Search in sources :

Example 1 with TableId

use of org.onosproject.net.flow.TableId 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();
}
Also used : IndexTableId(org.onosproject.net.flow.IndexTableId) TableId(org.onosproject.net.flow.TableId) IndexTableId(org.onosproject.net.flow.IndexTableId) ArrayList(java.util.ArrayList) L2ModificationInstruction(org.onosproject.net.flow.instructions.L2ModificationInstruction) OutputInstruction(org.onosproject.net.flow.instructions.Instructions.OutputInstruction) ModVlanIdInstruction(org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction) Instruction(org.onosproject.net.flow.instructions.Instruction) ConnectPoint(org.onosproject.net.ConnectPoint) DataPlaneEntity(org.onosproject.net.DataPlaneEntity) ModVlanIdInstruction(org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction) TrafficSelector(org.onosproject.net.flow.TrafficSelector) DefaultTrafficSelector(org.onosproject.net.flow.DefaultTrafficSelector) PipelineTraceableOutput(org.onosproject.net.PipelineTraceableOutput) PipelineTraceableHitChain(org.onosproject.net.PipelineTraceableHitChain) PortNumber(org.onosproject.net.PortNumber) FlowEntry(org.onosproject.net.flow.FlowEntry) PipelineTraceablePacket(org.onosproject.net.PipelineTraceablePacket) VlanIdCriterion(org.onosproject.net.flow.criteria.VlanIdCriterion)

Aggregations

ArrayList (java.util.ArrayList)1 ConnectPoint (org.onosproject.net.ConnectPoint)1 DataPlaneEntity (org.onosproject.net.DataPlaneEntity)1 PipelineTraceableHitChain (org.onosproject.net.PipelineTraceableHitChain)1 PipelineTraceableOutput (org.onosproject.net.PipelineTraceableOutput)1 PipelineTraceablePacket (org.onosproject.net.PipelineTraceablePacket)1 PortNumber (org.onosproject.net.PortNumber)1 DefaultTrafficSelector (org.onosproject.net.flow.DefaultTrafficSelector)1 FlowEntry (org.onosproject.net.flow.FlowEntry)1 IndexTableId (org.onosproject.net.flow.IndexTableId)1 TableId (org.onosproject.net.flow.TableId)1 TrafficSelector (org.onosproject.net.flow.TrafficSelector)1 VlanIdCriterion (org.onosproject.net.flow.criteria.VlanIdCriterion)1 Instruction (org.onosproject.net.flow.instructions.Instruction)1 OutputInstruction (org.onosproject.net.flow.instructions.Instructions.OutputInstruction)1 L2ModificationInstruction (org.onosproject.net.flow.instructions.L2ModificationInstruction)1 ModVlanIdInstruction (org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction)1