/* * Copyright (C) 2014 Red Hat, Inc. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html * * Authors : Madhu Venugopal */ 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 implements L2ForwardingProvider { private static final Logger logger = LoggerFactory.getLogger(L2ForwardingService.class); public L2ForwardingService() { super(Service.L2_FORWARDING); } public L2ForwardingService(Service service) { 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: */ @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 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 instructions = Lists.newArrayList(); List 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 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 instructions = Lists.newArrayList(); List 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 existingInstructions = null; if (flow != null) { Instructions ins = flow.getInstructions(); if (ins != null) { existingInstructions = ins.getInstruction(); } } List instructions = Lists.newArrayList(); InstructionBuilder ib = new InstructionBuilder(); List 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 instructions) { List actionList = Lists.newArrayList(); boolean removeFlow = true; if (instructions != null) { ApplyActionsCase aac = (ApplyActionsCase) ib.getInstruction(); Instruction in = instructions.get(0); List 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 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 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 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 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 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 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 instructions = Lists.newArrayList(); List 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 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 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 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 instructions) { NodeConnectorId ncid = new NodeConnectorId(OPENFLOW + dpidLong + ":" + port); logger.debug("createOutputPortInstructions() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions); List actionList = Lists.newArrayList(); ActionBuilder ab = new ActionBuilder(); List 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; } }