Subnet routing for hidden IPv6 addresses 68/72068/22
authorSomashekar Byrappa <somashekar.b@altencalsoftlabs.com>
Thu, 17 May 2018 12:42:52 +0000 (18:12 +0530)
committerSam Hague <shague@redhat.com>
Mon, 2 Jul 2018 16:25:09 +0000 (16:25 +0000)
As part of implementation of the spec, this patch handles:

+ Code has been enhanced to support subnet routing even for hidden
  IPv6 addresses.
+ Hidden IPv6 addresses are learnt via NA responses.

Depends-On: https://git.opendaylight.org/gerrit/#/c/71567/

JIRA: NETVIRT-1213

Change-Id: I9fe73027a5d1f25abde5f2233570755e333518cb
Signed-off-by: Somashekar Byrappa <somashekar.b@altencalsoftlabs.com>
vpnmanager/impl/pom.xml
vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/ArpMonitoringHandler.java
vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/ArpNotificationHandler.java [deleted file]
vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/SubnetRoutePacketInHandler.java
vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnConstants.java
vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnUtil.java [changed mode: 0755->0644]
vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/iplearn/AbstractIpLearnNotificationHandler.java [new file with mode: 0644]
vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/iplearn/ArpNotificationHandler.java [new file with mode: 0644]
vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/iplearn/Ipv6NaNotificationHandler.java [new file with mode: 0644]
vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/utilities/VpnManagerCounters.java
vpnmanager/impl/src/main/resources/org/opendaylight/blueprint/vpnmanager.xml

index 658d350f2c43f6b28de527bd41d196350d377a79..af0da925eb18139c93a0846fd0339e0b8c8a0190 100644 (file)
@@ -91,6 +91,11 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
             <artifactId>elanmanager-api</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>ipv6service-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
 
         <!-- Testing dependencies -->
         <dependency>
index c3e10c2aa34a1df2e7e3d37d2d09208288912d97..167e0cddd46fa3faf1d722b0cc79d16cc360047c 100644 (file)
@@ -19,6 +19,7 @@ import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.genius.arputil.api.ArpConstants;
 import org.opendaylight.genius.datastoreutils.AsyncClusteredDataTreeChangeListenerBase;
 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
+import org.opendaylight.genius.mdsalutil.NWUtil;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
 import org.opendaylight.genius.utils.clustering.EntityOwnershipUtils;
 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
@@ -143,9 +144,15 @@ public class ArpMonitoringHandler
                 String vpnName =  value.getVpnName();
                 MacEntry macEntry = new MacEntry(vpnName, srcMacAddress, srcInetAddr, value.getPortName(),
                         value.getCreationTime());
-                jobCoordinator.enqueueJob(buildJobKey(srcInetAddr.toString(), vpnName),
-                        new ArpMonitorStartTask(macEntry, arpMonitorProfileId, dataBroker, alivenessManager,
-                                neutronVpnService, interfaceManager));
+
+                if (NWUtil.isIpv4Address(value.getPortFixedip())) {
+                    jobCoordinator.enqueueJob(buildJobKey(srcInetAddr.toString(), vpnName),
+                            new ArpMonitorStartTask(macEntry, arpMonitorProfileId, dataBroker, alivenessManager,
+                                    neutronVpnService, interfaceManager));
+                } else {
+                    // TODO: Handle for IPv6 case
+                    LOG.warn("IPv6 address monitoring is not yet supported - add(). LearntVpnVipToPort={}", value);
+                }
             } catch (UnknownHostException e) {
                 LOG.error("Error in deserializing packet {} with exception", value, e);
             }
@@ -166,8 +173,14 @@ public class ArpMonitoringHandler
                 String interfaceName =  value.getPortName();
                 MacEntry macEntry = new MacEntry(vpnName, srcMacAddress, srcInetAddr, interfaceName,
                         value.getCreationTime());
-                jobCoordinator.enqueueJob(buildJobKey(srcInetAddr.toString(), vpnName),
-                        new ArpMonitorStopTask(macEntry, dataBroker, alivenessManager, Boolean.FALSE));
+
+                if (NWUtil.isIpv4Address(value.getPortFixedip())) {
+                    jobCoordinator.enqueueJob(buildJobKey(srcInetAddr.toString(), vpnName),
+                            new ArpMonitorStopTask(macEntry, dataBroker, alivenessManager, Boolean.FALSE));
+                } else {
+                    // TODO: Handle for IPv6 case
+                    LOG.warn("IPv6 address monitoring is not yet supported - remove(). LearntVpnVipToPort={}", value);
+                }
             } catch (UnknownHostException e) {
                 LOG.error("Error in deserializing packet {} with exception", value, e);
             }
