Merge "Sonar clean-up: OF13Provider"
authorSam Hague <shague@redhat.com>
Tue, 21 Jul 2015 12:53:48 +0000 (12:53 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Tue, 21 Jul 2015 12:53:48 +0000 (12:53 +0000)
47 files changed:
Vagrantfile
integrationtest/src/test/java/org/opendaylight/ovsdb/integrationtest/library/OvsdbLibraryIT.java
integrationtest/src/test/java/org/opendaylight/ovsdb/integrationtest/ovsdbclient/OvsdbClientTestIT.java
integrationtest/src/test/java/org/opendaylight/ovsdb/integrationtest/plugin/OvsdbPluginIT.java
integrationtest/src/test/java/org/opendaylight/ovsdb/integrationtest/plugin/OvsdbPluginV3IT.java
northbound/src/main/java/org/opendaylight/ovsdb/northbound/DatabaseResource.java
northbound/src/main/java/org/opendaylight/ovsdb/northbound/NodeResource.java
northbound/src/main/java/org/opendaylight/ovsdb/northbound/OvsdbNorthboundV2.java
northbound/src/main/java/org/opendaylight/ovsdb/northbound/TableResource.java
openstack/net-virt-it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/it/AbstractConfigTestBase.java
openstack/net-virt-providers/pom.xml
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/ConfigActivator.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/NetvirtProvidersProvider.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/AbstractServiceInstance.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/PipelineOrchestratorImpl.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/Service.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/L2ForwardingService.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/LoadBalancerService.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/Arp.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/ArpFlowFactory.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/ArpMessageAddress.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/ArpOperation.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/ArpResolverMetadata.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/ArpResolverUtils.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/ArpSender.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/ArpUtils.java [new file with mode: 0644]
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/GatewayMacResolverService.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/AbstractEvent.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/ConfigActivator.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/LBaaSPoolHandler.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/NeutronCacheUtils.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/SouthboundHandler.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/GatewayMacResolver.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/LoadBalancerConfiguration.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/impl/EventDispatcherImpl.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/impl/NeutronL3Adapter.java
ovsdb-plugin-compatibility-layer/src/main/java/org/opendaylight/ovsdb/compatibility/plugin/impl/ConfigurationServiceImpl.java
ovsdb-plugin-compatibility-layer/src/main/java/org/opendaylight/ovsdb/compatibility/plugin/impl/ConnectionServiceImpl.java
ovsdb-plugin-compatibility-layer/src/main/java/org/opendaylight/ovsdb/compatibility/plugin/impl/InventoryServiceImpl.java
plugin/src/main/java/org/opendaylight/ovsdb/plugin/api/Connection.java
plugin/src/main/java/org/opendaylight/ovsdb/plugin/api/OvsVswitchdSchemaConstants.java
plugin/src/main/java/org/opendaylight/ovsdb/plugin/impl/ConfigurationServiceImpl.java
plugin/src/main/java/org/opendaylight/ovsdb/plugin/impl/ConnectionServiceImpl.java
plugin/src/main/java/org/opendaylight/ovsdb/plugin/impl/InventoryServiceImpl.java
resources/commons/showOvsdbMdsal.py
utils/mdsal-openflow/src/main/java/org/opendaylight/ovsdb/utils/mdsal/openflow/ActionUtils.java
utils/mdsal-openflow/src/main/java/org/opendaylight/ovsdb/utils/mdsal/openflow/MatchUtils.java

index 4d7af0e9c7d70fcd82195f7a70a6cfc22eb6b56e..54d7eacfb11551304ba0fbaba786370dac39a62f 100644 (file)
@@ -33,6 +33,9 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
     mininet.vm.provider "vmware_fusion" do |vf|
       vf.vmx["memsize"] = "2048"
     end
+    mininet.vm.provider :libvirt do |lv|
+      lv.memory = 2048
+    end
     mininet.vm.provision "puppet" do |puppet|
       puppet.hiera_config_path = "resources/puppet/hiera.yaml"
       puppet.working_directory = "/vagrant/resources/puppet"
@@ -56,6 +59,9 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
     control.vm.provider "vmware_fusion" do |vf|
       vf.vmx["memsize"] = "4096"
     end
+    control.vm.provider :libvirt do |lv|
+      lv.memory = 4096
+    end
     control.vm.provision "puppet" do |puppet|
       puppet.hiera_config_path = "resources/puppet/hiera.yaml"
       puppet.working_directory = "/vagrant/resources/puppet"
@@ -82,6 +88,9 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
       compute.vm.provider "vmware_fusion" do |vf|
         vf.vmx["memsize"] = "4096"
       end
+      compute.vm.provider :libvirt do |lv|
+        lv.memory = 4096
+      end
       compute.vm.provision "puppet" do |puppet|
         puppet.hiera_config_path = "resources/puppet/hiera.yaml"
         puppet.working_directory = "/vagrant/resources/puppet"
index 4d5ea56b1bba632f7a1e8ffb9acb5509fe962490..3df31d0f5a3ef2095d8002a591ce65759f7a72b6 100644 (file)
@@ -112,8 +112,7 @@ public class OvsdbLibraryIT extends OvsdbIntegrationTestBase {
         ListenableFuture<List<String>> databases = client.getDatabases();
         List<String> dbNames = databases.get();
         assertNotNull(dbNames);
-        if (dbNames.contains(schema)) return true;
-        return false;
+        return dbNames.contains(schema);
     }
 
     static String testBridgeName = "br_test";
index d895a765061ac5fac43814edf7cdfa89049cdba1..5a31fe2afb7f4aad4405ebd661d8c39340eebb4b 100644 (file)
@@ -122,10 +122,14 @@ public class OvsdbClientTestIT extends OvsdbTestBase {
                 System.out.println("t = " + t);
             }
         });
-        if (updates != null) results.add(updates);
+        if (updates != null) {
+            results.add(updates);
+        }
         for (int i = 0; i < 3 ; i++) { //wait 3 seconds to get a result
             System.out.println("waiting on monitor response for Bridge Table...");
-            if (!results.isEmpty()) break;
+            if (!results.isEmpty()) {
+                break;
+            }
             Thread.sleep(1000);
         }
 
