blob: 954ecf86a28fd7f3cfb504560363ab156393483e [file] [log] [blame]
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -04001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -04003 *
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.drivers.bmv2;
18
19import org.onosproject.net.Device;
20import org.onosproject.net.DeviceId;
21import org.onosproject.net.driver.AbstractHandlerBehaviour;
22import org.onosproject.net.group.GroupBucket;
23import org.onosproject.net.group.GroupDescription;
24import org.onosproject.net.group.GroupOperation;
25import org.onosproject.net.group.GroupOperations;
26import org.onosproject.net.group.GroupProgrammable;
27import org.onosproject.net.pi.model.PiPipelineInterpreter;
28import org.onosproject.net.pi.runtime.PiAction;
29import org.onosproject.net.pi.runtime.PiActionGroup;
30import org.onosproject.net.pi.runtime.PiActionGroupId;
31import org.onosproject.net.pi.runtime.PiActionGroupMember;
32import org.onosproject.net.pi.runtime.PiActionGroupMemberId;
33import org.onosproject.net.pi.runtime.PiTableId;
34
35import java.nio.ByteBuffer;
36
37public class Bmv2GroupProgrammable extends AbstractHandlerBehaviour implements GroupProgrammable {
38
39 /*
40 Work in progress.
41 */
42
43 private Device device;
44
45 /*
46 About action groups in P4runtime:
47 The type field is a place holder in p4runtime.proto right now, and we haven't defined it yet. You can assume all
48 the groups are "select" as per the OF spec. As a remainder, in the P4 terminology a member corresponds to an OF
49 bucket. Each member can also be used directly in the match table (kind of like an OF indirect group).
50 */
51
52 @Override
53 public void performGroupOperation(DeviceId deviceId, GroupOperations groupOps) {
54
55 for (GroupOperation groupOp : groupOps.operations()) {
56 switch (groupOp.opType()) {
57 case ADD:
58 addGroup(deviceId, groupOp);
59 break;
60 default:
61 throw new UnsupportedOperationException();
62 }
63 }
64 }
65
66 private void addGroup(DeviceId deviceId, GroupOperation groupOp) {
67
68 // Most of this logic can go in a core service, e.g. PiGroupTranslationService
69
70 // From a P4Runtime perspective, we need first to insert members, then the group.
71
72 PiActionGroupId piActionGroupId = PiActionGroupId.of(groupOp.groupId().id());
73
74 PiActionGroup.Builder piActionGroupBuilder = PiActionGroup.builder()
75 .withId(piActionGroupId)
76 .withType(PiActionGroup.Type.SELECT);
77
78 if (groupOp.groupType() != GroupDescription.Type.SELECT) {
79 // log error
80 }
81
82 int bucketIdx = 0;
83 for (GroupBucket bucket : groupOp.buckets().buckets()) {
84 /*
85 Problem:
86 In P4Runtime action group members, i.e. action buckets, are associated to a numeric ID chosen
87 at member insertion time. This ID must be unique for the whole action profile (i.e. the group table in
88 OpenFlow). In ONOS, GroupBucket doesn't specify any ID.
89
90 Solutions:
91 - Change GroupBucket API to force application wanting to perform group operations to specify a member id.
92 - Maintain state to dynamically allocate/deallocate member IDs, e.g. in a dedicated service, or in a
93 P4Runtime Group Provider.
94
95 Hack:
96 Statically derive member ID by combining groupId and position of the bucket in the list.
97 */
98 int memberId = ByteBuffer.allocate(4)
99 .putShort((short) (piActionGroupId.id() % 2 ^ 16))
100 .putShort((short) (bucketIdx % 2 ^ 16))
101 .getInt();
102
103 // Need an interpreter to map the bucket treatment to a PI action
104
105 if (!device.is(PiPipelineInterpreter.class)) {
106 // log error
107 }
108
109 PiPipelineInterpreter interpreter = device.as(PiPipelineInterpreter.class);
110
111 /*
112 Problem:
113 In P4Runtime, action profiles (i.e. group tables) are specific to one or more tables.
114 Mapping of treatments depends on the target table. How do we derive the target table from here?
115
116 Solution:
117 - Change GroupDescription to allow applications to specify a table where this group will be called from.
118
119 Hack:
120 Assume we support pipelines with only one action profile associated to only one table, i.e. derive the
121 table ID by looking at the P4Info.
122 */
123
124 PiTableId piTableId = PiTableId.of("derive from P4Info");
125
126
127 PiAction action = null;
128 try {
129 action = interpreter.mapTreatment(bucket.treatment(), piTableId);
130 } catch (PiPipelineInterpreter.PiInterpreterException e) {
131 // log error
132 }
133
134 PiActionGroupMember member = PiActionGroupMember.builder()
135 .withId(PiActionGroupMemberId.of(memberId))
136 .withAction(action)
137 .withWeight(bucket.weight())
138 .build();
139
140 piActionGroupBuilder.addMember(member);
141
142 // Use P4RuntimeClient to install member;
143 // TODO: implement P4RuntimeClient method.
144 }
145
146 PiActionGroup piActionGroup = piActionGroupBuilder.build();
147
148 // Use P4RuntimeClient to insert group.
149 // TODO: implement P4RuntimeClient method.
150 }
151}