L3 Neutron events hookup to MultiTenantRouterForwardingProvider 00/10500/2
authorFlavio Fernandes <ffernand@redhat.com>
Fri, 29 Aug 2014 02:20:30 +0000 (22:20 -0400)
committerFlavio Fernandes <ffernand@redhat.com>
Sat, 30 Aug 2014 03:43:47 +0000 (23:43 -0400)
Neutron Router interface and floating ips will now trigger calls into MultiTenantRouterForwardingProvider.

Added implementations:
 * programStaticArpEntry (router interface)
 * programIpRewriteExclusion
 * programRouterInterface
 * programDefaultRouteEntry
 * programStaticArpEntry (tenant vms)
 * programIpRewriteRule

        Script for creating coke tenants in devstack:
        https://gist.github.com/1ba897e7cde8dbd87fe8

        Starting odl command:
        ./run.sh -virt ovsdb -Xms40m -Xmx1024m -XX:MaxPermSize=1024m

        LogLevel:
        setLogLevel org.opendaylight.ovsdb.openstack.netvirt.impl.NeutronL3Adapter trace

        Log of test:
        createTenants: https://gist.github.com/40364d727c40570fb4ff
        osgi: https://gist.github.com/105938470c9a19bebc4a

Change-Id: Ie4b30b2581c469064ca29a443d9ced4c2be4d3a9
Signed-off-by: Flavio Fernandes <ffernand@redhat.com>
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/Activator.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/RouterHandler.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/MultiTenantAwareRouter.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/Router.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/OpenstackRouter.java

index 2a4bc957e99d494fdd81989a3be36912daf0c695..9b460816ee6ce7dc492cef394b7f1b5508d5a66e 100644 (file)
@@ -24,6 +24,7 @@ import org.opendaylight.controller.networkconfig.neutron.INeutronPortCRUD;
 import org.opendaylight.controller.networkconfig.neutron.INeutronRouterAware;
 import org.opendaylight.controller.networkconfig.neutron.INeutronSecurityGroupAware;
 import org.opendaylight.controller.networkconfig.neutron.INeutronSecurityRuleAware;
+import org.opendaylight.controller.networkconfig.neutron.INeutronSubnetCRUD;
 import org.opendaylight.controller.networkconfig.neutron.INeutronSubnetAware;
 import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
 import org.opendaylight.controller.switchmanager.IInventoryListener;
@@ -31,6 +32,7 @@ import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
 import org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher;
 import org.opendaylight.ovsdb.openstack.netvirt.api.MultiTenantAwareRouter;
+import org.opendaylight.ovsdb.openstack.netvirt.api.MultiTenantRouterForwardingProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProviderManager;
 import org.opendaylight.ovsdb.openstack.netvirt.api.TenantNetworkManager;
