blob: 513b4fa3ba3aef52fe5589a580f1aa6eceaee290 [file] [log] [blame]
/*
* 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());
}
}