blob: de32b60d16e951740821955a495215a7ea3b6653 [file] [log] [blame]
Carmelo Cascone87b9b392017-10-02 18:33:20 +02001/*
2 * Copyright 2017-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.net.pi.impl;
18
Carmelo Casconea73f1062018-07-16 22:49:46 +020019import com.google.common.collect.Sets;
Carmelo Cascone87b9b392017-10-02 18:33:20 +020020import org.onosproject.net.Device;
21import org.onosproject.net.group.Group;
22import org.onosproject.net.group.GroupBucket;
Carmelo Casconea73f1062018-07-16 22:49:46 +020023import org.onosproject.net.group.GroupDescription;
Carmelo Cascone87b9b392017-10-02 18:33:20 +020024import org.onosproject.net.pi.model.PiPipeconf;
25import org.onosproject.net.pi.model.PiPipelineInterpreter;
26import org.onosproject.net.pi.runtime.PiAction;
Carmelo Casconecb4327a2018-09-11 15:17:23 -070027import org.onosproject.net.pi.runtime.PiActionProfileGroup;
28import org.onosproject.net.pi.runtime.PiActionProfileGroupId;
29import org.onosproject.net.pi.runtime.PiActionProfileMember;
30import org.onosproject.net.pi.runtime.PiActionProfileMemberId;
Carmelo Cascone87b9b392017-10-02 18:33:20 +020031import org.onosproject.net.pi.runtime.PiGroupKey;
32import org.onosproject.net.pi.runtime.PiTableAction;
Carmelo Cascone326ad2d2017-11-28 18:09:13 -080033import org.onosproject.net.pi.service.PiTranslationException;
Carmelo Cascone87b9b392017-10-02 18:33:20 +020034
35import java.nio.ByteBuffer;
Carmelo Casconea73f1062018-07-16 22:49:46 +020036import java.util.Set;
Carmelo Cascone87b9b392017-10-02 18:33:20 +020037
38import static java.lang.String.format;
Carmelo Cascone326ad2d2017-11-28 18:09:13 -080039import static org.onosproject.net.pi.impl.PiFlowRuleTranslatorImpl.translateTreatment;
Carmelo Cascone87b9b392017-10-02 18:33:20 +020040import static org.onosproject.net.pi.impl.PiUtils.getInterpreterOrNull;
41import static org.onosproject.net.pi.runtime.PiTableAction.Type.ACTION;
42
43/**
44 * Implementation of group translation logic.
45 */
Carmelo Cascone326ad2d2017-11-28 18:09:13 -080046final class PiGroupTranslatorImpl {
Carmelo Cascone87b9b392017-10-02 18:33:20 +020047
Carmelo Casconea73f1062018-07-16 22:49:46 +020048 private static final Set<GroupDescription.Type> SUPPORTED_GROUP_TYPES =
49 Sets.immutableEnumSet(
50 GroupDescription.Type.SELECT,
51 GroupDescription.Type.INDIRECT);
52
Carmelo Cascone326ad2d2017-11-28 18:09:13 -080053 private PiGroupTranslatorImpl() {
Carmelo Cascone87b9b392017-10-02 18:33:20 +020054 // Hides constructor.
55 }
56
57 /**
Carmelo Casconecb4327a2018-09-11 15:17:23 -070058 * Returns a PI action profile group equivalent to the given group, for the given pipeconf and device.
Carmelo Cascone87b9b392017-10-02 18:33:20 +020059 *
60 * @param group group
61 * @param pipeconf pipeconf
62 * @param device device
Carmelo Casconecb4327a2018-09-11 15:17:23 -070063 * @return PI action profile group
Carmelo Cascone87b9b392017-10-02 18:33:20 +020064 * @throws PiTranslationException if the group cannot be translated
65 */
Carmelo Casconecb4327a2018-09-11 15:17:23 -070066 static PiActionProfileGroup translate(Group group, PiPipeconf pipeconf, Device device)
67 throws PiTranslationException {
Carmelo Cascone87b9b392017-10-02 18:33:20 +020068
Carmelo Casconea73f1062018-07-16 22:49:46 +020069 if (!SUPPORTED_GROUP_TYPES.contains(group.type())) {
70 throw new PiTranslationException(format(
71 "group type %s not supported", group.type()));
72 }
73
Carmelo Cascone87b9b392017-10-02 18:33:20 +020074 final PiPipelineInterpreter interpreter = getInterpreterOrNull(device, pipeconf);
75
Carmelo Casconecb4327a2018-09-11 15:17:23 -070076 final PiActionProfileGroup.Builder piActionGroupBuilder = PiActionProfileGroup.builder()
77 .withId(PiActionProfileGroupId.of(group.id().id()));
Carmelo Cascone87b9b392017-10-02 18:33:20 +020078
Carmelo Cascone87b9b392017-10-02 18:33:20 +020079 if (!(group.appCookie() instanceof PiGroupKey)) {
Carmelo Casconea73f1062018-07-16 22:49:46 +020080 throw new PiTranslationException("group app cookie is not PI (class should be PiGroupKey)");
Carmelo Cascone87b9b392017-10-02 18:33:20 +020081 }
82 final PiGroupKey groupKey = (PiGroupKey) group.appCookie();
83
84 piActionGroupBuilder.withActionProfileId(groupKey.actionProfileId());
85
86 // Translate group buckets to PI group members
87 short bucketIdx = 0;
88 for (GroupBucket bucket : group.buckets().buckets()) {
89 /*
90 FIXME: the way member IDs are computed can cause collisions!
91 Problem:
Carmelo Casconecb4327a2018-09-11 15:17:23 -070092 In P4Runtime action profile members, i.e. action buckets, are associated to a numeric ID chosen
Carmelo Cascone87b9b392017-10-02 18:33:20 +020093 at member insertion time. This ID must be unique for the whole action profile (i.e. the group table in
94 OpenFlow). In ONOS, GroupBucket doesn't specify any ID.
95
96 Solutions:
97 - Change GroupBucket API to force application wanting to perform group operations to specify a member id.
98 - Maintain state to dynamically allocate/deallocate member IDs, e.g. in a dedicated service, or in a
99 P4Runtime Group Provider.
100
101 Hack:
102 Statically derive member ID by combining groupId and position of the bucket in the list.
103 */
104 ByteBuffer bb = ByteBuffer.allocate(4)
105 .putShort((short) (group.id().id() & 0xffff))
106 .putShort(bucketIdx);
107 bb.rewind();
108 int memberId = bb.getInt();
109 bucketIdx++;
110
111 final PiTableAction tableAction = translateTreatment(bucket.treatment(), interpreter, groupKey.tableId(),
112 pipeconf.pipelineModel());
wu66460c92018-10-23 11:36:30 +0800113 if (tableAction == null) {
114 throw new PiTranslationException("The PI table action returned by the interpreter is null");
115 }
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200116
117 if (tableAction.type() != ACTION) {
118 throw new PiTranslationException(format(
119 "PI table action of type %s is not supported in groups", tableAction.type()));
120 }
121
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700122 piActionGroupBuilder.addMember(PiActionProfileMember.builder()
Carmelo Casconee44592f2018-09-12 02:24:47 -0700123 .forActionProfile(groupKey.actionProfileId())
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700124 .withId(PiActionProfileMemberId.of(memberId))
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200125 .withAction((PiAction) tableAction)
126 .withWeight(bucket.weight())
127 .build());
128 }
129
130 return piActionGroupBuilder.build();
131 }
132}