use of org.onosproject.net.flow.instructions.Instruction in project onos by opennetworkinglab.
the class OvsOfdpaPipeline method versatileTreatmentBuilder.
@Override
protected TrafficTreatment.Builder versatileTreatmentBuilder(ForwardingObjective fwd) {
// XXX driver does not currently do type checking as per Tables 65-67 in
// OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
if (fwd.treatment() != null) {
for (Instruction ins : fwd.treatment().allInstructions()) {
if (ins instanceof OutputInstruction) {
OutputInstruction o = (OutputInstruction) ins;
if (PortNumber.CONTROLLER.equals(o.port())) {
ttBuilder.transition(PUNT_TABLE);
} else {
log.warn("Only allowed treatments in versatile forwarding " + "objectives are punts to the controller");
}
} else if (ins instanceof NoActionInstruction) {
// No action is allowed and nothing needs to be done
} else {
log.warn("Cannot process instruction in versatile fwd {}", ins);
}
}
if (fwd.treatment().clearedDeferred()) {
ttBuilder.wipeDeferred();
}
}
if (fwd.nextId() != null) {
// Override case
NextGroup next = getGroupForNextObjective(fwd.nextId());
if (next == null) {
fail(fwd, ObjectiveError.BADPARAMS);
return 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 null;
}
ttBuilder.deferred().group(group.id());
}
return ttBuilder;
}
use of org.onosproject.net.flow.instructions.Instruction in project onos by opennetworkinglab.
the class OvsOfdpaPipeline method processEthTypeSpecific.
/*
* Open vSwitch emulation allows MPLS ECMP.
*
* (non-Javadoc)
* @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthTypeSpecific
*/
@Override
protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
if (isDoubleTagged(fwd)) {
return processDoubleTaggedFwd(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) && (ethType.ethType().toShort() != Ethernet.TYPE_IPV6)) {
log.warn("processSpecific: Unsupported forwarding objective criteria" + "ethType:{} in dev:{}", ethType, deviceId);
fail(fwd, ObjectiveError.UNSUPPORTED);
return Collections.emptySet();
}
boolean defaultRule = false;
int forTableId;
TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder();
TrafficSelector.Builder complementarySelector = DefaultTrafficSelector.builder();
if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
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 ImmutableSet.of();
}
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 ImmutableSet.of();
}
filteredSelector.matchVlanId(assignedVlan);
filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
forTableId = MULTICAST_ROUTING_TABLE;
log.debug("processing IPv4 multicast specific forwarding objective {} -> next:{}" + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
} else {
if (ipv4Dst.prefixLength() == 0) {
// The entire IPV4_DST field is wildcarded intentionally
filteredSelector.matchEthType(Ethernet.TYPE_IPV4);
} else {
filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
}
forTableId = UNICAST_ROUTING_TABLE;
log.debug("processing IPv4 unicast specific forwarding objective {} -> next:{}" + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
}
} else if (ethType.ethType().toShort() == Ethernet.TYPE_IPV6) {
IpPrefix ipv6Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV6_DST)).ip();
if (ipv6Dst.isMulticast()) {
if (ipv6Dst.prefixLength() != IpAddress.INET6_BIT_LENGTH) {
log.debug("Multicast specific IPv6 forwarding objective can only be /128");
fail(fwd, ObjectiveError.BADPARAMS);
return ImmutableSet.of();
}
VlanId assignedVlan = readVlanFromSelector(fwd.meta());
if (assignedVlan == null) {
log.debug("VLAN ID required by multicast specific fwd obj is missing. Abort.");
fail(fwd, ObjectiveError.BADPARAMS);
return ImmutableSet.of();
}
filteredSelector.matchVlanId(assignedVlan);
filteredSelector.matchEthType(Ethernet.TYPE_IPV6).matchIPv6Dst(ipv6Dst);
forTableId = MULTICAST_ROUTING_TABLE;
log.debug("processing IPv6 multicast specific forwarding objective {} -> next:{}" + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
} else {
if (buildIpv6Selector(filteredSelector, fwd) < 0) {
return Collections.emptyList();
}
forTableId = UNICAST_ROUTING_TABLE;
}
} else {
filteredSelector.matchEthType(Ethernet.MPLS_UNICAST).matchMplsLabel(((MplsCriterion) selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
MplsBosCriterion bos = (MplsBosCriterion) selector.getCriterion(Criterion.Type.MPLS_BOS);
if (bos != null) {
filteredSelector.matchMplsBos(bos.mplsBos());
}
forTableId = MPLS_TABLE_1;
log.debug("processing MPLS specific forwarding objective {} -> next:{}" + " in dev {}", fwd.id(), fwd.nextId(), deviceId);
}
TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
if (fwd.treatment() != null) {
for (Instruction i : fwd.treatment().allInstructions()) {
if (i instanceof L3ModificationInstruction) {
L3ModificationInstruction l3instr = (L3ModificationInstruction) i;
if (l3instr.subtype().equals(L3ModificationInstruction.L3SubType.TTL_IN) || l3instr.subtype().equals(L3ModificationInstruction.L3SubType.TTL_OUT)) {
continue;
}
}
/*
* NOTE: OF-DPA does not support immediate instruction in
* L3 unicast and MPLS table.
*/
tb.deferred().add(i);
}
}
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();
}
tb.deferred().group(group.id());
}
}
tb.transition(ACL_TABLE);
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 (defaultRule) {
flowRuleCollection.add(defaultRoute(fwd, complementarySelector, forTableId, tb));
log.debug("Default rule 0.0.0.0/0 is being installed two rules");
}
return flowRuleCollection;
}
use of org.onosproject.net.flow.instructions.Instruction in project onos by opennetworkinglab.
the class OvsOfdpaPipeline 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
*/
@Override
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 Instructions.OutputInstruction).findFirst();
if (!outInstr.isPresent()) {
log.error("Egress forwarding objective:{} must include output port", fwd.id());
fail(fwd, ObjectiveError.BADPARAMS);
return rules;
}
PortNumber portNumber = ((Instructions.OutputInstruction) outInstr.get()).port();
sb.matchVlanId(vlanIdCriterion.vlanId());
OfdpaMatchActsetOutput actsetOutput = new OfdpaMatchActsetOutput(portNumber);
sb.extension(actsetOutput, deviceId);
// Build a flow rule for Egress VLAN Flow table
TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
tb.transition(UNICAST_ROUTING_TABLE_1);
if (fwd.treatment() != null) {
for (Instruction instr : fwd.treatment().allInstructions()) {
if (instr instanceof L2ModificationInstruction && ((L2ModificationInstruction) instr).subtype() == L2ModificationInstruction.L2SubType.VLAN_ID) {
tb.immediate().add(instr);
}
if (instr instanceof L2ModificationInstruction && ((L2ModificationInstruction) instr).subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
EthType ethType = ((L2ModificationInstruction.ModVlanHeaderInstruction) instr).ethernetType();
tb.immediate().pushVlan(ethType);
}
}
}
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_IN_INGRESS);
rules.add(ruleBuilder.build());
return rules;
}
use of org.onosproject.net.flow.instructions.Instruction in project onos by opennetworkinglab.
the class OfdpaPipelineTraceable method apply.
@Override
public PipelineTraceableOutput apply(PipelineTraceableInput input) {
PipelineTraceableOutput.Builder outputBuilder = PipelineTraceableOutput.builder();
log.debug("Current packet {} - applying flow tables", input.ingressPacket());
List<FlowEntry> outputFlows = new ArrayList<>();
List<Instruction> deferredInstructions = new ArrayList<>();
PipelineTraceableHitChain currentHitChain = PipelineTraceableHitChain.emptyHitChain();
TrafficSelector currentPacket = DefaultTrafficSelector.builder(input.ingressPacket().packet()).build();
// Init step - find out the first table
int initialTableId = -1;
FlowEntry nextTableIdEntry = findNextTableIdEntry(initialTableId, input.flows());
if (nextTableIdEntry == null) {
currentHitChain.setEgressPacket(new PipelineTraceablePacket(currentPacket));
currentHitChain.dropped();
return outputBuilder.appendToLog("No flow rules for device " + deviceId + ". Aborting").noFlows().addHitChain(currentHitChain).build();
}
// Iterates over the flow tables until the end of the pipeline
TableId tableId = nextTableIdEntry.table();
FlowEntry flowEntry;
boolean lastTable = false;
while (!lastTable) {
log.debug("Searching a Flow Entry on table {} for packet {}", tableId, currentPacket);
// Gets the rule that matches the incoming packet
flowEntry = matchHighestPriority(currentPacket, tableId, input.flows());
log.debug("Found Flow Entry {}", flowEntry);
// If the flow entry on a table is null and we are on hardware we treat as table miss, with few exceptions
if (flowEntry == null && isHardwareSwitch()) {
log.debug("Ofdpa Hw setup, no flow rule means table miss");
if (((IndexTableId) tableId).id() == MPLS_L3_TYPE_TABLE) {
// Apparently a miss but Table 27 on OFDPA is a fixed table
currentPacket = handleOfdpa27FixedTable(input.ingressPacket().packet(), currentPacket);
// The nextTable should be ACL
tableId = IndexTableId.of(ACL_TABLE - 1);
}
// Finding next table to go In case of miss
nextTableIdEntry = findNextTableIdEntry(((IndexTableId) tableId).id(), input.flows());
log.debug("Next table id entry {}", nextTableIdEntry);
// (another possibility is max tableId)
if (nextTableIdEntry == null && currentHitChain.hitChain().size() == 0) {
currentHitChain.setEgressPacket(new PipelineTraceablePacket(currentPacket));
currentHitChain.dropped();
return outputBuilder.appendToLog("No flow rules for device " + deviceId + ". Aborting").noFlows().addHitChain(currentHitChain).build();
} else if (nextTableIdEntry == null) {
// Means that no more flow rules are present
lastTable = true;
} else if (((IndexTableId) tableId).id() == TMAC_TABLE) {
// If the table is 20 OFDPA skips to table 50
log.debug("A miss on Table 20 on OFDPA means that we skip directly to table 50");
tableId = IndexTableId.of(BRIDGING_TABLE);
} else if (((IndexTableId) tableId).id() == MULTICAST_ROUTING_TABLE) {
// If the table is 40 OFDPA skips to table 60
log.debug("A miss on Table 40 on OFDPA means that we skip directly to table 60");
tableId = IndexTableId.of(ACL_TABLE);
} else {
tableId = nextTableIdEntry.table();
}
} else if (flowEntry == null) {
currentHitChain.setEgressPacket(new PipelineTraceablePacket(currentPacket));
currentHitChain.dropped();
return outputBuilder.appendToLog("Packet has no match on table " + tableId + " in device " + deviceId + ". Dropping").noFlows().addHitChain(currentHitChain).build();
} else {
// If the table has a transition
if (flowEntry.treatment().tableTransition() != null) {
// Updates the next table we transitions to
tableId = IndexTableId.of(flowEntry.treatment().tableTransition().tableId());
log.debug("Flow Entry has transition to table Id {}", tableId);
currentHitChain.addDataPlaneEntity(new DataPlaneEntity(flowEntry));
} else {
// Table has no transition so it means that it's an output rule if on the last table
log.debug("Flow Entry has no transition to table, treating as last rule {}", flowEntry);
currentHitChain.addDataPlaneEntity(new DataPlaneEntity(flowEntry));
outputFlows.add(flowEntry);
lastTable = true;
}
// Updates the packet according to the immediate actions of this flow rule.
currentPacket = updatePacket(currentPacket, flowEntry.treatment().immediate()).build();
// Saves the deferred rules for later maintaining the order
deferredInstructions.addAll(flowEntry.treatment().deferred());
// If the flow requires to clear deferred actions we do so for all the ones we encountered.
if (flowEntry.treatment().clearedDeferred()) {
deferredInstructions.clear();
}
// On table 10 OFDPA needs two rules to apply the vlan if none and then to transition to the next table.
if (shouldMatchSecondVlanFlow(flowEntry)) {
// Let's get the packet vlanId instruction
VlanIdCriterion packetVlanIdCriterion = (VlanIdCriterion) currentPacket.getCriterion(Criterion.Type.VLAN_VID);
// Let's get the flow entry vlan mod instructions
ModVlanIdInstruction entryModVlanIdInstruction = (ModVlanIdInstruction) flowEntry.treatment().immediate().stream().filter(instruction -> instruction instanceof ModVlanIdInstruction).findFirst().orElse(null);
// is a flow rule that matches on same criteria and with updated vlanId
if (entryModVlanIdInstruction != null) {
FlowEntry secondVlanFlow = getSecondFlowEntryOnTable10(currentPacket, packetVlanIdCriterion, entryModVlanIdInstruction, input.flows());
// We found the flow that we expected
if (secondVlanFlow != null) {
currentHitChain.addDataPlaneEntity(new DataPlaneEntity(secondVlanFlow));
} else {
currentHitChain.setEgressPacket(new PipelineTraceablePacket(currentPacket));
currentHitChain.dropped();
return outputBuilder.appendToLog("Missing forwarding rule for tagged" + " packet on " + deviceId).noFlows().addHitChain(currentHitChain).build();
}
}
}
}
}
// Creating a modifiable builder for the egress packet
TrafficSelector.Builder egressPacket = DefaultTrafficSelector.builder(currentPacket);
log.debug("Current packet {} - applying output flows", currentPacket);
// Handling output flows which basically means handling output to controller.
// OVS and OFDPA have both immediate -> OUTPUT:CONTROLLER. Theoretically there is no
// need to reflect the updates performed on the packets and on the chain.
List<PortNumber> outputPorts = new ArrayList<>();
handleOutputFlows(currentPacket, outputFlows, egressPacket, outputPorts, currentHitChain, outputBuilder, input.ingressPacket().packet());
// Immediate instructions
log.debug("Current packet {} - applying immediate instructions", currentPacket);
// Handling immediate instructions which basically means handling output to controller.
// OVS has immediate -> group -> OUTPUT:CONTROLLER.
List<DataPlaneEntity> entries = ImmutableList.copyOf(currentHitChain.hitChain());
// Go to the next step - using a copy of the egress packet and of the hit chain
PipelineTraceableHitChain newHitChain = PipelineTraceableHitChain.emptyHitChain();
currentHitChain.hitChain().forEach(newHitChain::addDataPlaneEntity);
TrafficSelector.Builder newEgressPacket = DefaultTrafficSelector.builder(egressPacket.build());
for (DataPlaneEntity entry : entries) {
flowEntry = entry.getFlowEntry();
if (flowEntry != null) {
getGroupsFromInstructions(input.groups(), flowEntry.treatment().immediate(), newEgressPacket, outputPorts, newHitChain, outputBuilder, input, false);
}
}
// Deferred instructions
log.debug("Current packet {} - applying deferred instructions", egressPacket.build());
// egress packet and of the hit chain. This is the last step.
if (deferredInstructions.size() > 0) {
handleDeferredActions(egressPacket.build(), input.groups(), deferredInstructions, outputPorts, currentHitChain, outputBuilder, input);
}
// Let's store the partial hit chain and set a message
if (outputPorts.isEmpty()) {
currentHitChain.setEgressPacket(new PipelineTraceablePacket(egressPacket.build()));
currentHitChain.dropped();
outputBuilder.appendToLog("Packet has no output in device " + deviceId + ". Dropping").dropped().addHitChain(currentHitChain);
}
// Done!
return outputBuilder.build();
}
use of org.onosproject.net.flow.instructions.Instruction in project onos by opennetworkinglab.
the class LinkCollectionCompiler method generateEgressActions.
/**
* Helper method to generate the egress actions.
*
* @param treatmentBuilder the treatment builder to update
* @param egressPoints the egress points
* @param initialState the initial state of the transition
*/
private void generateEgressActions(TrafficTreatment.Builder treatmentBuilder, List<FilteredConnectPoint> egressPoints, TrafficSelector initialState, LinkCollectionIntent intent) {
TrafficSelector prevState = initialState;
for (FilteredConnectPoint egressPoint : egressPoints) {
/*
* If we are at the egress, we have to transit to the final
* state. First we add the Intent treatment.
*/
intent.treatment().allInstructions().stream().filter(inst -> inst.type() != Instruction.Type.NOACTION).forEach(treatmentBuilder::add);
/*
* We generate the transition FIP->FEP.
*/
TrafficTreatment forwardingTreatment = forwardingTreatment(prevState, egressPoint.trafficSelector(), getEthType(intent.selector()));
/*
* We add the instruction necessary to the transition.
* Potentially we override the intent treatment.
*/
forwardingTreatment.allInstructions().stream().filter(inst -> inst.type() != Instruction.Type.NOACTION).forEach(treatmentBuilder::add);
/*
* Finally we set the output action.
*/
treatmentBuilder.setOutput(egressPoint.connectPoint().port());
if (optimizeTreatments()) {
/*
* We update the previous state. In this way instead of
* transiting from FIP->FEP we do FEP->FEP and so on.
*/
prevState = egressPoint.trafficSelector();
}
}
}
Aggregations