blob: 21ff675b012d200efb624c07fd3f8a734826e218 [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
Carmelo Cascone356ab8b2019-09-25 01:02:53 -070017package org.onosproject.pipelines.fabric.impl.behaviour;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070018
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;
Carmelo Cascone2102bfb2020-12-04 16:54:24 -080034import org.onosproject.pipelines.fabric.FabricConstants;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070035
Daniele Morof51d0c12019-07-30 10:43:10 -070036import java.util.List;
37import java.util.stream.Collectors;
38
Yi Tsengfa4a1c72017-11-03 10:22:38 -070039import static java.lang.String.format;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080040import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT;
41import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.ETH_DST;
42import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.ETH_SRC;
43import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.MPLS_LABEL;
44import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.MPLS_PUSH;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070045import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_ID;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080046import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_POP;
Carmelo Cascone356ab8b2019-09-25 01:02:53 -070047import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.instruction;
48import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.l2Instruction;
49import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.l2Instructions;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070050
Carmelo Casconeb5324e72018-11-25 02:26:32 -080051/**
52 * Treatment translation logic.
53 */
Yi Tsengfa4a1c72017-11-03 10:22:38 -070054final class FabricTreatmentInterpreter {
Yi Tseng20f9e7b2018-05-24 23:27:39 +080055
Daniele Morof51d0c12019-07-30 10:43:10 -070056 private final FabricCapabilities capabilities;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080057 private static final ImmutableMap<PiTableId, PiActionId> NOP_ACTIONS =
58 ImmutableMap.<PiTableId, PiActionId>builder()
59 .put(FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN,
60 FabricConstants.FABRIC_INGRESS_FILTERING_PERMIT)
61 .put(FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V4,
62 FabricConstants.FABRIC_INGRESS_FORWARDING_NOP_ROUTING_V4)
63 .put(FabricConstants.FABRIC_INGRESS_ACL_ACL,
64 FabricConstants.FABRIC_INGRESS_ACL_NOP_ACL)
65 .put(FabricConstants.FABRIC_EGRESS_EGRESS_NEXT_EGRESS_VLAN,
66 FabricConstants.FABRIC_EGRESS_EGRESS_NEXT_POP_VLAN)
67 .build();
Yi Tsengfa4a1c72017-11-03 10:22:38 -070068
Daniele Morof51d0c12019-07-30 10:43:10 -070069
70 FabricTreatmentInterpreter(FabricCapabilities capabilities) {
71 this.capabilities = capabilities;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070072 }
73
Yi Tseng47eac892018-07-11 02:17:04 +080074 static PiAction mapFilteringTreatment(TrafficTreatment treatment, PiTableId tableId)
Yi Tsengfa4a1c72017-11-03 10:22:38 -070075 throws PiInterpreterException {
Carmelo Casconeb5324e72018-11-25 02:26:32 -080076
77 if (!tableId.equals(FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN)) {
78 // Mapping for other tables of the filtering block must be handled
79 // in the pipeliner.
80 tableException(tableId);
Yi Tsengfa4a1c72017-11-03 10:22:38 -070081 }
82
Daniele Morof51d0c12019-07-30 10:43:10 -070083 // VLAN_POP action is equivalent to the permit action (VLANs pop is done anyway)
84 if (isNoAction(treatment) || isFilteringPopAction(treatment)) {
Carmelo Casconeb5324e72018-11-25 02:26:32 -080085 // Permit action if table is ingress_port_vlan;
86 return nop(tableId);
Yi Tsengfa4a1c72017-11-03 10:22:38 -070087 }
88
Carmelo Casconeb5324e72018-11-25 02:26:32 -080089 final ModVlanIdInstruction setVlanInst = (ModVlanIdInstruction) l2InstructionOrFail(
90 treatment, VLAN_ID, tableId);
Yi Tsengfa4a1c72017-11-03 10:22:38 -070091 return PiAction.builder()
Carmelo Casconeb5324e72018-11-25 02:26:32 -080092 .withId(FabricConstants.FABRIC_INGRESS_FILTERING_PERMIT_WITH_INTERNAL_VLAN)
93 .withParameter(new PiActionParam(
94 FabricConstants.VLAN_ID, setVlanInst.vlanId().toShort()))
Yi Tsengfa4a1c72017-11-03 10:22:38 -070095 .build();
96 }
97
Yi Tsengfa4a1c72017-11-03 10:22:38 -070098
Carmelo Casconeb5324e72018-11-25 02:26:32 -080099 static PiAction mapForwardingTreatment(TrafficTreatment treatment, PiTableId tableId)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700100 throws PiInterpreterException {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800101 if (isNoAction(treatment)) {
102 return nop(tableId);
Yi Tsengdf3eec52018-02-15 14:56:02 -0800103 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800104 treatmentException(
105 tableId, treatment,
106 "supports mapping only for empty/no-action treatments");
107 return null;
108 }
109
Daniele Morof51d0c12019-07-30 10:43:10 -0700110 PiAction mapNextTreatment(TrafficTreatment treatment, PiTableId tableId)
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800111 throws PiInterpreterException {
112 if (tableId == FabricConstants.FABRIC_INGRESS_NEXT_NEXT_VLAN) {
113 return mapNextVlanTreatment(treatment, tableId);
114 } else if (tableId == FabricConstants.FABRIC_INGRESS_NEXT_HASHED) {
115 return mapNextHashedOrSimpleTreatment(treatment, tableId, false);
116 } else if (tableId == FabricConstants.FABRIC_INGRESS_NEXT_SIMPLE) {
117 return mapNextHashedOrSimpleTreatment(treatment, tableId, true);
Carmelo Cascone45cc0862018-11-26 11:50:41 -0800118 } else if (tableId == FabricConstants.FABRIC_INGRESS_NEXT_XCONNECT) {
119 return mapNextXconnect(treatment, tableId);
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800120 }
121 throw new PiInterpreterException(format(
122 "Treatment mapping not supported for table '%s'", tableId));
123 }
124
Daniele Morof51d0c12019-07-30 10:43:10 -0700125 private PiAction mapNextVlanTreatment(TrafficTreatment treatment, PiTableId tableId)
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800126 throws PiInterpreterException {
Daniele Morof51d0c12019-07-30 10:43:10 -0700127 final List<ModVlanIdInstruction> modVlanIdInst = l2InstructionsOrFail(treatment, VLAN_ID, tableId)
128 .stream().map(i -> (ModVlanIdInstruction) i).collect(Collectors.toList());
129 if (modVlanIdInst.size() == 1) {
130 return PiAction.builder().withId(FabricConstants.FABRIC_INGRESS_NEXT_SET_VLAN)
131 .withParameter(new PiActionParam(
132 FabricConstants.VLAN_ID,
133 modVlanIdInst.get(0).vlanId().toShort()))
134 .build();
135 }
136 if (modVlanIdInst.size() == 2 && capabilities.supportDoubleVlanTerm()) {
137 return PiAction.builder()
138 .withId(FabricConstants.FABRIC_INGRESS_NEXT_SET_DOUBLE_VLAN)
139 .withParameter(new PiActionParam(
140 FabricConstants.INNER_VLAN_ID,
141 modVlanIdInst.get(0).vlanId().toShort()))
142 .withParameter(new PiActionParam(
143 FabricConstants.OUTER_VLAN_ID,
144 modVlanIdInst.get(1).vlanId().toShort()))
145 .build();
146 }
147 throw new PiInterpreterException("Too many VLAN instructions");
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800148 }
149
150 private static PiAction mapNextHashedOrSimpleTreatment(
151 TrafficTreatment treatment, PiTableId tableId, boolean simple)
152 throws PiInterpreterException {
153 // Provide mapping for output_hashed, routing_hashed, and
154 // mpls_routing_hashed. multicast_hashed can only be invoked with
155 // PiAction, hence no mapping. outPort required for all actions. Presence
156 // of other instructions will determine which action to map to.
157 final PortNumber outPort = ((OutputInstruction) instructionOrFail(
158 treatment, OUTPUT, tableId)).port();
159 final ModEtherInstruction ethDst = (ModEtherInstruction) l2Instruction(
160 treatment, ETH_DST);
161 final ModEtherInstruction ethSrc = (ModEtherInstruction) l2Instruction(
162 treatment, ETH_SRC);
163 final Instruction mplsPush = l2Instruction(
164 treatment, MPLS_PUSH);
165 final ModMplsLabelInstruction mplsLabel = (ModMplsLabelInstruction) l2Instruction(
166 treatment, MPLS_LABEL);
167
168 final PiAction.Builder actionBuilder = PiAction.builder()
169 .withParameter(new PiActionParam(FabricConstants.PORT_NUM, outPort.toLong()));
170
171 if (ethDst != null && ethSrc != null) {
172 actionBuilder.withParameter(new PiActionParam(
173 FabricConstants.SMAC, ethSrc.mac().toBytes()));
174 actionBuilder.withParameter(new PiActionParam(
175 FabricConstants.DMAC, ethDst.mac().toBytes()));
176 if (mplsLabel != null) {
177 // mpls_routing_hashed
178 return actionBuilder
179 .withParameter(new PiActionParam(FabricConstants.LABEL, mplsLabel.label().toInt()))
180 .withId(simple ? FabricConstants.FABRIC_INGRESS_NEXT_MPLS_ROUTING_SIMPLE
181 : FabricConstants.FABRIC_INGRESS_NEXT_MPLS_ROUTING_HASHED)
182 .build();
183 } else {
184 // routing_hashed
185 return actionBuilder
186 .withId(simple ? FabricConstants.FABRIC_INGRESS_NEXT_ROUTING_SIMPLE
187 : FabricConstants.FABRIC_INGRESS_NEXT_ROUTING_HASHED)
188 .build();
189 }
190 } else {
191 // output_hashed
192 return actionBuilder
193 .withId(simple ? FabricConstants.FABRIC_INGRESS_NEXT_OUTPUT_SIMPLE
194 : FabricConstants.FABRIC_INGRESS_NEXT_OUTPUT_HASHED)
195 .build();
196 }
197 }
198
Carmelo Cascone45cc0862018-11-26 11:50:41 -0800199 private static PiAction mapNextXconnect(
200 TrafficTreatment treatment, PiTableId tableId)
201 throws PiInterpreterException {
202 final PortNumber outPort = ((OutputInstruction) instructionOrFail(
203 treatment, OUTPUT, tableId)).port();
204 return PiAction.builder()
205 .withId(FabricConstants.FABRIC_INGRESS_NEXT_OUTPUT_XCONNECT)
206 .withParameter(new PiActionParam(
207 FabricConstants.PORT_NUM, outPort.toLong()))
208 .build();
209 }
210
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800211 static PiAction mapAclTreatment(TrafficTreatment treatment, PiTableId tableId)
212 throws PiInterpreterException {
213 if (isNoAction(treatment)) {
214 return nop(tableId);
215 }
Daniele Moro01ca2ab2019-06-25 11:48:48 -0700216 treatmentException(
217 tableId, treatment,
218 "unsupported treatment");
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800219
Daniele Moro01ca2ab2019-06-25 11:48:48 -0700220 // This function will never return null
221 return null;
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700222 }
223
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700224
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800225 static PiAction mapEgressNextTreatment(
226 TrafficTreatment treatment, PiTableId tableId)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700227 throws PiInterpreterException {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800228 l2InstructionOrFail(treatment, VLAN_POP, tableId);
229 return PiAction.builder()
230 .withId(FabricConstants.FABRIC_EGRESS_EGRESS_NEXT_POP_VLAN)
231 .build();
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700232
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700233 }
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800234
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800235 private static PiAction nop(PiTableId tableId) throws PiInterpreterException {
236 if (!NOP_ACTIONS.containsKey(tableId)) {
237 throw new PiInterpreterException(format("table '%s' doe not specify a nop action", tableId));
238 }
239 return PiAction.builder().withId(NOP_ACTIONS.get(tableId)).build();
240 }
241
242 private static boolean isNoAction(TrafficTreatment treatment) {
243 return treatment.equals(DefaultTrafficTreatment.emptyTreatment()) ||
244 treatment.allInstructions().isEmpty();
245 }
246
Daniele Morof51d0c12019-07-30 10:43:10 -0700247 private static boolean isFilteringPopAction(TrafficTreatment treatment) {
248 return l2Instruction(treatment, VLAN_POP) != null;
249 }
250
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800251 private static Instruction l2InstructionOrFail(
252 TrafficTreatment treatment,
253 L2ModificationInstruction.L2SubType subType, PiTableId tableId)
254 throws PiInterpreterException {
255 final Instruction inst = l2Instruction(treatment, subType);
256 if (inst == null) {
257 treatmentException(tableId, treatment, format("missing %s instruction", subType));
258 }
259 return inst;
260 }
261
Daniele Morof51d0c12019-07-30 10:43:10 -0700262 private static List<L2ModificationInstruction> l2InstructionsOrFail(
263 TrafficTreatment treatment,
264 L2ModificationInstruction.L2SubType subType, PiTableId tableId)
265 throws PiInterpreterException {
266 final List<L2ModificationInstruction> inst = l2Instructions(treatment, subType);
267 if (inst == null || inst.isEmpty()) {
268 treatmentException(tableId, treatment, format("missing %s instruction", subType));
269 }
270 return inst;
271 }
272
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800273 private static Instruction instructionOrFail(
274 TrafficTreatment treatment, Instruction.Type type, PiTableId tableId)
275 throws PiInterpreterException {
276 final Instruction inst = instruction(treatment, type);
277 if (inst == null) {
278 treatmentException(tableId, treatment, format("missing %s instruction", type));
279 }
280 return inst;
281 }
282
283 private static void tableException(PiTableId tableId)
284 throws PiInterpreterException {
285 throw new PiInterpreterException(format("Table '%s' not supported", tableId));
286 }
287
288 private static void treatmentException(
289 PiTableId tableId, TrafficTreatment treatment, String explanation)
290 throws PiInterpreterException {
291 throw new PiInterpreterException(format(
292 "Invalid treatment for table '%s', %s: %s", tableId, explanation, treatment));
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800293 }
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700294}