| /* |
| * Copyright 2019-present Open Networking Foundation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.onosproject.p4runtime.ctl.codec; |
| |
| import org.onosproject.net.pi.model.PiPipeconf; |
| import org.onosproject.net.pi.model.PiTableId; |
| import org.onosproject.net.pi.runtime.PiAction; |
| import org.onosproject.net.pi.runtime.PiActionProfileGroupId; |
| import org.onosproject.net.pi.runtime.PiActionProfileMemberId; |
| import org.onosproject.net.pi.runtime.PiCounterCellData; |
| import org.onosproject.net.pi.runtime.PiMatchKey; |
| import org.onosproject.net.pi.runtime.PiTableAction; |
| import org.onosproject.net.pi.runtime.PiTableEntry; |
| import org.onosproject.net.pi.runtime.PiTableEntryHandle; |
| import org.onosproject.p4runtime.ctl.utils.P4InfoBrowser; |
| import p4.config.v1.P4InfoOuterClass; |
| import p4.v1.P4RuntimeOuterClass; |
| |
| import java.util.OptionalInt; |
| |
| import static com.google.common.base.Preconditions.checkNotNull; |
| import static java.lang.String.format; |
| import static org.onosproject.p4runtime.ctl.codec.Codecs.CODECS; |
| |
| /** |
| * Codec for P4Runtime TableEntry. |
| */ |
| public final class TableEntryCodec |
| extends AbstractEntityCodec<PiTableEntry, PiTableEntryHandle, |
| P4RuntimeOuterClass.TableEntry, Object> { |
| |
| @Override |
| protected P4RuntimeOuterClass.TableEntry encode( |
| PiTableEntry piTableEntry, Object ignored, PiPipeconf pipeconf, |
| P4InfoBrowser browser) |
| throws CodecException, P4InfoBrowser.NotFoundException { |
| final P4RuntimeOuterClass.TableEntry.Builder tableEntryMsgBuilder = |
| keyMsgBuilder(piTableEntry.table(), piTableEntry.matchKey(), |
| piTableEntry.priority(), pipeconf, browser); |
| // Controller metadata (cookie) |
| tableEntryMsgBuilder.setControllerMetadata(piTableEntry.cookie()); |
| // Timeout. |
| if (piTableEntry.timeout().isPresent()) { |
| // FIXME: timeout is supported in P4Runtime v1.0 |
| log.warn("Found PI table entry with timeout set, " + |
| "not supported in P4Runtime: {}", piTableEntry); |
| } |
| // Table action. |
| if (piTableEntry.action() != null) { |
| tableEntryMsgBuilder.setAction( |
| encodePiTableAction(piTableEntry.action(), pipeconf)); |
| } |
| // Counter. |
| if (piTableEntry.counter() != null) { |
| tableEntryMsgBuilder.setCounterData(encodeCounter(piTableEntry.counter())); |
| } |
| return tableEntryMsgBuilder.build(); |
| } |
| |
| @Override |
| protected P4RuntimeOuterClass.TableEntry encodeKey( |
| PiTableEntryHandle handle, Object metadata, PiPipeconf pipeconf, |
| P4InfoBrowser browser) throws CodecException, P4InfoBrowser.NotFoundException { |
| return keyMsgBuilder(handle.tableId(), handle.matchKey(), |
| handle.priority(), pipeconf, browser).build(); |
| } |
| |
| @Override |
| protected P4RuntimeOuterClass.TableEntry encodeKey( |
| PiTableEntry piEntity, Object metadata, PiPipeconf pipeconf, |
| P4InfoBrowser browser) throws CodecException, P4InfoBrowser.NotFoundException { |
| return keyMsgBuilder(piEntity.table(), piEntity.matchKey(), |
| piEntity.priority(), pipeconf, browser).build(); |
| } |
| |
| @SuppressWarnings("OptionalUsedAsFieldOrParameterType") |
| private P4RuntimeOuterClass.TableEntry.Builder keyMsgBuilder( |
| PiTableId tableId, PiMatchKey matchKey, OptionalInt priority, |
| PiPipeconf pipeconf, P4InfoBrowser browser) |
| throws P4InfoBrowser.NotFoundException, CodecException { |
| final P4RuntimeOuterClass.TableEntry.Builder tableEntryMsgBuilder = |
| P4RuntimeOuterClass.TableEntry.newBuilder(); |
| final P4InfoOuterClass.Preamble tablePreamble = browser.tables() |
| .getByName(tableId.id()).getPreamble(); |
| // Table id. |
| tableEntryMsgBuilder.setTableId(tablePreamble.getId()); |
| // Field matches. |
| if (matchKey.equals(PiMatchKey.EMPTY)) { |
| tableEntryMsgBuilder.setIsDefaultAction(true); |
| } else { |
| tableEntryMsgBuilder.addAllMatch( |
| CODECS.fieldMatch().encodeAll( |
| matchKey.fieldMatches(), |
| tablePreamble, pipeconf)); |
| } |
| // Priority. |
| priority.ifPresent(tableEntryMsgBuilder::setPriority); |
| return tableEntryMsgBuilder; |
| } |
| |
| @Override |
| protected PiTableEntry decode( |
| P4RuntimeOuterClass.TableEntry message, Object ignored, |
| PiPipeconf pipeconf, P4InfoBrowser browser) |
| throws CodecException, P4InfoBrowser.NotFoundException { |
| PiTableEntry.Builder piTableEntryBuilder = PiTableEntry.builder(); |
| |
| P4InfoOuterClass.Preamble tablePreamble = browser.tables() |
| .getById(message.getTableId()).getPreamble(); |
| |
| // Table id. |
| piTableEntryBuilder.forTable(PiTableId.of(tablePreamble.getName())); |
| |
| // Priority. |
| if (message.getPriority() > 0) { |
| piTableEntryBuilder.withPriority(message.getPriority()); |
| } |
| |
| // Controller metadata (cookie) |
| piTableEntryBuilder.withCookie(message.getControllerMetadata()); |
| |
| // Table action. |
| if (message.hasAction()) { |
| piTableEntryBuilder.withAction(decodeTableActionMsg( |
| message.getAction(), pipeconf)); |
| } |
| |
| // Timeout. |
| // FIXME: how to decode table entry messages with timeout, given that |
| // the timeout value is lost after encoding? |
| |
| // Match key for field matches. |
| piTableEntryBuilder.withMatchKey( |
| PiMatchKey.builder() |
| .addFieldMatches(CODECS.fieldMatch().decodeAll( |
| message.getMatchList(), |
| tablePreamble, pipeconf)) |
| .build()); |
| |
| // Counter. |
| if (message.hasCounterData()) { |
| piTableEntryBuilder.withCounterCellData(decodeCounter(message.getCounterData())); |
| } |
| |
| return piTableEntryBuilder.build(); |
| } |
| |
| private P4RuntimeOuterClass.TableAction encodePiTableAction( |
| PiTableAction piTableAction, PiPipeconf pipeconf) |
| throws CodecException { |
| checkNotNull(piTableAction, "Cannot encode null PiTableAction"); |
| final P4RuntimeOuterClass.TableAction.Builder tableActionMsgBuilder = |
| P4RuntimeOuterClass.TableAction.newBuilder(); |
| switch (piTableAction.type()) { |
| case ACTION: |
| P4RuntimeOuterClass.Action theAction = CODECS.action() |
| .encode((PiAction) piTableAction, null, pipeconf); |
| tableActionMsgBuilder.setAction(theAction); |
| break; |
| case ACTION_PROFILE_GROUP_ID: |
| tableActionMsgBuilder.setActionProfileGroupId( |
| ((PiActionProfileGroupId) piTableAction).id()); |
| break; |
| case ACTION_PROFILE_MEMBER_ID: |
| tableActionMsgBuilder.setActionProfileMemberId( |
| ((PiActionProfileMemberId) piTableAction).id()); |
| break; |
| default: |
| throw new CodecException( |
| format("Building of table action type %s not implemented", |
| piTableAction.type())); |
| } |
| return tableActionMsgBuilder.build(); |
| } |
| |
| private PiTableAction decodeTableActionMsg( |
| P4RuntimeOuterClass.TableAction tableActionMsg, PiPipeconf pipeconf) |
| throws CodecException { |
| P4RuntimeOuterClass.TableAction.TypeCase typeCase = tableActionMsg.getTypeCase(); |
| switch (typeCase) { |
| case ACTION: |
| P4RuntimeOuterClass.Action actionMsg = tableActionMsg.getAction(); |
| return CODECS.action().decode( |
| actionMsg, null, pipeconf); |
| case ACTION_PROFILE_GROUP_ID: |
| return PiActionProfileGroupId.of( |
| tableActionMsg.getActionProfileGroupId()); |
| case ACTION_PROFILE_MEMBER_ID: |
| return PiActionProfileMemberId.of( |
| tableActionMsg.getActionProfileMemberId()); |
| default: |
| throw new CodecException( |
| format("Decoding of table action type %s not implemented", |
| typeCase.name())); |
| } |
| } |
| |
| private P4RuntimeOuterClass.CounterData encodeCounter( |
| PiCounterCellData piCounterCellData) { |
| return P4RuntimeOuterClass.CounterData.newBuilder() |
| .setPacketCount(piCounterCellData.packets()) |
| .setByteCount(piCounterCellData.bytes()).build(); |
| } |
| |
| private PiCounterCellData decodeCounter( |
| P4RuntimeOuterClass.CounterData counterData) { |
| return new PiCounterCellData( |
| counterData.getPacketCount(), counterData.getByteCount()); |
| } |
| } |