blob: badb38c202151a20627c6b20f021a9c8e90904f3 [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;
25import org.onosproject.net.flow.TrafficTreatment;
26import org.onosproject.net.flow.instructions.Instruction;
27import org.onosproject.net.flow.instructions.Instructions;
28import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
29import org.onosproject.net.flow.instructions.L2ModificationInstruction;
30import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
Yi Tseng1b154bd2017-11-20 17:48:19 -080031import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070032import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
33import org.onosproject.net.pi.model.PiActionId;
34import org.onosproject.net.pi.model.PiPipelineInterpreter.PiInterpreterException;
35import org.onosproject.net.pi.runtime.PiAction;
36import org.onosproject.net.pi.runtime.PiActionParam;
Yi Tseng1b154bd2017-11-20 17:48:19 -080037import org.slf4j.Logger;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070038
39import java.util.List;
40
41import static java.lang.String.format;
42import static org.onosproject.net.flow.instructions.Instruction.Type.L2MODIFICATION;
43import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070044import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_ID;
45import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_PUSH;
Yi Tseng1b154bd2017-11-20 17:48:19 -080046import static org.slf4j.LoggerFactory.getLogger;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070047
48
49final class FabricTreatmentInterpreter {
Yi Tseng1b154bd2017-11-20 17:48:19 -080050 private static final Logger log = getLogger(FabricTreatmentInterpreter.class);
Yi Tsengfa4a1c72017-11-03 10:22:38 -070051 private static final String INVALID_TREATMENT = "Invalid treatment for %s block: %s";
52
53 // Hide default constructor
54 protected FabricTreatmentInterpreter() {
55 }
56
57 /*
58 * In Filtering block, we need to implement these actions:
59 *
60 * push_internal_vlan
61 * set_vlan
62 * nop
63 *
64 * Unsupported, using PiAction directly:
65 * set_forwarding_type
66 */
67
68 static PiAction mapFilteringTreatment(TrafficTreatment treatment)
69 throws PiInterpreterException {
70 List<Instruction> instructions = treatment.allInstructions();
71 Instruction noActInst = Instructions.createNoAction();
72 if (instructions.isEmpty() || instructions.contains(noActInst)) {
73 // nop
74 return PiAction.builder()
75 .withId(FabricConstants.ACT_NOP_ID)
76 .build();
77 }
78
79 L2ModificationInstruction.ModVlanHeaderInstruction pushVlanInst = null;
80 ModVlanIdInstruction setVlanInst = null;
81
82 for (Instruction inst : instructions) {
83 if (inst.type() == L2MODIFICATION) {
84 L2ModificationInstruction l2Inst = (L2ModificationInstruction) inst;
85
86 if (l2Inst.subtype() == VLAN_PUSH) {
87 pushVlanInst = (L2ModificationInstruction.ModVlanHeaderInstruction) l2Inst;
88
89 } else if (l2Inst.subtype() == VLAN_ID) {
90 setVlanInst = (ModVlanIdInstruction) l2Inst;
91 }
92 }
93 }
94
95 if (setVlanInst == null) {
96 throw new PiInterpreterException(format(INVALID_TREATMENT, "filtering", treatment));
97 }
98
99 VlanId vlanId = setVlanInst.vlanId();
100 PiActionParam param = new PiActionParam(FabricConstants.ACT_PRM_NEW_VLAN_ID_ID,
101 ImmutableByteSequence.copyFrom(vlanId.toShort()));
102 PiActionId actionId;
103 if (pushVlanInst != null) {
104 // push_internal_vlan
Yi Tsengc6844f52017-12-19 11:58:25 -0800105 actionId = FabricConstants.ACT_FILTERING_PUSH_INTERNAL_VLAN_ID;
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700106 } else {
Yi Tsengc6844f52017-12-19 11:58:25 -0800107 actionId = FabricConstants.ACT_FILTERING_SET_VLAN_ID;
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700108 }
109
110 // set_vlan
111 return PiAction.builder()
112 .withId(actionId)
113 .withParameter(param)
114 .build();
115 }
116
117 /*
118 * In forwarding block, we need to implement these actions:
119 * duplicate_to_controller
120 *
121 * Unsupported, using PiAction directly:
122 * set_next_id
123 * push_mpls_and_next_v4
124 * push_mpls_and_next_v6
125 */
126
127 public static PiAction mapForwardingTreatment(TrafficTreatment treatment)
128 throws PiInterpreterException {
129 List<Instruction> insts = treatment.allInstructions();
130 OutputInstruction outInst = insts.stream()
131 .filter(inst -> inst.type() == OUTPUT)
132 .map(inst -> (OutputInstruction) inst)
133 .findFirst()
134 .orElse(null);
135
136 if (outInst == null) {
137 throw new PiInterpreterException(format(INVALID_TREATMENT, "forwarding", treatment));
138 }
139
140 PortNumber portNumber = outInst.port();
141 if (!portNumber.equals(PortNumber.CONTROLLER)) {
142 throw new PiInterpreterException(format("Unsupported port number %s," +
143 "supports punt action only",
144 portNumber));
145 }
146
147 return PiAction.builder()
Yi Tsengc6844f52017-12-19 11:58:25 -0800148 .withId(FabricConstants.ACT_FORWARDING_DUPLICATE_TO_CONTROLLER_ID)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700149 .build();
150 }
151
152 /*
153 * In Next block, we need to implement these actions:
154 * output
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700155 * set_vlan_output
Yi Tseng1b154bd2017-11-20 17:48:19 -0800156 * l3_routing
157 * mpls_routing_v4
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700158 *
159 * Unsupported, using PiAction directly:
Yi Tseng1b154bd2017-11-20 17:48:19 -0800160 * set_next_type
161 *
162 * Unsupported, need to find a way to implement it
163 * mpls_routing_v6
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700164 */
165
166 public static PiAction mapNextTreatment(TrafficTreatment treatment)
167 throws PiInterpreterException {
168 List<Instruction> insts = treatment.allInstructions();
169 OutputInstruction outInst = null;
170 ModEtherInstruction modEthDstInst = null;
171 ModEtherInstruction modEthSrcInst = null;
172 ModVlanIdInstruction modVlanIdInst = null;
Yi Tseng1b154bd2017-11-20 17:48:19 -0800173 ModMplsLabelInstruction modMplsInst = null;
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700174
Yi Tseng1b154bd2017-11-20 17:48:19 -0800175 // TODO: add NextFunctionType (like ForwardingFunctionType)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700176 for (Instruction inst : insts) {
177 switch (inst.type()) {
178 case L2MODIFICATION:
179 L2ModificationInstruction l2Inst = (L2ModificationInstruction) inst;
Yi Tseng1b154bd2017-11-20 17:48:19 -0800180 switch (l2Inst.subtype()) {
181 case ETH_SRC:
182 modEthSrcInst = (ModEtherInstruction) l2Inst;
183 break;
184 case ETH_DST:
185 modEthDstInst = (ModEtherInstruction) l2Inst;
186 break;
187 case VLAN_ID:
188 modVlanIdInst = (ModVlanIdInstruction) l2Inst;
189 break;
190 case MPLS_LABEL:
191 modMplsInst = (ModMplsLabelInstruction) l2Inst;
192 break;
Yi Tseng4fd28432018-02-01 14:48:03 -0800193 case VLAN_PUSH:
194 break;
Yi Tseng1b154bd2017-11-20 17:48:19 -0800195 default:
196 log.warn("Unsupported l2 instruction sub type: {}", l2Inst.subtype());
197 break;
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700198 }
199 break;
200 case OUTPUT:
201 outInst = (OutputInstruction) inst;
202 break;
203 default:
Yi Tseng1b154bd2017-11-20 17:48:19 -0800204 log.warn("Unsupported instruction sub type: {}", inst.type());
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700205 break;
206 }
207 }
208
209 if (outInst == null) {
210 throw new PiInterpreterException(format(INVALID_TREATMENT, "next", treatment));
211 }
212 short portNum = (short) outInst.port().toLong();
213 PiActionParam portNumParam = new PiActionParam(FabricConstants.ACT_PRM_PORT_NUM_ID,
214 ImmutableByteSequence.copyFrom(portNum));
215 if (modEthDstInst == null && modEthSrcInst == null) {
216 if (modVlanIdInst != null) {
217 VlanId vlanId = modVlanIdInst.vlanId();
218 PiActionParam vlanParam =
219 new PiActionParam(FabricConstants.ACT_PRM_NEW_VLAN_ID_ID,
220 ImmutableByteSequence.copyFrom(vlanId.toShort()));
221 // set_vlan_output
222 return PiAction.builder()
Yi Tsengc6844f52017-12-19 11:58:25 -0800223 .withId(FabricConstants.ACT_NEXT_SET_VLAN_OUTPUT_ID)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700224 .withParameters(ImmutableList.of(portNumParam, vlanParam))
225 .build();
226 } else {
227 // output
228 return PiAction.builder()
Yi Tsengc6844f52017-12-19 11:58:25 -0800229 .withId(FabricConstants.ACT_NEXT_OUTPUT_ID)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700230 .withParameter(portNumParam)
231 .build();
232 }
233 }
234
235 if (modEthDstInst != null && modEthSrcInst != null) {
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700236 MacAddress srcMac = modEthSrcInst.mac();
237 MacAddress dstMac = modEthDstInst.mac();
238 PiActionParam srcMacParam = new PiActionParam(FabricConstants.ACT_PRM_SMAC_ID,
239 ImmutableByteSequence.copyFrom(srcMac.toBytes()));
240 PiActionParam dstMacParam = new PiActionParam(FabricConstants.ACT_PRM_DMAC_ID,
241 ImmutableByteSequence.copyFrom(dstMac.toBytes()));
Yi Tseng1b154bd2017-11-20 17:48:19 -0800242
243 if (modMplsInst != null) {
244 // MPLS routing
245 MplsLabel mplsLabel = modMplsInst.label();
246 try {
247 ImmutableByteSequence mplsValue =
248 ImmutableByteSequence.fit(ImmutableByteSequence.copyFrom(mplsLabel.toInt()), 20);
249 PiActionParam mplsParam = new PiActionParam(FabricConstants.ACT_PRM_LABEL_ID, mplsValue);
250 return PiAction.builder()
251 // FIXME: fins a way to determine v4 or v6
Yi Tsengc6844f52017-12-19 11:58:25 -0800252 .withId(FabricConstants.ACT_NEXT_MPLS_ROUTING_V4_ID)
Yi Tseng1b154bd2017-11-20 17:48:19 -0800253 .withParameters(ImmutableList.of(portNumParam,
254 srcMacParam,
255 dstMacParam,
256 mplsParam))
257 .build();
258 } catch (ImmutableByteSequence.ByteSequenceTrimException e) {
259 // Basically this won't happened because we already limited
260 // size of mpls value to 20 bits (0xFFFFF)
261 throw new PiInterpreterException(format(INVALID_TREATMENT, "next", treatment));
262 }
263 }
264
265 // L3 routing
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700266 return PiAction.builder()
Yi Tsengc6844f52017-12-19 11:58:25 -0800267 .withId(FabricConstants.ACT_NEXT_L3_ROUTING_ID)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700268 .withParameters(ImmutableList.of(portNumParam,
269 srcMacParam,
270 dstMacParam))
271 .build();
272 }
273
274 throw new PiInterpreterException(format(INVALID_TREATMENT, "next", treatment));
275 }
276}