NETVIRT-1033: Adding ArpResponder flows for SR-IOV VMs 39/65539/36
authorAchuth Maniyedath <achuth.m@altencalsoftlabs.com>
Sat, 23 Sep 2017 12:50:14 +0000 (18:20 +0530)
committerSam Hague <shague@redhat.com>
Wed, 14 Feb 2018 21:57:03 +0000 (21:57 +0000)
DHCP Neutron Port ARP handling for SR-IOV VMs.
Handled removal of stale flows entry from ArpResponderTable.

New pipeline for processing Neutron port DHCP ARPs
Table 0 -> Table 18 -> Table 38 -> Table 81

Change-Id: Id5ee3160240cfcb6caec5790734d9f003c16640e
Signed-off-by: Achuth Maniyedath <achuth.maniyedath@gmail.com>
Signed-off-by: Vijayalakshmi Chickkamenahalli Nagaraju <vijayalakshmi.c@altencalsoftlabs.com>
13 files changed:
vpnservice/dhcpservice/dhcpservice-api/src/main/java/org/opendaylight/netvirt/dhcpservice/api/DhcpMConstants.java
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/netvirt/dhcpservice/DhcpDesignatedDpnListener.java
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/netvirt/dhcpservice/DhcpExternalTunnelManager.java
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/netvirt/dhcpservice/DhcpInterfaceEventListener.java
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/netvirt/dhcpservice/DhcpManager.java
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/netvirt/dhcpservice/DhcpNeutronPortListener.java
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/netvirt/dhcpservice/DhcpPktHandler.java
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/netvirt/dhcpservice/DhcpPortCache.java [new file with mode: 0644]
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/netvirt/dhcpservice/DhcpServiceUtils.java
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/netvirt/dhcpservice/jobs/DhcpInterfaceRemoveJob.java
vpnservice/elanmanager/elanmanager-api/src/main/java/org/opendaylight/netvirt/elanmanager/api/IElanService.java
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanServiceProvider.java
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/netvirt/elan/utils/ElanUtils.java

index 52300ea5683b2a83531404af852e69dbebd0d075..99f7f746ecd3cbc243c6e738d824e25dbbac7b76 100644 (file)
@@ -16,6 +16,7 @@ public interface DhcpMConstants {
 
     int DEFAULT_DHCP_FLOW_PRIORITY = 50;
     int DEFAULT_DHCP_ALLOCATION_POOL_FLOW_PRIORITY = DEFAULT_DHCP_FLOW_PRIORITY - 1;
+    int DEFAULT_DHCP_ARP_FLOW_PRIORITY = 10;
     int ARP_FLOW_PRIORITY = 50;
     short DEFAULT_FLOW_PRIORITY = 100;
 
index af89ba41d0510b59862c07204ab8d57d8153d1bb..3397b749b25e50d780ca313fae2cbec7dab5bd1a 100644 (file)
@@ -18,6 +18,7 @@ import org.opendaylight.genius.datastoreutils.AsyncClusteredDataTreeChangeListen
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.DesignatedSwitchesForExternalTunnels;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710.subnet.dhcp.port.data.SubnetToDhcpPort;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.config.rev150710.DhcpserviceConfig;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -63,19 +64,41 @@ public class DhcpDesignatedDpnListener
                 del.getTunnelRemoteIpAddress(), del.getElanInstanceName());
         dhcpExternalTunnelManager.unInstallDhcpFlowsForVms(del.getElanInstanceName(),
                 del.getTunnelRemoteIpAddress(), DhcpServiceUtils.getListOfDpns(broker));
+        LOG.trace("Removing designated DPN {} DHCP Arp Flows for Elan {}.", del.getDpId(), del.getElanInstanceName());
+        java.util.Optional<SubnetToDhcpPort> subnetDhcpData = dhcpExternalTunnelManager
+                .getSubnetDhcpPortData(del.getElanInstanceName());
+        if (subnetDhcpData.isPresent()) {
+            dhcpExternalTunnelManager.configureDhcpArpRequestResponseFlow(BigInteger.valueOf(del.getDpId()),
+                    del.getElanInstanceName(), false, del.getTunnelRemoteIpAddress(),
+                    subnetDhcpData.get().getPortFixedip(), subnetDhcpData.get().getPortMacaddress());
+        }
+
     }
 
     @Override
     protected void update(InstanceIdentifier<DesignatedSwitchForTunnel> identifier, DesignatedSwitchForTunnel original,
             DesignatedSwitchForTunnel update) {
         LOG.debug("Update for DesignatedSwitchForTunnel original {}, update {}", original, update);
+        dhcpExternalTunnelManager.removeFromLocalCache(BigInteger.valueOf(original.getDpId()),
+                original.getTunnelRemoteIpAddress(), original.getElanInstanceName());
         BigInteger designatedDpnId = BigInteger.valueOf(update.getDpId());
         IpAddress tunnelRemoteIpAddress = update.getTunnelRemoteIpAddress();
         String elanInstanceName = update.getElanInstanceName();
-        dhcpExternalTunnelManager.removeFromLocalCache(BigInteger.valueOf(original.getDpId()),
-                original.getTunnelRemoteIpAddress(), original.getElanInstanceName());
         dhcpExternalTunnelManager.updateLocalCache(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName);
         dhcpExternalTunnelManager.installRemoteMcastMac(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName);
+        java.util.Optional<SubnetToDhcpPort> subnetDhcpData = dhcpExternalTunnelManager
+                .getSubnetDhcpPortData(elanInstanceName);
+        if (subnetDhcpData.isPresent()) {
+            LOG.trace("Removing Designated DPN {} DHCP Arp Flows for Elan {}.", original.getDpId(),
+                    original.getElanInstanceName());
+            dhcpExternalTunnelManager.configureDhcpArpRequestResponseFlow(BigInteger.valueOf(original.getDpId()),
+                    original.getElanInstanceName(), false, original.getTunnelRemoteIpAddress(),
+                    subnetDhcpData.get().getPortFixedip(), subnetDhcpData.get().getPortMacaddress());
+            LOG.trace("Configuring DHCP Arp Flows for Designated dpn {} Elan {}", designatedDpnId, elanInstanceName);
+            dhcpExternalTunnelManager.configureDhcpArpRequestResponseFlow(designatedDpnId, elanInstanceName,
+                    true, tunnelRemoteIpAddress, subnetDhcpData.get().getPortFixedip(),
+                    subnetDhcpData.get().getPortMacaddress());
+        }
     }
 
     @Override
