*/
package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services;
+import java.math.BigInteger;
+import java.util.List;
+
+//import java.util.ListIterator;
+import org.opendaylight.ovsdb.openstack.netvirt.api.L2ForwardingProvider;
import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.ovsdb.utils.mdsal.openflow.ActionUtils;
+import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
+import org.opendaylight.ovsdb.utils.mdsal.openflow.MatchUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+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.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.Instructions;
+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.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.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxRegCaseBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
-public class L2ForwardingService extends AbstractServiceInstance {
+public class L2ForwardingService extends AbstractServiceInstance implements L2ForwardingProvider {
+ private static final Logger logger = LoggerFactory.getLogger(L2ForwardingService.class);
public L2ForwardingService() {
super(Service.L2_FORWARDING);
}
super(service);
}
+ /*
+ * (Table:L2Forwarding) Local Unicast
+ * Match: Tunnel ID and dMAC
+ * Action: Output Port
+ * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2 goto:<next-table>
+ */
+ @Override
+ public void programLocalUcastOut(Long dpidLong, String segmentationId,
+ Long localPort, String attachedMac, boolean write) {
+
+ String nodeName = OPENFLOW + dpidLong;
+
+ MatchBuilder matchBuilder = new MatchBuilder();
+ NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+ FlowBuilder flowBuilder = new FlowBuilder();
+
+ // Create the OF Match using MatchBuilder
+ flowBuilder.setMatch(MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId)).build());
+ flowBuilder.setMatch(MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(attachedMac), null).build());
+
+ String flowId = "UcastOut_"+segmentationId+"_"+localPort+"_"+attachedMac;
+ // Add Flow Attributes
+ flowBuilder.setId(new FlowId(flowId));
+ FlowKey key = new FlowKey(new FlowId(flowId));
+ flowBuilder.setStrict(true);
+ flowBuilder.setBarrier(false);
+ flowBuilder.setTableId(getTable());
+ flowBuilder.setKey(key);
+ flowBuilder.setFlowName(flowId);
+ flowBuilder.setHardTimeout(0);
+ flowBuilder.setIdleTimeout(0);
+
+ if (write) {
+ // Instantiate the Builders for the OF Actions and Instructions
+ InstructionBuilder ib = new InstructionBuilder();
+ InstructionsBuilder isb = new InstructionsBuilder();
+
+ // Instructions List Stores Individual Instructions
+ List<Instruction> instructions = Lists.newArrayList();
+
+ // Set the Output Port/Iface
+ InstructionUtils.createOutputPortInstructions(ib, dpidLong, localPort);
+ ib.setOrder(0);
+ ib.setKey(new InstructionKey(0));
+ instructions.add(ib.build());
+
+ // Add InstructionBuilder to the Instruction(s)Builder List
+ isb.setInstruction(instructions);
+
+ // Add InstructionsBuilder to FlowBuilder
+ flowBuilder.setInstructions(isb.build());
+ writeFlow(flowBuilder, nodeBuilder);
+ } else {
+ removeFlow(flowBuilder, nodeBuilder);
+ }
+ }
+ /*
+ * (Table:2) Local VLAN unicast
+ * Match: VLAN ID and dMAC
+ * Action: Output Port
+ * table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
+ * table=110,dl_vlan=2001,dl_dst=fa:16:3e:a3:3b:cc actions=pop_vlan,output:1
+ */
+
+ @Override
+ public void programLocalVlanUcastOut (Long dpidLong, String segmentationId, Long localPort, String attachedMac, boolean write) {
+
+ String nodeName = OPENFLOW + dpidLong;
+
+ MatchBuilder matchBuilder = new MatchBuilder();
+ NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+ FlowBuilder flowBuilder = new FlowBuilder();
+
+ // Create the OF Match using MatchBuilder
+ flowBuilder.setMatch(
+ MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId)), true).build());
+ flowBuilder.setMatch(MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(attachedMac), null).build());
+
+ String flowId = "VlanUcastOut_"+segmentationId+"_"+localPort+"_"+attachedMac;
+ // Add Flow Attributes
+ flowBuilder.setId(new FlowId(flowId));
+ FlowKey key = new FlowKey(new FlowId(flowId));
+ flowBuilder.setStrict(true);
+ flowBuilder.setBarrier(false);
+ flowBuilder.setTableId(getTable());
+ flowBuilder.setKey(key);
+ flowBuilder.setFlowName(flowId);
+ flowBuilder.setHardTimeout(0);
+ flowBuilder.setIdleTimeout(0);
+
+ if (write) {
+ // Instantiate the Builders for the OF Actions and Instructions
+ InstructionBuilder ib = new InstructionBuilder();
+ InstructionsBuilder isb = new InstructionsBuilder();
+
+ // Instructions List Stores Individual Instructions
+ List<Instruction> instructions = Lists.newArrayList();
+ List<Instruction> instructions_tmp = Lists.newArrayList();
+
+ /* Strip vlan and store to tmp instruction space*/
+ InstructionUtils.createPopVlanInstructions(ib);
+ ib.setOrder(0);
+ ib.setKey(new InstructionKey(0));
+ instructions_tmp.add(ib.build());
+
+ // Set the Output Port/Iface
+ ib = new InstructionBuilder();
+ InstructionUtils.addOutputPortInstructions(ib, dpidLong, localPort, instructions_tmp);
+ ib.setOrder(1);
+ ib.setKey(new InstructionKey(0));
+ instructions.add(ib.build());
+
+ // Add InstructionBuilder to the Instruction(s)Builder List
+ isb.setInstruction(instructions);
+
+ // Add InstructionsBuilder to FlowBuilder
+ flowBuilder.setInstructions(isb.build());
+ writeFlow(flowBuilder, nodeBuilder);
+ } else {
+ removeFlow(flowBuilder, nodeBuilder);
+ }
+ }
+
+
+ /**
+ * Utility function used by the flooding logic to allow a flow to be resubmitted
+ * to the local port flooding rule, after being outputed to all available tunnel
+ * or VLAN egress ports.
+ */
+ private void appendResubmitLocalFlood(InstructionBuilder ib) {
+
+ //Update the ApplyActions instructions
+ ApplyActionsCase aac = (ApplyActionsCase) ib.getInstruction();
+ List<Action> actionList = aac.getApplyActions().getAction();
+
+ int index = actionList.size();
+ ActionBuilder ab = new ActionBuilder();
+ ab.setAction(ActionUtils.nxLoadRegAction(new DstNxRegCaseBuilder().setNxReg(ClassifierService.REG_FIELD).build(),
+ BigInteger.valueOf(ClassifierService.REG_VALUE_FROM_REMOTE)));
+ ab.setOrder(index);
+ ab.setKey(new ActionKey(index));
+ actionList.add(ab.build());
+
+ index++;
+ ab = new ActionBuilder();
+ ab.setAction(ActionUtils.nxResubmitAction(null, this.getTable()));
+ ab.setOrder(index);
+ ab.setKey(new ActionKey(index));
+ actionList.add(ab.build());
+ }
+
+ /*
+ * (Table:2) Local Broadcast Flood
+ * Match: Tunnel ID and dMAC (::::FF:FF)
+ * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+ * actions=output:2,3,4,5
+ */
+
+ @Override
+ public void programLocalBcastOut(Long dpidLong, String segmentationId, Long localPort, boolean write) {
+
+ String nodeName = OPENFLOW + dpidLong;
+
+ MatchBuilder matchBuilder = new MatchBuilder();
+ NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+ FlowBuilder flowBuilder = new FlowBuilder();
+
+ // Create the OF Match using MatchBuilder
+ MatchUtils.addNxRegMatch(matchBuilder, new MatchUtils.RegMatch(ClassifierService.REG_FIELD, ClassifierService.REG_VALUE_FROM_REMOTE));
+ flowBuilder.setMatch(MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId)).build());
+ flowBuilder.setMatch(MatchUtils.createDestEthMatch(matchBuilder, new MacAddress("01:00:00:00:00:00"),
+ new MacAddress("01:00:00:00:00:00")).build());
+
+ String flowId = "BcastOut_"+segmentationId;
+ // Add Flow Attributes
+ flowBuilder.setId(new FlowId(flowId));
+ FlowKey key = new FlowKey(new FlowId(flowId));
+ flowBuilder.setStrict(true);
+ flowBuilder.setBarrier(false);
+ flowBuilder.setTableId(getTable());
+ flowBuilder.setKey(key);
+ flowBuilder.setPriority(16384);
+ flowBuilder.setFlowName(flowId);
+ flowBuilder.setHardTimeout(0);
+ flowBuilder.setIdleTimeout(0);
+ Flow flow = this.getFlow(flowBuilder, nodeBuilder);
+ // Instantiate the Builders for the OF Actions and Instructions
+ InstructionBuilder ib = new InstructionBuilder();
+ InstructionsBuilder isb = new InstructionsBuilder();
+ List<Instruction> instructions = Lists.newArrayList();
+ List<Instruction> existingInstructions = null;
+ if (flow != null) {
+ Instructions ins = flow.getInstructions();
+ if (ins != null) {
+ existingInstructions = ins.getInstruction();
+ }
+ }
+
+ if (write) {
+ // Create output port list
+ createOutputPortInstructions(ib, dpidLong, localPort, existingInstructions);
+ ib.setOrder(0);
+ ib.setKey(new InstructionKey(0));
+
+ /* Alternative method to address Bug 2004 is to make a call
+ * here to appendResubmitLocalFlood(ib) so that we send the
+ * flow back to the local flood rule.
+ */
+ instructions.add(ib.build());
+
+ // Add InstructionBuilder to the Instruction(s)Builder List
+ isb.setInstruction(instructions);
+
+ // Add InstructionsBuilder to FlowBuilder
+ flowBuilder.setInstructions(isb.build());
+
+ writeFlow(flowBuilder, nodeBuilder);
+ } else {
+ boolean flowRemove = InstructionUtils.removeOutputPortFromInstructions(ib, dpidLong, localPort,
+ existingInstructions);
+ if (flowRemove) {
+ /* if all ports are removed, remove flow */
+ removeFlow(flowBuilder, nodeBuilder);
+ } else {
+ /* Install instruction with new output port list*/
+ ib.setOrder(0);
+ ib.setKey(new InstructionKey(0));
+ instructions.add(ib.build());
+
+ // Add InstructionBuilder to the Instruction(s)Builder List
+ isb.setInstruction(instructions);
+
+ // Add InstructionsBuilder to FlowBuilder
+ flowBuilder.setInstructions(isb.build());
+ writeFlow(flowBuilder, nodeBuilder);
+ }
+ }
+ }
+
+ /*
+ * (Table:2) Local VLAN Broadcast Flood
+ * Match: vlan ID and dMAC (::::FF:FF)
+ * table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+ * actions=strip_vlan, output:2,3,4,5
+ * table=110,dl_vlan=2001,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=output:2,pop_vlan,output:1,output:3,output:4
+ */
+
+ @Override
+ public void programLocalVlanBcastOut(Long dpidLong, String segmentationId,
+ Long localPort, Long ethPort, boolean write) {
+
+ String nodeName = OPENFLOW + dpidLong;
+
+ MatchBuilder matchBuilder = new MatchBuilder();
+ NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+ FlowBuilder flowBuilder = new FlowBuilder();
+
+ // Create the OF Match using MatchBuilder
+ flowBuilder.setMatch(
+ MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId)), true).build());
+ flowBuilder.setMatch(MatchUtils.createDestEthMatch(matchBuilder, new MacAddress("01:00:00:00:00:00"),
+ new MacAddress("01:00:00:00:00:00")).build());
+
+ String flowId = "VlanBcastOut_"+segmentationId+"_"+ethPort;
+ // Add Flow Attributes
+ flowBuilder.setId(new FlowId(flowId));
+ FlowKey key = new FlowKey(new FlowId(flowId));
+ flowBuilder.setStrict(true);
+ flowBuilder.setBarrier(false);
+ flowBuilder.setTableId(getTable());
+ flowBuilder.setKey(key);
+ flowBuilder.setPriority(16384);
+ flowBuilder.setFlowName(flowId);
+ flowBuilder.setHardTimeout(0);
+ flowBuilder.setIdleTimeout(0);
+ Flow flow = this.getFlow(flowBuilder, nodeBuilder);
+ // Instantiate the Builders for the OF Actions and Instructions
+ List<Instruction> existingInstructions = null;
+ if (flow != null) {
+ Instructions ins = flow.getInstructions();
+ if (ins != null) {
+ existingInstructions = ins.getInstruction();
+ }
+ }
+
+ List<Instruction> instructions = Lists.newArrayList();
+ InstructionBuilder ib = new InstructionBuilder();
+ List<Action> actionList = null;
+ if (write) {
+ if (existingInstructions == null) {
+ /* First time called there should be no instructions.
+ * We can simply add the output:ethPort first, followed by
+ * popVlan and then the local port. The next calls will append
+ * the rest of the local ports.
+ */
+ ActionBuilder ab = new ActionBuilder();
+ actionList = Lists.newArrayList();
+
+ ab.setAction(ActionUtils.outputAction(new NodeConnectorId(nodeName + ":" + ethPort)));
+ ab.setOrder(0);
+ ab.setKey(new ActionKey(0));
+ actionList.add(ab.build());
+
+ ab.setAction(ActionUtils.popVlanAction());
+ ab.setOrder(1);
+ ab.setKey(new ActionKey(1));
+ actionList.add(ab.build());
+
+ ab.setAction(ActionUtils.outputAction(new NodeConnectorId(nodeName + ":" + localPort)));
+ ab.setOrder(2);
+ ab.setKey(new ActionKey(2));
+ actionList.add(ab.build());
+ } else {
+ /* Subsequent calls require appending any new local ports for this tenant. */
+ ApplyActionsCase aac = (ApplyActionsCase) ib.getInstruction();
+ Instruction in = existingInstructions.get(0);
+ actionList = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
+
+ NodeConnectorId ncid = new NodeConnectorId(nodeName + ":" + localPort);
+ boolean addNew = true;
+
+ /* Check if the port is already in the output list */
+ for (Action action : actionList) {
+ if (action.getAction() instanceof OutputActionCase) {
+ OutputActionCase opAction = (OutputActionCase) action.getAction();
+ if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
+ addNew = false;
+ break;
+ }
+ }
+ }
+
+ if (addNew) {
+ ActionBuilder ab = new ActionBuilder();
+
+ ab.setAction(ActionUtils.outputAction(new NodeConnectorId(nodeName + ":" + localPort)));
+ ab.setOrder(actionList.size());
+ ab.setKey(new ActionKey(actionList.size()));
+ actionList.add(ab.build());
+ }
+ }
+
+ ApplyActionsBuilder aab = new ApplyActionsBuilder();
+ aab.setAction(actionList);
+ ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+ ib.setOrder(0);
+ ib.setKey(new InstructionKey(0));
+ instructions.add(ib.build());
+
+ // Add InstructionBuilder to the Instruction(s)Builder List
+ InstructionsBuilder isb = new InstructionsBuilder();
+ isb.setInstruction(instructions);
+
+ // Add InstructionsBuilder to FlowBuilder
+ flowBuilder.setInstructions(isb.build());
+ writeFlow(flowBuilder, nodeBuilder);
+ } else {
+ //boolean flowRemove = removeOutputPortFromGroup(nodeBuilder, ib, dpidLong,
+ // localPort, existingInstructions);
+ boolean flowRemove = removeOutputPortFromInstructions(ib, dpidLong, localPort, ethPort,
+ existingInstructions);
+ if (flowRemove) {
+ /* if all ports are removed, remove flow */
+ removeFlow(flowBuilder, nodeBuilder);
+ } else {
+ /* Install instruction with new output port list*/
+ ib.setOrder(0);
+ ib.setKey(new InstructionKey(0));
+ instructions.add(ib.build());
+
+ // Add InstructionBuilder to the Instruction(s)Builder List
+ InstructionsBuilder isb = new InstructionsBuilder();
+ isb.setInstruction(instructions);
+
+ // Add InstructionsBuilder to FlowBuilder
+ flowBuilder.setInstructions(isb.build());
+ writeFlow(flowBuilder, nodeBuilder);
+ }
+ }
+ }
+
+ private boolean removeOutputPortFromInstructions(InstructionBuilder ib, Long dpidLong, Long localPort,
+ Long ethPort, List<Instruction> instructions) {
+ List<Action> actionList = Lists.newArrayList();
+ boolean removeFlow = true;
+
+ if (instructions != null) {
+ ApplyActionsCase aac = (ApplyActionsCase) ib.getInstruction();
+ Instruction in = instructions.get(0);
+ List<Action> oldActionList = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
+ NodeConnectorId ncid = new NodeConnectorId(OPENFLOW + dpidLong + ":" + localPort);
+ NodeConnectorId ncidEth = new NodeConnectorId(OPENFLOW + dpidLong + ":" + ethPort);
+
+ // Remove the port from the output list
+ ActionBuilder ab = new ActionBuilder();
+ int index = 2;
+ //for (ListIterator<Action> it = oldActionList.listIterator(oldActionList.size()); it.hasPrevious();) {
+ // Action action = it.previous();
+ for (Action action : oldActionList) {
+ if (action.getAction() instanceof OutputActionCase) {
+ OutputActionCase opAction = (OutputActionCase) action.getAction();
+ if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncidEth))) {
+ actionList.add(action);
+ } else if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid)) == false) {
+ ab.setAction(action.getAction());
+ ab.setOrder(index);
+ ab.setKey(new ActionKey(index));
+ actionList.add(ab.build());
+ index++;
+ }
+ } else {
+ actionList.add(action);
+ }
+ }
+ ApplyActionsBuilder aab = new ApplyActionsBuilder();
+ aab.setAction(actionList);
+ ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+ }
+
+ if (actionList != null && actionList.size() > 2) {
+ // Add InstructionBuilder to the Instruction(s)Builder List
+ InstructionsBuilder isb = new InstructionsBuilder();
+ isb.setInstruction(instructions);
+ removeFlow = false;
+ }
+
+ return removeFlow;
+ }
+
+ /*
+ * (Table:1) Local Table Miss
+ * Match: Any Remaining Flows w/a TunID
+ * Action: Drop w/ a low priority
+ * table=2,priority=8192,tun_id=0x5 actions=drop
+ */
+
+ @Override
+ public void programLocalTableMiss(Long dpidLong, String segmentationId, boolean write) {
+
+ String nodeName = OPENFLOW + dpidLong;
+
+ MatchBuilder matchBuilder = new MatchBuilder();
+ NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+ FlowBuilder flowBuilder = new FlowBuilder();
+
+ // Create Match(es) and Set them in the FlowBuilder Object
+ flowBuilder.setMatch(MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId)).build());
+
+ if (write) {
+ // Create the OF Actions and Instructions
+ InstructionBuilder ib = new InstructionBuilder();
+ InstructionsBuilder isb = new InstructionsBuilder();
+
+ // Instructions List Stores Individual Instructions
+ List<Instruction> instructions = Lists.newArrayList();
+
+ // Call the InstructionBuilder Methods Containing Actions
+ InstructionUtils.createDropInstructions(ib);
+ ib.setOrder(0);
+ ib.setKey(new InstructionKey(0));
+ instructions.add(ib.build());
+
+ // Add InstructionBuilder to the Instruction(s)Builder List
+ isb.setInstruction(instructions);
+
+ // Add InstructionsBuilder to FlowBuilder
+ flowBuilder.setInstructions(isb.build());
+ }
+
+ String flowId = "LocalTableMiss_"+segmentationId;
+ // Add Flow Attributes
+ flowBuilder.setId(new FlowId(flowId));
+ FlowKey key = new FlowKey(new FlowId(flowId));
+ flowBuilder.setStrict(true);
+ flowBuilder.setBarrier(false);
+ flowBuilder.setTableId(getTable());
+ flowBuilder.setKey(key);
+ flowBuilder.setPriority(8192);
+ flowBuilder.setFlowName(flowId);
+ flowBuilder.setHardTimeout(0);
+ flowBuilder.setIdleTimeout(0);
+ if (write) {
+ writeFlow(flowBuilder, nodeBuilder);
+ } else {
+ removeFlow(flowBuilder, nodeBuilder);
+ }
+ }
+
+ /*
+ * (Table:1) Local Table Miss
+ * Match: Any Remaining Flows w/a VLAN ID
+ * Action: Drop w/ a low priority
+ * table=2,priority=8192,vlan_id=0x5 actions=drop
+ */
+
+ @Override
+ public void programLocalVlanTableMiss(Long dpidLong, String segmentationId, boolean write) {
+
+ String nodeName = OPENFLOW + dpidLong;
+
+ MatchBuilder matchBuilder = new MatchBuilder();
+ NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+ FlowBuilder flowBuilder = new FlowBuilder();
+
+ // Create Match(es) and Set them in the FlowBuilder Object
+ flowBuilder.setMatch(
+ MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId)), true).build());
+
+ if (write) {
+ // Create the OF Actions and Instructions
+ InstructionBuilder ib = new InstructionBuilder();
+ InstructionsBuilder isb = new InstructionsBuilder();
+
+ // Instructions List Stores Individual Instructions
+ List<Instruction> instructions = Lists.newArrayList();
+
+ // Call the InstructionBuilder Methods Containing Actions
+ InstructionUtils.createDropInstructions(ib);
+ ib.setOrder(0);
+ ib.setKey(new InstructionKey(0));
+ instructions.add(ib.build());
+
+ // Add InstructionBuilder to the Instruction(s)Builder List
+ isb.setInstruction(instructions);
+
+ // Add InstructionsBuilder to FlowBuilder
+ flowBuilder.setInstructions(isb.build());
+ }
+
+ String flowId = "LocalTableMiss_"+segmentationId;
+ // Add Flow Attributes
+ flowBuilder.setId(new FlowId(flowId));
+ FlowKey key = new FlowKey(new FlowId(flowId));
+ flowBuilder.setStrict(true);
+ flowBuilder.setBarrier(false);
+ flowBuilder.setTableId(getTable());
+ flowBuilder.setKey(key);
+ flowBuilder.setPriority(8192);
+ flowBuilder.setFlowName(flowId);
+ flowBuilder.setHardTimeout(0);
+ flowBuilder.setIdleTimeout(0);
+ if (write) {
+ writeFlow(flowBuilder, nodeBuilder);
+ } else {
+ removeFlow(flowBuilder, nodeBuilder);
+ }
+ }
+
+
+ /*
+ * (Table:1) Egress Tunnel Traffic
+ * Match: Destination Ethernet Addr and Local InPort
+ * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
+ * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
+ * actions=output:10,goto_table:2"
+ */
+ // TODO : Check on the reason why the original handleTunnelOut was chaining the traffic to table 2
+ @Override
+ public void programTunnelOut(Long dpidLong, String segmentationId, Long OFPortOut, String attachedMac, boolean write) {
+
+ String nodeName = OPENFLOW + dpidLong;
+
+ MatchBuilder matchBuilder = new MatchBuilder();
+ NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+ FlowBuilder flowBuilder = new FlowBuilder();
+
+ // Create the OF Match using MatchBuilder
+ flowBuilder.setMatch(MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId)).build());
+ flowBuilder.setMatch(MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(attachedMac), null).build());
+
+ String flowId = "TunnelOut_"+segmentationId+"_"+OFPortOut+"_"+attachedMac;
+ // Add Flow Attributes
+ flowBuilder.setId(new FlowId(flowId));
+ FlowKey key = new FlowKey(new FlowId(flowId));
+ flowBuilder.setStrict(true);
+ flowBuilder.setBarrier(false);
+ flowBuilder.setTableId(getTable());
+ flowBuilder.setKey(key);
+ flowBuilder.setFlowName(flowId);
+ flowBuilder.setHardTimeout(0);
+ flowBuilder.setIdleTimeout(0);
+
+ if (write) {
+ // Instantiate the Builders for the OF Actions and Instructions
+ InstructionBuilder ib = new InstructionBuilder();
+ InstructionsBuilder isb = new InstructionsBuilder();
+
+ // Instructions List Stores Individual Instructions
+ List<Instruction> instructions = Lists.newArrayList();
+
+ // Set the Output Port/Iface
+ InstructionUtils.createOutputPortInstructions(ib, dpidLong, OFPortOut);
+ ib.setOrder(0);
+ ib.setKey(new InstructionKey(1));
+ instructions.add(ib.build());
+
+ // Add InstructionBuilder to the Instruction(s)Builder List
+ isb.setInstruction(instructions);
+
+ // Add InstructionsBuilder to FlowBuilder
+ flowBuilder.setInstructions(isb.build());
+
+ writeFlow(flowBuilder, nodeBuilder);
+ } else {
+ removeFlow(flowBuilder, nodeBuilder);
+ }
+ }
+
+ /*
+ * (Table:1) Egress VLAN Traffic
+ * Match: Destination Ethernet Addr and VLAN id
+ * Instruction: GOTO Table Table 2
+ * table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
+ * actions= goto_table:2"
+ */
+ // TODO : Check on the reason why the original handleTunnelOut was chaining the traffic to table 2
@Override
- public boolean isBridgeInPipeline (String nodeId) {
- return true;
+ public void programVlanOut(Long dpidLong, String segmentationId, Long ethPort, String attachedMac, boolean write) {
+
+ String nodeName = OPENFLOW + dpidLong;
+
+ MatchBuilder matchBuilder = new MatchBuilder();
+ NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+ FlowBuilder flowBuilder = new FlowBuilder();
+
+ // Create the OF Match using MatchBuilder
+ flowBuilder.setMatch(
+ MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId)), true).build());
+ flowBuilder.setMatch(MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(attachedMac), null).build());
+
+ String flowId = "VlanOut_"+segmentationId+"_"+ethPort+"_"+attachedMac;
+ // Add Flow Attributes
+ flowBuilder.setId(new FlowId(flowId));
+ FlowKey key = new FlowKey(new FlowId(flowId));
+ flowBuilder.setStrict(true);
+ flowBuilder.setBarrier(false);
+ flowBuilder.setTableId(getTable());
+ flowBuilder.setKey(key);
+ flowBuilder.setFlowName(flowId);
+ flowBuilder.setHardTimeout(0);
+ flowBuilder.setIdleTimeout(0);
+
+ if (write) {
+ // Instantiate the Builders for the OF Actions and Instructions
+ InstructionBuilder ib = new InstructionBuilder();
+ InstructionsBuilder isb = new InstructionsBuilder();
+
+ // Instructions List Stores Individual Instructions
+ List<Instruction> instructions = Lists.newArrayList();
+ InstructionUtils.createOutputPortInstructions(ib, dpidLong, ethPort);
+ ib.setOrder(0);
+ ib.setKey(new InstructionKey(1));
+ instructions.add(ib.build());
+
+ // Add InstructionBuilder to the Instruction(s)Builder List
+ isb.setInstruction(instructions);
+
+ // Add InstructionsBuilder to FlowBuilder
+ flowBuilder.setInstructions(isb.build());
+
+ writeFlow(flowBuilder, nodeBuilder);
+ } else {
+ removeFlow(flowBuilder, nodeBuilder);
+ }
+ }
+
+ /*
+ * (Table:1) Egress Tunnel Traffic
+ * Match: Destination Ethernet Addr and Local InPort
+ * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
+ * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+ * actions=output:10,output:11,goto_table:2
+ */
+ @Override
+ public void programTunnelFloodOut(Long dpidLong, String segmentationId, Long OFPortOut, boolean write) {
+
+ String nodeName = OPENFLOW + dpidLong;
+
+ MatchBuilder matchBuilder = new MatchBuilder();
+ NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+ FlowBuilder flowBuilder = new FlowBuilder();
+
+ // Create the OF Match using MatchBuilder
+ // Match TunnelID
+ MatchUtils.addNxRegMatch(matchBuilder, new MatchUtils.RegMatch(ClassifierService.REG_FIELD, ClassifierService.REG_VALUE_FROM_LOCAL));
+ flowBuilder.setMatch(MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId)).build());
+ // Match DMAC
+ flowBuilder.setMatch(MatchUtils.createDestEthMatch(matchBuilder, new MacAddress("01:00:00:00:00:00"),
+ new MacAddress("01:00:00:00:00:00")).build());
+
+ String flowId = "TunnelFloodOut_"+segmentationId;
+ // Add Flow Attributes
+ flowBuilder.setId(new FlowId(flowId));
+ FlowKey key = new FlowKey(new FlowId(flowId));
+ flowBuilder.setBarrier(true);
+ flowBuilder.setTableId(getTable());
+ flowBuilder.setKey(key);
+ flowBuilder.setPriority(16383); // FIXME: change it back to 16384 once bug 3005 is fixed.
+ flowBuilder.setFlowName(flowId);
+ flowBuilder.setHardTimeout(0);
+ flowBuilder.setIdleTimeout(0);
+
+ Flow flow = this.getFlow(flowBuilder, nodeBuilder);
+ // Instantiate the Builders for the OF Actions and Instructions
+ InstructionBuilder ib = new InstructionBuilder();
+ InstructionsBuilder isb = new InstructionsBuilder();
+ List<Instruction> instructions = Lists.newArrayList();
+ List<Instruction> existingInstructions = null;
+ if (flow != null) {
+ Instructions ins = flow.getInstructions();
+ if (ins != null) {
+ existingInstructions = ins.getInstruction();
+ }
+ }
+
+ if (write) {
+ // Set the Output Port/Iface
+ //createOutputGroupInstructions(nodeBuilder, ib, dpidLong, OFPortOut, existingInstructions);
+ createOutputPortInstructions(ib, dpidLong, OFPortOut, existingInstructions);
+ ib.setOrder(0);
+ ib.setKey(new InstructionKey(0));
+ instructions.add(ib.build());
+
+ // Add InstructionBuilder to the Instruction(s)Builder List
+ isb.setInstruction(instructions);
+
+ // Add InstructionsBuilder to FlowBuilder
+ flowBuilder.setInstructions(isb.build());
+
+ writeFlow(flowBuilder, nodeBuilder);
+ } else {
+ /* remove port from action list */
+ boolean flowRemove = InstructionUtils.removeOutputPortFromInstructions(ib, dpidLong,
+ OFPortOut, existingInstructions);
+ if (flowRemove) {
+ /* if all port are removed, remove the flow too. */
+ removeFlow(flowBuilder, nodeBuilder);
+ } else {
+ /* Install instruction with new output port list*/
+ ib.setOrder(0);
+ ib.setKey(new InstructionKey(0));
+ instructions.add(ib.build());
+
+ // Add InstructionBuilder to the Instruction(s)Builder List
+ isb.setInstruction(instructions);
+
+ // Add InstructionsBuilder to FlowBuilder
+ flowBuilder.setInstructions(isb.build());
+ writeFlow(flowBuilder, nodeBuilder);
+ }
+ }
+ }
+
+ /*
+ * (Table:1) Egress VLAN Traffic
+ * Match: Destination Ethernet Addr and VLAN id
+ * Instruction: GOTO table 2 and Output port eth interface
+ * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+ * actions=output:eth1,goto_table:2
+ */
+
+ @Override
+ public void programVlanFloodOut(Long dpidLong, String segmentationId, Long ethPort, boolean write) {
+
+ String nodeName = OPENFLOW + dpidLong;
+
+ MatchBuilder matchBuilder = new MatchBuilder();
+ NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+ FlowBuilder flowBuilder = new FlowBuilder();
+
+ // Create the OF Match using MatchBuilder
+ // Match Vlan ID
+ flowBuilder.setMatch(
+ MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId)), true).build());
+ // Match DMAC
+ flowBuilder.setMatch(MatchUtils.createDestEthMatch(matchBuilder, new MacAddress("01:00:00:00:00:00"),
+ new MacAddress("01:00:00:00:00:00")).build());
+
+ String flowId = "VlanFloodOut_"+segmentationId+"_"+ethPort;
+ // Add Flow Attributes
+ flowBuilder.setId(new FlowId(flowId));
+ FlowKey key = new FlowKey(new FlowId(flowId));
+ flowBuilder.setBarrier(true);
+ flowBuilder.setTableId(getTable());
+ flowBuilder.setKey(key);
+ flowBuilder.setPriority(16384);
+ flowBuilder.setFlowName(flowId);
+ flowBuilder.setHardTimeout(0);
+ flowBuilder.setIdleTimeout(0);
+
+ //ToDo: Is there something to be done with result of the call to getFlow?
+
+ Flow flow = this.getFlow(flowBuilder, nodeBuilder);
+ // Instantiate the Builders for the OF Actions and Instructions
+ InstructionBuilder ib = new InstructionBuilder();
+ InstructionsBuilder isb = new InstructionsBuilder();
+ List<Instruction> instructions = Lists.newArrayList();
+
+ if (write) {
+ // Set the Output Port/Iface
+ InstructionUtils.createOutputPortInstructions(ib, dpidLong, ethPort);
+ ib.setOrder(0);
+ ib.setKey(new InstructionKey(0));
+ instructions.add(ib.build());
+
+ // Add InstructionBuilder to the Instruction(s)Builder List
+ isb.setInstruction(instructions);
+
+ // Add InstructionsBuilder to FlowBuilder
+ flowBuilder.setInstructions(isb.build());
+
+ writeFlow(flowBuilder, nodeBuilder);
+ } else {
+ removeFlow(flowBuilder, nodeBuilder);
+ }
+ }
+
+ /*
+ * (Table:1) Table Drain w/ Catch All
+ * Match: Tunnel ID
+ * Action: GOTO Local Table (10)
+ * table=2,priority=8192,tun_id=0x5 actions=drop
+ */
+ @Override
+ public void programTunnelMiss(Long dpidLong, String segmentationId, boolean write) {
+
+ String nodeName = OPENFLOW + dpidLong;
+
+ MatchBuilder matchBuilder = new MatchBuilder();
+ NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+ FlowBuilder flowBuilder = new FlowBuilder();
+
+ // Create Match(es) and Set them in the FlowBuilder Object
+ flowBuilder.setMatch(MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId)).build());
+
+ if (write) {
+ // Create the OF Actions and Instructions
+ InstructionBuilder ib = new InstructionBuilder();
+ InstructionsBuilder isb = new InstructionsBuilder();
+
+ // Instructions List Stores Individual Instructions
+ List<Instruction> instructions = Lists.newArrayList();
+
+ // Call the InstructionBuilder Methods Containing Actions
+ ib = this.getMutablePipelineInstructionBuilder();
+ ib.setOrder(0);
+ ib.setKey(new InstructionKey(0));
+ instructions.add(ib.build());
+
+ // Add InstructionBuilder to the Instruction(s)Builder List
+ isb.setInstruction(instructions);
+
+ // Add InstructionsBuilder to FlowBuilder
+ flowBuilder.setInstructions(isb.build());
+ }
+
+ String flowId = "TunnelMiss_"+segmentationId;
+ // Add Flow Attributes
+ flowBuilder.setId(new FlowId(flowId));
+ FlowKey key = new FlowKey(new FlowId(flowId));
+ flowBuilder.setStrict(true);
+ flowBuilder.setBarrier(false);
+ flowBuilder.setTableId(getTable());
+ flowBuilder.setKey(key);
+ flowBuilder.setPriority(8192);
+ flowBuilder.setFlowName(flowId);
+ flowBuilder.setHardTimeout(0);
+ flowBuilder.setIdleTimeout(0);
+ if (write) {
+ writeFlow(flowBuilder, nodeBuilder);
+ } else {
+ removeFlow(flowBuilder, nodeBuilder);
+ }
+ }
+
+ /*
+ * (Table:1) Table Drain w/ Catch All
+ * Match: Vlan ID
+ * Action: Output port eth interface
+ * table=1,priority=8192,vlan_id=0x5 actions= output port:eth1
+ * table=110,priority=8192,dl_vlan=2001 actions=output:2
+ */
+
+ @Override
+ public void programVlanMiss(Long dpidLong, String segmentationId, Long ethPort, boolean write) {
+
+ String nodeName = OPENFLOW + dpidLong;
+
+ MatchBuilder matchBuilder = new MatchBuilder();
+ NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+ FlowBuilder flowBuilder = new FlowBuilder();
+
+ // Create Match(es) and Set them in the FlowBuilder Object
+ flowBuilder.setMatch(
+ MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId)), true).build());
+
+ if (write) {
+ // Create the OF Actions and Instructions
+ InstructionBuilder ib = new InstructionBuilder();
+ InstructionsBuilder isb = new InstructionsBuilder();
+
+ // Instructions List Stores Individual Instructions
+ List<Instruction> instructions = Lists.newArrayList();
+
+ // Set the Output Port/Iface
+ InstructionUtils.createOutputPortInstructions(ib, dpidLong, ethPort);
+ ib.setOrder(0);
+ ib.setKey(new InstructionKey(1));
+ instructions.add(ib.build());
+
+ // Add InstructionBuilder to the Instruction(s)Builder List
+ isb.setInstruction(instructions);
+
+ // Add InstructionsBuilder to FlowBuilder
+ flowBuilder.setInstructions(isb.build());
+ }
+
+ String flowId = "VlanMiss_"+segmentationId;
+ // Add Flow Attributes
+ flowBuilder.setId(new FlowId(flowId));
+ FlowKey key = new FlowKey(new FlowId(flowId));
+ flowBuilder.setStrict(true);
+ flowBuilder.setBarrier(false);
+ flowBuilder.setTableId(getTable());
+ flowBuilder.setKey(key);
+ flowBuilder.setPriority(8192);
+ flowBuilder.setFlowName(flowId);
+ flowBuilder.setHardTimeout(0);
+ flowBuilder.setIdleTimeout(0);
+ if (write) {
+ writeFlow(flowBuilder, nodeBuilder);
+ } else {
+ removeFlow(flowBuilder, nodeBuilder);
+ }
+ }
+
+ /**
+ * Create Output Port Group Instruction
+ *
+ * @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
+ * @return ib InstructionBuilder Map with instructions
+ */
+ protected InstructionBuilder createOutputPortInstructions(InstructionBuilder ib,
+ Long dpidLong, Long port ,
+ List<Instruction> instructions) {
+ NodeConnectorId ncid = new NodeConnectorId(OPENFLOW + dpidLong + ":" + port);
+ logger.debug("createOutputPortInstructions() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
+
+ List<Action> actionList = Lists.newArrayList();
+ ActionBuilder ab = new ActionBuilder();
+
+ List<Action> existingActions;
+ if (instructions != null && instructions.size() > 0) {
+ /**
+ * First instruction is the one containing the output ports.
+ * So, only extract the actions from that.
+ */
+ Instruction in = instructions.get(0);
+ if (in.getInstruction() instanceof ApplyActionsCase) {
+ existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
+ // Only include output actions
+ for (Action action : existingActions)
+ if (action.getAction() instanceof OutputActionCase)
+ actionList.add(action);
+ }
+ }
+ /* Create output action for this port*/
+ OutputActionBuilder oab = new OutputActionBuilder();
+ oab.setOutputNodeConnector(ncid);
+ ab.setAction(new OutputActionCaseBuilder().setOutputAction(oab.build()).build());
+ boolean addNew = true;
+
+ /* Find the group action and get the group */
+ for (Action action : actionList) {
+ OutputActionCase opAction = (OutputActionCase)action.getAction();
+ /* If output port action already in the action list of one of the buckets, skip */
+ if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
+ addNew = false;
+ break;
+ }
+ }
+ if (addNew) {
+ ab.setOrder(actionList.size());
+ ab.setKey(new ActionKey(actionList.size()));
+ actionList.add(ab.build());
+ }
+ // Create an Apply Action
+ ApplyActionsBuilder aab = new ApplyActionsBuilder();
+ aab.setAction(actionList);
+ ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+ logger.debug("createOutputPortInstructions() : applyAction {}", aab.build());
+ return ib;
}
-}
\ No newline at end of file
+}