Bug 4331 - External bridge used for gateway mac resolver needs to be dynamic
authorFlavio Fernandes <ffernand@redhat.com>
Fri, 8 Jan 2016 03:57:33 +0000 (22:57 -0500)
committerFlavio Fernandes <ffernand@redhat.com>
Mon, 11 Jan 2016 13:27:47 +0000 (08:27 -0500)
With this change the GatewayMacResolverService will become resilient to the cases
where nodes get deleted or lose br-ex connectivity after the resolver is kicked
off to periodically track a given ip address.

Also made some minor clean up in NeutronL3Adapter, so that it needs not to
duplicate work for tracking ip in the very first iteration. That duplication
is not necessary as the GatewayMacResolverService is already implemented
with thread executors for the periodic monitoring.

Lastly, this gerrit augments the GatewayMacResolver service to provide
an extra boolean param called refreshExternalNetworkBridgeDpidIfNeeded.
That can be used to control whether dpid used gets updated when mac is
not getting resolved.

Change-Id: I95b9e5a2d5773a6be82221b71000ace2a662e772
Signed-off-by: Flavio Fernandes <ffernand@redhat.com>
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/openflow13/services/arp/ArpResolverMetadata.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/GatewayMacResolverService.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/GatewayMacResolver.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/NodeCacheManager.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/impl/NeutronL3Adapter.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/impl/NodeCacheManagerImpl.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/impl/SouthboundImpl.java

index b2861c35d53b9a2b6443d67a402b40aa9974b081..9da80ffdfbe041867f56fc465ad19bb7808633d1 100644 (file)
@@ -8,20 +8,42 @@
 
 package org.opendaylight.ovsdb.openstack.netvirt.providers;
 
-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.api.ArpProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.ClassifierProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
+import org.opendaylight.ovsdb.openstack.netvirt.api.EgressAclProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.GatewayMacResolver;
+import org.opendaylight.ovsdb.openstack.netvirt.api.InboundNatProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.IngressAclProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.L2ForwardingProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.L2RewriteProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.L3ForwardingProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.LoadBalancerProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProviderManager;
+import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheListener;
+import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.ovsdb.openstack.netvirt.api.OutboundNatProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.RoutingProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.OF13Provider;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
 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.ArpResponderService;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services.ClassifierService;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services.EgressAclService;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services.InboundNatService;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services.IngressAclService;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services.L2ForwardingService;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services.L2RewriteService;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services.L3ForwardingService;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services.LoadBalancerService;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services.OutboundNatService;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services.RoutingService;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services.arp.GatewayMacResolverService;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
@@ -31,6 +53,11 @@ import org.osgi.util.tracker.ServiceTracker;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+
 public class ConfigActivator implements BundleActivator {
     private static final Logger LOG = LoggerFactory.getLogger(ConfigActivator.class);
     private List<ServiceRegistration<?>> registrations = new ArrayList<>();
@@ -101,7 +128,7 @@ public class ConfigActivator implements BundleActivator {
         registerService(context, OutboundNatProvider.class.getName(),
                 outboundNatService, Service.OUTBOUND_NAT);
 
-        GatewayMacResolverService gatewayMacResolverService = new GatewayMacResolverService();
+        final GatewayMacResolverService gatewayMacResolverService = new GatewayMacResolverService();
         registerService(context, GatewayMacResolver.class.getName(),
                 gatewayMacResolverService, Service.GATEWAY_RESOLVER);
         getNotificationProviderService().registerNotificationListener(gatewayMacResolverService);
@@ -137,6 +164,38 @@ public class ConfigActivator implements BundleActivator {
             }
         };
         networkingProviderManagerTracker.open();
+
+        @SuppressWarnings("unchecked")
+        ServiceTracker ConfigurationServiceTracker = new ServiceTracker(context,
+                ConfigurationService.class, null) {
+            @Override
+            public Object addingService(ServiceReference reference) {
+                LOG.info("addingService ConfigurationService");
+                ConfigurationService service =
+                        (ConfigurationService) context.getService(reference);
+                if (service != null) {
+                    gatewayMacResolverService.setDependencies(service);
+                }
+                return service;
+            }
+        };
+        ConfigurationServiceTracker.open();
+
+        @SuppressWarnings("unchecked")
+        ServiceTracker NodeCacheManagerTracker = new ServiceTracker(context,
+                NodeCacheManager.class, null) {
+            @Override
+            public Object addingService(ServiceReference reference) {
+                LOG.info("addingService NodeCacheManager");
+                NodeCacheManager service =
+                        (NodeCacheManager) context.getService(reference);
+                if (service != null) {
+                    gatewayMacResolverService.setDependencies(service);
+                }
+                return service;
+            }
+        };
+        NodeCacheManagerTracker.open();
     }
 
     @Override
