913dbd6673c197d042c512acacd6694897118948
[netvirt.git] / cloud-servicechain / impl / src / main / java / org / opendaylight / netvirt / cloudservicechain / listeners / VpnToElanFallbackNodeListener.java
1 /*
2  * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.netvirt.cloudservicechain.listeners;
9
10 import java.math.BigInteger;
11 import java.util.Arrays;
12 import java.util.Collections;
13 import java.util.List;
14 import javax.annotation.PostConstruct;
15 import javax.inject.Inject;
16 import javax.inject.Singleton;
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
19 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
20 import org.opendaylight.genius.mdsalutil.MDSALUtil;
21 import org.opendaylight.genius.mdsalutil.MatchInfo;
22 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
23 import org.opendaylight.genius.mdsalutil.NwConstants;
24 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
25 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
26 import org.opendaylight.genius.utils.ServiceIndex;
27 import org.opendaylight.netvirt.cloudservicechain.CloudServiceChainConstants;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
33 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
34 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
35 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
36 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
37 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
38 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
39 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 // Rationale: for vpn-servicechain and elan-servicechain to coexist in the same deployment, it is necessary a flow
44 // in LPortDispatcher that sets SI to ELAN in case that VPN does not apply
45 /**
46  * Listens for Node Up/Down events in order to install the L2 to L3 default
47  * fallback flow. This flow, with minimum priority, consists on matching on
48  * SI=2 and sets SI=3.
49  *
50  */
51 @Singleton
52 public class VpnToElanFallbackNodeListener
53         extends AsyncDataTreeChangeListenerBase<Node, VpnToElanFallbackNodeListener> {
54
55     private static final Logger LOG = LoggerFactory.getLogger(VpnToElanFallbackNodeListener.class);
56     private static final String L3_TO_L2_DEFAULT_FLOW_REF = "L3VPN_to_Elan_Fallback_Default_Rule";
57     private final DataBroker broker;
58     private final IMdsalApiManager mdsalMgr;
59
60     // TODO: Remove when included in ovsdb's SouthboundUtils
61     public static final TopologyId FLOW_TOPOLOGY_ID = new TopologyId(new Uri("flow:1"));
62
63     @Inject
64     public VpnToElanFallbackNodeListener(final DataBroker db, final IMdsalApiManager mdsalManager) {
65         super(Node.class, VpnToElanFallbackNodeListener.class);
66         this.broker = db;
67         this.mdsalMgr = mdsalManager;
68     }
69
70     @Override
71     @PostConstruct
72     public void init() {
73         LOG.info("{} start", getClass().getSimpleName());
74         registerListener(LogicalDatastoreType.OPERATIONAL, broker);
75     }
76
77     @Override
78     protected InstanceIdentifier<Node> getWildCardPath() {
79         return InstanceIdentifier.create(NetworkTopology.class)
80                                  .child(Topology.class, new TopologyKey(FLOW_TOPOLOGY_ID))
81                                  .child(Node.class);
82     }
83
84     @Override
85     protected VpnToElanFallbackNodeListener getDataTreeChangeListener() {
86         return VpnToElanFallbackNodeListener.this;
87     }
88
89     @Override
90     protected void remove(InstanceIdentifier<Node> identifier, Node del) {
91         BigInteger dpnId = getDpnIdFromNodeId(del.getNodeId());
92         if (dpnId == null) {
93             return;
94         }
95
96         LOG.debug("Removing L3VPN to ELAN default Fallback flow in LPortDispatcher table from Dpn {}",
97                   del.getNodeId());
98
99         Flow flowToRemove = new FlowBuilder().setFlowName(L3_TO_L2_DEFAULT_FLOW_REF)
100                 .setId(new FlowId(L3_TO_L2_DEFAULT_FLOW_REF))
101                 .setTableId(NwConstants.LPORT_DISPATCHER_TABLE).build();
102         mdsalMgr.removeFlow(dpnId, flowToRemove);
103     }
104
105     @Override
106     protected void update(InstanceIdentifier<Node> identifier, Node original, Node update) {
107     }
108
109     @Override
110     protected void add(InstanceIdentifier<Node> identifier, Node add) {
111         BigInteger dpnId = getDpnIdFromNodeId(add.getNodeId());
112         if (dpnId == null) {
113             return;
114         }
115
116         LOG.debug("Installing L3VPN to ELAN default Fallback flow in LPortDispatcher table on Dpn {}",
117                   add.getNodeId());
118         List<MatchInfo> matches = Collections.singletonList(new MatchMetadata(MetaDataUtil.getServiceIndexMetaData(
119                 ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants.L3VPN_SERVICE_INDEX)),
120                 MetaDataUtil.METADATA_MASK_SERVICE_INDEX));
121
122         BigInteger metadataToWrite =
123             MetaDataUtil.getServiceIndexMetaData(ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME,
124                                                                        NwConstants.ELAN_SERVICE_INDEX));
125         int instructionKey = 0;
126         List<Instruction> instructions =
127                 Arrays.asList(MDSALUtil.buildAndGetWriteMetadaInstruction(metadataToWrite,
128                         MetaDataUtil.METADATA_MASK_SERVICE_INDEX,
129                         ++instructionKey),
130                         MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.L3_INTERFACE_TABLE, ++instructionKey));
131
132         Flow flow = MDSALUtil.buildFlowNew(NwConstants.LPORT_DISPATCHER_TABLE, L3_TO_L2_DEFAULT_FLOW_REF,
133                 NwConstants.TABLE_MISS_PRIORITY, L3_TO_L2_DEFAULT_FLOW_REF,
134                 0, 0, CloudServiceChainConstants.COOKIE_L3_BASE,
135                 matches, instructions);
136         mdsalMgr.installFlow(dpnId, flow);
137     }
138
139
140     private BigInteger getDpnIdFromNodeId(NodeId nodeId) {
141         String[] node =  nodeId.getValue().split(":");
142         if (node.length < 2) {
143             LOG.warn("Unexpected nodeId {}", nodeId.getValue());
144             return null;
145         }
146         return new BigInteger(node[1]);
147     }
148 }