diff --git a/vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/ArpNotificationHandler.java b/vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/ArpNotificationHandler.java
deleted file mode 100644 (file)
index a1a84bc..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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.vpnmanager;
-
-import com.google.common.base.Optional;
-import com.google.common.cache.Cache;
-import com.google.common.cache.CacheBuilder;
-import java.math.BigInteger;
-import java.net.UnknownHostException;
-import java.util.List;
-import java.util.Objects;
-import java.util.concurrent.TimeUnit;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-import org.apache.commons.lang3.tuple.ImmutablePair;
-import org.apache.commons.lang3.tuple.Pair;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
-import org.opendaylight.genius.mdsalutil.NWUtil;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.ArpRequestReceived;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.ArpResponseReceived;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.MacChanged;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilListener;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.LearntVpnVipToPortEventAction;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPort;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.config.rev161130.VpnConfig;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@Singleton
-public class ArpNotificationHandler implements OdlArputilListener {
-    private static final Logger LOG = LoggerFactory.getLogger(ArpNotificationHandler.class);
-    // temp where Key is VPNInstance+IP and value is timestamp
-    private final Cache<Pair<String, String>, BigInteger> migrateArpCache;
-
-    private final DataBroker dataBroker;
-    private final IdManagerService idManager;
-    private final IInterfaceManager interfaceManager;
-    private final VpnConfig config;
-
-    @Inject
-    public ArpNotificationHandler(DataBroker dataBroker, IdManagerService idManager,
-                                  IInterfaceManager interfaceManager, VpnConfig vpnConfig) {
-        this.dataBroker = dataBroker;
-        this.idManager = idManager;
-        this.interfaceManager = interfaceManager;
-        this.config = vpnConfig;
-
-        long duration = config.getArpLearnTimeout() * 10;
-        long cacheSize = config.getArpCacheSize().longValue();
-        migrateArpCache =
-                CacheBuilder.newBuilder().maximumSize(cacheSize).expireAfterWrite(duration,
-                        TimeUnit.MILLISECONDS).build();
-    }
-
-    @Override
-    public void onMacChanged(MacChanged notification) {
-
-    }
-
-    @Override
-    public void onArpRequestReceived(ArpRequestReceived notification) {
-        String srcInterface = notification.getInterface();
-        IpAddress srcIP = notification.getSrcIpaddress();
-        PhysAddress srcMac = notification.getSrcMac();
-        IpAddress targetIP = notification.getDstIpaddress();
-        BigInteger metadata = notification.getMetadata();
-        boolean isGarp = srcIP.equals(targetIP);
-        if (!isGarp) {
-            LOG.info("ArpNotification Non-Gratuitous Request Received from "
-                      + "interface {} and IP {} having MAC {} target destination {}, ignoring..",
-                    srcInterface, srcIP.getIpv4Address().getValue(),srcMac.getValue(),
-                    targetIP.getIpv4Address().getValue());
-            return;
-        }
-        LOG.info("ArpNotification Gratuitous Request Received from "
-                  + "interface {} and IP {} having MAC {} target destination {}, learning MAC",
-                  srcInterface, srcIP.getIpv4Address().getValue(),srcMac.getValue(),
-                  targetIP.getIpv4Address().getValue());
-        processArpLearning(srcInterface, srcIP, srcMac, metadata, targetIP);
-    }
-
-    @Override
-    public void onArpResponseReceived(ArpResponseReceived notification) {
-        String srcInterface = notification.getInterface();
-        IpAddress srcIP = notification.getSrcIpaddress();
-        PhysAddress srcMac = notification.getSrcMac();
-        LOG.info("ArpNotification Response Received from interface {} and IP {} having MAC {}, learning MAC",
-                srcInterface, srcIP.getIpv4Address().getValue(), srcMac.getValue());
-        List<Adjacency> adjacencies = VpnUtil.getAdjacenciesForVpnInterfaceFromConfig(dataBroker, srcInterface);
-        if (adjacencies != null) {
-            for (Adjacency adj : adjacencies) {
-                String ipAddress = adj.getIpAddress();
-                try {
-                    if (NWUtil.isIpInSubnet(NWUtil.ipAddressToInt(srcIP.getIpv4Address().getValue()), ipAddress)) {
-                        return;
-                    }
-                } catch (UnknownHostException e) {
-                    LOG.error("Subnet string {} not convertible to InetAdddress", srcIP, e);
-                }
-            }
-        }
-        BigInteger metadata = notification.getMetadata();
-        IpAddress targetIP = notification.getDstIpaddress();
-        LOG.trace("ArpNotification Response Received from interface {} and IP {} having MAC {}, learning MAC",
-                srcInterface, srcIP.getIpv4Address().getValue(), srcMac.getValue());
-        processArpLearning(srcInterface, srcIP, srcMac, metadata, targetIP);
-    }
-
-    private void processArpLearning(String srcInterface, IpAddress srcIP, PhysAddress srcMac, BigInteger metadata,
-            IpAddress dstIP) {
-        if (metadata != null && !Objects.equals(metadata, BigInteger.ZERO)) {
-            Optional<List<String>> vpnList = VpnUtil
-                  .getVpnHandlingIpv4AssociatedWithInterface(dataBroker, srcInterface);
-            if (vpnList.isPresent()) {
-                for (String vpnName : vpnList.get()) {
-                    LOG.info("Received ARP for sender MAC {} and sender IP {} via interface {}",
-                              srcMac.getValue(), srcIP.getIpv4Address().getValue(), srcInterface);
-                    String srcIpToQuery = srcIP.getIpv4Address().getValue();
-                    String destIpToQuery = dstIP.getIpv4Address().getValue();
-                    LOG.info("ARP being processed for Source IP {}", srcIpToQuery);
-                    VpnPortipToPort vpnPortipToPort =
-                            VpnUtil.getNeutronPortFromVpnPortFixedIp(dataBroker, vpnName, srcIpToQuery);
-                    if (vpnPortipToPort != null) {
-                        /* This is a well known neutron port and so should be ignored
-                         * from being discovered
-                         */
-                        continue;
-                    }
-                    LearntVpnVipToPort learntVpnVipToPort = VpnUtil.getLearntVpnVipToPort(dataBroker,
-                              vpnName, srcIpToQuery);
-                    if (learntVpnVipToPort != null) {
-                        String oldPortName = learntVpnVipToPort.getPortName();
-                        String oldMac = learntVpnVipToPort.getMacAddress();
-                        if (!oldMac.equalsIgnoreCase(srcMac.getValue())) {
-                            //MAC has changed for requested IP
-                            LOG.info("ARP Source IP/MAC data modified for IP {} with MAC {} and Port {}",
-                                    srcIpToQuery, srcMac, srcInterface);
-                            synchronized ((vpnName + srcIpToQuery).intern()) {
-                                VpnUtil.createLearntVpnVipToPortEvent(dataBroker, vpnName, srcIpToQuery, destIpToQuery,
-                                        oldPortName, oldMac, LearntVpnVipToPortEventAction.Delete, null);
-                                putVpnIpToMigrateArpCache(vpnName, srcIpToQuery, srcMac);
-                            }
-                        }
-                    } else if (!isIpInArpMigrateCache(vpnName, srcIpToQuery)) {
-                        learnMacFromArpPackets(vpnName, srcInterface, srcIP, srcMac, dstIP);
-                    }
-                }
-            } else {
-                LOG.info("ARP NO_RESOLVE: VPN  not configured. Ignoring responding to ARP requests from this"
-                        + " Interface {}.", srcInterface);
-                return;
-
-            }
-        }
-    }
-
-    private void learnMacFromArpPackets(String vpnName, String srcInterface,
-        IpAddress srcIP, PhysAddress srcMac, IpAddress dstIP) {
-        String srcIpToQuery = srcIP.getIpv4Address().getValue();
-        String destIpToQuery = dstIP.getIpv4Address().getValue();
-        synchronized ((vpnName + srcIpToQuery).intern()) {
-            VpnUtil.createLearntVpnVipToPortEvent(dataBroker, vpnName, srcIpToQuery, destIpToQuery, srcInterface,
-                    srcMac.getValue(), LearntVpnVipToPortEventAction.Add, null);
-        }
-    }
-
-    private void putVpnIpToMigrateArpCache(String vpnName, String ipToQuery, PhysAddress srcMac) {
-        long cacheSize = config.getArpCacheSize().longValue();
-        if (migrateArpCache.size() >= cacheSize) {
-            LOG.debug("ARP_MIGRATE_CACHE: max size {} reached, assuming cache eviction we still put IP {}"
-                    + " vpnName {} with MAC {}", cacheSize, ipToQuery, vpnName, srcMac);
-        }
-        LOG.debug("ARP_MIGRATE_CACHE: add to dirty cache IP {} vpnName {} with MAC {}", ipToQuery, vpnName, srcMac);
-        migrateArpCache.put(new ImmutablePair<>(vpnName, ipToQuery),
-                new BigInteger(String.valueOf(System.currentTimeMillis())));
-    }
-
-    private boolean isIpInArpMigrateCache(String vpnName, String ipToQuery) {
-        if (migrateArpCache == null || migrateArpCache.size() == 0) {
-            return false;
-        }
-        Pair<String, String> keyPair = new ImmutablePair<>(vpnName, ipToQuery);
-        BigInteger prevTimeStampCached = migrateArpCache.getIfPresent(keyPair);
-        if (prevTimeStampCached == null) {
-            LOG.debug("ARP_MIGRATE_CACHE: there is no IP {} vpnName {} in dirty cache, so learn it",
-                    ipToQuery, vpnName);
-            return false;
-        }
-        if (System.currentTimeMillis() > prevTimeStampCached.longValue() + config.getArpLearnTimeout()) {
-            LOG.debug("ARP_MIGRATE_CACHE: older than timeout value - remove from dirty cache IP {} vpnName {}",
-                    ipToQuery, vpnName);
-            migrateArpCache.invalidate(keyPair);
-            return false;
-        }
-        LOG.debug("ARP_MIGRATE_CACHE: younger than timeout value - ignore learning IP {} vpnName {}",
-                ipToQuery, vpnName);
-        return true;
-    }
-}
index 972d3f723d5fc37fa2216e03fee612a24bf6a328..0dedba0a11ca426b90bcd85bb2cd43b7bc4ce32f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2016, 2018 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ * Copyright (c) 2016, 2018 Ericsson India Global Services Pvt Ltd. 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,
@@ -30,15 +30,22 @@ import org.opendaylight.infrautils.utils.concurrent.JdkFutures;
 import org.opendaylight.netvirt.vpnmanager.api.ICentralizedSwitchProvider;
 import org.opendaylight.netvirt.vpnmanager.api.VpnHelper;
 import org.opendaylight.netvirt.vpnmanager.utilities.VpnManagerCounters;
+import org.opendaylight.openflowplugin.libraries.liblldp.BitBufferHelper;
+import org.opendaylight.openflowplugin.libraries.liblldp.BufferException;
 import org.opendaylight.openflowplugin.libraries.liblldp.HexEncode;
 import org.opendaylight.openflowplugin.libraries.liblldp.NetUtils;
 import org.opendaylight.openflowplugin.libraries.liblldp.Packet;
 import org.opendaylight.openflowplugin.libraries.liblldp.PacketException;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
