Search in sources :

Example 1 with PiTableEntry

use of org.onosproject.net.pi.runtime.PiTableEntry in project onos by opennetworkinglab.

the class PiFlowRuleTranslatorImpl method translate.

/**
 * Returns a PI table entry equivalent to the given flow rule, for the given
 * pipeconf and device.
 *
 * @param rule     flow rule
 * @param pipeconf pipeconf
 * @param device   device
 * @return PI table entry
 * @throws PiTranslationException if the flow rule cannot be translated
 */
static PiTableEntry translate(FlowRule rule, PiPipeconf pipeconf, Device device) throws PiTranslationException {
    PiPipelineModel pipelineModel = pipeconf.pipelineModel();
    // Retrieve interpreter, if any.
    final PiPipelineInterpreter interpreter = getInterpreterOrNull(device, pipeconf);
    // Get table model.
    final PiTableId piTableId = translateTableId(rule.table(), interpreter);
    final PiTableModel tableModel = getTableModel(piTableId, pipelineModel);
    // Translate selector.
    final PiMatchKey piMatchKey;
    final boolean needPriority;
    if (rule.selector().criteria().isEmpty()) {
        piMatchKey = PiMatchKey.EMPTY;
        needPriority = false;
    } else {
        final Collection<PiFieldMatch> fieldMatches = translateFieldMatches(interpreter, rule.selector(), tableModel);
        piMatchKey = PiMatchKey.builder().addFieldMatches(fieldMatches).build();
        // FIXME: P4Runtime limit
        // Need to ignore priority if no TCAM lookup match field
        needPriority = tableModel.matchFields().stream().anyMatch(match -> match.matchType() == PiMatchType.TERNARY || match.matchType() == PiMatchType.RANGE || match.matchType() == PiMatchType.OPTIONAL);
    }
    // Translate treatment.
    final PiTableAction piTableAction = translateTreatment(rule.treatment(), interpreter, piTableId, pipelineModel);
    // Build PI entry.
    final PiTableEntry.Builder tableEntryBuilder = PiTableEntry.builder();
    tableEntryBuilder.forTable(piTableId).withMatchKey(piMatchKey);
    if (piTableAction != null) {
        tableEntryBuilder.withAction(piTableAction);
    }
    if (needPriority) {
        // FIXME: move priority check to P4Runtime driver.
        final int newPriority;
        if (rule.priority() > MAX_PI_PRIORITY) {
            log.warn("Flow rule priority too big, setting translated priority to max value {}: {}", MAX_PI_PRIORITY, rule);
            newPriority = MAX_PI_PRIORITY;
        } else {
            newPriority = MIN_PI_PRIORITY + rule.priority();
        }
        tableEntryBuilder.withPriority(newPriority);
    }
    if (!rule.isPermanent()) {
        if (tableModel.supportsAging()) {
            tableEntryBuilder.withTimeout(rule.timeout());
        } else {
            log.debug("Flow rule is temporary, but table '{}' doesn't support " + "aging, translating to permanent.", tableModel.id());
        }
    }
    return tableEntryBuilder.build();
}
Also used : PiTableId(org.onosproject.net.pi.model.PiTableId) PiOptionalFieldMatch(org.onosproject.net.pi.runtime.PiOptionalFieldMatch) PiUtils.getInterpreterOrNull(org.onosproject.net.pi.impl.PiUtils.getInterpreterOrNull) PiPipeconf(org.onosproject.net.pi.model.PiPipeconf) ImmutableByteSequence(org.onlab.util.ImmutableByteSequence) LoggerFactory(org.slf4j.LoggerFactory) PiActionParam(org.onosproject.net.pi.runtime.PiActionParam) PiActionParamModel(org.onosproject.net.pi.model.PiActionParamModel) PiPipelineModel(org.onosproject.net.pi.model.PiPipelineModel) PiMatchKey(org.onosproject.net.pi.runtime.PiMatchKey) PiUtils.translateTableId(org.onosproject.net.pi.impl.PiUtils.translateTableId) ImmutableByteSequence.prefixOnes(org.onlab.util.ImmutableByteSequence.prefixOnes) TrafficSelector(org.onosproject.net.flow.TrafficSelector) PiInstruction(org.onosproject.net.flow.instructions.PiInstruction) PiTableModel(org.onosproject.net.pi.model.PiTableModel) PiCriterion(org.onosproject.net.flow.criteria.PiCriterion) Map(java.util.Map) PiTranslationException(org.onosproject.net.pi.service.PiTranslationException) PiExactFieldMatch(org.onosproject.net.pi.runtime.PiExactFieldMatch) PiFieldMatch(org.onosproject.net.pi.runtime.PiFieldMatch) Criterion(org.onosproject.net.flow.criteria.Criterion) TrafficTreatment(org.onosproject.net.flow.TrafficTreatment) PiTableAction(org.onosproject.net.pi.runtime.PiTableAction) PiPipelineInterpreter(org.onosproject.net.pi.model.PiPipelineInterpreter) Logger(org.slf4j.Logger) Device(org.onosproject.net.Device) PiActionModel(org.onosproject.net.pi.model.PiActionModel) Instruction(org.onosproject.net.flow.instructions.Instruction) PiMatchFieldModel(org.onosproject.net.pi.model.PiMatchFieldModel) Collection(java.util.Collection) PiRangeFieldMatch(org.onosproject.net.pi.runtime.PiRangeFieldMatch) Set(java.util.Set) PiMatchFieldId(org.onosproject.net.pi.model.PiMatchFieldId) Maps(com.google.common.collect.Maps) Sets(com.google.common.collect.Sets) PiMatchType(org.onosproject.net.pi.model.PiMatchType) String.format(java.lang.String.format) PiTernaryFieldMatch(org.onosproject.net.pi.runtime.PiTernaryFieldMatch) ByteSequenceTrimException(org.onlab.util.ImmutableByteSequence.ByteSequenceTrimException) PROTOCOL_INDEPENDENT(org.onosproject.net.flow.criteria.Criterion.Type.PROTOCOL_INDEPENDENT) PiAction(org.onosproject.net.pi.runtime.PiAction) PiTableEntry(org.onosproject.net.pi.runtime.PiTableEntry) CriterionTranslatorHelper.translateCriterion(org.onosproject.net.pi.impl.CriterionTranslatorHelper.translateCriterion) FlowRule(org.onosproject.net.flow.FlowRule) StringJoiner(java.util.StringJoiner) PiTableType(org.onosproject.net.pi.model.PiTableType) PiLpmFieldMatch(org.onosproject.net.pi.runtime.PiLpmFieldMatch) PiActionSet(org.onosproject.net.pi.runtime.PiActionSet) PiTableModel(org.onosproject.net.pi.model.PiTableModel) PiMatchKey(org.onosproject.net.pi.runtime.PiMatchKey) PiTableAction(org.onosproject.net.pi.runtime.PiTableAction) PiTableId(org.onosproject.net.pi.model.PiTableId) PiTableEntry(org.onosproject.net.pi.runtime.PiTableEntry) PiPipelineInterpreter(org.onosproject.net.pi.model.PiPipelineInterpreter) PiFieldMatch(org.onosproject.net.pi.runtime.PiFieldMatch) PiPipelineModel(org.onosproject.net.pi.model.PiPipelineModel)

