use of org.onosproject.net.flow.FlowRule 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.FlowRule in project onos by opennetworkinglab.
the class Ofdpa2Pipeline method sendForwards.
// Builds the batch using the accumulated flow rules
private void sendForwards(List<Pair<ForwardingObjective, Collection<FlowRule>>> pairs) {
FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
log.debug("Sending {} fwd-objs", pairs.size());
List<Objective> fwdObjs = Lists.newArrayList();
// Iterates over all accumulated flow rules and then build an unique batch
pairs.forEach(pair -> {
ForwardingObjective fwd = pair.getLeft();
Collection<FlowRule> rules = pair.getRight();
switch(fwd.op()) {
case ADD:
rules.stream().filter(Objects::nonNull).forEach(flowOpsBuilder::add);
log.debug("Applying a add fwd-obj {} to sw:{}", fwd.id(), deviceId);
fwdObjs.add(fwd);
break;
case REMOVE:
rules.stream().filter(Objects::nonNull).forEach(flowOpsBuilder::remove);
log.debug("Deleting a flow rule to sw:{}", deviceId);
fwdObjs.add(fwd);
break;
default:
fail(fwd, ObjectiveError.UNKNOWN);
log.warn("Unknown forwarding type {}", fwd.op());
}
});
// Finally applies the operations
flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
@Override
public void onSuccess(FlowRuleOperations ops) {
log.trace("Flow rule operations onSuccess {}", ops);
fwdObjs.forEach(OfdpaPipelineUtility::pass);
}
@Override
public void onError(FlowRuleOperations ops) {
ObjectiveError error = ObjectiveError.FLOWINSTALLATIONFAILED;
log.warn("Flow rule operations onError {}. Reason = {}", ops, error);
fwdObjs.forEach(fwdObj -> fail(fwdObj, error));
}
}));
}
use of org.onosproject.net.flow.FlowRule in project onos by opennetworkinglab.
the class Ofdpa2Pipeline method processVersatile.
/**
* In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the
* ACL table.
* @param fwd the forwarding objective of type 'versatile'
* @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> processVersatile(ForwardingObjective fwd) {
log.debug("Processing versatile forwarding objective:{} in dev:{}", fwd.id(), deviceId);
List<FlowRule> flowRules = new ArrayList<>();
final AtomicBoolean ethTypeUsed = new AtomicBoolean(false);
if (fwd.nextId() == null && fwd.treatment() == null) {
log.error("Forwarding objective {} from {} must contain " + "nextId or Treatment", fwd.selector(), fwd.appId());
fail(fwd, ObjectiveError.BADPARAMS);
return Collections.emptySet();
}
TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
fwd.selector().criteria().forEach(criterion -> {
if (criterion instanceof VlanIdCriterion) {
VlanId vlanId = ((VlanIdCriterion) criterion).vlanId();
// match untagged packets this way in the ACL table.
if (vlanId.equals(VlanId.NONE)) {
return;
}
if (requireVlanExtensions()) {
OfdpaMatchVlanVid ofdpaMatchVlanVid = new OfdpaMatchVlanVid(vlanId);
sbuilder.extension(ofdpaMatchVlanVid, deviceId);
} else {
sbuilder.matchVlanId(vlanId);
}
} else if (criterion instanceof Icmpv6TypeCriterion) {
byte icmpv6Type = (byte) ((Icmpv6TypeCriterion) criterion).icmpv6Type();
sbuilder.matchIcmpv6Type(icmpv6Type);
} else if (criterion instanceof Icmpv6CodeCriterion) {
byte icmpv6Code = (byte) ((Icmpv6CodeCriterion) criterion).icmpv6Code();
sbuilder.matchIcmpv6Type(icmpv6Code);
} else if (criterion instanceof TcpPortCriterion || criterion instanceof UdpPortCriterion) {
// We need to revisit this if L4 dst port is used for other purpose in the future.
if (!supportIpv6L4Dst() && isIpv6(fwd.selector())) {
switch(criterion.type()) {
case UDP_DST:
case UDP_DST_MASKED:
case TCP_DST:
case TCP_DST_MASKED:
break;
default:
sbuilder.add(criterion);
}
} else {
sbuilder.add(criterion);
}
} else if (criterion instanceof EthTypeCriterion) {
sbuilder.add(criterion);
ethTypeUsed.set(true);
} else {
sbuilder.add(criterion);
}
});
TrafficTreatment.Builder ttBuilder = versatileTreatmentBuilder(fwd);
if (ttBuilder == null) {
return Collections.emptySet();
}
FlowRule.Builder ruleBuilder = DefaultFlowRule.builder().fromApp(fwd.appId()).withPriority(fwd.priority()).forDevice(deviceId).withSelector(sbuilder.build()).withTreatment(ttBuilder.build()).makePermanent().forTable(ACL_TABLE);
flowRules.add(ruleBuilder.build());
if (!ethTypeUsed.get() && requireEthType()) {
log.debug("{} doesn't match on ethType but requireEthType is true, adding complementary ACL flow.", sbuilder.toString());
sbuilder.matchEthType(Ethernet.TYPE_IPV6);
FlowRule.Builder ethTypeRuleBuilder = DefaultFlowRule.builder().fromApp(fwd.appId()).withPriority(fwd.priority()).forDevice(deviceId).withSelector(sbuilder.build()).withTreatment(ttBuilder.build()).makePermanent().forTable(ACL_TABLE);
flowRules.add(ethTypeRuleBuilder.build());
}
return flowRules;
}
use of org.onosproject.net.flow.FlowRule in project onos by opennetworkinglab.
the class Ofdpa2Pipeline method processFilter.
// ////////////////////////////////////
// Flow handling
// ////////////////////////////////////
/**
* As per OFDPA 2.0 TTP, filtering of VLAN ids and MAC addresses (for routing)
* configured on switch ports happen in different tables.
*
* @param filt the filtering objective
* @param install indicates whether to add or remove the objective
* @param applicationId the application that sent this objective
*/
protected void processFilter(FilteringObjective filt, boolean install, ApplicationId applicationId) {
// This driver only processes filtering criteria defined with switch
// ports as the key
PortCriterion portCriterion = null;
EthCriterion ethCriterion = null;
VlanIdCriterion vidCriterion = null;
if (!filt.key().equals(Criteria.dummy()) && filt.key().type() == Criterion.Type.IN_PORT) {
portCriterion = (PortCriterion) filt.key();
}
if (portCriterion == null) {
log.debug("No IN_PORT defined in filtering objective from app: {}", applicationId);
} else {
log.debug("Received filtering objective for dev/port: {}/{}", deviceId, portCriterion.port());
}
// convert filtering conditions for switch-intfs into flowrules
FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
for (Criterion criterion : filt.conditions()) {
switch(criterion.type()) {
case ETH_DST:
case ETH_DST_MASKED:
ethCriterion = (EthCriterion) criterion;
break;
case VLAN_VID:
vidCriterion = (VlanIdCriterion) criterion;
break;
default:
log.warn("Unsupported filter {}", criterion);
fail(filt, ObjectiveError.UNSUPPORTED);
return;
}
}
VlanId assignedVlan = null;
if (vidCriterion != null) {
// Use the VLAN in criterion if metadata is not present and the traffic is tagged
if (!vidCriterion.vlanId().equals(VlanId.NONE)) {
assignedVlan = vidCriterion.vlanId();
}
// If the meta VLAN is present let's update the assigned vlan
if (filt.meta() != null) {
VlanId metaVlan = readVlanFromTreatment(filt.meta());
if (metaVlan != null) {
assignedVlan = metaVlan;
}
}
if (assignedVlan == null) {
log.error("Driver fails to extract VLAN information. " + "Not processing VLAN filters on device {}.", deviceId);
log.debug("VLAN ID in criterion={}, metadata={}", readVlanFromTreatment(filt.meta()), vidCriterion.vlanId());
fail(filt, ObjectiveError.BADPARAMS);
return;
}
}
if (ethCriterion == null || ethCriterion.mac().equals(NONE)) {
// NOTE: it is possible that a filtering objective only has vidCriterion
log.debug("filtering objective missing dstMac, won't program TMAC table");
} else {
MacAddress unicastMac = readEthDstFromTreatment(filt.meta());
List<List<FlowRule>> allStages = processEthDstFilter(portCriterion, ethCriterion, vidCriterion, assignedVlan, 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 rule in TMAC table: {} for dev: {}", (install) ? "adding" : "removing", flowRule, deviceId);
if (install) {
ops = ops.add(flowRule);
} else {
// same VLAN on this device if TMAC doesn't support matching on in_port.
if (filt.meta() != null && filt.meta().clearedDeferred()) {
// TMac mcast does not match on the input port - we have to remove it
// only if this is the last port
FlowRule rule = buildTmacRuleForMcastFromUnicast(flowRule, applicationId);
// IPv6 or IPv4 tmac rule
if (rule != null) {
// Add first the mcast rule and then open a new stage for the unicast
ops = ops.remove(rule);
ops.newStage();
}
ops = ops.remove(flowRule);
} else if (matchInPortTmacTable()) {
ops = ops.remove(flowRule);
} else {
log.debug("Abort TMAC flow removal on {}. " + "Some other ports still share this TMAC flow", deviceId);
}
}
}
}
}
if (vidCriterion == null) {
// NOTE: it is possible that a filtering objective only has ethCriterion
log.info("filtering objective missing VLAN, cannot program VLAN Table");
} else {
List<List<FlowRule>> allStages = processVlanIdFilter(portCriterion, vidCriterion, assignedVlan, applicationId, install);
for (List<FlowRule> flowRules : allStages) {
log.trace("Starting a new flow rule stage for VLAN table flow");
ops.newStage();
for (FlowRule flowRule : flowRules) {
log.trace("{} flow rules in VLAN table: {} for dev: {}", (install) ? "adding" : "removing", flowRule, deviceId);
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(filt);
}
@Override
public void onError(FlowRuleOperations ops) {
log.info("Failed to apply all filtering rules in dev {}", deviceId);
fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
}
}));
}
use of org.onosproject.net.flow.FlowRule in project onos by opennetworkinglab.
the class Ofdpa2Pipeline method processEthDstOnlyFilter.
protected List<List<FlowRule>> processEthDstOnlyFilter(EthCriterion ethCriterion, ApplicationId applicationId) {
ImmutableList.Builder<FlowRule> builder = ImmutableList.builder();
TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
selector.matchEthType(Ethernet.TYPE_IPV4);
selector.matchEthDst(ethCriterion.mac());
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();
builder.add(rule);
selector = DefaultTrafficSelector.builder();
treatment = DefaultTrafficTreatment.builder();
selector.matchEthType(Ethernet.TYPE_IPV6);
selector.matchEthDst(ethCriterion.mac());
treatment.transition(UNICAST_ROUTING_TABLE);
rule = DefaultFlowRule.builder().forDevice(deviceId).withSelector(selector.build()).withTreatment(treatment.build()).withPriority(DEFAULT_PRIORITY).fromApp(applicationId).makePermanent().forTable(TMAC_TABLE).build();
return ImmutableList.of(builder.add(rule).build());
}
Aggregations