+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.MacAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.tag.name.map.ElanTagName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.ipv6util.rev170210.Ipv6NdutilService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIds;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
@@ -62,18 +69,20 @@ public class SubnetRoutePacketInHandler implements PacketProcessingListener {
     private final ICentralizedSwitchProvider centralizedSwitchProvider;
     private final IInterfaceManager interfaceManager;
     private final VpnManagerCounters vpnManagerCounters;
+    private final Ipv6NdutilService ipv6NdutilService;
 
     @Inject
     public SubnetRoutePacketInHandler(final DataBroker dataBroker, final PacketProcessingService packetService,
             final OdlInterfaceRpcService odlInterfaceRpcService,
-            final ICentralizedSwitchProvider centralizedSwitchProvider,
-            final IInterfaceManager interfaceManager, VpnManagerCounters vpnManagerCounters) {
+            final ICentralizedSwitchProvider centralizedSwitchProvider, final IInterfaceManager interfaceManager,
+            VpnManagerCounters vpnManagerCounters, final Ipv6NdutilService ipv6NdutilService) {
         this.dataBroker = dataBroker;
         this.packetService = packetService;
         this.odlInterfaceRpcService = odlInterfaceRpcService;
         this.centralizedSwitchProvider = centralizedSwitchProvider;
         this.interfaceManager = interfaceManager;
         this.vpnManagerCounters = vpnManagerCounters;
+        this.ipv6NdutilService = ipv6NdutilService;
     }
 
     @Override
@@ -99,69 +108,39 @@ public class SubnetRoutePacketInHandler implements PacketProcessingListener {
                 vpnManagerCounters.subnetRoutePacketFailed();
                 return;
             }
+            byte[] srcIpBytes = null;
+            byte[] dstIpBytes = null;
+            String srcIpStr;
+            String dstIpStr;
+            String srcMac = NWUtil.toStringMacAddress(res.getSourceMACAddress());
             try {
                 Packet pkt = res.getPayload();
                 if (pkt instanceof IPv4) {
                     IPv4 ipv4 = (IPv4) pkt;
-                    byte[] srcIp = Ints.toByteArray(ipv4.getSourceAddress());
-                    byte[] dstIp = Ints.toByteArray(ipv4.getDestinationAddress());
-                    String dstIpStr = NWUtil.toStringIpAddress(dstIp);
-                    String srcIpStr = NWUtil.toStringIpAddress(srcIp);
+                    srcIpBytes = Ints.toByteArray(ipv4.getSourceAddress());
+                    dstIpBytes = Ints.toByteArray(ipv4.getDestinationAddress());
                     // It is an ARP request on a configured VPN. So we must
                     // attempt to respond.
-                    long vpnId = MetaDataUtil.getVpnIdFromMetadata(metadata);
-
-                    LOG.info("{} onPacketReceived: Processing IPv4 Packet received with Source IP {} and Target IP {}"
-                            + " and vpnId {}", LOGGING_PREFIX, srcIpStr, dstIpStr, vpnId);
-
-                    Optional<VpnIds> vpnIdsOptional = SingleTransactionDataBroker.syncReadOptional(dataBroker,
-                            LogicalDatastoreType.CONFIGURATION, VpnUtil.getVpnIdToVpnInstanceIdentifier(vpnId));
-
-                    if (!vpnIdsOptional.isPresent()) {
-                        // Donot trigger subnetroute logic for packets from
-                        // unknown VPNs
-                        vpnManagerCounters.subnetRoutePacketIgnored();
-                        LOG.info("{} onPacketReceived: Ignoring IPv4 packet with destination Ip {} and source Ip {}"
-                                + " as it came on unknown VPN with ID {}", LOGGING_PREFIX, dstIpStr, srcIpStr, vpnId);
-                        return;
-                    }
-
-                    String vpnIdVpnInstanceName = vpnIdsOptional.get().getVpnInstanceName();
-                    if (VpnUtil.getNeutronPortFromVpnPortFixedIp(dataBroker, vpnIdVpnInstanceName, dstIpStr) != null) {
-                        vpnManagerCounters.subnetRoutePacketIgnored();
-                        LOG.info("{} onPacketReceived: IPv4 Packet received with Target IP {} source IP {} vpnId {} "
-                                + "is a valid Neutron port,ignoring subnet route processing", LOGGING_PREFIX, dstIpStr,
-                                srcIp, vpnId);
-                        return;
-                    }
-
-                    if (VpnUtil.getLearntVpnVipToPort(dataBroker, vpnIdVpnInstanceName, dstIpStr) != null) {
-                        vpnManagerCounters.subnetRoutePacketIgnored();
-                        LOG.info("{} onPacketReceived: IPv4 Packet received with Target IP {} source Ip {} vpnId {}"
-                                + " is an already discovered IPAddress, ignoring subnet route processing",
-                                LOGGING_PREFIX, dstIpStr, srcIp, vpnId);
-                        return;
-                    }
-
-                    long elanTag = MetaDataUtil.getElanTagFromMetadata(metadata);
-                    if (elanTag == 0L) {
-                        vpnManagerCounters.subnetRoutePacketFailed();
-                        LOG.error("{} onPacketReceived: elanTag value from metadata found to be 0, for IPv4 "
-                                + " Packet received with Target IP {} src Ip {} vpnId {}",
-                                LOGGING_PREFIX, dstIpStr, srcIp, vpnId);
-                        return;
+                } else {
+                    // IPv6 case
+                    // TODO: IPv6 deserializer
+                    int ethType = BitBufferHelper.getInt(
+                            BitBufferHelper.getBits(data, VpnConstants.ETHTYPE_START, VpnConstants.TWO_BYTES));
+                    if (ethType == VpnConstants.IP_V6_ETHTYPE) {
+                        srcIpBytes = BitBufferHelper.getBits(data, VpnConstants.IP_V6_HDR_START + 64, 128);
+                        dstIpBytes = BitBufferHelper.getBits(data, VpnConstants.IP_V6_HDR_START + 192, 128);
                     }
+                }
+                if (srcIpBytes == null || dstIpBytes == null) {
+                    LOG.trace("{} onPacketReceived: Non-IP packet received as {}", LOGGING_PREFIX, notification);
+                    return;
+                }
+                srcIpStr = NWUtil.toStringIpAddress(srcIpBytes);
+                dstIpStr = NWUtil.toStringIpAddress(dstIpBytes);
 
-                    if (!vpnIdsOptional.get().isExternalVpn()) {
-                        handleInternalVpnSubnetRoutePacket(metadata, dstIp, srcIpStr, dstIpStr,
-                                ipv4.getDestinationAddress(), vpnIdVpnInstanceName, elanTag);
-                        return;
-                    }
+                handleIpPackets(srcIpBytes, dstIpBytes, srcIpStr, dstIpStr, srcMac, metadata);
 
-                    byte[] srcMac = res.getSourceMACAddress();
-                    handleBgpVpnSubnetRoute(ipv4, srcMac, dstIp, dstIpStr, srcIpStr, elanTag);
-                }
-            } catch (UnknownHostException | InterruptedException | ExecutionException ex) {
+            } catch (UnknownHostException | InterruptedException | ExecutionException | BufferException ex) {
                 // Failed to handle packet
                 vpnManagerCounters.subnetRoutePacketFailed();
                 LOG.error("{} onPacketReceived: Failed to handle subnetroute packet.", LOGGING_PREFIX, ex);
@@ -176,17 +155,71 @@ public class SubnetRoutePacketInHandler implements PacketProcessingListener {
 
     }
 
-    private void handleBgpVpnSubnetRoute(IPv4 ipv4, byte[] srcMac, byte[] dstIp, String dstIpStr, String srcIpStr,
+    private void handleIpPackets(byte[] srcIp, byte[] dstIp, String srcIpStr, String dstIpStr, String srcMac,
+            BigInteger metadata)
+            throws UnknownHostException, InterruptedException, ExecutionException, ReadFailedException {
+        long vpnId = MetaDataUtil.getVpnIdFromMetadata(metadata);
+
+        LOG.info("{} onPacketReceived: Processing IP Packet received with Source IP {} and Target IP {}"
+                + " and vpnId {}", LOGGING_PREFIX, srcIpStr, dstIpStr, vpnId);
+
+        Optional<VpnIds> vpnIdsOptional = SingleTransactionDataBroker.syncReadOptional(dataBroker,
+                LogicalDatastoreType.CONFIGURATION, VpnUtil.getVpnIdToVpnInstanceIdentifier(vpnId));
+
+        if (!vpnIdsOptional.isPresent()) {
+            // Donot trigger subnetroute logic for packets from
+            // unknown VPNs
+            vpnManagerCounters.subnetRoutePacketIgnored();
+            LOG.info("{} onPacketReceived: Ignoring IPv4 packet with destination Ip {} and source Ip {}"
+                    + " as it came on unknown VPN with ID {}", LOGGING_PREFIX, dstIpStr, srcIpStr, vpnId);
+            return;
+        }
+
+        String vpnIdVpnInstanceName = vpnIdsOptional.get().getVpnInstanceName();
+        if (VpnUtil.getNeutronPortFromVpnPortFixedIp(dataBroker, vpnIdVpnInstanceName, dstIpStr) != null) {
+            vpnManagerCounters.subnetRoutePacketIgnored();
+            LOG.info("{} onPacketReceived: IP Packet received with Target IP {} source IP {} vpnId {} "
+                    + "is a valid Neutron port,ignoring subnet route processing", LOGGING_PREFIX, dstIpStr,
+                    srcIp, vpnId);
+            return;
+        }
+
+        if (VpnUtil.getLearntVpnVipToPort(dataBroker, vpnIdVpnInstanceName, dstIpStr) != null) {
+            vpnManagerCounters.subnetRoutePacketIgnored();
+            LOG.info("{} onPacketReceived: IP Packet received with Target IP {} source Ip {} vpnId {}"
+                    + " is an already discovered IPAddress, ignoring subnet route processing",
+                    LOGGING_PREFIX, dstIpStr, srcIp, vpnId);
+            return;
+        }
+
+        long elanTag = MetaDataUtil.getElanTagFromMetadata(metadata);
+        if (elanTag == 0L) {
+            vpnManagerCounters.subnetRoutePacketFailed();
+            LOG.error("{} onPacketReceived: elanTag value from metadata found to be 0, for IP "
+                    + " Packet received with Target IP {} src Ip {} vpnId {}",
+                    LOGGING_PREFIX, dstIpStr, srcIp, vpnId);
+            return;
+        }
+
+        if (!vpnIdsOptional.get().isExternalVpn()) {
+            handleInternalVpnSubnetRoutePacket(metadata, dstIp, srcIpStr, dstIpStr, vpnIdVpnInstanceName,
+                    elanTag);
+            return;
+        }
+
+        handleBgpVpnSubnetRoute(srcMac, dstIp, dstIpStr, srcIpStr, elanTag);
+    }
+
+    private void handleBgpVpnSubnetRoute(String srcMac, byte[] dstIp, String dstIpStr, String srcIpStr,
             long elanTag) throws UnknownHostException {
-        LOG.info("{} handleBgpVpnSubnetRoute: Processing IPv4 Packet received with Source IP {} and Target IP {}"
+        LOG.info("{} handleBgpVpnSubnetRoute: Processing IP Packet received with Source IP {} and Target IP {}"
                 + " and elan Tag {}", LOGGING_PREFIX, srcIpStr, dstIpStr, elanTag);
         SubnetOpDataEntry targetSubnetForPacketOut =
-                getTargetSubnetForPacketOut(dataBroker, elanTag, ipv4.getDestinationAddress());
+                getTargetSubnetForPacketOut(dataBroker, elanTag, dstIpStr);
 
         if (targetSubnetForPacketOut != null) {
             // Handle subnet routes ip requests
-            transmitArpPacket(targetSubnetForPacketOut.getNhDpnId(), srcIpStr, NWUtil.toStringMacAddress(srcMac), dstIp,
-                    elanTag);
+            transmitArpOrNsPacket(targetSubnetForPacketOut.getNhDpnId(), srcIpStr, srcMac, dstIp, dstIpStr, elanTag);
         } else {
             vpnManagerCounters.subnetRoutePacketFailed();
             LOG.debug("{} handleBgpVpnSubnetRoute: Could not find target subnet for packet out {}", LOGGING_PREFIX,
@@ -195,12 +228,11 @@ public class SubnetRoutePacketInHandler implements PacketProcessingListener {
     }
 
     private void handleInternalVpnSubnetRoutePacket(BigInteger metadata, byte[] dstIp, String srcIpStr, String dstIpStr,
-            int destinationAddress, String vpnIdVpnInstanceName, long elanTag)
+            String vpnIdVpnInstanceName, long elanTag)
             throws InterruptedException, ExecutionException, UnknownHostException {
         String vmVpnInterfaceName = VpnUtil.getVpnInterfaceName(odlInterfaceRpcService, metadata);
         if (isTunnel(vmVpnInterfaceName)) {
-            handlePacketFromTunnelToExternalNetwork(vpnIdVpnInstanceName,
-                    srcIpStr, dstIp, elanTag);
+            handlePacketFromTunnelToExternalNetwork(vpnIdVpnInstanceName, srcIpStr, dstIp, dstIpStr, elanTag);
         }
         VpnInterface vmVpnInterface = VpnUtil.getVpnInterface(dataBroker, vmVpnInterfaceName);
         if (vmVpnInterface == null) {
@@ -212,41 +244,50 @@ public class SubnetRoutePacketInHandler implements PacketProcessingListener {
                vmVpnInterface.getVpnInstanceNames())
                && !VpnUtil.isBgpVpnInternet(dataBroker, vpnIdVpnInstanceName)) {
             LOG.trace("Unknown IP is in internal network");
-            handlePacketToInternalNetwork(dstIp, dstIpStr, destinationAddress, elanTag);
+            handlePacketToInternalNetwork(dstIp, dstIpStr, elanTag);
         } else {
             LOG.trace("Unknown IP is in external network");
-            String vpnName = VpnUtil.getInternetVpnFromVpnInstanceList(dataBroker,
-                                vmVpnInterface.getVpnInstanceNames());
+            String vpnName =
+                    VpnUtil.getInternetVpnFromVpnInstanceList(dataBroker, vmVpnInterface.getVpnInstanceNames());
             if (vpnName != null) {
-                handlePacketToExternalNetwork(new Uuid(vpnIdVpnInstanceName),
-                                   vpnName, dstIp, elanTag);
+                handlePacketToExternalNetwork(new Uuid(vpnIdVpnInstanceName), vpnName, dstIp, dstIpStr, elanTag);
             } else {
                 vpnName = VpnHelper.getFirstVpnNameFromVpnInterface(vmVpnInterface);
-                LOG.trace("Unknown IP is in external network, but internet VPN not found."
-                         + " fallback to first VPN");
-                handlePacketToExternalNetwork(new Uuid(vpnIdVpnInstanceName),
-                                   vpnName, dstIp, elanTag);
+                LOG.trace("Unknown IP is in external network, but internet VPN not found." + " fallback to first VPN");
+                handlePacketToExternalNetwork(new Uuid(vpnIdVpnInstanceName), vpnName, dstIp, dstIpStr, elanTag);
 
             }
         }
     }
 
-    private void transmitArpPacket(BigInteger dpnId, String sourceIpAddress, String sourceMac, byte[] dstIp,
-            long elanTag) throws UnknownHostException {
-        LOG.debug("Sending arp with elan tag {}", elanTag);
-        vpnManagerCounters.subnetRoutePacketArpSent();
+    private void transmitArpOrNsPacket(BigInteger dpnId, String sourceIpAddress, String sourceMac, byte[] dstIpBytes,
+            String dstIpAddress, long elanTag) throws UnknownHostException {
         long groupid = VpnUtil.getRemoteBCGroup(elanTag);
-        TransmitPacketInput arpRequestInput = ArpUtils.createArpRequestInput(dpnId, groupid,
-                HexEncode.bytesFromHexString(sourceMac), InetAddress.getByName(sourceIpAddress).getAddress(), dstIp);
+        if (NWUtil.isIpv4Address(dstIpAddress)) {
+            LOG.debug("Sending ARP: srcIp={}, srcMac={}, dstIp={}, dpId={}, elan-tag={}", sourceIpAddress, sourceMac,
+                    dstIpAddress, dpnId, elanTag);
+            vpnManagerCounters.subnetRoutePacketArpSent();
+
+            TransmitPacketInput packetInput =
+                    ArpUtils.createArpRequestInput(dpnId, groupid, HexEncode.bytesFromHexString(sourceMac),
+                            InetAddress.getByName(sourceIpAddress).getAddress(), dstIpBytes);
+            JdkFutures.addErrorLogging(packetService.transmitPacket(packetInput), LOG, "Transmit packet");
+        } else {
+            // IPv6 case
+            LOG.debug("Sending NS: srcIp={}, srcMac={}, dstIp={}, dpId={}, elan-tag={}", sourceIpAddress, sourceMac,
+                    dstIpAddress, dpnId, elanTag);
+            vpnManagerCounters.subnetRoutePacketNsSent();
 
-        JdkFutures.addErrorLogging(packetService.transmitPacket(arpRequestInput), LOG, "Transmit packet");
+            VpnUtil.sendNeighborSolicationToOfGroup(this.ipv6NdutilService, new Ipv6Address(sourceIpAddress),
+                    new MacAddress(sourceMac), new Ipv6Address(dstIpAddress), groupid, dpnId);
+        }
     }
 
-    private void handlePacketToInternalNetwork(byte[] dstIp, String dstIpStr, int destinationAddress, long elanTag)
+    private void handlePacketToInternalNetwork(byte[] dstIp, String dstIpStr, long elanTag)
             throws UnknownHostException {
         try {
             SubnetOpDataEntry targetSubnetForPacketOut =
-                    getTargetSubnetForPacketOut(dataBroker, elanTag, destinationAddress);
+                    getTargetSubnetForPacketOut(dataBroker, elanTag, dstIpStr);
 
             if (targetSubnetForPacketOut == null) {
                 LOG.debug("Couldn't find matching subnet for elan tag {} and destination ip {}", elanTag, dstIpStr);
@@ -278,24 +319,23 @@ public class SubnetRoutePacketInHandler implements PacketProcessingListener {
                 return;
             }
 
-            transmitArpPacket(targetSubnetForPacketOut.getNhDpnId(), sourceIp, sourceMac, dstIp, elanTag);
+            transmitArpOrNsPacket(targetSubnetForPacketOut.getNhDpnId(), sourceIp, sourceMac, dstIp, dstIpStr, elanTag);
         } catch (ReadFailedException e) {
             LOG.error("handlePacketToInternalNetwork: Failed to read data store for destIp {} elanTag {}", dstIpStr,
                     elanTag);
         }
     }
 
-    private void handlePacketFromTunnelToExternalNetwork(String vpnIdVpnInstanceName,
-                        String srcIpStr, byte[] dstIp, long elanTag)
-                                throws UnknownHostException {
+    private void handlePacketFromTunnelToExternalNetwork(String vpnIdVpnInstanceName, String srcIpStr, byte[] dstIp,
+            String dstIpStr, long elanTag) throws UnknownHostException {
         String routerId = VpnUtil.getAssociatedExternalRouter(dataBroker, srcIpStr);
         if (null == routerId) {
             LOG.debug("This ip is not associated with any external router: {}", srcIpStr);
         }
-        handlePacketToExternalNetwork(new Uuid(vpnIdVpnInstanceName), routerId, dstIp, elanTag);
+        handlePacketToExternalNetwork(new Uuid(vpnIdVpnInstanceName), routerId, dstIp, dstIpStr, elanTag);
     }
 
-    private void handlePacketToExternalNetwork(Uuid vpnInstanceNameUuid, String routerId, byte[] dstIp,
+    private void handlePacketToExternalNetwork(Uuid vpnInstanceNameUuid, String routerId, byte[] dstIp, String dstIpStr,
             long elanTag) throws UnknownHostException {
         Routers externalRouter = VpnUtil.getExternalRouter(dataBroker, routerId);
         if (externalRouter == null) {
@@ -330,11 +370,12 @@ public class SubnetRoutePacketInHandler implements PacketProcessingListener {
             return;
         }
 
-        transmitArpPacket(dpnId, externalIp.get().getIpAddress(), externalRouter.getExtGwMacAddress(), dstIp, elanTag);
+        transmitArpOrNsPacket(dpnId, externalIp.get().getIpAddress(), externalRouter.getExtGwMacAddress(), dstIp,
+                dstIpStr, elanTag);
     }
 
     // return only the first VPN subnetopdataentry
-    private static SubnetOpDataEntry getTargetSubnetForPacketOut(DataBroker broker, long elanTag, int ipAddress) {
+    private static SubnetOpDataEntry getTargetSubnetForPacketOut(DataBroker broker, long elanTag, String ipAddress) {
         ElanTagName elanInfo = VpnUtil.getElanInfoByElanTag(broker, elanTag);
         if (elanInfo == null) {
             LOG.error("{} getTargetDpnForPacketOut: Unable to retrieve ElanInfo for elanTag {}", LOGGING_PREFIX,
@@ -371,7 +412,8 @@ public class SubnetRoutePacketInHandler implements PacketProcessingListener {
                 SubnetOpDataEntry subOpEntry = optionalSubs.get();
                 if (subOpEntry.getNhDpnId() != null) {
                     LOG.trace("{} getTargetDpnForPacketOut: Viewing Subnet {}", LOGGING_PREFIX, subnetId.getValue());
-                    boolean match = NWUtil.isIpInSubnet(ipAddress, subOpEntry.getSubnetCidr());
+                    IpPrefix cidr = new IpPrefix(subOpEntry.getSubnetCidr().toCharArray());
+                    boolean match = NWUtil.isIpAddressInRange(new IpAddress(ipAddress.toCharArray()), cidr);
                     LOG.trace("{} getTargetDpnForPacketOut: Viewing Subnet {} matching {}", LOGGING_PREFIX,
                             subnetId.getValue(), match);
                     if (match) {
index b540e853710ebf198a891e18dcd5dd18a5f74b28..c102c0c36e92754b708d4c48f9a09bb9195018d3 100644 (file)
@@ -39,6 +39,11 @@ public interface VpnConstants {
     long LOWER_PSEUDO_LPORT_TAG = Long.getLong("lower.lport.gid", 170001);
     long UPPER_PSEUDO_LPORT_TAG = Long.getLong("upper.lport.gid", 270000);
 
+    int IP_V6_ETHTYPE = 0x86DD;
+    int ETHTYPE_START = 96;
+    int TWO_BYTES = 16;
+    int IP_V6_HDR_START = 112;
+
     enum ITMTunnelLocType {
         Invalid(0), Internal(1), External(2), Hwvtep(3);
 
old mode 100755 (executable)
new mode 100644 (file)
index 8934e11..0c57450
@@ -84,6 +84,7 @@ import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev14081
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.vpn._interface.VpnInstanceNames.AssociatedSubnetType;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.vpn._interface.VpnInstanceNamesBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+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.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
@@ -139,6 +140,10 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev15033
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.ipv6util.rev170210.Ipv6NdutilService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.ipv6util.rev170210.SendNeighborSolicitationToOfGroupInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.ipv6util.rev170210.SendNeighborSolicitationToOfGroupInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.ipv6util.rev170210.SendNeighborSolicitationToOfGroupOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.L3nexthop;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.VpnNexthops;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.VpnNexthopsKey;
@@ -232,10 +237,10 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public final class VpnUtil {
+
     private static final Logger LOG = LoggerFactory.getLogger(VpnUtil.class);
-    private static final int DEFAULT_PREFIX_LENGTH = 32;
+
     static final int SINGLE_TRANSACTION_BROKER_NO_RETRY = 1;
-    private static final String PREFIX_SEPARATOR = "/";
 
     /**
      * Class to generate timestamps with microsecond precision.
@@ -264,12 +269,12 @@ public final class VpnUtil {
     private VpnUtil() {
     }
 
-    static InstanceIdentifier<VpnInterface> getVpnInterfaceIdentifier(String vpnInterfaceName) {
+    public static InstanceIdentifier<VpnInterface> getVpnInterfaceIdentifier(String vpnInterfaceName) {
         return InstanceIdentifier.builder(VpnInterfaces.class)
             .child(VpnInterface.class, new VpnInterfaceKey(vpnInterfaceName)).build();
     }
 
-    static InstanceIdentifier<VpnInterfaceOpDataEntry> getVpnInterfaceOpDataEntryIdentifier(
+    public static InstanceIdentifier<VpnInterfaceOpDataEntry> getVpnInterfaceOpDataEntryIdentifier(
                                                              String vpnInterfaceName, String vpnName) {
         return InstanceIdentifier.builder(VpnInterfaceOpData.class)
             .child(VpnInterfaceOpDataEntry.class,
@@ -441,7 +446,7 @@ public final class VpnUtil {
         return null;
     }
 
-    static List<Adjacency> getAdjacenciesForVpnInterfaceFromConfig(DataBroker broker, String intfName) {
+    public static List<Adjacency> getAdjacenciesForVpnInterfaceFromConfig(DataBroker broker, String intfName) {
         final InstanceIdentifier<VpnInterface> identifier = getVpnInterfaceIdentifier(intfName);
         InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
         Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, path);
@@ -478,7 +483,7 @@ public final class VpnUtil {
         return new AllocatedRdsBuilder().withKey(new AllocatedRdsKey(nexthop)).setNexthop(nexthop).setRd(rd);
     }
 
-    static Adjacencies getVpnInterfaceAugmentation(List<Adjacency> nextHopList) {
+    public static Adjacencies getVpnInterfaceAugmentation(List<Adjacency> nextHopList) {
         return new AdjacenciesBuilder().setAdjacency(nextHopList).build();
     }
 
@@ -809,7 +814,8 @@ public final class VpnUtil {
         return read(broker, LogicalDatastoreType.CONFIGURATION, interfaceId).isPresent();
     }
 
-    static Optional<List<String>> getVpnHandlingIpv4AssociatedWithInterface(DataBroker broker, String interfaceName) {
+    public static Optional<List<String>> getVpnHandlingAssociatedWithInterface(DataBroker broker,
+            String interfaceName) {
         InstanceIdentifier<VpnInterface> interfaceId = getVpnInterfaceIdentifier(interfaceName);
         Optional<List<String>> vpnOptional = Optional.absent();
         Optional<VpnInterface> optConfiguredVpnInterface = read(broker, LogicalDatastoreType.CONFIGURATION,
@@ -821,9 +827,6 @@ public final class VpnUtil {
             if (optVpnInstanceList.isPresent()) {
                 List<String> vpnList = new ArrayList<>();
                 for (VpnInstanceNames vpnInstance : optVpnInstanceList.get()) {
-                    if (vpnInstance.getAssociatedSubnetType().equals(AssociatedSubnetType.V6Subnet)) {
-                        continue;
-                    }
                     vpnList.add(vpnInstance.getVpnName());
                 }
                 vpnOptional = Optional.of(vpnList);
@@ -835,7 +838,7 @@ public final class VpnUtil {
     public static String getIpPrefix(String prefix) {
         String[] prefixValues = prefix.split("/");
         if (prefixValues.length == 1) {
-            prefix = prefix + PREFIX_SEPARATOR + DEFAULT_PREFIX_LENGTH;
+            prefix = NWUtil.toIpPrefix(prefix);
         }
         return prefix;
     }
@@ -992,7 +995,7 @@ public final class VpnUtil {
         }
     }
 
-    protected static void createLearntVpnVipToPort(DataBroker broker, String vpnName, String fixedIp, String
+    public static void createLearntVpnVipToPort(DataBroker broker, String vpnName, String fixedIp, String
             portName, String macAddress, WriteTransaction writeOperTxn) {
         synchronized ((vpnName + fixedIp).intern()) {
             InstanceIdentifier<LearntVpnVipToPort> id = buildLearntVpnVipToPortIdentifier(vpnName, fixedIp);
@@ -1006,7 +1009,7 @@ public final class VpnUtil {
             } else {
                 MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id, builder.build());
             }
-            LOG.debug("createLearntVpnVipToPort: ARP learned for fixedIp: {}, vpn {}, interface {}, mac {},"
+            LOG.debug("createLearntVpnVipToPort: ARP/NA learned for fixedIp: {}, vpn {}, interface {}, mac {},"
                     + " added to LearntVpnVipToPort DS", fixedIp, vpnName, portName, macAddress);
         }
     }
@@ -1017,8 +1020,8 @@ public final class VpnUtil {
                 new LearntVpnVipToPortKey(fixedIp, vpnName)).build();
     }
 
-    protected static void removeLearntVpnVipToPort(DataBroker broker, String vpnName, String fixedIp,
-                                                   WriteTransaction writeOperTxn) {
+    public static void removeLearntVpnVipToPort(DataBroker broker, String vpnName, String fixedIp,
+            WriteTransaction writeOperTxn) {
         synchronized ((vpnName + fixedIp).intern()) {
             InstanceIdentifier<LearntVpnVipToPort> id = buildLearntVpnVipToPortIdentifier(vpnName, fixedIp);
             if (writeOperTxn != null) {
@@ -1045,7 +1048,7 @@ public final class VpnUtil {
         }
     }
 
-    protected static void createLearntVpnVipToPortEvent(DataBroker broker, String vpnName, String srcIp, String destIP,
+    public static void createLearntVpnVipToPortEvent(DataBroker broker, String vpnName, String srcIp, String destIP,
                                                         String portName, String macAddress,
                                                         LearntVpnVipToPortEventAction action,
                                                         WriteTransaction writeOperTxn) {
@@ -1149,7 +1152,7 @@ public final class VpnUtil {
         return null;
     }
 
-    static LearntVpnVipToPort getLearntVpnVipToPort(DataBroker broker, String vpnName, String fixedIp) {
+    public static LearntVpnVipToPort getLearntVpnVipToPort(DataBroker broker, String vpnName, String fixedIp) {
         InstanceIdentifier<LearntVpnVipToPort> id = buildLearntVpnVipToPortIdentifier(vpnName, fixedIp);
         Optional<LearntVpnVipToPort> learntVpnVipToPort = read(broker, LogicalDatastoreType.OPERATIONAL, id);
         if (learntVpnVipToPort.isPresent()) {
@@ -1230,7 +1233,7 @@ public final class VpnUtil {
         return extNetwork != null ? extNetwork.getVpnid() : null;
     }
 
-    static List<Uuid> getExternalNetworkRouterIds(DataBroker dataBroker, Uuid networkId) {
+    public static List<Uuid> getExternalNetworkRouterIds(DataBroker dataBroker, Uuid networkId) {
         Networks extNetwork = getExternalNetwork(dataBroker, networkId);
         return extNetwork != null ? extNetwork.getRouterIds() : Collections.emptyList();
     }
@@ -1672,7 +1675,7 @@ public final class VpnUtil {
         return optionalSubnets.isPresent() ? optionalSubnets.get() : null;
     }
 
-    static Uuid getSubnetFromExternalRouterByIp(DataBroker dataBroker, Uuid routerId, String ip) {
+    public static Uuid getSubnetFromExternalRouterByIp(DataBroker dataBroker, Uuid routerId, String ip) {
         Routers externalRouter = VpnUtil.getExternalRouter(dataBroker, routerId.getValue());
         if (externalRouter != null && externalRouter.getExternalIps() != null) {
             for (ExternalIps externalIp : externalRouter.getExternalIps()) {
@@ -2303,4 +2306,22 @@ public final class VpnUtil {
             }
         }
     }
+
+    public static void sendNeighborSolicationToOfGroup(Ipv6NdutilService ipv6NdutilService, Ipv6Address srcIpv6Address,
+            MacAddress srcMac, Ipv6Address dstIpv6Address, Long ofGroupId, BigInteger dpId) {
+        SendNeighborSolicitationToOfGroupInput input = new SendNeighborSolicitationToOfGroupInputBuilder()
+                .setSourceIpv6(srcIpv6Address).setSourceLlAddress(srcMac).setTargetIpAddress(dstIpv6Address)
+                .setOfGroupId(ofGroupId).setDpId(dpId).build();
+        try {
+            Future<RpcResult<SendNeighborSolicitationToOfGroupOutput>> result = ipv6NdutilService
+                    .sendNeighborSolicitationToOfGroup(input);
+            RpcResult<SendNeighborSolicitationToOfGroupOutput> rpcResult = result.get();
+            if (!rpcResult.isSuccessful()) {
+                LOG.error("sendNeighborSolicitationToOfGroup: RPC Call failed for input={} and Errors={}", input,
+                        rpcResult.getErrors());
+            }
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Failed to send NS packet to ELAN group, input={}", input, e);
+        }
+    }
 }
diff --git a/vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/iplearn/AbstractIpLearnNotificationHandler.java b/vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/iplearn/AbstractIpLearnNotificationHandler.java
new file mode 100644 (file)
index 0000000..4159843
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2018 Alten Calsoft Labs India Pvt Ltd. 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.vpnmanager.iplearn;
+
+import com.google.common.base.Optional;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import java.math.BigInteger;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.commons.lang3.tuple.Pair;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
+import org.opendaylight.genius.mdsalutil.NWUtil;
+import org.opendaylight.netvirt.vpnmanager.VpnUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.LearntVpnVipToPortEventAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPort;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.config.rev161130.VpnConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AbstractIpLearnNotificationHandler {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractIpLearnNotificationHandler.class);
+
+    // temp where Key is VPNInstance+IP and value is timestamp
+    private final Cache<Pair<String, String>, BigInteger> migrateIpCache;
+
+    protected final DataBroker dataBroker;
+    protected final IdManagerService idManager;
+    protected final IInterfaceManager interfaceManager;
+    protected final VpnConfig config;
+
+    public AbstractIpLearnNotificationHandler(DataBroker dataBroker, IdManagerService idManager,
+            IInterfaceManager interfaceManager, VpnConfig vpnConfig) {
+        this.dataBroker = dataBroker;
+        this.idManager = idManager;
+        this.interfaceManager = interfaceManager;
+        this.config = vpnConfig;
+
+        long duration = config.getArpLearnTimeout() * 10;
+        long cacheSize = config.getArpCacheSize().longValue();
+        migrateIpCache =
+                CacheBuilder.newBuilder().maximumSize(cacheSize).expireAfterWrite(duration,
+                        TimeUnit.MILLISECONDS).build();
+    }
+
+    protected void validateAndProcessIpLearning(String srcInterface, IpAddress srcIP, MacAddress srcMac,
+            IpAddress targetIP, BigInteger metadata) {
+        List<Adjacency> adjacencies = VpnUtil.getAdjacenciesForVpnInterfaceFromConfig(dataBroker, srcInterface);
+        if (adjacencies != null) {
+            for (Adjacency adj : adjacencies) {
+                IpPrefix ipPrefix = new IpPrefix(adj.getIpAddress().toCharArray());
+                if (NWUtil.isIpAddressInRange(srcIP, ipPrefix)) {
+                    return;
+                }
+            }
+        }
+
+        LOG.trace("ARP/NA Notification Response Received from interface {} and IP {} having MAC {}, learning MAC",
+                srcInterface, String.valueOf(srcIP.getValue()), srcMac.getValue());
+        processIpLearning(srcInterface, srcIP, srcMac, metadata, targetIP);
+    }
+
+    protected void processIpLearning(String srcInterface, IpAddress srcIP, MacAddress srcMac, BigInteger metadata,
+            IpAddress dstIP) {
+        if (metadata != null && !Objects.equals(metadata, BigInteger.ZERO)) {
+            Optional<List<String>> vpnList = VpnUtil.getVpnHandlingAssociatedWithInterface(dataBroker, srcInterface);
+            if (vpnList.isPresent()) {
+                String srcIpToQuery = String.valueOf(srcIP.getValue());
+                String destIpToQuery = String.valueOf(dstIP.getValue());
+                for (String vpnName : vpnList.get()) {
+                    LOG.info("Received ARP/NA for sender MAC {} and sender IP {} via interface {}",
+                              srcMac.getValue(), srcIpToQuery, srcInterface);
+                    VpnPortipToPort vpnPortipToPort =
+                            VpnUtil.getNeutronPortFromVpnPortFixedIp(dataBroker, vpnName, srcIpToQuery);
+                    if (vpnPortipToPort != null) {
+                        /* This is a well known neutron port and so should be ignored
+                         * from being discovered
+                         */
+                        continue;
+                    }
+                    LearntVpnVipToPort learntVpnVipToPort = VpnUtil.getLearntVpnVipToPort(dataBroker,
+                              vpnName, srcIpToQuery);
+                    if (learntVpnVipToPort != null) {
+                        String oldPortName = learntVpnVipToPort.getPortName();
+                        String oldMac = learntVpnVipToPort.getMacAddress();
+                        if (!oldMac.equalsIgnoreCase(srcMac.getValue())) {
+                            //MAC has changed for requested IP
+                            LOG.info("ARP/NA Source IP/MAC data modified for IP {} with MAC {} and Port {}",
+                                    srcIpToQuery, srcMac, srcInterface);
+                            synchronized ((vpnName + srcIpToQuery).intern()) {
+                                VpnUtil.createLearntVpnVipToPortEvent(dataBroker, vpnName, srcIpToQuery, destIpToQuery,
+                                        oldPortName, oldMac, LearntVpnVipToPortEventAction.Delete, null);
+                                putVpnIpToMigrateIpCache(vpnName, srcIpToQuery, srcMac);
+                            }
+                        }
+                    } else if (!isIpInMigrateCache(vpnName, srcIpToQuery)) {
+                        learnMacFromIncomingPacket(vpnName, srcInterface, srcIP, srcMac, dstIP);
+                    }
+                }
+            } else {
+                LOG.info("IP LEARN NO_RESOLVE: VPN  not configured. Ignoring responding to ARP/NA requests from this"
+                        + " Interface {}.", srcInterface);
+                return;
+
+            }
+        }
+    }
+
+    private void learnMacFromIncomingPacket(String vpnName, String srcInterface, IpAddress srcIP, MacAddress srcMac,
+            IpAddress dstIP) {
+        String srcIpToQuery = String.valueOf(srcIP.getValue());
+        String destIpToQuery = String.valueOf(dstIP.getValue());
+        synchronized ((vpnName + srcIpToQuery).intern()) {
+            VpnUtil.createLearntVpnVipToPortEvent(dataBroker, vpnName, srcIpToQuery, destIpToQuery, srcInterface,
+                    srcMac.getValue(), LearntVpnVipToPortEventAction.Add, null);
+        }
+    }
+
+    private void putVpnIpToMigrateIpCache(String vpnName, String ipToQuery, MacAddress srcMac) {
+        long cacheSize = config.getArpCacheSize().longValue();
+        if (migrateIpCache.size() >= cacheSize) {
+            LOG.debug("IP_MIGRATE_CACHE: max size {} reached, assuming cache eviction we still put IP {}"
+                    + " vpnName {} with MAC {}", cacheSize, ipToQuery, vpnName, srcMac);
+        }
+        LOG.debug("IP_MIGRATE_CACHE: add to dirty cache IP {} vpnName {} with MAC {}", ipToQuery, vpnName, srcMac);
+        migrateIpCache.put(new ImmutablePair<>(vpnName, ipToQuery),
+                new BigInteger(String.valueOf(System.currentTimeMillis())));
+    }
+
+    private boolean isIpInMigrateCache(String vpnName, String ipToQuery) {
+        if (migrateIpCache == null || migrateIpCache.size() == 0) {
+            return false;
+        }
+        Pair<String, String> keyPair = new ImmutablePair<>(vpnName, ipToQuery);
+        BigInteger prevTimeStampCached = migrateIpCache.getIfPresent(keyPair);
+        if (prevTimeStampCached == null) {
+            LOG.debug("IP_MIGRATE_CACHE: there is no IP {} vpnName {} in dirty cache, so learn it",
+                    ipToQuery, vpnName);
+            return false;
+        }
+        if (System.currentTimeMillis() > prevTimeStampCached.longValue() + config.getArpLearnTimeout()) {
+            LOG.debug("IP_MIGRATE_CACHE: older than timeout value - remove from dirty cache IP {} vpnName {}",
+                    ipToQuery, vpnName);
+            migrateIpCache.invalidate(keyPair);
+            return false;
+        }
+        LOG.debug("IP_MIGRATE_CACHE: younger than timeout value - ignore learning IP {} vpnName {}",
+                ipToQuery, vpnName);
+        return true;
+    }
+}
diff --git a/vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/iplearn/ArpNotificationHandler.java b/vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/iplearn/ArpNotificationHandler.java
new file mode 100644 (file)
index 0000000..03630b5
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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.vpnmanager.iplearn;
+
+import java.math.BigInteger;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.ArpRequestReceived;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.ArpResponseReceived;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.MacChanged;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.config.rev161130.VpnConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public class ArpNotificationHandler extends AbstractIpLearnNotificationHandler implements OdlArputilListener {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ArpNotificationHandler.class);
+
+    @Inject
+    public ArpNotificationHandler(DataBroker dataBroker, IdManagerService idManager,
+                                  IInterfaceManager interfaceManager, VpnConfig vpnConfig) {
+        super(dataBroker, idManager, interfaceManager, vpnConfig);
+    }
+
+    @Override
+    public void onMacChanged(MacChanged notification) {
+
+    }
+
+    @Override
+    public void onArpRequestReceived(ArpRequestReceived notification) {
+        String srcInterface = notification.getInterface();
+        IpAddress srcIP = notification.getSrcIpaddress();
+        MacAddress srcMac = MacAddress.getDefaultInstance(notification.getSrcMac().getValue());
+        IpAddress targetIP = notification.getDstIpaddress();
+        BigInteger metadata = notification.getMetadata();
+        boolean isGarp = srcIP.equals(targetIP);
+        if (!isGarp) {
+            LOG.info(
+                    "ArpNotification Non-Gratuitous Request Received from "
+                            + "interface {} and IP {} having MAC {} target destination {}, ignoring..",
+                    srcInterface, String.valueOf(srcIP.getValue()), srcMac.getValue(),
+                    String.valueOf(targetIP.getValue()));
+            return;
+        }
+        LOG.info(
+                "ArpNotification Gratuitous Request Received from interface {} and IP {} having MAC {} "
+                        + "target destination {}, learning MAC",
+                srcInterface, String.valueOf(srcIP.getValue()), srcMac.getValue(), String.valueOf(targetIP.getValue()));
+
+        processIpLearning(srcInterface, srcIP, srcMac, metadata, targetIP);
+    }
+
+    @Override
+    public void onArpResponseReceived(ArpResponseReceived notification) {
+        String srcInterface = notification.getInterface();
+        IpAddress srcIP = notification.getSrcIpaddress();
+        MacAddress srcMac = MacAddress.getDefaultInstance(notification.getSrcMac().getValue());
+        BigInteger metadata = notification.getMetadata();
+        IpAddress targetIP = notification.getDstIpaddress();
+        LOG.info("ArpNotification Response Received from interface {} and IP {} having MAC {}, learning MAC",
+                srcInterface, String.valueOf(srcIP.getValue()), srcMac.getValue());
+
+        validateAndProcessIpLearning(srcInterface, srcIP, srcMac, targetIP, metadata);
+    }
+}
diff --git a/vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/iplearn/Ipv6NaNotificationHandler.java b/vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/iplearn/Ipv6NaNotificationHandler.java
new file mode 100644 (file)
index 0000000..18a3e26
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2018 Alten Calsoft Labs India Pvt Ltd. 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.vpnmanager.iplearn;
+
+import java.math.BigInteger;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.ipv6util.rev170210.Ipv6NdutilListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.ipv6util.rev170210.NaReceived;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.config.rev161130.VpnConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public class Ipv6NaNotificationHandler extends AbstractIpLearnNotificationHandler implements Ipv6NdutilListener {
+
+    private static final Logger LOG = LoggerFactory.getLogger(Ipv6NaNotificationHandler.class);
+
+    @Inject
+    public Ipv6NaNotificationHandler(DataBroker dataBroker, IdManagerService idManager,
+            IInterfaceManager interfaceManager, VpnConfig vpnConfig) {
+        super(dataBroker, idManager, interfaceManager, vpnConfig);
+    }
+
+    @Override
+    public void onNaReceived(NaReceived naPacket) {
+        String srcInterface = naPacket.getInterface();
+        IpAddress srcIP = new IpAddress(naPacket.getSourceIpv6());
+        MacAddress srcMac = naPacket.getSourceMac();
+        IpAddress targetIP = new IpAddress(naPacket.getTargetAddress());
+        BigInteger metadata = naPacket.getMetadata();
+        LOG.debug("NA notification received from interface {} and IP {} having MAC {}, targetIP={}", srcInterface,
+                String.valueOf(srcIP.getValue()), srcMac.getValue(), String.valueOf(targetIP.getValue()));
+
+        validateAndProcessIpLearning(srcInterface, srcIP, srcMac, targetIP, metadata);
+    }
+}
index 308bfb33d6b176537a3d9a5e0c9c4c748b9a1570..308987d37ccb1eda9e1e3ac6c0a0ad416c8529a1 100644 (file)
@@ -18,6 +18,7 @@ public class VpnManagerCounters {
     private final Meter subnetRoutePacketIgnoredMeter;
     private final Meter subnetRoutePacketFailedMeter;
     private final Meter subnetRoutePacketArpSentMeter;
+    private final Meter subnetRoutePacketNsSentMeter;
     private final Meter garpAddNotificationMeter;
     private final Meter garpUpdateNotificationMeter;
     private final Meter garpSentMeter;
@@ -30,6 +31,7 @@ public class VpnManagerCounters {
         this.subnetRoutePacketIgnoredMeter = meter(metricProvider, "subnet_route_packet_ignored");
         this.subnetRoutePacketFailedMeter = meter(metricProvider, "subnet_route_packet_failed");
         this.subnetRoutePacketArpSentMeter = meter(metricProvider, "subnet_route_packet_arp_sent");
+        this.subnetRoutePacketNsSentMeter = meter(metricProvider, "subnet_route_packet_ns_sent");
         this.garpAddNotificationMeter = meter(metricProvider, "garp_add_notification");
         this.garpUpdateNotificationMeter = meter(metricProvider, "garp_update_notification");
         this.garpSentMeter = meter(metricProvider, "garp_sent");
@@ -55,6 +57,10 @@ public class VpnManagerCounters {
         subnetRoutePacketArpSentMeter.mark();
     }
 
+    public void subnetRoutePacketNsSent() {
+        subnetRoutePacketNsSentMeter.mark();
+    }
+
     public void garpAddNotification() {
         garpAddNotificationMeter.mark();
     }
index 8422ed3ac248cbef5af73d21dc863737a8431eb6..6fb21aaeadb2f39b408985e11d02e0393536ac0c 100644 (file)
@@ -48,6 +48,8 @@
                    interface="org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.AlivenessMonitorService" />
   <odl:rpc-service id="itmRpcService"
                    interface="org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService"/>
+  <odl:rpc-service id="ipv6NdutilService"
+                   interface="org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.ipv6util.rev170210.Ipv6NdutilService"/>
 
   <service ref="dpnInVpnChangeListener" odl:type="default"
            interface="org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.OdlL3vpnListener" />
            interface="org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilListener" />
   <odl:notification-listener ref="arpNotificationHandler" />
 
+  <service ref="ipv6NaNotificationHandler" odl:type="default"
+           interface="org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.ipv6util.rev170210.Ipv6NdutilListener" />
+  <odl:notification-listener ref="ipv6NaNotificationHandler" />
+
   <service ref="vpnManagerImpl"
            interface="org.opendaylight.netvirt.vpnmanager.api.IVpnManager" />