@@ -137,7 +141,9 @@ public class OvsdbClientTestIT extends OvsdbTestBase {
         Assert.assertTrue(update.getRows().size() > 0);
         for (UUID uuid : update.getRows().keySet()) {
             Row<GenericTableSchema> aNew = update.getNew(uuid);
-            if (!aNew.getColumn(name).getData().equals(testBridgeName)) continue;
+            if (!aNew.getColumn(name).getData().equals(testBridgeName)) {
+                continue;
+            }
             if (filter) {
                 Assert.assertEquals(builder.getColumns().size(), aNew.getColumns().size());
             } else {
@@ -326,7 +332,9 @@ public class OvsdbClientTestIT extends OvsdbTestBase {
 
     @After
     public void tearDown() throws InterruptedException, ExecutionException {
-        if (dbSchema == null) return;
+        if (dbSchema == null) {
+            return;
+        }
         TableSchema<GenericTableSchema> bridge = dbSchema.table("Bridge", GenericTableSchema.class);
         ColumnSchema<GenericTableSchema, String> name = bridge.column("name", String.class);
         GenericTableSchema ovsTable = dbSchema.table("Open_vSwitch", GenericTableSchema.class);
index 7f1288f2dc34d0443160deac7c01c51380d747c7..bbdc1385cdf67f7e92f439960739c0da547c9278 100644 (file)
@@ -319,7 +319,9 @@ public class OvsdbPluginIT extends OvsdbIntegrationTestBase {
     public String getOpenVSwitchTableUUID(Connection connection) throws Exception {
         OpenVSwitch openVSwitch = connection.getClient().getTypedRowWrapper(OpenVSwitch.class, null);
         ConcurrentMap<String, Row> row = ovsdbConfigurationService.getRows(node, openVSwitch.getSchema().getName());
-        if (row == null || row.size() == 0) return null;
+        if (row == null || row.size() == 0) {
+            return null;
+        }
         return (String)row.keySet().toArray()[0];
     }
 
index 4a17c1ec7839b9b6855fcb998ac0264f4ac65a79..555485eb4bf7038d128f4945c2319e7d9be7d9c1 100644 (file)
@@ -244,7 +244,9 @@ public class OvsdbPluginV3IT extends OvsdbIntegrationTestBase {
     public String getOpenVSwitchTableUUID(Connection connection) throws Exception {
         OpenVSwitch openVSwitch = connection.getClient().getTypedRowWrapper(OpenVSwitch.class, null);
         ConcurrentMap<UUID, Row<GenericTableSchema>> rows = ovsdbConfigurationService.getRows(node, databaseName, openVSwitch.getSchema().getName());
-        if (rows == null || rows.size() == 0) return null;
+        if (rows == null || rows.size() == 0) {
+            return null;
+        }
         return rows.keySet().toArray()[0].toString();
     }
 
index 9552984c110f1885fce4aa79feb27eefeead2c52..acedbec28eec18413322445e65c9255140c8c24f 100644 (file)
@@ -77,9 +77,13 @@ public class DatabaseResource {
         OvsdbClient client = NodeResource.getOvsdbClient(nodeId, this);
         try {
             List<String> databases = client.getDatabases().get();
-            if (databases == null) return ciDatabaseName;
+            if (databases == null) {
+                return ciDatabaseName;
+            }
             for (String csDatabaseName : databases) {
-                if (csDatabaseName.equalsIgnoreCase(ciDatabaseName)) return csDatabaseName;
+                if (csDatabaseName.equalsIgnoreCase(ciDatabaseName)) {
+                    return csDatabaseName;
+                }
             }
             return ciDatabaseName;
         } catch (Exception e) {
index 034ddff6becd9eb4267e574a7a17414badae528b..695615ba8565e8130b3a5e6c7e541865cea115d1 100644 (file)
@@ -94,7 +94,9 @@ public class NodeResource {
     public Response getNodes() throws JsonProcessingException {
         OvsdbConnectionService connectionService = (OvsdbConnectionService)ServiceHelper.getGlobalInstance(OvsdbConnectionService.class, this);
         List<Node> nodes = connectionService.getNodes();
-        if (nodes == null) return Response.noContent().build();
+        if (nodes == null) {
+            return Response.noContent().build();
+        }
 
         List<String> nodeIds = Lists.newArrayList();
         for (Node node : nodes) {
index 3e3b6674dd7eee17edfe71045950f6fd1d039d15..a9f6200199847b7458d5efd24951a6dcc3221974 100644 (file)
@@ -685,9 +685,13 @@ public class OvsdbNorthboundV2 {
 
     private String getBackwardCompatibleTableName(OvsdbClient client, String databaseName, String tableName) {
         DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
-        if (dbSchema == null || tableName == null) return tableName;
+        if (dbSchema == null || tableName == null) {
+            return tableName;
+        }
         for (String dbTableName : dbSchema.getTables()) {
-            if (dbTableName.equalsIgnoreCase(tableName)) return dbTableName;
+            if (dbTableName.equalsIgnoreCase(tableName)) {
+                return dbTableName;
+            }
         }
         return tableName;
     }
index 46ae46ad76cfaecc900bb329c327a54f4aace105..a10aeae8f14dbf2d37694bae4405bac112039b4f 100644 (file)
@@ -84,7 +84,9 @@ public class TableResource {
             return ciTableName;
         }
         for (String tableName : tables) {
-            if (tableName.equalsIgnoreCase(ciTableName)) return tableName;
+            if (tableName.equalsIgnoreCase(ciTableName)) {
+                return tableName;
+            }
         }
         return ciTableName;
     }
index c47443be8c783b62908d136f3d14881cd4ec14fb..e08c32e301a53d99c8f8cf4794ca8c8d6a8f9a80 100644 (file)
@@ -87,7 +87,7 @@ public abstract class AbstractConfigTestBase {
         karafUrl = maven()
                 .groupId("org.opendaylight.ovsdb")
                 .artifactId("karaf")
-                .version("1.2.0-SNAPSHOT")
+                .versionAsInProject()
                 .type("zip");
 
         return karafUrl;
index c8c50bcbbc663943ad0f07bf9df5b3eff360a7cb..4ea6b6606d8b4702a160b96f06036961287efbce 100644 (file)
@@ -52,6 +52,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
     <ovsdb.utils.servicehelper.version>1.2.0-SNAPSHOT</ovsdb.utils.servicehelper.version>
     <powermock.version>1.5.2</powermock.version>
     <sonar-jacoco-listeners.version>2.4</sonar-jacoco-listeners.version>
+    <liblldp.version>0.9.1-SNAPSHOT</liblldp.version>
     <root.directory>${env.PWD}</root.directory>
     <sonar.jacoco.itReportPath>${root.directory}/target/code-coverage/jacoco-it.exec</sonar.jacoco.itReportPath>
   </properties>
@@ -151,6 +152,11 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
     </dependency>
+    <dependency>
+       <groupId>org.opendaylight.controller</groupId>
+       <artifactId>liblldp</artifactId>
+       <version>${liblldp.version}</version>
+     </dependency>
     <dependency>
       <groupId>org.mockito</groupId>
       <artifactId>mockito-core</artifactId>
index 8d56e89d9e98975d1b2eae9c33b7272b5c676ff3..2b98a0f79df0925a64c99a971afb9a2d49d4ee99 100644 (file)
@@ -4,7 +4,9 @@ import java.util.ArrayList;
 import java.util.Dictionary;
 import java.util.Hashtable;
 import java.util.List;
+
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
 import org.opendaylight.ovsdb.openstack.netvirt.api.*;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.OF13Provider;
@@ -12,6 +14,7 @@ import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.PipelineOrc
 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.PipelineOrchestratorImpl;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services.*;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services.arp.GatewayMacResolverService;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
@@ -91,6 +94,12 @@ public class ConfigActivator implements BundleActivator {
         registerService(context, OutboundNatProvider.class.getName(),
                 outboundNatService, Service.OUTBOUND_NAT);
 
+        GatewayMacResolverService gatewayMacResolverService = new GatewayMacResolverService();
+        registerService(context, GatewayMacResolver.class.getName(),
+                gatewayMacResolverService, Service.GATEWAY_RESOLVER);
+        getNotificationProviderService().registerNotificationListener(gatewayMacResolverService);
+
+
         pipelineOrchestrator.setDependencies(context, null);
         outboundNatService.setDependencies(context, null);
         egressAclService.setDependencies(context, null);
@@ -104,6 +113,7 @@ public class ConfigActivator implements BundleActivator {
         arpResponderService.setDependencies(context, null);
         classifierService.setDependencies(context, null);
         of13Provider.setDependencies(context, null);
+        gatewayMacResolverService.setDependencies(context, null);
 
         @SuppressWarnings("unchecked")
         ServiceTracker NetworkingProviderManagerTracker = new ServiceTracker(context,
@@ -153,4 +163,9 @@ public class ConfigActivator implements BundleActivator {
                 new String[] {AbstractServiceInstance.class.getName(), interfaceClassName},
                 properties, impl);
     }
+
+    private NotificationProviderService getNotificationProviderService(){
+        return this.providerContext.<NotificationProviderService>getSALService(
+                NotificationProviderService.class);
+    }
 }
index b94b268fc47bc95ef2980cae50974da7e036e9a9..0dc866a52ef61173837bca94c1c1fdb5f4bfc1c5 100644 (file)
@@ -15,6 +15,7 @@ public class NetvirtProvidersProvider implements BindingAwareProvider, AutoClose
     private BundleContext bundleContext = null;
     private static DataBroker dataBroker = null;
     private ConfigActivator activator;
+    private static ProviderContext providerContext = null;
 
     public NetvirtProvidersProvider(BundleContext bundleContext) {
         LOG.info("NetvirtProvidersProvider: bundleContext: {}", bundleContext);
@@ -25,16 +26,21 @@ public class NetvirtProvidersProvider implements BindingAwareProvider, AutoClose
         return dataBroker;
     }
 
+    public static ProviderContext getProviderContext() {
+        return providerContext;
+    }
+
     @Override
     public void close() throws Exception {
         activator.stop(bundleContext);
     }
 
     @Override
-    public void onSessionInitiated(ProviderContext providerContext) {
-        dataBroker = providerContext.getSALService(DataBroker.class);
+    public void onSessionInitiated(ProviderContext providerContextRef) {
+        dataBroker = providerContextRef.getSALService(DataBroker.class);
+        providerContext = providerContextRef;
         LOG.info("NetvirtProvidersProvider: onSessionInitiated dataBroker: {}", dataBroker);
-        this.activator = new ConfigActivator(providerContext);
+        this.activator = new ConfigActivator(providerContextRef);
         try {
             activator.start(bundleContext);
         } catch (Exception e) {
index 62c3464867f05766a9813d43869bce967e6479ea..5b9573fd4c094f9cab6262fba7c8e66fc3b251d8 100644 (file)
@@ -41,8 +41,10 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import com.google.common.base.Optional;
 import com.google.common.collect.Lists;
 import com.google.common.util.concurrent.CheckedFuture;
+
 import java.util.List;
 import java.util.concurrent.ExecutionException;
+
 import org.osgi.framework.ServiceReference;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -190,6 +192,24 @@ public abstract class AbstractServiceInstance {
         return null;
     }
 
+    public org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node
+    getOpenFlowNode(String nodeId) {
+
+        ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
+        try {
+            Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node> data =
+                    readTx.read(LogicalDatastoreType.OPERATIONAL, createNodePath(createNodeBuilder(nodeId))).get();
+            if (data.isPresent()) {
+                return data.get();
+            }
+        } catch (InterruptedException|ExecutionException e) {
+            logger.error(e.getMessage(), e);
+        }
+
+        logger.debug("Cannot find data for Node " + nodeId);
+        return null;
+    }
+
     private Long getDpid(Node node) {
         Long dpid = 0L;
         dpid = southbound.getDataPathId(node);
index dce4a39a87f8601690b83ae61b02baa706ad810c..b7d48671039b22649d1edc07e95bdae776f08d8c 100644 (file)
@@ -69,13 +69,17 @@ public class PipelineOrchestratorImpl implements ConfigInterface, NodeCacheListe
     @Override
     public Service getNextServiceInPipeline(Service service) {
         int index = staticPipeline.indexOf(service);
-        if (index >= staticPipeline.size() - 1) return null;
+        if (index >= staticPipeline.size() - 1) {
+            return null;
+        }
         return staticPipeline.get(index + 1);
     }
 
     @Override
     public AbstractServiceInstance getServiceInstance(Service service) {
-        if (service == null) return null;
+        if (service == null) {
+            return null;
+        }
         return serviceRegistry.get(service);
     }
 
index 88d465cda8de12d5a6069ab306c4e22e1f46c8e6..4af71d304362d76c7c4fff0e12ce67d3f5583960 100644 (file)
@@ -13,6 +13,7 @@ package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13;
 public enum Service {
 
     CLASSIFIER ((short) 0, "Classifier"),
+    GATEWAY_RESOLVER((short) 0, "External Network Gateway Resolver"),
     DIRECTOR ((short) 10, "Director"),
     ARP_RESPONDER ((short) 20, "Distributed ARP Responder"),
     INBOUND_NAT ((short) 30, "DNAT for inbound floating-ip traffic"),
index f37ac61f7b81864d0db487d1158d74c69bd27807..253be535cd0c8f56e438d31aa3f2aebd419a94b9 100644 (file)
@@ -1024,9 +1024,11 @@ public class L2ForwardingService extends AbstractServiceInstance implements Conf
             if (in.getInstruction() instanceof ApplyActionsCase) {
                 existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
                 // Only include output actions
-                for (Action action : existingActions)
-                    if (action.getAction() instanceof OutputActionCase)
+                for (Action action : existingActions) {
+                    if (action.getAction() instanceof OutputActionCase) {
                         actionList.add(action);
+                    }
+                }
             }
         }
         /* Create output action for this port*/
index 43142bd8f6fb3a7414ce1695c2790326a60d78e9..3b91ff500d1dbc0ef81c4030a0df8fc77afc2f91 100644 (file)
@@ -168,12 +168,13 @@ public class LoadBalancerService extends AbstractServiceInstance implements Load
 
         // Match Tunnel-ID, VIP, and Reg0==0
         if (lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) ||
-            lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE))
+            lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)) {
             MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(lbConfig.getProviderSegmentationId()));
-        else if (lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN))
+        } else if (lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
             MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(lbConfig.getProviderSegmentationId())), true);
-        else
+        } else {
             return; //Should not get here. TODO: Other types
+        }
 
         MatchUtils.createDstL3IPv4Match(matchBuilder, MatchUtils.iPv4PrefixFromIPv4Address(lbConfig.getVip()));
         MatchUtils.addNxRegMatch(matchBuilder, new MatchUtils.RegMatch(REG_FIELD_A, FIRST_PASS_REGA_MATCH_VALUE));
@@ -267,12 +268,13 @@ public class LoadBalancerService extends AbstractServiceInstance implements Load
 
         // Match Tunnel-ID, VIP, Reg0==1 and Reg1==Index of member
         if (lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) ||
-            lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE))
+            lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)) {
             MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(lbConfig.getProviderSegmentationId()));
-        else if (lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN))
+        } else if (lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
             MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(lbConfig.getProviderSegmentationId())), true);
-        else
+        } else {
             return; //Should not get here. TODO: Other types
+        }
 
         MatchUtils.createDstL3IPv4Match(matchBuilder, MatchUtils.iPv4PrefixFromIPv4Address(vip));
         MatchUtils.addNxRegMatch(matchBuilder, new MatchUtils.RegMatch(REG_FIELD_A, SECOND_PASS_REGA_MATCH_VALUE),
@@ -365,12 +367,13 @@ public class LoadBalancerService extends AbstractServiceInstance implements Load
 
         // Match Tunnel-ID, MemberIP, and Protocol/Port
         if (lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) ||
-                   lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE))
+                   lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)) {
             MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(lbConfig.getProviderSegmentationId()));
-        else if (lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN))
+        } else if (lbConfig.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
             MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(lbConfig.getProviderSegmentationId())), true);
