Neutron Port allocation for DHCP Service 69/61469/2
authorAchuth Maniyedath <achuth.m@altencalsoftlabs.com>
Thu, 11 May 2017 18:32:50 +0000 (00:02 +0530)
committerSam Hague <shague@redhat.com>
Thu, 10 Aug 2017 21:04:28 +0000 (21:04 +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: If1c787c50bd3054766caaa6b11e6c8023402cce4
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>
34 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/org/opendaylight/blueprint/dhcpservice.xml
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/NeutronNetworkChangeListener.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 fb78839c782d5a8c289d226a4ecc560ce31e8523..711c3ef767ddbdec72d08fdcca7c93fa9bacdddf 100644 (file)
@@ -46,4 +46,5 @@ module dhcpservice-api {
             leaf port-macaddress { type string;}
         }
     }
+
 }
\ No newline at end of file
index c576284eb77a00ecfe15484bc65e59262d421e3b..228bb71d90a1cd59bc88c0741a24833f0ced331e 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,12 +19,15 @@ 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.iana._if.type.rev140508.L2vlan;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.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;
@@ -41,15 +43,17 @@ public class DhcpInterfaceEventListener
     private final DhcpExternalTunnelManager dhcpExternalTunnelManager;
     private final 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();
     }
@@ -70,10 +74,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);
     }
 
@@ -113,14 +121,20 @@ public class DhcpInterfaceEventListener
             return;
         }
         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..7cc5eca0f62cc43e131a0d457f973f6bedf51590 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.netvirt.dhcpservice;
 
+import com.google.common.base.Optional;
+
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.math.BigInteger;
@@ -25,6 +27,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 +61,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 +80,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 +89,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 +98,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
@@ -223,16 +231,25 @@ public class DhcpPktHandler implements PacketProcessingListener {
         DhcpInfo dhcpInfo = null;
         if (port != null && subnet != null) {
             String clientIp = getIpv4Address(port);
-            String serverIp = null;
-            if (isIpv4Address(subnet.getGatewayIp())) {
-                serverIp = subnet.getGatewayIp().getIpv4Address().getValue();
-            }
-            if (clientIp != null && serverIp != null) {
-                List<IpAddress> dnsServers = subnet.getDnsNameservers();
+            List<IpAddress> dnsServers = subnet.getDnsNameservers();
+            /* If neutronport-dhcp flag was enabled and an ODL Subnet DHCP Port data was made available use the
+             * ports Fixed IP as server IP for DHCP communication.
+             */
+            java.util.Optional<SubnetToDhcpPort> dhcpPortData = DhcpServiceUtils.getSubnetDhcpPortData(broker,
+                    subnet.getUuid().getValue());
+            if (dhcpPortData.isPresent()) {
+                String 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).setGatewayIp(serverIp);
+                        .setDnsServersIpAddrs(dnsServers);
+            } else {
+                // DHCP Neutron Port not found for this network
+                LOG.error("DHCP response failed as Neutron DHCP Port is absent on subnet {} and so"
+                        + " cannot respond with offer for Port {}.", subnet.getUuid(),port.getUuid());
             }
         }
         return dhcpInfo;
@@ -269,7 +286,7 @@ public class DhcpPktHandler implements PacketProcessingListener {
     }
 
     private boolean isIpv4Address(IpAddress ip) {
-        return ip.getIpv4Address() != null;
+        return ip != null && ip.getIpv4Address() != null;
     }
 
     private Subnet getNeutronSubnet(Port port) {
@@ -487,7 +504,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 +514,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 ad38393330266604795dd9cf706f25d27233e752..3478c9548df693714fc7033aef28c96bdc97f3c4 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,56 @@ 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) {
+        String subnetId = port.getDeviceId().substring("OpenDaylight".length() + 1);
+        LOG.trace("Removing NetworkPortData entry for Subnet {}", subnetId);
+        InstanceIdentifier<SubnetToDhcpPort> identifier = buildSubnetToDhcpPort(subnetId);
+        try {
+            consumer.accept(identifier);
+            LOG.trace("Deleted SubnetDhcpPort for Subnet {}", subnetId);
+        } 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 +374,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..10e7545507842b39642cba9414294ed5c7a8908d 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,20 @@ 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 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 885ceaa63e66ee234dab15f670211225ee2739cf..b444412684b6dbb89c6c69933d79968f5342d3ab 100644 (file)
@@ -45,6 +45,16 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <groupId>org.opendaylight.genius</groupId>
       <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>idmanager-api</artifactId>
+      <version>${genius.version}</version>
     </dependency>
     <dependency>
       <groupId>${project.groupId}</groupId>
@@ -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..e2ba332
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * 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() {}
+
+    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;
+        }
+
+    }
+
+}
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 93a14860b88542bb9dba773926bdc9ef576c1017..4ce75b5211f162c15ade6111d710fa4bf52f8d02 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 551dc26a974465f2afbe4d1f9daefa8eeb94c5b4..55c3c88e2a86c4954845967731140ac21347a719 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;
@@ -1089,7 +1090,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
@@ -1466,7 +1467,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<>();
@@ -1476,7 +1477,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 4f26abfad0ff90c910b7c2f8a0fa036f938f3317..dc5528ec87a3bc0104b7b32c8899e48a27391241 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,18 @@ 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 1f73913168d959c97cad7b5c93d8fed3da6f5bd2..0510a987b297beb62c51ccd6a6911457d3cfbd34 100755 (executable)
@@ -69,6 +69,7 @@ import org.opendaylight.genius.utils.ServiceIndex;
 import org.opendaylight.genius.utils.batching.ResourceBatchingManager;
 import org.opendaylight.genius.utils.batching.ResourceBatchingManager.ShardResource;
 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;