@@ -86,6 +109,14 @@ public class DhcpDesignatedDpnListener
         String elanInstanceName = add.getElanInstanceName();
         dhcpExternalTunnelManager.updateLocalCache(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName);
         dhcpExternalTunnelManager.installRemoteMcastMac(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName);
+        LOG.trace("Configuring DHCP Arp Flows for Designated dpn {} Elan {}", designatedDpnId, elanInstanceName);
+        java.util.Optional<SubnetToDhcpPort> subnetDhcpData = dhcpExternalTunnelManager
+                .getSubnetDhcpPortData(elanInstanceName);
+        if (subnetDhcpData.isPresent()) {
+            dhcpExternalTunnelManager.configureDhcpArpRequestResponseFlow(designatedDpnId, elanInstanceName,
+                    true, tunnelRemoteIpAddress, subnetDhcpData.get().getPortFixedip(),
+                    subnetDhcpData.get().getPortMacaddress());
+        }
     }
 
     @Override
index 4d547c0b8f5c9d1df9005107a9f7bf508aed8db8..134529fda1f209e9c64ff00df3bd34e41bf6e9f1 100644 (file)
@@ -26,6 +26,7 @@ import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import javax.annotation.PostConstruct;
 import javax.inject.Inject;
+import javax.inject.Named;
 import javax.inject.Singleton;
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
@@ -48,6 +49,9 @@ import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipService;
 import org.opendaylight.netvirt.dhcpservice.api.DhcpMConstants;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderInput;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderUtil;
+import org.opendaylight.netvirt.elanmanager.api.IElanService;
 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayCache;
 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