-        else
+        } else {
             return; //Should not get here. TODO: Other types
+        }
 
         MatchUtils.createSrcL3IPv4Match(matchBuilder, MatchUtils.iPv4PrefixFromIPv4Address(member.getIP()));
         MatchUtils.createSetSrcTcpMatch(matchBuilder, new PortNumber(member.getPort()));
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/Arp.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/Arp.java
new file mode 100644 (file)
index 0000000..717473e
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services.arp;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import io.netty.buffer.Unpooled;
+
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.commons.lang3.tuple.Pair;
+import org.opendaylight.controller.liblldp.EtherTypes;
+import org.opendaylight.controller.liblldp.NetUtils;
+import org.opendaylight.controller.liblldp.Packet;
+import org.opendaylight.controller.liblldp.PacketException;
+
+/**
+ * Represents ARP packet. Contains methods ({@link #setSHAFieldCoordinate(Pair)}
+ * {@link #setSPAFieldCoordinate(Pair)} {@link #setTHAFieldCoordinate(Pair)}
+ * {@link #setTPAFieldCoordinate(Pair)}) for customization of ARP.
+ * Arp by default contain fields for IPv4 as protocol address and MAC as hardware address.
+ */
+public class Arp extends Packet {
+
+    private static final String HTYPE = "htype";
+    private static final String PTYPE = "ptype";
+    private static final String HLEN = "hlen";
+    private static final String PLEN = "plen";
+    private static final String OPERATION = "operation";
+    private static final String SHA = "sha";
+    private static final String SPA = "spa";
+    private static final String THA = "tha";
+    private static final String TPA = "tpa";
+
+    private static final int ARP_FIELDS_COUNT = 9;
+    private static final int ETHERNET_HW_TYPE = 1;
+    private final Map<String, Pair<Integer, Integer>> ARP_FIELD_COORDINATES = new LinkedHashMap<String, Pair<Integer, Integer>>() {
+
+        private static final long serialVersionUID = 1L;
+
+        {
+            put(HTYPE, ImmutablePair.of(0, 16));
+            put(PTYPE, ImmutablePair.of(16, 16));
+            put(HLEN, ImmutablePair.of(32, 8));
+            put(PLEN, ImmutablePair.of(40, 8));
+            put(OPERATION, ImmutablePair.of(48, 16));
+            put(SHA, ImmutablePair.of(64, 48));
+            put(SPA, ImmutablePair.of(112, 32));
+            put(THA, ImmutablePair.of(144, 48));
+            put(TPA, ImmutablePair.of(192, 32));
+        }
+    };
+
+    public Arp() {
+        payload = null;
+        hdrFieldsMap = new HashMap<String, byte[]>(ARP_FIELDS_COUNT);
+        setHardwareLength((short) 6); // MAC address length
+        setProtocolLength((short) 4); // IPv4 address length
+        setHardwareType(ETHERNET_HW_TYPE);
+        setProtocolType(EtherTypes.IPv4.intValue());
+        hdrFieldCoordMap = ARP_FIELD_COORDINATES;
+    }
+
+    public Pair<Integer, Integer> setSHAFieldCoordinate(Pair<Integer, Integer> bitOffsetAndBitLength) {
+        checkNotNullPair(bitOffsetAndBitLength);
+        return ARP_FIELD_COORDINATES.put(SHA, bitOffsetAndBitLength);
+    }
+
+    public Pair<Integer, Integer> setSPAFieldCoordinate(Pair<Integer, Integer> bitOffsetAndBitLength) {
+        checkNotNullPair(bitOffsetAndBitLength);
+        return ARP_FIELD_COORDINATES.put(SPA, bitOffsetAndBitLength);
+    }
+
+    public Pair<Integer, Integer> setTHAFieldCoordinate(Pair<Integer, Integer> bitOffsetAndBitLength) {
+        checkNotNullPair(bitOffsetAndBitLength);
+        return ARP_FIELD_COORDINATES.put(THA, bitOffsetAndBitLength);
+    }
+
+    public Pair<Integer, Integer> setTPAFieldCoordinate(Pair<Integer, Integer> bitOffsetAndBitLength) {
+        checkNotNullPair(bitOffsetAndBitLength);
+        return ARP_FIELD_COORDINATES.put(TPA, bitOffsetAndBitLength);
+    }
+
+    private void checkNotNullPair(Pair<Integer, Integer> pair) {
+        checkNotNull(pair);
+        checkNotNull(pair.getLeft());
+        checkNotNull(pair.getRight());
+    }
+
+    @Override
+    public Packet deserialize(byte[] data, int bitOffset, int size) throws PacketException {
+        return super.deserialize(data, bitOffset, size);
+    }
+
+    @Override
+    public byte[] serialize() throws PacketException {
+        return super.serialize();
+    }
+
+    @Override
+    public int getfieldnumBits(String fieldName) {
+        if (fieldName.equals(SHA) || fieldName.equals(THA)) {
+            return getHardwareLength() * NetUtils.NumBitsInAByte;
+        } else if (fieldName.equals(SPA) || fieldName.equals(TPA)) {
+            return getProtocolLength() * NetUtils.NumBitsInAByte;
+        }
+        return hdrFieldCoordMap.get(fieldName).getRight();
+    }
+
+    public Arp setHardwareType(int value) {
+        hdrFieldsMap.put(HTYPE, Unpooled.copyShort(value).array());
+        return this;
+    }
+
+    public Arp setProtocolType(int value) {
+        hdrFieldsMap.put(PTYPE, Unpooled.copyShort(value).array());
+        return this;
+    }
+
+    /**
+     * @param value hardware length in Bytes
+     */
+    public Arp setHardwareLength(short value) {
+        hdrFieldsMap.put(HLEN, Unpooled.buffer(1).writeByte(value).array());
+        return this;
+    }
+
+    /**
+     * @param value protocol length in Bytes
+     */
+    public Arp setProtocolLength(short value) {
+        hdrFieldsMap.put(PLEN, Unpooled.buffer(1).writeByte(value).array());
+        return this;
+    }
+
+    public Arp setOperation(int value) {
+        hdrFieldsMap.put(OPERATION, Unpooled.copyShort(value).array());
+        return this;
+    }
+
+    public Arp setSenderHardwareAddress(byte[] value) {
+        hdrFieldsMap.put(SHA, value);
+        return this;
+    }
+
+    public Arp setSenderProtocolAddress(byte[] value) {
+        hdrFieldsMap.put(SPA, value);
+        return this;
+    }
+
+    public Arp setTargetHardwareAddress(byte[] value) {
+        hdrFieldsMap.put(THA, value);
+        return this;
+    }
+
+    public Arp setTargetProtocolAddress(byte[] value) {
+        hdrFieldsMap.put(TPA, value);
+        return this;
+    }
+
+    public int getHardwareType() {
+        byte[] htype = hdrFieldsMap.get(HTYPE);
+        return Unpooled.wrappedBuffer(htype).readUnsignedShort();
+    }
+
+    public int getProtocolType() {
+        byte[] ptype = hdrFieldsMap.get(PTYPE);
+        return Unpooled.wrappedBuffer(ptype).readUnsignedShort();
+    }
+
+    public short getHardwareLength() {
+        byte[] hlen = hdrFieldsMap.get(HLEN);
+        return Unpooled.wrappedBuffer(hlen).readUnsignedByte();
+    }
+
+    public short getProtocolLength() {
+        byte[] plen = hdrFieldsMap.get(PLEN);
+        return Unpooled.wrappedBuffer(plen).readUnsignedByte();
+    }
+
+    public int getOperation() {
+        byte[] operation = hdrFieldsMap.get(OPERATION);
+        return Unpooled.wrappedBuffer(operation).readUnsignedShort();
+    }
+
+    public byte[] getSenderHardwareAddress() {
+        return hdrFieldsMap.get(SHA);
+    }
+
+    public byte[] getSenderProtocolAddress() {
+        return hdrFieldsMap.get(SPA);
+    }
+
+    public byte[] getTargetHardwareAddress() {
+        return hdrFieldsMap.get(THA);
+    }
+
+    public byte[] getTargetProtocolAddress() {
+        return hdrFieldsMap.get(TPA);
+    }
+
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/ArpFlowFactory.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/ArpFlowFactory.java
new file mode 100644 (file)
index 0000000..9699a51
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services.arp;
+
+import org.opendaylight.controller.liblldp.EtherTypes;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.output.action._case.OutputActionBuilder;
+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.ActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.OutputPortValues;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.arp.match.fields.ArpTargetHardwareAddressBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetDestinationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetTypeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
+
+/**
+ * Contains methods creating flow part for ARP flow.
+ */
+public class ArpFlowFactory {
+
+    private static final String HOST_MASK = "/32";
+
+    /**
+     * Creates {@link EthernetMatch} containing ARP ether-type and the given destination MAC address
+     */
+    public static EthernetMatch createEthernetMatch(MacAddress destinationMacAddress) {
+        return new EthernetMatchBuilder().setEthernetType(
+                new EthernetTypeBuilder().setType(new EtherType(Long.valueOf(EtherTypes.ARP.intValue()))).build())
+            .setEthernetDestination(new EthernetDestinationBuilder().setAddress(destinationMacAddress).build())
+            .build();
+    }
+
+    /**
+     * Creates {@link ArpMatch} containing Reply ARP operation, THA and TPA for the given target
+     * address and SPA for the given sender protocol address
+     */
+    public static ArpMatch createArpMatch(ArpMessageAddress targetAddress, Ipv4Address senderProtocolAddress) {
+        return new ArpMatchBuilder().setArpOp(ArpOperation.REPLY.intValue())
+            .setArpTargetHardwareAddress(
+                    new ArpTargetHardwareAddressBuilder().setAddress(targetAddress.getHardwareAddress()).build())
+            .setArpTargetTransportAddress(new Ipv4Prefix(targetAddress.getProtocolAddress().getValue() + HOST_MASK))
+            .setArpSourceTransportAddress(new Ipv4Prefix(senderProtocolAddress.getValue() + HOST_MASK))
+            .build();
+    }
+
+    /**
+     * Creates {@link Action} representing output to the controller
+     *
+     * @param order the order for the action
+     */
+    public static Action createSendToControllerAction(int order) {
+        return new ActionBuilder().setOrder(order)
+            .setKey(new ActionKey(order))
+            .setAction(
+                    new OutputActionCaseBuilder().setOutputAction(
+                            new OutputActionBuilder().setMaxLength(0xffff)
+                                .setOutputNodeConnector(new Uri(OutputPortValues.CONTROLLER.toString()))
+                                .build()).build())
+            .build();
+    }
+
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/ArpMessageAddress.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/ArpMessageAddress.java
new file mode 100644 (file)
index 0000000..e054862
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services.arp;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.annotation.concurrent.Immutable;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+
+/**
+ * Represents ARP fields where protocol address is IPv4 address and hardware address is MAC address.
+ */
+@Immutable
+public class ArpMessageAddress {
+
+    private final MacAddress hwAddress;
+    private final Ipv4Address protocolAddress;
+
+    public ArpMessageAddress(MacAddress hwAddress, Ipv4Address protocolAddress) {
+        this.hwAddress = checkNotNull(hwAddress);
+        this.protocolAddress = checkNotNull(protocolAddress);
+    }
+
+    public MacAddress getHardwareAddress() {
+        return hwAddress;
+    }
+
+    public Ipv4Address getProtocolAddress() {
+        return protocolAddress;
+    }
+
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/ArpOperation.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/ArpOperation.java
new file mode 100644 (file)
index 0000000..b65e5a2
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services.arp;
+
+import javax.annotation.Nullable;
+
+public enum ArpOperation {
+
+    REQUEST(1), REPLY(2);
+
+    private final int intOperation;
+
+    private ArpOperation(int operationNumber) {
+        this.intOperation = operationNumber;
+    }
+
+    public int intValue() {
+        return intOperation;
+    }
+
+    public static @Nullable ArpOperation loadFromInt(int intOperation) {
+        for (ArpOperation operation : ArpOperation.values()) {
+            if (operation.intOperation == intOperation) {
+                return operation;
+            }
+        }
+        return null;
+    }
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/ArpResolverMetadata.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/ArpResolverMetadata.java
new file mode 100644 (file)
index 0000000..8947cdf
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services.arp;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput;
+
+/**
+*
+* @author Anil Vishnoi (avishnoi@Brocade.com)
+*
+*/
+
+public final class ArpResolverMetadata {
+
+    private RemoveFlowInput flowToRemove;
+    private Ipv4Address gatewayIpAddress;
+    private MacAddress gatewayMacAddress;
+    private boolean periodicRefresh;
+
+    public ArpResolverMetadata(){
+
+    }
+    public ArpResolverMetadata(RemoveFlowInput flowToRemove, Ipv4Address gatewayIpAddress, boolean periodicRefresh){
+        this.flowToRemove = flowToRemove;
+        this.gatewayIpAddress = gatewayIpAddress;
+        this.periodicRefresh = periodicRefresh;
+    }
+
+    public ArpResolverMetadata(RemoveFlowInput flowToRemove, Ipv4Address gatewayIpAddress, MacAddress gatewayMacAddress, boolean periodicRefresh){
+        this.flowToRemove = flowToRemove;
+        this.gatewayIpAddress = gatewayIpAddress;
+        this.gatewayMacAddress = gatewayMacAddress;
+        this.periodicRefresh = periodicRefresh;
+    }
+
+    public RemoveFlowInput getFlowToRemove() {
+        return flowToRemove;
+    }
+    public boolean isPeriodicRefresh() {
+        return periodicRefresh;
+    }
+    public void setPeriodicRefresh(boolean periodicRefresh) {
+        this.periodicRefresh = periodicRefresh;
+    }
+    public void setFlowToRemove(RemoveFlowInput flowToRemove) {
+        this.flowToRemove = flowToRemove;
+    }
+    public Ipv4Address getGatewayIpAddress() {
+        return gatewayIpAddress;
+    }
+    public void setGatewayIpAddress(Ipv4Address gatewayIpAddress) {
+        this.gatewayIpAddress = gatewayIpAddress;
+    }
+    public MacAddress getGatewayMacAddress() {
+        return gatewayMacAddress;
+    }
+    public void setGatewayMacAddress(MacAddress gatewayMacAddress) {
+        this.gatewayMacAddress = gatewayMacAddress;
+    }
+
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/ArpResolverUtils.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/ArpResolverUtils.java
new file mode 100644 (file)
index 0000000..3f404f6
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services.arp;
+
+import org.opendaylight.controller.liblldp.EtherTypes;
+import org.opendaylight.controller.liblldp.Ethernet;
+import org.opendaylight.controller.liblldp.NetUtils;
+import org.opendaylight.controller.liblldp.PacketException;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
+
+public class ArpResolverUtils {
+
+    static {
+        Ethernet.etherTypeClassMap.put(EtherTypes.ARP.shortValue(), Arp.class);
+    }
+
+    /**
+     * Tries to deserialize received packet as ARP packet with IPv4 protocol address and MAC
+     * hardware address.
+     *
+     * @param potentialArp the packet for deserialization
+     * @return ARP packet if received packet is ARP and deserialization was successful
+     * @throws PacketException if packet is not ARP or deserialization was not successful
+     */
+    public static Arp getArpFrom(PacketReceived potentialArp) throws PacketException {
+        byte[] payload = potentialArp.getPayload();
+        Ethernet ethPkt = new Ethernet();
+        ethPkt.deserialize(payload, 0, payload.length * NetUtils.NumBitsInAByte);
+        if (ethPkt.getPayload() instanceof Arp) {
+            return (Arp) ethPkt.getPayload();
+        }
+        throw new PacketException("Packet is not ARP: " + potentialArp);
+    }
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/ArpSender.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/ArpSender.java
new file mode 100644 (file)
index 0000000..8f72018
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services.arp;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.liblldp.EtherTypes;
+import org.opendaylight.controller.liblldp.Ethernet;
+import org.opendaylight.controller.liblldp.NetUtils;
+import org.opendaylight.controller.liblldp.PacketException;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.JdkFutureAdapters;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Uses packet-out for sending ARP Requests.
+ */
+public class ArpSender {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ArpSender.class);
+
+    private static final String OFPP_ALL = "0xfffffffc";
+    private final PacketProcessingService packetProcessingService;
+
+    public ArpSender(PacketProcessingService packetProcessingService) {
+        this.packetProcessingService = checkNotNull(packetProcessingService);
+    }
+
+    /**
+     * Sends ARP Request as packet-out from all openflow physical ports on the given node.
+     *
+     * @param senderAddress the addresses used in sender part of ARP packet
+     * @param tpa the target protocol address, in this case IPv4 address for which MAC should be
+     *        discovered
+     * @param nodeIid the path to node from where the ARP packet will be flooded
+     * @return future result about success of packet-out
+     */
+    public ListenableFuture<RpcResult<Void>> floodArp(ArpMessageAddress senderAddress, Ipv4Address tpa,
+            InstanceIdentifier<Node> nodeIid) {
+        checkNotNull(senderAddress);
+        checkNotNull(tpa);
+        checkNotNull(nodeIid);
+        // node connector representing all physical ports on node
+        NodeConnectorKey nodeConnectorKey = new NodeConnectorKey(createNodeConnectorId(OFPP_ALL,
+                nodeIid.firstKeyOf(Node.class, NodeKey.class).getId()));
+        InstanceIdentifier<NodeConnector> egressNc = nodeIid.child(NodeConnector.class, nodeConnectorKey);
+        return sendArp(senderAddress, tpa, egressNc);
+    }
+
+    private NodeConnectorId createNodeConnectorId(String connectorId, NodeId nodeId) {
+        StringBuilder stringId = new StringBuilder(nodeId.getValue()).append(":").append(connectorId);
+        return new NodeConnectorId(stringId.toString());
+    }
+
+    /**
+     * Sends ARP Request as packet-out from the given port (node connector).
+     *
+     * @param senderAddress the addresses used in sender part of ARP packet
+     * @param tpa the target protocol address, in this case IPv4 address for which MAC should be
+     *        discovered
+     * @param egressNc the path to node connector from where the ARP packet will be sent
+     * @return future result about success of packet-out
+     */
+    public ListenableFuture<RpcResult<Void>> sendArp(ArpMessageAddress senderAddress, Ipv4Address tpa,
+            InstanceIdentifier<NodeConnector> egressNc) {
+        checkNotNull(senderAddress);
+        checkNotNull(tpa);
+        checkNotNull(egressNc);
+        final Ethernet arpFrame = createArpFrame(senderAddress, tpa);
+        byte[] arpFrameAsBytes;
+        try {
+            arpFrameAsBytes = arpFrame.serialize();
+        } catch (PacketException e) {
+            LOG.warn("Serializition of ARP packet is not successful.", e);
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("ARP packet: {}", ArpUtils.getArpFrameToStringFormat(arpFrame));
+            }
+            return Futures.immediateFailedFuture(e);
+        }
+        // Generate packet with destination switch and port
+        TransmitPacketInput packet = new TransmitPacketInputBuilder().setEgress(new NodeConnectorRef(egressNc))
+            .setNode(new NodeRef(egressNc.firstIdentifierOf(Node.class)))
+            .setPayload(arpFrameAsBytes)
+            .build();
+        if (LOG.isTraceEnabled()) {
+            LOG.trace("Sending ARP REQUEST \n{}", ArpUtils.getArpFrameToStringFormat(arpFrame));
+        }
+        Future<RpcResult<Void>> futureTransmitPacketResult = packetProcessingService.transmitPacket(packet);
+        return JdkFutureAdapters.listenInPoolThread(futureTransmitPacketResult);
+    }
+
+    private Ethernet createArpFrame(ArpMessageAddress senderAddress, Ipv4Address tpa) {
+        byte[] senderMac = ArpUtils.macToBytes(senderAddress.getHardwareAddress());
+        byte[] senderIp = ArpUtils.ipToBytes(senderAddress.getProtocolAddress());
+        byte[] targetMac = NetUtils.getBroadcastMACAddr();
+        byte[] targetIp = ArpUtils.ipToBytes(tpa);
+        Ethernet arpFrame = new Ethernet().setSourceMACAddress(senderMac)
+            .setDestinationMACAddress(targetMac)
+            .setEtherType(EtherTypes.ARP.shortValue());
+        Arp arp = new Arp().setOperation(ArpOperation.REQUEST.intValue())
+            .setSenderHardwareAddress(senderMac)
+            .setSenderProtocolAddress(senderIp)
+            .setTargetHardwareAddress(targetMac)
+            .setTargetProtocolAddress(targetIp);
+        arpFrame.setPayload(arp);
+        return arpFrame;
+    }
+
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/ArpUtils.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/ArpUtils.java
new file mode 100644 (file)
index 0000000..6e2aace
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services.arp;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+import javax.annotation.Nullable;
+
+import org.opendaylight.controller.liblldp.EtherTypes;
+import org.opendaylight.controller.liblldp.Ethernet;
+import org.opendaylight.controller.liblldp.HexEncode;
+import org.opendaylight.controller.liblldp.Packet;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+
+import com.google.common.net.InetAddresses;
+
+public class ArpUtils {
+
+    private ArpUtils() {
+        throw new UnsupportedOperationException("Cannot create an instance.");
+    }
+
+    /**
+     * Returns Ethernet and ARP in readable string format
+     */
+    public static String getArpFrameToStringFormat(Ethernet eth) {
+        String ethernetString = "Ethernet [getEtherType()="
+                + EtherTypes.loadFromString(String.valueOf(eth.getEtherType())) + ", getSourceMACAddress()="
+                + HexEncode.bytesToHexStringFormat(eth.getSourceMACAddress()) + ", getDestinationMACAddress()="
+                + HexEncode.bytesToHexStringFormat(eth.getDestinationMACAddress()) + "]\n";
+        Packet potentialArp = eth.getPayload();
+        String arpString = null;
+        if (potentialArp instanceof Arp) {
+            Arp arp = (Arp) potentialArp;
+            arpString = ArpUtils.getArpToStringFormat(arp);
+        } else {
+            arpString = "ARP was not found in Ethernet frame.";
+        }
+        return ethernetString.concat(arpString);
+    }
+
+    /**
+     * Returns ARP in readable string format
+     */
+    public static String getArpToStringFormat(Arp arp) {
+        try {
+            return "Arp [getHardwareType()=" + arp.getHardwareType() + ", getProtocolType()=" + arp.getProtocolType()
+                    + ", getHardwareLength()=" + arp.getHardwareLength() + ", getProtocolLength()="
+                    + arp.getProtocolLength() + ", getOperation()=" + ArpOperation.loadFromInt(arp.getOperation())
+                    + ", getSenderHardwareAddress()="
+                    + HexEncode.bytesToHexStringFormat(arp.getSenderHardwareAddress())
+                    + ", getSenderProtocolAddress()="
+                    + InetAddress.getByAddress(arp.getSenderProtocolAddress()).getHostAddress()
+                    + ", getTargetHardwareAddress()="
+                    + HexEncode.bytesToHexStringFormat(arp.getTargetHardwareAddress())
+                    + ", getTargetProtocolAddress()="
+                    + InetAddress.getByAddress(arp.getTargetProtocolAddress()).getHostAddress() + "]\n";
+        } catch (UnknownHostException e1) {
+            return "Error during parsing Arp " + arp;
+        }
+    }
+
+    public static byte[] macToBytes(MacAddress mac) {
+        return HexEncode.bytesFromHexString(mac.getValue());
+    }
+
+    public static @Nullable MacAddress bytesToMac(byte[] macBytes) {
+        String mac = HexEncode.bytesToHexStringFormat(macBytes);
+        if (!"null".equals(mac)) {
+            return new MacAddress(mac);
+        }
+        return null;
+    }
+
+    public static byte[] ipToBytes(Ipv4Address ip) {
+        return InetAddresses.forString(ip.getValue()).getAddress();
+    }
+
+    public static @Nullable Ipv4Address bytesToIp(byte[] ipv4AsBytes) {
+        try {
+            return new Ipv4Address(InetAddress.getByAddress(ipv4AsBytes).getHostAddress());
+        } catch (UnknownHostException e) {
+            return null;
+        }
+    }
+
+}
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/GatewayMacResolverService.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/GatewayMacResolverService.java
new file mode 100644 (file)
index 0000000..095b287
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services.arp;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.math.BigInteger;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.annotation.Nullable;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.openflowplugin.api.OFConstants;
+import org.opendaylight.ovsdb.openstack.netvirt.api.GatewayMacResolver;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.ConfigInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.NetvirtProvidersProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowModFlags;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActions;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.JdkFutureAdapters;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+
+/**
+ *
+ * @author Anil Vishnoi (avishnoi@Brocade.com)
+ *
+ */
+public class GatewayMacResolverService extends AbstractServiceInstance
+                                        implements ConfigInterface, GatewayMacResolver,PacketProcessingListener {
+
+    private static final Logger LOG = LoggerFactory.getLogger(GatewayMacResolverService.class);
+    private static final short TABEL_FOR_ARP_FLOW = 0;
+    private static final String ARP_REPLY_TO_CONTROLLER_FLOW_NAME = "GatewayArpReplyRouter";
+    private static final int ARP_REPLY_TO_CONTROLLER_FLOW_PRIORITY = 10000;
+    private static final Instruction SEND_TO_CONTROLLER_INSTRUCTION;
+    private ArpSender arpSender;
+    private SalFlowService flowService;
+    private final AtomicLong flowCookie = new AtomicLong();
+    private final ConcurrentHashMap<Ipv4Address, ArpResolverMetadata> arpRemoveFlowInputAndL3EpKeyById =
+            new ConcurrentHashMap<Ipv4Address, ArpResolverMetadata>();
+    private final int ARP_WATCH_BROTHERS = 10;
+    private final int WAIT_CYCLES = 3;
+    private final int PER_CYCLE_WAIT_DURATION = 1000;
+    private final ListeningExecutorService arpWatcherWall = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(ARP_WATCH_BROTHERS));
+    private AtomicBoolean initializationDone = new AtomicBoolean(false);
+
+    static {
+        ApplyActions applyActions = new ApplyActionsBuilder().setAction(
+                ImmutableList.of(ArpFlowFactory.createSendToControllerAction(0))).build();
+        SEND_TO_CONTROLLER_INSTRUCTION = new InstructionBuilder().setOrder(0)
+            .setInstruction(new ApplyActionsCaseBuilder().setApplyActions(applyActions).build())
+            .build();
+    }
+
+    public GatewayMacResolverService(){
+        super(Service.GATEWAY_RESOLVER);
+    }
+
+    public GatewayMacResolverService(Service service){
+        super(service);
+    }
+
+    private void init(){
+        if(!initializationDone.get()){
+            initializationDone.set(true);
+            ProviderContext providerContext = NetvirtProvidersProvider.getProviderContext();
+            checkNotNull(providerContext);
+            PacketProcessingService packetProcessingService = providerContext.getRpcService(PacketProcessingService.class);
+            if (packetProcessingService != null) {
+                LOG.debug("{} was found.", PacketProcessingService.class.getSimpleName());
+                this.arpSender = new ArpSender(packetProcessingService);
+            } else {
+                LOG.error("Missing service {}", PacketProcessingService.class.getSimpleName());
+                this.arpSender = null;
+            }
+            flowService = providerContext.getRpcService(SalFlowService.class);
+        }
+    }
+    /**
+     * Method do following actions:
+     * 1. Install flow to direct ARP response packet to controller
+     * 2. Send ARP request packet out on all port of the given External network bridge.
+     * 3. Cache the flow that need to be removed once ARP resolution is done.
+     * 4. Return listenable future so that user can add callback to get the MacAddress
+     * @param externalNetworkBridgeDpid Broadcast ARP request packet on this bridge
+     * @param gatewayIp IP address for which MAC need to be resolved
+     * @param sourceIpAddress Source Ip address for the ARP request packet
+     * @param sourceMacAddress Source Mac address for the ARP request packet
+     * @param periodicRefresh Enable/Disable periodic refresh of the Gateway Mac address
+     * NOTE:Periodic refresh is not supported yet.
+     * @param gatewayIp  Resolve MAC address of this Gateway Ip
+     * @return Future<MacAddress> Future object
+     */
+    @Override
+    public ListenableFuture<MacAddress> resolveMacAddress( final Long externalNetworkBridgeDpid, final Ipv4Address gatewayIp,
+            final Ipv4Address sourceIpAddress, final MacAddress sourceMacAddress, final Boolean periodicRefresh){
+        Preconditions.checkNotNull(sourceIpAddress);
+        Preconditions.checkNotNull(sourceMacAddress);
+        Preconditions.checkNotNull(gatewayIp);
+
+        LOG.info("Trigger Mac resolution for gateway {}, using source ip {} and mac {}",
+                gatewayIp.getValue(),sourceIpAddress.getValue(),sourceMacAddress.getValue());
+
+        init();
+        if(arpRemoveFlowInputAndL3EpKeyById.containsKey(gatewayIp)){
+            if(arpRemoveFlowInputAndL3EpKeyById.get(gatewayIp).getGatewayMacAddress() != null){
+                return arpWatcherWall.submit(new Callable<MacAddress>(){
+
+                    @Override
+                    public MacAddress call() throws Exception {
+                        return arpRemoveFlowInputAndL3EpKeyById.get(gatewayIp).getGatewayMacAddress();
+                    }
+                });
+            }
+        }else{
+            arpRemoveFlowInputAndL3EpKeyById.put(gatewayIp,
+                    new ArpResolverMetadata(null, gatewayIp,periodicRefresh));
+        }
+
+        final ArpMessageAddress senderAddress = new ArpMessageAddress(sourceMacAddress,sourceIpAddress);
+
+        final String nodeName = OPENFLOW + externalNetworkBridgeDpid;
+
+        final Node externalNetworkBridge = getOpenFlowNode(nodeName);
+        if(externalNetworkBridge == null){
+            LOG.error("MAC address for gateway {} can not be resolved, because external bridge {} "
+                    + "is not connected to controller.",gatewayIp.getValue(),externalNetworkBridgeDpid );
+            return null;
+        }
+        //Build arp reply router flow
+        final Flow arpReplyToControllerFlow = createArpReplyToControllerFlow(senderAddress, gatewayIp);
+
+
+        final InstanceIdentifier<Node> nodeIid = InstanceIdentifier.builder(Nodes.class)
+                .child(Node.class, externalNetworkBridge.getKey())
+                .build();
+        final InstanceIdentifier<Flow> flowIid = createFlowIid(arpReplyToControllerFlow, nodeIid);
+        final NodeRef nodeRef = new NodeRef(nodeIid);
+
+        //Install flow
+        Future<RpcResult<AddFlowOutput>> addFlowResult = flowService.addFlow(new AddFlowInputBuilder(
+                arpReplyToControllerFlow).setFlowRef(new FlowRef(flowIid)).setNode(nodeRef).build());
+        //wait for flow installation
+        Futures.addCallback(JdkFutureAdapters.listenInPoolThread(addFlowResult),
+                new FutureCallback<RpcResult<AddFlowOutput>>() {
+
+            @Override
+            public void onSuccess(RpcResult<AddFlowOutput> result) {
+                if (!result.isSuccessful()) {
+                    LOG.warn("Flow to route ARP Reply to Controller is not installed successfully : {} \nErrors: {}", flowIid,result.getErrors());
+                    return;
+                }
+                LOG.debug("Flow to route ARP Reply to Controller installed successfully : {}", flowIid);
+
+                //cache metadata
+                arpRemoveFlowInputAndL3EpKeyById.get(gatewayIp).setFlowToRemove(
+                        new RemoveFlowInputBuilder(arpReplyToControllerFlow).setNode(nodeRef).build());
+
+                //Broadcast ARP request packets
+                for (NodeConnector egressNc : externalNetworkBridge.getNodeConnector()) {
+                    KeyedInstanceIdentifier<NodeConnector, NodeConnectorKey> egressNcIid = nodeIid.child(
+                            NodeConnector.class, new NodeConnectorKey(egressNc.getId()));
+                    ListenableFuture<RpcResult<Void>> futureSendArpResult = arpSender.sendArp(
+                            senderAddress, gatewayIp, egressNcIid);
+                    Futures.addCallback(futureSendArpResult, logResult(gatewayIp, egressNcIid));
+                }
+            }
+
+            @Override
+            public void onFailure(Throwable t) {
+                LOG.warn("ARP Reply to Controller flow was not created: {}", flowIid, t);
+            }
+            }
+        );
+        //Wait for MacAddress population in cache
+        return waitForMacAddress(gatewayIp);
+    }
+
+    private ListenableFuture<MacAddress> waitForMacAddress(final Ipv4Address gatewayIp){
+
+        return arpWatcherWall.submit(new Callable<MacAddress>(){
+
+            @Override
+            public MacAddress call() throws Exception {
+                for(int cycle = 0;cycle < WAIT_CYCLES;cycle++){
+                    //Sleep before checking mac address, so meanwhile ARP request packets
+                    // will be broadcasted on the bridge.
+                    Thread.sleep(PER_CYCLE_WAIT_DURATION);
+                    ArpResolverMetadata arpResolverMetadata = arpRemoveFlowInputAndL3EpKeyById.get(gatewayIp);
+                    if(arpResolverMetadata != null && arpResolverMetadata.getGatewayMacAddress() != null){
+                        if(!arpResolverMetadata.isPeriodicRefresh()){
+                            return arpRemoveFlowInputAndL3EpKeyById.remove(gatewayIp).getGatewayMacAddress();
+                        }
+                        return arpResolverMetadata.getGatewayMacAddress();
+                    }
+                }
+                return null;
+            }
+        });
+    }
+    private static @Nullable Ipv4Address getIPv4Addresses(IpAddress ipAddress) {
+        if (ipAddress.getIpv4Address() == null) {
+            return null;
+        }
+        return ipAddress.getIpv4Address();
+    }
+
+    private Flow createArpReplyToControllerFlow(final ArpMessageAddress senderAddress, final Ipv4Address ipForRequestedMac) {
+        checkNotNull(senderAddress);
+        checkNotNull(ipForRequestedMac);
+        FlowBuilder arpFlow = new FlowBuilder().setTableId(TABEL_FOR_ARP_FLOW)
+            .setFlowName(ARP_REPLY_TO_CONTROLLER_FLOW_NAME)
+            .setPriority(ARP_REPLY_TO_CONTROLLER_FLOW_PRIORITY)
+            .setBufferId(OFConstants.OFP_NO_BUFFER)
+            .setIdleTimeout(0)
+            .setHardTimeout(0)
+            .setCookie(new FlowCookie(BigInteger.valueOf(flowCookie.incrementAndGet())))
+            .setFlags(new FlowModFlags(false, false, false, false, false));
+
+        EthernetMatch ethernetMatch = ArpFlowFactory.createEthernetMatch(senderAddress.getHardwareAddress());
+        ArpMatch arpMatch = ArpFlowFactory.createArpMatch(senderAddress, ipForRequestedMac);
+        Match match = new MatchBuilder().setEthernetMatch(ethernetMatch).setLayer3Match(arpMatch).build();
+        arpFlow.setMatch(match);
+        arpFlow.setInstructions(new InstructionsBuilder().setInstruction(
+                ImmutableList.of(SEND_TO_CONTROLLER_INSTRUCTION)).build());
+        arpFlow.setId(createFlowId(senderAddress, ipForRequestedMac));
+        return arpFlow.build();
+    }
+
+    private FlowId createFlowId(ArpMessageAddress senderAddress, Ipv4Address ipForRequestedMac) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(ARP_REPLY_TO_CONTROLLER_FLOW_NAME);
+        sb.append("|").append(ipForRequestedMac.getValue());
+        return new FlowId(sb.toString());
+    }
+
+    private static InstanceIdentifier<Flow> createFlowIid(Flow flow, InstanceIdentifier<Node> nodeIid) {
+        return nodeIid.builder()
+            .augmentation(FlowCapableNode.class)
+            .child(Table.class, new TableKey(flow.getTableId()))
+            .child(Flow.class, new FlowKey(flow.getId()))
+            .build();
+    }
+
+    private FutureCallback<RpcResult<Void>> logResult(final Ipv4Address tpa,
+            final KeyedInstanceIdentifier<NodeConnector, NodeConnectorKey> egressNcIid) {
+        return new FutureCallback<RpcResult<Void>>() {
+
+            @Override
+            public void onSuccess(RpcResult<Void> result) {
+                LOG.debug("ARP Request for IP {} was sent from {}.", tpa.getValue(), egressNcIid);
+            }
+
+            @Override
+            public void onFailure(Throwable t) {
+                LOG.warn("ARP Request for IP {} was NOT sent from {}.", tpa.getValue(), egressNcIid);
+            }
+        };
+    }
+
+    @Override
+    public void onPacketReceived(PacketReceived potentialArp) {
+        Arp arp = null;
+        try {
+            arp = ArpResolverUtils.getArpFrom(potentialArp);
+        } catch (Exception e) {
+            LOG.trace(
+                    "Failed to decode potential ARP packet. This could occur when other than ARP packet was received.",
+                    e);
+            return;
+        }
+        if (arp.getOperation() != ArpOperation.REPLY.intValue()) {
+            LOG.trace("Packet is not ARP REPLY packet.");
+            return;
+        }
+        if (LOG.isTraceEnabled()) {
+            LOG.trace("ARP REPLY received - {}", ArpUtils.getArpToStringFormat(arp));
+        }
+        NodeKey nodeKey = potentialArp.getIngress().getValue().firstKeyOf(Node.class, NodeKey.class);
+        if (nodeKey == null) {
+            LOG.info("Unknown source node of ARP packet: {}", potentialArp);
+            return;
+        }
+        Ipv4Address gatewayIpAddress = ArpUtils.bytesToIp(arp.getSenderProtocolAddress());
+        MacAddress gatewayMacAddress = ArpUtils.bytesToMac(arp.getSenderHardwareAddress());
+        ArpResolverMetadata removeFlowInputAndL3EpKey = arpRemoveFlowInputAndL3EpKeyById.get(gatewayIpAddress);
+        if(removeFlowInputAndL3EpKey != null){
+            removeFlowInputAndL3EpKey.setGatewayMacAddress(gatewayMacAddress);
+            flowService.removeFlow(removeFlowInputAndL3EpKey.getFlowToRemove());
+        }
+    }
+
+    @Override
+    public void setDependencies(BundleContext bundleContext,
+            ServiceReference serviceReference) {
+        super.setDependencies(bundleContext.getServiceReference(GatewayMacResolver.class.getName()), this);
+
+    }
+
+    @Override
+    public void setDependencies(Object impl) {}
+
+    @Override
+    public void stopPeriodicReferesh(Ipv4Address gatewayIp) {
+        init();
+        arpRemoveFlowInputAndL3EpKeyById.remove(gatewayIp);
+    }
+
+}
index a08e753a1df65146e2160d0cb9c2dde826911fd5..eb8d75154c79136b8e6cf02276a65a41f070afa9 100644 (file)
@@ -70,23 +70,30 @@ public abstract class AbstractEvent {
 
     @Override
     public boolean equals(Object obj) {
-        if (this == obj)
+        if (this == obj) {
             return true;
-        if (obj == null)
+        }
+        if (obj == null) {
             return false;
-        if (getClass() != obj.getClass())
+        }
+        if (getClass() != obj.getClass()) {
             return false;
+        }
         AbstractEvent other = (AbstractEvent) obj;
         if (handlerType == null) {
-            if (other.handlerType != null)
+            if (other.handlerType != null) {
                 return false;
-        } else if (!handlerType.equals(other.handlerType))
+            }
+        } else if (!handlerType.equals(other.handlerType)) {
             return false;
+        }
         if (action == null) {
-            if (other.action != null)
+            if (other.action != null) {
                 return false;
-        } else if (!action.equals(other.action))
+            }
+        } else if (!action.equals(other.action)) {
             return false;
+        }
         return true;
     }
 }
index bf3d965a72482f0d3b0612d45f3d14f6ccd0daa2..53dbd7c9e688cdc8c241c48bfdecaff172e6ac8a 100644 (file)
@@ -32,6 +32,7 @@ public class ConfigActivator implements BundleActivator {
     private ServiceTracker outboundNatProviderTracker;
     private ServiceTracker routingProviderTracker;
     private ServiceTracker l3ForwardingProviderTracker;
+    private ServiceTracker gatewayMacResolverProviderTracker;
 
     public ConfigActivator(ProviderContext providerContext) {
         this.providerContext = providerContext;
@@ -403,8 +404,26 @@ public class ConfigActivator implements BundleActivator {
         };
         l3ForwardingProviderTracker.open();
         this.l3ForwardingProviderTracker = l3ForwardingProviderTracker;
+
+        @SuppressWarnings("unchecked")
+        ServiceTracker gatewayMacResolverProviderTracker = new ServiceTracker(context,
+                GatewayMacResolver.class, null) {
+            @Override
+            public Object addingService(ServiceReference reference) {
+                LOG.info("addingService GatwayMacResolverProvider");
+                GatewayMacResolver service =
+                        (GatewayMacResolver) context.getService(reference);
+                if (service != null) {
+                    neutronL3Adapter.setDependencies(service);
+                }
+                return service;
+            }
+        };
+        gatewayMacResolverProviderTracker.open();
+        this.gatewayMacResolverProviderTracker = gatewayMacResolverProviderTracker;
     }
 
+
     @Override
     public void stop(BundleContext context) throws Exception {
         LOG.info("ConfigActivator stop");
index 86fd90e084c01d624ce45eaa984ada48622bbdcd..0d1cd37bc4aaa03b7ccd7f7bf0001d6901f6cba9 100755 (executable)
@@ -260,8 +260,9 @@ public class LBaaSPoolHandler extends AbstractHandler
                 }
             }
 
-            if (lbConfig.getMembers().size() > 0)
+            if (lbConfig.getMembers().size() > 0) {
                 lbConfigList.add(lbConfig);
+            }
         }
 
         return lbConfigList;
