blob: 4a4dff73f150ed8fb60c4354e9f45e1f3b1b6ce0 [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;
27import org.onosproject.net.pi.runtime.PiActionGroup;
28import org.onosproject.net.pi.runtime.PiActionGroupId;
29import org.onosproject.net.pi.runtime.PiActionGroupMember;
30import org.onosproject.net.pi.runtime.PiActionGroupMemberId;
31import 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 /**
58 * Returns a PI action group equivalent to the given group, for the given pipeconf and device.
59 *
60 * @param group group
61 * @param pipeconf pipeconf
62 * @param device device
63 * @return PI action group
64 * @throws PiTranslationException if the group cannot be translated
65 */
66 static PiActionGroup translate(Group group, PiPipeconf pipeconf, Device device) throws PiTranslationException {
67
Carmelo Casconea73f1062018-07-16 22:49:46 +020068 if (!SUPPORTED_GROUP_TYPES.contains(group.type())) {
69 throw new PiTranslationException(format(
70 "group type %s not supported", group.type()));
71 }
72
Carmelo Cascone87b9b392017-10-02 18:33:20 +020073 final PiPipelineInterpreter interpreter = getInterpreterOrNull(device, pipeconf);
74
75 final PiActionGroup.Builder piActionGroupBuilder = PiActionGroup.builder()
76 .withId(PiActionGroupId.of(group.id().id()));
77
Carmelo Cascone87b9b392017-10-02 18:33:20 +020078 if (!(group.appCookie() instanceof PiGroupKey)) {
Carmelo Casconea73f1062018-07-16 22:49:46 +020079 throw new PiTranslationException("group app cookie is not PI (class should be PiGroupKey)");
Carmelo Cascone87b9b392017-10-02 18:33:20 +020080 }
81 final PiGroupKey groupKey = (PiGroupKey) group.appCookie();
82
83 piActionGroupBuilder.withActionProfileId(groupKey.actionProfileId());
84
85 // Translate group buckets to PI group members
86 short bucketIdx = 0;
87 for (GroupBucket bucket : group.buckets().buckets()) {
88 /*
89 FIXME: the way member IDs are computed can cause collisions!
90 Problem:
91 In P4Runtime action group members, i.e. action buckets, are associated to a numeric ID chosen
92 at member insertion time. This ID must be unique for the whole action profile (i.e. the group table in
93 OpenFlow). In ONOS, GroupBucket doesn't specify any ID.
94
95 Solutions:
96 - Change GroupBucket API to force application wanting to perform group operations to specify a member id.
97 - Maintain state to dynamically allocate/deallocate member IDs, e.g. in a dedicated service, or in a
98 P4Runtime Group Provider.
99
100 Hack:
101 Statically derive member ID by combining groupId and position of the bucket in the list.
102 */
103 ByteBuffer bb = ByteBuffer.allocate(4)
104 .putShort((short) (group.id().id() & 0xffff))
105 .putShort(bucketIdx);
106 bb.rewind();
107 int memberId = bb.getInt();
108 bucketIdx++;
109
110 final PiTableAction tableAction = translateTreatment(bucket.treatment(), interpreter, groupKey.tableId(),
111 pipeconf.pipelineModel());
wu66460c92018-10-23 11:36:30 +0800112 if (tableAction == null) {
113 throw new PiTranslationException("The PI table action returned by the interpreter is null");
114 }
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200115
116 if (tableAction.type() != ACTION) {
117 throw new PiTranslationException(format(
118 "PI table action of type %s is not supported in groups", tableAction.type()));
119 }
120
121 piActionGroupBuilder.addMember(PiActionGroupMember.builder()
Carmelo Casconee44592f2018-09-12 02:24:47 -0700122 .forActionProfile(groupKey.actionProfileId())
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200123 .withId(PiActionGroupMemberId.of(memberId))
124 .withAction((PiAction) tableAction)
125 .withWeight(bucket.weight())
126 .build());
127 }
128
129 return piActionGroupBuilder.build();
130 }
131}