Bug 7778: VM's FIP are not able communicate to each other 39/54039/4
authorvinothb <vinothb@hcl.com>
Wed, 29 Mar 2017 23:06:32 +0000 (19:06 -0400)
committerSam Hague <shague@redhat.com>
Wed, 29 Mar 2017 15:07:04 +0000 (15:07 +0000)
in external network provider

Problem: NORMAL instruction support need to be removed
from legacy netvirt

Soultion: Added a separate flow for broadcast, multicast, unicast of
internal to external communication

Change-Id: Ifc7dec023511395b6a7d2f671b8350886ff11297
Signed-off-by: vinothb <vinothb@hcl.com>
Signed-off-by: Sam Hague <shague@redhat.com>
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/ConfigActivator.java
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/VlanResponderService.java
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/VLANProvider.java
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/VlanResponderProvider.java
openstack/utils/mdsal-openflow/src/main/java/org/opendaylight/netvirt/utils/mdsal/openflow/InstructionUtils.java
openstack/utils/mdsal-openflow/src/main/java/org/opendaylight/netvirt/utils/mdsal/openflow/MatchUtils.java

index 91618f951c73276ec6142f935c2069ab85dad9ac..6f684702c6f6d6b987422f41f639dd0d9cf3409c 100644 (file)
@@ -58,6 +58,7 @@ import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services.
 import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services.RoutingService;
 import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services.VlanResponderService;
 import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services.arp.GatewayMacResolverService;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
 import org.osgi.framework.BundleActivator;
