use of org.onosproject.net.flow.instructions.L2ModificationInstruction in project onos by opennetworkinglab.
the class Ofdpa2GroupHandler method createL2L3ChainInternal.
/**
* Internal implementation of createL2L3Chain.
* <p>
* The is_present bit in set_vlan_vid action is required to be 0 in OFDPA i12.
* Since it is non-OF spec, we need an extension treatment for that.
* The useSetVlanExtension must be set to false for OFDPA i12.
* </p>
*
* @param treatment that needs to be broken up to create the group chain
* @param nextId of the next objective that needs this group chain
* @param appId of the application that sent this next objective
* @param mpls determines if L3Unicast or MPLSInterface group is created
* @param meta metadata passed in by the application as part of the nextObjective
* @param useSetVlanExtension use the setVlanVid extension that has is_present bit set to 0.
* @return GroupInfo containing the GroupDescription of the
* L2Interface group(inner) and the GroupDescription of the (outer)
* L3Unicast/MPLSInterface group. May return null if there is an
* error in processing the chain
*/
protected GroupInfo createL2L3ChainInternal(TrafficTreatment treatment, int nextId, ApplicationId appId, boolean mpls, TrafficSelector meta, boolean useSetVlanExtension) {
// 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 dstMac;
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();
if (useSetVlanExtension) {
OfdpaSetVlanVid ofdpaSetVlanVid = new OfdpaSetVlanVid(vlanid);
outerTtb.extension(ofdpaSetVlanVid, deviceId);
} else {
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.debug("Driver does not handle this type of TrafficTreatment" + " instruction in l2l3chain: {} - {}", ins.type(), ins);
}
}
if (vlanid == null && meta != null) {
// use metadata if available
Criterion vidCriterion = meta.getCriterion(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) {
if (useSetVlanExtension) {
OfdpaSetVlanVid ofdpaSetVlanVid = new OfdpaSetVlanVid(vlanid);
outerTtb.extension(ofdpaSetVlanVid, deviceId);
} else {
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(temp::add);
innerTtb = temp;
}
// assemble information for ofdpa l2interface group
int l2groupId = l2GroupId(vlanid, 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(appKryo.serialize(l2gk));
// assemble information for outer group
GroupDescription outerGrpDesc;
if (mpls) {
// outer group is MPLS Interface
int mplsInterfaceIndex = getNextAvailableIndex();
int mplsGroupId = MPLS_INTERFACE_TYPE | (SUBTYPE_MASK & mplsInterfaceIndex);
final GroupKey mplsGroupKey = new DefaultGroupKey(appKryo.serialize(mplsInterfaceIndex));
outerTtb.group(new GroupId(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(appKryo.serialize(l3unicastIndex));
outerTtb.group(new GroupId(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, deviceId);
updatePendingGroups(l2groupkey, gce);
// create group description for the inner l2 interface group
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);
}
use of org.onosproject.net.flow.instructions.L2ModificationInstruction in project onos by opennetworkinglab.
the class Ofdpa2GroupHandler method modifySimpleNextObjective.
/**
* As per the OFDPA 2.0 TTP, packets are sent out of ports by using
* a chain of groups. The simple Next Objective passed in by the application
* is broken up into a group chain. The following chains can be modified
* depending on the parameters in the Next Objective.
* 1. L2 Interface group (no chaining)
* 2. L3 Unicast group -> L2 Interface group
*
* @param nextObj the nextObjective of type SIMPLE
*/
private void modifySimpleNextObjective(NextObjective nextObj, NextGroup nextGroup) {
TrafficTreatment treatment = nextObj.next().iterator().next();
// determine if plain L2 or L3->L2 chain
boolean plainL2 = true;
for (Instruction ins : treatment.allInstructions()) {
if (ins.type() == Instruction.Type.L2MODIFICATION) {
L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
if (l2ins.subtype() == L2ModificationInstruction.L2SubType.ETH_DST || l2ins.subtype() == L2ModificationInstruction.L2SubType.ETH_SRC || l2ins.subtype() == L2ModificationInstruction.L2SubType.VLAN_ID) {
plainL2 = false;
}
}
}
if (plainL2) {
modifyBucketInL2Group(nextObj, nextGroup);
} else {
modifyBucketInL3Group(nextObj, nextGroup);
}
return;
}
use of org.onosproject.net.flow.instructions.L2ModificationInstruction in project onos by opennetworkinglab.
the class Ofdpa2Pipeline method processEgress.
/**
* In the OF-DPA 2.0 pipeline, egress forwarding objectives go to the
* egress tables.
* @param fwd the forwarding objective of type 'egress'
* @return a collection of flow rules to be sent to the switch. An empty
* collection may be returned if there is a problem in processing
* the flow rule
*/
protected Collection<FlowRule> processEgress(ForwardingObjective fwd) {
log.debug("Processing egress forwarding objective:{} in dev:{}", fwd, deviceId);
List<FlowRule> rules = new ArrayList<>();
// Build selector
TrafficSelector.Builder sb = DefaultTrafficSelector.builder();
VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) fwd.selector().getCriterion(Criterion.Type.VLAN_VID);
if (vlanIdCriterion == null) {
log.error("Egress forwarding objective:{} must include vlanId", fwd.id());
fail(fwd, ObjectiveError.BADPARAMS);
return rules;
}
Optional<Instruction> outInstr = fwd.treatment().allInstructions().stream().filter(instruction -> instruction instanceof OutputInstruction).findFirst();
if (!outInstr.isPresent()) {
log.error("Egress forwarding objective:{} must include output port", fwd.id());
fail(fwd, ObjectiveError.BADPARAMS);
return rules;
}
PortNumber portNumber = ((OutputInstruction) outInstr.get()).port();
sb.matchVlanId(vlanIdCriterion.vlanId());
OfdpaMatchActsetOutput actsetOutput = new OfdpaMatchActsetOutput(portNumber);
sb.extension(actsetOutput, deviceId);
sb.extension(new OfdpaMatchAllowVlanTranslation(ALLOW_VLAN_TRANSLATION), deviceId);
// Build a flow rule for Egress VLAN Flow table
TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
tb.transition(EGRESS_DSCP_PCP_REMARK_FLOW_TABLE);
if (fwd.treatment() != null) {
for (Instruction instr : fwd.treatment().allInstructions()) {
if (instr instanceof L2ModificationInstruction && ((L2ModificationInstruction) instr).subtype() == L2SubType.VLAN_ID) {
tb.immediate().add(instr);
}
if (instr instanceof L2ModificationInstruction && ((L2ModificationInstruction) instr).subtype() == L2SubType.VLAN_PUSH) {
tb.immediate().pushVlan();
EthType ethType = ((L2ModificationInstruction.ModVlanHeaderInstruction) instr).ethernetType();
if (ethType.equals(EtherType.QINQ.ethType())) {
// Build a flow rule for Egress TPID Flow table
TrafficSelector tpidSelector = DefaultTrafficSelector.builder().extension(actsetOutput, deviceId).matchVlanId(VlanId.ANY).build();
TrafficTreatment tpidTreatment = DefaultTrafficTreatment.builder().extension(new Ofdpa3CopyField(COPY_FIELD_NBITS, COPY_FIELD_OFFSET, COPY_FIELD_OFFSET, OXM_ID_VLAN_VID, OXM_ID_PACKET_REG_1), deviceId).popVlan().pushVlan(EtherType.QINQ.ethType()).extension(new Ofdpa3CopyField(COPY_FIELD_NBITS, COPY_FIELD_OFFSET, COPY_FIELD_OFFSET, OXM_ID_PACKET_REG_1, OXM_ID_VLAN_VID), deviceId).build();
FlowRule.Builder tpidRuleBuilder = DefaultFlowRule.builder().fromApp(fwd.appId()).withPriority(fwd.priority()).forDevice(deviceId).withSelector(tpidSelector).withTreatment(tpidTreatment).makePermanent().forTable(EGRESS_TPID_FLOW_TABLE);
rules.add(tpidRuleBuilder.build());
}
}
}
}
FlowRule.Builder ruleBuilder = DefaultFlowRule.builder().fromApp(fwd.appId()).withPriority(fwd.priority()).forDevice(deviceId).withSelector(sb.build()).withTreatment(tb.build()).makePermanent().forTable(EGRESS_VLAN_FLOW_TABLE);
rules.add(ruleBuilder.build());
return rules;
}
use of org.onosproject.net.flow.instructions.L2ModificationInstruction in project onos by opennetworkinglab.
the class Ofdpa3GroupHandler method createUnfilteredL2L3Chain.
// TODO Introduce in the future an inner class to return two treatments
/**
* Internal implementation of createL2L3Chain for L2 unfiltered interface group.
*
* @param treatment that needs to be broken up to create the group chain
* @param nextId of the next objective that needs this group chain
* @param appId of the application that sent this next objective
* @param useSetVlanExtension use the setVlanVid extension that has is_present bit set to 0.
* @return GroupInfo containing the GroupDescription of the
* L2 Unfiltered Interface group(inner) and the GroupDescription of the (outer)
* L3Unicast group. May return null if there is an error in processing the chain.
*/
private GroupInfo createUnfilteredL2L3Chain(TrafficTreatment treatment, int nextId, ApplicationId appId, boolean useSetVlanExtension) {
// for the l2 unfiltered interface group, get port info
// for the l3 unicast group, get the src/dst mac, and vlan info
TrafficTreatment.Builder outerTtb = DefaultTrafficTreatment.builder();
TrafficTreatment.Builder innerTtb = DefaultTrafficTreatment.builder();
VlanId vlanId;
long portNum = 0;
MacAddress srcMac;
MacAddress dstMac;
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();
if (useSetVlanExtension) {
OfdpaSetVlanVid ofdpaSetVlanVid = new OfdpaSetVlanVid(vlanId);
outerTtb.extension(ofdpaSetVlanVid, deviceId);
} else {
outerTtb.setVlanId(vlanId);
}
break;
default:
break;
}
} else if (ins.type() == Instruction.Type.OUTPUT) {
portNum = ((Instructions.OutputInstruction) ins).port().toLong();
innerTtb.add(ins);
} else {
log.debug("Driver does not handle this type of TrafficTreatment" + " instruction in l2l3chain: {} - {}", ins.type(), ins);
}
}
innerTtb.extension(new OfdpaSetAllowVlanTranslation(Ofdpa3AllowVlanTranslationType.ALLOW), deviceId);
// assemble information for ofdpa l2 unfiltered interface group
int l2groupId = l2UnfilteredGroupId(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 = l2UnfilteredGroupKey(deviceId, portNum);
final GroupKey l2groupkey = new DefaultGroupKey(Ofdpa3Pipeline.appKryo.serialize(l2gk));
// assemble information for outer group (L3Unicast)
GroupDescription outerGrpDesc;
int l3unicastIndex = getNextAvailableIndex();
int l3groupId = L3_UNICAST_TYPE | (TYPE_MASK & l3unicastIndex);
final GroupKey l3groupkey = new DefaultGroupKey(Ofdpa3Pipeline.appKryo.serialize(l3unicastIndex));
outerTtb.group(new GroupId(l2groupId));
// create the l3unicast group description to wait for the
// l2 unfiltered 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, deviceId);
updatePendingGroups(l2groupkey, gce);
// create group description for the inner l2 unfiltered interface group
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 L2Unfiltered: device:{} gid:{} gkey:{} nextId:{}", deviceId, Integer.toHexString(l2groupId), l2groupkey, nextId);
return new GroupInfo(l2groupDescription, outerGrpDesc);
}
use of org.onosproject.net.flow.instructions.L2ModificationInstruction in project onos by opennetworkinglab.
the class Ofdpa3Pipeline method processDoubleTaggedFilter.
/**
* Configure filtering rules of outer and inner VLAN IDs, and a MAC address.
* Filtering happens in three tables (VLAN_TABLE, VLAN_1_TABLE, TMAC_TABLE).
*
* @param filteringObjective the filtering objective
* @param install true to add, false to remove
* @param applicationId for application programming this filter
*/
private void processDoubleTaggedFilter(FilteringObjective filteringObjective, boolean install, ApplicationId applicationId) {
PortCriterion portCriterion = null;
EthCriterion ethCriterion = null;
VlanIdCriterion innervidCriterion = null;
VlanIdCriterion outerVidCriterion = null;
boolean popVlan = false;
boolean removeDoubleTagged = true;
if (filteringObjective.meta().writeMetadata() != null) {
removeDoubleTagged = shouldRemoveDoubleTagged(filteringObjective.meta().writeMetadata());
}
log.info("HERE , removeDoubleTagged {}", removeDoubleTagged);
TrafficTreatment meta = filteringObjective.meta();
if (!filteringObjective.key().equals(Criteria.dummy()) && filteringObjective.key().type() == Criterion.Type.IN_PORT) {
portCriterion = (PortCriterion) filteringObjective.key();
}
if (portCriterion == null) {
log.warn("No IN_PORT defined in filtering objective from app: {}" + "Failed to program VLAN tables.", applicationId);
return;
} else {
log.debug("Received filtering objective for dev/port: {}/{}", deviceId, portCriterion.port());
}
// meta should have only one instruction, popVlan.
if (meta != null && meta.allInstructions().size() == 1) {
L2ModificationInstruction l2Inst = (L2ModificationInstruction) meta.allInstructions().get(0);
if (l2Inst.subtype().equals(L2SubType.VLAN_POP)) {
popVlan = true;
} else {
log.warn("Filtering objective can have only VLAN_POP instruction.");
return;
}
} else {
log.warn("Filtering objective should have one instruction.");
return;
}
FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
for (Criterion criterion : filteringObjective.conditions()) {
switch(criterion.type()) {
case ETH_DST:
case ETH_DST_MASKED:
ethCriterion = (EthCriterion) criterion;
break;
case VLAN_VID:
outerVidCriterion = (VlanIdCriterion) criterion;
break;
case INNER_VLAN_VID:
innervidCriterion = (VlanIdCriterion) criterion;
break;
default:
log.warn("Unsupported filter {}", criterion);
fail(filteringObjective, ObjectiveError.UNSUPPORTED);
return;
}
}
if (innervidCriterion == null || outerVidCriterion == null) {
log.warn("filtering objective should have two vidCriterion.");
return;
}
if (ethCriterion == null || ethCriterion.mac().equals(NONE)) {
// NOTE: it is possible that a filtering objective only has vidCriterion
log.warn("filtering objective missing dstMac, cannot program TMAC table");
return;
} else {
MacAddress unicastMac = readEthDstFromTreatment(filteringObjective.meta());
List<List<FlowRule>> allStages = processEthDstFilter(portCriterion, ethCriterion, innervidCriterion, innervidCriterion.vlanId(), unicastMac, applicationId);
for (List<FlowRule> flowRules : allStages) {
log.trace("Starting a new flow rule stage for TMAC table flow");
ops.newStage();
for (FlowRule flowRule : flowRules) {
log.trace("{} flow rules in TMAC table: {} for dev: {}", (install) ? "adding" : "removing", flowRules, deviceId);
if (install) {
ops = ops.add(flowRule);
} else {
// same VLAN on this device if TMAC doesn't support matching on in_port.
if (matchInPortTmacTable() || (filteringObjective.meta() != null && filteringObjective.meta().clearedDeferred())) {
// if metadata instruction not null and not removeDoubleTagged move on.
if ((filteringObjective.meta().writeMetadata() != null) && (!removeDoubleTagged)) {
log.info("Skipping removal of tmac rule for device {}", deviceId);
continue;
} else {
ops = ops.remove(flowRule);
}
} else {
log.debug("Abort TMAC flow removal on {}. Some other ports still share this TMAC flow");
}
}
}
}
}
List<FlowRule> rules;
rules = processDoubleVlanIdFilter(portCriterion, innervidCriterion, outerVidCriterion, popVlan, applicationId);
for (FlowRule flowRule : rules) {
log.trace("{} flow rule in VLAN table: {} for dev: {}", (install) ? "adding" : "removing", flowRule, deviceId);
// if context is remove, table is vlan_1 and removeDoubleTagged is false, continue.
if (flowRule.table().equals(IndexTableId.of(VLAN_TABLE)) && !removeDoubleTagged && !install) {
log.info("Skipping removal of vlan table rule for now!");
continue;
}
ops = install ? ops.add(flowRule) : ops.remove(flowRule);
}
// apply filtering flow rules
flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
@Override
public void onSuccess(FlowRuleOperations ops) {
log.debug("Applied {} filtering rules in device {}", ops.stages().get(0).size(), deviceId);
pass(filteringObjective);
}
@Override
public void onError(FlowRuleOperations ops) {
log.info("Failed to apply all filtering rules in dev {}", deviceId);
fail(filteringObjective, ObjectiveError.FLOWINSTALLATIONFAILED);
}
}));
}
Aggregations