@@ -283,10 +285,19 @@ public class Activator extends ComponentActivatorAbstractBase {
 
         if (imp.equals(NeutronL3Adapter.class)) {
             c.setInterface(NeutronL3Adapter.class.getName(), null);
-
+            c.add(createServiceDependency()
+                          .setService(org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService.class)
+                          .setRequired(true));
+            c.add(createServiceDependency().setService(TenantNetworkManager.class).setRequired(true));
+            c.add(createServiceDependency().setService(NetworkingProviderManager.class).setRequired(true));
+            c.add(createServiceDependency().setService(OvsdbConfigurationService.class).setRequired(true));
+            c.add(createServiceDependency().setService(OvsdbConnectionService.class).setRequired(true));
+            c.add(createServiceDependency().setService(INeutronNetworkCRUD.class).setRequired(true));
+            c.add(createServiceDependency().setService(INeutronSubnetCRUD.class).setRequired(true));
+            c.add(createServiceDependency().setService(INeutronPortCRUD.class).setRequired(true));
             c.add(createServiceDependency().setService(MultiTenantAwareRouter.class).setRequired(true));
-            // TODO: it will require MultiTenantRouterForwardingProvider
-            // c.add(createServiceDependency().setService(MultiTenantRouterForwardingProvider.class).setRequired(true));
+            // TODO: it should require MultiTenantRouterForwardingProvider
+            c.add(createServiceDependency().setService(MultiTenantRouterForwardingProvider.class).setRequired(false));
         }
 
         if (imp.equals(OpenstackRouter.class)) {
index e0d17201d463460cb0918b3a0f8205ac348d092e..a7cf21c95212e8212485ea876c40500c139cad36 100644 (file)
@@ -65,7 +65,7 @@ public class RouterHandler extends AbstractHandler
      *
      * @param delta
      *            updates to the router object using patch semantics
-     * @param router
+     * @param original
      *            instance of the Neutron Router object to be updated
      * @return integer
      *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
index b71807ea8bc6142a094e51b3017381ded0e29277..57df362ac922203ed975472df2d4d729c3f4543c 100644 (file)
@@ -11,8 +11,6 @@
 package org.opendaylight.ovsdb.openstack.netvirt.api;
 
 import java.net.InetAddress;
-import java.net.InterfaceAddress;
-import java.util.Set;
 import java.util.UUID;
 
 /**
@@ -21,27 +19,28 @@ import java.util.UUID;
  */
 public interface MultiTenantAwareRouter {
 
-  void addInterface(UUID tenantId, String interfaceName, Set<InterfaceAddress> addresses);
+    void addInterface(UUID tenantId, String interfaceName, InetAddress address, int mask);
 
-  void addInterface(UUID tenantId, String interfaceName, String macAddress, Set<InterfaceAddress> addresses);
+    void addInterface(UUID tenantId, String interfaceName, String macAddress, InetAddress address, int mask);
 
-  void updateInterface(UUID tenantId, String interfaceName, Set<InterfaceAddress> addresses);
+    void updateInterface(UUID tenantId, String interfaceName, InetAddress address, int mask);
 
-  void updateInterface(UUID tenantId, String interfaceName, String macAddress, Set<InterfaceAddress> addresses);
+    void updateInterface(UUID tenantId, String interfaceName, String macAddress, InetAddress address, int mask);
 
-  void removeInterface(UUID tenantId, String interfaceName);
+    void removeInterface(UUID tenantId, String interfaceName);
 
-  void addRoute(UUID tenantId, InterfaceAddress destination, InetAddress nextHop);
+    void addRoute(UUID tenantId, String destinationCidr, InetAddress nextHop);
 
-  void addRoute(UUID tenantId, InterfaceAddress destination, InetAddress nextHop, Integer priority);
+    void addRoute(UUID tenantId, String destinationCidr, InetAddress nextHop, Integer priority);
 
-  void removeRoute(UUID tenantId, InterfaceAddress destination, InetAddress nextHop);
+    void removeRoute(UUID tenantId, String destinationCidr, InetAddress nextHop);
 
-  void removeRoute(UUID tenantId, InterfaceAddress destination, InetAddress nextHop, Integer priority);
+    void removeRoute(UUID tenantId, String destinationCidr, InetAddress nextHop, Integer priority);
 
-  void addDefaultRoute(UUID tenantId, InetAddress nextHop);
+    void addDefaultRoute(UUID tenantId, InetAddress nextHop);
 
-  void addDefaultRoute(UUID tenantId, InetAddress nextHop, Integer priority);
+    void addDefaultRoute(UUID tenantId, InetAddress nextHop, Integer priority);
 
+    void addNatRule(UUID tenantId, InetAddress matchAddress, InetAddress rewriteAddress);
 
 }
index 9d0eda35446e115fa765c58732b7333e0e9f5bb8..a124f327144e760fc7c9349f03576a6dc4b44212 100644 (file)
 package org.opendaylight.ovsdb.openstack.netvirt.api;
 
 import java.net.InetAddress;
-import java.net.InterfaceAddress;
-import java.util.Set;
 
 /**
  * A Router
  */
 public interface Router {
 
-  void addInterface(String interfaceName, Set<InterfaceAddress> addresses);
+    void addInterface(String interfaceName, InetAddress address, int mask);
 
-  void addInterface(String interfaceName, String macAddress, Set<InterfaceAddress> addresses);
+    void addInterface(String interfaceName, String macAddress, InetAddress address, int mask);
 
-  void updateInterface(String interfaceName, Set<InterfaceAddress> addresses);
+    void updateInterface(String interfaceName, InetAddress address, int mask);
 
-  void updateInterface(String interfaceName, String macAddress, Set<InterfaceAddress> addresses);
+    void updateInterface(String interfaceName, String macAddress, InetAddress address, int mask);
 
-  void removeInterface(String interfaceName);
+    void removeInterface(String interfaceName);
 
-  void addRoute(InterfaceAddress destination, InetAddress nextHop);
+    void addRoute(String destinationCidr, InetAddress nextHop);
 
-  void addRoute(InterfaceAddress destination, InetAddress nextHop, Integer priority);
+    void addRoute(String destinationCidr, InetAddress nextHop, Integer priority);
 
-  void removeRoute(InterfaceAddress destination, InetAddress nextHop);
+    void removeRoute(String destinationCidr, InetAddress nextHop);
 
-  void removeRoute(InterfaceAddress destination, InetAddress nextHop, Integer priority);
+    void removeRoute(String destinationCidr, InetAddress nextHop, Integer priority);
 
-  void addDefaultRoute(InetAddress nextHop);
+    void addDefaultRoute(InetAddress nextHop);
 
-  void addDefaultRoute(InetAddress nextHop, Integer priority);
+    void addDefaultRoute(InetAddress nextHop, Integer priority);
 
-  void addNatRule(InetAddress matchAddress, InetAddress rewriteAddress);
+    void addNatRule(InetAddress matchAddress, InetAddress rewriteAddress);
 
 }
index 289e4130197c999a7e80b1f50ce72d82a4cc57b9..5618f67192cb4f4b1a04b3581c2db3ec4096d934 100644 (file)
 
 package org.opendaylight.ovsdb.openstack.netvirt.impl;
 
+import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkCRUD;
+import org.opendaylight.controller.networkconfig.neutron.INeutronPortCRUD;
+import org.opendaylight.controller.networkconfig.neutron.INeutronSubnetCRUD;
 import org.opendaylight.controller.networkconfig.neutron.NeutronFloatingIP;
 import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
 import org.opendaylight.controller.networkconfig.neutron.NeutronPort;
 import org.opendaylight.controller.networkconfig.neutron.NeutronRouter;
 import org.opendaylight.controller.networkconfig.neutron.NeutronRouter_Interface;
 import org.opendaylight.controller.networkconfig.neutron.NeutronSubnet;
+import org.opendaylight.controller.networkconfig.neutron.Neutron_IPs;
 import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.utils.HexEncode;
+import org.opendaylight.controller.sal.utils.Status;
+import org.opendaylight.controller.sal.utils.StatusCode;
+import org.opendaylight.ovsdb.lib.notation.Row;
 import org.opendaylight.ovsdb.openstack.netvirt.AbstractEvent;
 import org.opendaylight.ovsdb.openstack.netvirt.NorthboundEvent;
 import org.opendaylight.ovsdb.openstack.netvirt.api.MultiTenantAwareRouter;
 import org.opendaylight.ovsdb.openstack.netvirt.api.MultiTenantRouterForwardingProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProviderManager;
+import org.opendaylight.ovsdb.openstack.netvirt.api.TenantNetworkManager;
+import org.opendaylight.ovsdb.plugin.api.OvsdbConfigurationService;
+import org.opendaylight.ovsdb.plugin.api.OvsdbConnectionService;
+import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
 import org.opendaylight.ovsdb.schema.openvswitch.Interface;
 
+import com.google.common.base.Preconditions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
 /**
  * Neutron L3 Adapter implements a hub-like adapter for the various Neutron events. Based on
  * these events, the abstract router callbacks can be generated to the multi-tenant aware router,
@@ -39,9 +61,33 @@ public class NeutronL3Adapter {
     static final Logger logger = LoggerFactory.getLogger(NeutronL3Adapter.class);
 
     // The implementation for each of these services is resolved by the OSGi Service Manager
+    private volatile org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService configurationService;
+    private volatile TenantNetworkManager tenantNetworkManager;
+    private volatile NetworkingProviderManager networkingProviderManager;
+    private volatile OvsdbConfigurationService ovsdbConfigurationService;
+    private volatile OvsdbConnectionService connectionService;
+    private volatile INeutronNetworkCRUD neutronNetworkCache;
+    private volatile INeutronSubnetCRUD neutronSubnetCache;
+    private volatile INeutronPortCRUD neutronPortCache;
     private volatile MultiTenantAwareRouter multiTenantAwareRouter;
     private volatile MultiTenantRouterForwardingProvider multiTenantRouterForwardingProvider;
 
+    private Set<String> ipRewriteCache;
+    private Set<String> ipRewriteExclusionCache;
+    private Set<String> routerInterfacesCache;
+    private Set<String> staticArpEntryCache;
+    private Set<String> defaultRouteCache;
+    private Map<String, String> networkId2MacCache;
+
+    void init() {
+        this.ipRewriteCache = new HashSet<>();
+        this.ipRewriteExclusionCache = new HashSet<>();
+        this.routerInterfacesCache = new HashSet<>();
+        this.staticArpEntryCache = new HashSet<>();
+        this.defaultRouteCache = new HashSet<>();
+        this.networkId2MacCache = new HashMap();
+    }
+
     //
     // Callbacks from OVSDB's northbound handlers
     //
@@ -56,34 +102,34 @@ public class NeutronL3Adapter {
         logger.debug("Neutron port {} event : {}", action, neutronPort.toString());
 
         // TODO
-
     }
 
     public void handleNeutronRouterEvent(final NeutronRouter neutronRouter, NorthboundEvent.Action action) {
         logger.debug("Neutron router {} event : {}", action, neutronRouter.toString());
 
         // TODO
-
     }
 
     public void handleNeutronRouterInterfaceEvent(final NeutronRouter neutronRouter,
                                                   final NeutronRouter_Interface neutronRouterInterface,
                                                   NorthboundEvent.Action action) {
-        logger.debug(" Router {} interface {} attached. Subnet {}", neutronRouter.getName(),
+        logger.debug(" Router {} interface {} got event {}. Subnet {}",
+                     neutronRouter.getName(),
                      neutronRouterInterface.getPortUUID(),
+                     action,
                      neutronRouterInterface.getSubnetUUID());
 
-        // TODO
-
+        this.programFlowsForNeutronRouterInterface(neutronRouterInterface, action == AbstractEvent.Action.DELETE);
     }
 
     public void handleNeutronFloatingIPEvent(final NeutronFloatingIP neutronFloatingIP,
                                              NorthboundEvent.Action action) {
-        logger.debug(" Floating IP {} {}, uuid {}", action,
+        logger.debug(" Floating IP {} {}<->{}, network uuid {}", action,
                      neutronFloatingIP.getFixedIPAddress(),
-                     neutronFloatingIP.getFloatingIPUUID());
+                     neutronFloatingIP.getFloatingIPAddress(),
+                     neutronFloatingIP.getFloatingNetworkUUID());
 
-        // TODO
+        this.programFlowsForFloatingIP(neutronFloatingIP, action == AbstractEvent.Action.DELETE);
     }
 
     public void handleNeutronNetworkEvent(final NeutronNetwork neutronNetwork, NorthboundEvent.Action action) {
@@ -96,7 +142,7 @@ public class NeutronL3Adapter {
     // Callbacks from OVSDB's southbound handler
     //
 
-    public void handleInterfaceEvent(final Node node, final Interface intf, NeutronNetwork neutronNetwork,
+    public void handleInterfaceEvent(final Node node, final Interface intf, final NeutronNetwork neutronNetwork,
                                      AbstractEvent.Action action) {
         logger.debug("southbound interface {} node:{} interface:{}, neutronNetwork:{}",
                      action, node, intf, neutronNetwork);
@@ -104,4 +150,445 @@ public class NeutronL3Adapter {
         // TODO
     }
 
+    //
+    // Internal helpers
+    //
+
+    private void programFlowsForNeutronRouterInterface(final NeutronRouter_Interface neutronRouterInterface,
+                                                       Boolean isDelete) {
+        Preconditions.checkNotNull(neutronRouterInterface);
+
+        final NeutronPort neutronPort = neutronPortCache.getPort(neutronRouterInterface.getPortUUID());
+        final String macAddress = neutronPort != null ? neutronPort.getMacAddress() : null;
+        final List<Neutron_IPs> ipList = neutronPort != null ? neutronPort.getFixedIPs() : null;
+        final NeutronSubnet subnet = neutronSubnetCache.getSubnet(neutronRouterInterface.getSubnetUUID());
+        final NeutronNetwork neutronNetwork = subnet != null ?
+                                              neutronNetworkCache.getNetwork(subnet.getNetworkUUID()) : null;
+        final String providerSegmentationId = neutronNetwork != null ?
+                                              neutronNetwork.getProviderSegmentationID() : null;
+        final String gatewayIp = subnet != null ? subnet.getGatewayIP() : null;
+        final Boolean isExternal = neutronNetwork != null ? neutronNetwork.getRouterExternal() : Boolean.TRUE;
+        final String cidr = subnet != null ? subnet.getCidr() : null;
+        final int mask = getMaskLenFromCidr(cidr);
+
+        if (providerSegmentationId == null || providerSegmentationId.isEmpty() ||
+            cidr == null || cidr.isEmpty() ||
+            macAddress == null || macAddress.isEmpty() ||
+            ipList == null || ipList.isEmpty()) {
+            return;  // done: go no further w/out all the info needed...
+        }
+
+        final AbstractEvent.Action action =
+                isDelete ? AbstractEvent.Action.DELETE : AbstractEvent.Action.ADD;
+
+        // Keep cache for finding router's mac from network uuid
+        //
+        if (isDelete) {
+            networkId2MacCache.remove(neutronNetwork.getNetworkUUID());
+        } else {
+            networkId2MacCache.put(neutronNetwork.getNetworkUUID(), macAddress);
+        }
+
+        List<Node> nodes = connectionService.getNodes();
+        for (Node node : nodes) {
+            final Long dpid = getDpid(node);
+            final AbstractEvent.Action actionForNode =
+                    tenantNetworkManager.isTenantNetworkPresentInNode(node, providerSegmentationId) ?
+                    action : AbstractEvent.Action.DELETE;
+
+            for (Neutron_IPs neutronIP : ipList) {
+                final String ipStr = neutronIP.getIpAddress();
+                if (ipStr.isEmpty()) continue;
+                programRouterInterfaceStage1(node, dpid, providerSegmentationId, macAddress, ipStr, mask, actionForNode);
+                programStaticArpStage1(node, dpid, providerSegmentationId, macAddress, ipStr, actionForNode);
+            }
+
+            // Compute action to be programmed. In the case of rewrite exclusions, we must never program rules
+            // for the external neutron networks.
+            //
+            {
+                final AbstractEvent.Action actionForRewriteExclusion =
+                        isExternal ? AbstractEvent.Action.DELETE : actionForNode;
+                programIpRewriteExclusionStage1(node, dpid, providerSegmentationId, cidr, actionForRewriteExclusion);
+            }
+
+            // Default route. For non-external subnets, make sure that there is none configured.
+            //
+            if (gatewayIp != null && !gatewayIp.isEmpty()) {
+                final AbstractEvent.Action actionForNodeDefaultRoute =
+                        isExternal ? actionForNode : AbstractEvent.Action.DELETE;
+                final String defaultGatewayMacAddress = "00:01:02:03:04:05";  // FIXME!
+                programDefaultRouteStage1(node, dpid, providerSegmentationId, defaultGatewayMacAddress, gatewayIp,
+                                          actionForNodeDefaultRoute);
+            }
+        }
+    }
+
+    private void programRouterInterfaceStage1(Node node, Long dpid, String providerSegmentationId,
+                                              String macAddress, String ipStr, int mask,
+                                              AbstractEvent.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.toString() + ":" + providerSegmentationId + ":" +
+                                ipStr + "/" + Integer.toString(mask);
+        final Boolean isProgrammed = routerInterfacesCache.contains(cacheKey);
+
+        if (actionForNode == AbstractEvent.Action.DELETE && isProgrammed == Boolean.FALSE) return;
+        if (actionForNode == AbstractEvent.Action.ADD && isProgrammed == Boolean.TRUE) return;
+
+        Status status = this.programRouterInterfaceStage2(node, dpid, providerSegmentationId,
+                                                          macAddress, ipStr, mask, actionForNode);
+        if (status.isSuccess()) {
+            // Update cache
+            if (actionForNode == AbstractEvent.Action.ADD) {
+                // TODO: multiTenantAwareRouter.addInterface(UUID.fromString(tenant), ...);
+                routerInterfacesCache.add(cacheKey);
+            } else {
+                // TODO: multiTenantAwareRouter.removeInterface(...);
+                routerInterfacesCache.remove(cacheKey);
+            }
+        }
+    }
+
+    private Status programRouterInterfaceStage2(Node node, Long dpid, String providerSegmentationId,
+                                                String macAddress,
+                                                String address, int mask,
+                                                AbstractEvent.Action actionForNode) {
+        Status status;
+        try {
+            InetAddress inetAddress = InetAddress.getByName(address);
+            status = multiTenantRouterForwardingProvider == null ?
+                     new Status(StatusCode.SUCCESS) :
+                     multiTenantRouterForwardingProvider
+                             .programRouterInterface(node, dpid, providerSegmentationId,
+                                                     macAddress, inetAddress, mask, actionForNode);
+        } catch (UnknownHostException e) {
+            status = new Status(StatusCode.BADREQUEST);
+        }
+
+        if (status.isSuccess()) {
+            logger.debug("ProgramRouterInterface {} for mac:{} addr:{}/{} node:{} action:{}",
+                         multiTenantRouterForwardingProvider == null ? "skipped" : "programmed",
+                         macAddress, address, mask, node, actionForNode);
+        } else {
+            logger.error("ProgramRouterInterface failed for mac:{} addr:{}/{} node:{} action:{} status:{}",
+                         macAddress, address, mask, node, actionForNode, status);
+        }
+        return status;
+    }
+
+    private void programStaticArpStage1(Node node, Long dpid, String providerSegmentationId,
+                                        String macAddress, String ipStr,
+                                        AbstractEvent.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.toString() + ":" + providerSegmentationId + ":" + ipStr;
+        final Boolean isProgrammed = staticArpEntryCache.contains(cacheKey);
+
+        if (actionForNode == AbstractEvent.Action.DELETE && isProgrammed == Boolean.FALSE) return;
+        if (actionForNode == AbstractEvent.Action.ADD && isProgrammed == Boolean.TRUE) return;
+
+        Status status = this.programStaticArpStage2(node, dpid, providerSegmentationId,
+                                                    macAddress, ipStr, actionForNode);
+        if (status.isSuccess()) {
+            // Update cache
+            if (actionForNode == AbstractEvent.Action.ADD) {
+                staticArpEntryCache.add(cacheKey);
+            } else {
+                staticArpEntryCache.remove(cacheKey);
+            }
+        }
+    }
+
+    private Status programStaticArpStage2(Node node, Long dpid, String providerSegmentationId,
+                                                String macAddress,
+                                                String address,
+                                                AbstractEvent.Action actionForNode) {
+        Status status;
+        try {
+            InetAddress inetAddress = InetAddress.getByName(address);
+            status = multiTenantRouterForwardingProvider == null ?
+                     new Status(StatusCode.SUCCESS) :
+                     multiTenantRouterForwardingProvider
+                             .programStaticArpEntry(node, dpid, providerSegmentationId,
+                                                    macAddress, inetAddress, actionForNode);
+        } catch (UnknownHostException e) {
+            status = new Status(StatusCode.BADREQUEST);
+        }
+
+        if (status.isSuccess()) {
+            logger.debug("ProgramStaticArp {} for mac:{} addr:{} node:{} action:{}",
+                         multiTenantRouterForwardingProvider == null ? "skipped" : "programmed",
+                         macAddress, address, node, actionForNode);
+        } else {
+            logger.error("ProgramStaticArp failed for mac:{} addr:{} node:{} action:{} status:{}",
+                         macAddress, address, node, actionForNode, status);
+        }
+        return status;
+    }
+
+    private void programIpRewriteExclusionStage1(Node node, Long dpid, String providerSegmentationId,
+                                                 String cidr,
+                                                 AbstractEvent.Action actionForRewriteExclusion) {
+        // 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.toString() + ":" + providerSegmentationId + ":" + cidr;
+        final Boolean isProgrammed = ipRewriteExclusionCache.contains(cacheKey);
+
+        if (actionForRewriteExclusion == AbstractEvent.Action.DELETE && isProgrammed == Boolean.FALSE) return;
+        if (actionForRewriteExclusion == AbstractEvent.Action.ADD && isProgrammed == Boolean.TRUE) return;
+
+        Status status = this.programIpRewriteExclusionStage2(node, dpid, providerSegmentationId, cidr,
+                                                             actionForRewriteExclusion);
+        if (status.isSuccess()) {
+            // Update cache
+            if (actionForRewriteExclusion == AbstractEvent.Action.ADD) {
+                ipRewriteExclusionCache.add(cacheKey);
+            } else {
+                ipRewriteExclusionCache.remove(cacheKey);
+            }
+        }
+    }
+
+    private Status programIpRewriteExclusionStage2(Node node, Long dpid, String providerSegmentationId, String cidr,
+                                                   AbstractEvent.Action actionForNode) {
+        Status status = multiTenantRouterForwardingProvider == null ?
+                        new Status(StatusCode.SUCCESS) :
+                        multiTenantRouterForwardingProvider
+                                .programIpRewriteExclusion(node, dpid, providerSegmentationId, cidr, actionForNode);
+        if (status.isSuccess()) {
+            logger.debug("IpRewriteExclusion {} for cidr:{} node:{} action:{}",
+                         multiTenantRouterForwardingProvider == null ? "skipped" : "programmed",
+                         cidr, node, actionForNode);
+        } else {
+            logger.error("IpRewriteExclusion failed for cidr:{} node:{} action:{} status:{}",
+                         cidr, node, actionForNode, status);
+        }
+        return status;
+    }
+
+    private void programDefaultRouteStage1(Node node, Long dpid, String providerSegmentationId,
+                                           String defaultGatewayMacAddress, String gatewayIp,
+                                           AbstractEvent.Action actionForNodeDefaultRoute) {
+        // 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.toString() + ":" + providerSegmentationId + ":" + gatewayIp;
+        final Boolean isProgrammed = defaultRouteCache.contains(cacheKey);
+
+        if (actionForNodeDefaultRoute == AbstractEvent.Action.DELETE && isProgrammed == Boolean.FALSE) return;
+        if (actionForNodeDefaultRoute == AbstractEvent.Action.ADD && isProgrammed == Boolean.TRUE) return;
+
+        Status status = this.programDefaultRouteStage2(node, dpid, providerSegmentationId,
+                                                       defaultGatewayMacAddress, gatewayIp, actionForNodeDefaultRoute);
+        if (status.isSuccess()) {
+            // Update cache
+            if (actionForNodeDefaultRoute == AbstractEvent.Action.ADD) {
+                defaultRouteCache.add(cacheKey);
+            } else {
+                defaultRouteCache.remove(cacheKey);
+            }
+        }
+    }
+
+    private Status programDefaultRouteStage2(Node node, Long dpid, String providerSegmentationId,
+                                          String defaultGatewayMacAddress,
+                                          String gatewayIp,
+                                          AbstractEvent.Action actionForNodeDefaultRoute) {
+        Status status;
+        try {
+            InetAddress inetAddress = InetAddress.getByName(gatewayIp);
+            status = multiTenantRouterForwardingProvider == null ?
+                     new Status(StatusCode.SUCCESS) :
+                     multiTenantRouterForwardingProvider
+                             .programDefaultRouteEntry(node, dpid, providerSegmentationId,
+                                                       defaultGatewayMacAddress, inetAddress,
+                                                       actionForNodeDefaultRoute);
+        } catch (UnknownHostException e) {
+            status = new Status(StatusCode.BADREQUEST);
+        }
+
+        if (status.isSuccess()) {
+            logger.debug("ProgramDefaultRoute {} for mac:{} gatewayIp:{} node:{} action:{}",
+                         multiTenantRouterForwardingProvider == null ? "skipped" : "programmed",
+                         defaultGatewayMacAddress, gatewayIp, node, actionForNodeDefaultRoute);
+        } else {
+            logger.error("ProgramDefaultRoute failed for mac:{} gatewayIp:{} node:{} action:{} status:{}",
+                         defaultGatewayMacAddress, gatewayIp, node, actionForNodeDefaultRoute, status);
+        }
+        return status;
+    }
+
+    private void programFlowsForFloatingIP(final NeutronFloatingIP neutronFloatingIP, Boolean isDelete) {
+        Preconditions.checkNotNull(neutronFloatingIP);
+
+        final String networkUUID = neutronFloatingIP.getFloatingNetworkUUID();
+        final NeutronNetwork neutronNetwork = neutronNetworkCache.getNetwork(networkUUID);
+        final String providerSegmentationId = neutronNetwork != null ?
+                                              neutronNetwork.getProviderSegmentationID() : null;
+        final String routerMacAddress = networkId2MacCache.get(networkUUID);
+        final String fixedIPAddress = neutronFloatingIP.getFixedIPAddress();
+        final String floatingIpAddress = neutronFloatingIP.getFloatingIPAddress();
+
+        if (providerSegmentationId == null || providerSegmentationId.isEmpty() ||
+            routerMacAddress == null || routerMacAddress.isEmpty() ||
+            fixedIPAddress == null || fixedIPAddress.isEmpty() ||
+            floatingIpAddress == null || floatingIpAddress.isEmpty()) {
+            return;  // done: go no further w/out all the info needed...
+        }
+
+        final AbstractEvent.Action action = isDelete ? AbstractEvent.Action.DELETE : AbstractEvent.Action.ADD;
+        List<Node> nodes = connectionService.getNodes();
+        for (Node node : nodes) {
+            final Long dpid = getDpid(node);
+            final AbstractEvent.Action actionForNode =
+                    tenantNetworkManager.isTenantNetworkPresentInNode(node, providerSegmentationId) ?
+                    action : AbstractEvent.Action.DELETE;
+
+            // Rewrite from float to fixed and vice-versa
+            //
+            programIpRewriteStage1(node, dpid, providerSegmentationId, fixedIPAddress, floatingIpAddress, actionForNode);
+            programIpRewriteStage1(node, dpid, providerSegmentationId, floatingIpAddress, fixedIPAddress, actionForNode);
+
+            // Respond to arps for the floating ip address
+            //
+            programStaticArpStage1(node, dpid, providerSegmentationId, routerMacAddress, floatingIpAddress,
+                                   actionForNode);
+        }
+    }
+
+    private void programIpRewriteStage1(Node node, Long dpid, String providerSegmentationId,
+                                        String matchAddress, String rewriteAddress,
+                                        AbstractEvent.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.toString() + ":" + providerSegmentationId + ":" +
+                                matchAddress + ":" + rewriteAddress;
+        final Boolean isProgrammed = ipRewriteCache.contains(cacheKey);
+
+        if (actionForNode == AbstractEvent.Action.DELETE && isProgrammed == Boolean.FALSE) return;
+        if (actionForNode == AbstractEvent.Action.ADD && isProgrammed == Boolean.TRUE) return;
+
+        Status status = this.programIpRewriteStage2(node, dpid, providerSegmentationId,
+                                                    matchAddress, rewriteAddress, actionForNode);
+        if (status.isSuccess()) {
+            // Update cache
+            if (actionForNode == AbstractEvent.Action.ADD) {
+                ipRewriteCache.add(cacheKey);
+            } else {
+                ipRewriteCache.remove(cacheKey);
+            }
+        }
+    }
+
+    private Status programIpRewriteStage2(Node node, Long dpid, String providerSegmentationId,
+                                          String matchAddress, String rewriteAddress,
+                                          AbstractEvent.Action actionForNode) {
+        Status status;
+        try {
+            InetAddress inetMatchAddress = InetAddress.getByName(matchAddress);
+            InetAddress inetRewriteAddress = InetAddress.getByName(rewriteAddress);
+            status = multiTenantRouterForwardingProvider == null ?
+                     new Status(StatusCode.SUCCESS) :
+                     multiTenantRouterForwardingProvider
+                             .programIpRewriteRule(node, dpid, providerSegmentationId,
+                                                   inetMatchAddress, inetRewriteAddress, actionForNode);
+        } catch (UnknownHostException e) {
+            status = new Status(StatusCode.BADREQUEST);
+        }
+
+        if (status.isSuccess()) {
+            logger.debug("ProgramIpRewrite {} for match:{} rewrite:{} node:{} action:{}",
+                         multiTenantRouterForwardingProvider == null ? "skipped" : "programmed",
+                         matchAddress, rewriteAddress, node, actionForNode);
+        } else {
+            logger.error("ProgramIpRewrite failed for match:{} rewrite:{} node:{} action:{} status:{}",
+                         matchAddress, rewriteAddress, node, actionForNode, status);
+        }
+        return status;
+    }
+
+    //
+    // More Internals
+    //
+
+    private int getMaskLenFromCidr(String cidr) {
+        if (cidr == null) return 0;
+        String[] splits = cidr.split("/");
+        if (splits.length != 2) return 0;
+
+        int result;
+        try {
+            result = Integer.parseInt(splits[1].trim());
+        }
+        catch (NumberFormatException nfe)
+        {
+            result = 0;
+        }
+        return result;
+    }
+
+    private Long getDpid (Node node) {
+        Preconditions.checkNotNull(ovsdbConfigurationService);
+
+        String bridgeName = configurationService.getIntegrationBridgeName();
+        String bridgeUuid = this.getInternalBridgeUUID(node, bridgeName);
+        if (bridgeUuid == null) {
+            logger.error("Unable to spot Bridge Identifier for {} in {}", bridgeName, node);
+            return 0L;
+        }
+
+        try {
+            Row bridgeRow =  ovsdbConfigurationService
+                    .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), bridgeUuid);
+            Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeRow);
+            Set<String> dpids = bridge.getDatapathIdColumn().getData();
+            if (dpids == null || dpids.size() == 0) return 0L;
+            return HexEncode.stringToLong((String) dpids.toArray()[0]);
+        } catch (Exception e) {
+            logger.error("Error finding Bridge's OF DPID", e);
+            return 0L;
+        }
+    }
+
+    private String getInternalBridgeUUID (Node node, String bridgeName) {
+        Preconditions.checkNotNull(ovsdbConfigurationService);
+        try {
+            Map<String, Row>
+                    bridgeTable = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Bridge.class));
+            if (bridgeTable == null) return null;
+            for (String key : bridgeTable.keySet()) {
+                Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeTable.get(key));
+                if (bridge.getName().equals(bridgeName)) return key;
+            }
+        } catch (Exception e) {
+            logger.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);
+        }
+        return null;
+    }
+
 }
+
+/*
+JUNK
+
+        // NeutronPort neutronPort = neutronPortCache.getPort(neutronRouterInterface.getPortUUID());
+        NeutronSubnet subnet = neutronSubnetCache.getSubnet(neutronRouterInterface.getSubnetUUID());
+        NeutronNetwork neutronNetwork = neutronNetworkCache.getNetwork(subnet.getNetworkUUID());
+        String providerSegmentationId = neutronNetwork.getProviderSegmentationID();
+        Boolean isExternal = neutronNetwork.getRouterExternal();
+        String cidr = subnet.getCidr();
+
+        List<Node> nodes = connectionService.getNodes();
+        for (Node node : nodes) {
+            if (tenantNetworkManager.isTenantNetworkPresentInNode(node, providerSegmentationId)) {
+                Long dpid = getDpid(node);
+                Status status = multiTenantRouterForwardingProvider
+                        .programIpRewriteExclusion(node, dpid, providerSegmentationId, cidr, action);
+            }
+        }
+*/
index ce8f464131bf636e10962768c82fcd44bf5b5357..55425661c75ab7eb09184d32712ad246f05e81e1 100644 (file)
@@ -13,8 +13,6 @@ package org.opendaylight.ovsdb.openstack.netvirt.impl;
 import org.opendaylight.ovsdb.openstack.netvirt.api.MultiTenantAwareRouter;
 
 import java.net.InetAddress;
-import java.net.InterfaceAddress;
-import java.util.Set;
 import java.util.UUID;
 
 /**
@@ -24,23 +22,22 @@ import java.util.UUID;
 public class OpenstackRouter implements MultiTenantAwareRouter {
 
     @Override
-    public void addInterface(UUID tenantId, String interfaceName, Set<InterfaceAddress> addresses) {
+    public void addInterface(UUID tenantId, String interfaceName, InetAddress address, int mask) {
 
     }
 
     @Override
-    public void addInterface(UUID tenantId, String interfaceName, String macAddress, Set<InterfaceAddress> addresses) {
+    public void addInterface(UUID tenantId, String interfaceName, String macAddress, InetAddress address, int mask) {
 
     }
 
     @Override
-    public void updateInterface(UUID tenantId, String interfaceName, Set<InterfaceAddress> addresses) {
+    public void updateInterface(UUID tenantId, String interfaceName, InetAddress address, int mask) {
 
     }
 
     @Override
-    public void updateInterface(UUID tenantId, String interfaceName, String macAddress,
-                                Set<InterfaceAddress> addresses) {
+    public void updateInterface(UUID tenantId, String interfaceName, String macAddress, InetAddress address, int mask) {
 
     }
 
@@ -50,22 +47,22 @@ public class OpenstackRouter implements MultiTenantAwareRouter {
     }
 
     @Override
-    public void addRoute(UUID tenantId, InterfaceAddress destination, InetAddress nextHop) {
+    public void addRoute(UUID tenantId, String destinationCidr, InetAddress nextHop) {
 
     }
 
     @Override
-    public void addRoute(UUID tenantId, InterfaceAddress destination, InetAddress nextHop, Integer priority) {
+    public void addRoute(UUID tenantId, String destinationCidr, InetAddress nextHop, Integer priority) {
 
     }
 
     @Override
-    public void removeRoute(UUID tenantId, InterfaceAddress destination, InetAddress nextHop) {
+    public void removeRoute(UUID tenantId, String destinationCidr, InetAddress nextHop) {
 
     }
 
     @Override
-    public void removeRoute(UUID tenantId, InterfaceAddress destination, InetAddress nextHop, Integer priority) {
+    public void removeRoute(UUID tenantId, String destinationCidr, InetAddress nextHop, Integer priority) {
 
     }
 
@@ -78,4 +75,9 @@ public class OpenstackRouter implements MultiTenantAwareRouter {
     public void addDefaultRoute(UUID tenantId, InetAddress nextHop, Integer priority) {
 
     }
+
+    @Override
+    public void addNatRule(UUID tenantId, InetAddress matchAddress, InetAddress rewriteAddress) {
+
+    }
 }