Neutron Port allocation for DHCP Service 75/56875/37
authorAchuth Maniyedath <achuth.m@altencalsoftlabs.com>
Thu, 11 May 2017 18:32:50 +0000 (00:02 +0530)
committerVivekanandan Narasimhan <n.vivekanandan@ericsson.com>
Thu, 29 Jun 2017 03:50:09 +0000 (03:50 +0000)
The feature enables DHCP service to make use of the
newly created Neutron ports provisioned by Openstack
networking-odl driver at the time of Subnet creation.
Additionaly an ARPResponder flow is also introduced to
service the ARP requests for these ports during VM
DHCP renewal.

All ArpResponder handling for Router interface gateway,
floating IP and DHCP ports will be moved to ElanService,
introducing a pipeline change for ARP handling.

LPort Dispatcher Table(17) -> ARP Check Table(43) -> ARPResponder Group
-> ELAN Base Table(48), ARP Responder Table(81), Controller
-> Egress Dispatcher Tabel (220)

Change-Id: I8ebbe05c37f5e7e4c5ae1dd1d17faa12965d5e65
Depends-On: I2dce5e253d3c94180dd18e51125c5c18170b5c69
Signed-off-by: Achuth Maniyedath <achuth.m@altencalsoftlabs.com>
Signed-off-by: Vijayalakshmi Chickkamenahalli Nagaraju <vijayalakshmi.c@altencalsoftlabs.com>
Signed-off-by: karthik.p <karthik.p@altencalsoftlabs.com>
35 files changed:
.gitignore [changed mode: 0755->0644]
vpnservice/dhcpservice/dhcpservice-api/src/main/yang/dhcpservice-api.yang
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/DhcpServiceUtils.java
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/netvirt/dhcpservice/jobs/DhcpInterfaceAddJob.java
vpnservice/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/netvirt/dhcpservice/jobs/DhcpInterfaceRemoveJob.java
vpnservice/dhcpservice/dhcpservice-impl/src/main/resources/initial/netvirt-dhcpservice-config.xml
vpnservice/dhcpservice/dhcpservice-impl/src/main/resources/org/opendaylight/blueprint/dhcpservice.xml
vpnservice/dhcpservice/dhcpservice-impl/src/main/yang/dhcpservice-config.yang
vpnservice/elanmanager/elanmanager-api/pom.xml
vpnservice/elanmanager/elanmanager-api/src/main/java/org/opendaylight/netvirt/elan/arp/responder/ArpResponderConstant.java [moved from vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/arp/responder/ArpResponderConstant.java with 66% similarity]
vpnservice/elanmanager/elanmanager-api/src/main/java/org/opendaylight/netvirt/elan/arp/responder/ArpResponderInput.java [new file with mode: 0644]
vpnservice/elanmanager/elanmanager-api/src/main/java/org/opendaylight/netvirt/elan/arp/responder/ArpResponderUtil.java [new file with mode: 0644]
vpnservice/elanmanager/elanmanager-api/src/main/java/org/opendaylight/netvirt/elanmanager/api/ElanHelper.java
vpnservice/elanmanager/elanmanager-api/src/main/java/org/opendaylight/netvirt/elanmanager/api/IElanService.java
vpnservice/elanmanager/elanmanager-impl/pom.xml
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanInterfaceManager.java
vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanNodeListener.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
vpnservice/elanmanager/elanmanager-impl/src/main/resources/org/opendaylight/blueprint/elanmanager.xml
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatUtil.java
vpnservice/neutronvpn/neutronvpn-api/src/main/java/org/opendaylight/netvirt/neutronvpn/api/utils/NeutronConstants.java
vpnservice/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/netvirt/neutronvpn/NeutronPortChangeListener.java
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/ArpNotificationHandler.java
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnInterfaceManager.java
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnManagerImpl.java
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnNodeListener.java
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnUtil.java
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/arp/responder/ArpResponderHandler.java [new file with mode: 0644]
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/arp/responder/ArpResponderUtil.java [deleted file]
vpnservice/vpnmanager/vpnmanager-impl/src/main/resources/org/opendaylight/blueprint/vpnmanager.xml

old mode 100755 (executable)
new mode 100644 (file)
index 68beecf..9cb68e1
@@ -31,3 +31,6 @@ target-ide/
 yang-gen-config
 yang-gen-sal
 maven-metadata-local.xml
+.metadata
+.recommenders
+/.gitignore
index fd86e9ff7680e1bcc05c99ef3977e27387ffebe0..3f53edf55192b0dfd362cbce948f0755b66d87e9 100644 (file)
@@ -33,4 +33,16 @@ module dhcpservice-api {
             }
         }
     }
+
+    container subnet-dhcp-port-data {
+        config true;
+        list subnet-to-dhcp-port {
+            key "subnet-id";
+            leaf subnet-id { type string;}
+            leaf port-name { type string;}
+            leaf port-fixedip { type string;}
+            leaf port-macaddress { type string;}
+        }
+    }
+
 }
\ No newline at end of file
index db1c51281919cf2194d9f282674971b5033b8718..9712e6d91bea733fe98fa5ae4eec188e2653fb15 100644 (file)
@@ -9,7 +9,6 @@ package org.opendaylight.netvirt.dhcpservice;
 
 import java.math.BigInteger;
 import java.util.List;
-
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
@@ -20,10 +19,13 @@ import org.opendaylight.netvirt.dhcpservice.api.DhcpMConstants;
 import org.opendaylight.netvirt.dhcpservice.jobs.DhcpInterfaceAddJob;
 import org.opendaylight.netvirt.dhcpservice.jobs.DhcpInterfaceRemoveJob;
 import org.opendaylight.netvirt.dhcpservice.jobs.DhcpInterfaceUpdateJob;
+import org.opendaylight.netvirt.elanmanager.api.IElanService;
+import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronConstants;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -39,15 +41,17 @@ public class DhcpInterfaceEventListener
     private final DhcpExternalTunnelManager dhcpExternalTunnelManager;
     private DataStoreJobCoordinator dataStoreJobCoordinator;
     private final IInterfaceManager interfaceManager;
+    private final IElanService elanService;
 
     public DhcpInterfaceEventListener(DhcpManager dhcpManager, DataBroker dataBroker,
                                       DhcpExternalTunnelManager dhcpExternalTunnelManager,
-                                      IInterfaceManager interfaceManager) {
+                                      IInterfaceManager interfaceManager, IElanService elanService) {
         super(Interface.class, DhcpInterfaceEventListener.class);
         this.dhcpManager = dhcpManager;
         this.dataBroker = dataBroker;
         this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
         this.interfaceManager = interfaceManager;
+        this.elanService = elanService;
         registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
         dataStoreJobCoordinator = DataStoreJobCoordinator.getInstance();
     }
@@ -65,10 +69,14 @@ public class DhcpInterfaceEventListener
             return;
         }
         String interfaceName = del.getName();
+        Port port = dhcpManager.getNeutronPort(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, interfaceName, dpnId, interfaceManager);
+                dataBroker, del, dpnId, interfaceManager, elanService);
         dataStoreJobCoordinator.enqueueJob(DhcpServiceUtils.getJobKey(interfaceName), job, DhcpMConstants.RETRY_COUNT);
     }
 
@@ -104,14 +112,20 @@ public class DhcpInterfaceEventListener
     @Override
     protected void add(InstanceIdentifier<Interface> identifier, Interface add) {
         String interfaceName = add.getName();
+        LOG.trace("DhcpInterfaceAddJob to be created for interface {}", interfaceName);
         List<String> ofportIds = add.getLowerLayerIf();
         if (ofportIds == null || ofportIds.isEmpty()) {
             return;
         }
+        Port port = dhcpManager.getNeutronPort(interfaceName);
+        if (NeutronConstants.IS_DHCP_PORT.test(port)) {
+            return;
+        }
+
         NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
         BigInteger dpnId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
         DhcpInterfaceAddJob job = new DhcpInterfaceAddJob(dhcpManager, dhcpExternalTunnelManager, dataBroker,
-                interfaceName, dpnId, interfaceManager);
+                add, dpnId, interfaceManager, elanService);
         dataStoreJobCoordinator.enqueueJob(DhcpServiceUtils.getJobKey(interfaceName), job, DhcpMConstants.RETRY_COUNT);
     }
 
index e171baedff6e6d1cb96ca7c4f73c5e884451485c..62a1ef417b5ba27eafa023f4b3743d7be62d2806 100644 (file)
@@ -14,6 +14,7 @@ import java.util.List;
 import javax.annotation.PostConstruct;
 import javax.annotation.PreDestroy;
 import javax.inject.Inject;
+import javax.inject.Named;
 import javax.inject.Singleton;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
@@ -30,6 +31,7 @@ import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
 import org.opendaylight.netvirt.dhcpservice.api.DhcpMConstants;
+import org.opendaylight.netvirt.elanmanager.api.IElanService;
 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
@@ -48,6 +50,7 @@ public class DhcpManager {
     private final DataBroker broker;
     private final DhcpExternalTunnelManager dhcpExternalTunnelManager;
     private final IInterfaceManager interfaceManager;
+    private final IElanService elanService;
 
     private int dhcpOptLeaseTime = 0;
     private String dhcpOptDefDomainName;
@@ -58,22 +61,24 @@ public class DhcpManager {
     public DhcpManager(final IMdsalApiManager mdsalApiManager,
             final INeutronVpnManager neutronVpnManager,
             final DhcpserviceConfig config, final DataBroker dataBroker,
-            final DhcpExternalTunnelManager dhcpExternalTunnelManager, final IInterfaceManager interfaceManager) {
+            final DhcpExternalTunnelManager dhcpExternalTunnelManager, final IInterfaceManager interfaceManager,
+            final @Named("elanService") IElanService ielanService) {
         this.mdsalUtil = mdsalApiManager;
         this.neutronVpnService = neutronVpnManager;
         this.config = config;
         this.broker = dataBroker;
         this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
         this.interfaceManager = interfaceManager;
-
+        this.elanService = ielanService;
         configureLeaseDuration(DhcpMConstants.DEFAULT_LEASE_TIME);
     }
 
     @PostConstruct
     public void init() {
+        LOG.trace("Netvirt DHCP Manager Init .... {}",config.isControllerDhcpEnabled());
         if (config.isControllerDhcpEnabled()) {
-            dhcpInterfaceEventListener =
-                    new DhcpInterfaceEventListener(this, broker, dhcpExternalTunnelManager, interfaceManager);
+            dhcpInterfaceEventListener = new DhcpInterfaceEventListener(this, broker, dhcpExternalTunnelManager,
+                    interfaceManager, elanService);
             dhcpInterfaceConfigListener = new DhcpInterfaceConfigListener(broker, dhcpExternalTunnelManager, this);
             LOG.info("DHCP Service initialized");
         }
index b2f3892b98fd4ea909669c9ad8b44565da98829d..c19b09bb9f97f05231d65ca5b22587295bd4bdc7 100644 (file)
@@ -7,16 +7,29 @@
  */
 package org.opendaylight.netvirt.dhcpservice;
 
+import com.google.common.util.concurrent.ListenableFuture;
 import java.math.BigInteger;
+import java.util.ArrayList;
 import java.util.List;
+import java.util.function.Consumer;
 
 import javax.annotation.PostConstruct;
 import javax.annotation.PreDestroy;
 import javax.inject.Inject;
+import javax.inject.Named;
 import javax.inject.Singleton;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.genius.datastoreutils.AsyncClusteredDataTreeChangeListenerBase;
+import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderInput;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderInput.ArpReponderInputBuilder;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderUtil;
+import org.opendaylight.netvirt.elanmanager.api.ElanHelper;
+import org.opendaylight.netvirt.elanmanager.api.IElanService;
+import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronConstants;
 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.neutron.binding.rev150712.PortBindingExtension;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
@@ -33,14 +46,19 @@ public class DhcpNeutronPortListener
 
     private static final Logger LOG = LoggerFactory.getLogger(DhcpNeutronPortListener.class);
     private final DhcpExternalTunnelManager dhcpExternalTunnelManager;
+    private final IElanService elanService;
     private final DataBroker broker;
-    private DhcpserviceConfig config;
+    private final DhcpserviceConfig config;
+    private final IInterfaceManager interfaceManager;
 
     @Inject
-    public DhcpNeutronPortListener(final DataBroker db, final DhcpExternalTunnelManager dhcpExternalTunnelManager,
-                                   final DhcpserviceConfig config) {
+    public DhcpNeutronPortListener(DataBroker db, DhcpExternalTunnelManager dhcpExternalTunnelManager,
+            @Named("elanService") IElanService ielanService, IInterfaceManager interfaceManager,
+            DhcpserviceConfig config) {
         super(Port.class, DhcpNeutronPortListener.class);
         this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
+        this.elanService = ielanService;
+        this.interfaceManager = interfaceManager;
         this.broker = db;
         this.config = config;
     }
@@ -65,13 +83,34 @@ public class DhcpNeutronPortListener
     }
 
     @Override
+    @SuppressWarnings("deprecation")
     protected void remove(InstanceIdentifier<Port> identifier, Port del) {
         LOG.trace("Port removed: {}", del);
+        if (NeutronConstants.IS_ODL_DHCP_PORT.test(del)) {
+            DataStoreJobCoordinator portDataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+            portDataStoreCoordinator.enqueueJob(getJobKey(del), () -> {
+                WriteTransaction wrtConfigTxn = broker.newWriteOnlyTransaction();
+                List<ListenableFuture<Void>> futures = new ArrayList<>();
+                DhcpServiceUtils.removeSubnetDhcpPortData(del, subnetDhcpPortIdfr -> wrtConfigTxn
+                        .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());
+                    elanService.removeArpResponderFlow(arpInput);
+                });
+                futures.add(wrtConfigTxn.submit());
+                return futures;
+            });
+        }
         if (isVnicTypeDirectOrMacVtap(del)) {
             removePort(del);
         }
     }
 
+    private String getJobKey(Port port) {
+        return "PORT- " + port.getUuid().getValue();
+    }
+
     @Override
     protected void update(InstanceIdentifier<Port> identifier, Port original, Port update) {
         LOG.trace("Port changed to {}", update);
@@ -103,8 +142,28 @@ public class DhcpNeutronPortListener
     }
 
     @Override
+    @SuppressWarnings("deprecation")
     protected void add(InstanceIdentifier<Port> identifier, Port add) {
         LOG.trace("Port added {}", add);
+        if (NeutronConstants.IS_ODL_DHCP_PORT.test(add)) {
+            DataStoreJobCoordinator portDataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+            portDataStoreCoordinator.enqueueJob(getJobKey(add), () -> {
+                WriteTransaction wrtConfigTxn = broker.newWriteOnlyTransaction();
+                List<ListenableFuture<Void>> futures = new ArrayList<>();
+                DhcpServiceUtils.createSubnetDhcpPortData(add, (subnetDhcpPortIdfr, subnetToDhcpport) -> wrtConfigTxn
+                        .put(LogicalDatastoreType.CONFIGURATION, subnetDhcpPortIdfr, subnetToDhcpport));
+                processArpResponderForElanDpns(add, arpInput -> {
+                    LOG.trace("Installing ARP RESPONDER Flows  for dhcp port {} ipaddress {} with mac {} on dpn {}",
+                            arpInput.getInterfaceName(), arpInput.getSpa(), arpInput.getSha(), arpInput.getDpId());
+                    ArpReponderInputBuilder builder = new ArpReponderInputBuilder(arpInput);
+                    builder.setInstructions(ArpResponderUtil.getInterfaceInstructions(interfaceManager,
+                            arpInput.getInterfaceName(), arpInput.getSpa(), arpInput.getSha()));
+                    elanService.addArpResponderFlow(builder.buildForInstallFlow());
+                });
+                futures.add(wrtConfigTxn.submit());
+                return futures;
+            });
+        }
         if (!isVnicTypeDirectOrMacVtap(add)) {
             return;
         }
@@ -132,6 +191,7 @@ public class DhcpNeutronPortListener
             return;
         }
         dhcpExternalTunnelManager.updateVniMacToPortCache(new BigInteger(segmentationId), macAddress, port);
+
     }
 
     private String getMacAddress(Port port) {
@@ -152,4 +212,36 @@ public class DhcpNeutronPortListener
     protected DhcpNeutronPortListener getDataTreeChangeListener() {
         return DhcpNeutronPortListener.this;
     }
+
+    /**
+     * Handle(Add/Remove) ARP Responder for DHCP IP on all the DPNs when DHCP is
+     * enabled/disabled on subnet add or update or delete.
+     *
+     * @param port
+     *            DHCP port for which ARP Responder flow to be added when dhcp
+     *            flag is enabled on the subnet or DHCP port for which ARP
+     *            Responder flow to be removed when dhcp flag is disabled on the
+     *            Subnet
+     * @param arpResponderAction
+     *            ARP Responder Action to be performed i.e., add or remove flow
+     */
+    private void processArpResponderForElanDpns(Port port, Consumer<ArpResponderInput> arpResponderAction) {
+
+        java.util.Optional<String> ip4Address = DhcpServiceUtils.getIpV4Address(port);
+        if (!ip4Address.isPresent()) {
+            LOG.warn("There is no IPv4Address for port {}, not performing ARP responder add/remove flow operation",
+                    port.getName());
+            return;
+        }
+        ElanHelper.getDpnInterfacesInElanInstance(broker, port.getNetworkId().getValue()).stream()
+                .map(ifName -> DhcpServiceUtils.getInterfaceInfo(interfaceManager, ifName)).forEach(interfaceInfo -> {
+                    ArpResponderInput arpResponderInput = new ArpResponderInput.ArpReponderInputBuilder()
+                            .setDpId(interfaceInfo.getDpId()).setInterfaceName(interfaceInfo.getInterfaceName())
+                            .setLportTag(interfaceInfo.getInterfaceTag()).setSha(port.getMacAddress().getValue())
+                            .setSpa(ip4Address.get()).build();
+                    arpResponderAction.accept(arpResponderInput);
+                });
+
+    }
+
 }