index 05b58aaebbc5c71863f9cd8ad910deb130d7b4d1..e3291fba92a8dc41eee96c9dd124c1a4ac337b1f 100755 (executable)
@@ -31,8 +31,9 @@ public class NeutronCacheUtils {
      * @return MAC address registered with that IP address
      */
     public static String getMacAddress(INeutronPortCRUD neutronPortsCache, String subnetID, String ipAddr) {
-        if (ipAddr == null || subnetID == null)
+        if (ipAddr == null || subnetID == null) {
             return null;
+        }
 
         List<Neutron_IPs> fixedIPs;
         Iterator<Neutron_IPs> fixedIPIterator;
@@ -47,8 +48,9 @@ public class NeutronCacheUtils {
                 fixedIPIterator = fixedIPs.iterator();
                 while (fixedIPIterator.hasNext()) {
                     ip = fixedIPIterator.next();
-                    if (ip.getIpAddress().equals(ipAddr) && ip.getSubnetUUID().equals(subnetID))
+                    if (ip.getIpAddress().equals(ipAddr) && ip.getSubnetUUID().equals(subnetID)) {
                         return port.getMacAddress();
+                    }
                 }
             }
         }
@@ -73,8 +75,9 @@ public class NeutronCacheUtils {
                 break;
             }
         }