@@ -195,6 +196,22 @@ public class ConfigActivator implements BundleActivator {
         icmpEchoResponderService.setDependencies(context, null);
         vlanResponderService.setDependencies(context, null);
 
+        @SuppressWarnings("unchecked")
+        ServiceTracker neutronNetworkCacheTracker = new ServiceTracker(context,
+                INeutronNetworkCRUD.class, null) {
+            @Override
+            public Object addingService(ServiceReference reference) {
+                LOG.info("addingService INeutronNetworkCRUD");
+                INeutronNetworkCRUD service =
+                        (INeutronNetworkCRUD) context.getService(reference);
+                if (service != null) {
+                    vlanResponderService.setDependencies(service);
+                }
+                return service;
+            }
+        };
+        neutronNetworkCacheTracker.open();
+
         @SuppressWarnings("unchecked")
         ServiceTracker networkingProviderManagerTracker = new ServiceTracker(context,
                 NetworkingProviderManager.class, null) {
index 276bfffe7d1d378de3b44f70c0098761896aa745..29cc4cec4e59ff880d0dc65930457c1559650762 100644 (file)
@@ -7,28 +7,54 @@
  */
 package org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services;
 
-import java.util.Collections;
+import java.util.ArrayList;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.opendaylight.netvirt.openstack.netvirt.api.ConfigurationService;
+import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
+import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
+import org.opendaylight.netvirt.openstack.netvirt.api.TenantNetworkManager;
 import org.opendaylight.netvirt.openstack.netvirt.api.VlanResponderProvider;
 import org.opendaylight.netvirt.openstack.netvirt.providers.ConfigInterface;
 import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
 import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
+import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
 import org.opendaylight.netvirt.utils.mdsal.openflow.FlowUtils;
 import org.opendaylight.netvirt.utils.mdsal.openflow.InstructionUtils;
 import org.opendaylight.netvirt.utils.mdsal.openflow.MatchUtils;
+import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase;
+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.output.action._case.OutputActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
+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.action.list.ActionKey;
 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.inventory.rev130819.tables.table.FlowKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
 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.flow.types.rev131026.instruction.list.InstructionKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 import org.slf4j.Logger;
@@ -36,6 +62,17 @@ import org.slf4j.LoggerFactory;
 
 public class VlanResponderService extends AbstractServiceInstance implements VlanResponderProvider, ConfigInterface {
     private static final Logger LOG = LoggerFactory.getLogger(VlanResponderService.class);
+    private static final int PRIORITY_2 = 2;
+    private static final int PRIORITY_4 = 4;
+    private static final int PRIORITY_5 = 5;
+
+    private volatile ConfigurationService configurationService;
+    private volatile NodeCacheManager nodeCacheManager;
+    private volatile TenantNetworkManager tenantNetworkManager;
+    private volatile Southbound southbound;
+    private volatile INeutronNetworkCRUD neutronNetworkCache;
+    private volatile Map<String, ArrayList<ImmutablePair<String, Long>>> segmentationOfPortMap =
+            new ConcurrentHashMap<String, ArrayList<ImmutablePair<String, Long>>>();
 
     public VlanResponderService() {
         super(Service.OUTBOUND_NAT);
@@ -46,11 +83,54 @@ public class VlanResponderService extends AbstractServiceInstance implements Vla
     }
 
     /**
-     * Write or remove the flows for output instructions based on flag value actions.
-     * Sample flow: table=100, n_packets=1192, n_bytes=55496, priority=4,in_port=5,dl_src=fa:16:3e:74:a9:2e actions=output:3
+     * Creates provider network flows for internal bridge.
+     *
+     * @param dpIdInt dp Id
+     * @param segmentationId segmentation id
+     * @param patchIntPort patch port of internal bridge
+     * @param ofPort of port value
+     * @param macAddress mac address
+     * @param vlanProviderCache Initial VLAN cache with processing cache
+     * @param write - flag to indicate the operation
      */
     @Override
-    public void programProviderNetworkOutput(Long dpidLong, Long ofPort, Long patchPort, String macAddress, boolean write) {
+    public void programProviderNetworkRulesInternal(Long dpIdInt, String segmentationId, Long ofPort, Long patchIntPort,
+            String macAddress, Map<String, Set<String>> vlanProviderCache, boolean write) {
+
+        programProviderBroadAndMultiCastOfRouter(dpIdInt, segmentationId, ofPort, patchIntPort, macAddress, write);
+        programProviderUnicastFlowOfRouters(dpIdInt, segmentationId, ofPort, patchIntPort, macAddress, write);
+        programProviderUnicastFlowOfExternal(dpIdInt, segmentationId, ofPort, patchIntPort, macAddress, write);
+        programProviderBroadAndMultiCastOfExternal(dpIdInt, segmentationId, ofPort, patchIntPort, macAddress, write);
+        programProviderUnicastFlowFromExternal(dpIdInt, segmentationId, ofPort, patchIntPort, macAddress, vlanProviderCache, write);
+    }
+
+    /**
+     * Creates provider network flows for external bridge.
+     *
+     * @param dpIdExt dp id
+     * @param segmentationId segmentation id
+     * @param patchExtPort patch port of external bridge
+     * @param macAddress mac address
+     * @param vlanProviderCache Initial VLAN cache with processing cache
+     * @param write - flag indicate the operation
+     */
+    @Override
+    public void programProviderNetworkRulesExternal(Long dpIdExt,  String segmentationId, Long patchExtPort,
+            String macAddress, Map<String, Set<String>> vlanProviderCache, boolean write) {
+
+        programProviderNetworkForExternal(dpIdExt, segmentationId, patchExtPort, macAddress, vlanProviderCache, write);
+        programProviderNetworkDrop(dpIdExt, patchExtPort, vlanProviderCache, write);
+    }
+
+
+    /**
+     * Write or remove the flows for forward the BC/MC packets of router to patch port and
+     * the router ports connected to same external network.
+     * Sample flow: table=100, priority=5,in_port=2,dl_src=fa:16:3e:ff:9c:57,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00
+     * actions=output:3,push_vlan:0x8100,set_field:4196->vlan_vid,output:1
+     */
+    private void programProviderBroadAndMultiCastOfRouter(Long dpidLong, String segmentationId, Long ofPort, Long patchPort,
+                                             String macAddress, boolean write) {
         try {
             String nodeName = OPENFLOW + dpidLong;
             NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(nodeName);
@@ -59,87 +139,356 @@ public class VlanResponderService extends AbstractServiceInstance implements Vla
             MatchBuilder matchBuilder = new MatchBuilder();
             //Match In Port
             MatchUtils.createInPortMatch(matchBuilder, dpidLong, ofPort);
-            MatchUtils.createEthSrcMatch(matchBuilder, new MacAddress(macAddress));
+            matchBuilder = MatchUtils.createEthSrcDestMatch(matchBuilder, new MacAddress(macAddress),
+                    new MacAddress("01:00:00:00:00:00"), new MacAddress("01:00:00:00:00:00"));
             flowBuilder.setMatch(matchBuilder.build());
             // Add Flow Attributes
-            String flowName = "InternalBridge_output_" + dpidLong + "_" + ofPort;
+            String flowName = "ProviderNetwork_BC_Router_" + dpidLong + "_" + ofPort;
             final FlowId flowId = new FlowId(flowName);
             flowBuilder.setId(flowId).setBarrier(true).setTableId(getTable()).setKey(new FlowKey(flowId))
-                    .setPriority(4).setFlowName(flowName).setHardTimeout(0).setIdleTimeout(0);
+                    .setPriority(PRIORITY_5).setFlowName(flowName).setHardTimeout(0).setIdleTimeout(0);
+            ArrayList<ImmutablePair<String, Long>> macAddrOfPortPairList = segmentationOfPortMap.get(segmentationId);
+            if (macAddrOfPortPairList == null) {
+                macAddrOfPortPairList = new ArrayList<ImmutablePair<String, Long>>();
+                segmentationOfPortMap.put(segmentationId, macAddrOfPortPairList);
+            }
             if (write) {
+                ImmutablePair<String, Long> ofPortMacAddressPair = new ImmutablePair<>(macAddress, ofPort);
+                if (macAddrOfPortPairList.contains(ofPortMacAddressPair)) {
+                    return;
+                }
+                List<Instruction> outputInstructions = new ArrayList<Instruction>();
+                int instructionIndex = 0;
+                for (ImmutablePair<String, Long> macAddressOfPortPair : macAddrOfPortPairList) {
+                    InstructionUtils.createOutputPortInstruction(instructionIndex, dpidLong, macAddressOfPortPair.getRight(),
+                            outputInstructions);
+                    instructionIndex++;
+                }
                 // Set the Output Port/Iface
-                Instruction outputPortInstruction = InstructionUtils.createOutputPortInstructions(new InstructionBuilder(),
-                        dpidLong, patchPort).setOrder(0).setKey(new InstructionKey(0)).build();
+                Instruction outputPortInstruction = InstructionUtils.createVlanOutputPortInstructions(new InstructionBuilder(),
+                        dpidLong, patchPort, outputInstructions, new VlanId(Integer.valueOf(segmentationId)))
+                        .setOrder(0).setKey(new InstructionKey(0)).build();
                 // Add InstructionsBuilder to FlowBuilder
                 InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
                 writeFlow(flowBuilder, nodeBuilder);
+                macAddrOfPortPairList.add(ofPortMacAddressPair);
             } else {
                 removeFlow(flowBuilder, nodeBuilder);
+                Iterator<ImmutablePair<String, Long>> iterator = macAddrOfPortPairList.iterator();
+                while (iterator.hasNext()) {
+                    ImmutablePair<String, Long> macAddressOfPortPair = iterator.next();
+                    if (macAddress.equals(macAddressOfPortPair.getLeft())) {
+                        iterator.remove();
+                        break;
+                    }
+                }
+            }
+            programExistingProviderBroadAndMultiCastOfRouter(dpidLong, segmentationId, ofPort, patchPort, macAddress, write);
+        } catch (Exception e) {
+            LOG.error("Error while writing/removing broadcast flows. dpidLong = {}, patchPort={}, write = {}."
+                    + " Caused due to, {}", dpidLong, patchPort, write, e.getMessage());
+        }
+    }
+
+    /**
+     * Write or remove the existing flows of forward the BC/MC packets of router to patch port and
+     * the router ports connected to same external network.
+     * Sample flow: table=100, priority=5,in_port=2,dl_src=fa:16:3e:ff:9c:57,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00
+     * actions=output:3,push_vlan:0x8100,set_field:4196->vlan_vid,output:1
+     */
+    private void programExistingProviderBroadAndMultiCastOfRouter(Long dpidLong, String segmentationId, Long currentOfPort, Long patchPort,
+            String macAddress, boolean write) {
+
+        String nodeName = OPENFLOW + dpidLong;
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        ArrayList<ImmutablePair<String, Long>> macAddrOfPortPairList = segmentationOfPortMap.get(segmentationId);
+        for (ImmutablePair<String, Long> macAddrOfPortPair : macAddrOfPortPairList) {
+            Long ofPort = macAddrOfPortPair.getRight();
+            if (ofPort.equals(currentOfPort)) {
+                continue;
+            }
+            //Match In Port
+            MatchUtils.createInPortMatch(matchBuilder, dpidLong, ofPort);
+            matchBuilder = MatchUtils.createEthSrcDestMatch(matchBuilder, new MacAddress(macAddrOfPortPair.getLeft()),
+                    new MacAddress("01:00:00:00:00:00"), new MacAddress("01:00:00:00:00:00"));
+            flowBuilder.setMatch(matchBuilder.build());
+            // Add Flow Attributes
+            String flowName = "ProviderNetwork_BC_Router_" + dpidLong + "_" + ofPort;
+            final FlowId flowId = new FlowId(flowName);
+            flowBuilder.setId(flowId).setBarrier(true).setTableId(getTable()).setKey(new FlowKey(flowId))
+            .setPriority(PRIORITY_5).setFlowName(flowName).setHardTimeout(0).setIdleTimeout(0);
+
+            if (write) {
+                List<Instruction> outputInstructions = new ArrayList<Instruction>();
+                int instructionIndex = 0;
+                for (ImmutablePair<String, Long> macAddressOfPortPair : macAddrOfPortPairList) {
+                    if (ofPort.equals(macAddressOfPortPair.getRight())) {
+                        continue;
+                    }
+                    InstructionUtils.createOutputPortInstruction(instructionIndex, dpidLong, macAddressOfPortPair.getRight(),
+                            outputInstructions);
+                    instructionIndex++;
+                }
+
+                Instruction outputPortInstruction = InstructionUtils.createVlanOutputPortInstructions(new InstructionBuilder(),
+                        dpidLong, patchPort, outputInstructions, new VlanId(Integer.valueOf(segmentationId)))
+                        .setOrder(0).setKey(new InstructionKey(0)).build();
+                // Add InstructionsBuilder to FlowBuilder
+                InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
+                writeFlow(flowBuilder, nodeBuilder);
+            } else {
+                List<Instruction> outputInstructions = new ArrayList<Instruction>();
+                int instructionIndex = 0;
+                for (ImmutablePair<String, Long> ofPortMacAddrPair : macAddrOfPortPairList) {
+                    Long cachedOfPort = ofPortMacAddrPair.getRight();
+                    if (cachedOfPort.equals(ofPort) || cachedOfPort.equals(currentOfPort)) {
+                        continue;
+                    }
+                    InstructionUtils.createOutputPortInstruction(instructionIndex, dpidLong, cachedOfPort, outputInstructions);
+                    instructionIndex++;
+                }
+                Instruction outputPortInstruction = InstructionUtils.createVlanOutputPortInstructions(new InstructionBuilder(),
+                        dpidLong, patchPort, outputInstructions, new VlanId(Integer.valueOf(segmentationId)))
+                        .setOrder(0).setKey(new InstructionKey(0)).build();
+                // Add InstructionsBuilder to FlowBuilder
+                InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
+                writeFlow(flowBuilder, nodeBuilder);
+            }
+        }
+    }
+
+    /**
+     * Write or remove the flows for forward the packets from one router to another routers (Unicast flow)
+     * Sample flow: table=100, priority=4,in_port=2,dl_dst=fa:16:3e:4b:cc:0a actions=output:8
+     */
+    private void programProviderUnicastFlowOfRouters(Long dpidLong, String segmentationId, Long ofPort, Long patchPort,
+            String macAddress, boolean write) {
+        try {
+            String nodeName = OPENFLOW + dpidLong;
+            NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(nodeName);
+            FlowBuilder flowBuilder = new FlowBuilder();
+            ArrayList<ImmutablePair<String, Long>> macAddrOfPortPairList = segmentationOfPortMap.get(segmentationId);
+            if (write) {
+                for (ImmutablePair<String, Long> macAddressOfPortPair : macAddrOfPortPairList) {
+                    for (ImmutablePair<String, Long> subMacAddressOfPortPair : macAddrOfPortPairList) {
+                        if (macAddressOfPortPair.getLeft().equals(subMacAddressOfPortPair.getLeft())
+                                || ((!macAddressOfPortPair.getLeft().equals(macAddress) &&
+                                        !subMacAddressOfPortPair.getLeft().equals(macAddress)))) {
+                            continue;
+                        }
+                        // Create the OF Match using MatchBuilder
+                        MatchBuilder currentMatchBuilder = new MatchBuilder();
+                        //Match In Port
+                        MatchUtils.createInPortMatch(currentMatchBuilder, dpidLong, macAddressOfPortPair.getRight());
+                        currentMatchBuilder = MatchUtils.createDestEthMatch(currentMatchBuilder,
+                                new MacAddress(subMacAddressOfPortPair.getLeft()), null);
+                        flowBuilder.setMatch(currentMatchBuilder.build());
+                        // Add Flow Attributes
+                        String currentFlowName = "ProviderNetwork_unicast_router_" + dpidLong + "_" +
+                            macAddressOfPortPair.getLeft() + "_" + subMacAddressOfPortPair.getLeft();
+
+                        final FlowId flowId = new FlowId(currentFlowName);
+                        flowBuilder.setId(flowId).setBarrier(true).setTableId(getTable()).setKey(new FlowKey(flowId))
+                                .setPriority(PRIORITY_4).setFlowName(currentFlowName).setHardTimeout(0).setIdleTimeout(0);
+
+                        Instruction outputPortInstruction = InstructionUtils.createOutputPortInstructions(new InstructionBuilder(),
+                                dpidLong, subMacAddressOfPortPair.getRight()).setOrder(0).setKey(new InstructionKey(0)).build();
+                        // Add InstructionsBuilder to FlowBuilder
+                        InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
+                        writeFlow(flowBuilder, nodeBuilder);
+                    }
+                }
+            } else {
+                for (ImmutablePair<String, Long> macAddressOfPortPair : macAddrOfPortPairList) {
+                    if (macAddressOfPortPair.getLeft().equals(macAddress)) {
+                        continue;
+                    }
+                     // Create the OF Match using MatchBuilder
+                     MatchBuilder matchBuilder = new MatchBuilder();
+                     //Match In Port
+                     MatchUtils.createInPortMatch(matchBuilder, dpidLong, ofPort);
+                     matchBuilder = MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(macAddressOfPortPair.getLeft()), null);
+                     flowBuilder.setMatch(matchBuilder.build());
+                     // Add Flow Attributes
+                     String flowName = "ProviderNetwork_unicast_router_" + dpidLong + "_" + macAddress + "_" + macAddressOfPortPair.getLeft();
+                     FlowId flowId = new FlowId(flowName);
+                     flowBuilder.setId(flowId).setBarrier(true).setTableId(getTable()).setKey(new FlowKey(flowId))
+                              .setPriority(PRIORITY_4).setFlowName(flowName).setHardTimeout(0).setIdleTimeout(0);
+
+                    removeFlow(flowBuilder, nodeBuilder);
+
+                    MatchUtils.createInPortMatch(matchBuilder, dpidLong, macAddressOfPortPair.getRight());
+                    matchBuilder = MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(macAddress), null);
+                    flowBuilder.setMatch(matchBuilder.build());
+                    // Add Flow Attributes
+                    flowName = "ProviderNetwork_unicast_router_" + dpidLong + "_" + macAddressOfPortPair.getLeft() + "_" + macAddress;
+                    flowId = new FlowId(flowName);
+                    flowBuilder.setId(flowId).setBarrier(true).setTableId(getTable()).setKey(new FlowKey(flowId))
+                             .setPriority(PRIORITY_4).setFlowName(flowName).setHardTimeout(0).setIdleTimeout(0);
+
+                    removeFlow(flowBuilder, nodeBuilder);
+                }
+            }
+        } catch (Exception e) {
+            LOG.error("Error while writing/removing unicast flow of routers. dpidLong = {}, patchPort={}, write = {}."
+                    + " Caused due to, {}", dpidLong, patchPort, write, e.getMessage());
+        }
+    }
+
+    /**
+     * Write or remove the flows for forwarding the BC/MC packets to all other router ports connected to same external network.
+     * Sample flow: table=100, priority=4,in_port=1,dl_vlan=100,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=pop_vlan,output:2,output:8
+     */
+    private void programProviderBroadAndMultiCastOfExternal(Long dpidLong, String segmentationId, Long ofPort, Long patchPort,
+                                             String macAddress, boolean write) {
+        try {
+            String nodeName = OPENFLOW + dpidLong;
+            NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(nodeName);
+            FlowBuilder flowBuilder = new FlowBuilder();
+            // Create the OF Match using MatchBuilder
+            MatchBuilder matchBuilder = new MatchBuilder();
+         // Match Vlan ID
+            MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId)), true);
+            //Match In Port
+            MatchUtils.createInPortMatch(matchBuilder, dpidLong, patchPort);
+            matchBuilder = MatchUtils.createDestEthMatch(matchBuilder, new MacAddress("01:00:00:00:00:00"),
+                    new MacAddress("01:00:00:00:00:00"));
+            flowBuilder.setMatch(matchBuilder.build());
+            // Add Flow Attributes
+            String flowName = "ProviderNetwork_BC_External_" + segmentationId + "_" + patchPort;
+            final FlowId flowId = new FlowId(flowName);
+            flowBuilder.setId(flowId).setBarrier(true).setTableId(getTable()).setKey(new FlowKey(flowId))
+                    .setPriority(PRIORITY_4).setFlowName(flowName).setHardTimeout(0).setIdleTimeout(0);
+            if (write) {
+                ArrayList<ImmutablePair<String, Long>> macAddrOfPortPairList = segmentationOfPortMap.get(segmentationId);
+                List<Instruction> outputInstructions = new ArrayList<Instruction>();
+                int instructionIndex = 1;
+                for (ImmutablePair<String, Long> ofPortMacAddrPair : macAddrOfPortPairList) {
+                    InstructionUtils.createOutputPortInstruction(instructionIndex, dpidLong,
+                            ofPortMacAddrPair.getRight(), outputInstructions);
+                    instructionIndex++;
+                }
+                Instruction outputPortInstruction =
+                        InstructionUtils.createPopOutputPortInstructions(new InstructionBuilder(), dpidLong, null, outputInstructions)
+                        .setOrder(0)
+                        .setKey(new InstructionKey(0))
+                        .build();
+                InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
+                writeFlow(flowBuilder, nodeBuilder);
+            } else {
+                ArrayList<ImmutablePair<String, Long>> macAddrOfPortPairList = segmentationOfPortMap.get(segmentationId);
+                if (macAddrOfPortPairList == null || macAddrOfPortPairList.isEmpty()) {
+                    removeFlow(flowBuilder, nodeBuilder);
+                } else {
+                    List<Instruction> outputInstructions = new ArrayList<Instruction>();
+                    int instructionIndex = 1;
+                    for (ImmutablePair<String, Long> ofPortMacAddrPair : macAddrOfPortPairList) {
+                        InstructionUtils.createOutputPortInstruction(instructionIndex, dpidLong, ofPortMacAddrPair.getRight(),
+                                outputInstructions);
+                        instructionIndex++;
+                    }
+                    Instruction outputPortInstruction = InstructionUtils.createPopOutputPortInstructions(new InstructionBuilder(),
+                            dpidLong, null, outputInstructions).setOrder(0).setKey(new InstructionKey(0)).build();
+                    // Add InstructionsBuilder to FlowBuilder
+                    InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
+                    writeFlow(flowBuilder, nodeBuilder);
+                }
             }
         } catch (Exception e) {
-            LOG.error("Error while writing/removing output instruction flow. dpidLong = {}, patchPort={}, write = {}."
+            LOG.error("Error while writing/removing BC/MC flow of external interface. dpidLong = {}, patchPort={}, write = {}."
                     +" Caused due to, {}", dpidLong, patchPort, write, e.getMessage());
         }
     }
 
