Bug 6592: Adding output to group of external network when using NAPT 03/44903/3
authorTomer <tomer.pearl@hpe.com>
Mon, 29 Aug 2016 09:33:44 +0000 (12:33 +0300)
committerTomer <tomer.pearl@hpe.com>
Wed, 31 Aug 2016 14:48:15 +0000 (17:48 +0300)
https://bugs.opendaylight.org/show_bug.cgi?id=6592

Change-Id: I40b40f5f65c177b3a77a3206c95a4720ed0e66de
Signed-off-by: Tomer <tomer.pearl@hpe.com>
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/ExternalRoutersListener.java
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatUtil.java
vpnservice/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/netvirt/neutronvpn/NeutronvpnNatManager.java

index 5cb2db621554b7617eb0594caaa1cccc8a53abe9..f757d51976a07dc98c89aeaa9b1183ebeb1e40d3 100644 (file)
@@ -16,6 +16,7 @@ import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.JdkFutureAdapters;
 import com.google.common.util.concurrent.ListenableFuture;
 import java.math.BigInteger;
+import java.net.InetAddress;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -44,6 +45,8 @@ import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
@@ -100,6 +103,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.G
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.VpnRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -238,6 +242,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                     } else {
                         LOG.debug("NAT Service : Handle NAPT switch");
                         handlePrimaryNaptSwitch(dpnId, routerName);
+                        installNaptPfibExternalOutputFlow(routers, routerName, dpnId);
                     }
                 }
             }
@@ -347,6 +352,36 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         LOG.info("NAT Service : handleEnableSnat() Exit");
     }
 
+    private void installNaptPfibExternalOutputFlow(Routers routers, String routerName, BigInteger dpnId) {
+        Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+
+        String ip = getExternalIpFromRouter(routers);
+        Uuid subnetId = getSubnetIdOfIp(ip);
+
+        if (subnetId != null) {
+            FlowEntity postNaptFlowEntity = buildNaptFibExternalOutputFlowEntity(dpnId, routerId, subnetId, ip);
+            mdsalManager.installFlow(postNaptFlowEntity);
+        }
+    }
+
+    private Uuid getSubnetIdOfIp(String ip) {
+        if (ip != null) {
+            IpAddress externalIpv4Address = new IpAddress(new Ipv4Address(ip));
+            Port port = NatUtil.getNeutronPortForRouterGetewayIp(dataBroker, externalIpv4Address);
+            Uuid subnetId = NatUtil.getSubnetIdForFloatingIp(port, externalIpv4Address);
+            return subnetId;
+        }
+        return null;
+    }
+
+    private String getExternalIpFromRouter(Routers routers) {
+        List<String> extIps = routers.getExternalIps();
+        if (extIps != null && !extIps.isEmpty()) {
+            return extIps.get(0);
+        }
+        return null;
+    }
+
     private void subnetRegisterMapping(Routers routerEntry,Long segmentId) {
         List<Uuid> subnetList = null;
         List<String> externalIps = null;
@@ -535,6 +570,12 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                 append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID).toString();
     }
 
+    private String getFlowRefNaptFib(BigInteger dpnId, short tableId, long routerID, String externalIp) {
+        return new StringBuilder().append(NatConstants.NAPT_FLOWID_PREFIX).append(dpnId).append(NatConstants.FLOWID_SEPARATOR).
+                append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID).
+                append(NatConstants.FLOWID_SEPARATOR).append(externalIp).toString();
+    }
+
     public BigInteger getCookieOutboundFlow(long routerId) {
         return NwConstants.COOKIE_OUTBOUND_NAPT_TABLE.add(new BigInteger("0110001", 16)).add(
                 BigInteger.valueOf(routerId));
@@ -1398,7 +1439,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                 LOG.error("NAT Service : Unable to retrieve the primary NAPT switch for the router ID {} from RouterNaptSwitch model", routerId);
                 return;
             }
-            removeNaptFlowsFromActiveSwitch(routerId, routerName, naptSwitchDpnId, networkUuid, vpnId );
+            removeNaptFlowsFromActiveSwitch(routerId, routerName, naptSwitchDpnId, networkUuid, vpnId, externalIps);
             removeFlowsFromNonActiveSwitches(routerName, naptSwitchDpnId, networkUuid);
             try {
                 clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, vpnId);
@@ -1469,7 +1510,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
     }
 
-     public void removeNaptFlowsFromActiveSwitch(long routerId, String routerName, BigInteger dpnId, Uuid networkId, String vpnName){
+     public void removeNaptFlowsFromActiveSwitch(long routerId, String routerName, BigInteger dpnId, Uuid networkId, String vpnName, List<String> externalIps){
 
         LOG.debug("NAT Service : Remove NAPT flows from Active switch");
         BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
@@ -1497,6 +1538,8 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         LOG.info("NAT Service : Remove the flow in the " + NwConstants.OUTBOUND_NAPT_TABLE + " for the active switch with the DPN ID {} and router ID {}", dpnId, routerId);
         mdsalManager.removeFlow(outboundNatFlowEntity);
 
+        removeNaptFibExternalOutputFlows(routerId, dpnId, externalIps);
+
         //Remove the NAPT PFIB TABLE which forwards the incoming packet to FIB Table matching on the router ID.
         String natPfibFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId);
         FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibFlowRef);
@@ -1571,6 +1614,22 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         }
     }
 
