blob: 921b5f4136d7ffd81f4f44c02a9629b809885a05 [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;
45import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070046import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_ID;
47import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_PUSH;
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);
Yi Tsengfa4a1c72017-11-03 10:22:38 -070053 private static final String INVALID_TREATMENT = "Invalid treatment for %s block: %s";
Yi Tseng20f9e7b2018-05-24 23:27:39 +080054 private static final PiAction NOP = PiAction.builder()
Yi Tseng43ee7e82018-04-12 16:37:34 +080055 .withId(FabricConstants.NOP)
Yi Tseng20f9e7b2018-05-24 23:27:39 +080056 .build();
57
58 private static final PiAction POP_VLAN = PiAction.builder()
Yi Tseng43ee7e82018-04-12 16:37:34 +080059 .withId(FabricConstants.FABRIC_EGRESS_EGRESS_NEXT_POP_VLAN)
Yi Tseng20f9e7b2018-05-24 23:27:39 +080060 .build();
Yi Tsengfa4a1c72017-11-03 10:22:38 -070061
62 // Hide default constructor
63 protected FabricTreatmentInterpreter() {
64 }
65
66 /*
67 * In Filtering block, we need to implement these actions:
Yi Tsengfa4a1c72017-11-03 10:22:38 -070068 * push_internal_vlan
69 * set_vlan
70 * nop
71 *
72 * Unsupported, using PiAction directly:
73 * set_forwarding_type
Yi Tseng47eac892018-07-11 02:17:04 +080074 * drop
Yi Tsengfa4a1c72017-11-03 10:22:38 -070075 */
76
Yi Tseng47eac892018-07-11 02:17:04 +080077 static PiAction mapFilteringTreatment(TrafficTreatment treatment, PiTableId tableId)
Yi Tsengfa4a1c72017-11-03 10:22:38 -070078 throws PiInterpreterException {
79 List<Instruction> instructions = treatment.allInstructions();
80 Instruction noActInst = Instructions.createNoAction();
81 if (instructions.isEmpty() || instructions.contains(noActInst)) {
82 // nop
Yi Tseng20f9e7b2018-05-24 23:27:39 +080083 return NOP;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070084 }
85
86 L2ModificationInstruction.ModVlanHeaderInstruction pushVlanInst = null;
87 ModVlanIdInstruction setVlanInst = null;
88
89 for (Instruction inst : instructions) {
90 if (inst.type() == L2MODIFICATION) {
91 L2ModificationInstruction l2Inst = (L2ModificationInstruction) inst;
92
93 if (l2Inst.subtype() == VLAN_PUSH) {
94 pushVlanInst = (L2ModificationInstruction.ModVlanHeaderInstruction) l2Inst;
95
96 } else if (l2Inst.subtype() == VLAN_ID) {
97 setVlanInst = (ModVlanIdInstruction) l2Inst;
98 }
99 }
100 }
101
102 if (setVlanInst == null) {
103 throw new PiInterpreterException(format(INVALID_TREATMENT, "filtering", treatment));
104 }
105
106 VlanId vlanId = setVlanInst.vlanId();
Yi Tseng43ee7e82018-04-12 16:37:34 +0800107 PiActionParam param = new PiActionParam(FabricConstants.NEW_VLAN_ID,
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700108 ImmutableByteSequence.copyFrom(vlanId.toShort()));
109 PiActionId actionId;
110 if (pushVlanInst != null) {
111 // push_internal_vlan
Yi Tseng43ee7e82018-04-12 16:37:34 +0800112 actionId = FabricConstants.FABRIC_INGRESS_FILTERING_PUSH_INTERNAL_VLAN;
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700113 } else {
Yi Tseng43ee7e82018-04-12 16:37:34 +0800114 actionId = FabricConstants.FABRIC_INGRESS_FILTERING_SET_VLAN;
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700115 }
116
117 // set_vlan
118 return PiAction.builder()
119 .withId(actionId)
120 .withParameter(param)
121 .build();
122 }
123
124 /*
125 * In forwarding block, we need to implement these actions:
Yi Tseng47eac892018-07-11 02:17:04 +0800126 * send_to_controller
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700127 *
128 * Unsupported, using PiAction directly:
Yi Tseng47eac892018-07-11 02:17:04 +0800129 * set_next_id_bridging
130 * pop_mpls_and_next
131 * set_next_id_unicast_v4
132 * set_next_id_multicast_v4
133 * set_next_id_acl
134 * drop
135 * set_next_id_unicast_v6
136 * set_next_id_multicast_v6
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700137 */
138
Yi Tseng47eac892018-07-11 02:17:04 +0800139 public static PiAction mapForwardingTreatment(TrafficTreatment treatment, PiTableId tableId)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700140 throws PiInterpreterException {
Yi Tsengdf3eec52018-02-15 14:56:02 -0800141 // Empty treatment, generate table entry with no action
142 if (treatment.equals(DefaultTrafficTreatment.emptyTreatment())) {
143 return null;
144 }
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700145 List<Instruction> insts = treatment.allInstructions();
146 OutputInstruction outInst = insts.stream()
147 .filter(inst -> inst.type() == OUTPUT)
148 .map(inst -> (OutputInstruction) inst)
149 .findFirst()
150 .orElse(null);
151
152 if (outInst == null) {
153 throw new PiInterpreterException(format(INVALID_TREATMENT, "forwarding", treatment));
154 }
155
156 PortNumber portNumber = outInst.port();
157 if (!portNumber.equals(PortNumber.CONTROLLER)) {
158 throw new PiInterpreterException(format("Unsupported port number %s," +
159 "supports punt action only",
160 portNumber));
161 }
162
163 return PiAction.builder()
Yi Tseng47eac892018-07-11 02:17:04 +0800164 .withId(FabricConstants.FABRIC_INGRESS_FORWARDING_SEND_TO_CONTROLLER)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700165 .build();
166 }
167
168 /*
169 * In Next block, we need to implement these actions:
Yi Tseng47eac892018-07-11 02:17:04 +0800170 * set_vlan
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700171 * set_vlan_output
Yi Tseng47eac892018-07-11 02:17:04 +0800172 * output_simple
173 * output_hashed
174 * l3_routing_simple
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800175 * l3_routing_vlan
Yi Tseng47eac892018-07-11 02:17:04 +0800176 * l3_routing_hashed
177 * mpls_routing_v4_simple
178 * mpls_routing_v6_simple
179 * mpls_routing_v4_hashed
180 * mpls_routing_v6_hashed
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700181 *
Yi Tseng1b154bd2017-11-20 17:48:19 -0800182 * Unsupported, need to find a way to implement it
Yi Tseng47eac892018-07-11 02:17:04 +0800183 *
184 * set_mcast_group
185 *
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700186 */
187
Yi Tseng47eac892018-07-11 02:17:04 +0800188 public static PiAction mapNextTreatment(TrafficTreatment treatment, PiTableId tableId)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700189 throws PiInterpreterException {
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800190 // TODO: refactor this method
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700191 List<Instruction> insts = treatment.allInstructions();
192 OutputInstruction outInst = null;
193 ModEtherInstruction modEthDstInst = null;
194 ModEtherInstruction modEthSrcInst = null;
195 ModVlanIdInstruction modVlanIdInst = null;
Yi Tseng1b154bd2017-11-20 17:48:19 -0800196 ModMplsLabelInstruction modMplsInst = null;
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700197
Yi Tseng1b154bd2017-11-20 17:48:19 -0800198 // TODO: add NextFunctionType (like ForwardingFunctionType)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700199 for (Instruction inst : insts) {
200 switch (inst.type()) {
201 case L2MODIFICATION:
202 L2ModificationInstruction l2Inst = (L2ModificationInstruction) inst;
Yi Tseng1b154bd2017-11-20 17:48:19 -0800203 switch (l2Inst.subtype()) {
204 case ETH_SRC:
205 modEthSrcInst = (ModEtherInstruction) l2Inst;
206 break;
207 case ETH_DST:
208 modEthDstInst = (ModEtherInstruction) l2Inst;
209 break;
210 case VLAN_ID:
211 modVlanIdInst = (ModVlanIdInstruction) l2Inst;
212 break;
213 case MPLS_LABEL:
214 modMplsInst = (ModMplsLabelInstruction) l2Inst;
215 break;
216 default:
217 log.warn("Unsupported l2 instruction sub type: {}", l2Inst.subtype());
218 break;
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700219 }
220 break;
221 case OUTPUT:
222 outInst = (OutputInstruction) inst;
223 break;
224 default:
Yi Tseng1b154bd2017-11-20 17:48:19 -0800225 log.warn("Unsupported instruction sub type: {}", inst.type());
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700226 break;
227 }
228 }
229
Yi Tseng47eac892018-07-11 02:17:04 +0800230 if (tableId.equals(FabricConstants.FABRIC_INGRESS_NEXT_VLAN_META) &&
231 modVlanIdInst != null) {
232 // set_vlan
233 VlanId vlanId = modVlanIdInst.vlanId();
234 PiActionParam newVlanParam =
235 new PiActionParam(FabricConstants.NEW_VLAN_ID,
236 ImmutableByteSequence.copyFrom(vlanId.toShort()));
237 return PiAction.builder()
238 .withId(FabricConstants.FABRIC_INGRESS_NEXT_SET_VLAN)
239 .withParameter(newVlanParam)
240 .build();
241 }
242
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700243 if (outInst == null) {
Yi Tseng47eac892018-07-11 02:17:04 +0800244 throw new PiInterpreterException(format(INVALID_TREATMENT, "next", treatment));
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700245 }
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800246
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700247 short portNum = (short) outInst.port().toLong();
Yi Tseng43ee7e82018-04-12 16:37:34 +0800248 PiActionParam portNumParam = new PiActionParam(FabricConstants.PORT_NUM,
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700249 ImmutableByteSequence.copyFrom(portNum));
250 if (modEthDstInst == null && modEthSrcInst == null) {
251 if (modVlanIdInst != null) {
252 VlanId vlanId = modVlanIdInst.vlanId();
253 PiActionParam vlanParam =
Yi Tseng43ee7e82018-04-12 16:37:34 +0800254 new PiActionParam(FabricConstants.NEW_VLAN_ID,
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700255 ImmutableByteSequence.copyFrom(vlanId.toShort()));
Yi Tseng47eac892018-07-11 02:17:04 +0800256 // set_vlan_output (simple table)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700257 return PiAction.builder()
Yi Tseng43ee7e82018-04-12 16:37:34 +0800258 .withId(FabricConstants.FABRIC_INGRESS_NEXT_SET_VLAN_OUTPUT)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700259 .withParameters(ImmutableList.of(portNumParam, vlanParam))
260 .build();
261 } else {
Yi Tseng47eac892018-07-11 02:17:04 +0800262 // output (simple or hashed table)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700263 return PiAction.builder()
Yi Tseng47eac892018-07-11 02:17:04 +0800264 .withId(FabricConstants.FABRIC_INGRESS_NEXT_OUTPUT_SIMPLE)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700265 .withParameter(portNumParam)
266 .build();
267 }
268 }
269
270 if (modEthDstInst != null && modEthSrcInst != null) {
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700271 MacAddress srcMac = modEthSrcInst.mac();
272 MacAddress dstMac = modEthDstInst.mac();
Yi Tseng43ee7e82018-04-12 16:37:34 +0800273 PiActionParam srcMacParam = new PiActionParam(FabricConstants.SMAC,
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700274 ImmutableByteSequence.copyFrom(srcMac.toBytes()));
Yi Tseng43ee7e82018-04-12 16:37:34 +0800275 PiActionParam dstMacParam = new PiActionParam(FabricConstants.DMAC,
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700276 ImmutableByteSequence.copyFrom(dstMac.toBytes()));
Yi Tseng1b154bd2017-11-20 17:48:19 -0800277
278 if (modMplsInst != null) {
279 // MPLS routing
280 MplsLabel mplsLabel = modMplsInst.label();
281 try {
282 ImmutableByteSequence mplsValue =
Carmelo Cascone8a571af2018-04-06 23:17:04 -0700283 ImmutableByteSequence.copyFrom(mplsLabel.toInt()).fit(20);
Yi Tseng43ee7e82018-04-12 16:37:34 +0800284 PiActionParam mplsParam = new PiActionParam(FabricConstants.LABEL, mplsValue);
Yi Tseng47eac892018-07-11 02:17:04 +0800285
286 PiActionId actionId;
287 // FIXME: finds a way to determine v4 or v6
288 if (tableId.equals(FabricConstants.FABRIC_INGRESS_NEXT_SIMPLE)) {
289 actionId = FabricConstants.FABRIC_INGRESS_NEXT_MPLS_ROUTING_V4_SIMPLE;
290 } else if (tableId.equals(FabricConstants.FABRIC_INGRESS_NEXT_HASHED)) {
291 actionId = FabricConstants.FABRIC_INGRESS_NEXT_MPLS_ROUTING_V4_HASHED;
292 } else {
293 throw new PiInterpreterException(format(INVALID_TREATMENT, "next", treatment));
294 }
295
Yi Tseng1b154bd2017-11-20 17:48:19 -0800296 return PiAction.builder()
Yi Tseng47eac892018-07-11 02:17:04 +0800297 .withId(actionId)
Yi Tseng1b154bd2017-11-20 17:48:19 -0800298 .withParameters(ImmutableList.of(portNumParam,
299 srcMacParam,
300 dstMacParam,
301 mplsParam))
302 .build();
303 } catch (ImmutableByteSequence.ByteSequenceTrimException e) {
304 // Basically this won't happened because we already limited
305 // size of mpls value to 20 bits (0xFFFFF)
306 throw new PiInterpreterException(format(INVALID_TREATMENT, "next", treatment));
307 }
308 }
309
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800310 if (modVlanIdInst != null) {
311 VlanId vlanId = modVlanIdInst.vlanId();
312 PiActionParam vlanParam =
Yi Tseng43ee7e82018-04-12 16:37:34 +0800313 new PiActionParam(FabricConstants.NEW_VLAN_ID,
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800314 ImmutableByteSequence.copyFrom(vlanId.toShort()));
315 // L3 routing and set VLAN
316 return PiAction.builder()
Yi Tseng43ee7e82018-04-12 16:37:34 +0800317 .withId(FabricConstants.FABRIC_INGRESS_NEXT_L3_ROUTING_VLAN)
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800318 .withParameters(ImmutableList.of(srcMacParam, dstMacParam, portNumParam, vlanParam))
319 .build();
320 } else {
Yi Tseng47eac892018-07-11 02:17:04 +0800321 PiActionId actionId;
322 if (tableId.equals(FabricConstants.FABRIC_INGRESS_NEXT_SIMPLE)) {
323 actionId = FabricConstants.FABRIC_INGRESS_NEXT_L3_ROUTING_SIMPLE;
324 } else if (tableId.equals(FabricConstants.FABRIC_INGRESS_NEXT_HASHED)) {
325 actionId = FabricConstants.FABRIC_INGRESS_NEXT_L3_ROUTING_HASHED;
326 } else {
327 throw new PiInterpreterException(format(INVALID_TREATMENT, "next", treatment));
328 }
329
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800330 // L3 routing
331 return PiAction.builder()
Yi Tseng47eac892018-07-11 02:17:04 +0800332 .withId(actionId)
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800333 .withParameters(ImmutableList.of(portNumParam,
334 srcMacParam,
335 dstMacParam))
336 .build();
337 }
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700338 }
339
340 throw new PiInterpreterException(format(INVALID_TREATMENT, "next", treatment));
341 }
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800342
Yi Tseng47eac892018-07-11 02:17:04 +0800343 /*
344 * pop_vlan
345 */
346 public static PiAction mapEgressNextTreatment(TrafficTreatment treatment, PiTableId tableId) {
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800347 // Pop VLAN action for now, may add new action to this control block in the future.
348 return treatment.allInstructions()
349 .stream()
350 .filter(inst -> inst.type() == Instruction.Type.L2MODIFICATION)
351 .map(inst -> (L2ModificationInstruction) inst)
352 .filter(inst -> inst.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP)
353 .findFirst()
354 .map(inst -> POP_VLAN)
355 .orElse(NOP);
356 }
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700357}