+
     /**
-     * Write or remove the flows for POP VLAN instructions based on flag value actions.
-     * Sample flow: table=100, n_packets=218, n_bytes=15778, priority=4,in_port=3,dl_vlan=100 actions=pop_vlan,NORMAL
+     * Write or remove the flows for forwarding unicast packets from router to external Gateway.
+     * Sample flow: table=100, priority=2,in_port=2,dl_src=fa:16:3e:ff:9c:57 actions=push_vlan:0x8100,set_field:4196- >vlan_vid,output:1
      */
-    @Override
-    public void programProviderNetworkPopVlan(Long dpidLong, String segmentationId,
+    private void programProviderUnicastFlowOfExternal(Long dpidLong, String segmentationId, Long ofPort, Long patchPort,
+            String macAddress, boolean write) {
+        try {
+            String nodeName = OPENFLOW + dpidLong;
+            NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(nodeName);
+            FlowBuilder flowBuilder = new FlowBuilder();
+            // Create the OF Match using MatchBuilder
+            MatchBuilder matchBuilder = new MatchBuilder();
+            //Match In Port
+            MatchUtils.createInPortMatch(matchBuilder, dpidLong, ofPort);
+            MatchUtils.createEthSrcMatch(matchBuilder, new MacAddress(macAddress));
+            flowBuilder.setMatch(matchBuilder.build());
+            // Add Flow Attributes
+            String flowName = "ProviderNetwork_unicast_external_" + dpidLong + "_" + ofPort;
+            final FlowId flowId = new FlowId(flowName);
+            flowBuilder.setId(flowId).setBarrier(true).setTableId(getTable()).setKey(new FlowKey(flowId))
+                    .setPriority(PRIORITY_2).setFlowName(flowName).setHardTimeout(0).setIdleTimeout(0);
+            if (write) {
+                // Set the Output Port/Iface
+                Instruction outputPortInstruction = InstructionUtils.createPushVlanInstruction(new InstructionBuilder(),
+                        dpidLong, patchPort, new VlanId(Integer.valueOf(segmentationId)), new ArrayList<>())
+                        .setOrder(0).setKey(new InstructionKey(0)).build();
+                // Add InstructionsBuilder to FlowBuilder
+                InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
+                writeFlow(flowBuilder, nodeBuilder);
+            } else {
+                removeFlow(flowBuilder, nodeBuilder);
+            }
+        } catch (Exception e) {
+            LOG.error("Error while writing/removing unicast flow of external gateway. dpidLong = {}, write = {}."
+                    +" Caused due to, {}", dpidLong, write, e.getMessage());
+        }
+    }
+
+    /**
+     * Write or remove the flows for forwarding unicast packets from external Gateway to router.
+     * Sample flow: table=100, priority=4,in_port=1,dl_vlan=100,dl_dst=fa:16:3e:ff:9c:57 actions=pop_vlan,output:2
+     */
+    private void programProviderUnicastFlowFromExternal(Long dpidLong, String segmentationId,
                                               Long ofPort, Long patchPort, String macAddress,
                                               Map<String, Set<String>> vlanProviderCache, boolean write) {
         try {
             String nodeName = OPENFLOW + dpidLong;
             NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(nodeName);
             FlowBuilder flowBuilder = new FlowBuilder();
+            ArrayList<ImmutablePair<String, Long>> macAddrOfPortPairList = segmentationOfPortMap.get(segmentationId);
             // Create the OF Match using MatchBuilder
             MatchBuilder matchBuilder = new MatchBuilder();
             // Match Vlan ID
             MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId)), true);
             //Match In Port
             MatchUtils.createInPortMatch(matchBuilder, dpidLong, patchPort);
