Added support of multiple routers from neutron 86/18386/5
authorMartin Sunal <msunal@cisco.com>
Wed, 15 Apr 2015 22:51:08 +0000 (00:51 +0200)
committerKeith Burns <alagalah@gmail.com>
Fri, 17 Apr 2015 00:55:43 +0000 (00:55 +0000)
Limitation - you cannot create more than one router interface in the same subnet

Change-Id: I3ef30eb340a67ae3907669c05aa04c748dbe8fed
Signed-off-by: Martin Sunal <msunal@cisco.com>
neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/NeutronMapper.java
neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/NeutronNetworkAware.java
neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/NeutronPortAware.java
neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/NeutronRouterAware.java
neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/util/MappingUtils.java

index 979564a0e2e6cced786fa29f22a8d17b5d7c9a34..724107e61ab83a2a52280ef3820870e1ed411989 100644 (file)
@@ -59,8 +59,9 @@ public class NeutronMapper implements AutoCloseable {
                 INeutronSecurityGroupAware.class, new NeutronSecurityGroupAware(dataProvider), null);
         registrations.add(neutronSecurityGroupAwareRegistration);
 
+        NeutronRouterAware.init(dataProvider, epService);
         ServiceRegistration<INeutronRouterAware> neutronRouterAwareRegistration = context.registerService(
-                INeutronRouterAware.class, new NeutronRouterAware(dataProvider, epService), null);
+                INeutronRouterAware.class, NeutronRouterAware.getInstance(), null);
         registrations.add(neutronRouterAwareRegistration);
     }
 
