IPv6Service Binding using elanTag 77/43477/3
authorSridhar Gaddam <sgaddam@redhat.com>
Tue, 9 Aug 2016 07:44:12 +0000 (13:14 +0530)
committerSam Hague <shague@redhat.com>
Tue, 9 Aug 2016 20:06:43 +0000 (20:06 +0000)
This patch implements the following.
1. We do Service binding for a port only when a v6 address is
   configured on the port. IPv6Address could be part of the port
   when its initially created or later (i.e, port updated) after
   the VM is spawned. Both cases are handled and the port is
   unbinded when the v6Address-is-removed/port-deleted. Once
   Service Binding is done, packets would hit the IPV6_TABLE(45)
   for further processing.
2. Optimizes the IPv6 punt flows by matching on the elanTag.
   Previous patch implements punt flows based on the VM macaddress,
   this is not optimal as we have to add VM specific punt flows when
   a new VM is added. In this patch, we take into account the elanTag
   (i.e., network-id) and configure punt flows for
   - icmpv6 Router solicitation requests
   - icmpv6 Neighbor solicitation requests for router interface
3. Multiple IPv6 subnets can be added/deleted (even when existing VMs
   are present) on the network and those edge cases are handled in
   this patchset. IPv6Service maintains a cache of (dpnIds <--> List[ports])
   per network. We use this info, while programing flows when IPv6 subnets
   are added/deleted to handle the edge cases.

Change-Id: I84c98979e9f6f71feb934a96df68613dd6defc42
Signed-off-by: Sridhar Gaddam <sgaddam@redhat.com>
vpnservice/ipv6service/impl/pom.xml
vpnservice/ipv6service/impl/src/main/java/org/opendaylight/netvirt/ipv6service/IfMgr.java
vpnservice/ipv6service/impl/src/main/java/org/opendaylight/netvirt/ipv6service/Ipv6ServiceImpl.java
vpnservice/ipv6service/impl/src/main/java/org/opendaylight/netvirt/ipv6service/Ipv6ServiceInterfaceEventListener.java
vpnservice/ipv6service/impl/src/main/java/org/opendaylight/netvirt/ipv6service/NeutronNetworkChangeListener.java [new file with mode: 0644]
vpnservice/ipv6service/impl/src/main/java/org/opendaylight/netvirt/ipv6service/VirtualNetwork.java [new file with mode: 0644]
vpnservice/ipv6service/impl/src/main/java/org/opendaylight/netvirt/ipv6service/VirtualPort.java
vpnservice/ipv6service/impl/src/main/java/org/opendaylight/netvirt/ipv6service/utils/Ipv6Constants.java
vpnservice/ipv6service/impl/src/main/java/org/opendaylight/netvirt/ipv6service/utils/Ipv6ServiceUtils.java
vpnservice/ipv6service/impl/src/main/resources/org/opendaylight/blueprint/ipv6service.xml

index e50ecf0eecfcc4d1963dd20d8993c2857011d145..7e380bb30a5de722cc940e6140cd2ffa04334dcc 100644 (file)
@@ -93,6 +93,16 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <artifactId>slf4j-simple</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.netvirt</groupId>
+      <artifactId>elanmanager-api</artifactId>
+      <version>0.3.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.netvirt</groupId>
+      <artifactId>elanmanager-impl</artifactId>
+      <version>0.3.0-SNAPSHOT</version>
+    </dependency>
   </dependencies>
   <build>
     <plugins>
index 96bfbbaadbaa5f095055dd4e4755a899b4918024..2876556ef3ce1a7e0dcc6064072f2dc4c8d2fc35 100644 (file)
@@ -10,13 +10,18 @@ package org.opendaylight.netvirt.ipv6service;
 
 import com.google.common.net.InetAddresses;
 import io.netty.util.Timeout;
+import java.math.BigInteger;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
-import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.genius.mdsalutil.NwConstants;
+import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.netvirt.elanmanager.api.IElanService;
 import org.opendaylight.netvirt.ipv6service.utils.Ipv6Constants;
 import org.opendaylight.netvirt.ipv6service.utils.Ipv6Constants.Ipv6RtrAdvertType;
 import org.opendaylight.netvirt.ipv6service.utils.Ipv6ServiceUtils;
