blob: b501f33ef3dfffd8605132866e6193ade5d3cf03 [file] [log] [blame]
Yi Tsengfa4a1c72017-11-03 10:22:38 -07001/*
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.pipelines.fabric;
18
Carmelo Casconeb5324e72018-11-25 02:26:32 -080019import com.google.common.collect.ImmutableMap;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070020import org.onosproject.net.PortNumber;
Yi Tsengdf3eec52018-02-15 14:56:02 -080021import org.onosproject.net.flow.DefaultTrafficTreatment;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070022import org.onosproject.net.flow.TrafficTreatment;
23import org.onosproject.net.flow.instructions.Instruction;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070024import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
25import org.onosproject.net.flow.instructions.L2ModificationInstruction;
26import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
Yi Tseng1b154bd2017-11-20 17:48:19 -080027import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070028import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
29import org.onosproject.net.pi.model.PiActionId;
30import org.onosproject.net.pi.model.PiPipelineInterpreter.PiInterpreterException;
Yi Tseng47eac892018-07-11 02:17:04 +080031import org.onosproject.net.pi.model.PiTableId;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070032import org.onosproject.net.pi.runtime.PiAction;
33import org.onosproject.net.pi.runtime.PiActionParam;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070034
Daniele Morof51d0c12019-07-30 10:43:10 -070035import java.util.List;
36import java.util.stream.Collectors;
37
Yi Tsengfa4a1c72017-11-03 10:22:38 -070038import static java.lang.String.format;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080039import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT;
40import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.ETH_DST;
41import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.ETH_SRC;
42import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.MPLS_LABEL;
43import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.MPLS_PUSH;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070044import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_ID;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080045import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_POP;
46import static org.onosproject.pipelines.fabric.FabricUtils.instruction;
47import static org.onosproject.pipelines.fabric.FabricUtils.l2Instruction;
Daniele Morof51d0c12019-07-30 10:43:10 -070048import static org.onosproject.pipelines.fabric.FabricUtils.l2Instructions;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070049
Carmelo Casconeb5324e72018-11-25 02:26:32 -080050/**
51 * Treatment translation logic.
52 */
Yi Tsengfa4a1c72017-11-03 10:22:38 -070053final class FabricTreatmentInterpreter {
Yi Tseng20f9e7b2018-05-24 23:27:39 +080054
Daniele Morof51d0c12019-07-30 10:43:10 -070055 private final FabricCapabilities capabilities;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080056 private static final ImmutableMap<PiTableId, PiActionId> NOP_ACTIONS =
57 ImmutableMap.<PiTableId, PiActionId>builder()
58 .put(FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN,
59 FabricConstants.FABRIC_INGRESS_FILTERING_PERMIT)
60 .put(FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V4,
61 FabricConstants.FABRIC_INGRESS_FORWARDING_NOP_ROUTING_V4)
62 .put(FabricConstants.FABRIC_INGRESS_ACL_ACL,
63 FabricConstants.FABRIC_INGRESS_ACL_NOP_ACL)
64 .put(FabricConstants.FABRIC_EGRESS_EGRESS_NEXT_EGRESS_VLAN,
65 FabricConstants.FABRIC_EGRESS_EGRESS_NEXT_POP_VLAN)
66 .build();
Yi Tsengfa4a1c72017-11-03 10:22:38 -070067
Daniele Morof51d0c12019-07-30 10:43:10 -070068
69 FabricTreatmentInterpreter(FabricCapabilities capabilities) {
70 this.capabilities = capabilities;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070071 }
72
Yi Tseng47eac892018-07-11 02:17:04 +080073 static PiAction mapFilteringTreatment(TrafficTreatment treatment, PiTableId tableId)
Yi Tsengfa4a1c72017-11-03 10:22:38 -070074 throws PiInterpreterException {
Carmelo Casconeb5324e72018-11-25 02:26:32 -080075
76 if (!tableId.equals(FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN)) {
77 // Mapping for other tables of the filtering block must be handled
78 // in the pipeliner.
79 tableException(tableId);
Yi Tsengfa4a1c72017-11-03 10:22:38 -070080 }
81
Daniele Morof51d0c12019-07-30 10:43:10 -070082 // VLAN_POP action is equivalent to the permit action (VLANs pop is done anyway)
83 if (isNoAction(treatment) || isFilteringPopAction(treatment)) {
Carmelo Casconeb5324e72018-11-25 02:26:32 -080084 // Permit action if table is ingress_port_vlan;
85 return nop(tableId);
Yi Tsengfa4a1c72017-11-03 10:22:38 -070086 }
87
Carmelo Casconeb5324e72018-11-25 02:26:32 -080088 final ModVlanIdInstruction setVlanInst = (ModVlanIdInstruction) l2InstructionOrFail(
89 treatment, VLAN_ID, tableId);
Yi Tsengfa4a1c72017-11-03 10:22:38 -070090 return PiAction.builder()
Carmelo Casconeb5324e72018-11-25 02:26:32 -080091 .withId(FabricConstants.FABRIC_INGRESS_FILTERING_PERMIT_WITH_INTERNAL_VLAN)
92 .withParameter(new PiActionParam(
93 FabricConstants.VLAN_ID, setVlanInst.vlanId().toShort()))
Yi Tsengfa4a1c72017-11-03 10:22:38 -070094 .build();
95 }
96
Yi Tsengfa4a1c72017-11-03 10:22:38 -070097
Carmelo Casconeb5324e72018-11-25 02:26:32 -080098 static PiAction mapForwardingTreatment(TrafficTreatment treatment, PiTableId tableId)
Yi Tsengfa4a1c72017-11-03 10:22:38 -070099 throws PiInterpreterException {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800100 if (isNoAction(treatment)) {
101 return nop(tableId);
Yi Tsengdf3eec52018-02-15 14:56:02 -0800102 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800103 treatmentException(
104 tableId, treatment,
105 "supports mapping only for empty/no-action treatments");
106 return null;
107 }
108
Daniele Morof51d0c12019-07-30 10:43:10 -0700109 PiAction mapNextTreatment(TrafficTreatment treatment, PiTableId tableId)
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800110 throws PiInterpreterException {
111 if (tableId == FabricConstants.FABRIC_INGRESS_NEXT_NEXT_VLAN) {
112 return mapNextVlanTreatment(treatment, tableId);
113 } else if (tableId == FabricConstants.FABRIC_INGRESS_NEXT_HASHED) {
114 return mapNextHashedOrSimpleTreatment(treatment, tableId, false);
115 } else if (tableId == FabricConstants.FABRIC_INGRESS_NEXT_SIMPLE) {
116 return mapNextHashedOrSimpleTreatment(treatment, tableId, true);
Carmelo Cascone45cc0862018-11-26 11:50:41 -0800117 } else if (tableId == FabricConstants.FABRIC_INGRESS_NEXT_XCONNECT) {
118 return mapNextXconnect(treatment, tableId);
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800119 }
120 throw new PiInterpreterException(format(
121 "Treatment mapping not supported for table '%s'", tableId));
122 }
123
Daniele Morof51d0c12019-07-30 10:43:10 -0700124 private PiAction mapNextVlanTreatment(TrafficTreatment treatment, PiTableId tableId)
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800125 throws PiInterpreterException {
Daniele Morof51d0c12019-07-30 10:43:10 -0700126 final List<ModVlanIdInstruction> modVlanIdInst = l2InstructionsOrFail(treatment, VLAN_ID, tableId)
127 .stream().map(i -> (ModVlanIdInstruction) i).collect(Collectors.toList());
128 if (modVlanIdInst.size() == 1) {
129 return PiAction.builder().withId(FabricConstants.FABRIC_INGRESS_NEXT_SET_VLAN)
130 .withParameter(new PiActionParam(
131 FabricConstants.VLAN_ID,
132 modVlanIdInst.get(0).vlanId().toShort()))
133 .build();
134 }
135 if (modVlanIdInst.size() == 2 && capabilities.supportDoubleVlanTerm()) {
136 return PiAction.builder()
137 .withId(FabricConstants.FABRIC_INGRESS_NEXT_SET_DOUBLE_VLAN)
138 .withParameter(new PiActionParam(
139 FabricConstants.INNER_VLAN_ID,
140 modVlanIdInst.get(0).vlanId().toShort()))
141 .withParameter(new PiActionParam(
142 FabricConstants.OUTER_VLAN_ID,
143 modVlanIdInst.get(1).vlanId().toShort()))
144 .build();
145 }
146 throw new PiInterpreterException("Too many VLAN instructions");
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800147 }
148
149 private static PiAction mapNextHashedOrSimpleTreatment(
150 TrafficTreatment treatment, PiTableId tableId, boolean simple)
151 throws PiInterpreterException {
152 // Provide mapping for output_hashed, routing_hashed, and
153 // mpls_routing_hashed. multicast_hashed can only be invoked with
154 // PiAction, hence no mapping. outPort required for all actions. Presence
155 // of other instructions will determine which action to map to.
156 final PortNumber outPort = ((OutputInstruction) instructionOrFail(
157 treatment, OUTPUT, tableId)).port();
158 final ModEtherInstruction ethDst = (ModEtherInstruction) l2Instruction(
159 treatment, ETH_DST);
160 final ModEtherInstruction ethSrc = (ModEtherInstruction) l2Instruction(
161 treatment, ETH_SRC);
162 final Instruction mplsPush = l2Instruction(
163 treatment, MPLS_PUSH);
164 final ModMplsLabelInstruction mplsLabel = (ModMplsLabelInstruction) l2Instruction(
165 treatment, MPLS_LABEL);
166
167 final PiAction.Builder actionBuilder = PiAction.builder()
168 .withParameter(new PiActionParam(FabricConstants.PORT_NUM, outPort.toLong()));
169
170 if (ethDst != null && ethSrc != null) {
171 actionBuilder.withParameter(new PiActionParam(
172 FabricConstants.SMAC, ethSrc.mac().toBytes()));
173 actionBuilder.withParameter(new PiActionParam(
174 FabricConstants.DMAC, ethDst.mac().toBytes()));
175 if (mplsLabel != null) {
176 // mpls_routing_hashed
177 return actionBuilder
178 .withParameter(new PiActionParam(FabricConstants.LABEL, mplsLabel.label().toInt()))
179 .withId(simple ? FabricConstants.FABRIC_INGRESS_NEXT_MPLS_ROUTING_SIMPLE
180 : FabricConstants.FABRIC_INGRESS_NEXT_MPLS_ROUTING_HASHED)
181 .build();
182 } else {
183 // routing_hashed
184 return actionBuilder
185 .withId(simple ? FabricConstants.FABRIC_INGRESS_NEXT_ROUTING_SIMPLE
186 : FabricConstants.FABRIC_INGRESS_NEXT_ROUTING_HASHED)
187 .build();
188 }
189 } else {
190 // output_hashed
191 return actionBuilder
192 .withId(simple ? FabricConstants.FABRIC_INGRESS_NEXT_OUTPUT_SIMPLE
193 : FabricConstants.FABRIC_INGRESS_NEXT_OUTPUT_HASHED)
194 .build();
195 }
196 }
197
Carmelo Cascone45cc0862018-11-26 11:50:41 -0800198 private static PiAction mapNextXconnect(
199 TrafficTreatment treatment, PiTableId tableId)
200 throws PiInterpreterException {
201 final PortNumber outPort = ((OutputInstruction) instructionOrFail(
202 treatment, OUTPUT, tableId)).port();
203 return PiAction.builder()
204 .withId(FabricConstants.FABRIC_INGRESS_NEXT_OUTPUT_XCONNECT)
205 .withParameter(new PiActionParam(
206 FabricConstants.PORT_NUM, outPort.toLong()))
207 .build();
208 }
209
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800210 static PiAction mapAclTreatment(TrafficTreatment treatment, PiTableId tableId)
211 throws PiInterpreterException {
212 if (isNoAction(treatment)) {
213 return nop(tableId);
214 }
Daniele Moro01ca2ab2019-06-25 11:48:48 -0700215 treatmentException(
216 tableId, treatment,
217 "unsupported treatment");
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800218
Daniele Moro01ca2ab2019-06-25 11:48:48 -0700219 // This function will never return null
220 return null;
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700221 }
222
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700223
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800224 static PiAction mapEgressNextTreatment(
225 TrafficTreatment treatment, PiTableId tableId)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700226 throws PiInterpreterException {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800227 l2InstructionOrFail(treatment, VLAN_POP, tableId);
228 return PiAction.builder()
229 .withId(FabricConstants.FABRIC_EGRESS_EGRESS_NEXT_POP_VLAN)
230 .build();
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700231
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700232 }
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800233
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800234 private static PiAction nop(PiTableId tableId) throws PiInterpreterException {
235 if (!NOP_ACTIONS.containsKey(tableId)) {
236 throw new PiInterpreterException(format("table '%s' doe not specify a nop action", tableId));
237 }
238 return PiAction.builder().withId(NOP_ACTIONS.get(tableId)).build();
239 }
240
241 private static boolean isNoAction(TrafficTreatment treatment) {
242 return treatment.equals(DefaultTrafficTreatment.emptyTreatment()) ||
243 treatment.allInstructions().isEmpty();
244 }
245
Daniele Morof51d0c12019-07-30 10:43:10 -0700246 private static boolean isFilteringPopAction(TrafficTreatment treatment) {
247 return l2Instruction(treatment, VLAN_POP) != null;
248 }
249
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800250 private static Instruction l2InstructionOrFail(
251 TrafficTreatment treatment,
252 L2ModificationInstruction.L2SubType subType, PiTableId tableId)
253 throws PiInterpreterException {
254 final Instruction inst = l2Instruction(treatment, subType);
255 if (inst == null) {
256 treatmentException(tableId, treatment, format("missing %s instruction", subType));
257 }
258 return inst;
259 }
260
Daniele Morof51d0c12019-07-30 10:43:10 -0700261 private static List<L2ModificationInstruction> l2InstructionsOrFail(
262 TrafficTreatment treatment,
263 L2ModificationInstruction.L2SubType subType, PiTableId tableId)
264 throws PiInterpreterException {
265 final List<L2ModificationInstruction> inst = l2Instructions(treatment, subType);
266 if (inst == null || inst.isEmpty()) {
267 treatmentException(tableId, treatment, format("missing %s instruction", subType));
268 }
269 return inst;
270 }
271
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800272 private static Instruction instructionOrFail(
273 TrafficTreatment treatment, Instruction.Type type, PiTableId tableId)
274 throws PiInterpreterException {
275 final Instruction inst = instruction(treatment, type);
276 if (inst == null) {
277 treatmentException(tableId, treatment, format("missing %s instruction", type));
278 }
279 return inst;
280 }
281
282 private static void tableException(PiTableId tableId)
283 throws PiInterpreterException {
284 throw new PiInterpreterException(format("Table '%s' not supported", tableId));
285 }
286
287 private static void treatmentException(
288 PiTableId tableId, TrafficTreatment treatment, String explanation)
289 throws PiInterpreterException {
290 throw new PiInterpreterException(format(
291 "Invalid treatment for table '%s', %s: %s", tableId, explanation, treatment));
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800292 }
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700293}