blob: 00c4047cc743eb048aebd4bdb74abfece3c58623 [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;
36import org.onosproject.net.pi.runtime.PiAction;
37import org.onosproject.net.pi.runtime.PiActionParam;
Yi Tseng1b154bd2017-11-20 17:48:19 -080038import org.slf4j.Logger;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070039
40import java.util.List;
41
42import static java.lang.String.format;
43import static org.onosproject.net.flow.instructions.Instruction.Type.L2MODIFICATION;
44import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT;
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;
Yi Tseng1b154bd2017-11-20 17:48:19 -080047import static org.slf4j.LoggerFactory.getLogger;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070048
49
50final class FabricTreatmentInterpreter {
Yi Tseng1b154bd2017-11-20 17:48:19 -080051 private static final Logger log = getLogger(FabricTreatmentInterpreter.class);
Yi Tsengfa4a1c72017-11-03 10:22:38 -070052 private static final String INVALID_TREATMENT = "Invalid treatment for %s block: %s";
53
54 // Hide default constructor
55 protected FabricTreatmentInterpreter() {
56 }
57
58 /*
59 * In Filtering block, we need to implement these actions:
60 *
61 * push_internal_vlan
62 * set_vlan
63 * nop
64 *
65 * Unsupported, using PiAction directly:
66 * set_forwarding_type
67 */
68
69 static PiAction mapFilteringTreatment(TrafficTreatment treatment)
70 throws PiInterpreterException {
71 List<Instruction> instructions = treatment.allInstructions();
72 Instruction noActInst = Instructions.createNoAction();
73 if (instructions.isEmpty() || instructions.contains(noActInst)) {
74 // nop
75 return PiAction.builder()
76 .withId(FabricConstants.ACT_NOP_ID)
77 .build();
78 }
79
80 L2ModificationInstruction.ModVlanHeaderInstruction pushVlanInst = null;
81 ModVlanIdInstruction setVlanInst = null;
82
83 for (Instruction inst : instructions) {
84 if (inst.type() == L2MODIFICATION) {
85 L2ModificationInstruction l2Inst = (L2ModificationInstruction) inst;
86
87 if (l2Inst.subtype() == VLAN_PUSH) {
88 pushVlanInst = (L2ModificationInstruction.ModVlanHeaderInstruction) l2Inst;
89
90 } else if (l2Inst.subtype() == VLAN_ID) {
91 setVlanInst = (ModVlanIdInstruction) l2Inst;
92 }
93 }
94 }
95
96 if (setVlanInst == null) {
97 throw new PiInterpreterException(format(INVALID_TREATMENT, "filtering", treatment));
98 }
99
100 VlanId vlanId = setVlanInst.vlanId();
101 PiActionParam param = new PiActionParam(FabricConstants.ACT_PRM_NEW_VLAN_ID_ID,
102 ImmutableByteSequence.copyFrom(vlanId.toShort()));
103 PiActionId actionId;
104 if (pushVlanInst != null) {
105 // push_internal_vlan
Yi Tsengc6844f52017-12-19 11:58:25 -0800106 actionId = FabricConstants.ACT_FILTERING_PUSH_INTERNAL_VLAN_ID;
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700107 } else {
Yi Tsengc6844f52017-12-19 11:58:25 -0800108 actionId = FabricConstants.ACT_FILTERING_SET_VLAN_ID;
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700109 }
110
111 // set_vlan
112 return PiAction.builder()
113 .withId(actionId)
114 .withParameter(param)
115 .build();
116 }
117
118 /*
119 * In forwarding block, we need to implement these actions:
120 * duplicate_to_controller
121 *
122 * Unsupported, using PiAction directly:
123 * set_next_id
124 * push_mpls_and_next_v4
125 * push_mpls_and_next_v6
126 */
127
128 public static PiAction mapForwardingTreatment(TrafficTreatment treatment)
129 throws PiInterpreterException {
Yi Tsengdf3eec52018-02-15 14:56:02 -0800130 // Empty treatment, generate table entry with no action
131 if (treatment.equals(DefaultTrafficTreatment.emptyTreatment())) {
132 return null;
133 }
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700134 List<Instruction> insts = treatment.allInstructions();
135 OutputInstruction outInst = insts.stream()
136 .filter(inst -> inst.type() == OUTPUT)
137 .map(inst -> (OutputInstruction) inst)
138 .findFirst()
139 .orElse(null);
140
141 if (outInst == null) {
142 throw new PiInterpreterException(format(INVALID_TREATMENT, "forwarding", treatment));
143 }
144
145 PortNumber portNumber = outInst.port();
146 if (!portNumber.equals(PortNumber.CONTROLLER)) {
147 throw new PiInterpreterException(format("Unsupported port number %s," +
148 "supports punt action only",
149 portNumber));
150 }
151
152 return PiAction.builder()
Yi Tsengc6844f52017-12-19 11:58:25 -0800153 .withId(FabricConstants.ACT_FORWARDING_DUPLICATE_TO_CONTROLLER_ID)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700154 .build();
155 }
156
157 /*
158 * In Next block, we need to implement these actions:
159 * output
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700160 * set_vlan_output
Yi Tseng1b154bd2017-11-20 17:48:19 -0800161 * l3_routing
162 * mpls_routing_v4
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700163 *
164 * Unsupported, using PiAction directly:
Yi Tseng1b154bd2017-11-20 17:48:19 -0800165 * set_next_type
166 *
167 * Unsupported, need to find a way to implement it
168 * mpls_routing_v6
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700169 */
170
171 public static PiAction mapNextTreatment(TrafficTreatment treatment)
172 throws PiInterpreterException {
173 List<Instruction> insts = treatment.allInstructions();
174 OutputInstruction outInst = null;
175 ModEtherInstruction modEthDstInst = null;
176 ModEtherInstruction modEthSrcInst = null;
177 ModVlanIdInstruction modVlanIdInst = null;
Yi Tseng1b154bd2017-11-20 17:48:19 -0800178 ModMplsLabelInstruction modMplsInst = null;
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700179
Yi Tseng1b154bd2017-11-20 17:48:19 -0800180 // TODO: add NextFunctionType (like ForwardingFunctionType)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700181 for (Instruction inst : insts) {
182 switch (inst.type()) {
183 case L2MODIFICATION:
184 L2ModificationInstruction l2Inst = (L2ModificationInstruction) inst;
Yi Tseng1b154bd2017-11-20 17:48:19 -0800185 switch (l2Inst.subtype()) {
186 case ETH_SRC:
187 modEthSrcInst = (ModEtherInstruction) l2Inst;
188 break;
189 case ETH_DST:
190 modEthDstInst = (ModEtherInstruction) l2Inst;
191 break;
192 case VLAN_ID:
193 modVlanIdInst = (ModVlanIdInstruction) l2Inst;
194 break;
195 case MPLS_LABEL:
196 modMplsInst = (ModMplsLabelInstruction) l2Inst;
197 break;
Yi Tseng4fd28432018-02-01 14:48:03 -0800198 case VLAN_PUSH:
199 break;
Yi Tseng1b154bd2017-11-20 17:48:19 -0800200 default:
201 log.warn("Unsupported l2 instruction sub type: {}", l2Inst.subtype());
202 break;
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700203 }
204 break;
205 case OUTPUT:
206 outInst = (OutputInstruction) inst;
207 break;
208 default:
Yi Tseng1b154bd2017-11-20 17:48:19 -0800209 log.warn("Unsupported instruction sub type: {}", inst.type());
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700210 break;
211 }
212 }
213
214 if (outInst == null) {
215 throw new PiInterpreterException(format(INVALID_TREATMENT, "next", treatment));
216 }
217 short portNum = (short) outInst.port().toLong();
218 PiActionParam portNumParam = new PiActionParam(FabricConstants.ACT_PRM_PORT_NUM_ID,
219 ImmutableByteSequence.copyFrom(portNum));
220 if (modEthDstInst == null && modEthSrcInst == null) {
221 if (modVlanIdInst != null) {
222 VlanId vlanId = modVlanIdInst.vlanId();
223 PiActionParam vlanParam =
224 new PiActionParam(FabricConstants.ACT_PRM_NEW_VLAN_ID_ID,
225 ImmutableByteSequence.copyFrom(vlanId.toShort()));
226 // set_vlan_output
227 return PiAction.builder()
Yi Tsengc6844f52017-12-19 11:58:25 -0800228 .withId(FabricConstants.ACT_NEXT_SET_VLAN_OUTPUT_ID)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700229 .withParameters(ImmutableList.of(portNumParam, vlanParam))
230 .build();
231 } else {
232 // output
233 return PiAction.builder()
Yi Tsengc6844f52017-12-19 11:58:25 -0800234 .withId(FabricConstants.ACT_NEXT_OUTPUT_ID)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700235 .withParameter(portNumParam)
236 .build();
237 }
238 }
239
240 if (modEthDstInst != null && modEthSrcInst != null) {
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700241 MacAddress srcMac = modEthSrcInst.mac();
242 MacAddress dstMac = modEthDstInst.mac();
243 PiActionParam srcMacParam = new PiActionParam(FabricConstants.ACT_PRM_SMAC_ID,
244 ImmutableByteSequence.copyFrom(srcMac.toBytes()));
245 PiActionParam dstMacParam = new PiActionParam(FabricConstants.ACT_PRM_DMAC_ID,
246 ImmutableByteSequence.copyFrom(dstMac.toBytes()));
Yi Tseng1b154bd2017-11-20 17:48:19 -0800247
248 if (modMplsInst != null) {
249 // MPLS routing
250 MplsLabel mplsLabel = modMplsInst.label();
251 try {
252 ImmutableByteSequence mplsValue =
Carmelo Cascone8a571af2018-04-06 23:17:04 -0700253 ImmutableByteSequence.copyFrom(mplsLabel.toInt()).fit(20);
Yi Tseng1b154bd2017-11-20 17:48:19 -0800254 PiActionParam mplsParam = new PiActionParam(FabricConstants.ACT_PRM_LABEL_ID, mplsValue);
255 return PiAction.builder()
256 // FIXME: fins a way to determine v4 or v6
Yi Tsengc6844f52017-12-19 11:58:25 -0800257 .withId(FabricConstants.ACT_NEXT_MPLS_ROUTING_V4_ID)
Yi Tseng1b154bd2017-11-20 17:48:19 -0800258 .withParameters(ImmutableList.of(portNumParam,
259 srcMacParam,
260 dstMacParam,
261 mplsParam))
262 .build();
263 } catch (ImmutableByteSequence.ByteSequenceTrimException e) {
264 // Basically this won't happened because we already limited
265 // size of mpls value to 20 bits (0xFFFFF)
266 throw new PiInterpreterException(format(INVALID_TREATMENT, "next", treatment));
267 }
268 }
269
270 // L3 routing
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700271 return PiAction.builder()
Yi Tsengc6844f52017-12-19 11:58:25 -0800272 .withId(FabricConstants.ACT_NEXT_L3_ROUTING_ID)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700273 .withParameters(ImmutableList.of(portNumParam,
274 srcMacParam,
275 dstMacParam))
276 .build();
277 }
278
279 throw new PiInterpreterException(format(INVALID_TREATMENT, "next", treatment));
280 }
281}