+            matchBuilder = MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(macAddress), null);
             flowBuilder.setMatch(matchBuilder.build());
             // Add Flow Attributes
-            String flowName = "InternalBridge_popVLAN_" + segmentationId + "_" + patchPort;
+            String flowName = "ProviderNetwork_unicast_ext_int" + segmentationId + "_" + ofPort;
             final FlowId flowId = new FlowId(flowName);
             flowBuilder.setId(flowId).setBarrier(true).setTableId(getTable()).setKey(new FlowKey(flowId))
-                    .setPriority(4).setFlowName(flowName).setHardTimeout(0).setIdleTimeout(0);
+                    .setPriority(PRIORITY_4).setFlowName(flowName).setHardTimeout(0).setIdleTimeout(0);
             if (write) {
-                /* Strip vlan and store to tmp instruction space*/
-                Instruction popVlanInstruction = InstructionUtils.createPopVlanAndNormalInstructions(
-                        new InstructionBuilder()).setOrder(0).setKey(new InstructionKey(0)).build();
+                // Set the Output Port/Iface
+                Instruction outputPortInstruction = InstructionUtils.createPopOutputPortInstructions(new InstructionBuilder(),
+                        dpidLong, ofPort, null).setOrder(0).setKey(new InstructionKey(0)).build();
                 // Add InstructionsBuilder to FlowBuilder
-                InstructionUtils.setFlowBuilderInstruction(flowBuilder, popVlanInstruction);
+                InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
                 writeFlow(flowBuilder, nodeBuilder);
             } else {
-                Set<String> lstMacAddress = new HashSet<>();
-                if (vlanProviderCache != null && !vlanProviderCache.isEmpty() &&
-                        vlanProviderCache.containsKey(segmentationId)) {
-                    lstMacAddress = vlanProviderCache.get(segmentationId);
-                    lstMacAddress.remove(macAddress);
-                }
-                if (lstMacAddress == null || lstMacAddress.isEmpty()) {
-                    vlanProviderCache.remove(segmentationId);
-                }
-                boolean isSegmentationIdExist = vlanProviderCache.containsKey(segmentationId);
-                if (!isSegmentationIdExist) {
-                    removeFlow(flowBuilder, nodeBuilder);
-                }
-            }
+                 removeFlow(flowBuilder, nodeBuilder);
+               }
         } catch (Exception e) {
-            LOG.error("Error while writing/removing pop vlan instruction flow. dpidLong = {}, patchPort={}, write = {}."
+            LOG.error("Error while writing/removing unicast flow of external gateway to router. dpidLong = {}, patchPort={}, write = {}."
                     + "Caused due to, {}", dpidLong, patchPort, write, e.getMessage());
         }
     }
 
     /**
-     * Write or remove the flows for push VLAN instructions based on flag value actions.
-     * Sample flow: cookie=0x0, duration=4831.827s, table=0, n_packets=1202, n_bytes=56476, priority=4,in_port=3, dl_src=fa:16:3e:74:a9:2e actions=push_vlan:0x8100,set_field:4196 vlan_vid,NORMAL
+     * Write or remove the flows for external bridge.
+     * Sample flow: cookie=0x0, duration=4831.827s, table=0, n_packets=1202, n_bytes=56476, priority=4,in_port=3,
+     * dl_src=fa:16:3e:74:a9:2e actions=push_vlan:0x8100,set_field:4196 vlan_vid,NORMAL
      */