Example 2 with PiTableEntry

use of org.onosproject.net.pi.runtime.PiTableEntry in project onos by opennetworkinglab.

the class PiFlowRuleTranslatorImplTest method testTranslateFlowRules.

@Test
public void testTranslateFlowRules() throws Exception {
    ApplicationId appId = new DefaultApplicationId(1, "test");
    MacAddress ethDstMac = MacAddress.valueOf(random.nextLong());
    MacAddress ethSrcMac = MacAddress.valueOf(random.nextLong());
    short ethType = (short) (0x0000FFFF & random.nextInt());
    short outPort = (short) random.nextInt(65);
    short inPort = (short) random.nextInt(65);
    int timeout = random.nextInt(100);
    int priority = random.nextInt(100);
    TrafficSelector matchInPort1 = DefaultTrafficSelector.builder().matchInPort(PortNumber.portNumber(inPort)).matchEthDst(ethDstMac).matchEthSrc(ethSrcMac).matchEthType(ethType).build();
    TrafficSelector emptySelector = DefaultTrafficSelector.builder().build();
    TrafficTreatment outPort2 = DefaultTrafficTreatment.builder().setOutput(PortNumber.portNumber(outPort)).build();
    FlowRule rule1 = DefaultFlowRule.builder().forDevice(DEVICE_ID).forTable(INGRESS_TABLE0_CONTROL_TABLE0).fromApp(appId).withSelector(matchInPort1).withTreatment(outPort2).makeTemporary(timeout).withPriority(priority).build();
    FlowRule rule2 = DefaultFlowRule.builder().forDevice(DEVICE_ID).forTable(INGRESS_TABLE0_CONTROL_TABLE0).fromApp(appId).withSelector(matchInPort1).withTreatment(outPort2).makeTemporary(timeout).withPriority(priority).build();
    FlowRule defActionRule = DefaultFlowRule.builder().forDevice(DEVICE_ID).forTable(INGRESS_TABLE0_CONTROL_TABLE0).fromApp(appId).withSelector(emptySelector).withTreatment(outPort2).makeTemporary(timeout).withPriority(priority).build();
    PiTableEntry entry1 = PiFlowRuleTranslatorImpl.translate(rule1, pipeconf, null);
    PiTableEntry entry2 = PiFlowRuleTranslatorImpl.translate(rule2, pipeconf, null);
    PiTableEntry defActionEntry = PiFlowRuleTranslatorImpl.translate(defActionRule, pipeconf, null);
    // check equality, i.e. same rules must produce same entries
    new EqualsTester().addEqualityGroup(rule1, rule2).addEqualityGroup(entry1, entry2).testEquals();
    // parse values stored in entry1
    PiTernaryFieldMatch inPortParam = (PiTernaryFieldMatch) entry1.matchKey().fieldMatch(HDR_STANDARD_METADATA_INGRESS_PORT).get();
    PiTernaryFieldMatch ethDstParam = (PiTernaryFieldMatch) entry1.matchKey().fieldMatch(HDR_HDR_ETHERNET_DST_ADDR).get();
    PiTernaryFieldMatch ethSrcParam = (PiTernaryFieldMatch) entry1.matchKey().fieldMatch(HDR_HDR_ETHERNET_SRC_ADDR).get();
    PiTernaryFieldMatch ethTypeParam = (PiTernaryFieldMatch) entry1.matchKey().fieldMatch(HDR_HDR_ETHERNET_ETHER_TYPE).get();
    Optional<Double> expectedTimeout = pipeconf.pipelineModel().table(INGRESS_TABLE0_CONTROL_TABLE0).get().supportsAging() ? Optional.of((double) rule1.timeout()) : Optional.empty();
    // check that values stored in entry are the same used for the flow rule
    assertThat("Incorrect inPort match param value", inPortParam.value().asReadOnlyBuffer().getShort(), is(equalTo(inPort)));
    assertThat("Incorrect inPort match param mask", inPortParam.mask().asReadOnlyBuffer().getShort(), is(equalTo(IN_PORT_MASK)));
    assertThat("Incorrect ethDestMac match param value", ethDstParam.value().asArray(), is(equalTo(ethDstMac.toBytes())));
    assertThat("Incorrect ethDestMac match param mask", ethDstParam.mask().asArray(), is(equalTo(MacAddress.BROADCAST.toBytes())));
    assertThat("Incorrect ethSrcMac match param value", ethSrcParam.value().asArray(), is(equalTo(ethSrcMac.toBytes())));
    assertThat("Incorrect ethSrcMac match param mask", ethSrcParam.mask().asArray(), is(equalTo(MacAddress.BROADCAST.toBytes())));
    assertThat("Incorrect ethType match param value", ethTypeParam.value().asReadOnlyBuffer().getShort(), is(equalTo(ethType)));
    assertThat("Incorrect ethType match param mask", ethTypeParam.mask().asReadOnlyBuffer().getShort(), is(equalTo(ETH_TYPE_MASK)));
    // FIXME: re-enable when P4Runtime priority handling will be moved out of transltion service
    // see PiFlowRuleTranslatorImpl
    // assertThat("Incorrect priority value",
    // entry1.priority().get(), is(equalTo(MAX_PI_PRIORITY - rule1.priority())));
    assertThat("Incorrect timeout value", entry1.timeout(), is(equalTo(expectedTimeout)));
    assertThat("Match key should be empty", defActionEntry.matchKey(), is(equalTo(PiMatchKey.EMPTY)));
    assertThat("Priority should not be set", !defActionEntry.priority().isPresent());
}
Also used : EqualsTester(com.google.common.testing.EqualsTester) PiTernaryFieldMatch(org.onosproject.net.pi.runtime.PiTernaryFieldMatch) MacAddress(org.onlab.packet.MacAddress) DefaultTrafficTreatment(org.onosproject.net.flow.DefaultTrafficTreatment) TrafficTreatment(org.onosproject.net.flow.TrafficTreatment) DefaultApplicationId(org.onosproject.core.DefaultApplicationId) PiTableEntry(org.onosproject.net.pi.runtime.PiTableEntry) TrafficSelector(org.onosproject.net.flow.TrafficSelector) DefaultTrafficSelector(org.onosproject.net.flow.DefaultTrafficSelector) DefaultFlowRule(org.onosproject.net.flow.DefaultFlowRule) FlowRule(org.onosproject.net.flow.FlowRule) DefaultApplicationId(org.onosproject.core.DefaultApplicationId) ApplicationId(org.onosproject.core.ApplicationId) Test(org.junit.Test)

