blob: d14aa1a610a933a102ece7f6ab4cd0bc4cedbbc8 [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
19import com.google.common.collect.ImmutableList;
20import org.onlab.packet.MacAddress;
Yi Tseng1b154bd2017-11-20 17:48:19 -080021import org.onlab.packet.MplsLabel;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070022import org.onlab.packet.VlanId;
23import org.onlab.util.ImmutableByteSequence;
24import org.onosproject.net.PortNumber;
Yi Tsengdf3eec52018-02-15 14:56:02 -080025import org.onosproject.net.flow.DefaultTrafficTreatment;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070026import org.onosproject.net.flow.TrafficTreatment;
27import org.onosproject.net.flow.instructions.Instruction;
28import org.onosproject.net.flow.instructions.Instructions;
29import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
30import org.onosproject.net.flow.instructions.L2ModificationInstruction;
31import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
Yi Tseng1b154bd2017-11-20 17:48:19 -080032import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070033import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
34import org.onosproject.net.pi.model.PiActionId;
35import org.onosproject.net.pi.model.PiPipelineInterpreter.PiInterpreterException;
Yi Tseng47eac892018-07-11 02:17:04 +080036import org.onosproject.net.pi.model.PiTableId;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070037import org.onosproject.net.pi.runtime.PiAction;
38import org.onosproject.net.pi.runtime.PiActionParam;
Yi Tseng1b154bd2017-11-20 17:48:19 -080039import org.slf4j.Logger;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070040
41import java.util.List;
42
43import static java.lang.String.format;
44import static org.onosproject.net.flow.instructions.Instruction.Type.L2MODIFICATION;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070045import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_ID;
46import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_PUSH;
Carmelo Cascone1e8843f2018-07-19 19:01:12 +020047import static org.onosproject.pipelines.fabric.FabricUtils.getOutputPort;
Yi Tseng1b154bd2017-11-20 17:48:19 -080048import static org.slf4j.LoggerFactory.getLogger;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070049
50
51final class FabricTreatmentInterpreter {
Yi Tseng1b154bd2017-11-20 17:48:19 -080052 private static final Logger log = getLogger(FabricTreatmentInterpreter.class);
Carmelo Cascone1e8843f2018-07-19 19:01:12 +020053 private static final String INVALID_TREATMENT = "Invalid treatment for %s block [%s]";
54 private static final String INVALID_TREATMENT_WITH_EXP = "Invalid treatment for %s block: %s [%s]";
Charles Chancf696e52018-08-16 16:25:13 -070055 private static final PiAction NOP = PiAction.builder().withId(FabricConstants.NOP).build();
Carmelo Cascone8a715f82018-08-20 23:16:27 -070056 private static final PiAction NOP_INGRESS_PORT_VLAN = PiAction.builder()
57 .withId(FabricConstants.FABRIC_INGRESS_FILTERING_NOP_INGRESS_PORT_VLAN).build();
Charles Chancf696e52018-08-16 16:25:13 -070058 private static final PiAction NOP_ACL = PiAction.builder()
59 .withId(FabricConstants.FABRIC_INGRESS_FORWARDING_NOP_ACL).build();
Yi Tseng20f9e7b2018-05-24 23:27:39 +080060
61 private static final PiAction POP_VLAN = PiAction.builder()
Yi Tseng43ee7e82018-04-12 16:37:34 +080062 .withId(FabricConstants.FABRIC_EGRESS_EGRESS_NEXT_POP_VLAN)
Yi Tseng20f9e7b2018-05-24 23:27:39 +080063 .build();
Yi Tsengfa4a1c72017-11-03 10:22:38 -070064
65 // Hide default constructor
66 protected FabricTreatmentInterpreter() {
67 }
68
69 /*
70 * In Filtering block, we need to implement these actions:
Yi Tsengfa4a1c72017-11-03 10:22:38 -070071 * push_internal_vlan
72 * set_vlan
73 * nop
74 *
75 * Unsupported, using PiAction directly:
76 * set_forwarding_type
Yi Tseng47eac892018-07-11 02:17:04 +080077 * drop
Yi Tsengfa4a1c72017-11-03 10:22:38 -070078 */
79
Yi Tseng47eac892018-07-11 02:17:04 +080080 static PiAction mapFilteringTreatment(TrafficTreatment treatment, PiTableId tableId)
Yi Tsengfa4a1c72017-11-03 10:22:38 -070081 throws PiInterpreterException {
82 List<Instruction> instructions = treatment.allInstructions();
83 Instruction noActInst = Instructions.createNoAction();
84 if (instructions.isEmpty() || instructions.contains(noActInst)) {
85 // nop
Carmelo Cascone8a715f82018-08-20 23:16:27 -070086 return NOP_INGRESS_PORT_VLAN;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070087 }
88
89 L2ModificationInstruction.ModVlanHeaderInstruction pushVlanInst = null;
90 ModVlanIdInstruction setVlanInst = null;
91
92 for (Instruction inst : instructions) {
93 if (inst.type() == L2MODIFICATION) {
94 L2ModificationInstruction l2Inst = (L2ModificationInstruction) inst;
95
96 if (l2Inst.subtype() == VLAN_PUSH) {
97 pushVlanInst = (L2ModificationInstruction.ModVlanHeaderInstruction) l2Inst;
98
99 } else if (l2Inst.subtype() == VLAN_ID) {
100 setVlanInst = (ModVlanIdInstruction) l2Inst;
101 }
102 }
103 }
104
105 if (setVlanInst == null) {
106 throw new PiInterpreterException(format(INVALID_TREATMENT, "filtering", treatment));
107 }
108
109 VlanId vlanId = setVlanInst.vlanId();
Yi Tseng43ee7e82018-04-12 16:37:34 +0800110 PiActionParam param = new PiActionParam(FabricConstants.NEW_VLAN_ID,
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700111 ImmutableByteSequence.copyFrom(vlanId.toShort()));
112 PiActionId actionId;
113 if (pushVlanInst != null) {
114 // push_internal_vlan
Yi Tseng43ee7e82018-04-12 16:37:34 +0800115 actionId = FabricConstants.FABRIC_INGRESS_FILTERING_PUSH_INTERNAL_VLAN;
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700116 } else {
Yi Tseng43ee7e82018-04-12 16:37:34 +0800117 actionId = FabricConstants.FABRIC_INGRESS_FILTERING_SET_VLAN;
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700118 }
119
120 // set_vlan
121 return PiAction.builder()
122 .withId(actionId)
123 .withParameter(param)
124 .build();
125 }
126
127 /*
128 * In forwarding block, we need to implement these actions:
Yi Tseng47eac892018-07-11 02:17:04 +0800129 * send_to_controller
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700130 *
131 * Unsupported, using PiAction directly:
Yi Tseng47eac892018-07-11 02:17:04 +0800132 * set_next_id_bridging
133 * pop_mpls_and_next
134 * set_next_id_unicast_v4
135 * set_next_id_multicast_v4
136 * set_next_id_acl
137 * drop
138 * set_next_id_unicast_v6
139 * set_next_id_multicast_v6
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700140 */
141
Yi Tseng47eac892018-07-11 02:17:04 +0800142 public static PiAction mapForwardingTreatment(TrafficTreatment treatment, PiTableId tableId)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700143 throws PiInterpreterException {
Yi Tsengdf3eec52018-02-15 14:56:02 -0800144 // Empty treatment, generate table entry with no action
145 if (treatment.equals(DefaultTrafficTreatment.emptyTreatment())) {
Charles Chancf696e52018-08-16 16:25:13 -0700146 if (tableId.equals(FabricConstants.FABRIC_INGRESS_FORWARDING_ACL)) {
147 return NOP_ACL;
148 } else {
149 return NOP;
150 }
Yi Tsengdf3eec52018-02-15 14:56:02 -0800151 }
Carmelo Cascone1e8843f2018-07-19 19:01:12 +0200152 PortNumber outPort = getOutputPort(treatment);
153 if (outPort == null
154 || !outPort.equals(PortNumber.CONTROLLER)
155 || treatment.allInstructions().size() > 1) {
156 throw new PiInterpreterException(
157 format(INVALID_TREATMENT_WITH_EXP,
158 "forwarding", "supports only punt/clone to CPU actions",
159 treatment));
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700160 }
161
Carmelo Cascone1e8843f2018-07-19 19:01:12 +0200162 final PiActionId actionId = treatment.clearedDeferred()
163 ? FabricConstants.FABRIC_INGRESS_FORWARDING_PUNT_TO_CPU
164 : FabricConstants.FABRIC_INGRESS_FORWARDING_CLONE_TO_CPU;
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700165
166 return PiAction.builder()
Carmelo Cascone1e8843f2018-07-19 19:01:12 +0200167 .withId(actionId)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700168 .build();
169 }
170
171 /*
172 * In Next block, we need to implement these actions:
Yi Tseng47eac892018-07-11 02:17:04 +0800173 * set_vlan
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700174 * set_vlan_output
Yi Tseng47eac892018-07-11 02:17:04 +0800175 * output_simple
176 * output_hashed
177 * l3_routing_simple
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800178 * l3_routing_vlan
Yi Tseng47eac892018-07-11 02:17:04 +0800179 * l3_routing_hashed
180 * mpls_routing_v4_simple
181 * mpls_routing_v6_simple
182 * mpls_routing_v4_hashed
183 * mpls_routing_v6_hashed
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700184 *
Yi Tseng1b154bd2017-11-20 17:48:19 -0800185 * Unsupported, need to find a way to implement it
Yi Tseng47eac892018-07-11 02:17:04 +0800186 *
187 * set_mcast_group
188 *
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700189 */
190
Yi Tseng47eac892018-07-11 02:17:04 +0800191 public static PiAction mapNextTreatment(TrafficTreatment treatment, PiTableId tableId)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700192 throws PiInterpreterException {
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800193 // TODO: refactor this method
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700194 List<Instruction> insts = treatment.allInstructions();
195 OutputInstruction outInst = null;
196 ModEtherInstruction modEthDstInst = null;
197 ModEtherInstruction modEthSrcInst = null;
198 ModVlanIdInstruction modVlanIdInst = null;
Yi Tseng1b154bd2017-11-20 17:48:19 -0800199 ModMplsLabelInstruction modMplsInst = null;
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700200
Yi Tseng1b154bd2017-11-20 17:48:19 -0800201 // TODO: add NextFunctionType (like ForwardingFunctionType)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700202 for (Instruction inst : insts) {
203 switch (inst.type()) {
204 case L2MODIFICATION:
205 L2ModificationInstruction l2Inst = (L2ModificationInstruction) inst;
Yi Tseng1b154bd2017-11-20 17:48:19 -0800206 switch (l2Inst.subtype()) {
207 case ETH_SRC:
208 modEthSrcInst = (ModEtherInstruction) l2Inst;
209 break;
210 case ETH_DST:
211 modEthDstInst = (ModEtherInstruction) l2Inst;
212 break;
213 case VLAN_ID:
214 modVlanIdInst = (ModVlanIdInstruction) l2Inst;
215 break;
216 case MPLS_LABEL:
217 modMplsInst = (ModMplsLabelInstruction) l2Inst;
218 break;
Charles Chan8da57792018-08-16 16:59:42 -0700219 case VLAN_POP:
220 // VLAN_POP will be handled by mapEgressNextTreatment()
221 break;
Yi Tseng1b154bd2017-11-20 17:48:19 -0800222 default:
Carmelo Cascone1e8843f2018-07-19 19:01:12 +0200223 log.warn("Unsupported l2 instruction sub type {} [table={}, {}]",
224 l2Inst.subtype(), tableId, treatment);
Yi Tseng1b154bd2017-11-20 17:48:19 -0800225 break;
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700226 }
227 break;
228 case OUTPUT:
229 outInst = (OutputInstruction) inst;
230 break;
231 default:
Carmelo Cascone1e8843f2018-07-19 19:01:12 +0200232 log.warn("Unsupported instruction sub type {} [table={}, {}]",
233 inst.type(), tableId, treatment);
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700234 break;
235 }
236 }
237
Yi Tseng47eac892018-07-11 02:17:04 +0800238 if (tableId.equals(FabricConstants.FABRIC_INGRESS_NEXT_VLAN_META) &&
239 modVlanIdInst != null) {
240 // set_vlan
241 VlanId vlanId = modVlanIdInst.vlanId();
242 PiActionParam newVlanParam =
243 new PiActionParam(FabricConstants.NEW_VLAN_ID,
244 ImmutableByteSequence.copyFrom(vlanId.toShort()));
245 return PiAction.builder()
246 .withId(FabricConstants.FABRIC_INGRESS_NEXT_SET_VLAN)
247 .withParameter(newVlanParam)
248 .build();
249 }
250
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700251 if (outInst == null) {
Yi Tseng47eac892018-07-11 02:17:04 +0800252 throw new PiInterpreterException(format(INVALID_TREATMENT, "next", treatment));
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700253 }
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800254
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700255 short portNum = (short) outInst.port().toLong();
Yi Tseng43ee7e82018-04-12 16:37:34 +0800256 PiActionParam portNumParam = new PiActionParam(FabricConstants.PORT_NUM,
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700257 ImmutableByteSequence.copyFrom(portNum));
258 if (modEthDstInst == null && modEthSrcInst == null) {
259 if (modVlanIdInst != null) {
260 VlanId vlanId = modVlanIdInst.vlanId();
261 PiActionParam vlanParam =
Yi Tseng43ee7e82018-04-12 16:37:34 +0800262 new PiActionParam(FabricConstants.NEW_VLAN_ID,
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700263 ImmutableByteSequence.copyFrom(vlanId.toShort()));
Yi Tseng47eac892018-07-11 02:17:04 +0800264 // set_vlan_output (simple table)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700265 return PiAction.builder()
Yi Tseng43ee7e82018-04-12 16:37:34 +0800266 .withId(FabricConstants.FABRIC_INGRESS_NEXT_SET_VLAN_OUTPUT)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700267 .withParameters(ImmutableList.of(portNumParam, vlanParam))
268 .build();
269 } else {
Yi Tseng47eac892018-07-11 02:17:04 +0800270 // output (simple or hashed table)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700271 return PiAction.builder()
Yi Tseng47eac892018-07-11 02:17:04 +0800272 .withId(FabricConstants.FABRIC_INGRESS_NEXT_OUTPUT_SIMPLE)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700273 .withParameter(portNumParam)
274 .build();
275 }
276 }
277
278 if (modEthDstInst != null && modEthSrcInst != null) {
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700279 MacAddress srcMac = modEthSrcInst.mac();
280 MacAddress dstMac = modEthDstInst.mac();
Yi Tseng43ee7e82018-04-12 16:37:34 +0800281 PiActionParam srcMacParam = new PiActionParam(FabricConstants.SMAC,
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700282 ImmutableByteSequence.copyFrom(srcMac.toBytes()));
Yi Tseng43ee7e82018-04-12 16:37:34 +0800283 PiActionParam dstMacParam = new PiActionParam(FabricConstants.DMAC,
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700284 ImmutableByteSequence.copyFrom(dstMac.toBytes()));
Yi Tseng1b154bd2017-11-20 17:48:19 -0800285
286 if (modMplsInst != null) {
287 // MPLS routing
288 MplsLabel mplsLabel = modMplsInst.label();
289 try {
290 ImmutableByteSequence mplsValue =
Carmelo Cascone8a571af2018-04-06 23:17:04 -0700291 ImmutableByteSequence.copyFrom(mplsLabel.toInt()).fit(20);
Yi Tseng43ee7e82018-04-12 16:37:34 +0800292 PiActionParam mplsParam = new PiActionParam(FabricConstants.LABEL, mplsValue);
Yi Tseng47eac892018-07-11 02:17:04 +0800293
294 PiActionId actionId;
295 // FIXME: finds a way to determine v4 or v6
296 if (tableId.equals(FabricConstants.FABRIC_INGRESS_NEXT_SIMPLE)) {
297 actionId = FabricConstants.FABRIC_INGRESS_NEXT_MPLS_ROUTING_V4_SIMPLE;
298 } else if (tableId.equals(FabricConstants.FABRIC_INGRESS_NEXT_HASHED)) {
299 actionId = FabricConstants.FABRIC_INGRESS_NEXT_MPLS_ROUTING_V4_HASHED;
300 } else {
301 throw new PiInterpreterException(format(INVALID_TREATMENT, "next", treatment));
302 }
303
Yi Tseng1b154bd2017-11-20 17:48:19 -0800304 return PiAction.builder()
Yi Tseng47eac892018-07-11 02:17:04 +0800305 .withId(actionId)
Yi Tseng1b154bd2017-11-20 17:48:19 -0800306 .withParameters(ImmutableList.of(portNumParam,
307 srcMacParam,
308 dstMacParam,
309 mplsParam))
310 .build();
311 } catch (ImmutableByteSequence.ByteSequenceTrimException e) {
312 // Basically this won't happened because we already limited
313 // size of mpls value to 20 bits (0xFFFFF)
314 throw new PiInterpreterException(format(INVALID_TREATMENT, "next", treatment));
315 }
316 }
317
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800318 if (modVlanIdInst != null) {
319 VlanId vlanId = modVlanIdInst.vlanId();
320 PiActionParam vlanParam =
Yi Tseng43ee7e82018-04-12 16:37:34 +0800321 new PiActionParam(FabricConstants.NEW_VLAN_ID,
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800322 ImmutableByteSequence.copyFrom(vlanId.toShort()));
323 // L3 routing and set VLAN
324 return PiAction.builder()
Yi Tseng43ee7e82018-04-12 16:37:34 +0800325 .withId(FabricConstants.FABRIC_INGRESS_NEXT_L3_ROUTING_VLAN)
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800326 .withParameters(ImmutableList.of(srcMacParam, dstMacParam, portNumParam, vlanParam))
327 .build();
328 } else {
Yi Tseng47eac892018-07-11 02:17:04 +0800329 PiActionId actionId;
330 if (tableId.equals(FabricConstants.FABRIC_INGRESS_NEXT_SIMPLE)) {
331 actionId = FabricConstants.FABRIC_INGRESS_NEXT_L3_ROUTING_SIMPLE;
332 } else if (tableId.equals(FabricConstants.FABRIC_INGRESS_NEXT_HASHED)) {
333 actionId = FabricConstants.FABRIC_INGRESS_NEXT_L3_ROUTING_HASHED;
334 } else {
335 throw new PiInterpreterException(format(INVALID_TREATMENT, "next", treatment));
336 }
337
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800338 // L3 routing
339 return PiAction.builder()
Yi Tseng47eac892018-07-11 02:17:04 +0800340 .withId(actionId)
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800341 .withParameters(ImmutableList.of(portNumParam,
342 srcMacParam,
343 dstMacParam))
344 .build();
345 }
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700346 }
347
348 throw new PiInterpreterException(format(INVALID_TREATMENT, "next", treatment));
349 }
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800350
Yi Tseng47eac892018-07-11 02:17:04 +0800351 /*
352 * pop_vlan
353 */
354 public static PiAction mapEgressNextTreatment(TrafficTreatment treatment, PiTableId tableId) {
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800355 // Pop VLAN action for now, may add new action to this control block in the future.
356 return treatment.allInstructions()
357 .stream()
358 .filter(inst -> inst.type() == Instruction.Type.L2MODIFICATION)
359 .map(inst -> (L2ModificationInstruction) inst)
360 .filter(inst -> inst.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP)
361 .findFirst()
362 .map(inst -> POP_VLAN)
363 .orElse(NOP);
364 }
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700365}