-    @Override
-    public void programProviderNetworkPushVlan(Long dpidLong, String segmentationId,
+    private void programProviderNetworkForExternal(Long dpidLong, String segmentationId,
                                                Long patchExtPort, String macAddress,
                                                Map<String, Set<String>> vlanProviderCache, boolean write) {
         try {
@@ -148,36 +497,47 @@ public class VlanResponderService extends AbstractServiceInstance implements Vla
             FlowBuilder flowBuilder = new FlowBuilder();
             // Create the OF Match using MatchBuilder
             MatchBuilder matchBuilder = new MatchBuilder();
-            MatchUtils.createEthSrcMatch(matchBuilder, new MacAddress(macAddress));
+            //Match Vlan ID
+            MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId)), true);
             //Match In Port
             MatchUtils.createInPortMatch(matchBuilder, dpidLong, patchExtPort);
             flowBuilder.setMatch(matchBuilder.build());
             // Add Flow Attributes
-            String flowName = "ExternalBridge_pushVLAN_" + dpidLong + "_" + segmentationId + "_" + macAddress;
+            String flowName = "ProviderNetwork_pushVLAN_" + dpidLong + "_" + segmentationId;
             final FlowId flowId = new FlowId(flowName);
             flowBuilder.setId(flowId).setBarrier(true).setTableId((short) 0).setKey(new FlowKey(flowId))
