VLAN support for external networks 94/32094/10
authorTomas Cechvala <tcechval@cisco.com>
Mon, 21 Dec 2015 15:42:09 +0000 (16:42 +0100)
committerTomas Cechvala <tcechval@cisco.com>
Thu, 14 Jan 2016 16:47:26 +0000 (16:47 +0000)
 - tagging is applied on external ports of switches
 - link connected to external port is considered as trunk port
 - native VLAN not supported yet
 - mapping VLANs from Openstack not in scope here

Change-Id: Iaeeaa4d7966d49f2c7179ba22a9cc5972fd33b0a
Signed-off-by: Tomas Cechvala <tcechval@cisco.com>
14 files changed:
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/dto/IndexedTenant.java
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/endpoint/EndpointManager.java
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/ExternalMapper.java
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/FlowUtils.java
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/GroupTable.java
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/IngressNatMapper.java
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/PortSecurity.java
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/node/SwitchManager.java
renderers/ofoverlay/src/main/yang/ofoverlay.yang
renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/endpoint/MockEndpointManager.java
renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/ExternalMapperTest.java
renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/GroupTableTest.java
renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/OfTableTest.java
renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/PortSecurityTest.java

index 920c959cb140c0d261085566a692eae795ca2974..379c013c26599366932d5ae9f44624b2aa27968e 100644 (file)
@@ -237,7 +237,7 @@ public class IndexedTenant {
      */
     public Collection<Subnet> resolveSubnets(NetworkDomainId id) {
         Set<SubnetId> sset = new HashSet<>();
-        HashSet<NetworkDomainId> visited = new HashSet<>();        
+        HashSet<NetworkDomainId> visited = new HashSet<>();
         while (id != null) {
             if (visited.contains(id)) break;
             visited.add(id);
index 6fa78a52419e5405a66f7b4cc9335b603d70ec54..de7f63959b16f9bf743f6fb214c597d1df4ff6dc 100644 (file)
@@ -54,6 +54,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Prefix;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.l3endpoint.rev151217.NatAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.l3endpoint.rev151217.NatAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayConfig;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContextBuilder;
@@ -605,6 +606,8 @@ public class EndpointManager implements AutoCloseable {
      *
      * @return the
      *         {@link org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3}
+     * @return {@link Collection} of the {@link EndpointL3}.
+     *   Empty {@link Collection} if no {@link EndpointL3} is found.
      */
     protected Collection<EndpointL3> getL3Endpoints() {
         Endpoints endpoints = getEndpointsFromDataStore();
index 03e37a0e5e3959966f7c3b893bf3ee7907087259..a89d9de8edc4cfca11ed2e3d750b94a815a6f6e3 100755 (executable)
@@ -8,19 +8,45 @@
 
 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
 
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxRegMatch;
 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.applyActionIns;
 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.instructions;
 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxOutputRegAction;
 
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.opendaylight.groupbasedpolicy.dto.IndexedTenant;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.RegMatch;
+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.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
 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.flow.Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.l3endpoint.rev151217.NatAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.Segmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2FloodDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.Subnet;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg7;
+import org.apache.commons.net.util.SubnetUtils;
+import org.apache.commons.net.util.SubnetUtils.SubnetInfo;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Preconditions;
+
 /**
  * Manage the table that assigns source endpoint group, bridge domain, and
  * router domain to registers to be used by other tables.
@@ -44,19 +70,151 @@ public class ExternalMapper extends FlowTable {
     @Override
     public void sync(NodeId nodeId, OfWriter ofWriter) throws Exception {
 
-        if (ctx.getSwitchManager().getExternalPorts(nodeId) == null) {
+        if (ctx.getSwitchManager().getExternalPorts(nodeId).isEmpty()) {
             LOG.trace("No external ports found for node: {}", nodeId);
             return;
         }
         // Default drop all
         ofWriter.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(1), null, TABLE_ID));
 
+        /*
+         * When source address was translated to NAT address, it has to be figured out
+         * whether or not the traffic should be tagged since external interfaces are
+         * considered as trunk ports.
+         *
+         * Subnet to which NAT address belong have to be found so that
+         * corresponding L2FloodDomain can be resolved.
+         *
+         * If the L2FloodDomain contains Segmentation augmentation, a Flow is generated
+         * for applying VLAN tag against traffic with NAT IP as source address.
+         *
+         * Note: NetworkContainment of NAT EndpointL3 point's to subnet of original address.
+         * This is why subnet of NAT IP is resolved here.
+         */
+        Collection<EndpointL3> natL3Endpoints = ctx.getEndpointManager().getL3EndpointsWithNat();
+        if (natL3Endpoints != null) {
+            for (EndpointL3 natL3Ep : natL3Endpoints) {
+                IpAddress natIpAddress = Preconditions.checkNotNull(natL3Ep.getAugmentation(NatAddress.class),
+                        "NAT address augmentation is missing for NAT endpoint: [{}].", natL3Ep.getKey())
+                    .getNatAddress();
+                L2FloodDomain natEpl2Fd = resolveL2FloodDomainForIpv4Address(ctx.getTenant(natL3Ep.getTenant()),
+                        Preconditions.checkNotNull(natIpAddress.getIpv4Address(),
+                                "Endpoint {} does not have IPv4 address in NatAddress augmentation.", natL3Ep.getKey()));
+                if (natEpl2Fd != null && natEpl2Fd.getAugmentation(Segmentation.class) != null) {
+                    Integer vlanId = natEpl2Fd.getAugmentation(Segmentation.class).getSegmentationId();
+                    ofWriter.writeFlow(nodeId, TABLE_ID, buildPushVlanFlow(natIpAddress.getIpv4Address(), vlanId, 222));
+                }
+            }
+        }
+
+        /*
+         * Tagging should be also considered when traffic is routed or switched to external domain.
+         *
+         * If the L2FloodDomain of Endpoint contains Segmentation augmentation, a Flow
+         * for applying VLAN tag is generated. The flow matches against REG5 holding
+         * the L2FloodDomain and REG7 holding value of an external interface.
+         */
+        for (Endpoint ep : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
+            L2FloodDomain l2Fd = ctx.getTenant(ep.getTenant()).resolveL2FloodDomain(ep.getNetworkContainment());
+            Segmentation segmentation = l2Fd.getAugmentation(Segmentation.class);
+            if (segmentation == null) {
+                continue;
+            }
+            Integer vlanId = segmentation.getSegmentationId();
+            for (Flow flow : buildPushVlanFlow(nodeId, OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, ep).getFdId(),
+                    vlanId, 220)) {
+                ofWriter.writeFlow(nodeId, TABLE_ID, flow);
+            }
+        }
+
         /*
          *  Default Egress flow. Other methods may write to this table to augment egress
          *  functionality, such as bypassing/utilising the NAT table, or ServiceFunctionChaining
          */
         ofWriter.writeFlow(nodeId, TABLE_ID, defaultFlow());
+    }
 
+    static L2FloodDomain resolveL2FloodDomainForIpv4Address(IndexedTenant t, Ipv4Address ipv4Addr) {
+        Preconditions.checkNotNull(ipv4Addr);
+        if (t == null || t.getTenant() == null || t.getTenant().getForwardingContext() == null) {
+            return null;
+        }
+        List<Subnet> subnets = t.getTenant().getForwardingContext().getSubnet();
+        if (subnets != null) {
+            for (Subnet subnet : subnets) {
+                if (belongsToSubnet(ipv4Addr, subnet.getIpPrefix().getIpv4Prefix())) {
+                    return t.resolveL2FloodDomain(subnet.getParent());
+                }
+            }
+        }
+        LOG.warn(
+                "No subnet for IPv4 address {} found in tenant {}!",
+                ipv4Addr.getValue(), t.getTenant().getId());
+        return null;
+    }
+
+    static boolean belongsToSubnet(Ipv4Address ipv4Address, Ipv4Prefix subnetPrefix) {
+        SubnetUtils su = new SubnetUtils(subnetPrefix.getValue());
+        SubnetInfo si = su.getInfo();
+        return si.isInRange(ipv4Address.getValue());
+    }
+
+    /**
+     * Generates a {@link Flow} for tagging VLAN traffic based on given arguments.
+     *
+     * @param ipv4Address source IPv4 address
+     * @param vlanId ID of VLAN tag to apply
+     * @param priority priority of the flow in the table
+     * @return {@link Flow} matching IPv4 source address, IPv4 ether-type and VLAN not set.
+     */
+    private Flow buildPushVlanFlow(Ipv4Address ipv4Address, Integer vlanId, int priority) {
+        // It is not needed here to match against external interfaces because
+        // we only use NAT when going to external networks.
+        Ipv4Prefix natIp = new Ipv4Prefix(ipv4Address.getValue() + "/32");
+        Match match = new MatchBuilder()
+            .setEthernetMatch(FlowUtils.ethernetMatch(null, null, Long.valueOf(FlowUtils.IPv4)))
+            .setLayer3Match(new Ipv4MatchBuilder().setIpv4Source(natIp).build())
+            .setVlanMatch(FlowUtils.vlanMatch(0, false))
+            .build();
+        List<ActionBuilder> pushVlanActions = new ArrayList<>();
+        pushVlanActions.addAll(FlowUtils.pushVlanActions(vlanId));
+        pushVlanActions.add(new ActionBuilder().setOrder(0).setAction(nxOutputRegAction(NxmNxReg7.class)));
+        FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "external_nat_push_vlan", match);
+        return base().setPriority(priority)
+            .setId(flowid)
+            .setMatch(match)
+            .setInstructions(FlowUtils.instructions(applyActionIns(pushVlanActions)))
+            .build();
+    }
+
+    /**
+     * Generates a {@link Flow} for tagging VLAN traffic based on given arguments.
+     *
+     * @param nodeId of {@link Node} from which external interfaces are resolved
+     * @param fdId {@link L2FloodDomain} ordinal to match against
+     * @param vlanId applied to the traffic
+     * @param priority of flow in the table
+     * @return {@link List} of {@link Flow} matching {@link L2FloodDomain} in REG5,
+     * external interfaces of {@link Node} in REG7 and VLAN not set.
+     */
+    private List<Flow> buildPushVlanFlow(NodeId nodeId, int fdId, Integer vlanId, int priority) {
+        List<Flow> flows = new ArrayList<>();
+        for (Long portNum : ctx.getSwitchManager().getExternalPortNumbers(nodeId)) {
+            MatchBuilder mb = new MatchBuilder().setVlanMatch(FlowUtils.vlanMatch(0, false));
+            addNxRegMatch(mb, RegMatch.of(NxmNxReg7.class, BigInteger.valueOf(portNum).longValue()),
+                    RegMatch.of(NxmNxReg5.class, Long.valueOf(fdId)));
+            Match match = mb.build();
+            List<ActionBuilder> pushVlanActions = new ArrayList<>();
+            pushVlanActions.addAll(FlowUtils.pushVlanActions(vlanId));
+            pushVlanActions.add(new ActionBuilder().setOrder(0).setAction(nxOutputRegAction(NxmNxReg7.class)));
+            FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "external_push_vlan", match);
+            flows.add(base().setPriority(priority)
+                .setId(flowid)
+                .setMatch(match)
+                .setInstructions(FlowUtils.instructions(applyActionIns(pushVlanActions)))
+                .build());
+        }
+        return flows;
     }
 
     private Flow defaultFlow() {
index 3ca1ee9b69c4fe1c70d294c1b30d2717dc276f4b..3279cebdc27b9777cda9c45276af61efdd79418f 100755 (executable)
@@ -23,18 +23,24 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.acti
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.DropActionCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PopVlanActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetDlDstActionCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetDlSrcActionCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetNwDstActionCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetNwSrcActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetVlanIdActionCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.dec.nw.ttl._case.DecNwTtlBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.drop.action._case.DropActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.group.action._case.GroupActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.output.action._case.OutputActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.pop.vlan.action._case.PopVlanActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.push.vlan.action._case.PushVlanActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.dl.dst.action._case.SetDlDstActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.dl.src.action._case.SetDlSrcActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.nw.dst.action._case.SetNwDstActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.nw.src.action._case.SetNwSrcActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.vlan.id.action._case.SetVlanIdActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.address.address.Ipv4Builder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.address.address.Ipv6Builder;
@@ -68,11 +74,15 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetDestinationBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetSourceBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetTypeBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatch;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
@@ -186,6 +196,10 @@ public final class FlowUtils {
      * IPv6 ethertype
      */
     public static final Long IPv6 = Long.valueOf(0x86DD);
+    /**
+     * VLAN ethertype
+     */
+    public static final Integer VLAN = Integer.valueOf(0x8100);
 
     /**
      * Creates an Instance Identifier (path) for node with specified id
@@ -358,6 +372,29 @@ public final class FlowUtils {
             .build();
     }
 
+    public static VlanMatch vlanMatch(int vlanId, boolean vlanIdPresent) {
+    return new VlanMatchBuilder().setVlanId(
+            new VlanIdBuilder().setVlanId(new VlanId(vlanId)).setVlanIdPresent(vlanIdPresent).build()).build();
+    }
+
+    public static List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder> pushVlanActions(int vlanId) {
+        List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder> actions = new ArrayList<>();
+        actions.add(new ActionBuilder().setAction(pushVlanAction()).setOrder(0));
+        actions.add(new ActionBuilder().setAction(setVlanId(vlanId)).setOrder(1));
+        return actions;
+    }
+
+    public static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction popVlanInstruction(
+            int order) {
+        List<ActionBuilder> actionBuilders = new ArrayList<>();
+        actionBuilders.add(new ActionBuilder().setAction(popVlanAction()).setOrder(0));
+        return new InstructionBuilder().setInstruction(
+                new ApplyActionsCaseBuilder().setApplyActions(
+                        new ApplyActionsBuilder().setAction(actionList(actionBuilders)).build()).build())
+            .setOrder(order)
+            .build();
+    }
+
     public static Action setIpv4DstAction(Ipv4Address ipAddress) {
         Ipv4Builder ipDest = new Ipv4Builder();
         Ipv4Prefix prefixdst = new Ipv4Prefix(new Ipv4Prefix(ipAddress.getValue() + "/32"));
@@ -663,6 +700,20 @@ public final class FlowUtils {
         return emb.build();
     }
 
+    private static Action pushVlanAction() {
+        return new PushVlanActionCaseBuilder().setPushVlanAction(
+                new PushVlanActionBuilder().setEthernetType(VLAN).build()).build();
+    }
+
+    private static Action popVlanAction() {
+        return new PopVlanActionCaseBuilder().setPopVlanAction(new PopVlanActionBuilder().build()).build();
+    }
+
+    private static Action setVlanId(int vlanId) {
+        return new SetVlanIdActionCaseBuilder().setSetVlanIdAction(
+                new SetVlanIdActionBuilder().setVlanId(new VlanId(vlanId)).build()).build();
+    }
+
     private static List<ExtensionList> getExistingGeneralAugMatchNodesNodeTableFlow(MatchBuilder match) {
         ArrayList<ExtensionList> extensions = new ArrayList<>();
         if (match.getAugmentation(GeneralAugMatchNodesNodeTableFlow.class) != null) {
index bad5418cb02331f7321b588f0dccba3b17ccc88d..8547683d75463be47f8336f7d0abc610e8f0955d 100644 (file)
@@ -14,10 +14,13 @@ import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtil
 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIPv4Action;
 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.outputAction;
 
+import java.util.ArrayList;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
 
+import org.antlr.v4.runtime.misc.Array2DHashSet;
 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.groupbasedpolicy.dto.EgKey;
@@ -27,12 +30,15 @@ import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.endpoint.EndpointMan
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.BucketId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.Segmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2FloodDomain;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
@@ -85,7 +91,7 @@ public class GroupTable extends OfTable {
             EndpointFwdCtxOrdinals localEpFwdCtxOrds =
                     OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, localEp);
             if (localEpFwdCtxOrds == null) {
-                LOG.debug("getEndpointFwdCtxOrdinals is null for EP {}", localEp);
+                LOG.info("getEndpointFwdCtxOrdinals is null for EP {}", localEp);
                 continue;
             }
 
@@ -125,6 +131,7 @@ public class GroupTable extends OfTable {
                         ofWriter.writeBucket(nodeId, gid, bb.build());
                     }
                 }
+                // TODO broadcasts are not separated by EPG between endpoints on the same node
                 OfOverlayContext ofc = localEp.getAugmentation(OfOverlayContext.class);
                 if (EndpointManager.isExternal(localEp, ctx.getTenant(localEp.getTenant()).getExternalImplicitGroups()))
                     continue;
@@ -136,11 +143,44 @@ public class GroupTable extends OfTable {
                     LOG.warn("Could not parse port number {}", ofc.getNodeConnectorId(), e);
                     continue;
                 }
-
                 Action output = outputAction(ofc.getNodeConnectorId());
-                BucketBuilder bb = new BucketBuilder().setBucketId(new BucketId(Long.valueOf(bucketId)))
-                        .setAction(actionList(output));
+                BucketBuilder bb = new BucketBuilder().setBucketId(new BucketId(Long.valueOf(bucketId))).setAction(
+                        FlowUtils.actionList(output));
                 ofWriter.writeBucket(nodeId, gid, bb.build());
+
+                // if boradcast exceeds internal domain
+                for (Endpoint extEp : ctx.getEndpointManager().getExtEpsNoLocForGroup(epg)) {
+                    if (extEp.getNetworkContainment() != null
+                            && extEp.getNetworkContainment().equals(localEp.getNetworkContainment())) {
+                        L2FloodDomain l2Fd = ctx.getTenant(extEp.getTenant()).resolveL2FloodDomain(
+                                extEp.getNetworkContainment());
+                        if (l2Fd != null) {
+                            Segmentation segmentation = l2Fd.getAugmentation(Segmentation.class);
+                            // external endpoints do not have location augmentation
+                            // however they are beyond external ports
+                            for (NodeConnectorId extNcId : ctx.getSwitchManager().getExternalPorts(nodeId)) {
+                                try {
+                                    bucketId = getOfPortNum(extNcId);
+                                } catch (NumberFormatException e) {
+                                    LOG.warn("Could not parse external port number {}", extNcId, e);
+                                    continue;
+                                }
+                                ArrayList<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder>
+                                    actionList = new ArrayList<>();
+                                if (segmentation != null) {
+                                    Integer vlanId = segmentation.getSegmentationId();
+                                    actionList.addAll(FlowUtils.pushVlanActions(vlanId));
+                                    actionList.add(new ActionBuilder().setOrder(2).setAction(outputAction(extNcId)));
+                                } else {
+                                    actionList.add(new ActionBuilder().setOrder(0).setAction(outputAction(extNcId)));
+                                }
+                                bb.setBucketId(new BucketId(Long.valueOf(bucketId))).setAction(
+                                        FlowUtils.actionList(actionList));
+                                ofWriter.writeBucket(nodeId, gid, bb.build());
+                            }
+                        }
+                    }
+                }
             }
         }
     }
index 0c29b27759cb17eb383b8e6cd8b96116f949a839..f92198e074f22806778954a434a514d41baff2d0 100755 (executable)
@@ -42,6 +42,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.acti
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
@@ -84,7 +85,20 @@ public class IngressNatMapper extends FlowTable {
     @Override
     public void sync(NodeId nodeId, OfWriter ofWriter) throws Exception {
 
-        ofWriter.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(1), null, TABLE_ID));
+        // TODO for consideration: default instruction is goto next table because when matching against eth type 0x8100
+        // in PortSecurity, it's not possible to match against IPv4 addresses (only inf eth type would be 0x800)
+        // We can't determine just from L2 layer if traffic should be passed from PortSecurity here to IngressNat or to
+        // SourceMapper. Various 802.1q encapsulated IPs can pass through external ports - NATed or not NATed, remote
+        // or directly connected.
+        // All external ingress traffic is currently passed here and if no match is foud - no NAT is performed
+        // and processing continues in SourceMapper.
+        Flow flow = base()
+                .setTableId(TABLE_ID)
+                .setPriority(1)
+                .setInstructions(FlowUtils.instructions(FlowUtils.gotoTableIns(ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER())))
+                .setId(FlowIdUtils.newFlowId("gotoSourceMapper"))
+                .build();
+        ofWriter.writeFlow(nodeId, TABLE_ID, flow);
 
         // TODO Bug 3546 - Difficult: External port is unrelated to Tenant, L3C, L2BD..
 
index 0e188f79d1df8d9ca075bc7fa9e47c1750e94248..8c3ee06777f1efd9aa57476b08afbcd33e94e0e7 100755 (executable)
@@ -10,6 +10,8 @@ package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
 
 import java.util.Collections;
 import java.util.List;
+import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.Set;
 
 import org.opendaylight.groupbasedpolicy.dto.IndexedTenant;
@@ -21,13 +23,21 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.go.to.table._case.GoToTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
+
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.ExternalImplicitGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.Segmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2FloodDomain;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
@@ -66,15 +76,6 @@ public class PortSecurity extends FlowTable {
         if (tunnelIf != null)
             ofWriter.writeFlow(nodeId, TABLE_ID, allowFromPort(tunnelIf));
 
-        // Allow traffic from tunnel ports
-        //TODO Bug 3546 - Difficult: External port is unrelated to Tenant, L3C, L2BD..
-
-        Set<NodeConnectorId> external =
-                ctx.getSwitchManager().getExternalPorts(nodeId);
-        for (NodeConnectorId extIf : external) {
-            ofWriter.writeFlow(nodeId, TABLE_ID, allowFromExternalPort(extIf));
-        }
-
         // Default drop all
         ofWriter.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(1), null, TABLE_ID));
 
@@ -83,6 +84,7 @@ public class PortSecurity extends FlowTable {
         ofWriter.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(111), FlowUtils.IPv4, TABLE_ID));
         ofWriter.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(112), FlowUtils.IPv6, TABLE_ID));
 
+        Set<TenantId> tenantIds = new HashSet<>();
         for (Endpoint ep : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
             OfOverlayContext ofc = ep.getAugmentation(OfOverlayContext.class);
             if (ofc == null || ofc.getNodeConnectorId() == null) {
@@ -91,6 +93,7 @@ public class PortSecurity extends FlowTable {
                 continue;
             }
 
+            tenantIds.add(ep.getTenant());
             Set<ExternalImplicitGroup> eigs = getExternalImplicitGroupsForTenant(ep.getTenant());
             if (EndpointManager.isInternal(ep, eigs)) {
                 // Allow layer 3 traffic (ARP and IP) with the correct
@@ -108,6 +111,18 @@ public class PortSecurity extends FlowTable {
                 }
             }
         }
+
+        for (TenantId tenantId : tenantIds) {
+            for (NodeConnectorId nc : ctx.getSwitchManager().getExternalPorts(nodeId)) {
+                // TODO Bug 3546 - Difficult: External port is unrelated to Tenant, L3C, L2BD..
+                for (Flow flow : popVlanTagsOnExternalPort(nc, tenantId, 210)) {
+                    // tagged frames have to be untagged when entering policy domain
+                    ofWriter.writeFlow(nodeId, TABLE_ID, flow);
+                }
+                // allowing untagged frames entering policy domain
+                ofWriter.writeFlow(nodeId, TABLE_ID, allowFromExternalPort(nc, 200));
+            }
+        }
     }
 
     private Set<ExternalImplicitGroup> getExternalImplicitGroupsForTenant(TenantId tenantId) {
@@ -125,25 +140,12 @@ public class PortSecurity extends FlowTable {
         FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "allow", match);
         FlowBuilder flowb = base()
                 .setId(flowid)
-                .setPriority(Integer.valueOf(200))
+                .setPriority(Integer.valueOf(300))
                 .setMatch(match)
                 .setInstructions(FlowUtils.gotoTableInstructions(ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER()));
         return flowb.build();
     }
 
-    private Flow allowFromExternalPort(NodeConnectorId port) {
-        Match match = new MatchBuilder()
-                .setInPort(port)
-                .build();
-        FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "allowExternal", match);
-        FlowBuilder flowb = base()
-                .setId(flowid)
-                .setPriority(Integer.valueOf(200))
-                .setMatch(match)
-                .setInstructions(FlowUtils.gotoTableInstructions(ctx.getPolicyManager().getTABLEID_INGRESS_NAT()));
-        return flowb.build();
-    }
-
     private Flow l2flow(Endpoint ep, OfOverlayContext ofc, Integer priority) {
         Match match = new MatchBuilder()
                 .setEthernetMatch(
@@ -183,7 +185,6 @@ public class PortSecurity extends FlowTable {
                 .setMatch(match)
                 .setInstructions(FlowUtils.gotoTableInstructions(ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER()))
                 .build();
-
         return flow;
     }
 
@@ -241,4 +242,54 @@ public class PortSecurity extends FlowTable {
             ofWriter.writeFlow(nodeId, TABLE_ID,flow);
         }
     }
+
+    private Flow allowFromExternalPort(NodeConnectorId nc, Integer priority) {
+        Match match = new MatchBuilder().setInPort(nc).build();
+        FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "allowExternal", match);
+        FlowBuilder flowb = base().setId(flowid)
+            .setPriority(Integer.valueOf(priority))
+            .setMatch(match)
+            .setInstructions(FlowUtils.gotoTableInstructions(ctx.getPolicyManager().getTABLEID_INGRESS_NAT()));
+        return flowb.build();
+    }
+
+    /**
+     * Pops VLAN tag for inbound traffic.
+     *
+     * @param nc should be external for now
+     * @param tenantId of {@link Tenant} from which {@link L2FloodDomain}s are read from which VLAN IDs are resolved.
+     * @param priority of flows in the table
+     * @return {@link Flow}s which match on ingress port, and VLAN ID to pop.
+     *         {@link GoToTable} Instructions are set to INGRESS NAT table.
+     */
+    private List<Flow> popVlanTagsOnExternalPort(NodeConnectorId nc, TenantId tenantId, Integer priority) {
+        List<Flow> flows = new ArrayList<>();
+        for(L2FloodDomain l2Fd : ctx.getTenant(tenantId).getTenant().getForwardingContext().getL2FloodDomain()) {
+        Segmentation segmentation = l2Fd.getAugmentation(Segmentation.class);
+            if (segmentation != null) {
+                Integer vlanId = segmentation.getSegmentationId();
+                flows.add(buildPopVlanFlow(nc, vlanId, priority));
+            }
+        }
+        return flows;
+    }
+
+    private Flow buildPopVlanFlow(NodeConnectorId nc, Integer vlanId, int priority) {
+        Match match = new MatchBuilder()
+            .setVlanMatch(FlowUtils.vlanMatch(vlanId, true))
+            .setInPort(nc)
+            .build();
+        List<Instruction> instructions = new ArrayList<>();
+        instructions.add(FlowUtils.popVlanInstruction(0));
+        instructions.add(new InstructionBuilder().setOrder(1)
+             // TODO for now matches on external flows are passed to ingress nat table
+            .setInstruction(FlowUtils.gotoTableIns(ctx.getPolicyManager().getTABLEID_INGRESS_NAT()))
+            .build());
+        FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "allowExternalPopVlan", match);
+        return base().setPriority(priority)
+            .setId(flowid)
+            .setMatch(match)
+            .setInstructions(new InstructionsBuilder().setInstruction(instructions).build())
+            .build();
+    }
 }
index 17bb24b16f8ab3d4556b47710e9c08151293d76d..bcccf7c5224d0d5cad2cf782ae98e0166d717172 100644 (file)
@@ -9,6 +9,7 @@
 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.getOfPortNum;
 
 import java.util.Collection;
 import java.util.Collections;
@@ -22,6 +23,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
 
 import javax.annotation.Nullable;
 
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchListener;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
@@ -142,6 +144,21 @@ public class SwitchManager implements AutoCloseable {
         return ImmutableSet.copyOf(state.externalPorts);
     }
 
+    public Set<Long> getExternalPortNumbers(NodeId nodeId) {
+        Set<Long> extPortNumbers = new HashSet<>();
+        for(NodeConnectorId nc : getExternalPorts(nodeId)) {
+            long portNum;
+            try {
+                portNum = getOfPortNum(nc);
+            } catch (NumberFormatException ex) {
+                LOG.warn("Could not parse port number {}", nc, ex);
+                return null;
+            }
+            extPortNumbers.add(portNum);
+        }
+        return extPortNumbers;
+    }
+
     public synchronized Collection<NodeConnectorId> getTunnelPorts(NodeId nodeId) {
         Collection<NodeConnectorId> ncIds = new HashSet<>();
         SwitchState state = switches.get(nodeId);
index 5315e94938f160472d029215d1a95c998d92540e..52b06e5aebeb3886b75fb7af80efedd3480f6a81 100644 (file)
@@ -20,6 +20,7 @@ module ofoverlay {
 
     import gbp-common {prefix gbp-common;}
     import endpoint {prefix endpoint;}
+    import policy {prefix policy;}
 
     description
         "This module defines the group-based policy ofoverlay renderer model.";
@@ -121,6 +122,16 @@ module ofoverlay {
         uses endpoint-location;
     }
 
+    augment "/policy:tenants/policy:tenant/policy:forwarding-context/policy:l2-flood-domain" {
+        ext:augment-identifier "segmentation";
+        leaf segmentation-id {
+            description "Logical segmentation of an l2-flood-domain, e.g. by using VLANs.";
+            type uint16 {
+                range "1 .. 4095";
+            }
+        }
+    }
+
     augment "/inv:nodes/inv:node" {
         ext:augment-identifier "of-overlay-node-config";
         list tunnel {
index 9dbaefdd5e8dded2cfbebdfa1b203cff10b80660..7203ec8c0c6ea9866814975d5b856e62bc45debc 100644 (file)
@@ -8,7 +8,13 @@
 
 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.endpoint;
 
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Key;
 
 /**
  * Class for mocking up endpoints for unit tests
@@ -16,6 +22,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.r
  */
 public class MockEndpointManager extends EndpointManager {
 
+    private Map<EndpointL3Key, EndpointL3> endpointsL3 = new HashMap<>();
+
     public MockEndpointManager() {
         super(null, null, null, null, null);
     }
@@ -23,4 +31,13 @@ public class MockEndpointManager extends EndpointManager {
     public void addEndpoint(Endpoint ep) {
         processEndpoint(null, ep);
     }
+
+    public void addL3Endpoint(EndpointL3 l3Ep) {
+        endpointsL3.put(l3Ep.getKey(), l3Ep);
+    }
+
+    @Override
+    protected Collection<EndpointL3> getL3Endpoints() {
+        return endpointsL3.values();
+    }
 }
index 2656f06ed84e2b1bd076e287cc77ec5c7378bd7c..08497d036c9c2bf0818f0e90676b52934f317ad4 100755 (executable)
@@ -13,41 +13,61 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
 
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager;
+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.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.l3endpoint.rev151217.NatAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.l3endpoint.rev151217.NatAddressBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContextBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 
-public class ExternalMapperTest {
+import com.google.common.collect.ImmutableSet;
+
+public class ExternalMapperTest extends FlowTableTest {
 
     private ExternalMapper mapper;
 
-    private OfContext ctx;
     private short tableId;
     private NodeId nodeId;
     private OfWriter ofWriter;
-    private SwitchManager switchManager;
+
+    private NatAddress natAddr = new NatAddressBuilder()
+        .setNatAddress(new IpAddress(new Ipv4Address("192.168.111.52")))
+        .build();
+
+    private EndpointL3 natL3Ep = new EndpointL3Builder()
+        .setTenant(tid)
+        .setL3Context(l3c)
+        .setIpAddress(new IpAddress(new Ipv4Address("10.0.0.3")))
+        .addAugmentation(NatAddress.class, natAddr)
+        .build();
+
+    private Endpoint l2Ep = new EndpointBuilder()
+        .setTenant(tid)
+        .setMacAddress(new MacAddress("00:00:00:00:00:03"))
+        .setL2Context(bd)
+        .setNetworkContainment(sub)
+        .setEndpointGroup(eg)
+        .build();
 
     @Before
     public void initialisation() {
-        ctx = mock(OfContext.class);
-        tableId = 5;
+        initCtx();
+        tableId = 6;
         nodeId = mock(NodeId.class);
         ofWriter = mock(OfWriter.class);
-        switchManager = mock(SwitchManager.class);
-        when(ctx.getSwitchManager()).thenReturn(switchManager);
-
         mapper = new ExternalMapper(ctx, tableId);
     }
 
@@ -58,18 +78,21 @@ public class ExternalMapperTest {
 
     @Test
     public void syncTest() throws Exception {
-        NodeConnectorId nodeConnectorId = mock(NodeConnectorId.class);
-        Set<NodeConnectorId> externalPorts = new HashSet<NodeConnectorId>(Arrays.asList(nodeConnectorId));
-        when(switchManager.getExternalPorts(nodeId)).thenReturn(externalPorts);
-
+        ctx.addTenant(baseTenant().build());
+        endpointManager.addL3Endpoint(natL3Ep);
+        l2Ep = new EndpointBuilder(l2Ep)
+            .addAugmentation(OfOverlayContext.class,new OfOverlayContextBuilder()
+                .setNodeId(nodeId)
+                .build())
+            .build();
+        endpointManager.addEndpoint(l2Ep);
+        switchManager.addSwitch(nodeId,null,ImmutableSet.<NodeConnectorId>of(new NodeConnectorId("openflow:1:1")), null);
         mapper.sync(nodeId, ofWriter);
-        verify(ofWriter, times(2)).writeFlow(any(NodeId.class), any(Short.class), any(Flow.class));
+        verify(ofWriter, times(4)).writeFlow(any(NodeId.class), any(Short.class), any(Flow.class));
     }
 
     @Test
     public void syncTestNoExternalPorts() throws Exception {
-        when(switchManager.getExternalPorts(nodeId)).thenReturn(null);
-
         mapper.sync(nodeId, ofWriter);
         verify(ofWriter, never()).writeFlow(any(NodeId.class), any(Short.class), any(Flow.class));
     }
index 75080e0b63f96c4f30771a63b2fa8760de8b618f..27337f261032cbda3fbfccfe39ca644c7de68ede 100755 (executable)
@@ -32,6 +32,7 @@ import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.groupbasedpolicy.dto.EgKey;
 import org.opendaylight.groupbasedpolicy.dto.IndexedTenant;
+import org.opendaylight.groupbasedpolicy.dto.PolicyInfo;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.endpoint.EndpointManager;
@@ -44,6 +45,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.NetworkDomainId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
@@ -53,6 +55,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
 import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.util.concurrent.CheckedFuture;
 
 public class GroupTableTest {
index 13bf771333967c3dfadcfd9929914b056ff9b108..a4cbd9a303bfe6fb3e5a25ddac78ef764de362a7 100755 (executable)
@@ -27,6 +27,7 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionName;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierName;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClauseName;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2BridgeDomainId;\r
@@ -40,6 +41,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointBuilder;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContextBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.Segmentation;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.SegmentationBuilder;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.action.refs.ActionRefBuilder;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef;\r
@@ -49,8 +52,10 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.ForwardingContextBuilder;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.PolicyBuilder;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2BridgeDomainBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2FloodDomain;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2FloodDomainBuilder;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L3ContextBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.Subnet;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.SubnetBuilder;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.ContractBuilder;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.EndpointGroupBuilder;\r
@@ -86,9 +91,11 @@ public class OfTableTest {
     L3ContextId l3c = new L3ContextId("2cf51ee4-e996-467e-a277-2d380334a91d");\r
     L2BridgeDomainId bd = new L2BridgeDomainId("c95182ba-7807-43f8-98f7-6c7c720b7639");\r
     L2FloodDomainId fd = new L2FloodDomainId("98e1439e-52d2-46f8-bd69-5136e6088771");\r
+    L2FloodDomainId ext_fd = new L2FloodDomainId("d8024f7a-b83e-11e5-9912-ba0be0483c18");\r
     SubnetId sub = new SubnetId("4fcf8dfc-53b5-4aef-84d3-6b5586992fcb");\r
     SubnetId sub2 = new SubnetId("c285a59f-fcb8-42e6-bf29-87ea522fd626");\r
     SubnetId sub3 = new SubnetId("a0380d52-2a25-48ef-882c-a4d4cd9e00ec");\r
+    SubnetId ext_sub = new SubnetId("8da17ad9-3261-4dc9-bcff-928a2f73cce7");\r
     TenantId tid = new TenantId("1118c691-8520-47ad-80b8-4cf5e3fe3302");\r
     EndpointGroupId eg = new EndpointGroupId("36dec84a-08c7-497b-80b6-a0035af72a12");\r
     EndpointGroupId eg2 = new EndpointGroupId("632e5e11-7988-4eb5-8fe6-6c182d890276");\r
@@ -163,7 +170,22 @@ public class OfTableTest {
                         .setL3Context(ImmutableList.of(new L3ContextBuilder().setId(l3c).build()))\r
                         .setL2BridgeDomain(\r
                                 ImmutableList.of(new L2BridgeDomainBuilder().setId(bd).setParent(l3c).build()))\r
-                        .setL2FloodDomain(ImmutableList.of(new L2FloodDomainBuilder().setId(fd).setParent(bd).build()))\r
+                        .setL2FloodDomain(ImmutableList.of(\r
+                                new L2FloodDomainBuilder()\r
+                                    .setId(fd)\r
+                                    .setParent(bd)\r
+                                    .addAugmentation(Segmentation.class,\r
+                                        new SegmentationBuilder()\r
+                                        .setSegmentationId(Integer.valueOf(216))\r
+                                        .build())\r
+                                    .build(),\r
+                                new L2FloodDomainBuilder()\r
+                                    .setId(ext_fd)\r
+                                    .addAugmentation(Segmentation.class,\r
+                                        new SegmentationBuilder()\r
+                                        .setSegmentationId(Integer.valueOf(2016))\r
+                                        .build())\r
+                                    .build()))\r
                         .setSubnet(ImmutableList.of(\r
                                 new SubnetBuilder().setId(sub2)\r
                                     .setParent(fd)\r
@@ -179,8 +201,13 @@ public class OfTableTest {
                                     .setParent(bd)\r
                                     .setIpPrefix(new IpPrefix(new Ipv4Prefix("10.0.2.0/24")))\r
                                     .setVirtualRouterIp(new IpAddress(new Ipv4Address("10.0.2.1")))\r
+                                    .build(),\r
+                                new SubnetBuilder()\r
+                                    .setId(ext_sub)\r
+                                    .setIpPrefix(new IpPrefix(new Ipv4Prefix("192.168.111.0/24")))\r
+                                    .setParent(ext_fd)\r
                                     .build()))\r
-                        .build());\r
+                       .build());\r
     }\r
 \r
     protected ContractBuilder baseContract(List<Subject> subjects) {\r
index 4d7409b24912c872bc79496422ca46b447de5976..58562bcb7133ed08503be8b0bd7d28a785e85415 100755 (executable)
@@ -46,6 +46,14 @@ public class PortSecurityTest extends FlowTableTest {
     protected static final Logger LOG =\r
             LoggerFactory.getLogger(PortSecurityTest.class);\r
 \r
+    private Endpoint ep = localEP()\r
+            .setL3Address(ImmutableList.of(new L3AddressBuilder()\r
+            .setIpAddress(new IpAddress(new Ipv4Address("10.10.10.10")))\r
+            .build(),\r
+            new L3AddressBuilder()\r
+            .setIpAddress(new IpAddress(new Ipv6Address("2001:db8:85a3::8a2e:370:7334")))\r
+            .build()))\r
+        .build();\r
     @Override\r
     @Before\r
     public void setup() throws Exception {\r
@@ -97,7 +105,7 @@ public class PortSecurityTest extends FlowTableTest {
         for (Flow f : fm.getTableForNode(nodeId, ctx.getPolicyManager().getTABLEID_PORTSECURITY()).getFlow()) {\r
             flowMap.put(f.getId().getValue(), f);\r
             if (f.getMatch() != null && f.getMatch().getInPort() != null &&\r
-                ncs.contains(f.getMatch().getInPort().getValue())) {\r
+                (ncs.contains(f.getMatch().getInPort().getValue()))) {\r
                 assertTrue(f.getInstructions().equals(\r
                              FlowUtils.gotoTableInstructions(ctx.getPolicyManager().getTABLEID_INGRESS_NAT()))\r
                              || f.getInstructions().equals(\r
@@ -105,7 +113,7 @@ public class PortSecurityTest extends FlowTableTest {
                 count += 1;\r
             }\r
         }\r
-        assertEquals(2, count);\r
+        assertEquals(1, count);\r
         int numberOfFlows = fm.getTableForNode(nodeId, ctx.getPolicyManager().getTABLEID_PORTSECURITY()).getFlow().size();\r
         fm = dosync(flowMap);\r
         assertEquals(numberOfFlows, fm.getTableForNode(nodeId, ctx.getPolicyManager().getTABLEID_PORTSECURITY()).getFlow().size());\r
@@ -148,15 +156,6 @@ public class PortSecurityTest extends FlowTableTest {
 \r
     @Test\r
     public void testL3() throws Exception {\r
-        Endpoint ep = localEP()\r
-            .setL3Address(ImmutableList.of(new L3AddressBuilder()\r
-                .setIpAddress(new IpAddress(new Ipv4Address("10.10.10.10")))\r
-                .build(),\r
-                new L3AddressBuilder()\r
-                .setIpAddress(new IpAddress(new Ipv6Address("2001:db8:85a3::8a2e:370:7334")))\r
-                .build()))\r
-            .build();\r
-\r
         endpointManager.addEndpoint(ep);\r
 \r
         OfWriter fm = dosync(null);\r
@@ -197,4 +196,19 @@ public class PortSecurityTest extends FlowTableTest {
         fm = dosync(flowMap);\r
         assertEquals(numberOfFlows, fm.getTableForNode(nodeId, ctx.getPolicyManager().getTABLEID_PORTSECURITY()).getFlow().size());\r
     }\r
+\r
+    @Test\r
+    public void testExternal() throws Exception {\r
+        endpointManager.addEndpoint(ep);\r
+        switchManager.addSwitch(\r
+                new NodeId("openflow:12"),\r
+                new NodeConnectorId("openflow:12:1"),\r
+                ImmutableSet.of(new NodeConnectorId("openflow:12:2")),\r
+                new OfOverlayNodeConfigBuilder().setTunnel(\r
+                        ImmutableList.of(new TunnelBuilder().setTunnelType(TunnelTypeVxlan.class)\r
+                            .setNodeConnectorId(new NodeConnectorId("openflow:12:1"))\r
+                            .build())).build());\r
+        ctx.addTenant(baseTenant().build());\r
+        OfWriter fm = dosync(null);\r
+    }\r
 }\r