@@ -38,6 +43,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.No
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
@@ -48,13 +54,18 @@ public class IfMgr {
     static final Logger LOG = LoggerFactory.getLogger(IfMgr.class);
 
     private HashMap<Uuid, VirtualRouter> vrouters;
+    private HashMap<Uuid, VirtualNetwork> vnetworks;
     private HashMap<Uuid, VirtualSubnet> vsubnets;
     private HashMap<Uuid, VirtualPort> vintfs;
     private HashMap<Uuid, VirtualPort> vrouterv6IntfMap;
     private HashMap<Uuid, List<VirtualPort>> unprocessedRouterIntfs;
     private HashMap<Uuid, List<VirtualPort>> unprocessedSubnetIntfs;
-    private HashMap<String, ImmutablePair<String, VirtualPort>> ifaceFlowCache;
     private OdlInterfaceRpcService interfaceManagerRpc;
+    private IElanService elanProvider;
+    private IMdsalApiManager mdsalUtil;
+    private Ipv6ServiceUtils ipv6ServiceUtils;
+    private DataBroker dataBroker;
+
     private static IfMgr ifMgr;
     private Ipv6ServiceUtils ipv6Utils = Ipv6ServiceUtils.getInstance();
 
@@ -64,12 +75,13 @@ public class IfMgr {
 
     void init() {
         this.vrouters = new HashMap<>();
+        this.vnetworks = new HashMap<>();
         this.vsubnets = new HashMap<>();
         this.vintfs = new HashMap<>();
         this.vrouterv6IntfMap = new HashMap<>();
         this.unprocessedRouterIntfs = new HashMap<>();
         this.unprocessedSubnetIntfs = new HashMap<>();
-        this.ifaceFlowCache = new HashMap<>();
+        this.ipv6ServiceUtils = new Ipv6ServiceUtils();
         LOG.info("IfMgr is enabled");
     }
 
@@ -84,6 +96,18 @@ public class IfMgr {
         IfMgr.ifMgr = ifMgr;
     }
 
+    public void setElanProvider(IElanService elanProvider) {
+        this.elanProvider = elanProvider;
+    }
+
+    public void setDataBroker(DataBroker dataBroker) {
+        this.dataBroker = dataBroker;
+    }
+
+    public void setMdsalUtilManager(IMdsalApiManager mdsalUtil) {
+        this.mdsalUtil = mdsalUtil;
+    }
+
     public void setInterfaceManagerRpc(OdlInterfaceRpcService interfaceManagerRpc) {
         LOG.trace("Registered interfaceManager successfully");
         this.interfaceManagerRpc = interfaceManagerRpc;
@@ -263,7 +287,13 @@ public class IfMgr {
             transmitUnsolicitedRA(intf);
             MacAddress ifaceMac = MacAddress.getDefaultInstance(macAddress);
             Ipv6Address llAddr = ipv6Utils.getIpv6LinkLocalAddressFromMac(ifaceMac);
-            programNSFlowForAddress(intf, llAddr, true);
+            /* A new router interface is created. This is basically triggered when an
+            IPv6 subnet is associated to the router. Check if network is already hosting
+            any VMs. If so, on all the hosts that have VMs on the network, program the
+            icmpv6 punt flows in IPV6_TABLE(45).
+             */
+            programIcmpv6RSPuntFlows(intf, Ipv6Constants.ADD_FLOW);
+            programIcmpv6NSPuntFlowForAddress(intf, llAddr, Ipv6Constants.ADD_FLOW);
         } else {
             intf.setSubnetInfo(snetId, fixedIp);
         }
@@ -284,7 +314,7 @@ public class IfMgr {
         }
 
         vrouterv6IntfMap.put(networkId, intf);
-        programNSFlowForAddress(intf, fixedIp.getIpv6Address(), true);
+        programIcmpv6NSPuntFlowForAddress(intf, fixedIp.getIpv6Address(), Ipv6Constants.ADD_FLOW);
         return;
     }
 
@@ -296,6 +326,8 @@ public class IfMgr {
             return;
         }
 
+        List<Ipv6Address> existingIPv6AddressList = intf.getIpv6AddressesWithoutLLA();
+        List<Ipv6Address> newlyAddedIpv6AddressList = new ArrayList<>();
         intf.clearSubnetInfo();
         for (FixedIps fip : fixedIpsList) {
             IpAddress fixedIp = fip.getIpAddress();
@@ -325,6 +357,26 @@ public class IfMgr {
                 addUnprocessed(unprocessedSubnetIntfs, fip.getSubnetId(), intf);
             }
             vrouterv6IntfMap.put(intf.getNetworkID(), intf);
+
+            if (existingIPv6AddressList.contains(fixedIp.getIpv6Address())) {
+                existingIPv6AddressList.remove(fixedIp.getIpv6Address());
+            } else {
+                newlyAddedIpv6AddressList.add(fixedIp.getIpv6Address());
+            }
+        }
+
+        /* This is a port update event for routerPort. Check if any IPv6 subnet is added
+         or removed from the router port. Depending on subnet added/removed, we add/remove
+         the corresponding flows from IPV6_TABLE(45).
+         */
+        for (Ipv6Address ipv6Address: newlyAddedIpv6AddressList) {
+            // Some v6 subnets are associated to the routerPort add the corresponding NS Flows.
+            programIcmpv6NSPuntFlowForAddress(intf, ipv6Address, Ipv6Constants.ADD_FLOW);
+        }
+
+        for (Ipv6Address ipv6Address: existingIPv6AddressList) {
+            // Some v6 subnets are disassociated from the routerPort, remove the corresponding NS Flows.
+            programIcmpv6NSPuntFlowForAddress(intf, ipv6Address, Ipv6Constants.DEL_FLOW);
         }
         return;
     }
@@ -353,6 +405,10 @@ public class IfMgr {
                     .setMacAddress(macAddress)
                     .setRouterIntfFlag(false)
                     .setDeviceOwner(deviceOwner);
+            Long elanTag = getNetworkElanTag(networkId);
+            // Do service binding for the port and set the serviceBindingStatus to true.
+            ipv6ServiceUtils.bindIpv6Service(dataBroker, portId.getValue(), elanTag, NwConstants.IPV6_TABLE);
+            intf.setServiceBindingStatus(Boolean.TRUE);
         } else {
             intf.setSubnetInfo(snetId, fixedIp);
         }
@@ -369,6 +425,7 @@ public class IfMgr {
 
     public void updateHostIntf(Uuid portId, List<FixedIps> fixedIpsList) {
         LOG.debug("updateHostIntf portId {}, fixedIpsList {} ", portId, fixedIpsList);
+        Boolean portIncludesV6Address = Boolean.FALSE;
 
         VirtualPort intf = vintfs.get(portId);
         if (intf == null) {
@@ -382,6 +439,7 @@ public class IfMgr {
             if (fixedIp.getIpv4Address() != null) {
                 continue;
             }
+            portIncludesV6Address = Boolean.TRUE;
             //Save the interface ipv6 address in its fully expanded format
             Ipv6Address addr = new Ipv6Address(InetAddresses
                     .forString(fixedIp.getIpv6Address().getValue()).getHostAddress());
@@ -397,10 +455,25 @@ public class IfMgr {
                 addUnprocessed(unprocessedSubnetIntfs, fip.getSubnetId(), intf);
             }
         }
+
+        /* If the VMPort initially included an IPv6 address (along with IPv4 address) and IPv6 address
+         was removed, we will have to unbind the service on the VM port. Similarly we do a ServiceBind
+         if required.
+          */
+        if (portIncludesV6Address) {
+            if (intf.getServiceBindingStatus() == Boolean.FALSE) {
+                Long elanTag = getNetworkElanTag(intf.getNetworkID());
+                ipv6ServiceUtils.bindIpv6Service(dataBroker, portId.getValue(), elanTag, NwConstants.IPV6_TABLE);
+                intf.setServiceBindingStatus(Boolean.TRUE);
+            }
+        } else {
+            ipv6ServiceUtils.unbindIpv6Service(dataBroker, portId.getValue());
+            intf.setServiceBindingStatus(Boolean.FALSE);
+        }
         return;
     }
 
-    public void updateInterface(Uuid portId, String dpId, Long ofPort) {
+    public void updateInterface(Uuid portId, BigInteger dpId, Long ofPort) {
         LOG.debug("in updateInterface portId {}, dpId {}, ofPort {}",
             portId, dpId, ofPort);
         VirtualPort intf = vintfs.get(portId);
@@ -416,9 +489,16 @@ public class IfMgr {
         }
 
         if (intf != null) {
-            intf.setDpId(dpId)
+            intf.setDpId(dpId.toString())
                     .setOfPort(ofPort);
         }
+
+        // Update the network <--> List[dpnIds, List<ports>] cache.
+        VirtualNetwork vnet = vnetworks.get(intf.getNetworkID());
+        if (null != vnet) {
+            vnet.updateDpnPortInfo(dpId, portId, Ipv6Constants.ADD_ENTRY);
+        }
+
         return;
     }
 
@@ -430,18 +510,26 @@ public class IfMgr {
                 MacAddress ifaceMac = MacAddress.getDefaultInstance(intf.getMacAddress());
                 Ipv6Address llAddr = ipv6Utils.getIpv6LinkLocalAddressFromMac(ifaceMac);
                 vrouterv6IntfMap.remove(intf.getNetworkID(), intf);
-                programNSFlowForAddress(intf, llAddr, false);
+                /* Router port is deleted. Remove the corresponding icmpv6 punt flows on all
+                the dpnIds which were hosting the VMs on the network.
+                 */
+                programIcmpv6RSPuntFlows(intf, Ipv6Constants.DEL_FLOW);
+                for (Ipv6Address ipv6Address: intf.getIpv6Addresses()) {
+                    programIcmpv6NSPuntFlowForAddress(intf, ipv6Address, Ipv6Constants.DEL_FLOW);
+                }
                 transmitRouterAdvertisement(intf, Ipv6RtrAdvertType.CEASE_ADVERTISEMENT);
                 Ipv6TimerWheel timer = Ipv6TimerWheel.getInstance();
                 timer.cancelPeriodicTransmissionTimeout(intf.getPeriodicTimeout());
                 intf.resetPeriodicTimeout();
                 LOG.debug("Reset the periodic RA Timer for intf {}", intf.getIntfUUID());
-            }
-            for (IpAddress ipAddr : intf.getIpAddresses()) {
-                if (ipAddr.getIpv6Address() != null) {
-                    if (intf.getDeviceOwner().equalsIgnoreCase(Ipv6Constants.NETWORK_ROUTER_INTERFACE)) {
-                        programNSFlowForAddress(intf, ipAddr.getIpv6Address(), false);
-                    }
+            } else {
+                // Remove the serviceBinding entry for the port.
+                ipv6ServiceUtils.unbindIpv6Service(dataBroker, portId.getValue());
+                // Remove the portId from the (network <--> List[dpnIds, List <ports>]) cache.
+                VirtualNetwork vnet = vnetworks.get(intf.getNetworkID());
+                if (null != vnet) {
+                    BigInteger dpId = ipv6ServiceUtils.getDataPathId(intf.getDpId());
+                    vnet.updateDpnPortInfo(dpId, intf.getIntfUUID(), Ipv6Constants.DEL_ENTRY);
                 }
             }
             vintfs.remove(portId);
@@ -494,8 +582,70 @@ public class IfMgr {
         return null;
     }
 
-    private void programNSFlowForAddress(VirtualPort intf, Ipv6Address address, boolean action) {
-        //Todo: Will be done in a separate patch.
+    private void programIcmpv6RSPuntFlows(VirtualPort routerPort, int action) {
+        Long elanTag = getNetworkElanTag(routerPort.getNetworkID());
+        int flowStatus;
+        VirtualNetwork vnet = vnetworks.get(routerPort.getNetworkID());
+        if (vnet != null) {
+            List<BigInteger> dpnList = vnet.getDpnsHostingNetwork();
+            for (BigInteger dpId : dpnList) {
+                flowStatus = vnet.getRSPuntFlowStatusOnDpnId(dpId);
+                if (action == Ipv6Constants.ADD_FLOW && flowStatus == Ipv6Constants.FLOWS_NOT_CONFIGURED) {
+                    ipv6ServiceUtils.installIcmpv6RsPuntFlow(NwConstants.IPV6_TABLE, dpId, elanTag,
+                            mdsalUtil, Ipv6Constants.ADD_FLOW);
+                    vnet.setRSPuntFlowStatusOnDpnId(dpId, Ipv6Constants.FLOWS_CONFIGURED);
+                } else if (action == Ipv6Constants.DEL_FLOW && flowStatus == Ipv6Constants.FLOWS_CONFIGURED) {
+                    ipv6ServiceUtils.installIcmpv6RsPuntFlow(NwConstants.IPV6_TABLE, dpId, elanTag,
+                            mdsalUtil, Ipv6Constants.DEL_FLOW);
+                    vnet.setRSPuntFlowStatusOnDpnId(dpId, Ipv6Constants.FLOWS_NOT_CONFIGURED);
+                }
+            }
+        }
+    }
+
+    private void programIcmpv6NSPuntFlowForAddress(VirtualPort routerPort, Ipv6Address ipv6Address, int action) {
+        Long elanTag = getNetworkElanTag(routerPort.getNetworkID());
+        VirtualNetwork vnet = vnetworks.get(routerPort.getNetworkID());
+        if (vnet != null) {
+            Collection<VirtualNetwork.DpnInterfaceInfo> dpnIfaceList = vnet.getDpnIfaceList();
+            for (VirtualNetwork.DpnInterfaceInfo dpnIfaceInfo : dpnIfaceList) {
+                if (action == Ipv6Constants.ADD_FLOW && !dpnIfaceInfo.ndTargetFlowsPunted.contains(ipv6Address)) {
+                    ipv6ServiceUtils.installIcmpv6NsPuntFlow(NwConstants.IPV6_TABLE, dpnIfaceInfo.getDpId(),
+                            elanTag, ipv6Address.getValue(), mdsalUtil, Ipv6Constants.ADD_FLOW);
+                    dpnIfaceInfo.updateNDTargetAddress(ipv6Address, action);
+                } else if (action == Ipv6Constants.DEL_FLOW && dpnIfaceInfo.ndTargetFlowsPunted.contains(ipv6Address)) {
+                    ipv6ServiceUtils.installIcmpv6NsPuntFlow(NwConstants.IPV6_TABLE, dpnIfaceInfo.getDpId(),
+                            elanTag, ipv6Address.getValue(), mdsalUtil, Ipv6Constants.DEL_FLOW);
+                    dpnIfaceInfo.updateNDTargetAddress(ipv6Address, action);
+                }
+            }
+        }
+    }
+
+    public void programIcmpv6PuntFlowsIfNecessary(Uuid vmPortId, BigInteger dpId, VirtualPort routerPort) {
+        VirtualPort vmPort = vintfs.get(vmPortId);
+        if (null != vmPort) {
+            VirtualNetwork vnet = vnetworks.get(vmPort.getNetworkID());
+            if (null != vnet) {
+                VirtualNetwork.DpnInterfaceInfo dpnInfo = vnet.getDpnIfaceInfo(dpId);
+                if (null != dpnInfo) {
+                    Long elanTag = getNetworkElanTag(routerPort.getNetworkID());
+                    if (vnet.getRSPuntFlowStatusOnDpnId(dpId) == Ipv6Constants.FLOWS_NOT_CONFIGURED) {
+                        ipv6ServiceUtils.installIcmpv6RsPuntFlow(NwConstants.IPV6_TABLE, dpId, elanTag,
+                                mdsalUtil, Ipv6Constants.ADD_FLOW);
+                        vnet.setRSPuntFlowStatusOnDpnId(dpId, Ipv6Constants.FLOWS_CONFIGURED);
+                    }
+
+                    for (Ipv6Address ipv6Address: routerPort.getIpv6Addresses()) {
+                        if (!dpnInfo.ndTargetFlowsPunted.contains(ipv6Address)) {
+                            ipv6ServiceUtils.installIcmpv6NsPuntFlow(NwConstants.IPV6_TABLE, dpId,
+                                    elanTag, ipv6Address.getValue(), mdsalUtil, Ipv6Constants.ADD_FLOW);
+                            dpnInfo.updateNDTargetAddress(ipv6Address, Ipv6Constants.ADD_FLOW);
+                        }
+                    }
+                }
+            }
+        }
     }
 
     public String getInterfaceNameFromTag(long portTag) {
@@ -514,16 +664,51 @@ public class IfMgr {
         return interfaceName;
     }
 
-    public void updateInterfaceCache(String interfaceName, ImmutablePair<String, VirtualPort> pair) {
-        ifaceFlowCache.put(interfaceName, pair);
+    public Long updateNetworkElanTag(Uuid networkId) {
+        Long elanTag = null;
+        if (null != this.elanProvider) {
+            ElanInstance elanInstance = this.elanProvider.getElanInstance(networkId.getValue());
+            if (null != elanInstance) {
+                elanTag = elanInstance.getElanTag();
+                VirtualNetwork net = vnetworks.get(networkId);
+                if (null != net) {
+                    net.setElanTag(elanTag);
+                }
+            }
+        }
+        return elanTag;
+    }
+
+    public Long getNetworkElanTag(Uuid networkId) {
+        Long elanTag = null;
+        VirtualNetwork net = vnetworks.get(networkId);
+        if (null != net) {
+            elanTag = net.getElanTag();
+            if (null == elanTag) {
+                elanTag = updateNetworkElanTag(networkId);
+            }
+        }
+        return elanTag;
     }
 
-    public ImmutablePair<String, VirtualPort> getInterfaceCache(String interfaceName) {
-        return ifaceFlowCache.get(interfaceName);
+    public void addNetwork(Uuid networkId) {
+        VirtualNetwork net = vnetworks.get(networkId);
+        if (null == net) {
+            net = new VirtualNetwork();
+            net.setNetworkUuid(networkId);
+            vnetworks.put(networkId, net);
+            updateNetworkElanTag(networkId);
+        }
     }
 
-    public void removeInterfaceCache(String interfaceName) {
-        ifaceFlowCache.remove(interfaceName);
+    public void removeNetwork(Uuid networkId) {
+        // Delete the network and the corresponding dpnIds<-->List(ports) cache.
+        VirtualNetwork net = vnetworks.get(networkId);
+        if (null == net) {
+            net.removeSelf();
+            vnetworks.remove(networkId);
+            net = null;
+        }
     }
 
     private void transmitRouterAdvertisement(VirtualPort intf, Ipv6RtrAdvertType advType) {
index c3a28e871e289b23c64920251c72790c2772bf14..b29322119905923e5fcdefbd84ca9e5f54101311 100644 (file)
@@ -7,6 +7,9 @@
  */
 package org.opendaylight.netvirt.ipv6service;
 
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.netvirt.elanmanager.api.IElanService;
 import org.opendaylight.netvirt.ipv6service.utils.Ipv6PeriodicTrQueue;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
@@ -18,17 +21,29 @@ public class Ipv6ServiceImpl {
     private final PacketProcessingService pktProcessingService;
     private final OdlInterfaceRpcService interfaceManagerRpc;
     private final IfMgr ifMgr;
+    private final IElanService elanProvider;
+    private final DataBroker dataBroker;
+    private final IMdsalApiManager mdsalUtil;
 
     public Ipv6ServiceImpl(final PacketProcessingService pktProcessingService,
-                    final OdlInterfaceRpcService interfaceManagerRpc) {
+                           final OdlInterfaceRpcService interfaceManagerRpc,
+                           final IElanService elanProvider,
+                           final DataBroker dataBroker,
+                           final IMdsalApiManager mdsalUtil) {
         this.pktProcessingService = pktProcessingService;
         this.interfaceManagerRpc = interfaceManagerRpc;
+        this.elanProvider = elanProvider;
+        this.dataBroker = dataBroker;
+        this.mdsalUtil = mdsalUtil;
         ifMgr = IfMgr.getIfMgrInstance();
     }
 
     public void start() {
         LOG.info("{} start", getClass().getSimpleName());
         ifMgr.setInterfaceManagerRpc(interfaceManagerRpc);
+        ifMgr.setElanProvider(elanProvider);
+        ifMgr.setDataBroker(dataBroker);
+        ifMgr.setMdsalUtilManager(mdsalUtil);
         final Ipv6PeriodicRAThread ipv6Thread = Ipv6PeriodicRAThread.getInstance();
         Ipv6RouterAdvt.setPacketProcessingService(pktProcessingService);
     }
index fc42da86b5e2a0d0d4ccc68e24ea2da427a111dc..53cf56abed096bbd1074902a31e2ae4f6140460e 100644 (file)
@@ -9,18 +9,14 @@ package org.opendaylight.netvirt.ipv6service;
 
 import java.math.BigInteger;
 import java.util.List;
-import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
-import org.opendaylight.genius.mdsalutil.NwConstants;
-import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
 import org.opendaylight.netvirt.ipv6service.utils.Ipv6Constants;
 import org.opendaylight.netvirt.ipv6service.utils.Ipv6ServiceUtils;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
@@ -34,20 +30,16 @@ public class Ipv6ServiceInterfaceEventListener
         implements ClusteredDataTreeChangeListener<Interface>, AutoCloseable {
     private static final Logger LOG = LoggerFactory.getLogger(Ipv6ServiceInterfaceEventListener.class);
     private final DataBroker dataBroker;
-    private final IMdsalApiManager mdsalUtil;
     private final IfMgr ifMgr;
-    private Ipv6ServiceUtils ipv6ServiceUtils;
 
     /**
      * Intialize the member variables.
      * @param broker the data broker instance.
      */
-    public Ipv6ServiceInterfaceEventListener(DataBroker broker, IMdsalApiManager mdsalUtil) {
+    public Ipv6ServiceInterfaceEventListener(DataBroker broker) {
         super(Interface.class, Ipv6ServiceInterfaceEventListener.class);
         this.dataBroker = broker;
-        this.mdsalUtil = mdsalUtil;
         ifMgr = IfMgr.getIfMgrInstance();
-        ipv6ServiceUtils = new Ipv6ServiceUtils();
     }
 
     public void start() {
@@ -63,28 +55,6 @@ public class Ipv6ServiceInterfaceEventListener
     @Override
     protected void remove(InstanceIdentifier<Interface> key, Interface del) {
         LOG.debug("Port removed {}, {}", key, del);
-        List<String> ofportIds = del.getLowerLayerIf();
-        if (ofportIds == null || ofportIds.isEmpty()) {
-            return;
-        }
-        String interfaceName = del.getName();
-        ImmutablePair<String, VirtualPort> pair = ifMgr.getInterfaceCache(interfaceName);
-        if (pair != null && pair.getLeft() != null && pair.getRight() != null) {
-            NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
-            BigInteger dpId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
-            if (!dpId.equals(Ipv6Constants.INVALID_DPID)) {
-                VirtualPort routerPort = pair.getRight();
-                ipv6ServiceUtils.unbindIpv6Service(dataBroker, interfaceName);
-                ipv6ServiceUtils.installIcmpv6RsPuntFlow(NwConstants.IPV6_TABLE, dpId, pair.getLeft(),
-                        mdsalUtil, Ipv6Constants.DEL_FLOW);
-                for (Ipv6Address ipv6Address : routerPort.getIpv6Addresses()) {
-                    ipv6ServiceUtils.installIcmpv6NsPuntFlow(NwConstants.IPV6_TABLE, dpId,
-                            pair.getLeft(), ipv6Address.getValue(), mdsalUtil, Ipv6Constants.DEL_FLOW);
-                }
-                ifMgr.removeInterfaceCache(interfaceName);
-                ifMgr.deleteInterface(new Uuid(del.getName()), dpId.toString());
-            }
-        }
     }
 
     @Override
@@ -127,22 +97,15 @@ public class Ipv6ServiceInterfaceEventListener
                 }
 
                 Long ofPort = MDSALUtil.getOfPortNumberFromPortName(nodeConnectorId);
-                ifMgr.updateInterface(portId, dpId.toString(), ofPort);
+                ifMgr.updateInterface(portId, dpId, ofPort);
 
                 VirtualPort routerPort = ifMgr.getRouterV6InterfaceForNetwork(port.getNetworkID());
                 if (routerPort == null) {
                     LOG.info("Port {} is not associated to a Router, skipping.", routerPort);
                     return;
                 }
-
-                ipv6ServiceUtils.installIcmpv6RsPuntFlow(NwConstants.IPV6_TABLE, dpId,
-                        port.getMacAddress(), mdsalUtil, Ipv6Constants.ADD_FLOW);
-                for (Ipv6Address ipv6Address : routerPort.getIpv6Addresses()) {
-                    ipv6ServiceUtils.installIcmpv6NsPuntFlow(NwConstants.IPV6_TABLE, dpId,
-                            port.getMacAddress(), ipv6Address.getValue(), mdsalUtil, Ipv6Constants.ADD_FLOW);
-                }
-                ipv6ServiceUtils.bindIpv6Service(dataBroker, iface.getName(), NwConstants.IPV6_TABLE);
-                ifMgr.updateInterfaceCache(iface.getName(), new ImmutablePair<>(port.getMacAddress(), routerPort));
+                // Check and program icmpv6 punt flows on the dpnID if its the first VM on the host.
+                ifMgr.programIcmpv6PuntFlowsIfNecessary(portId, dpId, routerPort);
             }
         }
     }
diff --git a/vpnservice/ipv6service/impl/src/main/java/org/opendaylight/netvirt/ipv6service/NeutronNetworkChangeListener.java b/vpnservice/ipv6service/impl/src/main/java/org/opendaylight/netvirt/ipv6service/NeutronNetworkChangeListener.java
new file mode 100644 (file)
index 0000000..dcccf63
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016 Red Hat, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netvirt.ipv6service;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.genius.mdsalutil.AbstractDataChangeListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.Networks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NeutronNetworkChangeListener extends AbstractDataChangeListener<Network> implements AutoCloseable {
+    private static final Logger LOG = LoggerFactory.getLogger(NeutronRouterChangeListener.class);
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+    private final DataBroker dataBroker;
+    private final IfMgr ifMgr;
+
+    public NeutronNetworkChangeListener(final DataBroker dataBroker) {
+        super(Network.class);
+        this.dataBroker = dataBroker;
+        this.ifMgr = IfMgr.getIfMgrInstance();
+    }
+
+    public void start() {
+        LOG.info("{} start", getClass().getSimpleName());
+        listenerRegistration = dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+                getWildCardPath(), this, AsyncDataBroker.DataChangeScope.SUBTREE);
+    }
+
+    private InstanceIdentifier<Network> getWildCardPath() {
+        return InstanceIdentifier.create(Neutron.class).child(Networks.class).child(Network.class);
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<Network> identifier, Network input) {
+        LOG.debug("Add Network notification handler is invoked {} ", input);
+        ifMgr.addNetwork(input.getUuid());
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<Network> identifier, Network input) {
+        LOG.debug("Remove Network notification handler is invoked {} ", input);
+        ifMgr.removeNetwork(input.getUuid());
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<Network> identifier, Network original, Network update) {
+        LOG.debug("Update Network notification handler is invoked...");
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (listenerRegistration != null) {
+            listenerRegistration.close();
+            listenerRegistration = null;
+        }
+        LOG.info("{} close", getClass().getSimpleName());
+    }
+}
diff --git a/vpnservice/ipv6service/impl/src/main/java/org/opendaylight/netvirt/ipv6service/VirtualNetwork.java b/vpnservice/ipv6service/impl/src/main/java/org/opendaylight/netvirt/ipv6service/VirtualNetwork.java
new file mode 100644 (file)
index 0000000..61af2a2
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2016 Red Hat, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netvirt.ipv6service;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import org.opendaylight.netvirt.ipv6service.utils.Ipv6Constants;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+
+public class VirtualNetwork {
+    Long elanTag;
+    private Uuid networkUUID;
+    private HashMap<BigInteger, DpnInterfaceInfo> dpnIfaceList;
+
+    public VirtualNetwork() {
+        dpnIfaceList = new HashMap<BigInteger, DpnInterfaceInfo>();
+    }
+
+    public void setNetworkUuid(Uuid networkUuid) {
+        this.networkUUID = networkUuid;
+    }
+
+    public Uuid getNetworkUuid() {
+        return networkUUID;
+    }
+
+    public void updateDpnPortInfo(BigInteger dpnId, Uuid portId, int addOrRemove) {
+        DpnInterfaceInfo dpnInterface = dpnIfaceList.get(dpnId);
+        if (dpnInterface == null) {
+            dpnInterface = new DpnInterfaceInfo(dpnId);
+            dpnIfaceList.put(dpnId, dpnInterface);
+        }
+
+        if (addOrRemove == Ipv6Constants.ADD_ENTRY) {
+            dpnInterface.updatePort(portId);
+        } else {
+            dpnInterface.removePort(portId);
+        }
+    }
+
+    public Long getElanTag() {
+        return elanTag;
+    }
+
+    public void setElanTag(Long etag) {
+        elanTag = etag;
+    }
+
+    public List<BigInteger> getDpnsHostingNetwork() {
+        List<BigInteger> dpnList = new ArrayList<>();
+        Collection<DpnInterfaceInfo> dpnCollection = dpnIfaceList.values();
+        for (DpnInterfaceInfo dpnInterfaceInfo: dpnCollection) {
+            dpnList.add(dpnInterfaceInfo.getDpId());
+        }
+        return dpnList;
+    }
+
+    public Collection<DpnInterfaceInfo> getDpnIfaceList() {
+        return dpnIfaceList.values();
+    }
+
+    public DpnInterfaceInfo getDpnIfaceInfo(BigInteger dpId) {
+        return dpnIfaceList.get(dpId);
+    }
+
+    public void setRSPuntFlowStatusOnDpnId(BigInteger dpnId, int action) {
+        DpnInterfaceInfo dpnInterface = dpnIfaceList.get(dpnId);
+        if (null != dpnInterface) {
+            dpnInterface.setRsFlowConfiguredStatus(action);
+        }
+    }
+
+    public int getRSPuntFlowStatusOnDpnId(BigInteger dpnId) {
+        DpnInterfaceInfo dpnInterface = dpnIfaceList.get(dpnId);
+        if (null != dpnInterface) {
+            return dpnInterface.getRsFlowConfiguredStatus();
+        }
+        return Ipv6Constants.FLOWS_NOT_CONFIGURED;
+    }
+
+    public void clearDpnInterfaceList() {
+        dpnIfaceList.clear();
+    }
+
+    @Override
+    public String toString() {
+        return "VirtualNetwork [networkUUID=" + networkUUID + " dpnIfaceList=" + dpnIfaceList + "]";
+    }
+
+    public void removeSelf() {
+        Collection<DpnInterfaceInfo> dpns = dpnIfaceList.values();
+        Iterator itr = dpns.iterator();
+        while (itr.hasNext()) {
+            DpnInterfaceInfo dpnInterfaceInfo = (DpnInterfaceInfo) itr.next();
+            if (null != dpnInterfaceInfo) {
+                dpnInterfaceInfo.clearPortInfo();
+                dpnInterfaceInfo.clearNdTargetFlowInfo();
+            }
+        }
+        clearDpnInterfaceList();
+    }
+
+    public class DpnInterfaceInfo {
+        BigInteger dpId;
+        int rsPuntFlowConfigured;
+        List<Uuid> portUUID;
+        List<Ipv6Address> ndTargetFlowsPunted;
+
+        DpnInterfaceInfo(BigInteger dpnId) {
+            dpId = dpnId;
+            portUUID = new ArrayList<>();
+            ndTargetFlowsPunted = new ArrayList<>();
+            rsPuntFlowConfigured = Ipv6Constants.FLOWS_NOT_CONFIGURED;
+        }
+
+        public void setDpId(BigInteger dpId) {
+            this.dpId = dpId;
+        }
+
+        public BigInteger getDpId() {
+            return dpId;
+        }
+
+        public void setRsFlowConfiguredStatus(int status) {
+            this.rsPuntFlowConfigured = status;
+        }
+
+        public int getRsFlowConfiguredStatus() {
+            return rsPuntFlowConfigured;
+        }
+
+        public List<Ipv6Address> getNDTargetFlows() {
+            return ndTargetFlowsPunted;
+        }
+
+        public void updateNDTargetAddress(Ipv6Address ipv6Address, int addOrRemove) {
+            if (addOrRemove == Ipv6Constants.ADD_ENTRY) {
+                this.ndTargetFlowsPunted.add(ipv6Address);
+            } else {
+                this.ndTargetFlowsPunted.remove(ipv6Address);
+            }
+        }
+
+        public void clearNdTargetFlowInfo() {
+            this.ndTargetFlowsPunted.clear();
+        }
+
+        public void updatePort(Uuid portID) {
+            this.portUUID.add(portID);
+        }
+
+        public void removePort(Uuid portID) {
+            this.portUUID.remove(portID);
+        }
+
+        public void clearPortInfo() {
+            this.portUUID.clear();
+        }
+
+        @Override
+        public String toString() {
+            return "DpnInterfaceInfo [dpId=" + dpId + " rsPuntFlowConfigured=" + rsPuntFlowConfigured + " portUUID="
+                    + portUUID + "]";
+        }
+    }
+}
index 7fe2aa2b1a609a9389fedd3faa9c688c41b5e5e8..39ae9f2d06580fa68745dc48cdca9cd69a67fef9 100644 (file)
@@ -31,6 +31,7 @@ public class VirtualPort  {
     private String    dpId;
     private String    deviceOwner;
     private Long      ofPort;
+    private Boolean   serviceBindingStatus;
     private HashMap<Uuid, SubnetInfo> snetInfo;
     private Ipv6PeriodicTimer periodicTimer;
     private Timeout periodicTimeout;
@@ -47,6 +48,7 @@ public class VirtualPort  {
 
     public VirtualPort() {
         snetInfo = new HashMap<Uuid, SubnetInfo>();
+        serviceBindingStatus = Boolean.FALSE;
     }
 
     public Uuid getIntfUUID() {
@@ -129,6 +131,16 @@ public class VirtualPort  {
         return ipv6AddrList;
     }
 
+    public List<Ipv6Address> getIpv6AddressesWithoutLLA() {
+        List<Ipv6Address> ipv6AddrList = new ArrayList<>();
+        for (SubnetInfo subnetInfo : snetInfo.values()) {
+            if (subnetInfo.getIpAddr().getIpv6Address() instanceof Ipv6Address) {
+                ipv6AddrList.add(subnetInfo.getIpAddr().getIpv6Address());
+            }
+        }
+        return ipv6AddrList;
+    }
+
     public String getMacAddress() {
         return macAddress;
     }
@@ -181,6 +193,14 @@ public class VirtualPort  {
         return ofPort;
     }
 
+    public void setServiceBindingStatus(Boolean status) {
+        this.serviceBindingStatus = status;
+    }
+
+    public Boolean getServiceBindingStatus() {
+        return serviceBindingStatus;
+    }
+
     public void removeSelf() {
         if (routerIntfFlag == true) {
             if (router != null) {
index e46473e5fbea7823a144082819ae8d8257a7d1de..7f63cc3f52e08d9ecc03092f5f437a20c42750ce 100644 (file)
@@ -56,6 +56,10 @@ public class Ipv6Constants {
 
     public static final int ADD_FLOW = 0;
     public static final int DEL_FLOW = 1;
+    public static final int ADD_ENTRY = 0;
+    public static final int DEL_ENTRY = 1;
+    public static final int FLOWS_CONFIGURED = 1;
+    public static final int FLOWS_NOT_CONFIGURED = 0;
     public static final String OPENFLOW_NODE_PREFIX = "openflow:";
     public static final short IPV6_VERSION = 6;
     public static final short ICMP6_NHEADER = 58;
index 4796919969a055c3ba0bb3657ff7c3e40d9c784c..3fb6241707f5dd8cce7f26ed421225f6ab8f0d8b 100644 (file)
@@ -31,10 +31,12 @@ import org.opendaylight.genius.mdsalutil.InstructionType;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
 import org.opendaylight.genius.mdsalutil.MatchFieldType;
 import org.opendaylight.genius.mdsalutil.MatchInfo;
+import org.opendaylight.genius.mdsalutil.MetaDataUtil;
 import org.opendaylight.genius.mdsalutil.NwConstants;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
 import org.opendaylight.genius.mdsalutil.packet.IPProtocols;
 import org.opendaylight.genius.utils.ServiceIndex;
+import org.opendaylight.netvirt.elan.utils.ElanUtils;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
@@ -295,23 +297,21 @@ public class Ipv6ServiceUtils {
         return ipv6LLA;
     }
 
-    private static List<MatchInfo> getIcmpv6RSMatch(String vmMacAddress) {
+    private static List<MatchInfo> getIcmpv6RSMatch(Long elanTag) {
         List<MatchInfo> matches = new ArrayList<>();
-        matches.add(new MatchInfo(MatchFieldType.eth_src,
-                new String[] { vmMacAddress }));
         matches.add(new MatchInfo(MatchFieldType.eth_type,
                 new long[] { NwConstants.ETHTYPE_IPV6 }));
         matches.add(new MatchInfo(MatchFieldType.ip_proto,
                 new long[] { IPProtocols.IPV6ICMP.intValue() }));
         matches.add(new MatchInfo(MatchFieldType.icmp_v6,
                 new long[] { Ipv6Constants.ICMP_V6_RS_CODE, 0}));
+        matches.add(new MatchInfo(MatchFieldType.metadata,
+                new BigInteger[] { ElanUtils.getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE}));
         return matches;
     }
 
-    private List<MatchInfo> getIcmpv6NSMatch(String vmMacAddress, String ndTarget) {
+    private List<MatchInfo> getIcmpv6NSMatch(Long elanTag, String ndTarget) {
         List<MatchInfo> matches = new ArrayList<>();
-        matches.add(new MatchInfo(MatchFieldType.eth_src,
-                new String[] { vmMacAddress }));
         matches.add(new MatchInfo(MatchFieldType.eth_type,
                 new long[] { NwConstants.ETHTYPE_IPV6 }));
         matches.add(new MatchInfo(MatchFieldType.ip_proto,
@@ -320,64 +320,45 @@ public class Ipv6ServiceUtils {
                 new long[] { Ipv6Constants.ICMP_V6_NS_CODE, 0}));
         matches.add(new MatchInfo(MatchFieldType.ipv6_nd_target,
                 new String[] { ndTarget }));
+        matches.add(new MatchInfo(MatchFieldType.metadata,
+                new BigInteger[] { ElanUtils.getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE}));
         return matches;
     }
 
-    private static String getIPv6FlowRef(BigInteger dpId, String vmMacAddress, String flowType) {
+    private static String getIPv6FlowRef(BigInteger dpId, Long elanTag, String flowType) {
         return new StringBuffer().append(Ipv6Constants.FLOWID_PREFIX)
                 .append(dpId).append(Ipv6Constants.FLOWID_SEPARATOR)
-                .append(vmMacAddress).append(flowType).toString();
+                .append(elanTag).append(Ipv6Constants.FLOWID_SEPARATOR)
+                .append(flowType).toString();
     }
 
-    private static void installRsPuntFlow(String interfaceName, short tableId, BigInteger dpId, String vmMacAddress,
-                                          IMdsalApiManager mdsalUtil, int addOrRemove) {
-        List<MatchInfo> routerSolicitationMatch = getIcmpv6RSMatch(vmMacAddress);
+    public void installIcmpv6NsPuntFlow(short tableId, BigInteger dpId,  Long elanTag, String ipv6Address,
+                                        IMdsalApiManager mdsalUtil,int addOrRemove) {
+        List<MatchInfo> neighborSolicitationMatch = getIcmpv6NSMatch(elanTag, ipv6Address);
         List<InstructionInfo> instructions = new ArrayList<>();
         List<ActionInfo> actionsInfos = new ArrayList<>();
-        // Punt to controller
         actionsInfos.add(new ActionInfo(ActionType.punt_to_controller,
                 new String[] {}));
         instructions.add(new InstructionInfo(InstructionType.write_actions,
                 actionsInfos));
         FlowEntity rsFlowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
-                getIPv6FlowRef(dpId, vmMacAddress, "IPv6RS"),Ipv6Constants.DEFAULT_FLOW_PRIORITY, "IPv6RS", 0, 0,
-                NwConstants.COOKIE_IPV6_TABLE, routerSolicitationMatch, instructions);
-        if (addOrRemove == Ipv6Constants.DEL_FLOW) {
-            LOG.trace("Removing IPv6 Router Solicitation Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
-            mdsalUtil.removeFlow(rsFlowEntity);
-        } else {
-            LOG.trace("Installing IPv6 Router Solicitation Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
-            mdsalUtil.installFlow(rsFlowEntity);
-        }
-    }
-
-    public void installIcmpv6NsPuntFlow(short tableId, BigInteger dpId, String vmMacAddress,
-                                        String ipv6Address, IMdsalApiManager mdsalUtil, int addOrRemove) {
-        List<MatchInfo> neighborSolicitationMatch = getIcmpv6NSMatch(vmMacAddress, ipv6Address);
-        List<InstructionInfo> instructions = new ArrayList<>();
-        List<ActionInfo> actionsInfos = new ArrayList<>();
-        actionsInfos.add(new ActionInfo(ActionType.punt_to_controller,
-                new String[] {}));
-        instructions.add(new InstructionInfo(InstructionType.write_actions,
-                actionsInfos));
-        FlowEntity rsFlowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
-                getIPv6FlowRef(dpId, vmMacAddress, ipv6Address),Ipv6Constants.DEFAULT_FLOW_PRIORITY, "IPv6NS",
+                getIPv6FlowRef(dpId, elanTag, ipv6Address),Ipv6Constants.DEFAULT_FLOW_PRIORITY, "IPv6NS",
                 0, 0, NwConstants.COOKIE_IPV6_TABLE, neighborSolicitationMatch, instructions);
         if (addOrRemove == Ipv6Constants.DEL_FLOW) {
-            LOG.trace("Removing IPv6 Neighbor Solicitation Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
+            LOG.trace("Removing IPv6 Neighbor Solicitation Flow DpId {}, elanTag {}", dpId, elanTag);
             mdsalUtil.removeFlow(rsFlowEntity);
         } else {
-            LOG.trace("Installing IPv6 Neighbor Solicitation Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
+            LOG.trace("Installing IPv6 Neighbor Solicitation Flow DpId {}, elanTag {}", dpId, elanTag);
             mdsalUtil.installFlow(rsFlowEntity);
         }
     }
 
-    public void installIcmpv6RsPuntFlow(short tableId, BigInteger dpId, String vmMacAddress,
-                                          IMdsalApiManager mdsalUtil, int addOrRemove) {
+    public void installIcmpv6RsPuntFlow(short tableId, BigInteger dpId, Long elanTag, IMdsalApiManager mdsalUtil,
+                                        int addOrRemove) {
         if (dpId == null || dpId.equals(Ipv6Constants.INVALID_DPID)) {
             return;
         }
-        List<MatchInfo> routerSolicitationMatch = getIcmpv6RSMatch(vmMacAddress);
+        List<MatchInfo> routerSolicitationMatch = getIcmpv6RSMatch(elanTag);
         List<InstructionInfo> instructions = new ArrayList<>();
         List<ActionInfo> actionsInfos = new ArrayList<>();
         // Punt to controller
@@ -386,13 +367,13 @@ public class Ipv6ServiceUtils {
         instructions.add(new InstructionInfo(InstructionType.write_actions,
                 actionsInfos));
         FlowEntity rsFlowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
-                getIPv6FlowRef(dpId, vmMacAddress, "IPv6RS"),Ipv6Constants.DEFAULT_FLOW_PRIORITY, "IPv6RS", 0, 0,
+                getIPv6FlowRef(dpId, elanTag, "IPv6RS"),Ipv6Constants.DEFAULT_FLOW_PRIORITY, "IPv6RS", 0, 0,
                 NwConstants.COOKIE_IPV6_TABLE, routerSolicitationMatch, instructions);
         if (addOrRemove == Ipv6Constants.DEL_FLOW) {
-            LOG.trace("Removing IPv6 Router Solicitation Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
+            LOG.trace("Removing IPv6 Router Solicitation Flow DpId {}, elanTag {}", dpId, elanTag);
             mdsalUtil.removeFlow(rsFlowEntity);
         } else {
-            LOG.trace("Installing IPv6 Router Solicitation Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
+            LOG.trace("Installing IPv6 Router Solicitation Flow DpId {}, elanTag {}", dpId, elanTag);
             mdsalUtil.installFlow(rsFlowEntity);
         }
     }
@@ -414,9 +395,11 @@ public class Ipv6ServiceUtils {
                 .child(BoundServices.class, new BoundServicesKey(priority)).build();
     }
 
-    public void bindIpv6Service(DataBroker broker, String interfaceName, short tableId) {
+    public void bindIpv6Service(DataBroker broker, String interfaceName, Long elanTag, short tableId) {
         int instructionKey = 0;
         List<Instruction> instructions = new ArrayList<>();
+        instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanUtils.getElanMetadataLabel(elanTag),
+                MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
         instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(tableId, ++instructionKey));
         short serviceIndex = ServiceIndex.getIndex(NwConstants.IPV6_SERVICE_NAME, NwConstants.IPV6_SERVICE_INDEX);
         BoundServices
@@ -433,4 +416,12 @@ public class Ipv6ServiceUtils {
                 buildServiceId(interfaceName, ServiceIndex.getIndex(NwConstants.IPV6_SERVICE_NAME,
                         NwConstants.IPV6_SERVICE_INDEX)));
     }
+
+    public static BigInteger getDataPathId(String dpId) {
+        long dpid = 0L;
+        if (dpId != null) {
+            dpid = new BigInteger(dpId.replaceAll(":", ""), 16).longValue();
+        }
+        return BigInteger.valueOf(dpid);
+    }
 }
index 20891d759f11a0d5326b8817dcfa9cf95eb5e9c9..017075b9e5768d946d5ea97e474d8915864e427c 100644 (file)
@@ -9,6 +9,8 @@
   <reference id="mdsalUtils"
              interface="org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager" />
 
+  <reference id="elanProvider" interface="org.opendaylight.netvirt.elanmanager.api.IElanService" availability="optional" />
+
   <odl:rpc-service id="odlInterfaceRpcService"
                    interface="org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService" />
   <odl:rpc-service id="packetProcessingService"
@@ -25,7 +27,6 @@
         class="org.opendaylight.netvirt.ipv6service.Ipv6ServiceInterfaceEventListener"
         init-method="start" destroy-method="close">
     <argument ref="dataBroker" />
-    <argument ref="mdsalUtils" />
   </bean>
 
   <bean id="neutronPortChangeListener"
     <argument ref="dataBroker" />
   </bean>
 
+  <bean id="neutronNetworkChangeListener"
+        class="org.opendaylight.netvirt.ipv6service.NeutronNetworkChangeListener"
+        init-method="start" destroy-method="close">
+    <argument ref="dataBroker" />
+  </bean>
+
   <bean id="neutronSubnetChangeListener"
         class="org.opendaylight.netvirt.ipv6service.NeutronSubnetChangeListener"
         init-method="start" destroy-method="close">
@@ -58,5 +65,8 @@
         init-method="start" destroy-method="close">
     <argument ref="packetProcessingService" />
     <argument ref="odlInterfaceRpcService" />
+    <argument ref="elanProvider" />
+    <argument ref="dataBroker" />
+    <argument ref="mdsalUtils" />
   </bean>
 </blueprint>