@@ -667,23 +668,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.
      *
@@ -739,7 +728,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));
@@ -1022,7 +1012,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<>();
@@ -1102,7 +1092,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<>();
@@ -1312,7 +1302,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));
 
@@ -2014,7 +2004,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<>();
@@ -2330,4 +2320,26 @@ public class ElanUtils {
     public static String getElanInterfaceJobKey(String interfaceName) {
         return "elaninterface-" + interfaceName;
     }
-}
\ No newline at end of file
+
+    public void addArpResponderFlow(BigInteger dpnId, String ingressInterfaceName, String ipAddress, String macAddress,
+            int lportTag, List<Instruction> instructions) {
+        LOG.info("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.info("Installed the ARP Responder flow for Interface {}", ingressInterfaceName);
+    }
+
+    public void removeArpResponderFlow(BigInteger dpnId, String ingressInterfaceName, String ipAddress,
+            int lportTag) {
+        LOG.info("Removing the ARP responder flow on DPN {} of Interface {} with IP {}", dpnId, ingressInterfaceName,
+                ipAddress);
+        ArpResponderUtil.removeFlow(mdsalManager, dpnId, ArpResponderUtil.getFlowId(lportTag, ipAddress));
+    }
+}
+
+
index d2af26caf8a0370deda07f945bb25154d2f90333..19734b1bfedc3cd854a6ecd408f880357814a94f 100644 (file)
@@ -74,6 +74,7 @@
     <argument ref="dataBroker" />
     <argument ref="mdsalUtils" />
     <argument ref="elanConfig" />
+    <argument ref="idManagerService" />
   </bean>
 
   <bean id="elanPacketInHandler"