Example 3 with PiTableEntry

use of org.onosproject.net.pi.runtime.PiTableEntry in project onos by opennetworkinglab.

the class P4RuntimeFlowRuleProgrammable method getFlowEntries.

@Override
public Collection<FlowEntry> getFlowEntries() {
    if (!setupBehaviour("getFlowEntries()")) {
        return Collections.emptyList();
    }
    if (driverBoolProperty(READ_FROM_MIRROR, DEFAULT_READ_FROM_MIRROR)) {
        return getFlowEntriesFromMirror();
    }
    final ImmutableList.Builder<FlowEntry> result = ImmutableList.builder();
    final List<PiTableEntry> inconsistentEntries = Lists.newArrayList();
    // Read table entries from device.
    final Collection<PiTableEntry> deviceEntries = getAllTableEntriesFromDevice();
    if (deviceEntries == null) {
        // Potential error at the client level.
        return Collections.emptyList();
    }
    // Synchronize mirror with the device state.
    tableMirror.sync(deviceId, deviceEntries);
    if (deviceEntries.isEmpty()) {
        // Nothing to do.
        return Collections.emptyList();
    }
    final Map<PiTableEntryHandle, PiCounterCellData> counterCellMap = readEntryCounters(deviceEntries);
    // Forge flow entries with counter values.
    for (PiTableEntry entry : deviceEntries) {
        final PiTableEntryHandle handle = entry.handle(deviceId);
        final FlowEntry flowEntry = forgeFlowEntry(entry, handle, counterCellMap.get(handle));
        if (flowEntry == null) {
            // program via default_action, which cannot be removed.)
            if (!isOriginalDefaultEntry(entry)) {
                inconsistentEntries.add(entry);
            }
        } else {
            result.add(flowEntry);
        }
    }
    // Default entries need to be treated in a different way according to the spec:
    // the client can modify (reset or update) them but cannot remove the entries
    List<PiTableEntry> inconsistentDefaultEntries = Lists.newArrayList();
    List<PiTableEntry> tempDefaultEntries = inconsistentEntries.stream().filter(PiTableEntry::isDefaultAction).collect(Collectors.toList());
    inconsistentEntries.removeAll(tempDefaultEntries);
    // Once we have removed the default entry from inconsistentEntries we need to
    // craft for each default entry a copy without the action field. According to
    // the spec leaving the action field unset will reset the original default entry.
    tempDefaultEntries.forEach(piTableEntry -> {
        PiTableEntry resetEntry = PiTableEntry.builder().forTable(piTableEntry.table()).build();
        inconsistentDefaultEntries.add(resetEntry);
    });
    // Clean up of inconsistent entries.
    if (!inconsistentEntries.isEmpty() || !inconsistentDefaultEntries.isEmpty()) {
        WriteRequest writeRequest = client.write(p4DeviceId, pipeconf);
        // Trigger remove of inconsistent entries.
        if (!inconsistentEntries.isEmpty()) {
            log.warn("Found {} inconsistent table entries on {}, removing them...", inconsistentEntries.size(), deviceId);
            writeRequest = writeRequest.entities(inconsistentEntries, DELETE);
        }
        // Trigger reset of inconsistent default entries.
        if (!inconsistentDefaultEntries.isEmpty()) {
            log.warn("Found {} inconsistent default table entries on {}, resetting them...", inconsistentDefaultEntries.size(), deviceId);
            writeRequest = writeRequest.entities(inconsistentDefaultEntries, MODIFY);
        }
        // Submit delete request for non-default entries and modify request
        // for default entries. Updates mirror when done.
        writeRequest.submit().whenComplete((response, ex) -> {
            if (ex != null) {
                log.error("Exception removing inconsistent table entries", ex);
            } else {
                log.debug("Successfully removed {} out of {} inconsistent entries", response.success().size(), response.all().size());
            }
            // We can use the entity as the handle does not contain the action field
            // so the key will be removed even if the table entry is different
            response.success().forEach(entity -> tableMirror.remove((PiTableEntryHandle) entity.handle()));
        });
    }
    return result.build();
}
Also used : PiCounterCellData(org.onosproject.net.pi.runtime.PiCounterCellData) ImmutableList(com.google.common.collect.ImmutableList) WriteRequest(org.onosproject.p4runtime.api.P4RuntimeWriteClient.WriteRequest) PiTableEntry(org.onosproject.net.pi.runtime.PiTableEntry) FlowEntry(org.onosproject.net.flow.FlowEntry) DefaultFlowEntry(org.onosproject.net.flow.DefaultFlowEntry) PiTableEntryHandle(org.onosproject.net.pi.runtime.PiTableEntryHandle)

