use of org.onosproject.net.flow.TrafficSelector in project onos by opennetworkinglab.
the class Ofdpa2GroupHandler method createEcmpHashBucketChains.
/**
* Creates group chains for all buckets in a hashed group, and stores the
* GroupInfos and GroupKeys for all the groups in the lists passed in, which
* should be empty.
* <p>
* Does not create the top level ECMP group. Does not actually send the
* groups to the groupService.
*
* @param nextObj the Next Objective with buckets that need to be converted
* to group chains
* @param allGroupKeys a list to store groupKey for each bucket-group-chain
* @param unsentGroups a list to store GroupInfo for each bucket-group-chain
*/
protected void createEcmpHashBucketChains(NextObjective nextObj, List<Deque<GroupKey>> allGroupKeys, List<GroupInfo> unsentGroups) {
// break up hashed next objective to multiple groups
Collection<TrafficTreatment> buckets = nextObj.next();
for (TrafficTreatment bucket : buckets) {
// figure out how many labels are pushed in each bucket
int labelsPushed = 0;
MplsLabel innermostLabel = null;
for (Instruction ins : bucket.allInstructions()) {
if (ins.type() == Instruction.Type.L2MODIFICATION) {
L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
if (l2ins.subtype() == L2ModificationInstruction.L2SubType.MPLS_PUSH) {
labelsPushed++;
}
if (l2ins.subtype() == L2ModificationInstruction.L2SubType.MPLS_LABEL) {
if (innermostLabel == null) {
innermostLabel = ((L2ModificationInstruction.ModMplsLabelInstruction) l2ins).label();
}
}
}
}
Deque<GroupKey> gKeyChain = new ArrayDeque<>();
// here we only deal with 0 and 1 label push
if (labelsPushed == 0) {
GroupInfo noLabelGroupInfo;
TrafficSelector metaSelector = nextObj.meta();
if (metaSelector != null) {
if (isNotMplsBos(metaSelector)) {
noLabelGroupInfo = createL2L3Chain(bucket, nextObj.id(), nextObj.appId(), true, nextObj.meta());
} else {
noLabelGroupInfo = createL2L3Chain(bucket, nextObj.id(), nextObj.appId(), false, nextObj.meta());
}
} else {
noLabelGroupInfo = createL2L3Chain(bucket, nextObj.id(), nextObj.appId(), false, nextObj.meta());
}
if (noLabelGroupInfo == null) {
log.error("Could not process nextObj={} in dev:{}", nextObj.id(), deviceId);
return;
}
gKeyChain.addFirst(noLabelGroupInfo.innerMostGroupDesc().appCookie());
gKeyChain.addFirst(noLabelGroupInfo.nextGroupDesc().appCookie());
// we can't send the inner group description yet, as we have to
// create the dependent ECMP group first. So we store..
unsentGroups.add(noLabelGroupInfo);
} else if (labelsPushed == 1) {
GroupInfo onelabelGroupInfo = createL2L3Chain(bucket, nextObj.id(), nextObj.appId(), true, nextObj.meta());
if (onelabelGroupInfo == null) {
log.error("Could not process nextObj={} in dev:{}", nextObj.id(), deviceId);
return;
}
// we need to add another group to this chain - the L3VPN group
TrafficTreatment.Builder l3vpnTtb = DefaultTrafficTreatment.builder();
if (requireVlanPopBeforeMplsPush()) {
l3vpnTtb.popVlan();
}
l3vpnTtb.pushMpls().setMpls(innermostLabel).group(new GroupId(onelabelGroupInfo.nextGroupDesc().givenGroupId()));
if (supportCopyTtl()) {
l3vpnTtb.copyTtlOut();
}
if (supportSetMplsBos()) {
l3vpnTtb.setMplsBos(true);
}
if (requireVlanPopBeforeMplsPush()) {
l3vpnTtb.pushVlan().setVlanId(VlanId.vlanId(VlanId.RESERVED));
}
GroupBucket l3vpnGrpBkt = DefaultGroupBucket.createIndirectGroupBucket(l3vpnTtb.build());
int l3vpnIndex = getNextAvailableIndex();
int l3vpnGroupId = MPLS_L3VPN_SUBTYPE | (SUBTYPE_MASK & l3vpnIndex);
GroupKey l3vpnGroupKey = new DefaultGroupKey(appKryo.serialize(l3vpnIndex));
GroupDescription l3vpnGroupDesc = new DefaultGroupDescription(deviceId, GroupDescription.Type.INDIRECT, new GroupBuckets(Collections.singletonList(l3vpnGrpBkt)), l3vpnGroupKey, l3vpnGroupId, nextObj.appId());
GroupChainElem l3vpnGce = new GroupChainElem(l3vpnGroupDesc, 1, false, deviceId);
updatePendingGroups(onelabelGroupInfo.nextGroupDesc().appCookie(), l3vpnGce);
gKeyChain.addFirst(onelabelGroupInfo.innerMostGroupDesc().appCookie());
gKeyChain.addFirst(onelabelGroupInfo.nextGroupDesc().appCookie());
gKeyChain.addFirst(l3vpnGroupKey);
// now we can replace the outerGrpDesc with the one we just created
onelabelGroupInfo.nextGroupDesc(l3vpnGroupDesc);
// we can't send the innermost group yet, as we have to create
// the dependent ECMP group first. So we store ...
unsentGroups.add(onelabelGroupInfo);
log.debug("Trying L3VPN: device:{} gid:{} group key:{} nextId:{}", deviceId, Integer.toHexString(l3vpnGroupId), l3vpnGroupKey, nextObj.id());
} else {
log.warn("Driver currently does not handle more than 1 MPLS " + "labels. Not processing nextObjective {}", nextObj.id());
return;
}
// all groups in this chain
allGroupKeys.add(gKeyChain);
}
}
use of org.onosproject.net.flow.TrafficSelector in project onos by opennetworkinglab.
the class Ofdpa2Pipeline method processEthDstSpecific.
/**
* 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<FlowRule> processEthDstSpecific(ForwardingObjective fwd) {
List<FlowRule> 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();
if (!ethCriterion.mac().equals(NONE) && !ethCriterion.mac().equals(BROADCAST)) {
filteredSelectorBuilder.matchEthDst(ethCriterion.mac());
log.debug("processing L2 forwarding objective:{} -> next:{} in dev:{}", fwd.id(), fwd.nextId(), deviceId);
} else {
// Use wildcard DST_MAC if the MacAddress is None or Broadcast
log.debug("processing L2 Broadcast forwarding objective:{} -> next:{} " + "in dev:{} for vlan:{}", fwd.id(), fwd.nextId(), deviceId, vlanIdCriterion.vlanId());
}
if (requireVlanExtensions()) {
OfdpaMatchVlanVid ofdpaMatchVlanVid = new OfdpaMatchVlanVid(vlanIdCriterion.vlanId());
filteredSelectorBuilder.extension(ofdpaMatchVlanVid, deviceId);
} else {
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 = getGroupForNextObjective(fwd.nextId());
if (next != null) {
List<Deque<GroupKey>> 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;
}
use of org.onosproject.net.flow.TrafficSelector in project onos by opennetworkinglab.
the class Ofdpa2Pipeline method buildIpv6Selector.
/**
* Helper method to build Ipv6 selector using the selector provided by
* a forwarding objective.
*
* @param builderToUpdate the builder to update
* @param fwd the selector to read
* @return 0 if the update ends correctly. -1 if the matches
* are not yet supported
*/
int buildIpv6Selector(TrafficSelector.Builder builderToUpdate, ForwardingObjective fwd) {
TrafficSelector selector = fwd.selector();
IpPrefix ipv6Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV6_DST)).ip();
if (ipv6Dst.isMulticast()) {
if (ipv6Dst.prefixLength() != IpAddress.INET6_BIT_LENGTH) {
log.warn("Multicast specific forwarding objective can only be /128");
fail(fwd, ObjectiveError.BADPARAMS);
return -1;
}
VlanId assignedVlan = readVlanFromSelector(fwd.meta());
if (assignedVlan == null) {
log.warn("VLAN ID required by multicast specific fwd obj is missing. Abort.");
fail(fwd, ObjectiveError.BADPARAMS);
return -1;
}
if (requireVlanExtensions()) {
OfdpaMatchVlanVid ofdpaMatchVlanVid = new OfdpaMatchVlanVid(assignedVlan);
builderToUpdate.extension(ofdpaMatchVlanVid, deviceId);
} else {
builderToUpdate.matchVlanId(assignedVlan);
}
builderToUpdate.matchEthType(Ethernet.TYPE_IPV6).matchIPv6Dst(ipv6Dst);
log.debug("processing IPv6 multicast specific forwarding objective {} -> next:{}" + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
} else {
if (ipv6Dst.prefixLength() != 0) {
builderToUpdate.matchIPv6Dst(ipv6Dst);
}
builderToUpdate.matchEthType(Ethernet.TYPE_IPV6);
log.debug("processing IPv6 unicast specific forwarding objective {} -> next:{}" + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
}
return 0;
}
use of org.onosproject.net.flow.TrafficSelector in project onos by opennetworkinglab.
the class Ofdpa2Pipeline method buildIpv4Selector.
private int buildIpv4Selector(TrafficSelector.Builder builderToUpdate, TrafficSelector.Builder extBuilder, ForwardingObjective fwd, boolean allowDefaultRoute) {
TrafficSelector selector = fwd.selector();
IpPrefix ipv4Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip();
if (ipv4Dst.isMulticast()) {
if (ipv4Dst.prefixLength() != 32) {
log.warn("Multicast specific forwarding objective can only be /32");
fail(fwd, ObjectiveError.BADPARAMS);
return -1;
}
VlanId assignedVlan = readVlanFromSelector(fwd.meta());
if (assignedVlan == null) {
log.warn("VLAN ID required by multicast specific fwd obj is missing. Abort.");
fail(fwd, ObjectiveError.BADPARAMS);
return -1;
}
if (requireVlanExtensions()) {
OfdpaMatchVlanVid ofdpaMatchVlanVid = new OfdpaMatchVlanVid(assignedVlan);
builderToUpdate.extension(ofdpaMatchVlanVid, deviceId);
} else {
builderToUpdate.matchVlanId(assignedVlan);
}
builderToUpdate.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
log.debug("processing IPv4 multicast specific forwarding objective {} -> next:{}" + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
} else {
if (ipv4Dst.prefixLength() == 0) {
if (allowDefaultRoute) {
// The entire IPV4_DST field is wildcarded intentionally
builderToUpdate.matchEthType(Ethernet.TYPE_IPV4);
} else {
// NOTE: The switch does not support matching 0.0.0.0/0
// Split it into 0.0.0.0/1 and 128.0.0.0/1
builderToUpdate.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(IpPrefix.valueOf("0.0.0.0/1"));
extBuilder.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(IpPrefix.valueOf("128.0.0.0/1"));
}
} else {
builderToUpdate.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
}
log.debug("processing IPv4 unicast specific forwarding objective {} -> next:{}" + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
}
return 0;
}
use of org.onosproject.net.flow.TrafficSelector in project onos by opennetworkinglab.
the class Ofdpa2Pipeline method processEthTypeSpecificInternal.
/**
* Internal implementation of processEthTypeSpecific.
* <p>
* Wildcarded IPv4_DST is not supported in OFDPA i12. Therefore, we break
* the rule into 0.0.0.0/1 and 128.0.0.0/1.
* The allowDefaultRoute must be set to false for OFDPA i12.
* </p>
*
* @param fwd the forwarding objective
* @param allowDefaultRoute allow wildcarded IPv4_DST or not
* @param mplsNextTable next MPLS table
* @return A collection of flow rules, or an empty set
*/
protected Collection<FlowRule> processEthTypeSpecificInternal(ForwardingObjective fwd, boolean allowDefaultRoute, int mplsNextTable) {
TrafficSelector selector = fwd.selector();
EthTypeCriterion ethType = (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
boolean emptyGroup = false;
int forTableId;
TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder();
TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
TrafficSelector.Builder complementarySelector = DefaultTrafficSelector.builder();
if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
if (buildIpv4Selector(filteredSelector, complementarySelector, fwd, allowDefaultRoute) < 0) {
return Collections.emptyList();
}
// We need to set properly the next table
IpPrefix ipv4Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip();
if (ipv4Dst.isMulticast()) {
forTableId = MULTICAST_ROUTING_TABLE;
} else {
forTableId = UNICAST_ROUTING_TABLE;
}
// TODO decrementing IP ttl is done automatically for routing, this
// action is ignored or rejected in ofdpa as it is not fully implemented
// if (fwd.treatment() != null) {
// for (Instruction instr : fwd.treatment().allInstructions()) {
// if (instr instanceof L3ModificationInstruction &&
// ((L3ModificationInstruction) instr).subtype() == L3SubType.DEC_TTL) {
// tb.deferred().add(instr);
// }
// }
// }
} else if (ethType.ethType().toShort() == Ethernet.TYPE_IPV6) {
if (buildIpv6Selector(filteredSelector, fwd) < 0) {
return Collections.emptyList();
}
// We need to set the proper next table
IpPrefix ipv6Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV6_DST)).ip();
if (ipv6Dst.isMulticast()) {
forTableId = MULTICAST_ROUTING_TABLE;
} else {
forTableId = UNICAST_ROUTING_TABLE;
}
// TODO decrementing IP ttl is done automatically for routing, this
// action is ignored or rejected in ofdpa as it is not fully implemented
// if (fwd.treatment() != null) {
// for (Instruction instr : fwd.treatment().allInstructions()) {
// if (instr instanceof L3ModificationInstruction &&
// ((L3ModificationInstruction) instr).subtype() == L3SubType.DEC_TTL) {
// tb.deferred().add(instr);
// }
// }
// }
} else {
filteredSelector.matchEthType(Ethernet.MPLS_UNICAST).matchMplsLabel(((MplsCriterion) selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
MplsBosCriterion bos = (MplsBosCriterion) selector.getCriterion(MPLS_BOS);
if (bos != null && requireMplsBosMatch()) {
filteredSelector.matchMplsBos(bos.mplsBos());
}
forTableId = MPLS_TABLE_1;
log.debug("processing MPLS specific forwarding objective {} -> next:{}" + " in dev {}", fwd.id(), fwd.nextId(), deviceId);
if (fwd.treatment() != null) {
for (Instruction instr : fwd.treatment().allInstructions()) {
if (instr instanceof L2ModificationInstruction && ((L2ModificationInstruction) instr).subtype() == L2SubType.MPLS_POP) {
// setting the MPLS_TYPE so pop can happen down the pipeline
if (requireMplsPop()) {
if (mplsNextTable == MPLS_TYPE_TABLE && isNotMplsBos(selector)) {
tb.immediate().popMpls();
}
} else {
// Skip mpls pop action for mpls_unicast label
if (instr instanceof ModMplsHeaderInstruction && !((ModMplsHeaderInstruction) instr).ethernetType().equals(EtherType.MPLS_UNICAST.ethType())) {
tb.immediate().add(instr);
}
}
}
if (requireMplsTtlModification()) {
if (instr instanceof L3ModificationInstruction && ((L3ModificationInstruction) instr).subtype() == L3SubType.DEC_TTL) {
// FIXME Should modify the app to send the correct DEC_MPLS_TTL instruction
tb.immediate().decMplsTtl();
}
if (instr instanceof L3ModificationInstruction && ((L3ModificationInstruction) instr).subtype() == L3SubType.TTL_IN) {
tb.immediate().add(instr);
}
}
}
}
}
if (fwd.nextId() != null) {
NextGroup next = getGroupForNextObjective(fwd.nextId());
if (next != null) {
List<Deque<GroupKey>> 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) {
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();
}
if (isNotMplsBos(selector) && group.type().equals(SELECT)) {
log.warn("SR CONTINUE case cannot be handled as MPLS ECMP " + "is not implemented in OF-DPA yet. Aborting flow {} -> next:{} " + "in this device {}", fwd.id(), fwd.nextId(), deviceId);
fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
return Collections.emptySet();
}
tb.deferred().group(group.id());
// retrying flows may be necessary due to bug CORD-554
if (gkeys.size() == 1 && gkeys.get(0).size() == 1) {
if (shouldRetry()) {
log.warn("Found empty group 0x{} in dev:{} .. will retry fwd:{}", Integer.toHexString(group.id().id()), deviceId, fwd.id());
emptyGroup = true;
}
}
} else {
log.warn("Cannot find group for nextId:{} in dev:{}. Aborting fwd:{}", fwd.nextId(), deviceId, fwd.id());
fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
return Collections.emptySet();
}
}
if (forTableId == MPLS_TABLE_1) {
if (mplsNextTable == MPLS_L3_TYPE_TABLE) {
Ofdpa3SetMplsType setMplsType = new Ofdpa3SetMplsType(Ofdpa3MplsType.L3_PHP);
// set mpls type as apply_action
tb.immediate().extension(setMplsType, deviceId);
}
tb.transition(mplsNextTable);
} else {
tb.transition(ACL_TABLE);
}
if (fwd.treatment() != null && fwd.treatment().clearedDeferred()) {
if (supportsUnicastBlackHole()) {
tb.wipeDeferred();
} else {
log.warn("Clear Deferred is not supported Unicast Routing Table on device {}", deviceId);
return Collections.emptySet();
}
}
FlowRule.Builder ruleBuilder = DefaultFlowRule.builder().fromApp(fwd.appId()).withPriority(fwd.priority()).forDevice(deviceId).withSelector(filteredSelector.build()).withTreatment(tb.build()).forTable(forTableId);
if (fwd.permanent()) {
ruleBuilder.makePermanent();
} else {
ruleBuilder.makeTemporary(fwd.timeout());
}
Collection<FlowRule> flowRuleCollection = new ArrayList<>();
flowRuleCollection.add(ruleBuilder.build());
if (!allowDefaultRoute) {
flowRuleCollection.add(defaultRoute(fwd, complementarySelector, forTableId, tb));
log.debug("Default rule 0.0.0.0/0 is being installed two rules");
}
if (emptyGroup) {
retryExecutorService.schedule(new RetryFlows(fwd, flowRuleCollection), RETRY_MS, TimeUnit.MILLISECONDS);
}
return flowRuleCollection;
}
Aggregations