\ No newline at end of file
index 8da1335bc482ceca056e19f8204ee722c4e478bb..27ae06e03b88598240ed453efc6b9e5f309babb9 100644 (file)
@@ -25,6 +25,7 @@ import org.apache.commons.net.util.SubnetUtils.SubnetInfo;
 import org.opendaylight.controller.liblldp.EtherTypes;
 import org.opendaylight.controller.liblldp.NetUtils;
 import org.opendaylight.controller.liblldp.PacketException;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
@@ -58,11 +59,13 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.Pa
 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.SendToController;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
+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.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+
 @Singleton
 public class DhcpPktHandler implements PacketProcessingListener {
 
@@ -75,6 +78,7 @@ public class DhcpPktHandler implements PacketProcessingListener {
     private final IInterfaceManager interfaceManager;
     private final DhcpserviceConfig config;
     private final DhcpAllocationPoolManager dhcpAllocationPoolMgr;
+    private final DataBroker broker;
 
     @Inject
     public DhcpPktHandler(final DhcpManager dhcpManager,
@@ -83,7 +87,8 @@ public class DhcpPktHandler implements PacketProcessingListener {
                           final PacketProcessingService pktService,
                           final IInterfaceManager interfaceManager,
                           final DhcpserviceConfig config,
-                          final DhcpAllocationPoolManager dhcpAllocationPoolMgr) {
+                          final DhcpAllocationPoolManager dhcpAllocationPoolMgr,
+                          final DataBroker dataBroker) {
         this.interfaceManagerRpc = interfaceManagerRpc;
         this.pktService = pktService;
         this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
@@ -91,6 +96,7 @@ public class DhcpPktHandler implements PacketProcessingListener {
         this.interfaceManager = interfaceManager;
         this.config = config;
         this.dhcpAllocationPoolMgr = dhcpAllocationPoolMgr;
+        this.broker = dataBroker;
     }
 
     //TODO: Handle this in a separate thread
@@ -221,18 +227,39 @@ public class DhcpPktHandler implements PacketProcessingListener {
 
     private DhcpInfo getDhcpInfo(Port port, Subnet subnet) {
         DhcpInfo dhcpInfo = null;
+        List<IpAddress> dnsServers = subnet.getDnsNameservers();
         if (port != null && subnet != null) {
             String clientIp = getIpv4Address(port);
             String serverIp = null;
-            if (isIpv4Address(subnet.getGatewayIp())) {
+            /* 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 (config.getControllerDhcpMode() == DhcpserviceConfig.ControllerDhcpMode.UseOdlDhcpNeutronPort) {
+                java.util.Optional<SubnetToDhcpPort> dhcpPortData = DhcpServiceUtils.getSubnetDhcpPortData(broker,
+                        subnet.getUuid().getValue());
+                if (dhcpPortData.isPresent()) {
+                    serverIp = dhcpPortData.get().getPortFixedip();
+                    dhcpInfo = new DhcpInfo();
+                    if (isIpv4Address(subnet.getGatewayIp())) {
+                        dhcpInfo.setGatewayIp(subnet.getGatewayIp().getIpv4Address().getValue());
+                    }
+                    dhcpInfo.setClientIp(clientIp).setServerIp(serverIp)
+                            .setCidr(String.valueOf(subnet.getCidr().getValue())).setHostRoutes(subnet.getHostRoutes())
+                            .setDnsServersIpAddrs(dnsServers);
+                } else {
+                    // DHCP Neutron Port not found for this network
+                    LOG.error("Neutron DHCP port is not available for the Subnet {} and port {}.", subnet.getUuid(),
+                            port.getUuid());
+                }
+            //When neutronport-dhcp flag is disabled continue running DHCP Server by hijacking the subnet-gateway-ip
+            } else if (isIpv4Address(subnet.getGatewayIp())) {
                 serverIp = subnet.getGatewayIp().getIpv4Address().getValue();
-            }
-            if (clientIp != null && serverIp != null) {
-                List<IpAddress> dnsServers = subnet.getDnsNameservers();
-                dhcpInfo = new DhcpInfo();
-                dhcpInfo.setClientIp(clientIp).setServerIp(serverIp)
-                        .setCidr(String.valueOf(subnet.getCidr().getValue())).setHostRoutes(subnet.getHostRoutes())
-                        .setDnsServersIpAddrs(dnsServers).setGatewayIp(serverIp);
+                if (clientIp != null && serverIp != null) {
+                    dhcpInfo = new DhcpInfo();
+                    dhcpInfo.setClientIp(clientIp).setServerIp(serverIp)
+                            .setCidr(String.valueOf(subnet.getCidr().getValue())).setHostRoutes(subnet.getHostRoutes())
+                            .setDnsServersIpAddrs(dnsServers).setGatewayIp(serverIp);
+                }
             }
         }
         return dhcpInfo;
@@ -487,7 +514,7 @@ public class DhcpPktHandler implements PacketProcessingListener {
     }
 
     private void setCommonOptions(DHCP pkt, DhcpInfo dhcpInfo) {
-        String gwIp = dhcpInfo.getGatewayIp();
+        String serverIp = dhcpInfo.getServerIp();
         if (pkt.getMsgType() != DHCPConstants.MSG_NAK) {
             setNonNakOptions(pkt, dhcpInfo);
         }
@@ -497,8 +524,8 @@ public class DhcpPktHandler implements PacketProcessingListener {
              * options to maintain order. If we can't fill them, unset to avoid
              * sending wrong information in reply.
              */
-            if (gwIp != null) {
-                pkt.setOptionInetAddr(DHCPConstants.OPT_SERVER_IDENTIFIER, gwIp);
+            if (serverIp != null) {
+                pkt.setOptionInetAddr(DHCPConstants.OPT_SERVER_IDENTIFIER, serverIp);
             } else {
                 pkt.unsetOption(DHCPConstants.OPT_SERVER_IDENTIFIER);
             }
index e98c7886984d2f156327097e134ffb9f412dab7e..65f7d02692fe72cd81e53e42704844a79b540a38 100644 (file)
@@ -15,13 +15,18 @@ import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.concurrent.ExecutionException;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
 import java.util.stream.IntStream;
 import java.util.stream.LongStream;
-
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
+import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
+import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
 import org.opendaylight.genius.mdsalutil.ActionInfo;
 import org.opendaylight.genius.mdsalutil.FlowEntity;
 import org.opendaylight.genius.mdsalutil.InstructionInfo;
@@ -66,9 +71,14 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.Networks;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.NetworkKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
 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.SubnetDhcpPortData;
+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.api.rev150710.subnet.dhcp.port.data.SubnetToDhcpPortBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710.subnet.dhcp.port.data.SubnetToDhcpPortKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -83,7 +93,6 @@ public class DhcpServiceUtils {
             return;
         }
         List<MatchInfo> matches = getDhcpMatch(vmMacAddress);
-
         List<InstructionInfo> instructions = new ArrayList<>();
         List<ActionInfo> actionsInfos = new ArrayList<>();
 
@@ -289,6 +298,59 @@ public class DhcpServiceUtils {
                 .addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
     }
 
+    @SuppressWarnings("checkstyle:IllegalCatch")
+    protected static void createSubnetDhcpPortData(Port port,
+            BiConsumer<InstanceIdentifier<SubnetToDhcpPort>, SubnetToDhcpPort> consumer) {
+        java.util.Optional<String> ip4Address = getIpV4Address(port);
+        java.util.Optional<String> subnetId = getNeutronSubnetId(port);
+        if (!(ip4Address.isPresent() && subnetId.isPresent())) {
+            return;
+        }
+        LOG.trace("Adding SubnetPortData entry for subnet {}", subnetId.get());
+        InstanceIdentifier<SubnetToDhcpPort> identifier = buildSubnetToDhcpPort(subnetId.get());
+        SubnetToDhcpPort subnetToDhcpPort = getSubnetToDhcpPort(port, subnetId.get(), ip4Address.get());
+        try {
+            LOG.trace("Adding to SubnetToDhcpPort subnet {}  mac {}.", subnetId.get(),
+                    port.getMacAddress().getValue());
+            consumer.accept(identifier, subnetToDhcpPort);
+        } catch (Exception e) {
+            LOG.error("Failure while creating SubnetToDhcpPort map for network {}.", port.getNetworkId(), e);
+        }
+    }
+
+    @SuppressWarnings("checkstyle:IllegalCatch")
+    protected static void removeSubnetDhcpPortData(Port port, Consumer<InstanceIdentifier<SubnetToDhcpPort>> consumer) {
+        java.util.Optional<String> subnetId = getNeutronSubnetId(port);
+        if (!subnetId.isPresent()) {
+            return;
+        }
+        LOG.trace("Removing NetworkPortData entry for Subnet {}", subnetId);
+        InstanceIdentifier<SubnetToDhcpPort> identifier = buildSubnetToDhcpPort(subnetId.get());
+        try {
+            consumer.accept(identifier);
+            LOG.trace("Deleted SubnetDhcpPort for Network {}", subnetId.get());
+        } catch (Exception e) {
+            LOG.error("Failure while removing SubnetToDhcpPort for subnet {}.", subnetId, e);
+        }
+
+    }
+
+    static InstanceIdentifier<SubnetToDhcpPort> buildSubnetToDhcpPort(String subnetId) {
+        return InstanceIdentifier.builder(SubnetDhcpPortData.class)
+                .child(SubnetToDhcpPort.class, new SubnetToDhcpPortKey(subnetId)).build();
+    }
+
+    public static java.util.Optional<SubnetToDhcpPort> getSubnetDhcpPortData(DataBroker broker, String subnetId) {
+        InstanceIdentifier<SubnetToDhcpPort> id = buildSubnetToDhcpPort(subnetId);
+        try {
+            return java.util.Optional
+                    .ofNullable(SingleTransactionDataBroker.syncRead(broker, LogicalDatastoreType.CONFIGURATION, id));
+        } catch (ReadFailedException e) {
+            LOG.warn("Failed to read SubnetToDhcpPort for DS due to error {}", e.getMessage());
+        }
+        return java.util.Optional.empty();
+    }
+
     static IpAddress convertIntToIp(int ipn) {
         String[] array = IntStream.of(24, 16, 8, 0) //
                 .map(x -> (ipn >> x) & 0xFF).boxed() //
@@ -315,4 +377,40 @@ public class DhcpServiceUtils {
         return result;
     }
 
+
+    static SubnetToDhcpPort getSubnetToDhcpPort(Port port, String subnetId, String ipAddress) {
+        return new SubnetToDhcpPortBuilder()
+                .setKey(new SubnetToDhcpPortKey(subnetId))
+                .setSubnetId(subnetId).setPortName(port.getUuid().getValue())
+                .setPortMacaddress(port.getMacAddress().getValue()).setPortFixedip(ipAddress).build();
+    }
+
+    static InterfaceInfo getInterfaceInfo(IInterfaceManager interfaceManager, String interfaceName) {
+        return interfaceManager.getInterfaceInfoFromOperationalDataStore(interfaceName);
+    }
+
+    static BigInteger getDpIdFromInterface(IInterfaceManager interfaceManager, String interfaceName) {
+        return interfaceManager.getDpnForInterface(interfaceName);
+    }
+
+    public static java.util.Optional<String> getIpV4Address(Port port) {
+        if (port.getFixedIps() == null) {
+            return java.util.Optional.empty();
+        }
+        return port.getFixedIps().stream().filter(DhcpServiceUtils::isIpV4AddressAvailable)
+                .map(v -> v.getIpAddress().getIpv4Address().getValue()).findFirst();
+    }
+
+    public static java.util.Optional<String> getNeutronSubnetId(Port port) {
+        if (port.getFixedIps() == null) {
+            return java.util.Optional.empty();
+        }
+        return port.getFixedIps().stream().filter(DhcpServiceUtils::isIpV4AddressAvailable)
+                .map(v -> v.getSubnetId().getValue()).findFirst();
+    }
+
+    public static boolean isIpV4AddressAvailable(FixedIps fixedIp) {
+        return fixedIp != null && fixedIp.getIpAddress() != null && fixedIp.getIpAddress().getIpv4Address() != null;
+    }
+
 }
\ No newline at end of file
index a2e195285ec68560443ce3b7cf5e0ca7cb4406bf..49f6578e4bc9b030df3ff2d996330c412b115de5 100644 (file)
@@ -13,6 +13,7 @@ import com.google.common.util.concurrent.ListenableFuture;
 
 import java.math.BigInteger;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.Callable;
 
@@ -26,7 +27,11 @@ import org.opendaylight.netvirt.dhcpservice.DhcpExternalTunnelManager;
 import org.opendaylight.netvirt.dhcpservice.DhcpManager;
 import org.opendaylight.netvirt.dhcpservice.DhcpServiceUtils;
 import org.opendaylight.netvirt.dhcpservice.api.DhcpMConstants;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderInput.ArpReponderInputBuilder;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderUtil;
+import org.opendaylight.netvirt.elanmanager.api.IElanService;
 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.interfaces.state.Interface;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
@@ -34,6 +39,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpserv
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710._interface.name.mac.addresses.InterfaceNameMacAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710._interface.name.mac.addresses.InterfaceNameMacAddressBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710._interface.name.mac.addresses.InterfaceNameMacAddressKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710.subnet.dhcp.port.data.SubnetToDhcpPort;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -44,9 +50,10 @@ public class DhcpInterfaceAddJob implements Callable<List<ListenableFuture<Void>
     DhcpManager dhcpManager;
     DhcpExternalTunnelManager dhcpExternalTunnelManager;
     DataBroker dataBroker;
-    String interfaceName;
+    private final Interface interfaceAdd;
     BigInteger dpnId;
     IInterfaceManager interfaceManager;
+    private final IElanService elanService;
     private static final FutureCallback<Void> DEFAULT_CALLBACK = new FutureCallback<Void>() {
         @Override
         public void onSuccess(Void result) {
@@ -60,20 +67,22 @@ public class DhcpInterfaceAddJob implements Callable<List<ListenableFuture<Void>
     };
 
     public DhcpInterfaceAddJob(DhcpManager dhcpManager, DhcpExternalTunnelManager dhcpExternalTunnelManager,
-                               DataBroker dataBroker, String interfaceName, BigInteger dpnId,
-                               IInterfaceManager interfaceManager) {
+                               DataBroker dataBroker, Interface interfaceAdd, BigInteger dpnId,
+                               IInterfaceManager interfaceManager, IElanService elanService) {
         super();
         this.dhcpManager = dhcpManager;
         this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
         this.dataBroker = dataBroker;
-        this.interfaceName = interfaceName;
+        this.interfaceAdd = interfaceAdd;
         this.dpnId = dpnId;
         this.interfaceManager = interfaceManager;
+        this.elanService = elanService;
     }
 
     @Override
     public List<ListenableFuture<Void>> call() throws Exception {
         List<ListenableFuture<Void>> futures = new ArrayList<>();
+        String interfaceName = interfaceAdd.getName();
         LOG.trace("Received add DCN for interface {}, dpid {}", interfaceName, dpnId);
         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface =
                 interfaceManager.getInterfaceInfoFromConfigDataStore(interfaceName);
@@ -91,10 +100,27 @@ public class DhcpInterfaceAddJob implements Callable<List<ListenableFuture<Void>
         if (!dpnId.equals(DhcpMConstants.INVALID_DPID)) {
             Port port = dhcpManager.getNeutronPort(interfaceName);
             Subnet subnet = dhcpManager.getNeutronSubnet(port);
-            if (null != subnet && subnet.isEnableDhcp()) {
-                LOG.info("DhcpInterfaceEventListener add isEnableDhcp" + subnet.isEnableDhcp());
-                installDhcpEntries(interfaceName, dpnId, futures);
+            if (null == subnet || !subnet.isEnableDhcp()) {
+                LOG.debug("DHCP is not enabled for port {}", port.getName());
+                return Collections.emptyList();
             }
+            LOG.info("DhcpInterfaceEventListener add isEnableDhcp:{}", subnet.isEnableDhcp());
+            installDhcpEntries(interfaceAdd.getName(), dpnId, futures);
+            LOG.trace("Checking ElanDpnInterface {} for dpn {} ", interfaceName, dpnId);
+            String subnetId = subnet.getUuid().getValue();
+            java.util.Optional<SubnetToDhcpPort> subnetToDhcp = DhcpServiceUtils
+                    .getSubnetDhcpPortData(dataBroker, subnetId);
+            if (!subnetToDhcp.isPresent()) {
+                return Collections.emptyList();
+            }
+            LOG.trace("Installing the Arp responder for interface {} with DHCP MAC {} & IP {}.", interfaceName,
+                    subnetToDhcp.get().getPortMacaddress(), subnetToDhcp.get().getPortFixedip());
+            ArpReponderInputBuilder builder = new ArpReponderInputBuilder();
+            builder.setDpId(dpnId).setInterfaceName(interfaceName).setSpa(subnetToDhcp.get().getPortFixedip())
+                    .setSha(subnetToDhcp.get().getPortMacaddress()).setLportTag(interfaceAdd.getIfIndex());
+            builder.setInstructions(ArpResponderUtil.getInterfaceInstructions(interfaceManager, interfaceName,
+                    subnetToDhcp.get().getPortFixedip(), subnetToDhcp.get().getPortMacaddress()));
+            elanService.addArpResponderFlow(builder.buildForInstallFlow());
         }
         return futures;
     }
index e604bdd01ad3510c905a2aaa55233ca35769b7cd..a64136ce2d0bd02f55b65ad5a76d9584a5d2a1b6 100644 (file)
@@ -23,11 +23,16 @@ import org.opendaylight.genius.mdsalutil.MDSALUtil;
 import org.opendaylight.netvirt.dhcpservice.DhcpExternalTunnelManager;
 import org.opendaylight.netvirt.dhcpservice.DhcpManager;
 import org.opendaylight.netvirt.dhcpservice.DhcpServiceUtils;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderInput;
+import org.opendaylight.netvirt.elanmanager.api.IElanService;
 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.interfaces.state.Interface;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
 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._interface.name.mac.addresses.InterfaceNameMacAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710._interface.name.mac.addresses.InterfaceNameMacAddressKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710.subnet.dhcp.port.data.SubnetToDhcpPort;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -38,9 +43,10 @@ public class DhcpInterfaceRemoveJob implements Callable<List<ListenableFuture<Vo
     DhcpManager dhcpManager;
     DhcpExternalTunnelManager dhcpExternalTunnelManager;
     DataBroker dataBroker;
-    String interfaceName;
+    Interface interfaceDel;
     BigInteger dpnId;
     IInterfaceManager interfaceManager;
+    private final IElanService elanService;
     private static final FutureCallback<Void> DEFAULT_CALLBACK = new FutureCallback<Void>() {
         @Override
         public void onSuccess(Void result) {
@@ -55,19 +61,22 @@ public class DhcpInterfaceRemoveJob implements Callable<List<ListenableFuture<Vo
 
     public DhcpInterfaceRemoveJob(DhcpManager dhcpManager, DhcpExternalTunnelManager dhcpExternalTunnelManager,
                                   DataBroker dataBroker,
-                                  String interfaceName, BigInteger dpnId, IInterfaceManager interfaceManager) {
+                                  Interface interfaceDel, BigInteger dpnId, IInterfaceManager interfaceManager,
+                                  IElanService elanService) {
         super();
         this.dhcpManager = dhcpManager;
         this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
         this.dataBroker = dataBroker;
-        this.interfaceName = interfaceName;
+        this.interfaceDel = interfaceDel;
         this.dpnId = dpnId;
         this.interfaceManager = interfaceManager;
+        this.elanService = elanService;
     }
 
     @Override
     public List<ListenableFuture<Void>> call() throws Exception {
         List<ListenableFuture<Void>> futures = new ArrayList<>();
+        String interfaceName = interfaceDel.getName();
         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface =
                 interfaceManager.getInterfaceInfoFromConfigDataStore(interfaceName);
         if (iface != null) {
@@ -81,7 +90,21 @@ public class DhcpInterfaceRemoveJob implements Callable<List<ListenableFuture<Vo
                 return futures;
             }
         }
-        unInstallDhcpEntries(interfaceName, dpnId, futures);
+        Port port = dhcpManager.getNeutronPort(interfaceName);
+        java.util.Optional<String> subnetId = DhcpServiceUtils.getNeutronSubnetId(port);
+        if (subnetId.isPresent()) {
+            java.util.Optional<SubnetToDhcpPort> subnetToDhcp = DhcpServiceUtils.getSubnetDhcpPortData(dataBroker,
+                    subnetId.get());
+            if (subnetToDhcp.isPresent()) {
+                LOG.trace("Removing ArpResponder flow for last interface {} on DPN {}", interfaceName, dpnId);
+                ArpResponderInput arpInput = new ArpResponderInput.ArpReponderInputBuilder().setDpId(dpnId)
+                        .setInterfaceName(interfaceName).setSpa(subnetToDhcp.get().getPortFixedip())
+                        .setLportTag(interfaceDel.getIfIndex()).buildForRemoveFlow();
+                elanService.removeArpResponderFlow(arpInput);
+
+            }
+        }
+        unInstallDhcpEntries(interfaceDel.getName(), dpnId, futures);
         return futures;
     }
 
index eb1ef76ea495099993b202f3bde9462410b83d91..d6f1490c2439966df1bc8eef1e932f17b807d828 100644 (file)
@@ -1,4 +1,5 @@
 <dhcpservice-config xmlns="urn:opendaylight:params:xml:ns:yang:dhcpservice:config">
   <controller-dhcp-enabled>false</controller-dhcp-enabled>
   <dhcp-dynamic-allocation-pool-enabled>false</dhcp-dynamic-allocation-pool-enabled>
+  <controller-dhcp-mode>use-odl-dhcp-neutron-port</controller-dhcp-mode>
 </dhcpservice-config>
index e0f9f82b8f8340d0f7446e77a35bacee18926e71..90b8a92f823955ecc5111527dd433b0fab242833 100644 (file)
@@ -14,6 +14,8 @@
     interface="org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager" />
   <reference id="iInterfaceManager"
     interface="org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager" />
+  <reference id="elanService"
+             interface="org.opendaylight.netvirt.elanmanager.api.IElanService" />
 
   <odl:rpc-service id="odlInterfaceRpcService"
     interface="org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService" />
index c0b2768498583afafe5d29d2e0ecb21ffb68f5fc..bd2aef5a23d6a1517081b82aaf3d9d49cf9b53aa 100644 (file)
@@ -23,5 +23,15 @@ module dhcpservice-config {
             type boolean;
             default false;
         }
+
+        leaf controller-dhcp-mode {
+            description "Specify the controller DHCP mode to use Neutron port or Subnet gateway as DHCP server IP";
+            type enumeration {
+                enum "use-odl-dhcp-neutron-port";
+                enum "use-subnet-gateway-ip";
+            }
+            default "use-odl-dhcp-neutron-port";
+        }
+
     }
 }
index 885ceaa63e66ee234dab15f670211225ee2739cf..cde34c260f0094ba576fd159e2b5ea06f6df3b77 100644 (file)
@@ -46,6 +46,11 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <artifactId>interfacemanager-api</artifactId>
       <version>${genius.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.genius</groupId>
+      <artifactId>idmanager-api</artifactId>
+      <version>${genius.version}</version>
+    </dependency>
     <dependency>
       <groupId>${project.groupId}</groupId>
       <artifactId>neutronvpn-api</artifactId>
@@ -5,7 +5,7 @@
  * 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.arp.responder;
+package org.opendaylight.netvirt.elan.arp.responder;
 
 public enum ArpResponderConstant {
 
@@ -33,9 +33,18 @@ public enum ArpResponderConstant {
      * <p>Value:<b>Arp:tbl_{0}:lport_{1}:gw_{2}</b>
      * <ul><li>0: Table Id</li>
      * <li>1: LPort Tag</li>
-     * <li>2: Gateway IP in String</li></ul>
+     * <li>2: Target Protocol Address IP in String</li></ul>
      */
-    FLOW_ID_FORMAT("Arp:tbl_{0}:lport_{1}:gw_{2}"),
+    FLOW_ID_FORMAT_WITH_LPORT("Arp:tbl_{0}:lport_{1}:tpa_{2}"),
+    /**
+     * ARP Responder Flow ID.
+     *
+     * <p>Value:<b>Arp:tbl_{0}:lport_{1}:gw_{2}</b>
+     * <ul><li>0: Table Id</li>
+     * <li>1: LPort Tag</li>
+     * <li>2: Target Protocol Address IP in String</li></ul>
+     */
+    FLOW_ID_FORMAT_WITHOUT_LPORT("Arp:tbl_{0}:tpa_{1}"),
     /**
      * Pool name from which group id to be generated.
      *
@@ -47,7 +56,19 @@ public enum ArpResponderConstant {
      *
      * <p>Value:<b>arp.responder.group.id</b>
      */
-    ARP_RESPONDER_GROUP_ID("arp.responder.group.id");
+    ARP_RESPONDER_GROUP_ID("arp.responder.group.id"),
+    /**
+     * Prefix for arp check table.
+     *
+     * <p>Value:<b>arp.check.table.</b>
+     */
+    FLOWID_PREFIX_FOR_ARP_CHECK("arp.check.table."),
+    /**
+     * Prefix for l3 gateway mac table.
+     *
+     * <p>Value:<b>arp.l3.gwmac.table.</b>
+     */
+    FLOWID_PREFIX_FOR_MY_GW_MAC("arp.l3.gwmac.table.");
 
     /**
      * enum value holder.
diff --git a/vpnservice/elanmanager/elanmanager-api/src/main/java/org/opendaylight/netvirt/elan/arp/responder/ArpResponderInput.java b/vpnservice/elanmanager/elanmanager-api/src/main/java/org/opendaylight/netvirt/elan/arp/responder/ArpResponderInput.java
new file mode 100644 (file)
index 0000000..4135d4b
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * 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.elan.arp.responder;
+
+import com.google.common.base.Strings;
+
+import java.math.BigInteger;
+import java.util.Collections;
+import java.util.List;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
+
+
+public class ArpResponderInput {
+
+    private BigInteger dpId;
+    private String interfaceName;
+    private String spa;
+    private String sha;
+    private int lportTag;
+    private List<Instruction> instructions;
+
+    private ArpResponderInput() {
+        throw new AssertionError("Use ArpResponderInput Builder to instantiate theo object");
+    }
+
+    public BigInteger getDpId() {
+        return dpId;
+    }
+
+    public String getInterfaceName() {
+        return interfaceName;
+    }
+
+    public String getSpa() {
+        return spa;
+    }
+
+    public String getSha() {
+        return sha;
+    }
+
+    public int getLportTag() {
+        return lportTag;
+    }
+
+    public List<Instruction> getInstructions() {
+        if (instructions == null) {
+            instructions = Collections.emptyList();
+        }
+        return instructions;
+    }
+
+    public static class ArpReponderInputBuilder {
+
+        private ArpResponderInput input;
+
+        public ArpReponderInputBuilder() {
+            input = new ArpResponderInput();
+        }
+
+        public ArpResponderInput build() {
+            return input;
+        }
+
+        public ArpResponderInput buildForInstallFlow() {
+
+            if (input.dpId == null || Strings.isNullOrEmpty(input.interfaceName) || Strings.isNullOrEmpty(input.spa)
+                    || Strings.isNullOrEmpty(input.sha) || input.lportTag == 0 || input.instructions.isEmpty()) {
+                throw new AssertionError("Missing mandatory fields for ARP Responder Install Flow");
+            }
+
+            return input;
+        }
+
+        public ArpResponderInput buildForRemoveFlow() {
+
+            if (input.dpId == null || Strings.isNullOrEmpty(input.interfaceName) || Strings.isNullOrEmpty(input.spa)
+                    || input.lportTag == 0) {
+                throw new AssertionError("Missing mandatory fields for ARP Responder Install Flow");
+            }
+
+            return input;
+        }
+
+        public ArpReponderInputBuilder(ArpResponderInput input) {
+            super();
+            this.input = input;
+        }
+
+        public ArpReponderInputBuilder setDpId(BigInteger dpId) {
+            input.dpId = dpId;
+            return this;
+        }
+
+        public ArpReponderInputBuilder setInterfaceName(String interfaceName) {
+            input.interfaceName = interfaceName;
+            return this;
+        }
+
+        public ArpReponderInputBuilder setSpa(String spa) {
+            input.spa = spa;
+            return this;
+        }
+
+        public ArpReponderInputBuilder setSha(String sha) {
+            input.sha = sha;
+            return this;
+        }
+
+        public ArpReponderInputBuilder setLportTag(int lportTag) {
+            input.lportTag = lportTag;
+            return this;
+        }
+
+        public ArpReponderInputBuilder setInstructions(List<Instruction> instructions) {
+            input.instructions = instructions == null ? Collections.emptyList() : instructions;
+            return this;
+        }
+
+    }
+
+}
\ No newline at end of file
diff --git a/vpnservice/elanmanager/elanmanager-api/src/main/java/org/opendaylight/netvirt/elan/arp/responder/ArpResponderUtil.java b/vpnservice/elanmanager/elanmanager-api/src/main/java/org/opendaylight/netvirt/elan/arp/responder/ArpResponderUtil.java
new file mode 100644 (file)
index 0000000..6beda8d
--- /dev/null
@@ -0,0 +1,479 @@
+/*
+ * Copyright © 2016, 2017 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.elan.arp.responder;
+
+import java.math.BigInteger;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.BiFunction;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
+import org.opendaylight.genius.mdsalutil.ActionInfo;
+import org.opendaylight.genius.mdsalutil.BucketInfo;
+import org.opendaylight.genius.mdsalutil.FlowEntity;
+import org.opendaylight.genius.mdsalutil.GroupEntity;
+import org.opendaylight.genius.mdsalutil.InstructionInfo;
+import org.opendaylight.genius.mdsalutil.MDSALUtil;
+import org.opendaylight.genius.mdsalutil.MatchInfo;
+import org.opendaylight.genius.mdsalutil.MetaDataUtil;
+import org.opendaylight.genius.mdsalutil.NwConstants;
+import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
+import org.opendaylight.genius.mdsalutil.actions.ActionLoadIpToSpa;
+import org.opendaylight.genius.mdsalutil.actions.ActionLoadMacToSha;
+import org.opendaylight.genius.mdsalutil.actions.ActionMoveShaToTha;
+import org.opendaylight.genius.mdsalutil.actions.ActionMoveSourceDestinationEth;
+import org.opendaylight.genius.mdsalutil.actions.ActionMoveSpaToTpa;
+import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadInPort;
+import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
+import org.opendaylight.genius.mdsalutil.actions.ActionPuntToController;
+import org.opendaylight.genius.mdsalutil.actions.ActionSetArpOp;
+import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetSource;
+import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
+import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
+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.MatchEthernetType;
+import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
+import org.opendaylight.netvirt.elanmanager.api.ElanHelper;
+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.action.types.rev131112.action.list.Action;
+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.idmanager.rev160406.AllocateIdInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.add.group.input.buckets.bucket.action.action.NxActionResubmitRpcAddGroupCase;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Arp Responder Utility Class.
+ */
+public class ArpResponderUtil {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ArpResponderUtil.class);
+
+    private static final long WAIT_TIME_FOR_SYNC_INSTALL = Long.getLong("wait.time.sync.install", 300L);
+
+    /**
+     * A Utility class.
+     */
+    private ArpResponderUtil() {
+
+    }
+
+    /**
+     * Install Group flow on the DPN.
+     *
+     * @param mdSalManager
+     *            Reference of MDSAL API RPC that provides API for installing
+     *            group flow
+     * @param dpnId
+     *            DPN on which group flow to be installed
+     * @param groupdId
+     *            Uniquely identifiable Group Id for the group flow
+     * @param groupName
+     *            Name of the group flow
+     * @param buckets
+     *            List of the bucket actions for the group flow
+     */
+    public static void installGroup(IMdsalApiManager mdSalManager, BigInteger dpnId, long groupdId, String groupName,
+            List<BucketInfo> buckets) {
+        LOG.trace("Installing group flow on dpn {}", dpnId);
+        GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupdId, groupName, GroupTypes.GroupAll, buckets);
+        mdSalManager.syncInstallGroup(groupEntity, WAIT_TIME_FOR_SYNC_INSTALL);
+        try {
+            Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
+        } catch (InterruptedException e1) {
+            LOG.warn("Error while waiting for ARP Responder Group Entry to be installed on DPN {} ", dpnId);
+        }
+    }
+
+    /**
+     * Get Default ARP Responder Drop flow on the DPN.
+     *
+     * @param dpnId
+     *            DPN on which group flow to be installed
+     */
+    public static FlowEntity getArpResponderTableMissFlow(BigInteger dpnId) {
+        return MDSALUtil.buildFlowEntity(dpnId, NwConstants.ARP_RESPONDER_TABLE,
+                String.valueOf(NwConstants.ARP_RESPONDER_TABLE), NwConstants.TABLE_MISS_PRIORITY,
+                ArpResponderConstant.DROP_FLOW_NAME.value(), 0, 0, NwConstants.COOKIE_ARP_RESPONDER,
+                new ArrayList<MatchInfo>(),
+                Collections.singletonList(new InstructionApplyActions(Collections.singletonList(new ActionDrop()))));
+    }
+
+    /**
+     * Get Bucket Actions for ARP Responder Group Flow.
+     *
+     * <p>
+     * Install Default Groups, Group has 3 Buckets
+     * </p>
+     * <ul>
+     * <li>Punt to controller</li>
+     * <li>Resubmit to Table {@link NwConstants#LPORT_DISPATCHER_TABLE}, for
+     * ELAN flooding
+     * <li>Resubmit to Table {@link NwConstants#ARP_RESPONDER_TABLE}, for ARP
+     * Auto response from DPN itself</li>
+     * </ul>
+     *
+     * @param resubmitTableId
+     *            Resubmit Flow Table Id
+     * @param resubmitTableId2
+     *            Resubmit Flow Table Id
+     * @return List of bucket actions
+     */
+    public static List<BucketInfo> getDefaultBucketInfos(short resubmitTableId, short resubmitTableId2) {
+        return Arrays.asList(
+                new BucketInfo(Collections.singletonList(new ActionPuntToController())),
+                new BucketInfo(Collections.singletonList(new ActionNxResubmit(resubmitTableId))),
+                new BucketInfo(Collections.singletonList(new ActionNxResubmit(resubmitTableId2))));
+    }
+
+    /**
+     * Get Match Criteria for the ARP Responder Flow.
+     *
+     * <p>
+     * List of Match Criteria for ARP Responder
+     * </p>
+     * <ul>
+     * <li>Packet is ARP</li>
+     * <li>Packet is ARP Request</li>
+     * <li>The ARP packet is requesting for Gateway IP</li>
+     * <li>Metadata which is generated by using Service
+     * Index({@link NwConstants#L3VPN_SERVICE_INDEX}) Lport Tag
+     * ({@link MetaDataUtil#METADATA_MASK_LPORT_TAG}) and VRF
+     * ID({@link MetaDataUtil#METADATA_MASK_VRFID})</li>
+     * </ul>
+     *
+     * @param lportTag
+     *            LPort Tag
+     * @param elanInstance
+     *            Elan Instance
+     * @param ipAddress
+     *            Ip Address to be matched to this flow
+     * @return List of Match criteria
+     */
+    public static List<MatchInfo> getMatchCriteria(int lportTag, ElanInstance elanInstance,
+            String ipAddress) {
+
+        BigInteger metadata = ElanHelper.getElanMetadataLabel(elanInstance.getElanTag(), lportTag);
+        BigInteger metadataMask = ElanHelper.getElanMetadataMask();
+        return Arrays.asList(MatchEthernetType.ARP, MatchArpOp.REQUEST, new MatchArpTpa(ipAddress, "32"),
+                new MatchMetadata(metadata, metadataMask));
+
+    }
+
+    /**
+     * Get List of actions for ARP Responder Flows.
+     *
+     * <p>
+     * Actions consists of all the ARP actions and Resubmit Action to table
+     * {@link NwConstants#ELAN_BASE_TABLE} such that packets can flow ELAN Rule
+     *
+     * @param ipAddress
+     *            IP Address for which ARP Response packet is to be generated
+     * @param macAddress
+     *            MacAddress for which ARP Response packet is to be generated
+     * @return List of ARP Responder Actions actions
+     */
+    public static List<Action> getActions(IInterfaceManager ifaceMgrRpcService, String ifName, String ipAddress,
+            String macAddress) {
+
+        AtomicInteger actionCounter = new AtomicInteger();
+        List<Action> actions = arpActions.apply(actionCounter, macAddress, ipAddress);
+        actions.addAll(getEgressActionsForInterface(ifaceMgrRpcService, ifName, actionCounter.get()));
+        LOG.trace("Total Number of actions is {}", actionCounter);
+        return actions;
+
+    }
+
+    /**
+     * A Interface that represent lambda TriFunction.
+     *
+     * @param <T>
+     *            Input type
+     * @param <U>
+     *            Input type
+     * @param <S>
+     *            Input type
+     * @param <R>
+     *            Return Type
+     */
+    @SuppressWarnings("checkstyle:ParameterName")
+    public interface TriFunction<T, U, S, R> {
+        /**
+         * Apply the Action.
+         *
+         * @param t
+         *            Input1
+         * @param u
+         *            Input2
+         * @param s
+         *            Input3
+         * @return computed result
+         */
+        R apply(T t, U u, S s);
+    }
+
+    /**
+     * Lambda to apply arpAction. Inputs action counter, mac address and ip
+     * address
+     */
+    private static TriFunction<AtomicInteger, String, String, List<Action>> arpActions = (actionCounter, mac, ip) -> {
+        List<Action> actions = new ArrayList<>();
+        Collections.addAll(actions, new ActionMoveSourceDestinationEth().buildAction(actionCounter.getAndIncrement()),
+                new ActionSetFieldEthernetSource(new MacAddress(mac)).buildAction(actionCounter.getAndIncrement()),
+                new ActionSetArpOp(NwConstants.ARP_REPLY).buildAction(actionCounter.getAndIncrement()),
+                new ActionMoveShaToTha().buildAction(actionCounter.getAndIncrement()),
+                new ActionMoveSpaToTpa().buildAction(actionCounter.getAndIncrement()),
+                new ActionLoadMacToSha(new MacAddress(mac)).buildAction(actionCounter.getAndIncrement()),
+                new ActionLoadIpToSpa(ip).buildAction(actionCounter.getAndIncrement()),
+                new ActionNxLoadInPort(BigInteger.ZERO).buildAction(actionCounter.getAndIncrement()));
+        return actions;
+
+    };
+
+    /**
+     * Get instruction list for ARP responder flows.
+     */
+    public static List<Instruction> getInterfaceInstructions(IInterfaceManager ifaceMgrRpcService, String interfaceName,
+            String ipAddress, String macAddress) {
+        List<Action> actions = ArpResponderUtil.getActions(ifaceMgrRpcService, interfaceName, ipAddress, macAddress);
+        return Collections.singletonList(MDSALUtil.buildApplyActionsInstruction(actions));
+    }
+
+    /**
+     * Get instruction list for ARP responder flows originated from ext-net e.g.
+     * router-gw/fip.<br>
+     * The split-horizon bit should be reset in order to allow traffic from
+     * provider network to be routed back to flat/VLAN network and override the
+     * egress table drop flow.<br>
+     * In order to allow write-metadata in the ARP responder table the resubmit
+     * action needs to be replaced with goto instruction.
+     */
+    public static List<Instruction> getExtInterfaceInstructions(IInterfaceManager ifaceMgrRpcService,
+            String extInterfaceName, String ipAddress, String macAddress) {
+        AtomicInteger tableId = new AtomicInteger(-1);
+        List<Instruction> instructions = new ArrayList<>();
+        List<Action> actions = getActions(ifaceMgrRpcService, extInterfaceName, ipAddress, macAddress);
+        actions.removeIf(v -> {
+            org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action actionClass = v
+                    .getAction();
+            if (actionClass instanceof NxActionResubmitRpcAddGroupCase) {
+                tableId.set(((NxActionResubmitRpcAddGroupCase) actionClass).getNxResubmit().getTable());
+                return true;
+            } else {
+                return false;
+            }
+        });
+
+        instructions.add(MDSALUtil.buildApplyActionsInstruction(actions, 0));
+
+        if (tableId.get() != -1) {
+            // replace resubmit action with goto so it can co-exist with
+            // write-metadata
+            if ((short) tableId.get() > NwConstants.ARP_RESPONDER_TABLE) {
+                instructions.add(new InstructionGotoTable((short) tableId.get()).buildInstruction(2));
+            } else {
+                LOG.warn("Failed to insall responder flow for interface {}. Resubmit to {} can't be replaced with goto",
+                        extInterfaceName, tableId);
+            }
+        }
+
+        return instructions;
+    }
+
+    /**
+     * Install ARP Responder FLOW.
+     *
+     * @param mdSalManager
+     *            Reference of MDSAL API RPC that provides API for installing
+     *            flow
+     * @param dpnId
+     *            DPN on which flow to be installed
+     * @param flowId
+     *            Uniquely Identifiable Arp Responder Table flow Id
+     * @param flowName
+     *            Readable flow name
+     * @param priority
+     *            Flow Priority
+     * @param cookie
+     *            Flow Cookie
+     * @param matches
+     *            List of Match Criteria for the flow
+     * @param instructions
+     *            List of Instructions for the flow
+     */
+    public static void installFlow(IMdsalApiManager mdSalManager, BigInteger dpnId, String flowId, String flowName,
+            int priority, BigInteger cookie, List<MatchInfo> matches, List<Instruction> instructions) {
+        Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.ARP_RESPONDER_TABLE, flowId, priority, flowName, 0, 0,
+                cookie, matches, instructions);
+        mdSalManager.installFlow(dpnId, flowEntity);
+    }
+
+    /**
+     * Remove flow form DPN.
+     *
+     * @param mdSalManager
+     *            Reference of MDSAL API RPC that provides API for installing
+     *            flow
+     * @param dpnId
+     *            DPN form which flow to be removed
+     * @param flowId
+     *            Uniquely Identifiable Arp Responder Table flow Id that is to
+     *            be removed
+     */
+    public static void removeFlow(IMdsalApiManager mdSalManager, BigInteger dpnId, String flowId) {
+        Flow flowEntity = MDSALUtil.buildFlow(NwConstants.ARP_RESPONDER_TABLE, flowId);
+        mdSalManager.removeFlow(dpnId, flowEntity);
+    }
+
+    /**
+     * Creates Uniquely Identifiable flow Id.
+     *
+     * @param lportTag
+     *            LportTag of the flow
+     * @param ipAdress
+     *            Gateway IP for which ARP Response flow to be installed
+     * @return Unique Flow Id
+     *
+     * @see ArpResponderConstant#FLOW_ID_FORMAT_WITH_LPORT
+     * @see ArpResponderConstant#FLOW_ID_FORMAT_WITHOUT_LPORT
+     */
+    public static String getFlowId(int lportTag, String ipAdress) {
+        return MessageFormat.format(ArpResponderConstant.FLOW_ID_FORMAT_WITH_LPORT.value(),
+                        NwConstants.ARP_RESPONDER_TABLE, lportTag, ipAdress);
+    }
+
+    /**
+     * Generate Cookie per flow.
+     *
+     * <p>
+     * Cookie is generated by Summation of
+     * {@link NwConstants#COOKIE_ARP_RESPONDER} + 1 + lportTag + Gateway IP
+     *
+     * @param lportTag
+     *            Lport Tag of the flow
+     * @param ipAddress
+     *            Gateway IP for which ARP Response flow to be installed
+     * @return Cookie
+     */
+    public static BigInteger generateCookie(int lportTag, String ipAddress) {
+        LOG.trace("IPAddress in long {}", ipAddress);
+        BigInteger cookie = NwConstants.COOKIE_ARP_RESPONDER.add(BigInteger.valueOf(255))
+                .add(BigInteger.valueOf(ipTolong(ipAddress)));
+        return cookie.add(BigInteger.valueOf(lportTag));
+    }
+
+    private static BiFunction<Short, Integer, BigInteger> cookie = (tableId,
+            arpOpType) -> NwConstants.COOKIE_ARP_RESPONDER.add(BigInteger.ONE).add(BigInteger.valueOf(tableId))
+                    .add(BigInteger.valueOf(arpOpType));
+
+    private static BiFunction<Short, Integer, String> flowRef = (tableId,
+            arpOpType) -> (tableId == NwConstants.ARP_CHECK_TABLE
+                    ? ArpResponderConstant.FLOWID_PREFIX_FOR_ARP_CHECK.value()
+                    : ArpResponderConstant.FLOWID_PREFIX_FOR_MY_GW_MAC.value()) + tableId + NwConstants.FLOWID_SEPARATOR
+                    + (arpOpType == NwConstants.ARP_REQUEST ? "arp.request" : "arp.replay");
+
+    public static FlowEntity createArpDefaultFlow(BigInteger dpId, short tableId, int arpOpType,
+            Supplier<List<MatchInfo>> matches, Supplier<List<ActionInfo>> actions) {
+
+        List<InstructionInfo> instructions = Collections.singletonList(new InstructionApplyActions(actions.get()));
+        return MDSALUtil.buildFlowEntity(dpId, tableId, flowRef.apply(tableId, arpOpType),
+                NwConstants.DEFAULT_ARP_FLOW_PRIORITY, flowRef.apply(tableId, arpOpType), 0, 0,
+                cookie.apply(tableId, arpOpType), matches.get(), instructions);
+    }
+
+    /**
+     * Get IP Address in Long from String.
+     *
+     * @param address
+     *            IP Address that to be converted to long
+     * @return Long value of the IP Address
+     */
+    private static long ipTolong(String address) {
+
+        // Parse IP parts into an int array
+        long[] ip = new long[4];
+        String[] parts = address.split("\\.");
+
+        for (int i = 0; i < 4; i++) {
+            ip[i] = Long.parseLong(parts[i]);
+        }
+        // Add the above IP parts into an int number representing your IP
+        // in a 32-bit binary form
+        long ipNumbers = 0;
+        for (int i = 0; i < 4; i++) {
+            ipNumbers += ip[i] << (24 - (8 * i));
+        }
+        return ipNumbers;
+
+    }
+
+    /**
+     * Get List of Egress Action for the VPN interface.
+     *
+     * @param ifaceMgrRpcService
+     *            Interface Manager RPC reference that invokes API to retrieve
+     *            Egress Action
+     * @param ifName
+     *            VPN Interface for which Egress Action to be retrieved
+     * @param actionCounter
+     *            Action Key
+     * @return List of Egress Actions
+     */
+    public static List<Action> getEgressActionsForInterface(IInterfaceManager ifaceMgrRpcService, String ifName,
+            int actionCounter) {
+        List<ActionInfo> actionInfos = ifaceMgrRpcService.getInterfaceEgressActions(ifName);
+        AtomicInteger counter = new AtomicInteger(actionCounter);
+        return actionInfos.stream().map(v -> v.buildAction(counter.getAndIncrement())).collect(Collectors.toList());
+    }
+
+    /**
+     * Uses the IdManager to retrieve ARP Responder GroupId from ELAN pool.
+     *
+     * @param idManager
+     *            the id manager
+     * @return the integer
+     */
+    public static Long retrieveStandardArpResponderGroupId(IdManagerService idManager) {
+
+        AllocateIdInput getIdInput = new AllocateIdInputBuilder()
+                .setPoolName(ArpResponderConstant.ELAN_ID_POOL_NAME.value())
+                .setIdKey(ArpResponderConstant.ARP_RESPONDER_GROUP_ID.value()).build();
+
+        try {
+            Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
+            RpcResult<AllocateIdOutput> rpcResult = result.get();
+            if (rpcResult.isSuccessful()) {
+                LOG.trace("Retrieved Group Id is {}", rpcResult.getResult().getIdValue());
+                return rpcResult.getResult().getIdValue();
+            } else {
+                LOG.warn("RPC Call to Allocate Id returned with Errors {}", rpcResult.getErrors());
+            }
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.warn("Exception when Allocating Id", e);
+        }
+        return 0L;
+    }
+
+}
index d1133b75c83a7e37c3cefe92d464f4b7c70d210a..4ccd0e00938420965f85eb40761b5ca5edf352be 100644 (file)
@@ -7,15 +7,70 @@
  */
 package org.opendaylight.netvirt.elanmanager.api;
 
+import java.math.BigInteger;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
+import org.opendaylight.genius.mdsalutil.MetaDataUtil;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanDpnInterfaces;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
+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.instances.ElanInstance;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class ElanHelper {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ElanHelper.class);
+
+    private ElanHelper() {
+        throw new AssertionError(ElanHelper.class.getName() + " cannot be initialized.");
+    }
+
     public static InstanceIdentifier<ElanInstance> getElanInstanceConfigurationDataPath(String elanInstanceName) {
         return InstanceIdentifier.builder(ElanInstances.class)
                 .child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
     }
+
+    public static BigInteger getElanMetadataLabel(long elanTag) {
+        return MetaDataUtil.getElanTagMetadata(elanTag);
+    }
+
+    public static BigInteger getElanMetadataLabel(long elanTag, int lportTag) {
+        return getElanMetadataLabel(elanTag).or(MetaDataUtil.getLportTagMetaData(lportTag));
+    }
+
+    public static BigInteger getElanMetadataMask() {
+        return MetaDataUtil.METADATA_MASK_SERVICE.or(MetaDataUtil.METADATA_MASK_LPORT_TAG);
+    }
+
+    public static List<String> getDpnInterfacesInElanInstance(DataBroker broker, String elanInstanceName) {
+
+        InstanceIdentifier<ElanDpnInterfacesList> elanDpnInterfaceId = getElanDpnOperationDataPath(elanInstanceName);
+        try {
+            ElanDpnInterfacesList existingElanDpnInterfaces = SingleTransactionDataBroker.syncRead(broker,
+                    LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
+            if (existingElanDpnInterfaces != null) {
+                return existingElanDpnInterfaces.getDpnInterfaces().stream().flatMap(v -> v.getInterfaces().stream())
+                        .collect(Collectors.toList());
+            }
+        } catch (ReadFailedException e) {
+            LOG.warn("Failed to read ElanDpnInterfacesList with error {}", e.getMessage());
+        }
+        return Collections.emptyList();
+    }
+
+    public static InstanceIdentifier<ElanDpnInterfacesList> getElanDpnOperationDataPath(String elanInstanceName) {
+        return InstanceIdentifier.builder(ElanDpnInterfaces.class)
+                .child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName)).build();
+
+    }
 }
index df0b91e2ab90e97c3339ef3e678a347b6e787b19..8446d65ef0af9d292483e4609cc7fbd2ead3d0cc 100644 (file)
@@ -13,6 +13,7 @@ import java.util.Collection;
 import java.util.List;
 
 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderInput;
 import org.opendaylight.netvirt.elanmanager.exceptions.MacNotFoundException;
 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.interfaces.ElanInterface;
@@ -76,4 +77,22 @@ public interface IElanService extends IEtreeService {
 
     Boolean isOpenStackVniSemanticsEnforced();
 
+    /**
+     * Add ARP Responder Flow on the given dpn for the ingress interface.
+     *
+     * @param arpResponderInput
+     *            ArpResponder Input parameters
+     * @see ArpResponderInput
+     */
+    void addArpResponderFlow(ArpResponderInput arpResponderInput);
+
+    /**
+     * Remove ARP Responder flow from the given dpn for the ingress interface.
+     *
+     * @param arpResponderInput
+     *            ArpResponder Input parameters
+     * @see ArpResponderInput
+     */
+    void removeArpResponderFlow(ArpResponderInput arpResponderInput);
+
 }
index 939381728307051619ffaad3224365a5024d5f8e..970f7a562696fae8ff8226a0b4833c9fe3d41681 100644 (file)
       <artifactId>interfacemanager-api</artifactId>
       <version>${genius.version}</version>
     </dependency>
-    <dependency>
-      <groupId>org.opendaylight.genius</groupId>
-      <artifactId>idmanager-api</artifactId>
-      <version>${genius.version}</version>
-    </dependency>
     <dependency>
       <groupId>org.opendaylight.genius</groupId>
       <artifactId>itm-api</artifactId>
index e85c85c42224868138c386eb5e7dc91139eacfa2..f9b17a5ec487b279c58d33c0b3ebd56729d273d3 100644 (file)
@@ -64,6 +64,7 @@ import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayUtils;
 import org.opendaylight.netvirt.elan.utils.ElanConstants;
 import org.opendaylight.netvirt.elan.utils.ElanForwardingEntriesHandler;
 import org.opendaylight.netvirt.elan.utils.ElanUtils;
+import org.opendaylight.netvirt.elanmanager.api.ElanHelper;
 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
@@ -1081,7 +1082,7 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
      */
     private List<InstructionInfo> getInstructionsIntOrExtTunnelTable(Long elanTag) {
         List<InstructionInfo> mkInstructions = new ArrayList<>();
-        mkInstructions.add(new InstructionWriteMetadata(ElanUtils.getElanMetadataLabel(elanTag), ElanUtils
+        mkInstructions.add(new InstructionWriteMetadata(ElanHelper.getElanMetadataLabel(elanTag), ElanHelper
                 .getElanMetadataMask()));
         /* applicable for EXTERNAL_TUNNEL_TABLE only
         * TODO: We should point to SMAC or DMAC depending on a configuration property to enable mac learning
@@ -1458,7 +1459,7 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
             WriteTransaction tx) {
         int instructionKey = 0;
         List<Instruction> instructions = new ArrayList<>();
-        instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanUtils.getElanMetadataLabel(elanTag),
+        instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanHelper.getElanMetadataLabel(elanTag),
                 MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
 
         List<Action> actions = new ArrayList<>();
@@ -1468,7 +1469,7 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
                 elanTag).buildAction());
         instructions.add(MDSALUtil.buildApplyActionsInstruction(actions, ++instructionKey));
 
-        instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ELAN_BASE_TABLE,
+        instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ARP_CHECK_TABLE,
                 ++instructionKey));
 
         short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
index 575fb8dbac54c0b0833f0d07a38d99ab41dcef4b..98becfd9c9d26b639ce509c504461aa5a1c725e1 100644 (file)
@@ -10,11 +10,15 @@ package org.opendaylight.netvirt.elan.internal;
 import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
+import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
 import org.opendaylight.genius.mdsalutil.ActionInfo;
+import org.opendaylight.genius.mdsalutil.BucketInfo;
 import org.opendaylight.genius.mdsalutil.FlowEntity;
 import org.opendaylight.genius.mdsalutil.InstructionInfo;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
@@ -22,17 +26,22 @@ import org.opendaylight.genius.mdsalutil.MatchInfo;
 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
 import org.opendaylight.genius.mdsalutil.NwConstants;
 import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
+import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
 import org.opendaylight.genius.mdsalutil.actions.ActionLearn;
 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
 import org.opendaylight.genius.mdsalutil.actions.ActionPuntToController;
 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.genius.mdsalutil.matches.MatchArpOp;
 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetDestination;
 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
 import org.opendaylight.genius.mdsalutil.nxmatches.NxMatchRegister;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderConstant;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderUtil;
 import org.opendaylight.netvirt.elan.utils.ElanConstants;
 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.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
@@ -49,15 +58,18 @@ public class ElanNodeListener extends AsyncDataTreeChangeListenerBase<Node, Elan
 
     private final DataBroker broker;
     private final IMdsalApiManager mdsalManager;
+    private final IdManagerService idManagerService;
     private final int tempSmacLearnTimeout;
     private final boolean puntLldpToController;
 
 
-    public ElanNodeListener(DataBroker dataBroker, IMdsalApiManager mdsalManager, ElanConfig elanConfig) {
+    public ElanNodeListener(DataBroker dataBroker, IMdsalApiManager mdsalManager, ElanConfig elanConfig,
+            IdManagerService idManagerService) {
         this.broker = dataBroker;
         this.mdsalManager = mdsalManager;
         this.tempSmacLearnTimeout = elanConfig.getTempSmacLearnTimeout();
         this.puntLldpToController = elanConfig.isPuntLldpToController();
+        this.idManagerService = idManagerService;
     }
 
     @Override
@@ -89,11 +101,26 @@ public class ElanNodeListener extends AsyncDataTreeChangeListenerBase<Node, Elan
         BigInteger dpId = new BigInteger(node[1]);
         createTableMissEntry(dpId);
         createMulticastFlows(dpId);
+        createArpDefaultFlowsForArpCheckTable(dpId);
+    }
+
+    @SuppressWarnings("deprecation")
+    private void createArpDefaultFlowsForArpCheckTable(BigInteger dpId) {
+        DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+        dataStoreCoordinator.enqueueJob("ARP_CHECK_TABLE-" + dpId.toString(), () -> {
+            WriteTransaction writeFlowTx = broker.newWriteOnlyTransaction();
+            LOG.debug("Received notification to install Arp Check Default entries for dpn {} ", dpId);
+            createArpRequestMatchFlows(dpId, writeFlowTx);
+            createArpResponseMatchFlows(dpId, writeFlowTx);
+            return Arrays.asList(writeFlowTx.submit());
+        });
     }
 
     public void createTableMissEntry(BigInteger dpnId) {
         setupTableMissSmacFlow(dpnId);
         setupTableMissDmacFlow(dpnId);
+        setupTableMissArpCheckFlow(dpnId);
+        setupTableMissApResponderFlow(dpnId);
     }
 
     private void createMulticastFlows(BigInteger dpId) {
@@ -230,8 +257,45 @@ public class ElanNodeListener extends AsyncDataTreeChangeListenerBase<Node, Elan
 
     @Override
     protected ElanNodeListener getDataTreeChangeListener() {
-        // TODO Auto-generated method stub
         return ElanNodeListener.this;
     }
 
-}
+    private void setupTableMissApResponderFlow(final BigInteger dpnId) {
+        mdsalManager.installFlow(dpnId, ArpResponderUtil.getArpResponderTableMissFlow(dpnId));
+    }
+
+    private void setupTableMissArpCheckFlow(BigInteger dpnId) {
+        mdsalManager.installFlow(dpnId,
+                MDSALUtil.buildFlowEntity(dpnId, NwConstants.ARP_CHECK_TABLE,
+                        String.valueOf("L2.ELAN." + NwConstants.ARP_CHECK_TABLE), NwConstants.TABLE_MISS_PRIORITY,
+                        ArpResponderConstant.DROP_FLOW_NAME.value(), 0, 0, NwConstants.COOKIE_ARP_RESPONDER,
+                        new ArrayList<MatchInfo>(),
+                        Collections.singletonList(new InstructionGotoTable(NwConstants.ELAN_BASE_TABLE))));
+    }
+
+    private void createArpRequestMatchFlows(BigInteger dpId, WriteTransaction writeFlowTx) {
+
+        long arpRequestGroupId = ArpResponderUtil.retrieveStandardArpResponderGroupId(idManagerService);
+        List<BucketInfo> buckets = ArpResponderUtil.getDefaultBucketInfos(NwConstants.ELAN_BASE_TABLE,
+                NwConstants.ARP_RESPONDER_TABLE);
+        ArpResponderUtil.installGroup(mdsalManager, dpId, arpRequestGroupId,
+                ArpResponderConstant.GROUP_FLOW_NAME.value(), buckets);
+
+        FlowEntity arpReqArpCheckTbl = ArpResponderUtil.createArpDefaultFlow(dpId, NwConstants.ARP_CHECK_TABLE,
+                NwConstants.ARP_REQUEST, () -> Arrays.asList(MatchEthernetType.ARP, MatchArpOp.REQUEST),
+            () -> Collections.singletonList(new ActionGroup(arpRequestGroupId)));
+        LOG.trace("Invoking MDSAL to install Arp Rquest Match Flow for table {}", NwConstants.ARP_CHECK_TABLE);
+        mdsalManager.addFlowToTx(arpReqArpCheckTbl, writeFlowTx);
+
+    }
+
+    private void createArpResponseMatchFlows(BigInteger dpId, WriteTransaction writeFlowTx) {
+        FlowEntity arpRepArpCheckTbl = ArpResponderUtil.createArpDefaultFlow(dpId, NwConstants.ARP_CHECK_TABLE,
+                NwConstants.ARP_REPLY, () -> Arrays.asList(MatchEthernetType.ARP, MatchArpOp.REPLY),
+            () -> Arrays.asList(new ActionPuntToController(), new ActionNxResubmit(NwConstants.ELAN_BASE_TABLE)));
+        LOG.trace("Invoking MDSAL to install  Arp Reply Match Flow for Table {} ", NwConstants.ARP_CHECK_TABLE);
+        mdsalManager.addFlowToTx(arpRepArpCheckTbl, writeFlowTx);
+
+    }
+
+}
\ No newline at end of file
index 8d9e295281d293ffa98cfded5db00c8db3ee4ecf..a3e3be160c8770af6e9e28f53c898be969afac5a 100644 (file)
@@ -38,6 +38,7 @@ import org.opendaylight.genius.utils.ServiceIndex;
 import org.opendaylight.genius.utils.clustering.EntityOwnerUtils;
 import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundConstants;
 import org.opendaylight.infrautils.inject.AbstractLifecycle;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderInput;
 import org.opendaylight.netvirt.elan.statusanddiag.ElanStatusMonitor;
 import org.opendaylight.netvirt.elan.utils.ElanConstants;
 import org.opendaylight.netvirt.elan.utils.ElanUtils;
@@ -814,4 +815,20 @@ public class ElanServiceProvider extends AbstractLifecycle implements IElanServi
             isL2BeforeL3 = false;
         }
     }
+
+    @Override
+    public void addArpResponderFlow(ArpResponderInput arpResponderInput) {
+
+        elanUtils.addArpResponderFlow(arpResponderInput.getDpId(), arpResponderInput.getInterfaceName(),
+                arpResponderInput.getSpa(), arpResponderInput.getSha(), arpResponderInput.getLportTag(),
+                arpResponderInput.getInstructions());
+
+
+    }
+
+    @Override
+    public void removeArpResponderFlow(ArpResponderInput arpResponderInput) {
+        elanUtils.removeArpResponderFlow(arpResponderInput.getDpId(), arpResponderInput.getInterfaceName(),
+                arpResponderInput.getSpa(), arpResponderInput.getLportTag());
+    }
 }
index 63e579a34c691109d61dcdbfe1fe79802aad8713..018d9281d82f17d896df70eac84de9186019e6fc 100755 (executable)
@@ -67,6 +67,7 @@ import org.opendaylight.genius.mdsalutil.packet.Ethernet;
 import org.opendaylight.genius.mdsalutil.packet.IPv4;
 import org.opendaylight.genius.utils.ServiceIndex;
 import org.opendaylight.netvirt.elan.ElanException;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderUtil;
 import org.opendaylight.netvirt.elan.internal.ElanInstanceManager;
 import org.opendaylight.netvirt.elan.internal.ElanInterfaceManager;
 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
@@ -660,23 +661,11 @@ public class ElanUtils {
         return ElanConstants.ELAN_GID_MIN + etreeLeafTag % ElanConstants.ELAN_GID_MIN * 2;
     }
 
-    public static BigInteger getElanMetadataLabel(long elanTag) {
-        return MetaDataUtil.getElanTagMetadata(elanTag);
-    }
-
     public static BigInteger getElanMetadataLabel(long elanTag, boolean isSHFlagSet) {
         int shBit = isSHFlagSet ? 1 : 0;
         return BigInteger.valueOf(elanTag).shiftLeft(24).or(BigInteger.valueOf(shBit));
     }
 
-    public static BigInteger getElanMetadataLabel(long elanTag, int lportTag) {
-        return getElanMetadataLabel(elanTag).or(MetaDataUtil.getLportTagMetaData(lportTag));
-    }
-
-    public static BigInteger getElanMetadataMask() {
-        return MetaDataUtil.METADATA_MASK_SERVICE.or(MetaDataUtil.METADATA_MASK_LPORT_TAG);
-    }
-
     /**
      * Setting SMAC, DMAC, UDMAC in this DPN and optionally in other DPNs.
      *
@@ -732,7 +721,8 @@ public class ElanUtils {
         int lportTag = interfaceInfo.getInterfaceTag();
         // Matching metadata and eth_src fields
         List<MatchInfo> mkMatches = new ArrayList<>();
-        mkMatches.add(new MatchMetadata(getElanMetadataLabel(elanInfo.getElanTag(), lportTag), getElanMetadataMask()));
+        mkMatches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanInfo.getElanTag(), lportTag),
+                ElanHelper.getElanMetadataMask()));
         mkMatches.add(new MatchEthernetSource(new MacAddress(macAddress)));
         List<InstructionInfo> mkInstructions = new ArrayList<>();
         mkInstructions.add(new InstructionGotoTable(NwConstants.ELAN_DMAC_TABLE));
@@ -1015,7 +1005,7 @@ public class ElanUtils {
             ElanInstance elanInfo, long ifTag) {
 
         List<MatchInfo> mkMatches = new ArrayList<>();
-        mkMatches.add(new MatchMetadata(getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
+        mkMatches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
         mkMatches.add(new MatchEthernetDestination(new MacAddress(macAddress)));
 
         List<Instruction> mkInstructions = new ArrayList<>();
@@ -1095,7 +1085,7 @@ public class ElanUtils {
     public Flow buildRemoteDmacFlowEntry(BigInteger srcDpId, BigInteger destDpId, long lportTagOrVni, long elanTag,
             String macAddress, String displayName, ElanInstance elanInstance) throws ElanException {
         List<MatchInfo> mkMatches = new ArrayList<>();
-        mkMatches.add(new MatchMetadata(getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
+        mkMatches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
         mkMatches.add(new MatchEthernetDestination(new MacAddress(macAddress)));
 
         List<Instruction> mkInstructions = new ArrayList<>();
@@ -1305,7 +1295,7 @@ public class ElanUtils {
         int priority = ElanConstants.ELAN_SERVICE_PRIORITY;
         int instructionKey = 0;
         List<Instruction> instructions = new ArrayList<>();
-        instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(getElanMetadataLabel(elanTag),
+        instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanHelper.getElanMetadataLabel(elanTag),
                 MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
         instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ELAN_SMAC_TABLE, ++instructionKey));
 
@@ -2018,7 +2008,7 @@ public class ElanUtils {
     public static FlowEntity buildDmacRedirectToDispatcherFlow(BigInteger dpId, String dstMacAddress,
             String displayName, long elanTag) {
         List<MatchInfo> matches = new ArrayList<>();
-        matches.add(new MatchMetadata(getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
+        matches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
         matches.add(new MatchEthernetDestination(new MacAddress(dstMacAddress)));
         List<InstructionInfo> instructions = new ArrayList<>();
         List<ActionInfo> actions = new ArrayList<>();
@@ -2257,4 +2247,26 @@ public class ElanUtils {
         Set<String> removed = elanInstanceToInterfacesCache.remove(elanInstanceName);
         return removed != null ? removed : Collections.emptySet();
     }
-}
+
+    public void addArpResponderFlow(BigInteger dpnId, String ingressInterfaceName, String ipAddress, String macAddress,
+            int lportTag, List<Instruction> instructions) {
+        LOG.trace("Installing the ARP responder flow on DPN {} for Interface {} with MAC {} & IP {}", dpnId,
+                ingressInterfaceName, macAddress, ipAddress);
+
+        ElanInterface elanIface = getElanInterfaceByElanInterfaceName(broker, ingressInterfaceName);
+        ElanInstance elanInstance = getElanInstanceByName(broker, elanIface.getElanInstanceName());
+        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 ARP Responder flow for Interface {}", ingressInterfaceName);
+
+    }
+
+    public void removeArpResponderFlow(BigInteger dpnId, String ingressInterfaceName, String ipAddress,
+            int lportTag) {
+        LOG.trace("Removing the ARP responder flow on DPN {} of Interface {} with IP {}", dpnId, ingressInterfaceName,
+                ipAddress);
+        ArpResponderUtil.removeFlow(mdsalManager, dpnId, ArpResponderUtil.getFlowId(lportTag, ipAddress));
+    }
+}
\ No newline at end of file
index e3fde929773b57fef8f4e6eb8b0c5d910322bf32..d039091c3bc9e9efdd4931f6f2357a7b24a5d797 100644 (file)
@@ -74,6 +74,7 @@
     <argument ref="dataBroker" />
     <argument ref="mdsalUtils" />
     <argument ref="elanConfig" />
+    <argument ref="idManagerService" />
   </bean>
 
   <bean id="elanPacketInHandler"
index d90b96a110461649f123317b21410ea035d88b69..294845e0934793202518316a21cfedf73398b140 100644 (file)
@@ -1815,7 +1815,7 @@ public class NatUtil {
             LOG.debug("vpn-to-dpn-list is not empty for vpnName {}, dpn id {}, rd {} and floatingIp {}",
                     vpnName, dpnId, rd, externalIp);
             List<IpAddresses> ipAddressList = dpnInVpn.get().getIpAddresses();
-            if (ipAddressList.size() > 0) {
+            if (ipAddressList != null && !ipAddressList.isEmpty()) {
                 int floatingIpPresentCount = 0;
                 for (IpAddresses ipAddress: ipAddressList) {
                     if (!ipAddress.getIpAddress().equals(externalIp)
index f704aaff2b99889e30387233b063d1f93157aaec..198878eb0f452860a3312a257a1d38e807bf5035 100644 (file)
@@ -7,6 +7,10 @@
  */
 package org.opendaylight.netvirt.neutronvpn.api.utils;
 
+import java.util.function.Predicate;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
+
 public class NeutronConstants {
 
     public static final String DEVICE_OWNER_GATEWAY_INF = "network:router_gateway";
@@ -30,4 +34,11 @@ public class NeutronConstants {
     public static final String VIF_TYPE_MACVTAP = "macvtap";
     public static final String VNIC_TYPE_NORMAL = "normal";
 
+    public static final Predicate<Port> IS_DHCP_PORT = port -> port != null
+            && port.getDeviceOwner().equals(DEVICE_OWNER_DHCP);
+
+    public static final Predicate<Port> IS_ODL_DHCP_PORT = port -> port != null
+            && port.getDeviceOwner().equals(DEVICE_OWNER_DHCP) && port.getDeviceId() != null
+            && port.getDeviceId().startsWith("OpenDaylight");
+
 }
index d74774e351239c664e48c1f48240d8c08cc733a4..8304167d01dad27a999b6825811daf288b217057 100644 (file)
@@ -349,6 +349,9 @@ public class NeutronPortChangeListener extends AsyncDataTreeChangeListenerBase<P
         final Uuid portId = port.getUuid();
         final Uuid subnetId = port.getFixedIps().get(0).getSubnetId();
         final DataStoreJobCoordinator portDataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+        if (NeutronConstants.IS_ODL_DHCP_PORT.test(port)) {
+            return;
+        }
         portDataStoreCoordinator.enqueueJob("PORT- " + portName, () -> {
             WriteTransaction wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
             List<ListenableFuture<Void>> futures = new ArrayList<>();
@@ -383,6 +386,9 @@ public class NeutronPortChangeListener extends AsyncDataTreeChangeListenerBase<P
         final String portName = port.getUuid().getValue();
         final Uuid portId = port.getUuid();
         final Uuid subnetId = port.getFixedIps().get(0).getSubnetId();
+        if (NeutronConstants.IS_ODL_DHCP_PORT.test(port)) {
+            return;
+        }
         final DataStoreJobCoordinator portDataStoreCoordinator = DataStoreJobCoordinator.getInstance();
         portDataStoreCoordinator.enqueueJob("PORT- " + portName, () -> {
             WriteTransaction wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
index 2309a533d4891700473e656bce93566c2d1d25e3..5d7060c835b5f28dd49fadc8a09444bdb03b8e41 100644 (file)
@@ -23,7 +23,6 @@ import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
-import org.opendaylight.genius.mdsalutil.MetaDataUtil;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceBuilder;
@@ -41,7 +40,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adj
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyKey;
 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.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIds;
 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.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -115,19 +113,9 @@ public class ArpNotificationHandler implements OdlArputilListener {
     private void processArpLearning(String srcInterface, IpAddress srcIP, PhysAddress srcMac, BigInteger metadata,
             IpAddress dstIP) {
         if (metadata != null && !Objects.equals(metadata, BigInteger.ZERO)) {
-            long vpnId = MetaDataUtil.getVpnIdFromMetadata(metadata);
-            // Process ARP only if vpnservice is configured on the interface
-            InstanceIdentifier<VpnIds> vpnIdsInstanceIdentifier = VpnUtil.getVpnIdToVpnInstanceIdentifier(vpnId);
-            Optional<VpnIds> vpnIdsOptional
-                    = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnIdsInstanceIdentifier);
-            if (!vpnIdsOptional.isPresent()) {
-                LOG.trace("ARP NO_RESOLVE: VPN {} not configured. Ignoring responding to ARP requests on this VPN",
-                        vpnId);
-                return;
-            }
-            VpnIds vpnIds = vpnIdsOptional.get();
-            String vpnName = vpnIds.getVpnInstanceName();
-            if (VpnUtil.isInterfaceAssociatedWithVpn(dataBroker, vpnName, srcInterface)) {
+            Optional<String> vpn = VpnUtil.getVpnAssociatedWithInterface(dataBroker, srcInterface);
+            if (vpn.isPresent()) {
+                String vpnName = vpn.get();
                 LOG.debug("Received ARP for sender MAC {} and sender IP {} via interface {}",
                           srcMac.getValue(), srcIP.getIpv4Address().getValue(), srcInterface);
                 String ipToQuery = srcIP.getIpv4Address().getValue();
@@ -157,6 +145,11 @@ public class ArpNotificationHandler implements OdlArputilListener {
                 } else if (!isIpInArpMigrateCache(vpnName, ipToQuery)) {
                     learnMacFromArpPackets(vpnName, srcInterface, srcIP, srcMac, dstIP);
                 }
+            } else {
+                LOG.trace("ARP NO_RESOLVE: VPN  not configured. Ignoring responding to ARP requests from this"
+                        + " Interface {}.", srcInterface);
+                return;
+
             }
         }
     }
index 499a800b60bea073be91613dcb3dfe77cab7feaa..a67025c9f6524e007f4f65df77b4557d616615c9 100755 (executable)
@@ -52,7 +52,7 @@ import org.opendaylight.netvirt.vpnmanager.api.VpnExtraRouteHelper;
 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.IVpnLinkService;
 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkCache;
 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkDataComposite;
-import org.opendaylight.netvirt.vpnmanager.arp.responder.ArpResponderUtil;
+import org.opendaylight.netvirt.vpnmanager.arp.responder.ArpResponderHandler;
 import org.opendaylight.netvirt.vpnmanager.populator.input.L3vpnInput;
 import org.opendaylight.netvirt.vpnmanager.populator.intfc.VpnPopulator;
 import org.opendaylight.netvirt.vpnmanager.populator.registry.L3vpnRegistry;
@@ -63,7 +63,6 @@ import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev14081
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
@@ -128,6 +127,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
     private final IInterfaceManager interfaceManager;
     private final IVpnManager vpnManager;
     private final IVpnLinkService ivpnLinkService;
+    private final ArpResponderHandler arpResponderHandler;
 
     private ConcurrentHashMap<String, Runnable> vpnIntfMap = new ConcurrentHashMap<>();
 
@@ -148,7 +148,8 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                                final VpnFootprintService vpnFootprintService,
                                final IInterfaceManager interfaceManager,
                                final IVpnManager vpnManager,
-                               final IVpnLinkService ivpnLnkSrvce) {
+                               final IVpnLinkService ivpnLnkSrvce,
+                               final ArpResponderHandler arpResponderHandler) {
         super(VpnInterface.class, VpnInterfaceManager.class);
 
         this.dataBroker = dataBroker;
@@ -162,6 +163,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
         this.interfaceManager = interfaceManager;
         this.vpnManager = vpnManager;
         this.ivpnLinkService = ivpnLnkSrvce;
+        this.arpResponderHandler = arpResponderHandler;
         vpnInfUpdateTaskExecutor.scheduleWithFixedDelay(new VpnInterfaceUpdateTimerTask(),
             0, VPN_INF_UPDATE_TIMER_TASK_DELAY, TIME_UNIT);
     }
@@ -471,8 +473,9 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                     String gatewayMac = null;
                     long label = 0;
                     if (VpnUtil.isL3VpnOverVxLan(l3vni)) {
-                        gatewayMac = getGatewayMacAddressForInterface(vpnInstanceOpData.getVpnInstanceName(),
-                                intf.getName(), nextHop.getIpAddress()).get();
+                        final VpnPortipToPort gwPort = VpnUtil.getNeutronPortFromVpnPortFixedIp(dataBroker,
+                                vpnInstanceOpData.getVpnInstanceName(), nextHop.getIpAddress());
+                        gatewayMac = arpResponderHandler.getGatewayMacAddressForInterface(gwPort, intf.getName()).get();
                     } else {
                         label = nextHop.getLabel();
                     }
@@ -597,8 +600,8 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                         // Use this for programming ARP_RESPONDER table here.  And save this
                         // info into vpnInterface operational, so it can used in VrfEntryProcessor
                         // to populate L3_GW_MAC_TABLE there.
-                        addArpResponderFlow(dpnId, lportTag, vpnName, vpnId, interfaceName, subnetId,
-                                gwMac.get(), gatewayIp.get(), writeInvTxn);
+                        arpResponderHandler.addArpResponderFlow(dpnId, lportTag, vpnName, vpnId, interfaceName,
+                                subnetId, gatewayIp.get(), gwMac.get());
                         vpnInterfaceSubnetGwMacAddress = gwMac.get();
                     } else {
                         // A valid mac-address is not available for this subnet-gateway-ip
@@ -609,8 +612,8 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                         if (gwMac.isPresent()) {
                             VpnUtil.setupGwMacIfExternalVpn(dataBroker, mdsalManager, dpnId, interfaceName,
                                     vpnId, writeInvTxn, NwConstants.ADD_FLOW, interfaceState);
-                            addArpResponderFlow(dpnId, lportTag, vpnName, vpnId, interfaceName, subnetId,
-                                    gwMac.get(), gatewayIp.get(), writeInvTxn);
+                            arpResponderHandler.addArpResponderFlow(dpnId, lportTag, vpnName, vpnId, interfaceName,
+                                    subnetId, gatewayIp.get(), gwMac.get());
                         } else {
                             LOG.error("Gateway MAC for subnet ID {} could not be obtained, cannot create "
                                             + "ARP responder flow for interface name {}, vpnName {}, gwIp {}",
@@ -1181,7 +1184,8 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                                     vpnId, writeInvTxn, NwConstants.DEL_FLOW, interfaceState);
 
                         }
-                        removeArpResponderFlow(dpnId, lportTag, subnetId, writeInvTxn);
+                        arpResponderHandler.removeArpResponderFlow(dpnId, lportTag, interfaceName, vpnName, vpnId,
+                                subnetId);
                     }
 
                     if (!nhList.isEmpty()) {
@@ -1226,27 +1230,6 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
         }
     }
 
-    private  void addArpResponderFlow(final BigInteger dpId, final int lportTag, final String vpnName,
-                                      final long vpnId, final String ifName, final Uuid subnetId,
-                                      final String subnetGwMac, final String gwIp, final WriteTransaction writeInvTxn) {
-        LOG.trace("Creating the ARP Responder flow for VPN Interface {}",ifName);
-        final String flowId = ArpResponderUtil.getFlowID(lportTag, gwIp);
-        List<Action> actions = ArpResponderUtil.getActions(ifaceMgrRpcService, ifName, gwIp, subnetGwMac);
-        ArpResponderUtil.installFlow(mdsalManager, writeInvTxn, dpId, flowId, flowId,
-                NwConstants.DEFAULT_ARP_FLOW_PRIORITY, ArpResponderUtil.generateCookie(lportTag, gwIp),
-                ArpResponderUtil.getMatchCriteria(lportTag, vpnId, gwIp),
-                Collections.singletonList(MDSALUtil.buildApplyActionsInstruction(actions)));
-        LOG.trace("Installed the ARP Responder flow for VPN Interface {}", ifName);
-    }
-
-    private Optional<String> getGatewayMacAddressForInterface(String vpnName, String ifName, String ipAddress) {
-        VpnPortipToPort gwPort = VpnUtil.getNeutronPortFromVpnPortFixedIp(dataBroker, vpnName, ipAddress);
-        //Check if a router gateway interface is available for the subnet gw is so then use Router interface
-        // else use connected interface
-        return Optional.of((gwPort != null && gwPort.isSubnetIp())
-                ? gwPort.getMacAddress() : InterfaceUtils.getMacAddressForInterface(dataBroker, ifName).get());
-    }
-
     private Optional<String> getMacAddressForSubnetIp(String vpnName, String ifName, String ipAddress) {
         VpnPortipToPort gwPort = VpnUtil.getNeutronPortFromVpnPortFixedIp(dataBroker, vpnName, ipAddress);
         //Check if a router gateway interface is available for the subnet gw is so then use Router interface
@@ -1257,16 +1240,6 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
         return Optional.absent();
     }
 
-    private void removeArpResponderFlow(final BigInteger dpId, final int lportTag, final Uuid subnetUuid,
-                                        final WriteTransaction writeInvTxn) {
-        final Optional<String> gwIp = VpnUtil.getVpnSubnetGatewayIp(dataBroker, subnetUuid);
-        if (gwIp.isPresent()) {
-            LOG.trace("VPNInterface adjacency Gsteway IP {} for ARP Responder removal", gwIp.get());
-            final String flowId = ArpResponderUtil.getFlowID(lportTag, gwIp.get());
-            ArpResponderUtil.removeFlow(mdsalManager, writeInvTxn, dpId, flowId);
-        }
-    }
-
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
     private void removePrefixFromBGP(String primaryRd, String rd, String vpnName, String prefix, String nextHop,
@@ -1588,7 +1561,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                         operationalAdjacency = populator.createOperationalAdjacency(input);
                         int label = operationalAdjacency.getLabel().intValue();
                         addExtraRoute(vpnName, adj.getIpAddress(), nh, rdToAllocate.get(),
-                                currVpnIntf.getVpnInstanceName(), (int) label, l3vni, origin,
+                                currVpnIntf.getVpnInstanceName(), label, l3vni, origin,
                                 currVpnIntf.getName(), operationalAdjacency, encapType, writeConfigTxn);
                     } else {
                         LOG.error("No rds to allocate extraroute {}", prefix);
index 549704ca915938e6031c3c950a70622343b9c8b4..7847416636e97ded6487bc18f70fc9a796c5c411 100644 (file)
@@ -8,6 +8,7 @@
 package org.opendaylight.netvirt.vpnmanager;
 
 import java.math.BigInteger;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
@@ -15,15 +16,19 @@ import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
 import org.opendaylight.genius.mdsalutil.NwConstants;
+import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
 import org.opendaylight.genius.mdsalutil.nxmatches.NxMatchRegister;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderInput;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderInput.ArpReponderInputBuilder;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderUtil;
 import org.opendaylight.netvirt.elanmanager.api.IElanService;
 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
-import org.opendaylight.netvirt.vpnmanager.arp.responder.ArpResponderUtil;
 import org.opendaylight.netvirt.vpnmanager.utilities.InterfaceUtils;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
@@ -32,7 +37,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instru
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
@@ -50,9 +54,8 @@ public class VpnManagerImpl implements IVpnManager {
     private final VpnInstanceListener vpnInstanceListener;
     private final IdManagerService idManager;
     private final IMdsalApiManager mdsalManager;
-    private final VpnFootprintService vpnFootprintService;
-    private final OdlInterfaceRpcService ifaceMgrRpcService;
     private final IElanService elanService;
+    private final IInterfaceManager interfaceManager;
     private final VpnSubnetRouteHandler vpnSubnetRouteHandler;
 
     public VpnManagerImpl(final DataBroker dataBroker,
@@ -61,17 +64,16 @@ public class VpnManagerImpl implements IVpnManager {
                           final VpnInterfaceManager vpnInterfaceManager,
                           final IMdsalApiManager mdsalManager,
                           final VpnFootprintService vpnFootprintService,
-                          final OdlInterfaceRpcService ifaceMgrRpcService,
                           final IElanService elanService,
+                          final IInterfaceManager interfaceManager,
                           final VpnSubnetRouteHandler vpnSubnetRouteHandler) {
         this.dataBroker = dataBroker;
         this.vpnInterfaceManager = vpnInterfaceManager;
         this.vpnInstanceListener = vpnInstanceListener;
         this.idManager = idManagerService;
         this.mdsalManager = mdsalManager;
-        this.vpnFootprintService = vpnFootprintService;
-        this.ifaceMgrRpcService = ifaceMgrRpcService;
         this.elanService = elanService;
+        this.interfaceManager = interfaceManager;
         this.vpnSubnetRouteHandler = vpnSubnetRouteHandler;
     }
 
@@ -262,7 +264,7 @@ public class VpnManagerImpl implements IVpnManager {
                 installArpResponderFlowsToExternalNetworkIp(macAddress, dpnId, extInterfaceName, lportTag, vpnId,
                         fixedIp, writeTx);
             } else {
-                removeArpResponderFlowsToExternalNetworkIp(dpnId, lportTag, fixedIp, writeTx);
+                removeArpResponderFlowsToExternalNetworkIp(dpnId, lportTag, fixedIp, writeTx,extInterfaceName);
             }
         }
 
@@ -289,19 +291,25 @@ public class VpnManagerImpl implements IVpnManager {
     }
 
     private void installArpResponderFlowsToExternalNetworkIp(String macAddress, BigInteger dpnId,
-            String extInterfaceName, Integer lportTag, long vpnId, String fixedIp, WriteTransaction writeTx) {
-        String flowId = ArpResponderUtil.getFlowID(lportTag, fixedIp);
-        List<Instruction> instructions = ArpResponderUtil.getExtInterfaceInstructions(ifaceMgrRpcService,
-                extInterfaceName, fixedIp, macAddress);
-        ArpResponderUtil.installFlow(mdsalManager, writeTx, dpnId, flowId, flowId,
-                NwConstants.DEFAULT_ARP_FLOW_PRIORITY, ArpResponderUtil.generateCookie(lportTag, fixedIp),
-                ArpResponderUtil.getMatchCriteria(lportTag, vpnId, fixedIp), instructions);
+            String extInterfaceName, int lportTag, long vpnId, String fixedIp, WriteTransaction writeTx) {
+        // reset the split-horizon bit to allow traffic to be sent back to the
+        // provider port
+        List<Instruction> instructions = new ArrayList<>();
+        instructions.add(
+                new InstructionWriteMetadata(BigInteger.ZERO, MetaDataUtil.METADATA_MASK_SH_FLAG).buildInstruction(1));
+        instructions.addAll(
+                ArpResponderUtil.getExtInterfaceInstructions(interfaceManager, extInterfaceName, fixedIp, macAddress));
+        ArpReponderInputBuilder builder = new ArpReponderInputBuilder().setDpId(dpnId)
+                .setInterfaceName(extInterfaceName).setSpa(fixedIp).setSha(macAddress).setLportTag(lportTag);
+        builder.setInstructions(instructions);
+        elanService.addArpResponderFlow(builder.buildForInstallFlow());
     }
 
     private void removeArpResponderFlowsToExternalNetworkIp(BigInteger dpnId, Integer lportTag, String fixedIp,
-            WriteTransaction writeTx) {
-        String flowId = ArpResponderUtil.getFlowID(lportTag, fixedIp);
-        ArpResponderUtil.removeFlow(mdsalManager, writeTx, dpnId, flowId);
+            WriteTransaction writeTx,String extInterfaceName) {
+        ArpResponderInput arpInput = new ArpReponderInputBuilder().setDpId(dpnId).setInterfaceName(extInterfaceName)
+                .setSpa(fixedIp).setLportTag(lportTag).buildForRemoveFlow();
+        elanService.removeArpResponderFlow(arpInput);
     }
 
     private long getVpnIdFromExtNetworkId(Uuid extNetworkId) {
index 1736b2e519768f26f5b82ef6375afebc3c82a29e..eb15a60dd82da5bfb46b6f80e7364aa1a6b5af2f 100644 (file)
@@ -11,6 +11,7 @@ import com.google.common.util.concurrent.ListenableFuture;
 
 import java.math.BigInteger;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.Callable;
@@ -22,13 +23,11 @@ import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.genius.datastoreutils.AsyncClusteredDataTreeChangeListenerBase;
 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
 import org.opendaylight.genius.mdsalutil.ActionInfo;
-import org.opendaylight.genius.mdsalutil.BucketInfo;
 import org.opendaylight.genius.mdsalutil.FlowEntity;
 import org.opendaylight.genius.mdsalutil.InstructionInfo;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
 import org.opendaylight.genius.mdsalutil.MatchInfo;
 import org.opendaylight.genius.mdsalutil.NwConstants;
-import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
 import org.opendaylight.genius.mdsalutil.actions.ActionPuntToController;
 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
@@ -36,8 +35,7 @@ import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
 import org.opendaylight.genius.mdsalutil.matches.MatchArpOp;
 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
-import org.opendaylight.netvirt.vpnmanager.arp.responder.ArpResponderConstant;
-import org.opendaylight.netvirt.vpnmanager.arp.responder.ArpResponderUtil;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderUtil;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
@@ -120,8 +118,7 @@ public class VpnNodeListener extends AsyncClusteredDataTreeChangeListenerBase<No
                     makeL3IntfTblMissFlow(writeFlowTx, dpId, NwConstants.ADD_FLOW);
                     makeSubnetRouteTableMissFlow(writeFlowTx, dpId, NwConstants.ADD_FLOW);
                     createTableMissForVpnGwFlow(writeFlowTx, dpId);
-                    createArpRequestMatchFlowForGwMacTable(writeFlowTx, dpId);
-                    createArpResponseMatchFlowForGwMacTable(writeFlowTx, dpId);
+                    createL3GwMacArpFlows(writeFlowTx, dpId);
                     programTableMissForVpnVniDemuxTable(writeFlowTx, dpId, NwConstants.ADD_FLOW);
                     List<ListenableFuture<Void>> futures = new ArrayList<ListenableFuture<Void>>();
                     futures.add(writeFlowTx.submit());
@@ -194,9 +191,9 @@ public class VpnNodeListener extends AsyncClusteredDataTreeChangeListenerBase<No
                 .LPORT_DISPATCHER_TABLE));
         List<InstructionInfo> instructions = Collections.singletonList(new InstructionApplyActions(actionsInfos));
         List<MatchInfo> matches = new ArrayList<MatchInfo>();
-        String flowRef = getTableMissFlowRef(dpnId, (short)NwConstants.L3VNI_EXTERNAL_TUNNEL_DEMUX_TABLE,
+        String flowRef = getTableMissFlowRef(dpnId, NwConstants.L3VNI_EXTERNAL_TUNNEL_DEMUX_TABLE,
                 NwConstants.TABLE_MISS_FLOW);
-        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, (short)NwConstants.L3VNI_EXTERNAL_TUNNEL_DEMUX_TABLE,
+        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3VNI_EXTERNAL_TUNNEL_DEMUX_TABLE,
                 flowRef, NwConstants.TABLE_MISS_PRIORITY, "VPN-VNI Demux Table Miss", 0, 0,
                 new BigInteger("1080000", 16), matches, instructions);
 
@@ -218,51 +215,19 @@ public class VpnNodeListener extends AsyncClusteredDataTreeChangeListenerBase<No
             instructions);
         LOG.trace("Invoking MDSAL to install L3 Gw Mac Table Miss Entry");
         mdsalManager.addFlowToTx(flowEntityMissforGw, writeFlowTx);
-        mdsalManager.addFlowToTx(ArpResponderUtil.getArpResponderTableMissFlow(dpId), writeFlowTx);
     }
 
-    private void createArpRequestMatchFlowForGwMacTable(WriteTransaction writeFlowTx, BigInteger dpId) {
-        final List<BucketInfo> buckets = ArpResponderUtil.getDefaultBucketInfos(
-            NwConstants.LPORT_DISPATCHER_TABLE,
-            NwConstants.ARP_RESPONDER_TABLE);
-        ArpResponderUtil.installGroup(mdsalManager, dpId,
-            ArpResponderUtil.retrieveStandardArpResponderGroupId(idManagerService),
-            ArpResponderConstant.GROUP_FLOW_NAME.value(), buckets);
-
-        final List<MatchInfo> matches = new ArrayList<>();
-        matches.add(MatchEthernetType.ARP);
-        matches.add(MatchArpOp.REQUEST);
-        final List<ActionInfo> actionInfos = Collections.singletonList(
-            new ActionGroup(ArpResponderUtil.retrieveStandardArpResponderGroupId(idManagerService)));
-        final List<InstructionInfo> instructions = Collections.singletonList(new InstructionApplyActions(actionInfos));
-        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_GW_MAC_TABLE,
-            getFlowRefForArpFlows(dpId, NwConstants.L3_GW_MAC_TABLE, NwConstants.ARP_REQUEST),
-            NwConstants.DEFAULT_ARP_FLOW_PRIORITY, "L3GwMac Arp Rquest", 0, 0, new BigInteger("1080000", 16), matches,
-            instructions);
-        LOG.trace("Invoking MDSAL to install L3 Gw Mac Arp Rquest Match Flow");
-        mdsalManager.addFlowToTx(flowEntity, writeFlowTx);
-    }
-
-    private void createArpResponseMatchFlowForGwMacTable(WriteTransaction writeFlowTx, BigInteger dpId) {
-        List<MatchInfo> matches = new ArrayList<>();
-        matches.add(MatchEthernetType.ARP);
-        matches.add(MatchArpOp.REPLY);
-        List<ActionInfo> actionsInfos = new ArrayList<>();
-        actionsInfos.add(new ActionPuntToController());
-        actionsInfos.add(new ActionNxResubmit(NwConstants.LPORT_DISPATCHER_TABLE));
-        List<InstructionInfo> instructions = Collections.singletonList(new InstructionApplyActions(actionsInfos));
-        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_GW_MAC_TABLE,
-            getFlowRefForArpFlows(dpId, NwConstants.L3_GW_MAC_TABLE, NwConstants.ARP_REPLY),
-            NwConstants.DEFAULT_ARP_FLOW_PRIORITY, "L3GwMac Arp Reply", 0, 0, new BigInteger("1080000", 16), matches,
-            instructions);
-        LOG.trace("Invoking MDSAL to install L3 Gw Mac Arp Reply Match Flow");
-        mdsalManager.addFlowToTx(flowEntity, writeFlowTx);
-    }
-
-    private String getFlowRefForArpFlows(BigInteger dpnId, short tableId, int arpRequestOrReply) {
-        return new StringBuffer().append(FLOWID_PREFIX_FOR_ARP).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
-            .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(arpRequestOrReply)
-            .append(FLOWID_PREFIX).toString();
+    private void createL3GwMacArpFlows(WriteTransaction writeFlowTx, BigInteger dpId) {
+        FlowEntity arpReqGwMacTbl = ArpResponderUtil.createArpDefaultFlow(dpId, NwConstants.L3_GW_MAC_TABLE,
+                NwConstants.ARP_REQUEST, () -> Arrays.asList(MatchEthernetType.ARP, MatchArpOp.REQUEST),
+            () -> Collections.singletonList(new ActionNxResubmit(NwConstants.LPORT_DISPATCHER_TABLE)));
+        LOG.trace("Invoking MDSAL to install Arp Rquest Match Flow for table {}", NwConstants.L3_GW_MAC_TABLE);
+        mdsalManager.addFlowToTx(arpReqGwMacTbl, writeFlowTx);
+        FlowEntity arpRepGwMacTbl = ArpResponderUtil.createArpDefaultFlow(dpId, NwConstants.L3_GW_MAC_TABLE,
+                NwConstants.ARP_REPLY, () -> Arrays.asList(MatchEthernetType.ARP, MatchArpOp.REPLY),
+            () -> Collections.singletonList(new ActionNxResubmit(NwConstants.LPORT_DISPATCHER_TABLE)));
+        LOG.trace("Invoking MDSAL to install  Arp Reply Match Flow for Table {} ", NwConstants.L3_GW_MAC_TABLE);
+        mdsalManager.addFlowToTx(arpRepGwMacTbl, writeFlowTx);
     }
 
     private String getTableMissFlowRef(BigInteger dpnId, short tableId, int tableMiss) {
index 3b860251e4b8e857946bebfb30e1722a5e1f4681..a64ee700e482b4f164d6ec42ad936de52bded2cf 100755 (executable)
@@ -115,6 +115,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Rou
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.SubnetOpData;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnIdToVpnInstance;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceToVpnId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnToExtraroutes;
 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.adjacency.list.AdjacencyKey;
@@ -215,7 +216,7 @@ public class VpnUtil {
                 new PrefixesKey(ipPrefix)).build();
     }
 
-    static InstanceIdentifier<VpnIds> getPrefixToInterfaceIdentifier(long vpnId) {
+    public static InstanceIdentifier<VpnIds> getPrefixToInterfaceIdentifier(long vpnId) {
         return InstanceIdentifier.builder(PrefixToInterface.class)
             .child(VpnIds.class, new VpnIdsKey(vpnId)).build();
     }
@@ -490,6 +491,18 @@ public class VpnUtil {
         return vpnId;
     }
 
+    public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance
+                        .to.vpn.id.VpnInstance> getVpnInstanceToVpnIdIdentifier(
+            String vpnName) {
+        return InstanceIdentifier.builder(VpnInstanceToVpnId.class)
+                .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
+                          .VpnInstance.class,
+                        new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn
+                               .id.VpnInstanceKey(
+                                vpnName))
+                .build();
+    }
+
     /**
      * Retrieves the VPN Route Distinguisher searching by its Vpn instance name.
      *
@@ -717,18 +730,15 @@ public class VpnUtil {
         return read(broker, LogicalDatastoreType.CONFIGURATION, interfaceId).isPresent();
     }
 
-    static boolean isInterfaceAssociatedWithVpn(DataBroker broker, String vpnName, String interfaceName) {
+    static Optional<String> getVpnAssociatedWithInterface(DataBroker broker, String interfaceName) {
         InstanceIdentifier<VpnInterface> interfaceId = getVpnInterfaceIdentifier(interfaceName);
-        Optional<VpnInterface> optConfiguredVpnInterface =
-            read(broker, LogicalDatastoreType.CONFIGURATION, interfaceId);
-
+        Optional<String> vpnOptional = Optional.absent();
+        Optional<VpnInterface> optConfiguredVpnInterface = read(broker, LogicalDatastoreType.CONFIGURATION,
+                interfaceId);
         if (optConfiguredVpnInterface.isPresent()) {
-            String configuredVpnName = optConfiguredVpnInterface.get().getVpnInstanceName();
-            if (configuredVpnName != null && configuredVpnName.equalsIgnoreCase(vpnName)) {
-                return true;
-            }
+            vpnOptional = Optional.of(optConfiguredVpnInterface.get().getVpnInstanceName());
         }
-        return false;
+        return vpnOptional;
     }
 
     public static String getIpPrefix(String prefix) {
@@ -1087,7 +1097,7 @@ public class VpnUtil {
         return id;
     }
 
-    static VpnPortipToPort getNeutronPortFromVpnPortFixedIp(DataBroker broker, String vpnName, String fixedIp) {
+    public static VpnPortipToPort getNeutronPortFromVpnPortFixedIp(DataBroker broker, String vpnName, String fixedIp) {
         InstanceIdentifier id = buildVpnPortipToPortIdentifier(vpnName, fixedIp);
         Optional<VpnPortipToPort> vpnPortipToPortData = read(broker, LogicalDatastoreType.CONFIGURATION, id);
         if (vpnPortipToPortData.isPresent()) {
diff --git a/vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/arp/responder/ArpResponderHandler.java b/vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/arp/responder/ArpResponderHandler.java
new file mode 100644 (file)
index 0000000..b4196e0
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2016 - 2017 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.arp.responder;
+
+import com.google.common.base.Optional;
+
+import java.math.BigInteger;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderInput.ArpReponderInputBuilder;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderUtil;
+import org.opendaylight.netvirt.elanmanager.api.IElanService;
+import org.opendaylight.netvirt.vpnmanager.VpnUtil;
+import org.opendaylight.netvirt.vpnmanager.utilities.InterfaceUtils;
+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.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class that is responsible for handling ARP Responder flows which involves to
+ * differentiate between router and connected mac cases, identify DPNs and
+ * installation and uninstallation of flows.
+ *
+ */
+public class ArpResponderHandler {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ArpResponderHandler.class);
+    /**
+     * MDSAL DataBroker reference.
+     */
+    private final DataBroker dataBroker;
+    /**
+     * Elan RPC service reference.
+     */
+    private final IElanService elanService;
+    /**
+     * RPC to access InterfaceManager APIs.
+     */
+    private final IInterfaceManager interfaceManager;
+
+    /**
+     * Constructor.
+     *
+     * @param dataBroker
+     *            {@link #dataBroker}
+     * @param elanService
+     *            {@link #elanService}
+     * @param interfaceManager
+     *            {@link #interfaceManager}
+     *
+     */
+    public ArpResponderHandler(DataBroker dataBroker, IElanService elanService, IInterfaceManager interfaceManager) {
+        super();
+        this.dataBroker = dataBroker;
+        this.elanService = elanService;
+        this.interfaceManager = interfaceManager;
+    }
+
+    /**
+     * Add ARP Responder flow, by invoking ELan RPC service.
+     *
+     * @param dpnId
+     *            dpn Id on which ARP responder flow to be added
+     * @param lportTag
+     *            lport tag of the interface
+     * @param vpnName
+     *            vpnname of the interface
+     * @param vpnId
+     *            vpn id that interface belongs to
+     * @param interfaceName
+     *            interface to which ARP responder flow to be added
+     * @param subnetId
+     *            subnet Id of the interface
+     * @param gatewayIp
+     *            gateway ip of the interface
+     * @param mac
+     *            mac address
+     */
+    public void addArpResponderFlow(BigInteger dpnId, int lportTag, String vpnName, long vpnId, String interfaceName,
+            Uuid subnetId, String gatewayIp, String mac) {
+
+        LOG.trace("Creating the ARP Responder flow for VPN Interface {}", interfaceName);
+        ArpReponderInputBuilder builder = new ArpReponderInputBuilder();
+        builder.setDpId(dpnId).setInterfaceName(interfaceName).setSpa(gatewayIp).setSha(mac).setLportTag(lportTag);
+        builder.setInstructions(
+                ArpResponderUtil.getInterfaceInstructions(interfaceManager, interfaceName, gatewayIp, mac));
+        elanService.addArpResponderFlow(builder.buildForInstallFlow());
+    }
+
+    /**
+     * Remove ARP Responder flow when VM interface is removed, by invoking ELan
+     * RPC service.
+     *
+     * @param dpId
+     *            dpn Id on which ARP responder flow to be removed
+     * @param lportTag
+     *            lport tag of the interface
+     * @param ifName
+     *            interface to which ARP responder flow to be removed
+     * @param vpnName
+     *            vpnname of the interface
+     * @param vpnId
+     *            vpn id that interface belongs to
+     *
+     * @param subnetUuid
+     *            subnet Id of the interface
+     */
+    public void removeArpResponderFlow(BigInteger dpId, int lportTag, String ifName, String vpnName, long vpnId,
+            Uuid subnetUuid) {
+        Optional<String> gwIp = VpnUtil.getVpnSubnetGatewayIp(dataBroker, subnetUuid);
+        if (gwIp.isPresent()) {
+            ArpReponderInputBuilder builder = new ArpReponderInputBuilder();
+            builder.setDpId(dpId).setInterfaceName(ifName).setSpa(gwIp.get()).setLportTag(lportTag);
+            elanService.removeArpResponderFlow(builder.buildForRemoveFlow());
+        }
+    }
+
+    /**
+     * Get Mac address from given gateway port and interface name.
+     *
+     * @param gwPort
+     *            gateway port
+     * @param ifName
+     *            interface for which gateway to be retrieved
+     * @return mac address if present else optional absent value
+     */
+    public Optional<String> getGatewayMacAddressForInterface(VpnPortipToPort gwPort, String ifName) {
+        // Check if a router gateway interface is available for the subnet gw is
+        // so then use Router interface
+        // else use connected interface
+        return Optional.of((gwPort != null && gwPort.isSubnetIp()) ? gwPort.getMacAddress()
+                : InterfaceUtils.getMacAddressForInterface(dataBroker, ifName).get());
+    }
+
+}
\ No newline at end of file
diff --git a/vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/arp/responder/ArpResponderUtil.java b/vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/arp/responder/ArpResponderUtil.java
deleted file mode 100644 (file)
index 155a704..0000000
+++ /dev/null
@@ -1,443 +0,0 @@
-/*
- * Copyright © 2016, 2017 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.arp.responder;
-
-import java.math.BigInteger;
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
-import org.opendaylight.genius.mdsalutil.BucketInfo;
-import org.opendaylight.genius.mdsalutil.FlowEntity;
-import org.opendaylight.genius.mdsalutil.GroupEntity;
-import org.opendaylight.genius.mdsalutil.MDSALUtil;
-import org.opendaylight.genius.mdsalutil.MatchInfo;
-import org.opendaylight.genius.mdsalutil.MetaDataUtil;
-import org.opendaylight.genius.mdsalutil.NwConstants;
-import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
-import org.opendaylight.genius.mdsalutil.actions.ActionLoadIpToSpa;
-import org.opendaylight.genius.mdsalutil.actions.ActionLoadMacToSha;
-import org.opendaylight.genius.mdsalutil.actions.ActionMoveShaToTha;
-import org.opendaylight.genius.mdsalutil.actions.ActionMoveSourceDestinationEth;
-import org.opendaylight.genius.mdsalutil.actions.ActionMoveSpaToTpa;
-import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadInPort;
-import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
-import org.opendaylight.genius.mdsalutil.actions.ActionPuntToController;
-import org.opendaylight.genius.mdsalutil.actions.ActionSetArpOp;
-import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetSource;
-import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
-import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
-import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
-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.MatchEthernetType;
-import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
-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.action.types.rev131112.action.list.Action;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
-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.idmanager.rev160406.AllocateIdInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.add.group.input.buckets.bucket.action.action.NxActionResubmitRpcAddGroupCase;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Arp Responder Utility Class.
- */
-public class ArpResponderUtil {
-
-    private static final Logger LOG = LoggerFactory.getLogger(ArpResponderUtil.class);
-
-    private static final long WAIT_TIME_FOR_SYNC_INSTALL = Long.getLong("wait.time.sync.install", 300L);
-
-    /**
-     * A Utility class.
-     */
-    private ArpResponderUtil() {
-
-    }
-
-    /**
-     * Install Group flow on the DPN.
-     *
-     * @param mdSalManager Reference of MDSAL API RPC that provides API for installing group flow
-     * @param dpnId DPN on which group flow to be installed
-     * @param groupdId Uniquely identifiable Group Id for the group flow
-     * @param groupName Name of the group flow
-     * @param buckets List of the bucket actions for the group flow
-     */
-    public static void installGroup(final IMdsalApiManager mdSalManager,
-        final BigInteger dpnId, final long groupdId, final String groupName,
-        final List<BucketInfo> buckets) {
-        LOG.trace("Installing group flow on dpn {}", dpnId);
-        final GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpnId,
-            groupdId, groupName, GroupTypes.GroupAll, buckets);
-        mdSalManager.syncInstallGroup(groupEntity, WAIT_TIME_FOR_SYNC_INSTALL);
-        try {
-            Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
-        } catch (InterruptedException e1) {
-            LOG.warn("Error while waiting for ARP Responder Group Entry to be installed on DPN {} ", dpnId);
-        }
-    }
-
-    /**
-     * Get Default ARP Responder Drop flow on the DPN.
-     *
-     * @param dpnId DPN on which group flow to be installed
-     */
-    public static FlowEntity getArpResponderTableMissFlow(final BigInteger dpnId) {
-        return MDSALUtil.buildFlowEntity(dpnId, NwConstants.ARP_RESPONDER_TABLE,
-            String.valueOf(NwConstants.ARP_RESPONDER_TABLE),
-            NwConstants.TABLE_MISS_PRIORITY,
-            ArpResponderConstant.DROP_FLOW_NAME.value(), 0, 0,
-            NwConstants.COOKIE_ARP_RESPONDER,
-            new ArrayList<MatchInfo>(),
-            Collections.singletonList(new InstructionApplyActions(Collections.singletonList(new ActionDrop()))));
-    }
-
-    /**
-     * Get Bucket Actions for ARP Responder Group Flow.
-     *
-     * <p>Install Default Groups, Group has 3 Buckets
-     * </p>
-     * <ul>
-     * <li>Punt to controller</li>
-     * <li>Resubmit to Table {@link NwConstants#LPORT_DISPATCHER_TABLE}, for
-     * ELAN flooding
-     * <li>Resubmit to Table {@link NwConstants#ARP_RESPONDER_TABLE}, for ARP
-     * Auto response from DPN itself</li>
-     * </ul>
-     *
-     * @param resubmitTableId Resubmit Flow Table Id
-     * @param resubmitTableId2 Resubmit Flow Table Id
-     * @return List of bucket actions
-     */
-    public static List<BucketInfo> getDefaultBucketInfos(
-        final short resubmitTableId, final short resubmitTableId2) {
-        final List<BucketInfo> buckets = new ArrayList<>();
-        buckets.add(new BucketInfo(Collections.singletonList(new ActionPuntToController())));
-        buckets.add(new BucketInfo(Collections.singletonList(new ActionNxResubmit(resubmitTableId))));
-        buckets.add(new BucketInfo(Collections.singletonList(new ActionNxResubmit(resubmitTableId2))));
-        return buckets;
-    }
-
-    /**
-     * Get Match Criteria for the ARP Responder Flow.
-     *
-     * <p>List of Match Criteria for ARP Responder
-     * </p>
-     * <ul>
-     * <li>Packet is ARP</li>
-     * <li>Packet is ARP Request</li>
-     * <li>The ARP packet is requesting for Gateway IP</li>
-     * <li>Metadata which is generated by using Service
-     * Index({@link NwConstants#L3VPN_SERVICE_INDEX}) Lport Tag
-     * ({@link MetaDataUtil#METADATA_MASK_LPORT_TAG}) and VRF
-     * ID({@link MetaDataUtil#METADATA_MASK_VRFID})</li>
-     * </ul>
-     *
-     * @param lportTag LPort Tag
-     * @param vpnId VPN ID
-     * @param ipAddress Gateway IP
-     * @return List of Match criteria
-     */
-    public static List<MatchInfo> getMatchCriteria(final int lportTag,
-        final long vpnId, final String ipAddress) {
-
-        final List<MatchInfo> matches = new ArrayList<>();
-        short matchIndex = NwConstants.L3VPN_SERVICE_INDEX;
-        final BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(
-            lportTag, ++matchIndex, MetaDataUtil.getVpnIdMetadata(vpnId));
-        final BigInteger metadataMask = MetaDataUtil
-            .getMetaDataMaskForLPortDispatcher(
-                MetaDataUtil.METADATA_MASK_SERVICE_INDEX,
-                MetaDataUtil.METADATA_MASK_LPORT_TAG,
-                MetaDataUtil.METADATA_MASK_VRFID);
-
-        // Matching Arp request flows
-        matches.add(MatchEthernetType.ARP);
-        matches.add(new MatchMetadata(metadata, metadataMask));
-        matches.add(MatchArpOp.REQUEST);
-        matches.add(new MatchArpTpa(ipAddress, "32"));
-        return matches;
-
-    }
-
-    /**
-     * Get List of actions for ARP Responder Flows.
-     *
-     * <p>Actions consists of all the ARP actions from
-     * and Egress Actions Retrieved
-     *
-     * @param ifaceMgrRpcService Interface manager RPC reference to invoke RPC to get Egress actions for the interface
-     * @param vpnInterface VPN Interface for which flow to be installed
-     * @param ipAddress Gateway IP Address
-     * @param macAddress Gateway MacAddress
-     * @return List of ARP Responder Actions actions
-     */
-    public static List<Action> getActions(
-        final OdlInterfaceRpcService ifaceMgrRpcService,
-        final String vpnInterface, final String ipAddress,
-        final String macAddress) {
-
-        final List<Action> actions = new ArrayList<>();
-        int actionCounter = 0;
-        actions.add(new ActionMoveSourceDestinationEth().buildAction(actionCounter++));
-        actions.add(new ActionSetFieldEthernetSource(new MacAddress(macAddress)).buildAction(actionCounter++));
-        actions.add(new ActionSetArpOp(NwConstants.ARP_REPLY).buildAction(actionCounter++));
-        actions.add(new ActionMoveShaToTha().buildAction(actionCounter++));
-        actions.add(new ActionMoveSpaToTpa().buildAction(actionCounter++));
-        actions.add(new ActionLoadMacToSha(new MacAddress(macAddress)).buildAction(actionCounter++));
-        actions.add(new ActionLoadIpToSpa(ipAddress).buildAction(actionCounter++));
-        // A temporary fix until to send packet to incoming port by loading IN_PORT with zero, until in_port is
-        // overridden in table=0
-        actions.add(new ActionNxLoadInPort(BigInteger.ZERO).buildAction(actionCounter++));
-
-        actions.addAll(getEgressActionsForInterface(ifaceMgrRpcService, vpnInterface, actionCounter));
-        LOG.trace("Total Number of actions is {}", actionCounter);
-        return actions;
-
-    }
-
-    /**
-     * Get instruction list for ARP responder flows originated from ext-net e.g.
-     * router-gw/fip.<br>
-     * The split-horizon bit should be reset in order to allow traffic from
-     * provider network to be routed back to flat/VLAN network and override the
-     * egress table drop flow.<br>
-     * In order to allow write-metadata in the ARP responder table the resubmit
-     * action needs to be replaced with goto instruction.
-     */
-    public static List<Instruction> getExtInterfaceInstructions(final OdlInterfaceRpcService ifaceMgrRpcService,
-            final String extInterfaceName, final String ipAddress, final String macAddress) {
-        Short tableId = null;
-        List<Instruction> instructions = new ArrayList<>();
-        List<Action> actions = getActions(ifaceMgrRpcService, extInterfaceName, ipAddress, macAddress);
-        for (Iterator<Action> iterator = actions.iterator(); iterator.hasNext();) {
-            org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action actionClass = iterator
-                    .next().getAction();
-            if (actionClass instanceof NxActionResubmitRpcAddGroupCase) {
-                tableId = ((NxActionResubmitRpcAddGroupCase) actionClass).getNxResubmit().getTable();
-                iterator.remove();
-                break;
-            }
-        }
-
-        instructions.add(MDSALUtil.buildApplyActionsInstruction(actions, 0));
-        // reset the split-horizon bit to allow traffic to be sent back to the
-        // provider port
-        instructions.add(
-                new InstructionWriteMetadata(BigInteger.ZERO, MetaDataUtil.METADATA_MASK_SH_FLAG).buildInstruction(1));
-
-        if (tableId != null) {
-            // replace resubmit action with goto so it can co-exist with
-            // write-metadata
-            if (tableId > NwConstants.ARP_RESPONDER_TABLE) {
-                instructions.add(new InstructionGotoTable(tableId).buildInstruction(2));
-            } else {
-                LOG.warn("Failed to insall responder flow for interface {}. Resubmit to {} can't be replaced with goto",
-                        extInterfaceName, tableId);
-            }
-        }
-
-        return instructions;
-    }
-
-    /**
-     * Install ARP Responder FLOW.
-     *
-     * @param mdSalManager
-     *            Reference of MDSAL API RPC that provides API for installing
-     *            flow
-     * @param writeInvTxn
-     *            Write Transaction to write the flow
-     * @param dpnId
-     *            DPN on which flow to be installed
-     * @param flowId
-     *            Uniquely Identifiable Arp Responder Table flow Id
-     * @param flowName
-     *            Readable flow name
-     * @param priority
-     *            Flow Priority
-     * @param cookie
-     *            Flow Cookie
-     * @param matches
-     *            List of Match Criteria for the flow
-     * @param instructions
-     *            List of Instructions for the flow
-     */
-    public static void installFlow(final IMdsalApiManager mdSalManager,
-            final WriteTransaction writeInvTxn, final BigInteger dpnId,
-            final String flowId, final String flowName,
-            final int priority, final BigInteger cookie,
-            List<MatchInfo> matches, List<Instruction> instructions) {
-        final Flow flowEntity = MDSALUtil.buildFlowNew(
-                NwConstants.ARP_RESPONDER_TABLE, flowId, priority, flowName, 0,
-                0, cookie, matches, instructions);
-        mdSalManager.addFlowToTx(dpnId, flowEntity, writeInvTxn);
-    }
-
-    /**
-     * Remove flow form DPN.
-     *
-     * @param mdSalManager Reference of MDSAL API RPC that provides API for installing flow
-     * @param writeInvTxn Write Transaction to write the flow
-     * @param dpnId DPN form which flow to be removed
-     * @param flowId Uniquely Identifiable Arp Responder Table flow Id that is to be removed
-     */
-    public static void removeFlow(final IMdsalApiManager mdSalManager,
-        final WriteTransaction writeInvTxn,
-        final BigInteger dpnId, final String flowId) {
-        final Flow flowEntity = MDSALUtil
-            .buildFlow(NwConstants.ARP_RESPONDER_TABLE, flowId);
-        mdSalManager.removeFlowToTx(dpnId, flowEntity, writeInvTxn);
-    }
-
-    /**
-     * Creates Uniquely Identifiable flow Id.
-     *
-     * <p><b>Refer:</b> {@link ArpResponderConstant#FLOW_ID_FORMAT}
-     *
-     * @param lportTag LportTag of the flow
-     * @param gwIp Gateway IP for which ARP Response flow to be installed
-     * @return Unique Flow Id
-     */
-    public static String getFlowID(final int lportTag, final String gwIp) {
-        return MessageFormat.format(ArpResponderConstant.FLOW_ID_FORMAT.value(),
-            NwConstants.ARP_RESPONDER_TABLE, lportTag, gwIp);
-    }
-
-    /**
-     * Generate Cookie per flow.
-     *
-     * <p>Cookie is generated by Summation of
-     * {@link NwConstants#COOKIE_ARP_RESPONDER} + 1 + lportTag + Gateway IP
-     *
-     * @param lportTag Lport Tag of the flow
-     * @param gwIp Gateway IP for which ARP Response flow to be installed
-     * @return Cookie
-     */
-    public static BigInteger generateCookie(final long lportTag,
-        final String gwIp) {
-        LOG.trace("IPAddress in long {}", gwIp);
-        return NwConstants.COOKIE_ARP_RESPONDER.add(BigInteger.ONE)
-            .add(BigInteger.valueOf(lportTag))
-            .add(BigInteger.valueOf(ipTolong(gwIp)));
-    }
-
-    /**
-     * Get IP Address in Long from String.
-     *
-     * @param address IP Address that to be converted to long
-     * @return Long value of the IP Address
-     */
-    private static long ipTolong(String address) {
-
-        // Parse IP parts into an int array
-        long[] ip = new long[4];
-        String[] parts = address.split("\\.");
-
-        for (int i = 0; i < 4; i++) {
-            ip[i] = Long.parseLong(parts[i]);
-        }
-        // Add the above IP parts into an int number representing your IP
-        // in a 32-bit binary form
-        long ipNumbers = 0;
-        for (int i = 0; i < 4; i++) {
-            ipNumbers += ip[i] << (24 - (8 * i));
-        }
-        return ipNumbers;
-
-    }
-
-    /**
-     * Get List of Egress Action for the VPN interface.
-     *
-     * @param ifaceMgrRpcService Interface Manager RPC reference that invokes API to retrieve Egress Action
-     * @param ifName VPN Interface for which Egress Action to be retrieved
-     * @param actionCounter Action Key
-     * @return List of Egress Actions
-     */
-    public static List<Action> getEgressActionsForInterface(
-        final OdlInterfaceRpcService ifaceMgrRpcService, String ifName,
-        int actionCounter) {
-        final List<Action> listActions = new ArrayList<>();
-        try {
-            final RpcResult<GetEgressActionsForInterfaceOutput> result = ifaceMgrRpcService
-                .getEgressActionsForInterface(
-                    new GetEgressActionsForInterfaceInputBuilder()
-                        .setIntfName(ifName).build())
-                .get();
-            if (result.isSuccessful()) {
-                final List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action>
-                    actions = result
-                    .getResult().getAction();
-                for (final Action action : actions) {
-
-                    listActions
-                        .add(
-                            new org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list
-                                .ActionBuilder(
-                                action).setKey(new ActionKey(actionCounter))
-                                .setOrder(actionCounter++).build());
-
-                }
-            } else {
-                LOG.warn(
-                    "RPC Call to Get egress actions for interface {} returned with Errors {}",
-                    ifName, result.getErrors());
-            }
-        } catch (InterruptedException | ExecutionException e) {
-            LOG.warn("Exception when egress actions for interface {}", ifName,
-                e);
-        }
-        return listActions;
-    }
-
-    /**
-     * Uses the IdManager to retrieve ARP Responder GroupId from ELAN pool.
-     *
-     * @param idManager the id manager
-     * @return the integer
-     */
-    public static Long retrieveStandardArpResponderGroupId(IdManagerService idManager) {
-
-        AllocateIdInput getIdInput =
-            new AllocateIdInputBuilder().setPoolName(ArpResponderConstant.ELAN_ID_POOL_NAME.value())
-                .setIdKey(ArpResponderConstant.ARP_RESPONDER_GROUP_ID.value()).build();
-
-        try {
-            Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
-            RpcResult<AllocateIdOutput> rpcResult = result.get();
-            if (rpcResult.isSuccessful()) {
-                LOG.trace("Retrieved Group Id is {}", rpcResult.getResult().getIdValue());
-                return rpcResult.getResult().getIdValue();
-            } else {
-                LOG.warn("RPC Call to Allocate Id returned with Errors {}", rpcResult.getErrors());
-            }
-        } catch (InterruptedException | ExecutionException e) {
-            LOG.warn("Exception when Allocating Id", e);
-        }
-        return 0L;
-    }
-
-}
index 6d278cce0711f7e8e27a2602885206aa6c56f1ca..9a98b74cf34c9325ddc5d7cb8386d948717ca43c 100644 (file)
   <service ref="vpnFootprintService"
            interface="org.opendaylight.netvirt.vpnmanager.api.IVpnFootprintService" />
 
+  <bean id="arpResponderHandler" class="org.opendaylight.netvirt.vpnmanager.arp.responder.ArpResponderHandler">
+    <argument ref="dataBroker" />
+    <argument ref="elanService" />
+    <argument ref="interfaceManager" />
+  </bean>
+
   <bean id="vpnInterfaceManager"
         class="org.opendaylight.netvirt.vpnmanager.VpnInterfaceManager"
         init-method="start" destroy-method="close">
@@ -77,6 +83,7 @@
     <argument ref="interfaceManager" />
     <argument ref="vpnManager" />
     <argument ref="interVpnLinkService" />
+    <argument ref="arpResponderHandler" />
   </bean>
 
   <bean id="interfaceStateChangeListener"
     <argument ref="vpnInterfaceManager" />
     <argument ref="mdsalUtils" />
     <argument ref="vpnFootprintService" />
-    <argument ref="odlInterfaceRpcService" />
     <argument ref="elanService" />
+    <argument ref="interfaceManager" />
     <argument ref="vpnSubnetRouteHandler" />
-
   </bean>
   <service ref="vpnManagerImpl"
            interface="org.opendaylight.netvirt.vpnmanager.api.IVpnManager" />