index b08e2d15f617a22f8606fc3435875c79554f6a55..a2dabc7efb2d43d4239e7846e0b1b0dc52294caa 100644 (file)
@@ -1766,9 +1766,9 @@ public class NatUtil {
                     + "rd {} and floatingIp {}", vpnName, dpnId, rd, externalIp);
             try {
                 List<IpAddresses> ipAddressList = dpnInVpn.get().getIpAddresses();
-                if ((ipAddressList != null) && (ipAddressList.size() > 0)) {
+                if (ipAddressList != null && !ipAddressList.isEmpty()) {
                     int floatingIpPresentCount = 0;
-                    for (IpAddresses ipAddress : ipAddressList) {
+                    for (IpAddresses ipAddress: ipAddressList) {
                         if (!ipAddress.getIpAddress().equals(externalIp)
                                 && IpAddresses.IpAddressSource.FloatingIP.equals(ipAddress.getIpAddressSource())) {
                             floatingIpPresentCount++;
index f704aaff2b99889e30387233b063d1f93157aaec..af2db1cf164d2aa0b16fb2e8152a87b8c8ec5bf6 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
+            && DEVICE_OWNER_DHCP.equals(port.getDeviceOwner());
+
+    public static final Predicate<Port> IS_ODL_DHCP_PORT = port -> port != null
+            && DEVICE_OWNER_DHCP.equals(port.getDeviceOwner()) && port.getDeviceId() != null
+            && port.getDeviceId().startsWith("OpenDaylight");
+
 }
index abd74c6262515d27aaf78d7b0c1857d938d56c05..9c60acb0fdec37b57e5adca9f003ed42429af78d 100644 (file)
@@ -153,9 +153,12 @@ public class NeutronNetworkChangeListener extends AsyncDataTreeChangeListenerBas
         if (!Objects.equals(origSegmentType, updateSegmentType)
                 || !Objects.equals(origSegmentationId, updateSegmentationId)
                 || !Objects.equals(origPhysicalNetwork, updatePhysicalNetwork)) {
-            if (NeutronvpnUtils.getIsExternal(original) && NeutronvpnUtils.isFlatOrVlanNetwork(original)) {
+            if (NeutronvpnUtils.getIsExternal(original) && NeutronvpnUtils.isFlatOrVlanNetwork(original)
+                    && !NeutronvpnUtils.isFlatOrVlanNetwork(update)) {
                 nvpnManager.removeExternalVpnInterfaces(original.getUuid());
+                nvpnManager.removeVpn(original.getUuid());
             }
+
             ElanInstance elanInstance = elanService.getElanInstance(elanInstanceName);
             if (elanInstance != null) {
                 elanService.deleteExternalElanNetwork(elanInstance);
@@ -164,9 +167,12 @@ public class NeutronNetworkChangeListener extends AsyncDataTreeChangeListenerBas
                 elanService.updateExternalElanNetwork(elanInstance);
             }
 
-            if (NeutronvpnUtils.getIsExternal(update) && NeutronvpnUtils.isFlatOrVlanNetwork(update)) {
+            if (NeutronvpnUtils.getIsExternal(update) && NeutronvpnUtils.isFlatOrVlanNetwork(update)
+                    && !NeutronvpnUtils.isFlatOrVlanNetwork(original)) {
+                nvpnManager.createL3InternalVpn(update.getUuid(), null, null, null, null, null, null, null);
                 nvpnManager.createExternalVpnInterfaces(update.getUuid());
             }
+
         }
     }
 
index 97def2c3b9044ffa9724b468e708576d7b7e58ed..66b9b48745e4519f67186b23192a81ebfd36fdf0 100644 (file)
@@ -346,6 +346,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<>();
@@ -380,6 +383,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 7fcb99ee0760350c798cee1872c183273cef5f11..2cb2fa074374583b06fb71be33ca7806e1270e63 100644 (file)
@@ -25,7 +25,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.genius.mdsalutil.NWUtil;
 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;
@@ -45,7 +44,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;
@@ -126,26 +124,18 @@ public class ArpNotificationHandler implements OdlArputilListener {
         }
         BigInteger metadata = notification.getMetadata();
         IpAddress targetIP = notification.getDstIpaddress();
+        LOG.trace("ArpNotification Response Received from interface {} and IP {} having MAC {}, learning MAC",
+                srcInterface, srcIP.getIpv4Address().getValue(), srcMac.getValue());
         processArpLearning(srcInterface, srcIP, srcMac, metadata, targetIP);
     }
 
     private void processArpLearning(String srcInterface, IpAddress srcIP, PhysAddress srcMac, BigInteger metadata,
             IpAddress dstIP) {
         if (metadata != null && !Objects.equals(metadata, BigInteger.ZERO)) {
-            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)) {
-                LOG.debug("Received ARP for sender MAC {} and sender IP {} via interface {}",
+            Optional<String> vpn = VpnUtil.getVpnAssociatedWithInterface(dataBroker, srcInterface);
+            if (vpn.isPresent()) {
+                String vpnName = vpn.get();
+                LOG.info("Received ARP for sender MAC {} and sender IP {} via interface {}",
                           srcMac.getValue(), srcIP.getIpv4Address().getValue(), srcInterface);
                 String ipToQuery = srcIP.getIpv4Address().getValue();
                 LOG.info("ARP being processed for Source IP {}", ipToQuery);
@@ -174,6 +164,11 @@ public class ArpNotificationHandler implements OdlArputilListener {
                 } else if (!isIpInArpMigrateCache(vpnName, ipToQuery)) {
                     learnMacFromArpPackets(vpnName, srcInterface, srcIP, srcMac, dstIP);
                 }
+            } else {
+                LOG.info("ARP NO_RESOLVE: VPN  not configured. Ignoring responding to ARP requests from this"
+                        + " Interface {}.", srcInterface);
+                return;
+
             }
         }
     }
index a3c57f590c51b7676135c24a1e5cbf96efc10e45..cfdcde64b1f3997381449631ea3dcc6a1fe8bf4e 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;
@@ -129,6 +128,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<>();
 
@@ -149,7 +149,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;
@@ -163,6 +164,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);
     }
@@ -493,8 +495,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();
                     }
@@ -627,8 +630,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
@@ -639,8 +642,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 {}",
@@ -1214,7 +1217,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()) {
@@ -1259,27 +1263,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
@@ -1290,16 +1273,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,
@@ -1629,7 +1602,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 547394da449c7b0207a3e0ba6195a58482e5450e..13dc30bb2d42c62fd8f63f6498619a7613b03698 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;
     }
 
@@ -263,7 +265,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);
             }
         }
 
