From 76dc892491948adae5e5e62cf94448967e8d865b Mon Sep 17 00:00:00 2001 From: Ashlee Young Date: Sun, 6 Dec 2015 07:15:03 -0800 Subject: Fixes bad POM file with ONOS commit 8c68536972f63069c263635c9d9f4f31d7f3e9a2 Change-Id: I7adb5a2d3738d53dbc41db7577768b0e7ced5450 Signed-off-by: Ashlee Young --- .../driver/pipeline/CpqdOFDPA2Pipeline.java | 116 +++- .../driver/pipeline/OFDPA2Pipeline.java | 769 ++++++++------------- .../driver/pipeline/OpenstackPipeline.java | 286 ++++++++ .../onosproject/driver/pipeline/SpringOpenTTP.java | 53 +- 4 files changed, 709 insertions(+), 515 deletions(-) create mode 100644 framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OpenstackPipeline.java (limited to 'framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline') diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA2Pipeline.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA2Pipeline.java index 937c9ac8..02522cf1 100644 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA2Pipeline.java +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA2Pipeline.java @@ -39,7 +39,9 @@ import org.onosproject.net.flow.FlowRuleOperations; import org.onosproject.net.flow.FlowRuleOperationsContext; import org.onosproject.net.flow.TrafficSelector; import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.flow.criteria.Criteria; import org.onosproject.net.flow.criteria.Criterion; +import org.onosproject.net.flow.criteria.EthCriterion; import org.onosproject.net.flow.criteria.EthTypeCriterion; import org.onosproject.net.flow.criteria.IPCriterion; import org.onosproject.net.flow.criteria.MplsBosCriterion; @@ -62,6 +64,14 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { private final Logger log = getLogger(getClass()); + /* + * Cpqd emulation does not require the non-OF standard rules for + * matching untagged packets. + * + * (non-Javadoc) + * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processVlanIdFilter + */ + @Override protected List processVlanIdFilter(PortCriterion portCriterion, VlanIdCriterion vidCriterion, @@ -122,16 +132,101 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { return rules; } + /* + * Cpqd emulation does not handle vlan tags and mpls labels correctly. + * Workaround requires popping off the VLAN tags in the TMAC table. + * + * (non-Javadoc) + * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthDstFilter + */ @Override - protected Collection processSpecific(ForwardingObjective fwd) { + protected List processEthDstFilter(PortCriterion portCriterion, + EthCriterion ethCriterion, + VlanIdCriterion vidCriterion, + VlanId assignedVlan, + ApplicationId applicationId) { + //handling untagged packets via assigned VLAN + if (vidCriterion.vlanId() == VlanId.NONE) { + vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan); + } + // ofdpa cannot match on ALL portnumber, so we need to use separate + // rules for each port. + List portnums = new ArrayList(); + if (portCriterion.port() == PortNumber.ALL) { + for (Port port : deviceService.getPorts(deviceId)) { + if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) { + portnums.add(port.number()); + } + } + } else { + portnums.add(portCriterion.port()); + } + + List rules = new ArrayList(); + for (PortNumber pnum : portnums) { + // for unicast IP packets + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + selector.matchInPort(pnum); + selector.matchVlanId(vidCriterion.vlanId()); + selector.matchEthType(Ethernet.TYPE_IPV4); + selector.matchEthDst(ethCriterion.mac()); + /* + * Note: CpqD switches do not handle MPLS-related operation properly + * for a packet with VLAN tag. We pop VLAN here as a workaround. + * Side effect: HostService learns redundant hosts with same MAC but + * different VLAN. No known side effect on the network reachability. + */ + treatment.popVlan(); + treatment.transition(UNICAST_ROUTING_TABLE); + FlowRule rule = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(DEFAULT_PRIORITY) + .fromApp(applicationId) + .makePermanent() + .forTable(TMAC_TABLE).build(); + rules.add(rule); + //for MPLS packets + selector = DefaultTrafficSelector.builder(); + treatment = DefaultTrafficTreatment.builder(); + selector.matchInPort(pnum); + selector.matchVlanId(vidCriterion.vlanId()); + selector.matchEthType(Ethernet.MPLS_UNICAST); + selector.matchEthDst(ethCriterion.mac()); + // workaround here again + treatment.popVlan(); + treatment.transition(MPLS_TABLE_0); + rule = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(DEFAULT_PRIORITY) + .fromApp(applicationId) + .makePermanent() + .forTable(TMAC_TABLE).build(); + rules.add(rule); + } + return rules; + } + + /* + * Cpqd emulation allows MPLS ecmp. + * + * (non-Javadoc) + * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthTypeSpecific + */ + @Override + protected Collection processEthTypeSpecific(ForwardingObjective fwd) { TrafficSelector selector = fwd.selector(); EthTypeCriterion ethType = (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE); if ((ethType == null) || (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) && (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST)) { - log.warn("processSpecific: Unsupported " - + "forwarding objective criteraia"); + log.warn("processSpecific: Unsupported forwarding objective criteria" + + "ethType:{} in dev:{}", ethType, deviceId); fail(fwd, ObjectiveError.UNSUPPORTED); return Collections.emptySet(); } @@ -143,8 +238,8 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { .matchIPDst(((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip()); forTableId = UNICAST_ROUTING_TABLE; - log.debug("processing IPv4 specific forwarding objective {} hash{} in dev:{}", - fwd.id(), fwd.hashCode(), deviceId); + log.debug("processing IPv4 specific forwarding objective {} -> next:{}" + + " in dev:{}", fwd.id(), fwd.nextId(), deviceId); } else { filteredSelector .matchEthType(Ethernet.MPLS_UNICAST) @@ -156,8 +251,8 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { filteredSelector.matchMplsBos(bos.mplsBos()); } forTableId = MPLS_TABLE_1; - log.debug("processing MPLS specific forwarding objective {} hash:{} in dev {}", - fwd.id(), fwd.hashCode(), deviceId); + log.debug("processing MPLS specific forwarding objective {} -> next:{}" + + " in dev {}", fwd.id(), fwd.nextId(), deviceId); } TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder(); @@ -197,7 +292,6 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { return Collections.singletonList(ruleBuilder.build()); } - @Override protected void initializePipeline() { processPortTable(); @@ -210,7 +304,6 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { processAclTable(); } - @Override protected void processPortTable() { FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); @@ -239,7 +332,6 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { })); } - @Override protected void processTmacTable() { //table miss entry FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); @@ -270,7 +362,6 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { })); } - @Override protected void processIpTable() { //table miss entry FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); @@ -278,6 +369,7 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); selector = DefaultTrafficSelector.builder(); treatment = DefaultTrafficTreatment.builder(); + treatment.deferred().setOutput(PortNumber.CONTROLLER); treatment.transition(ACL_TABLE); FlowRule rule = DefaultFlowRule.builder() .forDevice(deviceId) @@ -301,7 +393,6 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { })); } - @Override protected void processMplsTable() { //table miss entry FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); @@ -374,7 +465,6 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { })); } - @Override protected void processAclTable() { //table miss entry - catch all to executed action-set FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA2Pipeline.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA2Pipeline.java index 863caebb..5f84b43a 100644 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA2Pipeline.java +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA2Pipeline.java @@ -18,7 +18,6 @@ package org.onosproject.driver.pipeline; import static org.onlab.util.Tools.groupedThreads; import static org.slf4j.LoggerFactory.getLogger; -import java.nio.ByteBuffer; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; @@ -28,6 +27,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -35,14 +35,9 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import org.onlab.osgi.ServiceDirectory; -import org.onlab.packet.Data; import org.onlab.packet.Ethernet; -import org.onlab.packet.IPv4; -import org.onlab.packet.IpPrefix; -import org.onlab.packet.MPLS; import org.onlab.packet.MacAddress; import org.onlab.packet.MplsLabel; -import org.onlab.packet.UDP; import org.onlab.packet.VlanId; import org.onlab.util.KryoNamespace; import org.onosproject.core.ApplicationId; @@ -99,10 +94,6 @@ import org.onosproject.net.group.GroupEvent; import org.onosproject.net.group.GroupKey; import org.onosproject.net.group.GroupListener; import org.onosproject.net.group.GroupService; -import org.onosproject.net.packet.DefaultOutboundPacket; -import org.onosproject.net.packet.OutboundPacket; -import org.onosproject.net.packet.PacketContext; -import org.onosproject.net.packet.PacketProcessor; import org.onosproject.net.packet.PacketService; import org.onosproject.store.serializers.KryoNamespaces; import org.slf4j.Logger; @@ -160,7 +151,6 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline protected ApplicationId driverId; protected PacketService packetService; protected DeviceService deviceService; - private InternalPacketProcessor processor = new InternalPacketProcessor(); protected KryoNamespace appKryo = new KryoNamespace.Builder() .register(KryoNamespaces.API) .register(GroupKey.class) @@ -170,7 +160,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline .register(ArrayDeque.class) .build(); - private Cache pendingNextObjectives; + private Cache> pendingNextObjectives; private ConcurrentHashMap> pendingGroups; private ScheduledExecutorService groupChecker = @@ -196,10 +186,12 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline pendingNextObjectives = CacheBuilder.newBuilder() .expireAfterWrite(20, TimeUnit.SECONDS) .removalListener(( - RemovalNotification notification) -> { + RemovalNotification> notification) -> { if (notification.getCause() == RemovalCause.EXPIRED) { - fail(notification.getValue().nextObjective(), - ObjectiveError.GROUPINSTALLATIONFAILED); + notification.getValue().forEach(ofdpaNextGrp -> + fail(ofdpaNextGrp.nextObj, + ObjectiveError.GROUPINSTALLATIONFAILED)); + } }).build(); @@ -212,7 +204,6 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline flowObjectiveStore = context.store(); packetService = serviceDirectory.get(PacketService.class); deviceService = serviceDirectory.get(DeviceService.class); - packetService.addProcessor(processor, PacketProcessor.director(2)); groupService.addListener(new InnerGroupListener()); driverId = coreService.registerApplication( @@ -271,7 +262,6 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline log.warn("Unknown forwarding type {}", fwd.op()); } - flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() { @Override public void onSuccess(FlowRuleOperations ops) { @@ -283,7 +273,6 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED); } })); - } @Override @@ -697,17 +686,57 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline * returned if there is an issue in processing the objective. */ protected Collection processSpecific(ForwardingObjective fwd) { - TrafficSelector selector = fwd.selector(); - EthTypeCriterion ethType = - (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE); - if ((ethType == null) || - (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) && - (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST)) { - log.warn("processSpecific: Unsupported " - + "forwarding objective criteraia"); + log.trace("Processing specific fwd objective:{} in dev:{} with next:{}", + fwd.id(), deviceId, fwd.nextId()); + boolean isEthTypeObj = isSupportedEthTypeObjective(fwd); + boolean isEthDstObj = isSupportedEthDstObjective(fwd); + + if (isEthTypeObj) { + return processEthTypeSpecific(fwd); + } else if (isEthDstObj) { + return processEthDstSpecific(fwd); + } else { + log.warn("processSpecific: Unsupported forwarding objective " + + "criteria fwd:{} in dev:{}", fwd.nextId(), deviceId); fail(fwd, ObjectiveError.UNSUPPORTED); return Collections.emptySet(); } + } + + private boolean isSupportedEthTypeObjective(ForwardingObjective fwd) { + TrafficSelector selector = fwd.selector(); + EthTypeCriterion ethType = (EthTypeCriterion) selector + .getCriterion(Criterion.Type.ETH_TYPE); + if ((ethType == null) || + ((ethType.ethType().toShort() != Ethernet.TYPE_IPV4) && + (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST))) { + return false; + } + return true; + } + + private boolean isSupportedEthDstObjective(ForwardingObjective fwd) { + TrafficSelector selector = fwd.selector(); + EthCriterion ethDst = (EthCriterion) selector + .getCriterion(Criterion.Type.ETH_DST); + VlanIdCriterion vlanId = (VlanIdCriterion) selector + .getCriterion(Criterion.Type.VLAN_VID); + if (ethDst == null && vlanId == null) { + return false; + } + return true; + } + + /** + * Handles forwarding rules to the IP and MPLS tables. + * + * @param fwd the forwarding objective + * @return A collection of flow rules, or an empty set + */ + protected Collection processEthTypeSpecific(ForwardingObjective fwd) { + TrafficSelector selector = fwd.selector(); + EthTypeCriterion ethType = + (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE); int forTableId = -1; TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder(); @@ -716,8 +745,8 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline .matchIPDst(((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip()); forTableId = UNICAST_ROUTING_TABLE; - log.debug("processing IPv4 specific forwarding objective {} in dev:{}", - fwd.id(), deviceId); + log.debug("processing IPv4 specific forwarding objective {} -> next:{}" + + " in dev:{}", fwd.id(), fwd.nextId(), deviceId); } else { filteredSelector .matchEthType(Ethernet.MPLS_UNICAST) @@ -729,8 +758,8 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline filteredSelector.matchMplsBos(bos.mplsBos()); } forTableId = MPLS_TABLE_1; - log.debug("processing MPLS specific forwarding objective {} in dev {}", - fwd.id(), deviceId); + log.debug("processing MPLS specific forwarding objective {} -> next:{}" + + " in dev {}", fwd.id(), fwd.nextId(), deviceId); } TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder(); @@ -754,6 +783,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline // MPLS interface, or a MPLS SWAP (with-same) but that would // have to be handled in the next-objective. Also the pop-mpls // logic used here won't work in non-BoS case. + fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED); return Collections.emptySet(); } @@ -762,7 +792,8 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline // we only need the top level group's key to point the flow to it Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst()); if (group == null) { - log.warn("The group left!"); + log.warn("Group with key:{} for next-id:{} not found in dev:{}", + gkeys.get(0).peekFirst(), fwd.nextId(), deviceId); fail(fwd, ObjectiveError.GROUPMISSING); return Collections.emptySet(); } @@ -786,6 +817,88 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline return Collections.singletonList(ruleBuilder.build()); } + /** + * Handles forwarding rules to the L2 bridging table. Flow actions are not + * allowed in the bridging table - instead we use L2 Interface group or + * L2 flood group + * + * @param fwd the forwarding objective + * @return A collection of flow rules, or an empty set + */ + protected Collection processEthDstSpecific(ForwardingObjective fwd) { + List rules = new ArrayList<>(); + + // Build filtered selector + TrafficSelector selector = fwd.selector(); + EthCriterion ethCriterion = (EthCriterion) selector + .getCriterion(Criterion.Type.ETH_DST); + VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) selector + .getCriterion(Criterion.Type.VLAN_VID); + + if (vlanIdCriterion == null) { + log.warn("Forwarding objective for bridging requires vlan. Not " + + "installing fwd:{} in dev:{}", fwd.id(), deviceId); + fail(fwd, ObjectiveError.BADPARAMS); + return Collections.emptySet(); + } + + TrafficSelector.Builder filteredSelectorBuilder = + DefaultTrafficSelector.builder(); + // Do not match MacAddress for subnet broadcast entry + if (!ethCriterion.mac().equals(MacAddress.NONE)) { + filteredSelectorBuilder.matchEthDst(ethCriterion.mac()); + log.debug("processing L2 forwarding objective:{} -> next:{} in dev:{}", + fwd.id(), fwd.nextId(), deviceId); + } else { + log.debug("processing L2 Broadcast forwarding objective:{} -> next:{} " + + "in dev:{} for vlan:{}", + fwd.id(), fwd.nextId(), deviceId, vlanIdCriterion.vlanId()); + } + filteredSelectorBuilder.matchVlanId(vlanIdCriterion.vlanId()); + TrafficSelector filteredSelector = filteredSelectorBuilder.build(); + + if (fwd.treatment() != null) { + log.warn("Ignoring traffic treatment in fwd rule {} meant for L2 table" + + "for dev:{}. Expecting only nextId", fwd.id(), deviceId); + } + + TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder(); + if (fwd.nextId() != null) { + NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId()); + if (next != null) { + List> gkeys = appKryo.deserialize(next.data()); + // we only need the top level group's key to point the flow to it + Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst()); + if (group != null) { + treatmentBuilder.deferred().group(group.id()); + } else { + log.warn("Group with key:{} for next-id:{} not found in dev:{}", + gkeys.get(0).peekFirst(), fwd.nextId(), deviceId); + fail(fwd, ObjectiveError.GROUPMISSING); + return Collections.emptySet(); + } + } + } + treatmentBuilder.immediate().transition(ACL_TABLE); + TrafficTreatment filteredTreatment = treatmentBuilder.build(); + + // Build bridging table entries + FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder(); + flowRuleBuilder.fromApp(fwd.appId()) + .withPriority(fwd.priority()) + .forDevice(deviceId) + .withSelector(filteredSelector) + .withTreatment(filteredTreatment) + .forTable(BRIDGING_TABLE); + if (fwd.permanent()) { + flowRuleBuilder.makePermanent(); + } else { + flowRuleBuilder.makeTemporary(fwd.timeout()); + } + rules.add(flowRuleBuilder.build()); + return rules; + } + private void pass(Objective obj) { if (obj.context().isPresent()) { obj.context().get().onSuccess(obj); @@ -842,9 +955,26 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline * @param nextObj the nextObjective of type SIMPLE */ private void processSimpleNextObjective(NextObjective nextObj) { - // break up simple next objective to GroupChain objects TrafficTreatment treatment = nextObj.next().iterator().next(); + // determine if plain L2 or L3->L2 + boolean plainL2 = true; + for (Instruction ins : treatment.allInstructions()) { + if (ins.type() == Instruction.Type.L2MODIFICATION) { + L2ModificationInstruction l2ins = (L2ModificationInstruction) ins; + if (l2ins.subtype() == L2SubType.ETH_DST || + l2ins.subtype() == L2SubType.ETH_SRC) { + plainL2 = false; + break; + } + } + } + + if (plainL2) { + createL2InterfaceGroup(nextObj); + return; + } + // break up simple next objective to GroupChain objects GroupInfo groupInfo = createL2L3Chain(treatment, nextObj.id(), nextObj.appId(), false, nextObj.meta()); @@ -860,8 +990,8 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline Collections.singletonList(gkeyChain), nextObj); - // store l3groupkey with the ofdpaGroupChain for the nextObjective that depends on it - pendingNextObjectives.put(groupInfo.outerGrpDesc.appCookie(), ofdpaGrp); + // store l3groupkey with the ofdpaNextGroup for the nextObjective that depends on it + updatePendingNextObjective(groupInfo.outerGrpDesc.appCookie(), ofdpaGrp); // now we are ready to send the l2 groupDescription (inner), as all the stores // that will get async replies have been updated. By waiting to update @@ -869,6 +999,98 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline groupService.addGroup(groupInfo.innerGrpDesc); } + private void updatePendingNextObjective(GroupKey key, OfdpaNextGroup value) { + List nextList = new CopyOnWriteArrayList(); + nextList.add(value); + List ret = pendingNextObjectives.asMap() + .putIfAbsent(key, nextList); + if (ret != null) { + ret.add(value); + } + } + + /** + * Creates a simple L2 Interface Group. + * + * @param nextObj the next Objective + */ + private void createL2InterfaceGroup(NextObjective nextObj) { + // only allowed actions are vlan pop and outport + TrafficTreatment.Builder ttb = DefaultTrafficTreatment.builder(); + PortNumber portNum = null; + for (Instruction ins : nextObj.next().iterator().next().allInstructions()) { + if (ins.type() == Instruction.Type.L2MODIFICATION) { + L2ModificationInstruction l2ins = (L2ModificationInstruction) ins; + switch (l2ins.subtype()) { + case VLAN_POP: + ttb.add(l2ins); + break; + default: + break; + } + } else if (ins.type() == Instruction.Type.OUTPUT) { + portNum = ((OutputInstruction) ins).port(); + ttb.add(ins); + } else { + log.warn("Driver does not handle this type of TrafficTreatment" + + " instruction in simple nextObjectives: {}", ins.type()); + } + } + //use the vlanid associated with the port + VlanId vlanid = port2Vlan.get(portNum); + + if (vlanid == null && nextObj.meta() != null) { + // use metadata vlan info if available + Criterion vidCriterion = nextObj.meta().getCriterion(Type.VLAN_VID); + if (vidCriterion != null) { + vlanid = ((VlanIdCriterion) vidCriterion).vlanId(); + } + } + + if (vlanid == null) { + log.error("Driver cannot process an L2/L3 group chain without " + + "egress vlan information for dev: {} port:{}", + deviceId, portNum); + return; + } + + // assemble information for ofdpa l2interface group + Integer l2groupId = L2INTERFACEMASK | (vlanid.toShort() << 16) | (int) portNum.toLong(); + // a globally unique groupkey that is different for ports in the same devices + // but different for the same portnumber on different devices. Also different + // for the various group-types created out of the same next objective. + int l2gk = 0x0ffffff & (deviceId.hashCode() << 8 | (int) portNum.toLong()); + final GroupKey l2groupkey = new DefaultGroupKey(appKryo.serialize(l2gk)); + + // create group description for the l2interfacegroup + GroupBucket l2interfaceGroupBucket = + DefaultGroupBucket.createIndirectGroupBucket(ttb.build()); + GroupDescription l2groupDescription = + new DefaultGroupDescription( + deviceId, + GroupDescription.Type.INDIRECT, + new GroupBuckets(Collections.singletonList( + l2interfaceGroupBucket)), + l2groupkey, + l2groupId, + nextObj.appId()); + log.debug("Trying L2Interface: device:{} gid:{} gkey:{} nextId:{}", + deviceId, Integer.toHexString(l2groupId), + l2groupkey, nextObj.id()); + + // create object for local and distributed storage + Deque singleKey = new ArrayDeque<>(); + singleKey.addFirst(l2groupkey); + OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup( + Collections.singletonList(singleKey), + nextObj); + + // store l2groupkey for the nextObjective that depends on it + updatePendingNextObjective(l2groupkey, ofdpaGrp); + // send the group description to the group service + groupService.addGroup(l2groupDescription); + } + /** * Creates one of two possible group-chains from the treatment * passed in. Depending on the MPLS boolean, this method either creates @@ -895,6 +1117,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline TrafficTreatment.Builder innerTtb = DefaultTrafficTreatment.builder(); VlanId vlanid = null; long portNum = 0; + boolean setVlan = false, popVlan = false; for (Instruction ins : treatment.allInstructions()) { if (ins.type() == Instruction.Type.L2MODIFICATION) { L2ModificationInstruction l2ins = (L2ModificationInstruction) ins; @@ -908,9 +1131,11 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline case VLAN_ID: vlanid = ((ModVlanIdInstruction) l2ins).vlanId(); outerTtb.setVlanId(vlanid); + setVlan = true; break; case VLAN_POP: innerTtb.popVlan(); + popVlan = true; break; case DEC_MPLS_TTL: case MPLS_LABEL: @@ -935,12 +1160,11 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline vlanid = port2Vlan.get(PortNumber.portNumber(portNum)); } - if (vlanid == null) { - // use metadata - for (Criterion metaCriterion : meta.criteria()) { - if (metaCriterion.type() == Type.VLAN_VID) { - vlanid = ((VlanIdCriterion) metaCriterion).vlanId(); - } + if (vlanid == null && meta != null) { + // use metadata if available + Criterion vidCriterion = meta.getCriterion(Type.VLAN_VID); + if (vidCriterion != null) { + vlanid = ((VlanIdCriterion) vidCriterion).vlanId(); } } @@ -951,6 +1175,14 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline return null; } + if (!setVlan && !popVlan) { + // untagged outgoing port + TrafficTreatment.Builder temp = DefaultTrafficTreatment.builder(); + temp.popVlan(); + innerTtb.build().allInstructions().forEach(i -> temp.add(i)); + innerTtb = temp; + } + // assemble information for ofdpa l2interface group Integer l2groupId = L2INTERFACEMASK | (vlanid.toShort() << 16) | (int) portNum; // a globally unique groupkey that is different for ports in the same devices @@ -1077,6 +1309,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline } // also ensure that all ports are in the same vlan + // XXX maybe HA issue here? VlanId thisvlanid = port2Vlan.get(portNum); if (vlanid == null) { vlanid = thisvlanid; @@ -1151,7 +1384,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline // store l2floodgroupkey with the ofdpaGroupChain for the nextObjective // that depends on it - pendingNextObjectives.put(l2floodgroupkey, ofdpaGrp); + updatePendingNextObjective(l2floodgroupkey, ofdpaGrp); for (GroupDescription l2intGrpDesc : l2interfaceGroupDescs) { // store all l2groupkeys with the groupChainElem for the l2floodgroup @@ -1336,7 +1569,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline // store l3ecmpGroupKey with the ofdpaGroupChain for the nextObjective // that depends on it - pendingNextObjectives.put(l3ecmpGroupKey, ofdpaGrp); + updatePendingNextObjective(l3ecmpGroupKey, ofdpaGrp); log.debug("Trying L3ECMP: device:{} gid:{} gkey:{} nextId:{}", deviceId, Integer.toHexString(l3ecmpGroupId), @@ -1422,16 +1655,18 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline processGroupChain(gce); } } else { - OfdpaNextGroup obj = pendingNextObjectives.getIfPresent(key); - if (obj != null) { - log.info("Group service processed group key {} in device:{}. " - + "Done implementing next objective: {} <<-->> gid:{}", - key, deviceId, obj.nextObjective().id(), - Integer.toHexString(groupService.getGroup(deviceId, key) - .givenGroupId())); - pass(obj.nextObjective()); + List objList = pendingNextObjectives.getIfPresent(key); + if (objList != null) { pendingNextObjectives.invalidate(key); - flowObjectiveStore.putNextGroup(obj.nextObjective().id(), obj); + objList.forEach(obj -> { + log.info("Group service processed group key {} in device:{}. " + + "Done implementing next objective: {} <<-->> gid:{}", + key, deviceId, obj.nextObjective().id(), + Integer.toHexString(groupService.getGroup(deviceId, key) + .givenGroupId())); + pass(obj.nextObjective()); + flowObjectiveStore.putNextGroup(obj.nextObjective().id(), obj); + }); } } }); @@ -1455,16 +1690,18 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline processGroupChain(gce); } } else { - OfdpaNextGroup obj = pendingNextObjectives.getIfPresent(key); - if (obj != null) { - log.info("group ADDED with key {} in dev {}.. Done implementing next " - + "objective: {} <<-->> gid:{}", - key, deviceId, obj.nextObjective().id(), - Integer.toHexString(groupService.getGroup(deviceId, key) - .givenGroupId())); - pass(obj.nextObjective()); + List objList = pendingNextObjectives.getIfPresent(key); + if (objList != null) { pendingNextObjectives.invalidate(key); - flowObjectiveStore.putNextGroup(obj.nextObjective().id(), obj); + objList.forEach(obj -> { + log.info("group ADDED with key {} in dev {}.. Done implementing next " + + "objective: {} <<-->> gid:{}", + key, deviceId, obj.nextObjective().id(), + Integer.toHexString(groupService.getGroup(deviceId, key) + .givenGroupId())); + pass(obj.nextObjective()); + flowObjectiveStore.putNextGroup(obj.nextObjective().id(), obj); + }); } } } @@ -1550,418 +1787,6 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline " waiting-on-groups: " + waitOnGroups.get() + " device: " + deviceId); } - - } - - ////////////////////////////////////// - // Test code to be used for future - // static-flow-pusher app - ////////////////////////////////////// - - public void processStaticFlows() { - //processPortTable(); - processGroupTable(); - processVlanTable(); - processTmacTable(); - processIpTable(); - //processMcastTable(); - //processBridgingTable(); - processAclTable(); - sendPackets(); - processMplsTable(); - } - - protected void processGroupTable() { - TrafficTreatment.Builder act = DefaultTrafficTreatment.builder(); - - act.popVlan(); // to send out untagged packets - act.setOutput(PortNumber.portNumber(24)); - GroupBucket bucket = - DefaultGroupBucket.createIndirectGroupBucket(act.build()); - final GroupKey groupkey = new DefaultGroupKey(appKryo.serialize(500)); - Integer groupId = 0x00c80018; //l2 interface, vlan 200, port 24 - GroupDescription groupDescription = new DefaultGroupDescription(deviceId, - GroupDescription.Type.INDIRECT, - new GroupBuckets(Collections.singletonList(bucket)), - groupkey, - groupId, - driverId); - groupService.addGroup(groupDescription); - - TrafficTreatment.Builder act2 = DefaultTrafficTreatment.builder(); - act2.setOutput(PortNumber.portNumber(40)); - GroupBucket bucket2 = DefaultGroupBucket.createIndirectGroupBucket(act2.build()); - final GroupKey groupkey2 = new DefaultGroupKey(appKryo.serialize(502)); - Integer groupId2 = 0x00c50028; //l2 interface, vlan 197, port 40 - GroupDescription groupDescription2 = new DefaultGroupDescription(deviceId, - GroupDescription.Type.INDIRECT, - new GroupBuckets(Collections.singletonList(bucket2)), - groupkey2, - groupId2, - driverId); - groupService.addGroup(groupDescription2); - - while (groupService.getGroup(deviceId, groupkey2) == null) { - try { - Thread.sleep(500); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - //Now for L3 Unicast group - TrafficTreatment.Builder act3 = DefaultTrafficTreatment.builder(); - act3.setEthDst(MacAddress.valueOf(0x2020)); - act3.setEthSrc(MacAddress.valueOf(0x1010)); - act3.setVlanId(VlanId.vlanId((short) 200)); - act3.group(new DefaultGroupId(0x00c80018)); // point to L2 interface - // MPLS interface group - does not work for popping single label - //Integer secGroupId = MPLSINTERFACEMASK | 38; // 0x90000026 - Integer groupId3 = L3UNICASTMASK | 1; // 0x20000001 - GroupBucket bucket3 = - DefaultGroupBucket.createIndirectGroupBucket(act3.build()); - final GroupKey groupkey3 = new DefaultGroupKey(appKryo.serialize(503)); - GroupDescription groupDescription3 = new DefaultGroupDescription(deviceId, - GroupDescription.Type.INDIRECT, - new GroupBuckets(Collections.singletonList(bucket3)), - groupkey3, - groupId3, - driverId); - groupService.addGroup(groupDescription3); - - //Another L3 Unicast group - TrafficTreatment.Builder act4 = DefaultTrafficTreatment.builder(); - act4.setEthDst(MacAddress.valueOf(0x3030)); - act4.setEthSrc(MacAddress.valueOf(0x1010)); - act4.setVlanId(VlanId.vlanId((short) 197)); - act4.group(new DefaultGroupId(0x00c50028)); // point to L2 interface - Integer groupId4 = L3UNICASTMASK | 2; // 0x20000002 - GroupBucket bucket4 = - DefaultGroupBucket.createIndirectGroupBucket(act4.build()); - final GroupKey groupkey4 = new DefaultGroupKey(appKryo.serialize(504)); - GroupDescription groupDescription4 = new DefaultGroupDescription(deviceId, - GroupDescription.Type.INDIRECT, - new GroupBuckets(Collections.singletonList(bucket4)), - groupkey4, - groupId4, - driverId); - groupService.addGroup(groupDescription4); - - while (groupService.getGroup(deviceId, groupkey4) == null) { - try { - Thread.sleep(500); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - // L3 ecmp group - TrafficTreatment.Builder act5 = DefaultTrafficTreatment.builder(); - act5.group(new DefaultGroupId(0x20000001)); - TrafficTreatment.Builder act6 = DefaultTrafficTreatment.builder(); - act6.group(new DefaultGroupId(0x20000002)); - GroupBucket buckete1 = - DefaultGroupBucket.createSelectGroupBucket(act5.build()); - GroupBucket buckete2 = - DefaultGroupBucket.createSelectGroupBucket(act6.build()); - List bktlist = new ArrayList(); - bktlist.add(buckete1); - bktlist.add(buckete2); - final GroupKey groupkey5 = new DefaultGroupKey(appKryo.serialize(505)); - Integer groupId5 = L3ECMPMASK | 5; // 0x70000005 - GroupDescription groupDescription5 = new DefaultGroupDescription(deviceId, - GroupDescription.Type.SELECT, - new GroupBuckets(bktlist), - groupkey5, - groupId5, - driverId); - groupService.addGroup(groupDescription5); - - - } - - @SuppressWarnings("deprecation") - protected void processMplsTable() { - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - selector.matchEthType(Ethernet.MPLS_UNICAST); - selector.matchMplsLabel(MplsLabel.mplsLabel(0xff)); //255 - selector.matchMplsBos(true); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - treatment.decMplsTtl(); // nw_ttl does not work - treatment.copyTtlIn(); - treatment.popMpls(Ethernet.TYPE_IPV4); - treatment.deferred().group(new DefaultGroupId(0x20000001)); // point to L3 Unicast - //treatment.deferred().group(new DefaultGroupId(0x70000005)); // point to L3 ECMP - treatment.transition(ACL_TABLE); - FlowRule test = DefaultFlowRule.builder().forDevice(deviceId) - .withSelector(selector.build()).withTreatment(treatment.build()) - .withPriority(DEFAULT_PRIORITY).fromApp(driverId).makePermanent() - .forTable(24).build(); - ops = ops.add(test); - - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Initialized mpls table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to initialize mpls table"); - } - })); - - } - - protected void processPortTable() { - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - selector.matchInPort(PortNumber.portNumber(0)); // should be maskable? - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - treatment.transition(VLAN_TABLE); - FlowRule tmisse = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(LOWEST_PRIORITY) - .fromApp(driverId) - .makePermanent() - .forTable(PORT_TABLE).build(); - ops = ops.add(tmisse); - - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Initialized port table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to initialize port table"); - } - })); - - } - - private void processVlanTable() { - // Table miss entry is not required as ofdpa default is to drop - // In OF terms, the absence of a t.m.e. also implies drop - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector.matchInPort(PortNumber.portNumber(12)); - selector.matchVlanId(VlanId.vlanId((short) 100)); - treatment.transition(TMAC_TABLE); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(DEFAULT_PRIORITY) - .fromApp(driverId) - .makePermanent() - .forTable(VLAN_TABLE).build(); - ops = ops.add(rule); - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Initialized vlan table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to initialize vlan table"); - } - })); - } - - protected void processTmacTable() { - //table miss entry - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector.matchInPort(PortNumber.portNumber(12)); - selector.matchVlanId(VlanId.vlanId((short) 100)); - selector.matchEthType(Ethernet.TYPE_IPV4); - selector.matchEthDst(MacAddress.valueOf("00:00:00:00:00:02")); - treatment.transition(UNICAST_ROUTING_TABLE); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(DEFAULT_PRIORITY) - .fromApp(driverId) - .makePermanent() - .forTable(TMAC_TABLE).build(); - ops = ops.add(rule); - - selector.matchEthType(Ethernet.MPLS_UNICAST); - treatment.transition(MPLS_TABLE_0); - FlowRule rulempls = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(DEFAULT_PRIORITY) - .fromApp(driverId) - .makePermanent() - .forTable(TMAC_TABLE).build(); - ops = ops.add(rulempls); - - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Initialized tmac table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to initialize tmac table"); - } - })); - } - - protected void processIpTable() { - //table miss entry - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector.matchEthType(Ethernet.TYPE_IPV4); - selector.matchIPDst(IpPrefix.valueOf("2.0.0.0/16")); - treatment.deferred().group(new DefaultGroupId(0x20000001)); - treatment.transition(ACL_TABLE); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(30000) - .fromApp(driverId) - .makePermanent() - .forTable(UNICAST_ROUTING_TABLE).build(); - ops = ops.add(rule); - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Initialized IP table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to initialize unicast IP table"); - } - })); - } - - protected void processAclTable() { - //table miss entry - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector.matchEthDst(MacAddress.valueOf("00:00:00:00:00:02")); - treatment.deferred().group(new DefaultGroupId(0x20000001)); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(60000) - .fromApp(driverId) - .makePermanent() - .forTable(ACL_TABLE).build(); - ops = ops.add(rule); - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Initialized Acl table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to initialize Acl table"); - } - })); - } - - private void sendPackets() { - Ethernet eth = new Ethernet(); - eth.setDestinationMACAddress("00:00:00:00:00:02"); - eth.setSourceMACAddress("00:00:00:11:22:33"); - eth.setVlanID((short) 100); - eth.setEtherType(Ethernet.MPLS_UNICAST); - MPLS mplsPkt = new MPLS(); - mplsPkt.setLabel(255); - mplsPkt.setTtl((byte) 5); - - IPv4 ipv4 = new IPv4(); - - ipv4.setDestinationAddress("4.0.5.6"); - ipv4.setSourceAddress("1.0.2.3"); - ipv4.setTtl((byte) 64); - ipv4.setChecksum((short) 0); - - UDP udp = new UDP(); - udp.setDestinationPort(666); - udp.setSourcePort(333); - udp.setPayload(new Data(new byte[]{(byte) 1, (byte) 2})); - udp.setChecksum((short) 0); - - ipv4.setPayload(udp); - mplsPkt.setPayload(ipv4); - eth.setPayload(mplsPkt); - - TrafficTreatment treatment = DefaultTrafficTreatment.builder() - .setOutput(PortNumber.portNumber(24)) - .build(); - OutboundPacket packet = new DefaultOutboundPacket(deviceId, - treatment, - ByteBuffer.wrap(eth.serialize())); - - - Ethernet eth2 = new Ethernet(); - eth2.setDestinationMACAddress("00:00:00:00:00:02"); - eth2.setSourceMACAddress("00:00:00:11:22:33"); - eth2.setVlanID((short) 100); - eth2.setEtherType(Ethernet.TYPE_IPV4); - - IPv4 ipv42 = new IPv4(); - ipv42.setDestinationAddress("2.0.0.2"); - ipv42.setSourceAddress("1.0.9.9"); - ipv42.setTtl((byte) 64); - ipv42.setChecksum((short) 0); - - UDP udp2 = new UDP(); - udp2.setDestinationPort(999); - udp2.setSourcePort(333); - udp2.setPayload(new Data(new byte[]{(byte) 1, (byte) 2})); - udp2.setChecksum((short) 0); - - ipv42.setPayload(udp2); - eth2.setPayload(ipv42); - - TrafficTreatment treatment2 = DefaultTrafficTreatment.builder() - .setOutput(PortNumber.portNumber(26)) - .build(); - OutboundPacket packet2 = new DefaultOutboundPacket(deviceId, - treatment2, - ByteBuffer.wrap(eth2.serialize())); - - - log.info("Emitting packets now"); - packetService.emit(packet); - packetService.emit(packet); - packetService.emit(packet2); - packetService.emit(packet); - packetService.emit(packet); - log.info("Done emitting packets"); - } - - private class InternalPacketProcessor implements PacketProcessor { - - @Override - public void process(PacketContext context) { - - - } } } diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OpenstackPipeline.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OpenstackPipeline.java new file mode 100644 index 00000000..7a92b4fa --- /dev/null +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OpenstackPipeline.java @@ -0,0 +1,286 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.driver.pipeline; + +import org.onlab.osgi.ServiceDirectory; +import org.onlab.packet.Ethernet; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.net.DeviceId; +import org.onosproject.net.behaviour.Pipeliner; +import org.onosproject.net.behaviour.PipelinerContext; +import org.onosproject.net.flow.DefaultFlowRule; +import org.onosproject.net.flow.DefaultTrafficSelector; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.FlowRule; +import org.onosproject.net.flow.FlowRuleOperations; +import org.onosproject.net.flow.FlowRuleOperationsContext; +import org.onosproject.net.flow.FlowRuleService; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.flow.criteria.Criterion; +import org.onosproject.net.flow.criteria.EthTypeCriterion; +import org.onosproject.net.flow.criteria.UdpPortCriterion; +import org.onosproject.net.flowobjective.FilteringObjective; +import org.onosproject.net.flowobjective.FlowObjectiveStore; +import org.onosproject.net.flowobjective.ForwardingObjective; +import org.onosproject.net.flowobjective.NextObjective; +import org.onosproject.net.flowobjective.Objective; +import org.onosproject.net.flowobjective.ObjectiveError; +import org.slf4j.Logger; + +import java.util.Collection; +import java.util.Collections; + +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Driver for OpenstackSwitching. + */ +public class OpenstackPipeline extends DefaultSingleTablePipeline + implements Pipeliner { + + private final Logger log = getLogger(getClass()); + private CoreService coreService; + private ServiceDirectory serviceDirectory; + protected FlowObjectiveStore flowObjectiveStore; + protected DeviceId deviceId; + protected ApplicationId appId; + protected FlowRuleService flowRuleService; + + protected static final int VNI_TABLE = 0; + protected static final int FORWARDING_TABLE = 1; + + private static final int DROP_PRIORITY = 0; + private static final int TIME_OUT = 0; + private static final int DHCP_SERVER_PORT = 67; + private static final int DHCP_CLIENT_PORT = 68; + + + @Override + public void init(DeviceId deviceId, PipelinerContext context) { + super.init(deviceId, context); + this.serviceDirectory = context.directory(); + this.deviceId = deviceId; + + coreService = serviceDirectory.get(CoreService.class); + flowRuleService = serviceDirectory.get(FlowRuleService.class); + flowObjectiveStore = context.store(); + + appId = coreService.registerApplication( + "org.onosproject.driver.OpenstackPipeline"); + + initializePipeline(); + } + + @Override + public void filter(FilteringObjective filteringObjective) { + super.filter(filteringObjective); + } + + @Override + public void next(NextObjective nextObjective) { + super.next(nextObjective); + } + + @Override + public void forward(ForwardingObjective forwardingObjective) { + Collection rules; + FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder(); + + rules = processForward(forwardingObjective); + + switch (forwardingObjective.op()) { + case ADD: + rules.stream() + .filter(rule -> rule != null) + .forEach(flowOpsBuilder::add); + break; + case REMOVE: + rules.stream() + .filter(rule -> rule != null) + .forEach(flowOpsBuilder::remove); + break; + default: + fail(forwardingObjective, ObjectiveError.UNKNOWN); + log.warn("Unknown forwarding type {}"); + } + + flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() { + @Override + public void onSuccess(FlowRuleOperations ops) { + pass(forwardingObjective); + } + + @Override + public void onError(FlowRuleOperations ops) { + fail(forwardingObjective, ObjectiveError.FLOWINSTALLATIONFAILED); + } + })); + } + + private void initializePipeline() { + processVNITable(true); + processForwardingTable(true); + } + + private void processVNITable(boolean install) { + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + + treatment.transition(FORWARDING_TABLE); + + FlowRule flowRule = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(DROP_PRIORITY) + .fromApp(appId) + .makePermanent() + .forTable(VNI_TABLE) + .build(); + + applyRules(install, flowRule); + } + + private void processForwardingTable(boolean install) { + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + + treatment.drop(); + + FlowRule flowRule = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(DROP_PRIORITY) + .fromApp(appId) + .makePermanent() + .forTable(FORWARDING_TABLE) + .build(); + + applyRules(install, flowRule); + } + + private void applyRules(boolean install, FlowRule flowRule) { + FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder(); + + flowOpsBuilder = install ? flowOpsBuilder.add(flowRule) : flowOpsBuilder.remove(flowRule); + + flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() { + @Override + public void onSuccess(FlowRuleOperations ops) { + log.debug("Provisioned vni or forwarding table"); + } + + @Override + public void onError(FlowRuleOperations ops) { + log.debug("Failed to privision vni or forwarding table"); + } + })); + } + + private Collection processForward(ForwardingObjective forwardingObjective) { + switch (forwardingObjective.flag()) { + case SPECIFIC: + return processSpecific(forwardingObjective); + case VERSATILE: + return processVersatile(forwardingObjective); + default: + fail(forwardingObjective, ObjectiveError.UNKNOWN); + log.warn("Unknown forwarding flag {}", forwardingObjective.flag()); + } + return Collections.emptySet(); + } + + private Collection processVersatile(ForwardingObjective forwardingObjective) { + log.debug("Processing versatile forwarding objective"); + + FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(forwardingObjective.selector()) + .withTreatment(forwardingObjective.treatment()) + .withPriority(forwardingObjective.priority()) + .fromApp(forwardingObjective.appId()); + + if (forwardingObjective.permanent()) { + ruleBuilder.makePermanent(); + } else { + ruleBuilder.makeTemporary(TIME_OUT); + } + + //ARP & DHCP Rule + EthTypeCriterion ethCriterion = + (EthTypeCriterion) forwardingObjective.selector().getCriterion(Criterion.Type.ETH_TYPE); + UdpPortCriterion udpPortCriterion = (UdpPortCriterion) forwardingObjective + .selector().getCriterion(Criterion.Type.UDP_DST); + if (ethCriterion != null) { + if (ethCriterion.ethType().toShort() == Ethernet.TYPE_ARP || + ethCriterion.ethType().toShort() == Ethernet.TYPE_LLDP) { + ruleBuilder.forTable(VNI_TABLE); + return Collections.singletonList(ruleBuilder.build()); + } else if (udpPortCriterion != null && udpPortCriterion.udpPort().toInt() == DHCP_SERVER_PORT) { + ruleBuilder.forTable(VNI_TABLE); + return Collections.singletonList(ruleBuilder.build()); + } + } + return Collections.emptySet(); + } + + private Collection processSpecific(ForwardingObjective forwardingObjective) { + log.debug("Processing specific forwarding objective"); + + FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(forwardingObjective.selector()) + .withTreatment(forwardingObjective.treatment()) + .withPriority(forwardingObjective.priority()) + .fromApp(forwardingObjective.appId()); + + if (forwardingObjective.permanent()) { + ruleBuilder.makePermanent(); + } else { + ruleBuilder.makeTemporary(TIME_OUT); + } + + //VNI Table Rule + if (forwardingObjective.selector().getCriterion(Criterion.Type.IN_PORT) != null) { + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); + forwardingObjective.treatment().allInstructions().forEach(tBuilder::add); + tBuilder.transition(FORWARDING_TABLE); + ruleBuilder.withTreatment(tBuilder.build()); + ruleBuilder.forTable(VNI_TABLE); + } else { + ruleBuilder.forTable(FORWARDING_TABLE); + } + + return Collections.singletonList(ruleBuilder.build()); + } + + + private void pass(Objective obj) { + if (obj.context().isPresent()) { + obj.context().get().onSuccess(obj); + } + } + + private void fail(Objective obj, ObjectiveError error) { + if (obj.context().isPresent()) { + obj.context().get().onError(obj, error); + } + } +} + diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java index 8ac5eec8..dba4557a 100644 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java @@ -287,24 +287,14 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour case SIMPLE: Collection treatments = nextObjective.next(); if (treatments.size() == 1) { - TrafficTreatment treatment = treatments.iterator().next(); - GroupBucket bucket = DefaultGroupBucket - .createIndirectGroupBucket(treatment); - final GroupKey key = new DefaultGroupKey( - appKryo.serialize(nextObjective - .id())); - GroupDescription groupDescription = new DefaultGroupDescription( - deviceId, - GroupDescription.Type.INDIRECT, - new GroupBuckets( - Collections.singletonList(bucket)), - key, - null, - nextObjective.appId()); - log.debug("Creating SIMPLE group for next objective id {} " - + "in dev:{}", nextObjective.id(), deviceId); - pendingGroups.put(key, nextObjective); - groupService.addGroup(groupDescription); + // Spring Open TTP converts simple nextObjective to flow-actions + // in a dummy group + TrafficTreatment treatment = nextObjective.next().iterator().next(); + log.debug("Converting SIMPLE group for next objective id {} " + + "to {} flow-actions in device:{}", nextObjective.id(), + treatment.allInstructions().size(), deviceId); + flowObjectiveStore.putNextGroup(nextObjective.id(), + new SpringOpenGroup(null, treatment)); } break; case HASHED: @@ -624,8 +614,9 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour if (next != null) { SpringOpenGroup soGroup = appKryo.deserialize(next.data()); if (soGroup.dummy) { - log.debug("Adding flow-actions for fwd. obj. {} " - + "in dev: {}", fwd.id(), deviceId); + log.debug("Adding {} flow-actions for fwd. obj. {} -> next:{} " + + "in dev: {}", soGroup.treatment.allInstructions().size(), + fwd.id(), fwd.nextId(), deviceId); for (Instruction ins : soGroup.treatment.allInstructions()) { treatmentBuilder.add(ins); } @@ -639,7 +630,8 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour } treatmentBuilder.deferred().group(group.id()); log.debug("Adding OUTGROUP action to group:{} for fwd. obj. {} " - + "in dev: {}", group.id(), fwd.id(), deviceId); + + "for next:{} in dev: {}", group.id(), fwd.id(), + fwd.nextId(), deviceId); } } else { log.warn("processSpecific: No associated next objective object"); @@ -705,10 +697,11 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour if (next != null) { SpringOpenGroup soGrp = appKryo.deserialize(next.data()); if (soGrp.dummy) { - log.debug("Adding flow-actions for fwd. obj. {} " - + "in dev: {}", fwd.id(), deviceId); + log.debug("Adding {} flow-actions for fwd. obj. {} " + + "in dev: {}", soGrp.treatment.allInstructions().size(), + fwd.id(), deviceId); for (Instruction ins : soGrp.treatment.allInstructions()) { - treatmentBuilder.add(ins); + treatmentBuilder.deferred().add(ins); } } else { GroupKey key = soGrp.key; @@ -773,6 +766,12 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour return rules; } + /* + * Note: CpqD switches do not handle MPLS-related operation properly + * for a packet with VLAN tag. We pop VLAN here as a workaround. + * Side effect: HostService learns redundant hosts with same MAC but + * different VLAN. No known side effect on the network reachability. + */ protected List processEthDstFilter(EthCriterion ethCriterion, VlanIdCriterion vlanIdCriterion, FilteringObjective filt, @@ -783,12 +782,6 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour vlanIdCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan); } - /* - * Note: CpqD switches do not handle MPLS-related operation properly - * for a packet with VLAN tag. We pop VLAN here as a workaround. - * Side effect: HostService learns redundant hosts with same MAC but - * different VLAN. No known side effect on the network reachability. - */ List rules = new ArrayList<>(); TrafficSelector.Builder selectorIp = DefaultTrafficSelector .builder(); -- cgit 1.2.3-korg