Example 4 with PiTableEntry

use of org.onosproject.net.pi.runtime.PiTableEntry in project onos by opennetworkinglab.

the class P4RuntimeFlowRuleProgrammable method getOriginalDefaultEntry.

private PiTableEntry getOriginalDefaultEntry(PiTableId tableId) {
    final PiTableEntryHandle handle = PiTableEntry.builder().forTable(tableId).withMatchKey(PiMatchKey.EMPTY).build().handle(deviceId);
    final TimedEntry<PiTableEntry> originalDefaultEntry = defaultEntryMirror.get(handle);
    if (originalDefaultEntry != null) {
        return originalDefaultEntry.entry();
    }
    return null;
}
Also used : PiTableEntry(org.onosproject.net.pi.runtime.PiTableEntry) PiTableEntryHandle(org.onosproject.net.pi.runtime.PiTableEntryHandle)

Example 5 with PiTableEntry

use of org.onosproject.net.pi.runtime.PiTableEntry in project onos by opennetworkinglab.

the class TableEntryEncoderTest method testEncodeWithNoAction.

@Test
public void testEncodeWithNoAction() throws Exception {
    TableEntry tableEntryMsg = Codecs.CODECS.tableEntry().encode(piTableEntryWithoutAction, null, defaultPipeconf);
    PiTableEntry decodedPiTableEntry = Codecs.CODECS.tableEntry().decode(tableEntryMsg, null, defaultPipeconf);
    // Test equality for decoded entry.
    new EqualsTester().addEqualityGroup(piTableEntryWithoutAction, decodedPiTableEntry).testEquals();
    // Table ID.
    int p4InfoTableId = browser.tables().getByName(tableId.id()).getPreamble().getId();
    int encodedTableId = tableEntryMsg.getTableId();
    assertThat(encodedTableId, is(p4InfoTableId));
    // Ternary match.
    byte[] encodedTernaryMatchValue = tableEntryMsg.getMatch(0).getTernary().getValue().toByteArray();
    assertThat(encodedTernaryMatchValue, is(ethAddr.asArray()));
    // no action
    assertThat(tableEntryMsg.hasAction(), is(false));
    // Counter
    CounterData counterData = tableEntryMsg.getCounterData();
    PiCounterCellData encodedCounterData = new PiCounterCellData(counterData.getPacketCount(), counterData.getByteCount());
    assertThat(encodedCounterData, is(counterCellData));
// TODO: improve, assert other field match types (ternary, LPM)
}
Also used : TableEntry(p4.v1.P4RuntimeOuterClass.TableEntry) PiTableEntry(org.onosproject.net.pi.runtime.PiTableEntry) PiCounterCellData(org.onosproject.net.pi.runtime.PiCounterCellData) EqualsTester(com.google.common.testing.EqualsTester) PiTableEntry(org.onosproject.net.pi.runtime.PiTableEntry) CounterData(p4.v1.P4RuntimeOuterClass.CounterData) Test(org.junit.Test)