@@ -290,19 +292,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 1a936afc863d4eb3442e37c746453260b5c2b820..eb15a60dd82da5bfb46b6f80e7364aa1a6b5af2f 100644 (file)
@@ -11,8 +11,10 @@ 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;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
@@ -21,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;
@@ -35,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;
@@ -110,19 +109,21 @@ public class VpnNodeListener extends AsyncClusteredDataTreeChangeListenerBase<No
     private void processNodeAdd(BigInteger dpId) {
         DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
         dataStoreCoordinator.enqueueJob("VPNNODE-" + dpId.toString(),
-            () -> {
-                WriteTransaction writeFlowTx = broker.newWriteOnlyTransaction();
-                LOG.debug("Received notification to install TableMiss entries for dpn {} ", dpId);
-                makeTableMissFlow(writeFlowTx, dpId, NwConstants.ADD_FLOW);
-                makeL3IntfTblMissFlow(writeFlowTx, dpId, NwConstants.ADD_FLOW);
-                makeSubnetRouteTableMissFlow(writeFlowTx, dpId, NwConstants.ADD_FLOW);
-                createTableMissForVpnGwFlow(writeFlowTx, dpId);
-                createArpRequestMatchFlowForGwMacTable(writeFlowTx, dpId);
-                createArpResponseMatchFlowForGwMacTable(writeFlowTx, dpId);
-                programTableMissForVpnVniDemuxTable(writeFlowTx, dpId, NwConstants.ADD_FLOW);
-                List<ListenableFuture<Void>> futures = new ArrayList<>();
-                futures.add(writeFlowTx.submit());
-                return futures;
+            new Callable<List<ListenableFuture<Void>>>() {
+                @Override
+                public List<ListenableFuture<Void>> call() throws Exception {
+                    WriteTransaction writeFlowTx = broker.newWriteOnlyTransaction();
+                    LOG.debug("Received notification to install TableMiss entries for dpn {} ", dpId);
+                    makeTableMissFlow(writeFlowTx, dpId, NwConstants.ADD_FLOW);
+                    makeL3IntfTblMissFlow(writeFlowTx, dpId, NwConstants.ADD_FLOW);
+                    makeSubnetRouteTableMissFlow(writeFlowTx, dpId, NwConstants.ADD_FLOW);
+                    createTableMissForVpnGwFlow(writeFlowTx, dpId);
+                    createL3GwMacArpFlows(writeFlowTx, dpId);
+                    programTableMissForVpnVniDemuxTable(writeFlowTx, dpId, NwConstants.ADD_FLOW);
+                    List<ListenableFuture<Void>> futures = new ArrayList<ListenableFuture<Void>>();
+                    futures.add(writeFlowTx.submit());
+                    return futures;
+                }
             });
     }
 
@@ -190,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);
 
@@ -214,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 108dc369bfdb0f479209475b4838e335c3333167..69312c699db3d3db00285c926cc56b51a9f2f56a 100755 (executable)
@@ -116,6 +116,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;
@@ -216,7 +217,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();
     }
@@ -491,6 +492,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.
      *
@@ -718,18 +731,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) {
@@ -1088,7 +1098,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..499b995
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * 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 06fcf460f27b1bb569807a360f47393a99466d66..2f431524d08edd107c8ee3dc473ff5c3fb1d706f 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" />