-                    .setPriority(4).setFlowName(flowName).setHardTimeout(0).setIdleTimeout(0);
+                    .setPriority(PRIORITY_4).setFlowName(flowName).setHardTimeout(0).setIdleTimeout(0);
             if (write) {
                 LOG.debug("In programProviderNetworkPushVlan macAddress:" + macAddress
                         + "segmentationId:" + segmentationId);
-                Set<String> lstMacAddress;
+                Set<String> lstMacAddress = new HashSet<String>();
                 if (vlanProviderCache != null && !vlanProviderCache.isEmpty() && vlanProviderCache.containsKey(segmentationId)) {
                     lstMacAddress = vlanProviderCache.get(segmentationId);
                 } else {
-                    lstMacAddress = new HashSet<>();
+                    lstMacAddress = new HashSet<String>();
                     vlanProviderCache.put(segmentationId, lstMacAddress);
                 }
                 lstMacAddress.add(macAddress);
-                InstructionBuilder ib = new InstructionBuilder();
-                // Set VLAN ID Instruction
-                InstructionUtils.createSetVlanAndNormalInstructions(ib, new VlanId(Integer.valueOf(segmentationId)));
-                ib.setOrder(0);
-                ib.setKey(new InstructionKey(0));
-                Instruction pushVLANInstruction = ib.build();
-                InstructionUtils.setFlowBuilderInstruction(flowBuilder, pushVLANInstruction);
+                Instruction normalInstruction = InstructionUtils.createNormalInstructions(
+                        FlowUtils.getNodeName(dpidLong), new InstructionBuilder()).
+                        setOrder(0).setKey(new InstructionKey(0)).build();
+                // Add InstructionsBuilder to FlowBuilder
+                InstructionUtils.setFlowBuilderInstruction(flowBuilder, normalInstruction);
                 writeFlow(flowBuilder, nodeBuilder);
             } else {
-                removeFlow(flowBuilder, nodeBuilder);
+                Set<String> lstMacAddress = new HashSet<String>();
+                if (vlanProviderCache != null && !vlanProviderCache.isEmpty() && vlanProviderCache.containsKey(segmentationId)) {
+                    lstMacAddress = vlanProviderCache.get(segmentationId);
+                    lstMacAddress.remove(macAddress);
+                }
+                if (lstMacAddress == null || lstMacAddress.isEmpty()) {
+                    vlanProviderCache.remove(segmentationId);
+                }
+                boolean isSegmentationIdExist = vlanProviderCache.containsKey(segmentationId);
+                if (!isSegmentationIdExist)  {
+                    removeFlow(flowBuilder, nodeBuilder);
+                }
+                //removeFlow(flowBuilder, nodeBuilder);
             }
         } catch (Exception e) {
             LOG.error("Error while writing/removing push vlan instruction flow. dpidLong = {}, patchPort={}, write = {}."
@@ -189,8 +549,7 @@ public class VlanResponderService extends AbstractServiceInstance implements Vla
      * Write or remove the flows for drop instructions based on flag value actions.
      * Sample flow: table=0, n_packets=0, n_bytes=0, priority=2,in_port=3 actions=drop
      */
-    @Override
-    public void programProviderNetworkDrop(Long dpidLong, Long patchExtPort,
+    private void programProviderNetworkDrop(Long dpidLong, Long patchExtPort,
                                            Map<String, Set<String>> vlanProviderCache, boolean write) {
         try {
             String nodeName = OPENFLOW + dpidLong;
@@ -202,10 +561,10 @@ public class VlanResponderService extends AbstractServiceInstance implements Vla
             MatchUtils.createInPortMatch(matchBuilder, dpidLong, patchExtPort);
             flowBuilder.setMatch(matchBuilder.build());
             // Add Flow Attributes
-            String flowName = "ExternalBridge_drop_" + dpidLong + "_" + patchExtPort;
+            String flowName = "ProviderNetwork_drop_" + dpidLong + "_" + patchExtPort;
             final FlowId flowId = new FlowId(flowName);
             flowBuilder.setId(flowId).setBarrier(true).setTableId((short) 0)
-                    .setKey(new FlowKey(flowId)).setPriority(2).setFlowName(flowName)
+                    .setKey(new FlowKey(flowId)).setPriority(PRIORITY_2).setFlowName(flowName)
                     .setHardTimeout(0).setIdleTimeout(0);
             if (write) {
                 // Call the InstructionBuilder Methods Containing Actions
@@ -227,12 +586,67 @@ public class VlanResponderService extends AbstractServiceInstance implements Vla
         }
     }
 
+    private void populateSegmentationCache() {
+        try {
+            Map<String, String> networkUUIDSegIdMap = new ConcurrentHashMap<String, String>();
+            for (Node node : nodeCacheManager.getBridgeNodes()) {
+                Node srcBridgeNode = southbound.getBridgeNode(node, configurationService.getIntegrationBridgeName());
+                if (srcBridgeNode != null) {
+                    List<OvsdbTerminationPointAugmentation> terminationPointOfBridgeList =
+                            southbound.getTerminationPointsOfBridge(srcBridgeNode);
+                    for (OvsdbTerminationPointAugmentation intf : terminationPointOfBridgeList) {
+                        NeutronPort neutronPort = tenantNetworkManager.getTenantPort(intf);
+                        if (neutronPort != null && neutronPort.getDeviceOwner().equalsIgnoreCase(Constants.OWNER_ROUTER_GATEWAY)) {
+                            final String macAddress = neutronPort.getMacAddress();
+                            final String networkUUID = neutronPort.getNetworkUUID();
+                            String providerSegmentationId = networkUUIDSegIdMap.get(networkUUID);
+                            if (providerSegmentationId == null) {
+                                NeutronNetwork neutronNetwork = neutronNetworkCache.getNetwork(networkUUID);
+                                providerSegmentationId = neutronNetwork != null ?
+                                        neutronNetwork.getProviderSegmentationID() : null;
+                            }
+                            if (providerSegmentationId == null || providerSegmentationId.isEmpty()
+                                    || macAddress == null || macAddress.isEmpty()) {
+                                continue;
+                            }
+                            networkUUIDSegIdMap.put(networkUUID, providerSegmentationId);
+                            ArrayList<ImmutablePair<String, Long>> macAddrOfPortPairList = segmentationOfPortMap.get(providerSegmentationId);
+                            if (macAddrOfPortPairList == null)
+                            {
+                                macAddrOfPortPairList = new ArrayList<ImmutablePair<String, Long>>();
+                                segmentationOfPortMap.put(providerSegmentationId, macAddrOfPortPairList);
+                            }
+                            ImmutablePair<String, Long> macAddrOfPortPair = new ImmutablePair<String, Long>(macAddress, intf.getOfport());
+                            macAddrOfPortPairList.add(macAddrOfPortPair);
+                        }
+                    }
+                }
+            }
+        }
+        catch (Exception e) {
+            LOG.error("Error while populating segmentation mac-ofport cache, due to {} ", e.getMessage());
+        }
+    }
+
     @Override
     public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
         super.setDependencies(bundleContext.getServiceReference(VlanResponderProvider.class.getName()), this);
+        configurationService =
+                (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
+        southbound =
+                (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
+        nodeCacheManager =
+                (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
+        tenantNetworkManager =
+                (TenantNetworkManager) ServiceHelper.getGlobalInstance(TenantNetworkManager.class, this);
     }
 
     @Override
-    public void setDependencies(Object impl) {}
+    public void setDependencies(Object impl) {
+        if (impl instanceof INeutronNetworkCRUD) {
+            neutronNetworkCache = (INeutronNetworkCRUD)impl;
+        }
+        populateSegmentationCache();
+    }
 
 }
index dbd3881e5ee27dbe13c7001fc8e41c8db2ba9a85..bd8cc9790618ad56537735b416f6ff5f19a273fd 100644 (file)
@@ -68,12 +68,11 @@ public class VLANProvider implements ConfigInterface {
             Preconditions.checkNotNull(dpIdInt);
             Preconditions.checkNotNull(dpIdExt);
             Preconditions.checkNotNull(portNameInt);
-            vlanResponderProvider.programProviderNetworkOutput(dpIdInt, ofPort, patchIntPort, macAddress, write);
-            vlanResponderProvider.programProviderNetworkPopVlan(dpIdInt, network.getProviderSegmentationID(),
-                   ofPort, patchIntPort, macAddress, vlanProviderCache, write);
-            vlanResponderProvider.programProviderNetworkPushVlan(dpIdExt, network.getProviderSegmentationID(),
-                   patchExtPort, macAddress, vlanProviderCache, write);
-            vlanResponderProvider.programProviderNetworkDrop(dpIdExt, patchExtPort, vlanProviderCache, write);
+            vlanResponderProvider.programProviderNetworkRulesInternal(dpIdInt, network.getProviderSegmentationID(), ofPort,
+                    patchIntPort, macAddress, vlanProviderCache, write);
+
+            vlanResponderProvider.programProviderNetworkRulesExternal(dpIdExt, network.getProviderSegmentationID(),
+                    patchExtPort, macAddress, vlanProviderCache, write);
         } catch(Exception e) {
             LOG.error("programProviderNetworkFlow:Error while writing a flows. Caused due to, " + e.getMessage());
         }
index a52d8df3d8f003f124f9cadbe6881babb24f3dab..3e714e698848857d94fde4bc2cd4c268e065533a 100644 (file)
@@ -15,46 +15,29 @@ import java.util.Set;
  */
 public interface VlanResponderProvider {
     /**
-     * Creates flow for OUTPUT instruction.
-     * @param dpidLong dp Id
-     * @param patchIntPort patch port of internal bridge
-     * @param ofPortValue of port value
-     * @param macAddress mac address
-     * @param write - flag to indicate the operation
-     */
-    void programProviderNetworkOutput(Long dpidLong, Long patchIntPort, Long ofPortValue, String macAddress, boolean write);
-
-    /**
-     * Creates flow for POP VLAN instruction.
+     * Creates provider network flows for internal bridge.
+     *
      * @param dpidLong dp Id
      * @param segmentationId segmentation id
-     * @param patchIntPort patch port of internal bridge
-     * @param ofPortValue of port value
+     * @param patchPort patch port of internal bridge
+     * @param ofPort of port value
      * @param macAddress mac address
      * @param vlanProviderCache Initial VLAN cache with processing cache
      * @param write - flag to indicate the operation
      */
-    void programProviderNetworkPopVlan(Long dpidLong, String segmentationId, Long patchIntPort, Long ofPortValue, String macAddress,
-            Map<String, Set<String>> vlanProviderCache, boolean write);
-
-    /**
-     * Creates flow for Push VLAN instruction.
-     * @param dpidLong dp Id
-     * @param segmentationId Segmentation id
-     * @param patchExtPort patch port of external bridge
-     * @param macAddress mac address
-     * @param vlanProviderCache Initial VLAN cache with processing cache
-     * @param write - flag indicate the operation
-     */
-    void programProviderNetworkPushVlan(Long dpidLong, String segmentationId, Long patchExtPort, String macAddress,
-            Map<String, Set<String>> vlanProviderCache, boolean write);
+    void programProviderNetworkRulesInternal(Long dpidLong, String segmentationId, Long ofPort, Long patchPort,
+            String macAddress, Map<String, Set<String>> vlanProviderCache, boolean write);
 
     /**
-     * Creates flow for Drop instruction.
+     * Creates provider network flows for external bridge.
+     *
      * @param dpidLong dp id
+     * @param segmentationId segmentation id
      * @param patchExtPort patch port of external bridge
+     * @param macAddress mac address
      * @param vlanProviderCache Initial VLAN cache with processing cache
      * @param write - flag indicate the operation
      */
-    void programProviderNetworkDrop(Long dpidLong, Long patchExtPort, Map<String, Set<String>> vlanProviderCache, boolean write);
+    void programProviderNetworkRulesExternal(Long dpidLong,  String segmentationId, Long patchExtPort,
+            String macAddress, Map<String, Set<String>> vlanProviderCache, boolean write);
 }
index 320d70a4e63486ca50027c33d11804b6febce9b2..4386181ee827b9e417e4787900a057e9e9ae45c9 100644 (file)
@@ -83,6 +83,7 @@ public class InstructionUtils {
     private static final Logger LOG = LoggerFactory.getLogger(InstructionUtils.class);
     private static final int IPV4 = 0x8100;
     private static final int MAX_LENGTH = 0xffff;
+    private static final int MAX_LENGTH_FOR_OUTPUT_INS = 60;
 
     /**
      * Create Send to Controller Reserved Port Instruction (packet_in)
@@ -187,28 +188,202 @@ public class InstructionUtils {
      */
     public static InstructionBuilder createOutputPortInstructions(InstructionBuilder ib, Long dpidLong, Long port) {
 
-        NodeConnectorId ncid = new NodeConnectorId("openflow:" + dpidLong + ":" + port);
-        LOG.debug("createOutputPortInstructions() Node Connector ID is - Type=openflow: DPID={} inPort={} ",
-                dpidLong, port);
+        List<Action> actionList = new ArrayList<>();
+        actionList.add(createOutputActionWithIndex(actionList.size(), dpidLong, port).build());
+
+        return createOutputApplyAction(ib, actionList);
+    }
+
+    /**
+     * Create Output Port Instruction and append the list of instructions
+     *
+     * @param ib       Map InstructionBuilder without any instructions
+     * @param dpidLong Long the datapath ID of a switch/node
+     * @param port     Long representing a port on a switch/node
+     * @param instructions the list of instructions
+     * @return ib InstructionBuilder Map with instructions
+     */
+    public static InstructionBuilder createOutputPortInstructions(InstructionBuilder ib,
+            Long dpidLong, Long port ,
+            List<Instruction> instructions) {
+
+        List<Action> actionList = new ArrayList<>();
+        actionList.add(createOutputActionWithIndex(actionList.size(), dpidLong, port).build());
+
+        List<Action> existingActions;
+        for (Instruction instruction : instructions) {
+            if (instruction.getInstruction() instanceof ApplyActionsCase) {
+                existingActions = (((ApplyActionsCase) instruction.getInstruction()).getApplyActions().getAction());
+                // Only include output actions
+                for (Action action : existingActions) {
+                        actionList.add(action);
+                }
+            }
+        }
+
+        return createOutputApplyAction(ib, actionList);
+    }
 
+    /**
+     * Create Output Port Instruction with specified index and add to the list.
+     *
+     * @param index   index of the action
+     * @param dpidLong Long the datapath ID of a switch/node
+     * @param ofPort     Long representing a port on a switch/node
+     * @param outputInstructions list to add the generated actions
+     */
+    public static void createOutputPortInstruction(int index, Long dpidLong,
+                Long ofPort, List<Instruction> outputInstructions) {
+        InstructionBuilder ib = new InstructionBuilder();
         List<Action> actionList = new ArrayList<>();
+        actionList.add(createOutputActionWithIndex(index, dpidLong, ofPort).build());
+
+        // Create an Apply Action
+        outputInstructions.add(createOutputApplyAction(ib, actionList).build());
+    }
+
+    private static ActionBuilder createOutputActionWithIndex(int index, long dpidLong, long ofPort) {
+        NodeConnectorId ncid = new NodeConnectorId("openflow:" + dpidLong + ":" + ofPort);
         ActionBuilder ab = new ActionBuilder();
+        /* Create output action for this port*/
         OutputActionBuilder oab = new OutputActionBuilder();
         oab.setOutputNodeConnector(ncid);
-
         ab.setAction(new OutputActionCaseBuilder().setOutputAction(oab.build()).build());
-        ab.setOrder(0);
-        ab.setKey(new ActionKey(0));
-        actionList.add(ab.build());
+        ab.setOrder(index);
+        ab.setKey(new ActionKey(index));
+        return ab;
+    }
 
+    private static InstructionBuilder createOutputApplyAction(InstructionBuilder ib, List<Action> actionList) {
         // Create an Apply Action
         ApplyActionsBuilder aab = new ApplyActionsBuilder();
         aab.setAction(actionList);
         ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+        return ib;
+    }
+
+    /**
+     * Create Output Port Instruction with push vlan.
+     *
+     * @param ib       Map InstructionBuilder without any instructions
+     * @param dpidLong Long the datapath ID of a switch/node
+     * @param port     Long representing a port on a switch/node
+     * @param instructions list to add the generated actions
+     * @param vlanId the vlan Id
+     */
+    public static InstructionBuilder createVlanOutputPortInstructions(InstructionBuilder ib,
+            Long dpidLong, Long port, List<Instruction> instructions, VlanId vlanId) {
 
+        List<Action> actionList = new ArrayList<>();
+        ActionBuilder ab = new ActionBuilder();
+
+        List<Action> existingActions;
+        for (Instruction instruction : instructions) {
+            if (instruction.getInstruction() instanceof ApplyActionsCase) {
+                existingActions = (((ApplyActionsCase) instruction.getInstruction()).getApplyActions().getAction());
+                // Only include output actions
+                for (Action action : existingActions) {
+                    if (action.getAction() instanceof OutputActionCase) {
+                        actionList.add(action);
+                    }
+                }
+            }
+        }
+        createPushVlanInstruction(ib, dpidLong, port, vlanId, actionList);
         return ib;
     }
 
+    /**
+     * Create Output Port Instruction with push vlan.
+     *
+     * @param ib       Map InstructionBuilder without any instructions
+     * @param dpidLong Long the datapath ID of a switch/node
+     * @param port     Long representing a port on a switch/node
+     * @param vlanId the vlan Id
+     * @param actionList list to actions to be added.
+     */
+    public static InstructionBuilder createPushVlanInstruction(InstructionBuilder ib,
+                Long dpidLong, Long port, VlanId vlanId, List<Action> actionList) {
+
+        NodeConnectorId ncid = new NodeConnectorId("openflow:" + dpidLong + ":" + port);
+        ActionBuilder ab = new ActionBuilder();
+
+        /* First we push vlan header */
+        PushVlanActionBuilder vlan = new PushVlanActionBuilder();
+        vlan.setEthernetType(IPV4);
+        ab.setAction(new PushVlanActionCaseBuilder().setPushVlanAction(vlan.build()).build());
+        ab.setOrder(actionList.size());
+        actionList.add(ab.build());
+
+        SetFieldBuilder setFieldBuilder = new SetFieldBuilder();
+
+        VlanMatchBuilder vlanMatchBuilder = new VlanMatchBuilder();
+        VlanIdBuilder vlanIdBuilder = new VlanIdBuilder();
+        vlanMatchBuilder.setVlanId(vlanIdBuilder.setVlanId(vlanId).setVlanIdPresent(true).build());
+        setFieldBuilder.setVlanMatch(vlanMatchBuilder.build());
+        ab = new ActionBuilder();
+        ab.setAction(new SetFieldCaseBuilder().setSetField(setFieldBuilder.build()).build());
+        ab.setOrder(actionList.size());
+        actionList.add(ab.build());
+
+        ab = new ActionBuilder();
+        OutputActionBuilder output = new OutputActionBuilder();
+        output.setMaxLength(MAX_LENGTH_FOR_OUTPUT_INS);
+        output.setOutputNodeConnector(ncid);
+        ab.setAction(new OutputActionCaseBuilder().setOutputAction(output.build()).build());
+        ab.setOrder(actionList.size());
+        actionList.add(ab.build());
+
+        return createOutputApplyAction(ib, actionList);
+    }
+
+    /**
+     * Create Output Port Instruction with Pop vlan.
+     *
+     * @param ib       Map InstructionBuilder without any instructions
+     * @param dpidLong Long the datapath ID of a switch/node
+     * @param port     Long representing a port on a switch/node
+     * @param instructions list to add the generated actions
+     */
+    public static InstructionBuilder createPopOutputPortInstructions(InstructionBuilder ib,
+            Long dpidLong, Long port ,
+            List<Instruction> instructions) {
+
+        List<Action> actionList = new ArrayList<>();
+        ActionBuilder ab = new ActionBuilder();
+
+        PopVlanActionBuilder popVlanActionBuilder = new PopVlanActionBuilder();
+        ab.setAction(new PopVlanActionCaseBuilder().setPopVlanAction(popVlanActionBuilder.build()).build());
+        ab.setOrder(0);
+        actionList.add(ab.build());
+        List<Action> existingActions;
+        if(instructions != null && !instructions.isEmpty()) {
+            for (Instruction instruction : instructions) {
+                if (instruction.getInstruction() instanceof ApplyActionsCase) {
+                    existingActions = (((ApplyActionsCase) instruction.getInstruction()).getApplyActions().getAction());
+                    // Only include output actions
+                    for (Action action : existingActions) {
+                        if (action.getAction() instanceof OutputActionCase) {
+                            actionList.add(action);
+                        }
+                    }
+                }
+           }
+        }
+
+        if (port != null) {
+            /* Create output action for this port*/
+            NodeConnectorId ncid = new NodeConnectorId("openflow:" + dpidLong + ":" + port);
+            OutputActionBuilder oab = new OutputActionBuilder();
+            oab.setOutputNodeConnector(ncid);
+            ab.setAction(new OutputActionCaseBuilder().setOutputAction(oab.build()).build());
+            ab.setOrder(actionList.size());
+            ab.setKey(new ActionKey(actionList.size()));
+            actionList.add(ab.build());
+        }
+        return createOutputApplyAction(ib, actionList);
+    }
+
     /**
      * add Output Port action to Instruction action list.
      * This is use for flow with single output port actions.
@@ -403,55 +578,6 @@ public class InstructionUtils {
         return ib;
     }
 
-    /**
-     * Creates Set Vlan ID Instruction along with VLAN Id match and NORMAL actions- This includes push vlan action, and set field -&gt; vlan vid action
-     * @param ib     Map InstructionBuilder without any instructions
-     * @param vlanId Integer representing a VLAN ID Integer representing a VLAN ID
-     * @return ib Map InstructionBuilder with instructions
-     */
-    public static InstructionBuilder createSetVlanAndNormalInstructions(InstructionBuilder ib, VlanId vlanId) {
-
-        List<Action> actionList = new ArrayList<>();
-        ActionBuilder ab = new ActionBuilder();
-
-        /* First we push vlan header */
-        PushVlanActionBuilder vlan = new PushVlanActionBuilder();
-        vlan.setEthernetType(IPV4);
-        ab.setAction(new PushVlanActionCaseBuilder().setPushVlanAction(vlan.build()).build());
-        ab.setOrder(0);
-        actionList.add(ab.build());
-
-        SetFieldBuilder setFieldBuilder = new SetFieldBuilder();
-
-        VlanMatchBuilder vlanBuilder1 = new VlanMatchBuilder();
-        VlanIdBuilder vlanIdBuilder = new VlanIdBuilder();
-        VlanId vlanId1 = new VlanId(vlanId);
-        vlanBuilder1.setVlanId(vlanIdBuilder.setVlanId(vlanId1).setVlanIdPresent(true).build());
-        setFieldBuilder.setVlanMatch(vlanBuilder1.build());
-        ab = new ActionBuilder();
-        ab.setAction(new SetFieldCaseBuilder().setSetField(setFieldBuilder.build()).build());
-        ab.setOrder(1);
-        actionList.add(ab.build());
-
-        ab = new ActionBuilder();
-        OutputActionBuilder output = new OutputActionBuilder();
-        output.setMaxLength(60);
-        Uri value = new Uri(OutputPortValues.NORMAL.toString());
-        output.setOutputNodeConnector(value);
-        ab.setAction(new OutputActionCaseBuilder().setOutputAction(output.build()).build());
-        ab.setOrder(2);
-        actionList.add(ab.build());
-
-        // Create an Apply Action
-        ApplyActionsBuilder aab = new ApplyActionsBuilder();
-        aab.setAction(actionList);
-
-        // Wrap our Apply Action in an Instruction
-        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
-
-        return ib;
-    }
-
     /**
      * Create Pop Vlan Instruction - this remove vlan header
      *
index c02abb05812430e052705df9d29853213a7179e5..304b52533410014ec9d995803ec94307a4e585c7 100644 (file)
@@ -244,6 +244,32 @@ public class MatchUtils {
         return matchBuilder;
     }
 
+    /**
+     * Create Ethernet Source and Destination Match
+     *
+     * @param matchBuilder MatchBuilder Object without a match yet
+     * @param sMacAddr     String representing a source MAC
+     * @param dMacAddr     String representing a destination MAC
+     * @param mask the mask of the Destination Mac Address
+     * @return matchBuilder Map MatchBuilder Object with a match
+     */
+    public static MatchBuilder createEthSrcDestMatch(MatchBuilder matchBuilder, MacAddress sMacAddr, MacAddress dMacAddr, MacAddress mask) {
+        EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder();
+        EthernetSourceBuilder ethSourceBuilder = new EthernetSourceBuilder();
+        ethSourceBuilder.setAddress(sMacAddr);
+        ethernetMatch.setEthernetSource(ethSourceBuilder.build());
+
+        EthernetDestinationBuilder ethDestinationBuilder = new EthernetDestinationBuilder();
+        ethDestinationBuilder.setAddress(dMacAddr);
+        if (mask != null) {
+            ethDestinationBuilder.setMask(mask);
+        }
+        ethernetMatch.setEthernetDestination(ethDestinationBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+
+        return matchBuilder;
+    }
+
     /**
      * Tunnel ID Match Builder
      *