index 941f246ee078a8ea748cbcea8eee20c7c31a5bdb..7c39fff1ce9194112c90d899b4e00f1e122756b2 100644 (file)
@@ -24,7 +24,8 @@ public final class ArpResolverMetadata {
 
     private final GatewayMacResolverListener gatewayMacResolverListener;
     private final Ipv4Address gatewayIpAddress;
-    private final Long externalNetworkBridgeDpid;
+    private Long externalNetworkBridgeDpid;
+    private final boolean refreshExternalNetworkBridgeDpidIfNeeded;
     private final Ipv4Address arpRequestSourceIp;
     private final MacAddress arpRequestSourceMacAddress;
     private final boolean periodicRefresh;
@@ -36,10 +37,12 @@ public final class ArpResolverMetadata {
 
     public ArpResolverMetadata(final GatewayMacResolverListener gatewayMacResolverListener,
                                final Long externalNetworkBridgeDpid,
+                               final boolean refreshExternalNetworkBridgeDpidIfNeeded,
             final Ipv4Address gatewayIpAddress, final Ipv4Address arpRequestSourceIp,
             final MacAddress arpRequestMacAddress, final boolean periodicRefresh){
         this.gatewayMacResolverListener = gatewayMacResolverListener;
         this.externalNetworkBridgeDpid = externalNetworkBridgeDpid;
+        this.refreshExternalNetworkBridgeDpidIfNeeded = refreshExternalNetworkBridgeDpidIfNeeded;
         this.gatewayIpAddress = gatewayIpAddress;
         this.arpRequestSourceIp = arpRequestSourceIp;
         this.arpRequestSourceMacAddress = arpRequestMacAddress;
@@ -49,12 +52,15 @@ public final class ArpResolverMetadata {
         this.numberOfOutstandingArpRequests = 0;
     }
 
-    public RemoveFlowInput getFlowToRemove() {
-        return flowToRemove;
+    public boolean isRefreshExternalNetworkBridgeDpidIfNeeded() {
+        return refreshExternalNetworkBridgeDpidIfNeeded;
     }
     public boolean isPeriodicRefresh() {
         return periodicRefresh;
     }
+    public RemoveFlowInput getFlowToRemove() {
+        return flowToRemove;
+    }
     public void setFlowToRemove(RemoveFlowInput flowToRemove) {
         this.flowToRemove = flowToRemove;
     }
@@ -82,12 +88,18 @@ public final class ArpResolverMetadata {
     public Long getExternalNetworkBridgeDpid() {
         return externalNetworkBridgeDpid;
     }
+    public void setExternalNetworkBridgeDpid(Long externalNetworkBridgeDpid) {
+        this.externalNetworkBridgeDpid = externalNetworkBridgeDpid;
+    }
     public Ipv4Address getArpRequestSourceIp() {
         return arpRequestSourceIp;
     }
     public MacAddress getArpRequestSourceMacAddress() {
         return arpRequestSourceMacAddress;
     }
+    public boolean isGatewayMacAddressResolved() {
+        return gatewayMacAddressResolved;
+    }
 
     /**
      * This method is used to determine whether to use the broadcast MAC or the unicast MAC as the destination address
@@ -122,6 +134,10 @@ public final class ArpResolverMetadata {
     public int hashCode() {
         final int prime = 31;
         int result = 1;
+
+        result = prime
+                * result
+                + ((gatewayMacResolverListener == null) ? 0 : gatewayMacResolverListener.hashCode());
         result = prime
                 * result
                 + ((arpRequestSourceMacAddress == null) ? 0 : arpRequestSourceMacAddress
@@ -138,6 +154,7 @@ public final class ArpResolverMetadata {
                 * result
                 + ((gatewayIpAddress == null) ? 0 : gatewayIpAddress.hashCode());
         result = prime * result + (periodicRefresh ? 1231 : 1237);
+        result = prime * result + (refreshExternalNetworkBridgeDpidIfNeeded ? 1231 : 1237);
         return result;
     }
 
@@ -150,6 +167,11 @@ public final class ArpResolverMetadata {
         if (getClass() != obj.getClass())
             return false;
         ArpResolverMetadata other = (ArpResolverMetadata) obj;
+        if (gatewayMacResolverListener == null) {
+            if (other.gatewayMacResolverListener != null)
+                return false;
+        } else if (!gatewayMacResolverListener.equals(other.gatewayMacResolverListener))
+            return false;
         if (arpRequestSourceMacAddress == null) {
             if (other.arpRequestSourceMacAddress != null)
                 return false;
@@ -173,6 +195,8 @@ public final class ArpResolverMetadata {
             return false;
         if (periodicRefresh != other.periodicRefresh)
             return false;
+        if (refreshExternalNetworkBridgeDpidIfNeeded != other.refreshExternalNetworkBridgeDpidIfNeeded)
+            return false;
         return true;
     }
 
index 3c1ab52410b9fa41b585e6789c154778cf0b6cec..be01ac5a0cb6668a369d0890575fac2e958ef27a 100644 (file)
@@ -7,24 +7,20 @@
  */
 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.Map.Entry;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicLong;
-
+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;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
 import org.opendaylight.openflowplugin.api.OFConstants;
+import org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService;
 import org.opendaylight.ovsdb.openstack.netvirt.api.GatewayMacResolver;
 import org.opendaylight.ovsdb.openstack.netvirt.api.GatewayMacResolverListener;
+import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheManager;
 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;
@@ -72,14 +68,21 @@ 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;
+import java.math.BigInteger;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+
+import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
  *
@@ -107,6 +110,8 @@ public class GatewayMacResolverService extends AbstractServiceInstance
     private final ScheduledExecutorService gatewayMacRefresherPool = Executors.newScheduledThreadPool(1);
     private final ScheduledExecutorService refreshRequester = Executors.newSingleThreadScheduledExecutor();
     private AtomicBoolean initializationDone = new AtomicBoolean(false);
+    private volatile ConfigurationService configurationService;
+    private volatile NodeCacheManager nodeCacheManager;
 
     static {
         ApplyActions applyActions = new ApplyActionsBuilder().setAction(
@@ -145,7 +150,8 @@ public class GatewayMacResolverService extends AbstractServiceInstance
                     if (!gatewayToArpMetadataMap.isEmpty()){
                         for(final Entry<Ipv4Address, ArpResolverMetadata> gatewayToArpMetadataEntry : gatewayToArpMetadataMap.entrySet()){
                             final Ipv4Address gatewayIp = gatewayToArpMetadataEntry.getKey();
-                            final ArpResolverMetadata gatewayMetaData = gatewayToArpMetadataEntry.getValue();
+                            final ArpResolverMetadata gatewayMetaData =
+                                    checkAndGetExternalBridgeDpid(gatewayToArpMetadataEntry.getValue());
                             gatewayMacRefresherPool.schedule(new Runnable(){
 
                                 @Override
@@ -154,13 +160,15 @@ public class GatewayMacResolverService extends AbstractServiceInstance
                                     final Node externalNetworkBridge = getExternalBridge(gatewayMetaData.getExternalNetworkBridgeDpid());
                                     if(externalNetworkBridge == null){
                                         LOG.error("MAC address for gateway {} can not be resolved, because external bridge {} "
-                                                + "is not connected to controller.",gatewayIp.getValue(),gatewayMetaData.getExternalNetworkBridgeDpid() );
+                                                + "is not connected to controller.",
+                                                gatewayIp.getValue(),
+                                                gatewayMetaData.getExternalNetworkBridgeDpid() );
+                                    } else {
+                                        LOG.debug("Refresh Gateway Mac for gateway {} using source ip {} and mac {} for ARP request",
+                                                gatewayIp.getValue(),gatewayMetaData.getArpRequestSourceIp().getValue(),gatewayMetaData.getArpRequestSourceMacAddress().getValue());
+
+                                        sendGatewayArpRequest(externalNetworkBridge,gatewayIp,gatewayMetaData.getArpRequestSourceIp(), gatewayMetaData.getArpRequestSourceMacAddress());
                                     }
-
-                                    LOG.debug("Refresh Gateway Mac for gateway {} using source ip {} and mac {} for ARP request",
-                                            gatewayIp.getValue(),gatewayMetaData.getArpRequestSourceIp().getValue(),gatewayMetaData.getArpRequestSourceMacAddress().getValue());
-
-                                    sendGatewayArpRequest(externalNetworkBridge,gatewayIp,gatewayMetaData.getArpRequestSourceIp(), gatewayMetaData.getArpRequestSourceMacAddress());
                                 }
                             }, 1, TimeUnit.SECONDS);
                         }
@@ -180,14 +188,15 @@ public class GatewayMacResolverService extends AbstractServiceInstance
      * @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.
      * @return Future object
      */
     @Override
     public ListenableFuture<MacAddress> resolveMacAddress(
             final GatewayMacResolverListener gatewayMacResolverListener, final Long externalNetworkBridgeDpid,
+            final Boolean refreshExternalNetworkBridgeDpidIfNeeded,
             final Ipv4Address gatewayIp, final Ipv4Address sourceIpAddress, final MacAddress sourceMacAddress,
             final Boolean periodicRefresh){
+        Preconditions.checkNotNull(refreshExternalNetworkBridgeDpidIfNeeded);
         Preconditions.checkNotNull(sourceIpAddress);
         Preconditions.checkNotNull(sourceMacAddress);
         Preconditions.checkNotNull(gatewayIp);
@@ -208,14 +217,20 @@ public class GatewayMacResolverService extends AbstractServiceInstance
             }
         }else{
             gatewayToArpMetadataMap.put(gatewayIp,new ArpResolverMetadata(gatewayMacResolverListener,
-                    externalNetworkBridgeDpid, gatewayIp,sourceIpAddress,sourceMacAddress,periodicRefresh));
+                    externalNetworkBridgeDpid, refreshExternalNetworkBridgeDpidIfNeeded,
+                    gatewayIp, sourceIpAddress, sourceMacAddress, periodicRefresh));
         }
 
 
         final Node externalNetworkBridge = getExternalBridge(externalNetworkBridgeDpid);
-        if(externalNetworkBridge == null){
-            LOG.error("MAC address for gateway {} can not be resolved, because external bridge {} "
-                    + "is not connected to controller.",gatewayIp.getValue(),externalNetworkBridgeDpid );
+        if (externalNetworkBridge == null) {
+            if (!refreshExternalNetworkBridgeDpidIfNeeded) {
+                LOG.error("MAC address for gateway {} can not be resolved, because external bridge {} "
+                        + "is not connected to controller.", gatewayIp.getValue(), externalNetworkBridgeDpid);
+            } else {
+                LOG.debug("MAC address for gateway {} can not be resolved, since dpid was not refreshed yet",
+                        gatewayIp.getValue());
+            }
             return null;
         }
 
@@ -226,9 +241,62 @@ public class GatewayMacResolverService extends AbstractServiceInstance
     }
 
     private Node getExternalBridge(final Long externalNetworkBridgeDpid){
-        final String nodeName = OPENFLOW + externalNetworkBridgeDpid;
+        if (externalNetworkBridgeDpid != null) {
+            final String nodeName = OPENFLOW + externalNetworkBridgeDpid;
+            return getOpenFlowNode(nodeName);
+        }
+        return null;
+    }
+
+    private ArpResolverMetadata checkAndGetExternalBridgeDpid(ArpResolverMetadata gatewayMetaData) {
+        final Long origDpid = gatewayMetaData.getExternalNetworkBridgeDpid();
 
-        return getOpenFlowNode(nodeName);
+        // If we are not allowing dpid to change, there is nothing further to do here
+        if (!gatewayMetaData.isRefreshExternalNetworkBridgeDpidIfNeeded()) {
+            return gatewayMetaData;
+        }
+
+        // If current dpid is null, or if mac is not getting resolved, make an attempt to
+        // grab a different dpid, so a different (or updated) external bridge gets used
+        if (origDpid == null || !gatewayMetaData.isGatewayMacAddressResolved()) {
+            Long newDpid = getAnotherExternalBridgeDpid(origDpid);
+            gatewayMetaData.setExternalNetworkBridgeDpid(newDpid);
+        }
+
+        return gatewayMetaData;
+    }
+
+    private Long getAnotherExternalBridgeDpid(final Long unwantedDpid) {
+        LOG.trace("Being asked to find a new dpid. unwantedDpid:{} cachemanager:{} configurationService:{}",
+                unwantedDpid, nodeCacheManager, configurationService);
+
+        if (nodeCacheManager == null) {
+            LOG.error("Unable to find external dpid to use for resolver: no nodeCacheManager");
+            return unwantedDpid;
+        }
+        if (configurationService == null) {
+            LOG.error("Unable to find external dpid to use for resolver: no configurationService");
+            return unwantedDpid;
+        }
+
+        // Pickup another dpid in list that is different than the unwanted one provided and is in the
+        // operational tree. If none can be found, return the provided dpid as a last resort.
+        // 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 think of another solution.
+        List<Long> dpids =  nodeCacheManager.getBridgeDpids(configurationService.getExternalBridgeName());
+        Collections.shuffle(dpids);
+        for (Long dpid : dpids) {
+            if (dpid == null || dpid.equals(unwantedDpid) || getExternalBridge(dpid) == null) {
+                continue;
+            }
+
+            LOG.debug("Gateway Mac Resolver Service will use dpid {}", dpid);
+            return dpid;
+        }
+
+        LOG.warn("Unable to find usable external dpid for resolver. Best choice is still {}", unwantedDpid);
+        return unwantedDpid;
     }
 
     private void sendGatewayArpRequest(final Node externalNetworkBridge,final Ipv4Address gatewayIp,
@@ -398,7 +466,13 @@ public class GatewayMacResolverService extends AbstractServiceInstance
     }
 
     @Override
-    public void setDependencies(Object impl) {}
+    public void setDependencies(Object impl) {
+        if (impl instanceof NodeCacheManager) {
+            nodeCacheManager = (NodeCacheManager) impl;
+        } else if (impl instanceof ConfigurationService) {
+            configurationService = (ConfigurationService) impl;
+        }
+    }
 
     @Override
     public void stopPeriodicRefresh(Ipv4Address gatewayIp) {
index 1042f8b59611131247717185977bc93cb3026e01..626f9dca68be0100240d7551e23c100dc974bd1b 100644 (file)
@@ -31,14 +31,17 @@ public interface GatewayMacResolver {
      * periodicRefresh flag.
      * @param gatewayMacResolverListener An optional listener for mac update callback (can be null)
      * @param externalNetworkBridgeDpid This bridge will be used for sending ARP request
+     * @param refreshExternalNetworkBridgeDpidIfNeeded Instructs resolver to change bridge dpid if resolve is failing
      * @param gatewayIp ARP request will be send for this ip address
      * @param sourceIpAddress Source IP address for the ARP request (localhost)
      * @param sourceMacAddress Source MAC address for the ARP request (localhost)
      * @param periodicRefresh Do you want to periodically refresh the gateway mac?
      * @return ListenableFuture that contains the mac address of gateway ip.
      */
-    public ListenableFuture<MacAddress> resolveMacAddress(final GatewayMacResolverListener gatewayMacResolverListener,
-            final Long externalNetworkBridgeDpid, final Ipv4Address gatewayIp, final Ipv4Address sourceIpAddress,
+    public ListenableFuture<MacAddress> resolveMacAddress(
+            final GatewayMacResolverListener gatewayMacResolverListener,
+            final Long externalNetworkBridgeDpid, final Boolean refreshExternalNetworkBridgeDpidIfNeeded,
+            final Ipv4Address gatewayIp, final Ipv4Address sourceIpAddress,
             final MacAddress sourceMacAddress, final Boolean periodicRefresh);
 
     /**
index 1627f228670fee277e1509b6dfdae43e30b4a5cd..a27b229afa46acbb82fc06382b46aced6fc44f17 100644 (file)
@@ -27,6 +27,7 @@ public interface NodeCacheManager {
     List<Node> getNodes();
     Map<NodeId, Node> getOvsdbNodes();
     List<Node> getBridgeNodes();
+    List<Long> getBridgeDpids(final String bridgeName);
     void cacheListenerAdded(final ServiceReference ref, NodeCacheListener handler);
     void cacheListenerRemoved(final ServiceReference ref);
 
index f7a96764a9fb3a75335a42bff6c555bf84ebd249..32969722f0af643d159ba14bca0dcc719163fbd9 100644 (file)
@@ -8,17 +8,7 @@
 
 package org.opendaylight.ovsdb.openstack.netvirt.impl;
 
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
+import com.google.common.base.Preconditions;
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
 import org.opendaylight.ovsdb.openstack.netvirt.AbstractEvent;
@@ -71,10 +61,14 @@ import org.osgi.framework.ServiceReference;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-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 java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 
 /**
  * Neutron L3 Adapter implements a hub-like adapter for the various Neutron events. Based on
@@ -137,7 +131,6 @@ public class NeutronL3Adapter extends AbstractHandler implements GatewayMacResol
     private Boolean enabled = false;
     private Boolean flgDistributedARPEnabled = true;
     private Boolean isCachePopulationDone = false;
-    private final ExecutorService gatewayMacResolverPool = Executors.newFixedThreadPool(5);
 
     private Southbound southbound;
     private NeutronModelsDataStoreHelper neutronModelsDataStoreHelper;
@@ -433,15 +426,10 @@ public class NeutronL3Adapter extends AbstractHandler implements GatewayMacResol
         final boolean isDelete = action == Action.DELETE;
 
         if (neutronPort.getDeviceOwner().equalsIgnoreCase(OWNER_ROUTER_GATEWAY)){
-            if(!isDelete){
-                Node externalBridgeNode = getExternalBridgeNode();
-                if(externalBridgeNode != null){
-                    LOG.info("Port {} is network router gateway interface, "
-                            + "triggering gateway resolution for the attached external network on node {}", neutronPort, externalBridgeNode);
-                    this.triggerGatewayMacResolver(externalBridgeNode, neutronPort);
-                }else{
-                    LOG.error("Did not find Node that has external bridge (br-ex), Gateway resolution failed");
-                }
+            if (!isDelete) {
+                LOG.info("Port {} is network router gateway interface, "
+                        + "triggering gateway resolution for the attached external network", neutronPort);
+                this.triggerGatewayMacResolver(neutronPort);
             }else{
                 NeutronNetwork externalNetwork = neutronNetworkCache.getNetwork(neutronPort.getNetworkUUID());
 
@@ -1411,7 +1399,7 @@ public class NeutronL3Adapter extends AbstractHandler implements GatewayMacResol
     }
 
     private Long getDpidForExternalBridge(Node node) {
-        // Check if node is integration bridge; and only then return its dpid
+        // Check if node is external bridge; and only then return its dpid
         if (southbound.getBridge(node, configurationService.getExternalBridgeName()) != null) {
             return southbound.getDataPathId(node);
         }
@@ -1465,9 +1453,8 @@ public class NeutronL3Adapter extends AbstractHandler implements GatewayMacResol
          }
      }
 
-    public void triggerGatewayMacResolver(final Node node, final NeutronPort gatewayPort ){
+    private void triggerGatewayMacResolver(final NeutronPort gatewayPort){
 
-        Preconditions.checkNotNull(node);
         Preconditions.checkNotNull(gatewayPort);
         NeutronNetwork externalNetwork = neutronNetworkCache.getNetwork(gatewayPort.getNetworkUUID());
 
@@ -1477,36 +1464,18 @@ public class NeutronL3Adapter extends AbstractHandler implements GatewayMacResol
 
                 // TODO: address IPv6 case.
                 if (externalSubnet != null &&
-                    externalSubnet.getIpVersion() == 4 &&
-                    gatewayPort.getFixedIPs() != null) {
-                    LOG.info("Trigger MAC resolution for gateway ip {} on Node {}",externalSubnet.getGatewayIP(),node.getNodeId());
-                    ListenableFuture<MacAddress> gatewayMacAddress =
-                        gatewayMacResolver.resolveMacAddress(this,
-                                                             getDpidForExternalBridge(node),
-                                                             new Ipv4Address(externalSubnet.getGatewayIP()),
-                                                             new Ipv4Address(gatewayPort.getFixedIPs().get(0).getIpAddress()),
-                                                             new MacAddress(gatewayPort.getMacAddress()),
-                                                             true);
-                    if(gatewayMacAddress != null){
-                        Futures.addCallback(gatewayMacAddress, new FutureCallback<MacAddress>(){
-                            @Override
-                            public void onSuccess(MacAddress result) {
-                                if(result != null){
-                                    if(!result.getValue().equals(externalRouterMac)){
-                                        updateExternalRouterMac(result.getValue());
-                                        LOG.info("Resolved MAC address for gateway IP {} is {}", externalSubnet.getGatewayIP(),result.getValue());
-                                    }
-                                }else{
-                                    LOG.warn("MAC address resolution failed for gateway IP {}", externalSubnet.getGatewayIP());
-                                }
-                            }
-
-                            @Override
-                            public void onFailure(Throwable t) {
-                                LOG.warn("MAC address resolution failed for gateway IP {}", externalSubnet.getGatewayIP());
-                            }
-                        }, gatewayMacResolverPool);
-                    }
+                        externalSubnet.getIpVersion() == 4 &&
+                        gatewayPort.getFixedIPs() != null) {
+                    LOG.info("Trigger MAC resolution for gateway ip {}", externalSubnet.getGatewayIP());
+
+                    gatewayMacResolver.resolveMacAddress(
+                            this, /* gatewayMacResolverListener */
+                            null, /* externalNetworkBridgeDpid */
+                            true, /* refreshExternalNetworkBridgeDpidIfNeeded */
+                            new Ipv4Address(externalSubnet.getGatewayIP()),
+                            new Ipv4Address(gatewayPort.getFixedIPs().get(0).getIpAddress()),
+                            new MacAddress(gatewayPort.getMacAddress()),
+                            true /* periodicRefresh */);
                 } else {
                     LOG.warn("No gateway IP address found for external network {}", externalNetwork);
                 }
index 574331d6b784a33e395241e2ade0eeb2175d82fc..ded9a368529f33f8cbe761e177af7559eb339b3d 100644 (file)
@@ -21,6 +21,7 @@ import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheListener;
 import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheManager;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 
@@ -155,6 +156,20 @@ public class NodeCacheManagerImpl extends AbstractHandler implements NodeCacheMa
         return nodes;
     }
 
+    @Override
+    public List <Long> getBridgeDpids(final String bridgeName) {
+        List<Long> dpids = Lists.newArrayList();
+        for (Node node : nodeCache.values()) {
+            if (bridgeName == null || southbound.getBridge(node, bridgeName) != null) {
+                long dpid = southbound.getDataPathId(node);
+                if (dpid != 0L) {
+                    dpids.add(Long.valueOf(dpid));
+                }
+            }
+        }
+        return dpids;
+    }
+
     @Override
     public List<Node> getNodes() {
         List<Node> nodes = Lists.newArrayList();
index fb7f8e1224e599a0b2ceca4ab9aa35763812a7df..e280edeb77dd45cf2f7e443cd62247e71df0b64c 100644 (file)
@@ -311,12 +311,8 @@ public class SouthboundImpl implements Southbound {
     }
 
     public String getDatapathId(Node node) {
-        String datapathId = null;
         OvsdbBridgeAugmentation ovsdbBridgeAugmentation = node.getAugmentation(OvsdbBridgeAugmentation.class);
-        if (ovsdbBridgeAugmentation != null && ovsdbBridgeAugmentation.getDatapathId() != null) {
-            datapathId = node.getAugmentation(OvsdbBridgeAugmentation.class).getDatapathId().getValue();
-        }
-        return datapathId;
+        return getDatapathId(ovsdbBridgeAugmentation);
     }
 
     public String getDatapathId(OvsdbBridgeAugmentation ovsdbBridgeAugmentation) {