index e59e2bdda47229e2474daef7d389e38804b6f876..ba09345cacf118272858b46b200679871ac3ea1b 100644 (file)
@@ -125,7 +125,7 @@ public class NeutronNetworkAware implements INeutronNetworkAware {
     private void addEpgRouterIfMissing(TenantId tenantId, ReadWriteTransaction rwTx) {
         Optional<EndpointGroup> potentialEpgRouter = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
                 IidFactory.endpointGroupIid(tenantId, MappingUtils.EPG_ROUTER_ID), rwTx);
-        if (potentialEpgRouter.isPresent()) {
+        if (!potentialEpgRouter.isPresent()) {
             EndpointGroup epgRouter = new EndpointGroupBuilder().setId(MappingUtils.EPG_ROUTER_ID)
                 .setDescription(new Description(MappingUtils.NEUTRON_ROUTER__ + "epg_routers"))
                 .setIntraGroupPolicy(IntraGroupPolicy.RequireContract)
index 95945a6003dc5e38c92ca5eb94adc68927dbc0c8..42c6ff95fc5446d4967c9f87e44a4790fb41e425 100644 (file)
@@ -24,11 +24,13 @@ import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.DataStoreHelper;
 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.IidFactory;
 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils.ForwardingCtx;
 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.NeutronUtils;
 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.Utils;
-import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils.ForwardingCtx;
 import org.opendaylight.neutron.spi.INeutronPortAware;
 import org.opendaylight.neutron.spi.NeutronPort;
+import org.opendaylight.neutron.spi.NeutronRouter;
+import org.opendaylight.neutron.spi.NeutronRouter_Interface;
 import org.opendaylight.neutron.spi.NeutronSecurityGroup;
 import org.opendaylight.neutron.spi.NeutronSecurityRule;
 import org.opendaylight.neutron.spi.Neutron_IPs;
@@ -69,7 +71,7 @@ import com.google.common.collect.ImmutableList;
 
 public class NeutronPortAware implements INeutronPortAware {
 
-    private static final Logger LOG = LoggerFactory.getLogger(NeutronPortAware.class);
+    public static final Logger LOG = LoggerFactory.getLogger(NeutronPortAware.class);
     private static final String DEVICE_OWNER_DHCP = "network:dhcp";
     private static final String DEVICE_OWNER_ROUTER_IFACE = "network:router_interface";
     private static final int DHCP_CLIENT_PORT = 68;
@@ -104,13 +106,21 @@ public class NeutronPortAware implements INeutronPortAware {
     public void neutronPortCreated(NeutronPort port) {
         LOG.trace("neutronPortCreated - {}", port);
         if (isRouterInterfacePort(port)) {
-            LOG.trace("Port is router interface - do nothing - NeutronRouterAware handles router iface");
+            LOG.trace("Port is router interface.");
+            NeutronRouter neutronRouter = createRouter(port);
+            NeutronRouter_Interface routerIface = createRouterInterface(port);
+            int canAttachInterface = NeutronRouterAware.getInstance().canAttachInterface(neutronRouter, routerIface);
+            if (canAttachInterface == StatusCode.OK) {
+                NeutronRouterAware.getInstance().neutronRouterInterfaceAttached(neutronRouter, routerIface);
+            }
             return;
         }
+
         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
         TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
 
         if (isDhcpPort(port)) {
+            LOG.trace("Port is DHCP port.");
             List<NeutronSecurityRule> dhcpSecRules = createDhcpSecRules(port, null, rwTx);
             if (dhcpSecRules == null) {
                 rwTx.cancel();
@@ -170,6 +180,24 @@ public class NeutronPortAware implements INeutronPortAware {
         DataStoreHelper.submitToDs(rwTx);
     }
 
+    private static NeutronRouter createRouter(NeutronPort port) {
+        NeutronRouter neutronRouter = new NeutronRouter();
+        neutronRouter.setRouterUUID(port.getDeviceID());
+        neutronRouter.setTenantID(port.getTenantID());
+        neutronRouter.setName("Router_port__" + Strings.nullToEmpty(port.getName()));
+        return neutronRouter;
+    }
+
+    private static NeutronRouter_Interface createRouterInterface(NeutronPort port) {
+        Neutron_IPs firstIp = MappingUtils.getFirstIp(port.getFixedIPs());
+        if (firstIp == null) {
+            throw new IllegalStateException("Illegal state - Port " + port.getID() + " representing router interface does not have an IP.");
+        }
+        NeutronRouter_Interface routerIface = new NeutronRouter_Interface(firstIp.getSubnetUUID(), port.getID());
+        routerIface.setTenantID(port.getTenantID());
+        return routerIface;
+    }
+
     public static boolean addNeutronPort(NeutronPort port, ReadWriteTransaction rwTx, EndpointService epService) {
         TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
         L2FloodDomainId l2FdId = new L2FloodDomainId(port.getNetworkUUID());
@@ -211,7 +239,7 @@ public class NeutronPortAware implements INeutronPortAware {
 
     private List<NeutronSecurityRule> createDhcpSecRules(NeutronPort port, EndpointGroupId consumerEpgId, ReadTransaction rTx) {
         TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
-        Neutron_IPs firstIp = getFirstIp(port.getFixedIPs());
+        Neutron_IPs firstIp = MappingUtils.getFirstIp(port.getFixedIPs());
         if (firstIp == null) {
             LOG.warn("Illegal state - DHCP port does not have an IP address.");
             return null;
@@ -452,7 +480,7 @@ public class NeutronPortAware implements INeutronPortAware {
         List<Neutron_IPs> fixedIPs = port.getFixedIPs();
         // TODO Li msunal this getting of just first IP has to be rewrite when OFOverlay renderer
         // will support l3-endpoints. Then we will register L2 and L3 endpoints separately.
-        Neutron_IPs firstIp = getFirstIp(fixedIPs);
+        Neutron_IPs firstIp = MappingUtils.getFirstIp(fixedIPs);
         if (firstIp != null) {
             inputBuilder.setNetworkContainment(new SubnetId(firstIp.getSubnetUUID()));
             L3Address l3Address = new L3AddressBuilder().setIpAddress(Utils.createIpAddress(firstIp.getIpAddress()))
@@ -496,18 +524,6 @@ public class NeutronPortAware implements INeutronPortAware {
         return new Name("tap" + port.getID().substring(0, 11));
     }
 
-    private static Neutron_IPs getFirstIp(List<Neutron_IPs> fixedIPs) {
-        if (fixedIPs == null || fixedIPs.isEmpty()) {
-            return null;
-        }
-        Neutron_IPs neutron_Ip = fixedIPs.get(0);
-        if (fixedIPs.size() > 1) {
-            LOG.warn("Neutron mapper does not support multiple IPs on the same port. Only first IP is selected {}",
-                    neutron_Ip);
-        }
-        return neutron_Ip;
-    }
-
     private static boolean isDhcpPort(NeutronPort port) {
         return DEVICE_OWNER_DHCP.equals(port.getDeviceOwner());
     }
index e105f8a2c5a5e5eb0dd0d7b2bc39ff53fce2f2fd..093fd32fe0f66da05f5d188c4e57e5823a758a28 100644 (file)
@@ -2,6 +2,7 @@ package org.opendaylight.groupbasedpolicy.neutron.mapper.mapping;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
@@ -12,12 +13,11 @@ import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.DataStoreHelper;
 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.IidFactory;
 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils.ForwardingCtx;
 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.NeutronUtils;
 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.Utils;
-import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils.ForwardingCtx;
 import org.opendaylight.neutron.spi.INeutronPortCRUD;
 import org.opendaylight.neutron.spi.INeutronRouterAware;
-import org.opendaylight.neutron.spi.INeutronRouterCRUD;
 import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
 import org.opendaylight.neutron.spi.NeutronCRUDInterfaces;
 import org.opendaylight.neutron.spi.NeutronPort;
@@ -35,6 +35,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.EndpointService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L3;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L3Builder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.mapper.rev150223.mappings.network.mappings.NetworkMapping;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomain;
@@ -48,33 +51,35 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Optional;
+import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableList;
 
 public class NeutronRouterAware implements INeutronRouterAware {
 
     private static final Logger LOG = LoggerFactory.getLogger(NeutronRouterAware.class);
-    private final DataBroker dataProvider;
-    private final EndpointService epService;
+    private static final NeutronRouterAware INSTANCE = new NeutronRouterAware();
+    private static DataBroker dataProvider;
+    private static EndpointService epService;
+
+    private NeutronRouterAware() {
+        if (NeutronRouterAware.INSTANCE != null) {
+            throw new IllegalStateException("Already instantiated");
+        }
+    }
+
+    public static NeutronRouterAware getInstance() {
+        return NeutronRouterAware.INSTANCE;
+    }
 
-    public NeutronRouterAware(DataBroker dataProvider, EndpointService epService) {
-        this.dataProvider = checkNotNull(dataProvider);
-        this.epService = checkNotNull(epService);
+    public static void init(DataBroker dataProvider, EndpointService epService) {
+        NeutronRouterAware.dataProvider = checkNotNull(dataProvider);
+        NeutronRouterAware.epService = checkNotNull(epService);
     }
 
     @Override
     public int canCreateRouter(NeutronRouter router) {
         LOG.trace("canCreateRouter - {}", router);
-        INeutronRouterCRUD routerInterface = NeutronCRUDInterfaces.getINeutronRouterCRUD(this);
-        if (routerInterface == null) {
-            LOG.warn("Illegal state - No provider for {}", INeutronSubnetCRUD.class.getName());
-            return StatusCode.INTERNAL_SERVER_ERROR;
-        }
-
-        List<NeutronRouter> allRouters = routerInterface.getAllRouters();
-        if (allRouters != null && !allRouters.isEmpty()) {
-            LOG.warn("Illegal state - Neutron mapper does not support multiple routers yet.");
-            return StatusCode.FORBIDDEN;
-        }
+        // nothing to consider
         return StatusCode.OK;
     }
 
@@ -123,7 +128,7 @@ public class NeutronRouterAware implements INeutronRouterAware {
     public int canAttachInterface(NeutronRouter router, NeutronRouter_Interface routerInterface) {
         LOG.trace("canAttachInterface - router: {} interface: {}", router, routerInterface);
         try (ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction()) {
-            L3ContextId l3ContextId = new L3ContextId(router.getID());
+            L3ContextId l3ContextIdFromRouterId = new L3ContextId(router.getID());
             TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
             SubnetId subnetId = new SubnetId(routerInterface.getSubnetUUID());
             Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
@@ -135,7 +140,7 @@ public class NeutronRouterAware implements INeutronRouterAware {
             Subnet subnet = potentialSubnet.get();
             L2FloodDomainId l2FdId = new L2FloodDomainId(subnet.getParent().getValue());
             ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rTx);
-            if (fwCtx.getL3Context() != null && fwCtx.getL3Context().equals(l3ContextId)) {
+            if (fwCtx.getL3Context() != null && fwCtx.getL3Context().equals(l3ContextIdFromRouterId)) {
                 // TODO Be msunal
                 LOG.warn("Illegal state - Neutron mapper does not support multiple router interfaces in the same subnet yet.");
                 return StatusCode.FORBIDDEN;
@@ -161,21 +166,22 @@ public class NeutronRouterAware implements INeutronRouterAware {
 
         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
         TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
-        L3ContextId l3ContextId = new L3ContextId(router.getID());
-        InstanceIdentifier<L3Context> l3ContextIid = IidFactory.l3ContextIid(tenantId, l3ContextId);
-        Optional<L3Context> potentialL3Context = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
-                l3ContextIid, rwTx);
+        L3ContextId l3ContextIdFromRouterId = new L3ContextId(router.getID());
+        InstanceIdentifier<L3Context> l3ContextIidForRouterId = IidFactory.l3ContextIid(tenantId,
+                l3ContextIdFromRouterId);
+        Optional<L3Context> potentialL3ContextForRouter = DataStoreHelper.readFromDs(
+                LogicalDatastoreType.CONFIGURATION, l3ContextIidForRouterId, rwTx);
         // add L3 context if missing
-        if (!potentialL3Context.isPresent()) {
+        if (!potentialL3ContextForRouter.isPresent()) {
             Name l3ContextName = null;
-            if (router.getName() != null) {
+            if (!Strings.isNullOrEmpty(router.getName())) {
                 l3ContextName = new Name(router.getName());
             }
-            L3Context l3Context = new L3ContextBuilder().setId(l3ContextId)
+            L3Context l3Context = new L3ContextBuilder().setId(l3ContextIdFromRouterId)
                 .setName(l3ContextName)
                 .setDescription(new Description(MappingUtils.NEUTRON_ROUTER__ + router.getID()))
                 .build();
-            rwTx.put(LogicalDatastoreType.CONFIGURATION, l3ContextIid, l3Context);
+            rwTx.put(LogicalDatastoreType.CONFIGURATION, l3ContextIidForRouterId, l3Context);
         }
 
         SubnetId subnetId = new SubnetId(routerInterface.getSubnetUUID());
@@ -207,8 +213,8 @@ public class NeutronRouterAware implements INeutronRouterAware {
             return;
         }
 
-        L2BridgeDomain l2BridgeDomain = new L2BridgeDomainBuilder(fwCtx.getL2BridgeDomain()).setParent(l3ContextId)
-            .build();
+        L2BridgeDomain l2BridgeDomain = new L2BridgeDomainBuilder(fwCtx.getL2BridgeDomain()).setParent(
+                l3ContextIdFromRouterId).build();
         rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BridgeDomain.getId()),
                 l2BridgeDomain);
 
@@ -226,6 +232,8 @@ public class NeutronRouterAware implements INeutronRouterAware {
             }
         }
 
+        List<L3> l3Eps = new ArrayList<>();
+        L3ContextId oldL3ContextId = fwCtx.getL3Context().getId();
         NeutronSubnet neutronSubnet = subnetInterface.getSubnet(subnetId.getValue());
         List<NeutronPort> portsInNeutronSubnet = neutronSubnet.getPortsInSubnet();
         for (NeutronPort port : portsInNeutronSubnet) {
@@ -234,6 +242,17 @@ public class NeutronRouterAware implements INeutronRouterAware {
                 rwTx.cancel();
                 return;
             }
+            // TODO Li msunal this has to be rewrite when OFOverlay renderer will support l3-endpoints.
+            Neutron_IPs firstIp = MappingUtils.getFirstIp(port.getFixedIPs());
+            if (firstIp != null) {
+                l3Eps.add(new L3Builder().setL3Context(oldL3ContextId)
+                    .setIpAddress(Utils.createIpAddress(firstIp.getIpAddress()))
+                    .build());
+            }
+        }
+
+        if (!l3Eps.isEmpty()) {
+            epService.unregisterEndpoint(new UnregisterEndpointInputBuilder().setL3(l3Eps).build());
         }
 
         DataStoreHelper.submitToDs(rwTx);
@@ -242,7 +261,7 @@ public class NeutronRouterAware implements INeutronRouterAware {
     public static List<NeutronSecurityRule> createRouterSecRules(NeutronPort port, EndpointGroupId consumerEpgId,
             ReadTransaction rTx) {
         TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
-        Neutron_IPs firstIp = getFirstIp(port.getFixedIPs());
+        Neutron_IPs firstIp = MappingUtils.getFirstIp(port.getFixedIPs());
         if (firstIp == null) {
             LOG.warn("Illegal state - Router port does not have an IP address.");
             return null;
@@ -262,18 +281,6 @@ public class NeutronRouterAware implements INeutronRouterAware {
         return ImmutableList.of(routerRuleEgress, routerRuleIngress);
     }
 
-    private static Neutron_IPs getFirstIp(List<Neutron_IPs> fixedIPs) {
-        if (fixedIPs == null || fixedIPs.isEmpty()) {
-            return null;
-        }
-        Neutron_IPs neutron_Ip = fixedIPs.get(0);
-        if (fixedIPs.size() > 1) {
-            LOG.warn("Neutron mapper does not support multiple IPs on the same port. Only first IP is selected {}",
-                    neutron_Ip);
-        }
-        return neutron_Ip;
-    }
-
     private static NeutronSecurityRule createRouterSecRule(String ruleUuid, TenantId tenantId, IpPrefix ipSubnet,
             EndpointGroupId consumerEpgId, boolean isEgress) {
         NeutronSecurityRule dhcpSecRule = new NeutronSecurityRule();
index 0f26982a2d2b80413c33bc463dade670daeb9c3c..f456480d1e26a3719cd2296d234958809287e88a 100644 (file)
@@ -1,8 +1,12 @@
 package org.opendaylight.groupbasedpolicy.neutron.mapper.util;
 
+import java.util.List;
+
 import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.NeutronPortAware;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.AllowAction;
+import org.opendaylight.neutron.spi.Neutron_IPs;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2BridgeDomainId;
@@ -87,4 +91,16 @@ public final class MappingUtils {
         }
 
     }
+
+    public static Neutron_IPs getFirstIp(List<Neutron_IPs> fixedIPs) {
+        if (fixedIPs == null || fixedIPs.isEmpty()) {
+            return null;
+        }
+        Neutron_IPs neutron_Ip = fixedIPs.get(0);
+        if (fixedIPs.size() > 1) {
+            NeutronPortAware.LOG.warn("Neutron mapper does not support multiple IPs on the same port. Only first IP is selected {}",
+                    neutron_Ip);
+        }
+        return neutron_Ip;
+    }
 }