-        if (networkID == null)
+        if (networkID == null) {
             return null;
+        }
 
         List<NeutronNetwork> allNetworks = neutronNetworkCache.getAllNetworks();
         for (NeutronNetwork network: allNetworks) {
index 3d89b43dc468720399509f45103ee61d56e4181c..61f6d7cf75a9116a0f9b8fea4afcdae42b4730de 100644 (file)
@@ -295,8 +295,10 @@ public class SouthboundHandler extends AbstractHandler
     private void processPortUpdate(Node node, OvsdbTerminationPointAugmentation port) {
         LOGGER.debug("processPortUpdate <{}> <{}>", node, port);
         NeutronNetwork network = tenantNetworkManager.getTenantNetwork(port);
-        if (network != null && !network.getRouterExternal()) {
-            this.handleInterfaceUpdate(node, port);
+        if (network != null ){
+            if(!network.getRouterExternal()){
+                this.handleInterfaceUpdate(node, port);
+            }
         }
     }
 
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/GatewayMacResolver.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/GatewayMacResolver.java
new file mode 100644 (file)
index 0000000..28e6fc1
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.openstack.netvirt.api;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+*
+* @author Anil Vishnoi (avishnoi@Brocade.com)
+*
+*/
+
+public interface GatewayMacResolver {
+
+    /**
+     * Method will trigger the mac resolution for gateway IP. If user set periodicRefresh to true,
+     * it will periodically trigger the gateway resolution after a specific time interval. If
+     * periodicRefresh is false, it will just do one time gateway resolution.
+     * @param externalNetworkBridgeDpid
+     * @param gatewayIp
+     * @param periodicReferesh
+     * @return
+     */
+    public ListenableFuture<MacAddress> resolveMacAddress( final Long externalNetworkBridgeDpid, final Ipv4Address gatewayIp,
+            final Ipv4Address sourceIpAddress, final MacAddress sourceMacAddress, final Boolean periodicRefresh);
+
+    /**
+     * Method will stop the periodic refresh of the given gateway ip address.
+     * @param gatewayIp
+     */
+    public void stopPeriodicReferesh(final Ipv4Address gatewayIp);
+}
index 5b315235a67c69b22d96b6f78c7aa0d80946b987..ccb8655222fbe51f0d7b8a9c1a847558fcfac608 100755 (executable)
@@ -68,33 +68,44 @@ public class LoadBalancerConfiguration {
          */
         @Override
         public boolean equals(Object obj) {
-            if (this == obj)
+            if (this == obj) {
                 return true;
-            if (obj == null)
+            }
+            if (obj == null) {
                 return false;
-            if (getClass() != obj.getClass())
+            }
+            if (getClass() != obj.getClass()) {
                 return false;
+            }
             LoadBalancerPoolMember other = (LoadBalancerPoolMember) obj;
             if (ipAddr == null) {
-                if (other.ipAddr != null)
+                if (other.ipAddr != null) {
                     return false;
-            } else if (!ipAddr.equals(other.ipAddr))
+                }
+            } else if (!ipAddr.equals(other.ipAddr)) {
                 return false;
+            }
             if (macAddr == null) {
-                if (other.macAddr != null)
+                if (other.macAddr != null) {
                     return false;
-            } else if (!macAddr.equals(other.macAddr))
+                }
+            } else if (!macAddr.equals(other.macAddr)) {
                 return false;
+            }
             if (port == null) {
-                if (other.port != null)
+                if (other.port != null) {
                     return false;
-            } else if (!port.equals(other.port))
+                }
+            } else if (!port.equals(other.port)) {
                 return false;
+            }
             if (protocol == null) {
-                if (other.protocol != null)
+                if (other.protocol != null) {
                     return false;
-            } else if (!protocol.equals(other.protocol))
+                }
+            } else if (!protocol.equals(other.protocol)) {
                 return false;
+            }
             return true;
         }
 