@@ -67,9 +71,13 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.Desi
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnel;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710.subnet.dhcp.port.data.SubnetToDhcpPort;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepLogicalSwitchRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorRef;
@@ -100,6 +108,7 @@ public class DhcpExternalTunnelManager {
     private final IInterfaceManager interfaceManager;
     private final JobCoordinator jobCoordinator;
     private final L2GatewayCache l2GatewayCache;
+    private IElanService elanService;
 
     private final ConcurrentMap<BigInteger, Set<Pair<IpAddress, String>>> designatedDpnsToTunnelIpElanNameCache =
             new ConcurrentHashMap<>();
@@ -112,7 +121,8 @@ public class DhcpExternalTunnelManager {
     public DhcpExternalTunnelManager(final DataBroker broker,
             final IMdsalApiManager mdsalUtil, final ItmRpcService itmRpcService,
             final EntityOwnershipService entityOwnershipService, final IInterfaceManager interfaceManager,
-            final JobCoordinator jobCoordinator, final L2GatewayCache l2GatewayCache) {
+            final JobCoordinator jobCoordinator, final L2GatewayCache l2GatewayCache,
+            @Named("elanService") IElanService ielanService) {
         this.broker = broker;
         this.txRunner = new ManagedNewTransactionRunnerImpl(broker);
         this.mdsalUtil = mdsalUtil;
@@ -121,6 +131,7 @@ public class DhcpExternalTunnelManager {
         this.interfaceManager = interfaceManager;
         this.jobCoordinator = jobCoordinator;
         this.l2GatewayCache = l2GatewayCache;
+        this.elanService = ielanService;
     }
 
     @PostConstruct
@@ -398,6 +409,11 @@ public class DhcpExternalTunnelManager {
             LOG.trace("Updating DHCP flows for VMs {} with new designated DPN {}", setOfVmMacs, newDesignatedDpn);
             installDhcpFlowsForVms(newDesignatedDpn, setOfVmMacs, tx);
         }
+        java.util.Optional<SubnetToDhcpPort> subnetDhcpData = getSubnetDhcpPortData(pair.getRight());
+        if (subnetDhcpData.isPresent()) {
+            configureDhcpArpRequestResponseFlow(newDesignatedDpn, pair.getRight(), true,
+                    pair.getLeft(), subnetDhcpData.get().getPortFixedip(), subnetDhcpData.get().getPortMacaddress());
+        }
     }
 
     private void changeExistingFlowToDrop(Pair<IpAddress, String> tunnelIpElanNamePair, BigInteger dpnId,
@@ -476,6 +492,122 @@ public class DhcpExternalTunnelManager {
                 vmMacAddress, NwConstants.ADD_FLOW, mdsalUtil, tx);
     }
 
+    public void addOrRemoveDhcpArpFlowforElan(String elanInstanceName, boolean addFlow, String dhcpIpAddress,
+                                              String dhcpMacAddress) {
+        LOG.trace("Configure DHCP SR-IOV Arp flows for Elan {} dpns .", elanInstanceName);
+        for (Entry<BigInteger, Set<Pair<IpAddress,String>>> entry : designatedDpnsToTunnelIpElanNameCache.entrySet()) {
+            BigInteger dpn = entry.getKey();
+            Set<Pair<IpAddress,String>> tunnelIpElanNameSet = entry.getValue();
+            for (Pair<IpAddress, String> pair : tunnelIpElanNameSet) {
+                if (pair.getRight().equalsIgnoreCase(elanInstanceName)) {
+                    if (addFlow) {
+                        LOG.trace("Adding SR-IOV DHCP Arp Flows for Elan {} and tunnelIp {}",
+                                elanInstanceName, pair.getLeft());
+                        configureDhcpArpRequestResponseFlow(dpn, elanInstanceName, true,
+                                pair.getLeft(), dhcpIpAddress, dhcpMacAddress);
+                    } else {
+                        LOG.trace("Deleting SR-IOV DHCP Arp Flows for Elan {} and tunnelIp {}",
+                                elanInstanceName, pair.getLeft());
+                        configureDhcpArpRequestResponseFlow(dpn, elanInstanceName, false,
+                                pair.getLeft(), dhcpIpAddress, dhcpMacAddress);
+                    }
+                }
+            }
+        }
+    }
+
+
+    public void configureDhcpArpRequestResponseFlow(BigInteger dpnId, String elanInstanceName, boolean addFlow,
+                                            IpAddress tunnelIp, String dhcpIpAddress, String dhcpMacAddress) {
+        L2GatewayDevice device = getDeviceFromTunnelIp(elanInstanceName, tunnelIp);
+        if (device == null) {
+            LOG.error("Unable to get L2Device for tunnelIp {} and elanInstanceName {}", tunnelIp,
+                    elanInstanceName);
+        }
+        jobCoordinator.enqueueJob(getJobKey(elanInstanceName), () -> {
+            if (entityOwnershipUtils.isEntityOwner(HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+                    HwvtepSouthboundConstants.ELAN_ENTITY_NAME)) {
+                String tunnelInterfaceName = getExternalTunnelInterfaceName(String.valueOf(dpnId),
+                        device.getHwvtepNodeId());
+                int lportTag = interfaceManager.getInterfaceInfo(tunnelInterfaceName).getInterfaceTag();
+                InstanceIdentifier<ElanInstance> elanIdentifier = InstanceIdentifier.builder(ElanInstances.class)
+                        .child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
+                Optional<ElanInstance> optElan = MDSALUtil.read(broker,
+                        LogicalDatastoreType.CONFIGURATION, elanIdentifier);
+                if (optElan.isPresent()) {
+                    LOG.trace("Configuring the SR-IOV Arp request/response flows for LPort {} ElanTag {}.",
+                            lportTag, optElan.get().getElanTag());
+                    Uuid nwUuid = new Uuid(elanInstanceName);
+                    String strVni = DhcpServiceUtils.getSegmentationId(nwUuid, broker);
+                    BigInteger vni = strVni != null ? new BigInteger(strVni) : BigInteger.ZERO;
+                    if (!vni.equals(BigInteger.ZERO)) {
+                        if (addFlow) {
+                            LOG.trace("Installing the SR-IOV DHCP Arp flow for DPN {} Port Ip {}, Lport {}.",
+                                    dpnId, dhcpIpAddress, lportTag);
+                            installDhcpArpRequestFlows(dpnId, vni, dhcpIpAddress, lportTag,
+                                    optElan.get().getElanTag());
+                            installDhcpArpResponderFlows(dpnId, tunnelInterfaceName, lportTag, elanInstanceName,
+                                    dhcpIpAddress, dhcpMacAddress);
+                        } else {
+                            LOG.trace("Uninstalling the SR-IOV DHCP Arp flows for DPN {} Port Ip {}, Lport {}.",
+                                    dpnId, dhcpIpAddress, lportTag);
+                            uninstallDhcpArpRequestFlows(dpnId, vni, dhcpIpAddress, lportTag);
+                            uninstallDhcpArpResponderFlows(dpnId, tunnelInterfaceName, lportTag, dhcpIpAddress);
+                        }
+                    }
+                }
+            }
+            return null;
+        });
+    }
+
+    public  java.util.Optional<SubnetToDhcpPort> getSubnetDhcpPortData(String elanInstanceName) {
+        java.util.Optional<SubnetToDhcpPort> optSubnetDhcp = java.util.Optional.empty();
+        Uuid nwUuid = new Uuid(elanInstanceName);
+        List<Uuid> subnets = DhcpServiceUtils.getSubnetIdsFromNetworkId(broker, nwUuid);
+        for (Uuid subnet : subnets) {
+            if (DhcpServiceUtils.isIpv4Subnet(broker, subnet)) {
+                optSubnetDhcp = DhcpServiceUtils.getSubnetDhcpPortData(broker, subnet.getValue());
+                return optSubnetDhcp;
+            }
+        }
+        return optSubnetDhcp;
+    }
+
+    private void installDhcpArpRequestFlows(BigInteger dpnId, BigInteger vni, String dhcpIpAddress,
+                                            int lportTag, Long elanTag) {
+        DhcpServiceUtils.setupDhcpArpRequest(dpnId, NwConstants.EXTERNAL_TUNNEL_TABLE, vni, dhcpIpAddress,
+                lportTag, elanTag, true, mdsalUtil);
+    }
+
+    private void installDhcpArpResponderFlows(BigInteger dpnId, String interfaceName, int lportTag,
+                                              String elanInstanceName, String dhcpIpAddress, String dhcpMacAddress) {
+        LOG.trace("Adding SR-IOV DHCP ArpResponder for elan {} Lport {} Port Ip {}.",
+                elanInstanceName, lportTag, dhcpIpAddress);
+        ArpResponderInput.ArpReponderInputBuilder builder = new ArpResponderInput.ArpReponderInputBuilder();
+        builder.setDpId(dpnId).setInterfaceName(interfaceName).setSpa(dhcpIpAddress).setSha(dhcpMacAddress)
+                .setLportTag(lportTag);
+        builder.setInstructions(ArpResponderUtil.getInterfaceInstructions(interfaceManager, interfaceName,
+                dhcpIpAddress, dhcpMacAddress));
+        elanService.addExternalTunnelArpResponderFlow(builder.buildForInstallFlow(), elanInstanceName);
+    }
+
+    private void uninstallDhcpArpResponderFlows(BigInteger dpnId, String interfaceName, int lportTag,
+                                                String dhcpIpAddress) {
+        LOG.trace("Removing SR-IOV DHCP ArpResponder flow for interface {} on DPN {}", interfaceName, dpnId);
+        ArpResponderInput arpInput = new ArpResponderInput.ArpReponderInputBuilder().setDpId(dpnId)
+                .setInterfaceName(interfaceName).setSpa(dhcpIpAddress)
+                .setLportTag(lportTag).buildForRemoveFlow();
+        elanService.removeArpResponderFlow(arpInput);
+    }
+
+    private void uninstallDhcpArpRequestFlows(BigInteger dpnId, BigInteger vni, String dhcpIpAddress,
+                                              int lportTag) {
+        DhcpServiceUtils.setupDhcpArpRequest(dpnId, NwConstants.EXTERNAL_TUNNEL_TABLE, vni, dhcpIpAddress,
+                lportTag, null, false, mdsalUtil);
+    }
+
+
     public void unInstallDhcpEntries(BigInteger dpnId, String vmMacAddress, WriteTransaction tx) {
         DhcpServiceUtils.setupDhcpFlowEntry(dpnId, NwConstants.DHCP_TABLE_EXTERNAL_TUNNEL,
                 vmMacAddress, NwConstants.DEL_FLOW, mdsalUtil, tx);
@@ -510,6 +642,7 @@ public class DhcpExternalTunnelManager {
             return Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(tx -> {
                 for (Pair<IpAddress, String> tunnelElanPair : tunnelElanPairSet) {
                     IpAddress tunnelIpInDpn = tunnelElanPair.getLeft();
+                    String elanInstanceName = tunnelElanPair.getRight();
                     if (tunnelIpInDpn.equals(tunnelIp)) {
                         if (!checkL2GatewayConnection(tunnelElanPair)) {
                             LOG.trace("Couldn't find device for given tunnelIpElanPair {} in L2GwConnCache",
@@ -518,6 +651,12 @@ public class DhcpExternalTunnelManager {
                         List<BigInteger> dpns = DhcpServiceUtils.getListOfDpns(broker);
                         dpns.remove(interfaceDpn);
                         changeExistingFlowToDrop(tunnelElanPair, interfaceDpn, tx);
+                        java.util.Optional<SubnetToDhcpPort> subnetDhcpData = getSubnetDhcpPortData(elanInstanceName);
+                        if (subnetDhcpData.isPresent()) {
+                            configureDhcpArpRequestResponseFlow(interfaceDpn, elanInstanceName, false,
+                                    tunnelIpInDpn, subnetDhcpData.get().getPortFixedip(),
+                                    subnetDhcpData.get().getPortMacaddress());
+                        }
                         updateCacheAndInstallNewFlows(interfaceDpn, dpns, tunnelElanPair, tx);
                     }
                 }
@@ -756,7 +895,8 @@ public class DhcpExternalTunnelManager {
             return Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(tx -> {
                 for (Pair<IpAddress, String> pair : tunnelIpElanPair) {
                     if (tunnelIp.equals(pair.getLeft())) {
-                        BigInteger newDesignatedDpn = designateDpnId(tunnelIp, pair.getRight(), dpns);
+                        String elanInstanceName = pair.getRight();
+                        BigInteger newDesignatedDpn = designateDpnId(tunnelIp, elanInstanceName, dpns);
                         if (newDesignatedDpn != null && !newDesignatedDpn.equals(DhcpMConstants.INVALID_DPID)) {
                             Set<String> vmMacAddress = tunnelIpElanNameToVmMacCache.get(pair);
                             if (vmMacAddress != null && !vmMacAddress.isEmpty()) {
@@ -765,6 +905,12 @@ public class DhcpExternalTunnelManager {
                                 installDhcpFlowsForVms(newDesignatedDpn, vmMacAddress, tx);
                             }
                         }
+                        java.util.Optional<SubnetToDhcpPort> subnetDhcpData = getSubnetDhcpPortData(elanInstanceName);
+                        if (subnetDhcpData.isPresent()) {
+                            configureDhcpArpRequestResponseFlow(newDesignatedDpn, elanInstanceName,
+                                    true, tunnelIp, subnetDhcpData.get().getPortFixedip(),
+                                    subnetDhcpData.get().getPortMacaddress());
+                        }
                     }
                 }
             }));
index f43cdc3b4f3bb36da6eda1fa8fc277cb72b5b730..af96970426e61427e318a05d53981ee7184d90ed 100644 (file)
@@ -43,17 +43,19 @@ public class DhcpInterfaceEventListener
     private final JobCoordinator jobCoordinator;
     private final IInterfaceManager interfaceManager;
     private final IElanService elanService;
+    private final DhcpPortCache dhcpPortCache;
 
     public DhcpInterfaceEventListener(DhcpManager dhcpManager, DataBroker dataBroker,
                                       DhcpExternalTunnelManager dhcpExternalTunnelManager,
                                       IInterfaceManager interfaceManager, IElanService elanService,
-                                      JobCoordinator jobCoordinator) {
+                                      DhcpPortCache dhcpPortCache, JobCoordinator jobCoordinator) {
         super(Interface.class, DhcpInterfaceEventListener.class);
         this.dhcpManager = dhcpManager;
         this.dataBroker = dataBroker;
         this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
         this.interfaceManager = interfaceManager;
         this.elanService = elanService;
+        this.dhcpPortCache = dhcpPortCache;
         this.jobCoordinator = jobCoordinator;
         registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
     }
@@ -74,15 +76,16 @@ public class DhcpInterfaceEventListener
             return;
         }
         String interfaceName = del.getName();
-        Port port = dhcpManager.getNeutronPort(interfaceName);
+        Port port = dhcpPortCache.get(interfaceName);
         if (NeutronConstants.IS_DHCP_PORT.test(port)) {
             return;
         }
         NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
         BigInteger dpnId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
         DhcpInterfaceRemoveJob job = new DhcpInterfaceRemoveJob(dhcpManager, dhcpExternalTunnelManager,
-                dataBroker, del, dpnId, interfaceManager, elanService);
+                dataBroker, del, dpnId, interfaceManager, elanService, port);
         jobCoordinator.enqueueJob(DhcpServiceUtils.getJobKey(interfaceName), job, DhcpMConstants.RETRY_COUNT);
+        dhcpPortCache.remove(interfaceName);
     }
 
     @Override
@@ -130,7 +133,7 @@ public class DhcpInterfaceEventListener
         if (NeutronConstants.IS_DHCP_PORT.test(port)) {
             return;
         }
-
+        dhcpPortCache.put(interfaceName, port);
         NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
         BigInteger dpnId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
         DhcpInterfaceAddJob job = new DhcpInterfaceAddJob(dhcpManager, dhcpExternalTunnelManager, dataBroker,
index 2639c003d0951c64b22de037ce25b5130e3b6f23..6f0f7616f7a0ac388a9f64dabf57a47f083fcacd 100644 (file)
@@ -52,6 +52,7 @@ public class DhcpManager {
     private final IInterfaceManager interfaceManager;
     private final IElanService elanService;
     private final JobCoordinator jobCoordinator;
+    private DhcpPortCache dhcpPortCache;
 
     private volatile int dhcpOptLeaseTime = 0;
     private volatile String dhcpOptDefDomainName;
@@ -63,7 +64,7 @@ public class DhcpManager {
             final INeutronVpnManager neutronVpnManager,
             final DhcpserviceConfig config, final DataBroker dataBroker,
             final DhcpExternalTunnelManager dhcpExternalTunnelManager, final IInterfaceManager interfaceManager,
-            final @Named("elanService") IElanService ielanService,
+            @Named("elanService") IElanService ielanService, final DhcpPortCache dhcpPortCache,
             final JobCoordinator jobCoordinator) {
         this.mdsalUtil = mdsalApiManager;
         this.neutronVpnService = neutronVpnManager;
@@ -72,6 +73,7 @@ public class DhcpManager {
         this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
         this.interfaceManager = interfaceManager;
         this.elanService = ielanService;
+        this.dhcpPortCache = dhcpPortCache;
         this.jobCoordinator = jobCoordinator;
         configureLeaseDuration(DhcpMConstants.DEFAULT_LEASE_TIME);
     }
@@ -81,7 +83,7 @@ public class DhcpManager {
         LOG.trace("Netvirt DHCP Manager Init .... {}",config.isControllerDhcpEnabled());
         if (config.isControllerDhcpEnabled()) {
             dhcpInterfaceEventListener = new DhcpInterfaceEventListener(this, broker, dhcpExternalTunnelManager,
-                    interfaceManager, elanService, jobCoordinator);
+                    interfaceManager, elanService, dhcpPortCache, jobCoordinator);
             dhcpInterfaceConfigListener = new DhcpInterfaceConfigListener(broker, dhcpExternalTunnelManager, this,
                     jobCoordinator);
             LOG.info("DHCP Service initialized");
index 4ff59dcee2e609f01243dd21dd5afba9a79f80cf..4042dfb1760bafe341d07b839c212262640580e3 100644 (file)
@@ -98,14 +98,17 @@ public class DhcpNeutronPortListener
         if (NeutronConstants.IS_ODL_DHCP_PORT.test(del)) {
             jobCoordinator.enqueueJob(getJobKey(del),
                 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
+                    java.util.Optional<String> ip4Address = DhcpServiceUtils.getIpV4Address(del);
+                    if (ip4Address.isPresent()) {
+                        dhcpExternalTunnelManager.addOrRemoveDhcpArpFlowforElan(del.getNetworkId().getValue(),
+                                false, ip4Address.get(), del.getMacAddress().getValue());
+                    }
                     DhcpServiceUtils.removeSubnetDhcpPortData(del, subnetDhcpPortIdfr -> tx
                             .delete(LogicalDatastoreType.CONFIGURATION, subnetDhcpPortIdfr));
                     processArpResponderForElanDpns(del, arpInput -> {
-                        LOG.trace(
-                                "Removing ARP RESPONDER Flows  for dhcp port {} with ipaddress {} with mac {} on dpn "
-                                        + "{}",
-                                arpInput.getInterfaceName(), arpInput.getSpa(), arpInput.getSha(),
-                                arpInput.getDpId());
+                        LOG.trace("Removing ARPResponder Flows  for dhcp port {} with ipaddress {} with mac {} "
+                                        + " on dpn {}. ",arpInput.getInterfaceName(), arpInput.getSpa(),
+                                        arpInput.getSha(), arpInput.getDpId());
                         elanService.removeArpResponderFlow(arpInput);
                     });
                 })));
@@ -196,6 +199,11 @@ public class DhcpNeutronPortListener
                         elanService.addArpResponderFlow(builder.buildForInstallFlow());
                     });
                 })));
+            java.util.Optional<String> ip4Address = DhcpServiceUtils.getIpV4Address(add);
+            if (ip4Address.isPresent()) {
+                dhcpExternalTunnelManager.addOrRemoveDhcpArpFlowforElan(add.getNetworkId().getValue(),
+                        true, ip4Address.get(), add.getMacAddress().getValue());
+            }
         }
         if (!isVnicTypeDirectOrMacVtap(add)) {
             return;
index b214e41a168be3d27657b2267b497f4006380d0b..0687408069fab2f4eca5e6f365d535f91554b9f6 100644 (file)
@@ -137,16 +137,20 @@ public class DhcpPktHandler implements PacketProcessingListener {
                     LOG.error("Failed to get interface info for interface name {}", interfaceName);
                     return;
                 }
-                Port port = getNeutronPort(interfaceName);
+                Port port;
+                if (tunnelId != null) {
+                    port = dhcpExternalTunnelManager.readVniMacToPortCache(tunnelId, macAddress);
+                } else {
+                    port = getNeutronPort(interfaceName);
+                }
                 Subnet subnet = getNeutronSubnet(port);
-                //When neutronport-dhcp flag is disabled continue running DHCP Server by hijacking the subnet-gateway-ip
                 String serverMacAddress = interfaceInfo.getMacAddress();
                 String serverIp = null;
                 if (subnet != null) {
                     java.util.Optional<SubnetToDhcpPort> dhcpPortData = DhcpServiceUtils
                             .getSubnetDhcpPortData(broker, subnet.getUuid().getValue());
-                    /* If neutronport-dhcp flag was enabled and an ODL network DHCP Port data was made available use the
-                     * ports Fixed IP as server IP for DHCP communication.
+                    /* If enable_dhcp_service flag was enabled and an ODL network DHCP Port data was made available use
+                     * the ports Fixed IP as server IP for DHCP communication.
                      */
                     if (dhcpPortData.isPresent()) {
                         serverIp = dhcpPortData.get().getPortFixedip();
@@ -158,7 +162,11 @@ public class DhcpPktHandler implements PacketProcessingListener {
                         return;
                     }
                 }
-                DHCP replyPkt = handleDhcpPacket(pktIn, interfaceName, macAddress, tunnelId, port, subnet, serverIp);
+                DHCP replyPkt = handleDhcpPacket(pktIn, interfaceName, macAddress, port, subnet, serverIp);
+                if (replyPkt == null) {
+                    LOG.warn("Unable to construct reply packet for interface name {}", interfaceName);
+                    return;
+                }
                 byte[] pktOut = getDhcpPacketOut(replyPkt, ethPkt, serverMacAddress);
                 sendPacketOut(pktOut, interfaceInfo.getDpId(), interfaceName, tunnelId);
             }
@@ -172,19 +180,13 @@ public class DhcpPktHandler implements PacketProcessingListener {
         JdkFutures.addErrorLogging(pktService.transmitPacket(output), LOG, "Transmit packet");
     }
 
-    private DHCP handleDhcpPacket(DHCP dhcpPkt, String interfaceName, String macAddress, BigInteger tunnelId,
-                                  Port interfacePort, Subnet subnet, String serverIp) {
+    private DHCP handleDhcpPacket(DHCP dhcpPkt, String interfaceName, String macAddress, Port interfacePort,
+                                  Subnet subnet, String serverIp) {
         LOG.trace("DHCP pkt rcvd {}", dhcpPkt);
         byte msgType = dhcpPkt.getMsgType();
-        Port port;
-        if (tunnelId != null) {
-            port = dhcpExternalTunnelManager.readVniMacToPortCache(tunnelId, macAddress);
-        } else {
-            port = interfacePort;
-        }
         DhcpInfo dhcpInfo = null;
-        if (port != null) {
-            dhcpInfo = handleDhcpNeutronPacket(msgType, port, subnet, serverIp);
+        if (interfacePort != null) {
+            dhcpInfo = handleDhcpNeutronPacket(msgType, interfacePort, subnet, serverIp);
         } else if (config.isDhcpDynamicAllocationPoolEnabled()) {
             dhcpInfo = handleDhcpAllocationPoolPacket(msgType, dhcpPkt, interfaceName, macAddress);
         }
diff --git a/vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/netvirt/dhcpservice/DhcpPortCache.java b/vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/netvirt/dhcpservice/DhcpPortCache.java
new file mode 100644 (file)
index 0000000..1047b05
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright © 2015, 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,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netvirt.dhcpservice;
+
+import java.util.concurrent.ConcurrentHashMap;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.PostConstruct;
+import javax.inject.Singleton;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public class DhcpPortCache {
+
+    private static final Logger LOG = LoggerFactory.getLogger(DhcpPortCache.class);
+    private final ConcurrentHashMap<String, Port> portMap = new ConcurrentHashMap<String, Port>();
+
+    @PostConstruct
+    public void init() {
+        LOG.trace("Initialize DhcpPortCache. ");
+    }
+
+    public  void put(@Nonnull  String interfaceName, Port port) {
+        portMap.put(interfaceName, port);
+        LOG.trace("Added the interface {} to DhcpPortCache",interfaceName);
+    }
+
+    @Nullable
+    public Port get(@Nonnull String interfaceName) {
+        return portMap.get(interfaceName);
+    }
+
+    public void remove(@Nonnull String interfaceName) {
+        portMap.remove(interfaceName);
+    }
+}
index ca82ae64c93c6253bc13902e638f23dbcfd0afc0..940749304f1c2c9ca76b338827a6073c4bf6c2db 100644 (file)
@@ -11,7 +11,10 @@ package org.opendaylight.netvirt.dhcpservice;
 import com.google.common.base.Optional;
 import com.google.common.util.concurrent.FutureCallback;
 import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
@@ -36,23 +39,29 @@ import org.opendaylight.genius.mdsalutil.InstructionInfo;
 import org.opendaylight.genius.mdsalutil.MDSALDataStoreUtils;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
 import org.opendaylight.genius.mdsalutil.MatchInfo;
+import org.opendaylight.genius.mdsalutil.NWUtil;
 import org.opendaylight.genius.mdsalutil.NwConstants;
 import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
 import org.opendaylight.genius.mdsalutil.actions.ActionPuntToController;
 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.genius.mdsalutil.matches.MatchArpOp;
+import org.opendaylight.genius.mdsalutil.matches.MatchArpTpa;
 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetSource;
 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
 import org.opendaylight.genius.mdsalutil.matches.MatchIpProtocol;
+import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
 import org.opendaylight.genius.mdsalutil.matches.MatchUdpDestinationPort;
 import org.opendaylight.genius.mdsalutil.matches.MatchUdpSourcePort;
 import org.opendaylight.genius.utils.ServiceIndex;
 import org.opendaylight.netvirt.dhcpservice.api.DhcpMConstants;
+import org.opendaylight.netvirt.elanmanager.api.ElanHelper;
 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
 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.interfaces.rev140508.InterfacesState;
 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.flow.inventory.rev130819.tables.table.Flow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceBindings;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeIngress;
@@ -70,6 +79,11 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.Elan
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesListKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkMaps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.IpVersionBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.IpVersionV4;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeVxlan;
 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;
@@ -78,6 +92,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.por
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.Subnets;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.SubnetKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710.InterfaceNameMacAddresses;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710.SubnetDhcpPortData;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710._interface.name.mac.addresses.InterfaceNameMacAddress;
@@ -144,6 +161,14 @@ public final class DhcpServiceUtils {
                 .append(vmMacAddress).toString();
     }
 
+    private static String getDhcpArpFlowRef(BigInteger dpId, long tableId, long lportTag, String ipAddress) {
+        return new StringBuffer().append(DhcpMConstants.FLOWID_PREFIX)
+                .append(dpId).append(NwConstants.FLOWID_SEPARATOR)
+                .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
+                .append(lportTag).append(NwConstants.FLOWID_SEPARATOR)
+                .append(ipAddress).toString();
+    }
+
     public static void setupDhcpDropAction(BigInteger dpId, short tableId, String vmMacAddress, int addOrRemove,
                                            IMdsalApiManager mdsalUtil, WriteTransaction tx) {
         if (dpId == null || dpId.equals(DhcpMConstants.INVALID_DPID) || vmMacAddress == null) {
@@ -174,6 +199,26 @@ public final class DhcpServiceUtils {
         }
     }
 
+    @SuppressWarnings("checkstyle:IllegalCatch")
+    public static void setupDhcpArpRequest(BigInteger dpId, short tableId, BigInteger vni, String dhcpIpAddress,
+                                           int lportTag, Long elanTag, boolean add, IMdsalApiManager mdsalUtil) {
+        List<MatchInfo> matches = getDhcpArpMatch(vni, dhcpIpAddress);
+        if (add) {
+            Flow flow = MDSALUtil.buildFlowNew(tableId, getDhcpArpFlowRef(dpId, tableId, lportTag, dhcpIpAddress),
+                    DhcpMConstants.DEFAULT_DHCP_ARP_FLOW_PRIORITY, "DHCPArp", 0, 0,
+                    generateDhcpArpCookie(lportTag, dhcpIpAddress), matches, null);
+            LOG.trace("Removing DHCP ARP Flow DpId {}, DHCP Port IpAddress {}", dpId, dhcpIpAddress);
+            mdsalUtil.removeFlow(dpId, flow);
+        } else {
+            Flow flow = MDSALUtil.buildFlowNew(tableId, getDhcpArpFlowRef(dpId, tableId, lportTag, dhcpIpAddress),
+                    DhcpMConstants.DEFAULT_DHCP_ARP_FLOW_PRIORITY, "DHCPArp", 0, 0,
+                    generateDhcpArpCookie(lportTag, dhcpIpAddress), matches,
+                    getDhcpArpInstructions(elanTag, lportTag));
+            LOG.trace("Adding DHCP ARP Flow DpId {}, DHCPPort IpAddress {}", dpId, dhcpIpAddress);
+            mdsalUtil.installFlow(dpId, flow);
+        }
+    }
+
     public static List<MatchInfo> getDhcpMatch() {
         List<MatchInfo> matches = new ArrayList<>();
         matches.add(MatchEthernetType.IPV4);
@@ -189,7 +234,32 @@ public final class DhcpServiceUtils {
         return matches;
     }
 
-    @Nonnull
+    private static List<MatchInfo> getDhcpArpMatch(BigInteger vni, String ipAddress) {
+        return Arrays.asList(MatchEthernetType.ARP, MatchArpOp.REQUEST, new MatchTunnelId(vni),
+                new MatchArpTpa(ipAddress, "32"));
+    }
+
+    private static List<Instruction> getDhcpArpInstructions(Long elanTag, int lportTag) {
+        List<Instruction> mkInstructions = new ArrayList<>();
+        int instructionKey = 0;
+        mkInstructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(
+                ElanHelper.getElanMetadataLabel(elanTag, lportTag), ElanHelper.getElanMetadataMask(),
+                ++instructionKey));
+        mkInstructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ARP_RESPONDER_TABLE,
+                ++instructionKey));
+        return mkInstructions;
+    }
+
+    private static BigInteger generateDhcpArpCookie(int lportTag, String ipAddress) {
+        try {
+            BigInteger cookie = NwConstants.TUNNEL_TABLE_COOKIE.add(BigInteger.valueOf(255))
+                    .add(BigInteger.valueOf(NWUtil.convertInetAddressToLong(InetAddress.getByName(ipAddress))));
+            return cookie.add(BigInteger.valueOf(lportTag));
+        } catch (UnknownHostException e) {
+            return NwConstants.TUNNEL_TABLE_COOKIE.add(BigInteger.valueOf(lportTag));
+        }
+    }
+
     public static List<BigInteger> getListOfDpns(DataBroker broker) {
         return extractDpnsFromNodes(MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
                 InstanceIdentifier.builder(Nodes.class).build()));
@@ -455,4 +525,34 @@ public final class DhcpServiceUtils {
         return null;
     }
 
+    public static List<Uuid> getSubnetIdsFromNetworkId(DataBroker broker, Uuid networkId) {
+        InstanceIdentifier id = buildNetworkMapIdentifier(networkId);
+        Optional<NetworkMap> optionalNetworkMap = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
+        if (optionalNetworkMap.isPresent()) {
+            return optionalNetworkMap.get().getSubnetIdList();
+        }
+        return null;
+    }
+
+    static InstanceIdentifier<NetworkMap> buildNetworkMapIdentifier(Uuid networkId) {
+        InstanceIdentifier<NetworkMap> id = InstanceIdentifier.builder(NetworkMaps.class).child(NetworkMap.class, new
+                NetworkMapKey(networkId)).build();
+        return id;
+    }
+
+    public static boolean isIpv4Subnet(DataBroker broker, Uuid subnetUuid) {
+        final SubnetKey subnetkey = new SubnetKey(subnetUuid);
+        final InstanceIdentifier<Subnet> subnetidentifier = InstanceIdentifier.create(Neutron.class)
+                .child(Subnets.class).child(Subnet.class, subnetkey);
+        final Optional<Subnet> subnet = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, subnetidentifier);
+        if (subnet.isPresent()) {
+            Class<? extends IpVersionBase> ipVersionBase = subnet.get().getIpVersion();
+            if (ipVersionBase.equals(IpVersionV4.class)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
 }
+
index e3771a6dcbd9eefae90d838e7a4332d9d98294ee..77fcaa6b16d2ddb2870db1e33217d2c33487fbf2 100644 (file)
@@ -63,11 +63,12 @@ public class DhcpInterfaceRemoveJob implements Callable<List<ListenableFuture<Vo
     private final BigInteger dpnId;
     private final IInterfaceManager interfaceManager;
     private final IElanService elanService;
+    private final Port port;
 
     public DhcpInterfaceRemoveJob(DhcpManager dhcpManager, DhcpExternalTunnelManager dhcpExternalTunnelManager,
                                   DataBroker dataBroker,
                                   Interface interfaceDel, BigInteger dpnId, IInterfaceManager interfaceManager,
-                                  IElanService elanService) {
+                                  IElanService elanService, Port port) {
         this.dhcpManager = dhcpManager;
         this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
         this.dataBroker = dataBroker;
@@ -76,6 +77,7 @@ public class DhcpInterfaceRemoveJob implements Callable<List<ListenableFuture<Vo
         this.dpnId = dpnId;
         this.interfaceManager = interfaceManager;
         this.elanService = elanService;
+        this.port = port;
     }
 
     @Override
@@ -98,7 +100,6 @@ public class DhcpInterfaceRemoveJob implements Callable<List<ListenableFuture<Vo
         // Support for VM migration use cases.
         futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(
             tx -> DhcpServiceUtils.unbindDhcpService(interfaceName, tx)));
-        Port port = dhcpManager.getNeutronPort(interfaceName);
         java.util.Optional<String> subnetId = DhcpServiceUtils.getNeutronSubnetId(port);
         if (subnetId.isPresent()) {
             java.util.Optional<SubnetToDhcpPort> subnetToDhcp = DhcpServiceUtils.getSubnetDhcpPortData(dataBroker,
index 61d1ff1bb1fd03269bc4b846b0c275ddc66f7954..b797bc7216af5ce0b86145dc9673ce00aeee070f 100644 (file)
@@ -93,6 +93,17 @@ public interface IElanService extends IEtreeService {
      */
     void addArpResponderFlow(ArpResponderInput arpResponderInput);
 
+    /**
+     * Add ARP Responder Flow on the given dpn for the SR-IOV VMs ingress interface.
+     *
+     * @param arpResponderInput
+     *            ArpResponder Input parameters
+     * @see ArpResponderInput
+     * @param elanInstanceName
+     *           The elanInstance  corresponding to the interface
+     */
+    void addExternalTunnelArpResponderFlow(ArpResponderInput arpResponderInput, String elanInstanceName);
+
     /**
      * Remove ARP Responder flow from the given dpn for the ingress interface.
      *
index 609816821e18648301ee1eae49b226e060bb75d8..a1504834d46b3130d1cf7c5fbb3c8256bbc63ffe 100644 (file)
@@ -854,6 +854,13 @@ public class ElanServiceProvider extends AbstractLifecycle implements IElanServi
                 arpResponderInput.getInstructions());
     }
 
+    @Override
+    public void addExternalTunnelArpResponderFlow(ArpResponderInput arpResponderInput, String elanInstanceName) {
+        elanUtils.addExternalTunnelArpResponderFlow(arpResponderInput.getDpId(), arpResponderInput.getSpa(),
+                arpResponderInput.getSha(), arpResponderInput.getLportTag(),
+                arpResponderInput.getInstructions(), elanInstanceName);
+    }
+
     @Override
     public void removeArpResponderFlow(ArpResponderInput arpResponderInput) {
         elanUtils.removeArpResponderFlow(arpResponderInput.getDpId(), arpResponderInput.getInterfaceName(),
index 98887c111630b4e1f0727d43797f3fd76461372f..453823bece5892fea6ebaf0b444a0fb2f98f2760 100755 (executable)
@@ -1796,6 +1796,18 @@ public class ElanUtils {
         LOG.info("Installed the ARP Responder flow for Interface {}", ingressInterfaceName);
     }
 
+    public void addExternalTunnelArpResponderFlow(BigInteger dpnId, String ipAddress, String macAddress,
+                        int lportTag, List<Instruction> instructions, String elanInstanceName) {
+        LOG.trace("Installing the ExternalTunnel ARP responder flow on DPN {} for ElanInstance {} with MAC {} & IP {}",
+                dpnId, elanInstanceName, macAddress, ipAddress);
+        ElanInstance elanInstance = getElanInstanceByName(broker, elanInstanceName);
+        String flowId = ArpResponderUtil.getFlowId(lportTag, ipAddress);
+        ArpResponderUtil.installFlow(mdsalManager, dpnId, flowId, flowId, NwConstants.DEFAULT_ARP_FLOW_PRIORITY,
+                ArpResponderUtil.generateCookie(lportTag, ipAddress),
+                ArpResponderUtil.getMatchCriteria(lportTag, elanInstance, ipAddress), instructions);
+        LOG.trace("Installed the ExternalTunnel ARP Responder flow for ElanInstance {}", elanInstanceName);
+    }
+
     public void removeArpResponderFlow(BigInteger dpnId, String ingressInterfaceName, String ipAddress,
             int lportTag) {
         LOG.info("Removing the ARP responder flow on DPN {} of Interface {} with IP {}", dpnId, ingressInterfaceName,