Bug 4579 - Periodic ARP resolver is missing callback for MAC updates
authorFlavio Fernandes <ffernand@redhat.com>
Wed, 9 Dec 2015 12:42:26 +0000 (07:42 -0500)
committerFlavio Fernandes <ffernand@redhat.com>
Mon, 14 Dec 2015 14:55:44 +0000 (09:55 -0500)
Patch set 2: fix formatting

Change-Id: I21523c0c6e06c21f4dbf5b914f5dec625a40ab83
Signed-off-by: Flavio Fernandes <ffernand@redhat.com>
Also-By: Andre Fredette <afredette@redhat.com>
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/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/NeutronL3AdapterEvent.java [new file with mode: 0644]
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/GatewayMacResolverListener.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/impl/NeutronL3Adapter.java
openstack/net-virt/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/impl/NeutronL3AdapterTest.java

index aed4a647fe5732fc976215e32dc32cde994eab64..941f246ee078a8ea748cbcea8eee20c7c31a5bdb 100644 (file)
@@ -8,6 +8,8 @@
 package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services.arp;
 
 import org.opendaylight.controller.liblldp.NetUtils;
+import org.opendaylight.ovsdb.openstack.netvirt.api.GatewayMacResolverListener;
+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.service.rev130819.RemoveFlowInput;
@@ -20,6 +22,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.Remo
 
 public final class ArpResolverMetadata {
 
+    private final GatewayMacResolverListener gatewayMacResolverListener;
     private final Ipv4Address gatewayIpAddress;
     private final Long externalNetworkBridgeDpid;
     private final Ipv4Address arpRequestSourceIp;
@@ -31,9 +34,11 @@ public final class ArpResolverMetadata {
     private int numberOfOutstandingArpRequests;
     private static final int MAX_OUTSTANDING_ARP_REQUESTS = 2;
 
-    public ArpResolverMetadata(final Long externalNetworkBridgeDpid,
+    public ArpResolverMetadata(final GatewayMacResolverListener gatewayMacResolverListener,
+                               final Long externalNetworkBridgeDpid,
             final Ipv4Address gatewayIpAddress, final Ipv4Address arpRequestSourceIp,
             final MacAddress arpRequestMacAddress, final boolean periodicRefresh){
+        this.gatewayMacResolverListener = gatewayMacResolverListener;
         this.externalNetworkBridgeDpid = externalNetworkBridgeDpid;
         this.gatewayIpAddress = gatewayIpAddress;
         this.arpRequestSourceIp = arpRequestSourceIp;
@@ -61,6 +66,11 @@ public final class ArpResolverMetadata {
     }
     public void setGatewayMacAddress(MacAddress gatewayMacAddress) {
         if (gatewayMacAddress != null) {
+            if (gatewayMacResolverListener != null &&
+                    !gatewayMacAddress.equals(this.gatewayMacAddress)) {
+                gatewayMacResolverListener.gatewayMacResolved(externalNetworkBridgeDpid,
+                        new IpAddress(gatewayIpAddress), gatewayMacAddress);
+            }
             gatewayMacAddressResolved = true;
             numberOfOutstandingArpRequests = 0;
         } else {
index e74a7b60a7dad61ad5eebcea67d11fecbaabddc0..3c1ab52410b9fa41b585e6789c154778cf0b6cec 100644 (file)
@@ -24,6 +24,7 @@ import java.util.concurrent.atomic.AtomicLong;
 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.api.GatewayMacResolverListener;
 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;
@@ -183,8 +184,10 @@ public class GatewayMacResolverService extends AbstractServiceInstance
      * @return Future object
      */
     @Override
-    public ListenableFuture<MacAddress> resolveMacAddress( final Long externalNetworkBridgeDpid, final Ipv4Address gatewayIp,
-            final Ipv4Address sourceIpAddress, final MacAddress sourceMacAddress, final Boolean periodicRefresh){
+    public ListenableFuture<MacAddress> resolveMacAddress(
+            final GatewayMacResolverListener gatewayMacResolverListener, final Long externalNetworkBridgeDpid,
+            final Ipv4Address gatewayIp, final Ipv4Address sourceIpAddress, final MacAddress sourceMacAddress,
+            final Boolean periodicRefresh){
         Preconditions.checkNotNull(sourceIpAddress);
         Preconditions.checkNotNull(sourceMacAddress);
         Preconditions.checkNotNull(gatewayIp);
@@ -204,7 +207,7 @@ public class GatewayMacResolverService extends AbstractServiceInstance
                 });
             }
         }else{
-            gatewayToArpMetadataMap.put(gatewayIp,new ArpResolverMetadata(
+            gatewayToArpMetadataMap.put(gatewayIp,new ArpResolverMetadata(gatewayMacResolverListener,
                     externalNetworkBridgeDpid, gatewayIp,sourceIpAddress,sourceMacAddress,periodicRefresh));
         }
 
index d503a8d55fb40b04b59a8dc09f2af5b16541fcfe..c110bfc75803d1960d6f83fa287412db0fbc4158 100644 (file)
@@ -27,7 +27,8 @@ public abstract class AbstractEvent {
         NEUTRON_LOAD_BALANCER,
         NEUTRON_LOAD_BALANCER_POOL,
         NEUTRON_LOAD_BALANCER_POOL_MEMBER,
-        NODE;
+        NODE,
+        NEUTRON_L3_ADAPTER;
 
         public static final int size = HandlerType.values().length;
     }
index 8a5915b2449c2bedfee1982af524158040e89641..504202cc15f00e7e38e5eb2d8d2166cc42a31bf3 100644 (file)
@@ -23,6 +23,7 @@ import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
 import org.opendaylight.ovsdb.openstack.netvirt.api.EgressAclProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
 import org.opendaylight.ovsdb.openstack.netvirt.api.GatewayMacResolver;
+import org.opendaylight.ovsdb.openstack.netvirt.api.GatewayMacResolverListener;
 import org.opendaylight.ovsdb.openstack.netvirt.api.InboundNatProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.api.IngressAclProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.api.L3ForwardingProvider;
@@ -192,10 +193,14 @@ public class ConfigActivator implements BundleActivator {
         registerService(context,
                 new String[]{EventDispatcher.class.getName()}, null, eventDispatcher);
 
+        Dictionary<String, Object> neutronL3AdapterProperties = new Hashtable<>();
+        neutronL3AdapterProperties.put(Constants.EVENT_HANDLER_TYPE_PROPERTY,
+                AbstractEvent.HandlerType.NEUTRON_L3_ADAPTER);
         final NeutronL3Adapter neutronL3Adapter = new NeutronL3Adapter(
                 new NeutronModelsDataStoreHelper(this.providerContext.getSALService(DataBroker.class)));
         registerService(context,
-                new String[]{NeutronL3Adapter.class.getName()}, null, neutronL3Adapter);
+                new String[]{NeutronL3Adapter.class.getName(), GatewayMacResolverListener.class.getName()},
+                neutronL3AdapterProperties, neutronL3Adapter);
 
         OpenstackRouter openstackRouter = new OpenstackRouter();
         registerService(context,
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/NeutronL3AdapterEvent.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/NeutronL3AdapterEvent.java
new file mode 100644 (file)
index 0000000..a5515dc
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2015 Red Hat, 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;
+
+import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
+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.yang.types.rev100924.MacAddress;
+
+public class NeutronL3AdapterEvent extends AbstractEvent {
+    public enum SubType {
+        SUBTYPE_EXTERNAL_MAC_UPDATE;  // TODO: Add more subtypes as they come here
+
+        public static final int size = HandlerType.values().length;
+    }
+
+    private final SubType subtype;
+
+    private final Long bridgeDpid;
+    private final IpAddress gatewayIpAddress;
+    private final MacAddress macAddress;
+
+    public NeutronL3AdapterEvent(final Long bridgeDpid, final IpAddress gatewayIpAddress, final MacAddress macAddress) {
+        super(HandlerType.NEUTRON_L3_ADAPTER, Action.UPDATE);
+
+        this.subtype = SubType.SUBTYPE_EXTERNAL_MAC_UPDATE;
+        this.bridgeDpid = bridgeDpid;
+        this.gatewayIpAddress = gatewayIpAddress;
+        this.macAddress = macAddress;
+    }
+
+    public SubType getSubType() {
+        return subtype;
+    }
+
+    public Long getBridgeDpid() {
+        return bridgeDpid;
+    }
+    public IpAddress getGatewayIpAddress() {
+        return gatewayIpAddress;
+    }
+    public MacAddress getMacAddress() {
+        return macAddress;
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronL3AdapterEvent [handler=" + super.getHandlerType()
+                + ", action=" + super.getAction()
+                + ", subtype=" + subtype
+                + ", bridgeDpid=" + bridgeDpid
+                + ", gatewayIpAddress=" + gatewayIpAddress
+                + ", macAddress=" + macAddress
+                + "]";
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + ((subtype == null) ? 0 : subtype.hashCode());
+        result = prime * result + ((bridgeDpid == null) ? 0 : bridgeDpid.hashCode());
+        result = prime * result + ((gatewayIpAddress == null) ? 0 : gatewayIpAddress.hashCode());
+        result = prime * result + ((macAddress == null) ? 0 : macAddress.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        NeutronL3AdapterEvent other = (NeutronL3AdapterEvent) obj;
+        if (subtype == null) {
+            if (other.subtype != null) {
+                return false;
+            }
+        } else if (!subtype.equals(other.subtype)) {
+            return false;
+        }
+        if (bridgeDpid == null) {
+            if (other.bridgeDpid != null) {
+                return false;
+            }
+        } else if (!bridgeDpid.equals(other.bridgeDpid)) {
+            return false;
+        }
+        if (gatewayIpAddress == null) {
+            if (other.gatewayIpAddress != null) {
+                return false;
+            }
+        } else if (!gatewayIpAddress.equals(other.gatewayIpAddress)) {
+            return false;
+        }
+        if (macAddress == null) {
+            if (other.macAddress != null) {
+                return false;
+            }
+        } else if (!macAddress.equals(other.macAddress)) {
+            return false;
+        }
+        return true;
+    }
+}
index a96d78b4b57937847b604baab67439c71bf12e8e..1042f8b59611131247717185977bc93cb3026e01 100644 (file)
@@ -29,6 +29,7 @@ public interface GatewayMacResolver {
      * If user call the same method with different source ip and mac address, GatewayMacResolver service will
      * update the internally cached data with these new source ip and mac address and will use it as per
      * 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 gatewayIp ARP request will be send for this ip address
      * @param sourceIpAddress Source IP address for the ARP request (localhost)
@@ -36,8 +37,9 @@ public interface GatewayMacResolver {
      * @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 Long externalNetworkBridgeDpid, final Ipv4Address gatewayIp,
-            final Ipv4Address sourceIpAddress, final MacAddress sourceMacAddress, final Boolean periodicRefresh);
+    public ListenableFuture<MacAddress> resolveMacAddress(final GatewayMacResolverListener gatewayMacResolverListener,
+            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.
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/GatewayMacResolverListener.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/GatewayMacResolverListener.java
new file mode 100644 (file)
index 0000000..b2e46b1
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015 Red Hat, 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.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+
+/**
+ * This interface allows for notifications from GatewayMacResolver to a generic listener.
+ */
+public interface GatewayMacResolverListener {
+
+    /**
+     * Method will trigger when the mac for gateway IP is resolved or updated.
+     *
+     * @param externalNetworkBridgeDpid Bridge used for sending ARP request
+     * @param gatewayIpAddress Ip address that Mac Resolver ARPed for
+     * @param macAddress Mac Address associated with the gatewayIpAddress
+     */
+    void gatewayMacResolved(final Long externalNetworkBridgeDpid, final IpAddress gatewayIpAddress,
+                            final MacAddress macAddress);
+}
index dfcfdaa8cc5d464b58781ddff5741b89b82ac1eb..7009bcb45cd9abea7cd692a680b985c711907ada 100644 (file)
@@ -21,12 +21,17 @@ import java.util.concurrent.Executors;
 
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
+import org.opendaylight.ovsdb.openstack.netvirt.AbstractEvent;
+import org.opendaylight.ovsdb.openstack.netvirt.AbstractHandler;
 import org.opendaylight.ovsdb.openstack.netvirt.ConfigInterface;
+import org.opendaylight.ovsdb.openstack.netvirt.NeutronL3AdapterEvent;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
 import org.opendaylight.ovsdb.openstack.netvirt.api.ArpProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
+import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
 import org.opendaylight.ovsdb.openstack.netvirt.api.GatewayMacResolver;
+import org.opendaylight.ovsdb.openstack.netvirt.api.GatewayMacResolverListener;
 import org.opendaylight.ovsdb.openstack.netvirt.api.InboundNatProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.api.L3ForwardingProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheManager;
@@ -52,6 +57,7 @@ import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCR
 import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl.NeutronIAwareUtil;
 import org.opendaylight.ovsdb.utils.neutron.utils.NeutronModelsDataStoreHelper;
 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
+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.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
@@ -75,7 +81,7 @@ import com.google.common.util.concurrent.ListenableFuture;
  * these events, the abstract router callbacks can be generated to the multi-tenant aware router,
  * as well as the multi-tenant router forwarding provider.
  */
-public class NeutronL3Adapter implements ConfigInterface {
+public class NeutronL3Adapter extends AbstractHandler implements GatewayMacResolverListener, ConfigInterface {
     private static final Logger LOG = LoggerFactory.getLogger(NeutronL3Adapter.class);
 
     // The implementation for each of these services is resolved by the OSGi Service Manager
@@ -175,6 +181,58 @@ public class NeutronL3Adapter implements ConfigInterface {
         }
     }
 
+    //
+    // Callbacks from AbstractHandler
+    //
+    @Override
+    public void processEvent(AbstractEvent abstractEvent) {
+        if (!(abstractEvent instanceof NeutronL3AdapterEvent)) {
+            LOG.error("Unable to process abstract event " + abstractEvent);
+            return;
+        }
+        NeutronL3AdapterEvent ev = (NeutronL3AdapterEvent) abstractEvent;
+        switch (ev.getAction()) {
+            case UPDATE:
+                if (ev.getSubType() == NeutronL3AdapterEvent.SubType.SUBTYPE_EXTERNAL_MAC_UPDATE) {
+                    updateExternalRouterMac( ev.getMacAddress().getValue() );
+                } else {
+                    LOG.warn("Received update for an unexpected event " + ev);
+                }
+                break;
+            case ADD:
+                // fall through...
+                // break;
+            case DELETE:
+                // fall through...
+                // break;
+            default:
+                LOG.warn("Unable to process event " + ev);
+                break;
+        }
+    }
+
+    //
+    // Callbacks from GatewayMacResolverListener
+    //
+
+    @Override
+    public void gatewayMacResolved(Long externalNetworkBridgeDpid, IpAddress gatewayIpAddress, MacAddress macAddress) {
+        LOG.info("got gatewayMacResolved callback for ip {} on dpid {} to mac {}",
+                gatewayIpAddress, externalNetworkBridgeDpid, macAddress);
+        if (!this.enabled) {
+            return;
+        }
+
+        if (macAddress == null || macAddress.getValue() == null) {
+            // TODO: handle cases when mac is null
+            return;
+        }
+
+        //
+        // Enqueue event so update is handled by adapter's thread
+        //
+        enqueueEvent( new NeutronL3AdapterEvent(externalNetworkBridgeDpid, gatewayIpAddress, macAddress) );
+    }
 
     private void populateL3ForwardingCaches() {
         if (!this.enabled) {
@@ -1418,7 +1476,8 @@ public class NeutronL3Adapter implements ConfigInterface {
                     gatewayPort.getFixedIPs() != null) {
                     LOG.info("Trigger MAC resolution for gateway ip {} on Node {}",externalSubnet.getGatewayIP(),node.getNodeId());
                     ListenableFuture<MacAddress> gatewayMacAddress =
-                        gatewayMacResolver.resolveMacAddress(getDpidForExternalBridge(node),
+                        gatewayMacResolver.resolveMacAddress(this,
+                                                             getDpidForExternalBridge(node),
                                                              new Ipv4Address(externalSubnet.getGatewayIP()),
                                                              new Ipv4Address(gatewayPort.getFixedIPs().get(0).getIpAddress()),
                                                              new MacAddress(gatewayPort.getMacAddress()),
@@ -1464,6 +1523,9 @@ public class NeutronL3Adapter implements ConfigInterface {
 
     @Override
     public void setDependencies(ServiceReference serviceReference) {
+        eventDispatcher =
+                (EventDispatcher) ServiceHelper.getGlobalInstance(EventDispatcher.class, this);
+        eventDispatcher.eventHandlerAdded(serviceReference, this);
         tenantNetworkManager =
                 (TenantNetworkManager) ServiceHelper.getGlobalInstance(TenantNetworkManager.class, this);
         configurationService =
index fc9a266f80cb7917c6c721b0c37d10f32cb3bdfc..54c18b16482a06837c672381f7d92aa91d59a174 100644 (file)
@@ -45,9 +45,11 @@ import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
 import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
 import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
 import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
+import org.opendaylight.ovsdb.openstack.netvirt.AbstractHandler;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
 import org.opendaylight.ovsdb.openstack.netvirt.api.ArpProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService;
+import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
 import org.opendaylight.ovsdb.openstack.netvirt.api.InboundNatProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.api.L3ForwardingProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheManager;
@@ -892,6 +894,7 @@ public class NeutronL3AdapterTest {
 
     @Test
     public void testSetDependencies() throws Exception {
+        EventDispatcher eventDispatcher = mock(EventDispatcher.class);
         TenantNetworkManager tenantNetworkManager = mock(TenantNetworkManager.class);
         ConfigurationService configurationService = mock(ConfigurationService.class);
         ArpProvider arpProvider = mock(ArpProvider.class);
@@ -903,6 +906,7 @@ public class NeutronL3AdapterTest {
         Southbound southbound = mock(Southbound.class);
 
         PowerMockito.mockStatic(ServiceHelper.class);
+        PowerMockito.when(ServiceHelper.getGlobalInstance(EventDispatcher.class, neutronL3Adapter)).thenReturn(eventDispatcher);
         PowerMockito.when(ServiceHelper.getGlobalInstance(TenantNetworkManager.class, neutronL3Adapter)).thenReturn(tenantNetworkManager);
         PowerMockito.when(ServiceHelper.getGlobalInstance(ConfigurationService.class, neutronL3Adapter)).thenReturn(configurationService);
         PowerMockito.when(ServiceHelper.getGlobalInstance(ArpProvider.class, neutronL3Adapter)).thenReturn(arpProvider);
@@ -915,6 +919,8 @@ public class NeutronL3AdapterTest {
 
         neutronL3Adapter.setDependencies(mock(ServiceReference.class));
 
+        assertEquals("Error, did not return the correct object", getAbstractHandlerField("eventDispatcher"),
+                eventDispatcher);
         assertEquals("Error, did not return the correct object", getField("tenantNetworkManager"), tenantNetworkManager);
         assertEquals("Error, did not return the correct object", getField("configurationService"), configurationService);
         assertEquals("Error, did not return the correct object", getField("arpProvider"), arpProvider);
@@ -965,6 +971,12 @@ public class NeutronL3AdapterTest {
         MemberModifier.field(NeutronL3Adapter.class, "enabled").set(neutronL3Adapter , true);
     }
 
+    private Object getAbstractHandlerField(String fieldName) throws Exception {
+        Field field = AbstractHandler.class.getDeclaredField(fieldName);
+        field.setAccessible(true);
+        return field.get(neutronL3Adapter);
+    }
+
     private Object getField(String fieldName) throws Exception {
         Field field = NeutronL3Adapter.class.getDeclaredField(fieldName);
         field.setAccessible(true);