Aggregations

PiTableEntry (org.onosproject.net.pi.runtime.PiTableEntry)21 Test (org.junit.Test)13 EqualsTester (com.google.common.testing.EqualsTester)6 TableEntry (p4.v1.P4RuntimeOuterClass.TableEntry)5 PiAction (org.onosproject.net.pi.runtime.PiAction)4 PiTernaryFieldMatch (org.onosproject.net.pi.runtime.PiTernaryFieldMatch)4 FlowRule (org.onosproject.net.flow.FlowRule)3 PiCounterCellData (org.onosproject.net.pi.runtime.PiCounterCellData)3 PiExactFieldMatch (org.onosproject.net.pi.runtime.PiExactFieldMatch)3 PiTableEntryHandle (org.onosproject.net.pi.runtime.PiTableEntryHandle)3 Up4Translator (org.omecproject.up4.Up4Translator)2 TrafficSelector (org.onosproject.net.flow.TrafficSelector)2 TrafficTreatment (org.onosproject.net.flow.TrafficTreatment)2 PiOptionalFieldMatch (org.onosproject.net.pi.runtime.PiOptionalFieldMatch)2 ImmutableList (com.google.common.collect.ImmutableList)1 Maps (com.google.common.collect.Maps)1 Sets (com.google.common.collect.Sets)1 String.format (java.lang.String.format)1 Collection (java.util.Collection)1 Map (java.util.Map)1