+    private void removeNaptFibExternalOutputFlows(long routerId, BigInteger dpnId, List<String> externalIps) {
+        for (String ip : externalIps) {
+            String extIp = removeMaskFromIp(ip);
+            String postNaptFlowRef = getFlowRefNaptFib(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId, extIp);
+            LOG.info("NAT Service : Remove the flow in the " + NwConstants.NAPT_PFIB_TABLE + " for the active switch with the DPN ID {} and router ID {} and IP {}", dpnId, routerId, extIp);
+            mdsalManager.removeFlow(NatUtil.buildFlowEntity(dpnId,NwConstants.NAPT_PFIB_TABLE, postNaptFlowRef));
+        }
+    }
+
+    private String removeMaskFromIp(String ip) {
+        if (ip != null && !ip.trim().isEmpty()) {
+            return ip.split("/")[0];
+        }
+        return ip;
+    }
+
      public void removeNaptFlowsFromActiveSwitchInternetVpn(long routerId, String routerName, BigInteger dpnId, Uuid networkId, String vpnName){
 
          LOG.debug("NAT Service : Remove NAPT flows from Active switch Internet Vpn");
@@ -1972,9 +2031,13 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         }
         return false;
     }
-
     public void installFlowsWithUpdatedVpnId(BigInteger primarySwitchId, String routerName, long bgpVpnId, long
             routerId, boolean isSnatCfgd){
+        installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, routerId, isSnatCfgd, null);
+    }
+
+    public void installFlowsWithUpdatedVpnId(BigInteger primarySwitchId, String routerName, long bgpVpnId, long
+            routerId, boolean isSnatCfgd, Routers router){
         long changedVpnId = bgpVpnId;
         String logMsg = "NAT Service : Update the BGP VPN ID {}";
         if (bgpVpnId == NatConstants.INVALID_ID){
@@ -2187,6 +2250,33 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         return flowEntity;
     }
 
+    protected FlowEntity buildNaptFibExternalOutputFlowEntity(BigInteger dpId, long routerId, Uuid subnetId, String externalIp) {
+        LOG.debug("NAT Service : buildPostSnatFlowEntity called for dpId {}, routerId {}, srcIp {}", dpId, routerId,
+                externalIp);
+
+        List<MatchInfo> matches = new ArrayList<>();
+        matches.add(new MatchInfo(MatchFieldType.eth_type, new long[] { NwConstants.ETHTYPE_IPV4 }));
+        matches.add(new MatchInfo(MatchFieldType.metadata,
+                new BigInteger[] { MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID }));
+        matches.add(new MatchInfo(MatchFieldType.ipv4_source, new String[] { externalIp , "32" }));
+
+        List<InstructionInfo> instructions = new ArrayList<>();
+        List<ActionInfo> actionsInfos = new ArrayList<>();
+        instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
+        instructions.add(new InstructionInfo(InstructionType.write_metadata,
+                new BigInteger[] { MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID }));
+
+        long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(subnetId.getValue()), idManager);
+        actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
+
+        String flowRef = getFlowRefNaptFib(dpId, NwConstants.NAPT_PFIB_TABLE, routerId, externalIp);
+        BigInteger cookie = getCookieOutboundFlow(routerId);
+        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.NAPT_PFIB_TABLE, flowRef, 6, flowRef, 0,
+                0, cookie, matches, instructions);
+        LOG.debug("NAT Service : returning flowEntity {}", flowEntity);
+        return flowEntity;
+    }
+
     public void installNaptPfibEntryWithBgpVpn(BigInteger dpnId, long segmentId, long changedVpnId) {
         LOG.debug("NAT Service : installNaptPfibEntryWithBgpVpn called for dpnId {} and segmentId {} ,BGP VPN ID {}", dpnId, segmentId, changedVpnId);
         FlowEntity naptPfibFlowEntity = buildNaptPfibFlowEntityWithUpdatedVpnId(dpnId, segmentId, changedVpnId);
index f2168f2f1d9056d994595344956fe58be2d35685..242910ea22a67e166c835107005cdd4ebc315c35 100644 (file)
@@ -1088,6 +1088,16 @@ public class NatUtil {
 
     public static Port getNeutronPortForFloatingIp(DataBroker broker,
             org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress targetIP) {
+      return getNeutronPortForIp(broker, targetIP, NeutronConstants.DEVICE_OWNER_FLOATING_IP);
+    }
+
+    public static Port getNeutronPortForRouterGetewayIp(DataBroker broker,
+            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress targetIP) {
+      return getNeutronPortForIp(broker, targetIP, NeutronConstants.DEVICE_OWNER_GATEWAY_INF);
+    }
+
+    public static Port getNeutronPortForIp(DataBroker broker,
+            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress targetIP, String deviceType) {
         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports>
         portsIdentifier = InstanceIdentifier
                 .create(Neutron.class)
@@ -1100,7 +1110,7 @@ public class NatUtil {
         }
 
         for (Port port : portsOptional.get().getPort()) {
-            if (NeutronConstants.DEVICE_OWNER_FLOATING_IP.equals(port.getDeviceOwner()) && port.getFixedIps() != null) {
+            if (deviceType.equals(port.getDeviceOwner()) && port.getFixedIps() != null) {
                 for (FixedIps ip : port.getFixedIps()) {
                     if (Objects.equals(ip.getIpAddress(), targetIP)) {
                         return port;
index 98d458f8fa87a1105984289e8ba19966b25c175c..5ecd1fd7208419baa6ce53d5412f9223ed4346ca 100644 (file)
@@ -296,6 +296,8 @@ public class NeutronvpnNatManager implements AutoCloseable {
             rtrList.add(routerId);
             builder.setRouterIds(rtrList);
 
+            builder.setVpnid(routerId);
+
             Networks networkss = builder.build();
             // Add Networks object to the ExternalNetworks list
             //isLockAcquired = NeutronvpnUtils.lock(lockManager, extNetId.getValue());