Charles Chan
Committed by Gerrit Code Review

Fix group handler in CpqD OFDPA driver

We should not use OFDPA extension VLAN ID in CpqD OFDPA driver (gerrit#8609)

Change-Id: Ife451c25c48a7aba2c4f7f8c66f71c9f362ab37c
/*
* Copyright 2016-present 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.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.DefaultGroupId;
import org.onosproject.net.flow.DefaultTrafficTreatment;
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.VlanIdCriterion;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flow.instructions.Instructions;
import org.onosproject.net.flow.instructions.L2ModificationInstruction;
import org.onosproject.net.group.DefaultGroupBucket;
import org.onosproject.net.group.DefaultGroupDescription;
import org.onosproject.net.group.DefaultGroupKey;
import org.onosproject.net.group.GroupBucket;
import org.onosproject.net.group.GroupBuckets;
import org.onosproject.net.group.GroupDescription;
import org.onosproject.net.group.GroupKey;
import org.slf4j.Logger;
import java.util.Collections;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Group handler for CpqD OFDPA pipeline.
*/
public class CpqdOfdpa2GroupHandler extends Ofdpa2GroupHandler {
private final Logger log = getLogger(getClass());
@Override
protected GroupInfo createL2L3Chain(TrafficTreatment treatment, int nextId,
ApplicationId appId, boolean mpls,
TrafficSelector meta) {
// for the l2interface group, get vlan and port info
// for the outer group, get the src/dst mac, and vlan info
TrafficTreatment.Builder outerTtb = DefaultTrafficTreatment.builder();
TrafficTreatment.Builder innerTtb = DefaultTrafficTreatment.builder();
VlanId vlanid = null;
long portNum = 0;
boolean setVlan = false, popVlan = false;
MacAddress srcMac = MacAddress.ZERO;
MacAddress dstMac = MacAddress.ZERO;
for (Instruction ins : treatment.allInstructions()) {
if (ins.type() == Instruction.Type.L2MODIFICATION) {
L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
switch (l2ins.subtype()) {
case ETH_DST:
dstMac = ((L2ModificationInstruction.ModEtherInstruction) l2ins).mac();
outerTtb.setEthDst(dstMac);
break;
case ETH_SRC:
srcMac = ((L2ModificationInstruction.ModEtherInstruction) l2ins).mac();
outerTtb.setEthSrc(srcMac);
break;
case VLAN_ID:
vlanid = ((L2ModificationInstruction.ModVlanIdInstruction) l2ins).vlanId();
outerTtb.setVlanId(vlanid);
setVlan = true;
break;
case VLAN_POP:
innerTtb.popVlan();
popVlan = true;
break;
case DEC_MPLS_TTL:
case MPLS_LABEL:
case MPLS_POP:
case MPLS_PUSH:
case VLAN_PCP:
case VLAN_PUSH:
default:
break;
}
} else if (ins.type() == Instruction.Type.OUTPUT) {
portNum = ((Instructions.OutputInstruction) ins).port().toLong();
innerTtb.add(ins);
} else {
log.warn("Driver does not handle this type of TrafficTreatment"
+ " instruction in nextObjectives: {}", ins.type());
}
}
if (vlanid == null && meta != null) {
// use metadata if available
Criterion vidCriterion = meta.getCriterion(Criterion.Type.VLAN_VID);
if (vidCriterion != null) {
vlanid = ((VlanIdCriterion) vidCriterion).vlanId();
}
// if vlan is not set, use the vlan in metadata for outerTtb
if (vlanid != null && !setVlan) {
outerTtb.setVlanId(vlanid);
}
}
if (vlanid == null) {
log.error("Driver cannot process an L2/L3 group chain without "
+ "egress vlan information for dev: {} port:{}",
deviceId, portNum);
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
int l2groupId = L2_INTERFACE_TYPE | (vlanid.toShort() << 16) | (int) portNum;
// a globally unique groupkey that is different for ports in the same device,
// 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 = l2InterfaceGroupKey(deviceId, vlanid, portNum);
final GroupKey l2groupkey = new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(l2gk));
// assemble information for outer group
GroupDescription outerGrpDesc = null;
if (mpls) {
// outer group is MPLSInteface
int mplsInterfaceIndex = getNextAvailableIndex();
int mplsgroupId = MPLS_INTERFACE_TYPE | (SUBTYPE_MASK & mplsInterfaceIndex);
final GroupKey mplsgroupkey = new DefaultGroupKey(
Ofdpa2Pipeline.appKryo.serialize(mplsInterfaceIndex));
outerTtb.group(new DefaultGroupId(l2groupId));
// create the mpls-interface group description to wait for the
// l2 interface group to be processed
GroupBucket mplsinterfaceGroupBucket =
DefaultGroupBucket.createIndirectGroupBucket(outerTtb.build());
outerGrpDesc = new DefaultGroupDescription(
deviceId,
GroupDescription.Type.INDIRECT,
new GroupBuckets(Collections.singletonList(
mplsinterfaceGroupBucket)),
mplsgroupkey,
mplsgroupId,
appId);
log.debug("Trying MPLS-Interface: device:{} gid:{} gkey:{} nextid:{}",
deviceId, Integer.toHexString(mplsgroupId),
mplsgroupkey, nextId);
} else {
// outer group is L3Unicast
int l3unicastIndex = getNextAvailableIndex();
int l3groupId = L3_UNICAST_TYPE | (TYPE_MASK & l3unicastIndex);
final GroupKey l3groupkey = new DefaultGroupKey(
Ofdpa2Pipeline.appKryo.serialize(l3unicastIndex));
outerTtb.group(new DefaultGroupId(l2groupId));
// create the l3unicast group description to wait for the
// l2 interface group to be processed
GroupBucket l3unicastGroupBucket =
DefaultGroupBucket.createIndirectGroupBucket(outerTtb.build());
outerGrpDesc = new DefaultGroupDescription(
deviceId,
GroupDescription.Type.INDIRECT,
new GroupBuckets(Collections.singletonList(
l3unicastGroupBucket)),
l3groupkey,
l3groupId,
appId);
log.debug("Trying L3Unicast: device:{} gid:{} gkey:{} nextid:{}",
deviceId, Integer.toHexString(l3groupId),
l3groupkey, nextId);
}
// store l2groupkey with the groupChainElem for the outer-group that depends on it
GroupChainElem gce = new GroupChainElem(outerGrpDesc, 1, false);
updatePendingGroups(l2groupkey, gce);
// create group description for the inner l2interfacegroup
GroupBucket l2InterfaceGroupBucket =
DefaultGroupBucket.createIndirectGroupBucket(innerTtb.build());
GroupDescription l2groupDescription =
new DefaultGroupDescription(
deviceId,
GroupDescription.Type.INDIRECT,
new GroupBuckets(Collections.singletonList(
l2InterfaceGroupBucket)),
l2groupkey,
l2groupId,
appId);
log.debug("Trying L2Interface: device:{} gid:{} gkey:{} nextId:{}",
deviceId, Integer.toHexString(l2groupId),
l2groupkey, nextId);
return new GroupInfo(l2groupDescription, outerGrpDesc);
}
}
......@@ -32,15 +32,20 @@ import org.onlab.packet.MacAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.VlanId;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.behaviour.NextGroup;
import org.onosproject.net.behaviour.PipelinerContext;
import org.onosproject.net.device.DeviceService;
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.Criteria;
......@@ -60,6 +65,7 @@ import org.onosproject.net.flowobjective.ForwardingObjective;
import org.onosproject.net.flowobjective.ObjectiveError;
import org.onosproject.net.group.Group;
import org.onosproject.net.group.GroupKey;
import org.onosproject.net.group.GroupService;
import org.slf4j.Logger;
......@@ -75,6 +81,27 @@ public class CpqdOfdpa2Pipeline extends Ofdpa2Pipeline {
private final Logger log = getLogger(getClass());
@Override
public void init(DeviceId deviceId, PipelinerContext context) {
this.deviceId = deviceId;
// Initialize OFDPA group handler
groupHandler = new CpqdOfdpa2GroupHandler();
groupHandler.init(deviceId, context);
serviceDirectory = context.directory();
coreService = serviceDirectory.get(CoreService.class);
flowRuleService = serviceDirectory.get(FlowRuleService.class);
groupService = serviceDirectory.get(GroupService.class);
flowObjectiveStore = context.store();
deviceService = serviceDirectory.get(DeviceService.class);
driverId = coreService.registerApplication(
"org.onosproject.driver.CpqdOfdpa2Pipeline");
initializePipeline();
}
/*
* CPQD emulation does not require special untagged packet handling, unlike
* the real ofdpa.
......@@ -253,13 +280,13 @@ public class CpqdOfdpa2Pipeline extends Ofdpa2Pipeline {
for (PortNumber pnum : portnums) {
// update storage
ofdpa2GroupHandler.port2Vlan.put(pnum, storeVlan);
Set<PortNumber> vlanPorts = ofdpa2GroupHandler.vlan2Port.get(storeVlan);
groupHandler.port2Vlan.put(pnum, storeVlan);
Set<PortNumber> vlanPorts = groupHandler.vlan2Port.get(storeVlan);
if (vlanPorts == null) {
vlanPorts = Collections.newSetFromMap(
new ConcurrentHashMap<PortNumber, Boolean>());
vlanPorts.add(pnum);
ofdpa2GroupHandler.vlan2Port.put(storeVlan, vlanPorts);
groupHandler.vlan2Port.put(storeVlan, vlanPorts);
} else {
vlanPorts.add(pnum);
}
......
......@@ -25,13 +25,18 @@ import java.util.List;
import org.onlab.packet.Ethernet;
import org.onlab.packet.VlanId;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.behaviour.NextGroup;
import org.onosproject.net.behaviour.PipelinerContext;
import org.onosproject.net.device.DeviceService;
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.FlowRuleService;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.criteria.Criteria;
......@@ -46,6 +51,7 @@ import org.onosproject.net.flowobjective.ForwardingObjective;
import org.onosproject.net.flowobjective.ObjectiveError;
import org.onosproject.net.group.Group;
import org.onosproject.net.group.GroupKey;
import org.onosproject.net.group.GroupService;
import org.slf4j.Logger;
......@@ -63,6 +69,27 @@ public class CpqdOfdpa2VlanPipeline extends CpqdOfdpa2Pipeline {
private final Logger log = getLogger(getClass());
@Override
public void init(DeviceId deviceId, PipelinerContext context) {
this.deviceId = deviceId;
// Initialize OFDPA group handler
groupHandler = new CpqdOfdpa2GroupHandler();
groupHandler.init(deviceId, context);
serviceDirectory = context.directory();
coreService = serviceDirectory.get(CoreService.class);
flowRuleService = serviceDirectory.get(FlowRuleService.class);
groupService = serviceDirectory.get(GroupService.class);
flowObjectiveStore = context.store();
deviceService = serviceDirectory.get(DeviceService.class);
driverId = coreService.registerApplication(
"org.onosproject.driver.CpqdOfdpa2VlanPipeline");
initializePipeline();
}
/*
* Cpqd emulation does not handle vlan tags and mpls labels correctly.
* Since this driver does not deal with MPLS, there is no need for
......
......@@ -92,28 +92,28 @@ public class Ofdpa2GroupHandler {
* L2 Flood Groups have <4bits-4><12bits-vlanid><16bits-index>
* L3 VPN Groups have <4bits-9><4bits-2><24bits-index>
*/
private static final int L2_INTERFACE_TYPE = 0x00000000;
private static final int L3_INTERFACE_TYPE = 0x50000000;
private static final int L3_UNICAST_TYPE = 0x20000000;
private static final int L3_MULTICAST_TYPE = 0x60000000;
private static final int MPLS_INTERFACE_TYPE = 0x90000000;
private static final int MPLS_L3VPN_SUBTYPE = 0x92000000;
private static final int L3_ECMP_TYPE = 0x70000000;
private static final int L2_FLOOD_TYPE = 0x40000000;
private static final int TYPE_MASK = 0x0fffffff;
private static final int SUBTYPE_MASK = 0x00ffffff;
private static final int TYPE_VLAN_MASK = 0x0000ffff;
private static final int PORT_LOWER_BITS_MASK = 0x3f;
private static final long PORT_HIGHER_BITS_MASK = ~PORT_LOWER_BITS_MASK;
protected static final int L2_INTERFACE_TYPE = 0x00000000;
protected static final int L3_INTERFACE_TYPE = 0x50000000;
protected static final int L3_UNICAST_TYPE = 0x20000000;
protected static final int L3_MULTICAST_TYPE = 0x60000000;
protected static final int MPLS_INTERFACE_TYPE = 0x90000000;
protected static final int MPLS_L3VPN_SUBTYPE = 0x92000000;
protected static final int L3_ECMP_TYPE = 0x70000000;
protected static final int L2_FLOOD_TYPE = 0x40000000;
protected static final int TYPE_MASK = 0x0fffffff;
protected static final int SUBTYPE_MASK = 0x00ffffff;
protected static final int TYPE_VLAN_MASK = 0x0000ffff;
protected static final int PORT_LOWER_BITS_MASK = 0x3f;
protected static final long PORT_HIGHER_BITS_MASK = ~PORT_LOWER_BITS_MASK;
private final Logger log = getLogger(getClass());
private ServiceDirectory serviceDirectory;
protected GroupService groupService;
protected StorageService storageService;
private DeviceId deviceId;
protected DeviceId deviceId;
private FlowObjectiveStore flowObjectiveStore;
private Cache<GroupKey, List<OfdpaNextGroup>> pendingNextObjectives;
private ConcurrentHashMap<GroupKey, Set<GroupChainElem>> pendingGroups;
......@@ -282,8 +282,8 @@ public class Ofdpa2GroupHandler {
/**
* Creates one of two possible group-chains from the treatment
* passed in. Depending on the MPLS boolean, this method either creates
* an L3Unicast Group --> L2Interface Group, if mpls is false;
* or MPLSInterface Group --> L2Interface Group, if mpls is true;
* an L3Unicast Group --&gt; L2Interface Group, if mpls is false;
* or MPLSInterface Group --&gt; L2Interface Group, if mpls is true;
* The returned 'inner' group description is always the L2 Interface group.
*
* @param treatment that needs to be broken up to create the group chain
......@@ -296,7 +296,7 @@ public class Ofdpa2GroupHandler {
* L3Unicast/MPLSInterface group. May return null if there is an
* error in processing the chain
*/
private GroupInfo createL2L3Chain(TrafficTreatment treatment, int nextId,
protected GroupInfo createL2L3Chain(TrafficTreatment treatment, int nextId,
ApplicationId appId, boolean mpls,
TrafficSelector meta) {
// for the l2interface group, get vlan and port info
......@@ -1039,7 +1039,7 @@ public class Ofdpa2GroupHandler {
}
}
private void updatePendingGroups(GroupKey gkey, GroupChainElem gce) {
protected void updatePendingGroups(GroupKey gkey, GroupChainElem gce) {
Set<GroupChainElem> gceSet = Collections.newSetFromMap(
new ConcurrentHashMap<GroupChainElem, Boolean>());
gceSet.add(gce);
......@@ -1145,7 +1145,7 @@ public class Ofdpa2GroupHandler {
}
}
private int getNextAvailableIndex() {
protected int getNextAvailableIndex() {
return (int) nextIndex.incrementAndGet();
}
......@@ -1160,7 +1160,7 @@ public class Ofdpa2GroupHandler {
* @param portNumber Port number
* @return L2 interface group key
*/
private int l2InterfaceGroupKey(
protected int l2InterfaceGroupKey(
DeviceId deviceId, VlanId vlanId, long portNumber) {
int portLowerBits = (int) portNumber & PORT_LOWER_BITS_MASK;
long portHigherBits = portNumber & PORT_HIGHER_BITS_MASK;
......@@ -1171,7 +1171,7 @@ public class Ofdpa2GroupHandler {
/**
* Utility class for moving group information around.
*/
private class GroupInfo {
protected class GroupInfo {
/**
* Description of the inner-most group of the group chain.
* It is always an L2 interface group.
......@@ -1240,7 +1240,7 @@ public class Ofdpa2GroupHandler {
* class are meant to be temporary and live as long as it is needed to wait for
* preceding groups in the group chain to be created.
*/
private class GroupChainElem {
protected class GroupChainElem {
private GroupDescription groupDescription;
private AtomicInteger waitOnGroups;
private boolean addBucketToGroup;
......
......@@ -108,9 +108,9 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline
protected static final int LOWEST_PRIORITY = 0x0;
private final Logger log = getLogger(getClass());
private ServiceDirectory serviceDirectory;
protected ServiceDirectory serviceDirectory;
protected FlowRuleService flowRuleService;
private CoreService coreService;
protected CoreService coreService;
protected GroupService groupService;
protected FlowObjectiveStore flowObjectiveStore;
protected DeviceId deviceId;
......@@ -125,20 +125,20 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline
.register(ArrayDeque.class)
.build();
protected Ofdpa2GroupHandler ofdpa2GroupHandler;
protected Ofdpa2GroupHandler groupHandler;
protected Set<IPCriterion> sentIpFilters = Collections.newSetFromMap(
new ConcurrentHashMap<>());
@Override
public void init(DeviceId deviceId, PipelinerContext context) {
this.serviceDirectory = context.directory();
this.deviceId = deviceId;
// Initialize OFDPA group handler
ofdpa2GroupHandler = new Ofdpa2GroupHandler();
ofdpa2GroupHandler.init(deviceId, context);
groupHandler = new Ofdpa2GroupHandler();
groupHandler.init(deviceId, context);
serviceDirectory = context.directory();
coreService = serviceDirectory.get(CoreService.class);
flowRuleService = serviceDirectory.get(FlowRuleService.class);
groupService = serviceDirectory.get(GroupService.class);
......@@ -146,7 +146,7 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline
deviceService = serviceDirectory.get(DeviceService.class);
driverId = coreService.registerApplication(
"org.onosproject.driver.OFDPA2Pipeline");
"org.onosproject.driver.Ofdpa2Pipeline");
initializePipeline();
}
......@@ -224,19 +224,19 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline
}
log.debug("Processing NextObjective id{} in dev{} - add group",
nextObjective.id(), deviceId);
ofdpa2GroupHandler.addGroup(nextObjective);
groupHandler.addGroup(nextObjective);
break;
case ADD_TO_EXISTING:
if (nextGroup != null) {
log.debug("Processing NextObjective id{} in dev{} - add bucket",
nextObjective.id(), deviceId);
ofdpa2GroupHandler.addBucketToGroup(nextObjective, nextGroup);
groupHandler.addBucketToGroup(nextObjective, nextGroup);
} else {
// it is possible that group-chain has not been fully created yet
log.debug("Waiting to add bucket to group for next-id:{} in dev:{}",
nextObjective.id(), deviceId);
// by design only one pending bucket is allowed for the group
ofdpa2GroupHandler.pendingBuckets.put(nextObjective.id(), nextObjective);
groupHandler.pendingBuckets.put(nextObjective.id(), nextObjective);
}
break;
case REMOVE:
......@@ -247,7 +247,7 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline
}
log.debug("Processing NextObjective id{} in dev{} - remove group",
nextObjective.id(), deviceId);
ofdpa2GroupHandler.removeGroup(nextObjective, nextGroup);
groupHandler.removeGroup(nextObjective, nextGroup);
break;
case REMOVE_FROM_EXISTING:
if (nextGroup == null) {
......@@ -257,7 +257,7 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline
}
log.debug("Processing NextObjective id{} in dev{} - remove bucket",
nextObjective.id(), deviceId);
ofdpa2GroupHandler.removeBucketFromGroup(nextObjective, nextGroup);
groupHandler.removeBucketFromGroup(nextObjective, nextGroup);
break;
default:
log.warn("Unsupported operation {}", nextObjective.op());
......@@ -500,13 +500,13 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline
for (PortNumber pnum : portnums) {
// update storage
ofdpa2GroupHandler.port2Vlan.put(pnum, storeVlan);
Set<PortNumber> vlanPorts = ofdpa2GroupHandler.vlan2Port.get(storeVlan);
groupHandler.port2Vlan.put(pnum, storeVlan);
Set<PortNumber> vlanPorts = groupHandler.vlan2Port.get(storeVlan);
if (vlanPorts == null) {
vlanPorts = Collections.newSetFromMap(
new ConcurrentHashMap<PortNumber, Boolean>());
vlanPorts.add(pnum);
ofdpa2GroupHandler.vlan2Port.put(storeVlan, vlanPorts);
groupHandler.vlan2Port.put(storeVlan, vlanPorts);
} else {
vlanPorts.add(pnum);
}
......