2 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.netvirt.cloudservicechain.listeners;
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;
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
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
52 public class VpnToElanFallbackNodeListener
53 extends AsyncDataTreeChangeListenerBase<Node, VpnToElanFallbackNodeListener> {
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;
60 // TODO: Remove when included in ovsdb's SouthboundUtils
61 public static final TopologyId FLOW_TOPOLOGY_ID = new TopologyId(new Uri("flow:1"));
64 public VpnToElanFallbackNodeListener(final DataBroker db, final IMdsalApiManager mdsalManager) {
65 super(Node.class, VpnToElanFallbackNodeListener.class);
67 this.mdsalMgr = mdsalManager;
73 LOG.info("{} start", getClass().getSimpleName());
74 registerListener(LogicalDatastoreType.OPERATIONAL, broker);
78 protected InstanceIdentifier<Node> getWildCardPath() {
79 return InstanceIdentifier.create(NetworkTopology.class)
80 .child(Topology.class, new TopologyKey(FLOW_TOPOLOGY_ID))
85 protected VpnToElanFallbackNodeListener getDataTreeChangeListener() {
86 return VpnToElanFallbackNodeListener.this;
90 protected void remove(InstanceIdentifier<Node> identifier, Node del) {
91 BigInteger dpnId = getDpnIdFromNodeId(del.getNodeId());
96 LOG.debug("Removing L3VPN to ELAN default Fallback flow in LPortDispatcher table from Dpn {}",
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);
106 protected void update(InstanceIdentifier<Node> identifier, Node original, Node update) {
110 protected void add(InstanceIdentifier<Node> identifier, Node add) {
111 BigInteger dpnId = getDpnIdFromNodeId(add.getNodeId());
116 LOG.debug("Installing L3VPN to ELAN default Fallback flow in LPortDispatcher table on Dpn {}",
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));
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,
130 MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.L3_INTERFACE_TABLE, ++instructionKey));
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);
140 private BigInteger getDpnIdFromNodeId(NodeId nodeId) {
141 String[] node = nodeId.getValue().split(":");
142 if (node.length < 2) {
143 LOG.warn("Unexpected nodeId {}", nodeId.getValue());
146 return new BigInteger(node[1]);