@@ -156,8 +167,9 @@ public class LoadBalancerConfiguration {
 
     public Map<String, LoadBalancerPoolMember> addMember(String uuid, LoadBalancerPoolMember member) {
         //If index is not set for this object, update it before inserting
-        if (member.getIndex() == -1)
+        if (member.getIndex() == -1) {
             member.setIndex(members.size());
+        }
         this.members.put(uuid, member);
         return this.members;
     }
@@ -171,16 +183,18 @@ public class LoadBalancerConfiguration {
         /* Update indices of all other members
          */
         int index = 0;
-        for(Map.Entry<String, LoadBalancerPoolMember> entry : this.getMembers().entrySet())
+        for(Map.Entry<String, LoadBalancerPoolMember> entry : this.getMembers().entrySet()) {
             ((LoadBalancerPoolMember) entry.getValue()).setIndex(index++);
+        }
         return this.members;
     }
 
     public boolean isValid() {
-        if (members.size() == 0)
+        if (members.size() == 0) {
             return false;
-        else if (providerNetworkType == null)
+        } else if (providerNetworkType == null) {
             return false;
+        }
         return true;
     }
 
index d50046c77337180ed6743717d6f9b9b8e48f0312..129276c32efa4fda8f2aae63b0acc44d9d4df790 100644 (file)
@@ -74,8 +74,9 @@ public class EventDispatcherImpl implements EventDispatcher, ConfigInterface {
             if (!eventHandler.awaitTermination(10, TimeUnit.SECONDS)) {
                 eventHandler.shutdownNow();
                 // Wait a while for tasks to respond to being cancelled
-                if (!eventHandler.awaitTermination(10, TimeUnit.SECONDS))
+                if (!eventHandler.awaitTermination(10, TimeUnit.SECONDS)) {
                     logger.error("Dispatcher's event handler did not terminate");
+                }
             }
         } catch (InterruptedException e) {
             // (Re-)Cancel if current thread also interrupted
index d0fb583268d6346a360e173bab260be1d88cfd82..1c58e6ca6062aeb7bbd1bedc9f44306926e76e82 100644 (file)
@@ -24,11 +24,17 @@ import org.opendaylight.neutron.spi.Neutron_IPs;
 import org.opendaylight.ovsdb.openstack.netvirt.ConfigInterface;
 import org.opendaylight.ovsdb.openstack.netvirt.api.*;
 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 
 import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 import org.slf4j.Logger;
@@ -42,6 +48,8 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 
 /**
  * Neutron L3 Adapter implements a hub-like adapter for the various Neutron events. Based on
@@ -63,6 +71,7 @@ public class NeutronL3Adapter implements ConfigInterface {
     private volatile OutboundNatProvider outboundNatProvider;
     private volatile ArpProvider arpProvider;
     private volatile RoutingProvider routingProvider;
+    private volatile GatewayMacResolver gatewayMacResolver;
 
     private class FloatIpData {
         private final Long dpid;          // br-int of node where floating ip is associated with tenant port
@@ -100,6 +109,7 @@ public class NeutronL3Adapter implements ConfigInterface {
     private Boolean enabled = false;
     private Boolean flgDistributedARPEnabled = true;
     private Southbound southbound;
+    private final ExecutorService gatewayMacResolverPool = Executors.newFixedThreadPool(5);
 
     private static final String OWNER_ROUTER_INTERFACE = "network:router_interface";
     private static final String OWNER_ROUTER_INTERFACE_DISTRIBUTED = "network:router_interface_distributed";
@@ -193,11 +203,36 @@ public class NeutronL3Adapter implements ConfigInterface {
 
         final boolean isDelete = action == Action.DELETE;
 
+        if (neutronPort.getDeviceOwner().equalsIgnoreCase(OWNER_ROUTER_GATEWAY)){
+            if(!isDelete){
+                Node externalBridgeNode = getExternalBridgeNode();
+                if(externalBridgeNode != null){
+                    LOGGER.info("Port {} is network router gateway interface, "
+                            + "triggering gateway resolution for the attached external network on node {}",neutronPort,externalBridgeNode);
+                    this.triggerGatewayMacResolver(externalBridgeNode, neutronPort);
+                }else{
+                    LOGGER.error("Did not find Node that has external bridge (br-ex), Gateway resolution failed");
+                }
+            }else{
+                NeutronNetwork externalNetwork = neutronNetworkCache.getNetwork(neutronPort.getNetworkUUID());
+
+                if(externalNetwork != null){
+                    if(externalNetwork.isRouterExternal()){
+                        final NeutronSubnet externalSubnet = getExternalNetworkSubnet(neutronPort);
+                        if(externalSubnet != null){
+                            gatewayMacResolver.stopPeriodicReferesh(new Ipv4Address(externalSubnet.getGatewayIP()));
+                        }
+                    }
+                }
+            }
+        }
+
         // Treat the port event as a router interface event if the port belongs to router. This is a
         // helper for handling cases when handleNeutronRouterInterfaceEvent is not available
         //
         if (neutronPort.getDeviceOwner().equalsIgnoreCase(OWNER_ROUTER_INTERFACE) ||
             neutronPort.getDeviceOwner().equalsIgnoreCase(OWNER_ROUTER_INTERFACE_DISTRIBUTED)) {
+
             for (Neutron_IPs neutronIP : neutronPort.getFixedIPs()) {
                 NeutronRouter_Interface neutronRouterInterface =
                         new NeutronRouter_Interface(neutronIP.getSubnetUUID(), neutronPort.getPortUUID());
@@ -623,7 +658,7 @@ public class NeutronL3Adapter implements ConfigInterface {
                                            Action actionForNode) {
         // Based on the local cache, figure out whether programming needs to occur. To do this, we
         // will look at desired action for node.
-        //
+
         final String cacheKey = node.getNodeId().getValue() + ":" + providerSegmentationId + ":" + ipStr;
         final Boolean isProgrammed = l3ForwardingCache.contains(cacheKey);
 
@@ -1205,6 +1240,88 @@ public class NeutronL3Adapter implements ConfigInterface {
         return null;
     }
 
+    private Long getDpidForExternalBridge(Node node) {
+        // Check if node is integration bridge; and only then return its dpid
+        if (southbound.getBridge(node, configurationService.getExternalBridgeName()) != null) {
+            return southbound.getDataPathId(node);
+        }
+        return null;
+    }
+
+    private Node getExternalBridgeNode(){
+        //Pickup the first node that has external bridge (br-ex).
+        //NOTE: We are assuming that all the br-ex are serving one external network and gateway ip of
+        //the external network is reachable from every br-ex
+        // TODO: Consider other deployment scenario, and thing of better solution.
+        List<Node> allBridges = nodeCacheManager.getBridgeNodes();
+        for(Node node : allBridges){
+            if (southbound.getBridge(node, configurationService.getExternalBridgeName()) != null) {
+                return node;
+            }
+        }
+        return null;
+    }
+
+    private NeutronSubnet getExternalNetworkSubnet(NeutronPort gatewayPort){
+        NeutronSubnet extSubnet = null;
+        for (NeutronSubnet subnet : neutronSubnetCache.getAllSubnets()){
+            if(subnet.getPortsInSubnet().contains(gatewayPort)){
+                extSubnet = subnet;
+                break;
+            }
+        }
+        return extSubnet;
+    }
+
+    public void triggerGatewayMacResolver(final Node node, final NeutronPort gatewayPort ){
+
+        Preconditions.checkNotNull(node);
+        Preconditions.checkNotNull(gatewayPort);
+        NeutronNetwork externalNetwork = neutronNetworkCache.getNetwork(gatewayPort.getNetworkUUID());
+
+        if(externalNetwork != null){
+            if(externalNetwork.isRouterExternal()){
+                final NeutronSubnet externalSubnet = getExternalNetworkSubnet(gatewayPort);
+                if(externalSubnet != null){
+                    if(externalSubnet.getGatewayIP() != null){
+                        LOGGER.info("Trigger MAC resolution for gateway ip {} on Node {}",externalSubnet.getGatewayIP(),node.getNodeId());
+
+                        ListenableFuture<MacAddress> gatewayMacAddress =
+                                gatewayMacResolver.resolveMacAddress(getDpidForExternalBridge(node),
+                                        new Ipv4Address(externalSubnet.getGatewayIP()),
+                                        new Ipv4Address(gatewayPort.getFixedIPs().get(0).getIpAddress()),
+                                        new MacAddress(gatewayPort.getMacAddress()),
+                                        false);
+                        if(gatewayMacAddress != null){
+                            Futures.addCallback(gatewayMacAddress, new FutureCallback<MacAddress>(){
+                                @Override
+                                public void onSuccess(MacAddress result) {
+                                    if(result != null){
+                                        updateExternalRouterMac(result.getValue());
+                                        LOGGER.info("Resolved MAC address for gateway IP {} is {}", externalSubnet.getGatewayIP(),result.getValue());
+                                    }else{
+                                        LOGGER.warn("MAC address resolution failed for gateway IP {}",externalSubnet.getGatewayIP());
+                                    }
+                                }
+
+                                @Override
+                                public void onFailure(Throwable t) {
+                                    LOGGER.warn("MAC address resolution failed for gateway IP {}",externalSubnet.getGatewayIP());
+                                }
+                            }, gatewayMacResolverPool);
+                        }
+                    }else{
+                        LOGGER.warn("No gateway IP address found for external subnet {}",externalSubnet);
+                    }
+                }else{
+                    LOGGER.warn("Neutron subnet not found for external network {}",externalNetwork);
+                }
+            }
+        }else{
+            LOGGER.warn("Neutron network not found for router interface {}",gatewayPort);
+        }
+    }
+
     /**
      * Return String that represents OF port with marker explicitly provided (reverse of MatchUtils:parseExplicitOFPort)
      *
@@ -1235,7 +1352,8 @@ public class NeutronL3Adapter implements ConfigInterface {
                 (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
         southbound =
                 (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
-
+        gatewayMacResolver =
+                (GatewayMacResolver) ServiceHelper.getGlobalInstance(GatewayMacResolver.class, this);
         initL3AdapterMembers();
     }
 
@@ -1257,6 +1375,8 @@ public class NeutronL3Adapter implements ConfigInterface {
             routingProvider = (RoutingProvider)impl;
         } else if (impl instanceof L3ForwardingProvider) {
             l3ForwardingProvider = (L3ForwardingProvider)impl;
+        }else if (impl instanceof GatewayMacResolver) {
+            gatewayMacResolver = (GatewayMacResolver)impl;
         }
     }
 }
index 628e6798d16862110f22efd4ce8aed3540d3d5e6..a4148cb34d2b9ef48e5cf72a8d9593be242e42bc 100644 (file)
@@ -68,8 +68,7 @@ public class ConfigurationServiceImpl implements OvsdbConfigurationService
     }
 
     public void unsetOvsdbConfigurationService(org.opendaylight.ovsdb.plugin.api.OvsdbConfigurationService pluginOvsdbConfigurationService){
-        if(this.pluginOvsdbConfigurationService != null)
-            this.pluginOvsdbConfigurationService = null;
+        this.pluginOvsdbConfigurationService = null;
     }
 
 
index db6daa05d260bc37d009de2ae03f7552c596a068..4eb1235b4ef3f642e3e33b6e8102b7a330f76747 100644 (file)
@@ -62,9 +62,9 @@ public class ConnectionServiceImpl implements OvsdbConnectionService{
     }
 
     public void unsetOvsdbConnectionService(org.opendaylight.ovsdb.plugin.api.OvsdbConnectionService pluginOvsdbConnectionService){
-        if(this.pluginOvsdbConnectionService != null)
-            this.pluginOvsdbConnectionService = null;
+        this.pluginOvsdbConnectionService = null;
     }
+
     @Override
     public Connection getConnection(Node node) {
         return pluginOvsdbConnectionService.getConnection(NodeUtils.getMdsalNode(node));
index b2fd8aaabf9027c876f77459630b4e09d73c2a32..c6943807d643098a2ac34e862148f7120ae9b6cf 100644 (file)
@@ -87,8 +87,9 @@ public class InventoryServiceImpl implements OvsdbInventoryService,
     }
 
     public void removeOvsdbInventoryListener(OvsdbInventoryListener pluginOvsdbInventoryListener){
-        if(this.ovsdbInventoryListeners.contains(ovsdbInventoryListeners))
+        if(this.ovsdbInventoryListeners.contains(ovsdbInventoryListeners)) {
             this.ovsdbInventoryListeners.remove(ovsdbInventoryListeners);
+        }
     }
 
     @Override
@@ -149,23 +150,26 @@ public class InventoryServiceImpl implements OvsdbInventoryService,
     @Override
     public void nodeAdded(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node node,
                           InetAddress address, int port) {
-        for(OvsdbInventoryListener listener : this.ovsdbInventoryListeners)
+        for(OvsdbInventoryListener listener : this.ovsdbInventoryListeners) {
             listener.nodeAdded(NodeUtils.getSalNode(node), address, port);
+        }
 
     }
 
     @Override
     public void nodeRemoved(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node node) {
-        for(OvsdbInventoryListener listener : this.ovsdbInventoryListeners)
+        for(OvsdbInventoryListener listener : this.ovsdbInventoryListeners) {
             listener.nodeRemoved(NodeUtils.getSalNode(node));
+        }
 
     }
 
     @Override
     public void rowAdded(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node node,
                          String tableName, String uuid, Row row) {
-        for(OvsdbInventoryListener listener : this.ovsdbInventoryListeners)
+        for(OvsdbInventoryListener listener : this.ovsdbInventoryListeners) {
             listener.rowAdded(NodeUtils.getSalNode(node), tableName, uuid, row);
+        }
 
     }
 
@@ -173,8 +177,9 @@ public class InventoryServiceImpl implements OvsdbInventoryService,
     public void rowUpdated(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node node,
                            String tableName, String uuid, Row old,
             Row row) {
-        for(OvsdbInventoryListener listener : this.ovsdbInventoryListeners)
+        for(OvsdbInventoryListener listener : this.ovsdbInventoryListeners) {
             listener.rowUpdated(NodeUtils.getSalNode(node), tableName, uuid, old, row);
+        }
 
     }
 
@@ -182,7 +187,8 @@ public class InventoryServiceImpl implements OvsdbInventoryService,
     public void rowRemoved(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node node,
                            String tableName, String uuid, Row row,
             Object context) {
-        for(OvsdbInventoryListener listener : this.ovsdbInventoryListeners)
+        for(OvsdbInventoryListener listener : this.ovsdbInventoryListeners) {
             listener.rowRemoved(NodeUtils.getSalNode(node), tableName, uuid, row, context);
+        }
     }
 }
index c7091a61106d5764fd91f5acc166b30527033c01..47af9fb3e3c2d83d73ac569f21fe4f328120a9cf 100644 (file)
@@ -87,13 +87,23 @@ public class Connection {
 
     @Override
     public boolean equals(Object obj) {
-        if (this == obj) return true;
-        if (obj == null) return false;
-        if (getClass() != obj.getClass()) return false;
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
         Connection other = (Connection) obj;
         if (identifier == null) {
-            if (other.identifier != null) return false;
-        } else if (!identifier.equals(other.identifier)) return false;
+            if (other.identifier != null) {
+                return false;
+            }
+        } else if (!identifier.equals(other.identifier)) {
+            return false;
+        }
         return true;
     }
 }
index 022af289fe715523961921d1d80d1b3aafb5ac4c..5481e08b4e171c1361be37f6d87f5b3635537e76 100644 (file)
@@ -58,8 +58,7 @@ public final class OvsVswitchdSchemaConstants {
     }
 
     public static boolean shouldConfigureController (String databaseName, String tableName) {
-        if (autoConfigureController && databaseName.equals(DATABASE_NAME) && tableName.equals("Bridge")) return true;
-        return false;
+        return autoConfigureController && databaseName.equals(DATABASE_NAME) && tableName.equals("Bridge");
     }
 
     public enum PortType {
index 443e878028b2d7f0b737d598f55d1bf68ab847eb..12acd4717910e21f81080cfddf6fed511cc46e4a 100644 (file)
@@ -499,17 +499,23 @@ public class ConfigurationServiceImpl implements OvsdbConfigurationService
     @Override
     public <T extends TypedBaseTable<?>> String getTableName(Node node, Class<T> typedClass) {
         Connection connection = connectionService.getConnection(node);
-        if (connection == null) return null;
+        if (connection == null) {
+            return null;
+        }
         OvsdbClient client = connection.getClient();
         TypedBaseTable<?> typedTable = client.getTypedRowWrapper(typedClass, null);
-        if (typedTable == null) return null;
+        if (typedTable == null) {
+            return null;
+        }
         return typedTable.getSchema().getName();
     }
 
     @Override
     public <T extends TypedBaseTable<?>> T getTypedRow(Node node, Class<T> typedClass, Row row) {
         Connection connection = connectionService.getConnection(node);
-        if (connection == null) return null;
+        if (connection == null) {
+            return null;
+        }
         OvsdbClient client = connection.getClient();
         return (T)client.getTypedRowWrapper(typedClass, row);
     }
@@ -517,7 +523,9 @@ public class ConfigurationServiceImpl implements OvsdbConfigurationService
     @Override
     public <T extends TypedBaseTable<?>> T createTypedRow(Node node, Class<T> typedClass) {
         Connection connection = connectionService.getConnection(node);
-        if (connection == null) return null;
+        if (connection == null) {
+            return null;
+        }
         OvsdbClient client = connection.getClient();
         return client.createTypedRowWrapper(typedClass);
     }
@@ -526,7 +534,9 @@ public class ConfigurationServiceImpl implements OvsdbConfigurationService
 
     private String getTableNameForRowUuid(Node node, String databaseName, UUID rowUuid) {
         ConcurrentMap<String, ConcurrentMap<String, Row>> cache  = ovsdbInventoryService.getCache(node, databaseName);
-        if (cache == null) return null;
+        if (cache == null) {
+            return null;
+        }
         for (String tableName : cache.keySet()) {
             ConcurrentMap<String, Row> rows = cache.get(tableName);
             if (rows.get(rowUuid.toString()) != null) {
index 6aa9cd1f52d892297cedd158ab1557fde8a230ff..8582174d835096e3e94dc1c4e2049dad70dbbf69 100644 (file)
@@ -150,7 +150,9 @@ public class ConnectionServiceImpl implements OvsdbConnectionService,
 
         try {
             port = Integer.parseInt(params.get(ConnectionConstants.PORT));
-            if (port == 0) port = DEFAULT_OVSDB_PORT;
+            if (port == 0) {
+                port = DEFAULT_OVSDB_PORT;
+            }
         } catch (Exception e) {
             port = DEFAULT_OVSDB_PORT;
         }
@@ -343,7 +345,9 @@ public class ConnectionServiceImpl implements OvsdbConnectionService,
     @Override
     public void disconnected(OvsdbClient client) {
         Connection connection = ovsdbConnections.get(this.getConnectionIdentifier(client));
-        if (connection == null) return;
+        if (connection == null) {
+            return;
+        }
         this.disconnect(connection.getNode());
     }
 }
index 7edee2590a45309f3efce40b9c60aef4f102eefa..00a4a28d60be593e00ec41f9135d0014eae654a5 100644 (file)
@@ -95,7 +95,9 @@ public class InventoryServiceImpl implements OvsdbInventoryService {
     @Override
     public ConcurrentMap<String, ConcurrentMap<String, Row>> getCache(Node n, String databaseName) {
         NodeDatabase db = dbCache.get(n);
-        if (db == null) return null;
+        if (db == null) {
+            return null;
+        }
         return db.getDatabase(databaseName);
     }
 
@@ -103,7 +105,9 @@ public class InventoryServiceImpl implements OvsdbInventoryService {
     @Override
     public ConcurrentMap<String, Row> getTableCache(Node n, String databaseName, String tableName) {
         NodeDatabase db = dbCache.get(n);
-        if (db == null) return null;
+        if (db == null) {
+            return null;
+        }
         return db.getTableCache(databaseName, tableName);
     }
 
@@ -111,7 +115,9 @@ public class InventoryServiceImpl implements OvsdbInventoryService {
     @Override
     public Row getRow(Node n, String databaseName, String tableName, String uuid) {
         NodeDatabase db = dbCache.get(n);
-        if (db == null) return null;
+        if (db == null) {
+            return null;
+        }
         return db.getRow(databaseName, tableName, uuid);
     }
 
@@ -128,7 +134,9 @@ public class InventoryServiceImpl implements OvsdbInventoryService {
     @Override
     public void removeRow(Node n, String databaseName, String tableName, String uuid) {
         NodeDatabase db = dbCache.get(n);
-        if (db != null) db.removeRow(databaseName, tableName, uuid);
+        if (db != null) {
+            db.removeRow(databaseName, tableName, uuid);
+        }
     }
 
     @Override
@@ -181,7 +189,9 @@ public class InventoryServiceImpl implements OvsdbInventoryService {
                 @Override
                 public void run() {
                     try {
-                        if (ovsdbConfigurationService != null) ovsdbConfigurationService.setOFController(node, uuid.toString());
+                        if (ovsdbConfigurationService != null) {
+                            ovsdbConfigurationService.setOFController(node, uuid.toString());
+                        }
                     } catch (InterruptedException | ExecutionException e) {
                         e.printStackTrace();
                     }
index 05102cb7d6016a9f20a0db575c6b89ba1fdc5041..864cb08366222e4ae402c15779f76f9275cf4079 100755 (executable)
@@ -459,13 +459,10 @@ def showPrettyNamesMap():
     prtLn('aliasMap:', 0)
     resultMap = {}
     for bridge in state.bridgeNodes.values():
-        resultMap[ bridge.alias ] = bridge.getOpenflowName()
+        resultMap[ bridge.alias ] = '{0: <25} {1: <7} {2}'.format(bridge.getOpenflowName(), bridge.name, bridge.dpId)
 
-    resultMapKeys = resultMap.keys()
-    resultMapKeys.sort()
-
-    for resultMapKey in resultMapKeys:
-        prtLn('{0}{1: <10} -> {2}'.format(spc, resultMapKey, resultMap[resultMapKey]), 0)
+    for resultMapKey in sorted(resultMap):
+        prtLn('{0}{1: <10} ->  {2}'.format(spc, resultMapKey, resultMap[resultMapKey]), 0)
     prtLn('', 0)
 
 # --
index ebe575b051feade02376fdf607cf2eb1825a1259..88d41a210ad3e3a6720f10265878c54c764d5b53 100644 (file)
@@ -399,10 +399,11 @@ public final class ActionUtils {
         final String HEXES = "0123456789ABCDEF";
         byte[] address = new byte[6];
         String[] macBytes = macAddress.split(":");
-        if (macBytes.length != 6)
+        if (macBytes.length != 6) {
             throw new IllegalArgumentException(
                     "Specified MAC Address must contain 12 hex digits" +
                     " separated pairwise by :'s.");
+        }
         for (int i = 0; i < 6; ++i) {
             address[i] = (byte) ((HEXES.indexOf(macBytes[i].toUpperCase()
                                                         .charAt(0)) << 4) | HEXES.indexOf(macBytes[i].toUpperCase()
index 4e190003208a826c21088350fb965904a4d69c7b..5eda399db8f795a4ad5d85e874134dac42569389 100644 (file)
@@ -1106,18 +1106,21 @@ public class MatchUtils {
                                               MacAddress dstMac,
                                               Long etherType) {
         EthernetMatchBuilder emb = new  EthernetMatchBuilder();
-        if (srcMac != null)
+        if (srcMac != null) {
             emb.setEthernetSource(new EthernetSourceBuilder()
                 .setAddress(srcMac)
                 .build());
-        if (dstMac != null)
+        }
+        if (dstMac != null) {
             emb.setEthernetDestination(new EthernetDestinationBuilder()
                 .setAddress(dstMac)
                 .build());
-        if (etherType != null)
+        }
+        if (etherType != null) {
             emb.setEthernetType(new EthernetTypeBuilder()
                 .setType(new EtherType(etherType))
                 .build());
+        }
         return emb.build();
     }