blob: bca8424cfed4fcc3fc9c5592c62baaf5d0715794 [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
35import static java.lang.String.format;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080036import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT;
37import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.ETH_DST;
38import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.ETH_SRC;
39import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.MPLS_LABEL;
40import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.MPLS_PUSH;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070041import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_ID;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080042import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_POP;
43import static org.onosproject.pipelines.fabric.FabricUtils.instruction;
44import static org.onosproject.pipelines.fabric.FabricUtils.l2Instruction;
45import static org.onosproject.pipelines.fabric.FabricUtils.outputPort;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070046
Carmelo Casconeb5324e72018-11-25 02:26:32 -080047/**
48 * Treatment translation logic.
49 */
Yi Tsengfa4a1c72017-11-03 10:22:38 -070050final class FabricTreatmentInterpreter {
Yi Tseng20f9e7b2018-05-24 23:27:39 +080051
Carmelo Casconeb5324e72018-11-25 02:26:32 -080052 private static final ImmutableMap<PiTableId, PiActionId> NOP_ACTIONS =
53 ImmutableMap.<PiTableId, PiActionId>builder()
54 .put(FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN,
55 FabricConstants.FABRIC_INGRESS_FILTERING_PERMIT)
56 .put(FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V4,
57 FabricConstants.FABRIC_INGRESS_FORWARDING_NOP_ROUTING_V4)
58 .put(FabricConstants.FABRIC_INGRESS_ACL_ACL,
59 FabricConstants.FABRIC_INGRESS_ACL_NOP_ACL)
60 .put(FabricConstants.FABRIC_EGRESS_EGRESS_NEXT_EGRESS_VLAN,
61 FabricConstants.FABRIC_EGRESS_EGRESS_NEXT_POP_VLAN)
62 .build();
Yi Tsengfa4a1c72017-11-03 10:22:38 -070063
Carmelo Casconeb5324e72018-11-25 02:26:32 -080064 private FabricTreatmentInterpreter() {
65 // Hide default constructor
Yi Tsengfa4a1c72017-11-03 10:22:38 -070066 }
67
Yi Tseng47eac892018-07-11 02:17:04 +080068 static PiAction mapFilteringTreatment(TrafficTreatment treatment, PiTableId tableId)
Yi Tsengfa4a1c72017-11-03 10:22:38 -070069 throws PiInterpreterException {
Carmelo Casconeb5324e72018-11-25 02:26:32 -080070
71 if (!tableId.equals(FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN)) {
72 // Mapping for other tables of the filtering block must be handled
73 // in the pipeliner.
74 tableException(tableId);
Yi Tsengfa4a1c72017-11-03 10:22:38 -070075 }
76
Carmelo Casconeb5324e72018-11-25 02:26:32 -080077 if (isNoAction(treatment)) {
78 // Permit action if table is ingress_port_vlan;
79 return nop(tableId);
Yi Tsengfa4a1c72017-11-03 10:22:38 -070080 }
81
Carmelo Casconeb5324e72018-11-25 02:26:32 -080082 final ModVlanIdInstruction setVlanInst = (ModVlanIdInstruction) l2InstructionOrFail(
83 treatment, VLAN_ID, tableId);
Yi Tsengfa4a1c72017-11-03 10:22:38 -070084 return PiAction.builder()
Carmelo Casconeb5324e72018-11-25 02:26:32 -080085 .withId(FabricConstants.FABRIC_INGRESS_FILTERING_PERMIT_WITH_INTERNAL_VLAN)
86 .withParameter(new PiActionParam(
87 FabricConstants.VLAN_ID, setVlanInst.vlanId().toShort()))
Yi Tsengfa4a1c72017-11-03 10:22:38 -070088 .build();
89 }
90
Yi Tsengfa4a1c72017-11-03 10:22:38 -070091
Carmelo Casconeb5324e72018-11-25 02:26:32 -080092 static PiAction mapForwardingTreatment(TrafficTreatment treatment, PiTableId tableId)
Yi Tsengfa4a1c72017-11-03 10:22:38 -070093 throws PiInterpreterException {
Carmelo Casconeb5324e72018-11-25 02:26:32 -080094 if (isNoAction(treatment)) {
95 return nop(tableId);
Yi Tsengdf3eec52018-02-15 14:56:02 -080096 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -080097 treatmentException(
98 tableId, treatment,
99 "supports mapping only for empty/no-action treatments");
100 return null;
101 }
102
103 static PiAction mapNextTreatment(TrafficTreatment treatment, PiTableId tableId)
104 throws PiInterpreterException {
105 if (tableId == FabricConstants.FABRIC_INGRESS_NEXT_NEXT_VLAN) {
106 return mapNextVlanTreatment(treatment, tableId);
107 } else if (tableId == FabricConstants.FABRIC_INGRESS_NEXT_HASHED) {
108 return mapNextHashedOrSimpleTreatment(treatment, tableId, false);
109 } else if (tableId == FabricConstants.FABRIC_INGRESS_NEXT_SIMPLE) {
110 return mapNextHashedOrSimpleTreatment(treatment, tableId, true);
Carmelo Cascone45cc0862018-11-26 11:50:41 -0800111 } else if (tableId == FabricConstants.FABRIC_INGRESS_NEXT_XCONNECT) {
112 return mapNextXconnect(treatment, tableId);
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800113 }
114 throw new PiInterpreterException(format(
115 "Treatment mapping not supported for table '%s'", tableId));
116 }
117
118 private static PiAction mapNextVlanTreatment(TrafficTreatment treatment, PiTableId tableId)
119 throws PiInterpreterException {
120 final ModVlanIdInstruction modVlanIdInst = (ModVlanIdInstruction)
121 l2InstructionOrFail(treatment, VLAN_ID, tableId);
122 return PiAction.builder()
123 .withId(FabricConstants.FABRIC_INGRESS_NEXT_SET_VLAN)
124 .withParameter(new PiActionParam(
125 FabricConstants.VLAN_ID,
126 modVlanIdInst.vlanId().toShort()))
127 .build();
128 }
129
130 private static PiAction mapNextHashedOrSimpleTreatment(
131 TrafficTreatment treatment, PiTableId tableId, boolean simple)
132 throws PiInterpreterException {
133 // Provide mapping for output_hashed, routing_hashed, and
134 // mpls_routing_hashed. multicast_hashed can only be invoked with
135 // PiAction, hence no mapping. outPort required for all actions. Presence
136 // of other instructions will determine which action to map to.
137 final PortNumber outPort = ((OutputInstruction) instructionOrFail(
138 treatment, OUTPUT, tableId)).port();
139 final ModEtherInstruction ethDst = (ModEtherInstruction) l2Instruction(
140 treatment, ETH_DST);
141 final ModEtherInstruction ethSrc = (ModEtherInstruction) l2Instruction(
142 treatment, ETH_SRC);
143 final Instruction mplsPush = l2Instruction(
144 treatment, MPLS_PUSH);
145 final ModMplsLabelInstruction mplsLabel = (ModMplsLabelInstruction) l2Instruction(
146 treatment, MPLS_LABEL);
147
148 final PiAction.Builder actionBuilder = PiAction.builder()
149 .withParameter(new PiActionParam(FabricConstants.PORT_NUM, outPort.toLong()));
150
151 if (ethDst != null && ethSrc != null) {
152 actionBuilder.withParameter(new PiActionParam(
153 FabricConstants.SMAC, ethSrc.mac().toBytes()));
154 actionBuilder.withParameter(new PiActionParam(
155 FabricConstants.DMAC, ethDst.mac().toBytes()));
156 if (mplsLabel != null) {
157 // mpls_routing_hashed
158 return actionBuilder
159 .withParameter(new PiActionParam(FabricConstants.LABEL, mplsLabel.label().toInt()))
160 .withId(simple ? FabricConstants.FABRIC_INGRESS_NEXT_MPLS_ROUTING_SIMPLE
161 : FabricConstants.FABRIC_INGRESS_NEXT_MPLS_ROUTING_HASHED)
162 .build();
163 } else {
164 // routing_hashed
165 return actionBuilder
166 .withId(simple ? FabricConstants.FABRIC_INGRESS_NEXT_ROUTING_SIMPLE
167 : FabricConstants.FABRIC_INGRESS_NEXT_ROUTING_HASHED)
168 .build();
169 }
170 } else {
171 // output_hashed
172 return actionBuilder
173 .withId(simple ? FabricConstants.FABRIC_INGRESS_NEXT_OUTPUT_SIMPLE
174 : FabricConstants.FABRIC_INGRESS_NEXT_OUTPUT_HASHED)
175 .build();
176 }
177 }
178
Carmelo Cascone45cc0862018-11-26 11:50:41 -0800179 private static PiAction mapNextXconnect(
180 TrafficTreatment treatment, PiTableId tableId)
181 throws PiInterpreterException {
182 final PortNumber outPort = ((OutputInstruction) instructionOrFail(
183 treatment, OUTPUT, tableId)).port();
184 return PiAction.builder()
185 .withId(FabricConstants.FABRIC_INGRESS_NEXT_OUTPUT_XCONNECT)
186 .withParameter(new PiActionParam(
187 FabricConstants.PORT_NUM, outPort.toLong()))
188 .build();
189 }
190
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800191 static PiAction mapAclTreatment(TrafficTreatment treatment, PiTableId tableId)
192 throws PiInterpreterException {
193 if (isNoAction(treatment)) {
194 return nop(tableId);
195 }
196
197 final PortNumber outPort = outputPort(treatment);
Carmelo Cascone1e8843f2018-07-19 19:01:12 +0200198 if (outPort == null
199 || !outPort.equals(PortNumber.CONTROLLER)
200 || treatment.allInstructions().size() > 1) {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800201 treatmentException(
202 tableId, treatment,
203 "supports only punt/clone to CPU actions");
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700204 }
205
Carmelo Cascone1e8843f2018-07-19 19:01:12 +0200206 final PiActionId actionId = treatment.clearedDeferred()
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800207 ? FabricConstants.FABRIC_INGRESS_ACL_PUNT_TO_CPU
208 : FabricConstants.FABRIC_INGRESS_ACL_CLONE_TO_CPU;
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700209
210 return PiAction.builder()
Carmelo Cascone1e8843f2018-07-19 19:01:12 +0200211 .withId(actionId)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700212 .build();
213 }
214
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700215
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800216 static PiAction mapEgressNextTreatment(
217 TrafficTreatment treatment, PiTableId tableId)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700218 throws PiInterpreterException {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800219 l2InstructionOrFail(treatment, VLAN_POP, tableId);
220 return PiAction.builder()
221 .withId(FabricConstants.FABRIC_EGRESS_EGRESS_NEXT_POP_VLAN)
222 .build();
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700223
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700224 }
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800225
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800226 private static PiAction nop(PiTableId tableId) throws PiInterpreterException {
227 if (!NOP_ACTIONS.containsKey(tableId)) {
228 throw new PiInterpreterException(format("table '%s' doe not specify a nop action", tableId));
229 }
230 return PiAction.builder().withId(NOP_ACTIONS.get(tableId)).build();
231 }
232
233 private static boolean isNoAction(TrafficTreatment treatment) {
234 return treatment.equals(DefaultTrafficTreatment.emptyTreatment()) ||
235 treatment.allInstructions().isEmpty();
236 }
237
238 private static Instruction l2InstructionOrFail(
239 TrafficTreatment treatment,
240 L2ModificationInstruction.L2SubType subType, PiTableId tableId)
241 throws PiInterpreterException {
242 final Instruction inst = l2Instruction(treatment, subType);
243 if (inst == null) {
244 treatmentException(tableId, treatment, format("missing %s instruction", subType));
245 }
246 return inst;
247 }
248
249 private static Instruction instructionOrFail(
250 TrafficTreatment treatment, Instruction.Type type, PiTableId tableId)
251 throws PiInterpreterException {
252 final Instruction inst = instruction(treatment, type);
253 if (inst == null) {
254 treatmentException(tableId, treatment, format("missing %s instruction", type));
255 }
256 return inst;
257 }
258
259 private static void tableException(PiTableId tableId)
260 throws PiInterpreterException {
261 throw new PiInterpreterException(format("Table '%s' not supported", tableId));
262 }
263
264 private static void treatmentException(
265 PiTableId tableId, TrafficTreatment treatment, String explanation)
266 throws PiInterpreterException {
267 throw new PiInterpreterException(format(
268 "Invalid treatment for table '%s', %s: %s", tableId, explanation, treatment));
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800269 }
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700270}