blob: 42481116037b852275dceba40c6492ebce5f5216 [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);
111 }
112 throw new PiInterpreterException(format(
113 "Treatment mapping not supported for table '%s'", tableId));
114 }
115
116 private static PiAction mapNextVlanTreatment(TrafficTreatment treatment, PiTableId tableId)
117 throws PiInterpreterException {
118 final ModVlanIdInstruction modVlanIdInst = (ModVlanIdInstruction)
119 l2InstructionOrFail(treatment, VLAN_ID, tableId);
120 return PiAction.builder()
121 .withId(FabricConstants.FABRIC_INGRESS_NEXT_SET_VLAN)
122 .withParameter(new PiActionParam(
123 FabricConstants.VLAN_ID,
124 modVlanIdInst.vlanId().toShort()))
125 .build();
126 }
127
128 private static PiAction mapNextHashedOrSimpleTreatment(
129 TrafficTreatment treatment, PiTableId tableId, boolean simple)
130 throws PiInterpreterException {
131 // Provide mapping for output_hashed, routing_hashed, and
132 // mpls_routing_hashed. multicast_hashed can only be invoked with
133 // PiAction, hence no mapping. outPort required for all actions. Presence
134 // of other instructions will determine which action to map to.
135 final PortNumber outPort = ((OutputInstruction) instructionOrFail(
136 treatment, OUTPUT, tableId)).port();
137 final ModEtherInstruction ethDst = (ModEtherInstruction) l2Instruction(
138 treatment, ETH_DST);
139 final ModEtherInstruction ethSrc = (ModEtherInstruction) l2Instruction(
140 treatment, ETH_SRC);
141 final Instruction mplsPush = l2Instruction(
142 treatment, MPLS_PUSH);
143 final ModMplsLabelInstruction mplsLabel = (ModMplsLabelInstruction) l2Instruction(
144 treatment, MPLS_LABEL);
145
146 final PiAction.Builder actionBuilder = PiAction.builder()
147 .withParameter(new PiActionParam(FabricConstants.PORT_NUM, outPort.toLong()));
148
149 if (ethDst != null && ethSrc != null) {
150 actionBuilder.withParameter(new PiActionParam(
151 FabricConstants.SMAC, ethSrc.mac().toBytes()));
152 actionBuilder.withParameter(new PiActionParam(
153 FabricConstants.DMAC, ethDst.mac().toBytes()));
154 if (mplsLabel != null) {
155 // mpls_routing_hashed
156 return actionBuilder
157 .withParameter(new PiActionParam(FabricConstants.LABEL, mplsLabel.label().toInt()))
158 .withId(simple ? FabricConstants.FABRIC_INGRESS_NEXT_MPLS_ROUTING_SIMPLE
159 : FabricConstants.FABRIC_INGRESS_NEXT_MPLS_ROUTING_HASHED)
160 .build();
161 } else {
162 // routing_hashed
163 return actionBuilder
164 .withId(simple ? FabricConstants.FABRIC_INGRESS_NEXT_ROUTING_SIMPLE
165 : FabricConstants.FABRIC_INGRESS_NEXT_ROUTING_HASHED)
166 .build();
167 }
168 } else {
169 // output_hashed
170 return actionBuilder
171 .withId(simple ? FabricConstants.FABRIC_INGRESS_NEXT_OUTPUT_SIMPLE
172 : FabricConstants.FABRIC_INGRESS_NEXT_OUTPUT_HASHED)
173 .build();
174 }
175 }
176
177 static PiAction mapAclTreatment(TrafficTreatment treatment, PiTableId tableId)
178 throws PiInterpreterException {
179 if (isNoAction(treatment)) {
180 return nop(tableId);
181 }
182
183 final PortNumber outPort = outputPort(treatment);
Carmelo Cascone1e8843f2018-07-19 19:01:12 +0200184 if (outPort == null
185 || !outPort.equals(PortNumber.CONTROLLER)
186 || treatment.allInstructions().size() > 1) {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800187 treatmentException(
188 tableId, treatment,
189 "supports only punt/clone to CPU actions");
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700190 }
191
Carmelo Cascone1e8843f2018-07-19 19:01:12 +0200192 final PiActionId actionId = treatment.clearedDeferred()
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800193 ? FabricConstants.FABRIC_INGRESS_ACL_PUNT_TO_CPU
194 : FabricConstants.FABRIC_INGRESS_ACL_CLONE_TO_CPU;
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700195
196 return PiAction.builder()
Carmelo Cascone1e8843f2018-07-19 19:01:12 +0200197 .withId(actionId)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700198 .build();
199 }
200
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700201
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800202 static PiAction mapEgressNextTreatment(
203 TrafficTreatment treatment, PiTableId tableId)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700204 throws PiInterpreterException {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800205 l2InstructionOrFail(treatment, VLAN_POP, tableId);
206 return PiAction.builder()
207 .withId(FabricConstants.FABRIC_EGRESS_EGRESS_NEXT_POP_VLAN)
208 .build();
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700209
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700210 }
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800211
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800212 private static PiAction nop(PiTableId tableId) throws PiInterpreterException {
213 if (!NOP_ACTIONS.containsKey(tableId)) {
214 throw new PiInterpreterException(format("table '%s' doe not specify a nop action", tableId));
215 }
216 return PiAction.builder().withId(NOP_ACTIONS.get(tableId)).build();
217 }
218
219 private static boolean isNoAction(TrafficTreatment treatment) {
220 return treatment.equals(DefaultTrafficTreatment.emptyTreatment()) ||
221 treatment.allInstructions().isEmpty();
222 }
223
224 private static Instruction l2InstructionOrFail(
225 TrafficTreatment treatment,
226 L2ModificationInstruction.L2SubType subType, PiTableId tableId)
227 throws PiInterpreterException {
228 final Instruction inst = l2Instruction(treatment, subType);
229 if (inst == null) {
230 treatmentException(tableId, treatment, format("missing %s instruction", subType));
231 }
232 return inst;
233 }
234
235 private static Instruction instructionOrFail(
236 TrafficTreatment treatment, Instruction.Type type, PiTableId tableId)
237 throws PiInterpreterException {
238 final Instruction inst = instruction(treatment, type);
239 if (inst == null) {
240 treatmentException(tableId, treatment, format("missing %s instruction", type));
241 }
242 return inst;
243 }
244
245 private static void tableException(PiTableId tableId)
246 throws PiInterpreterException {
247 throw new PiInterpreterException(format("Table '%s' not supported", tableId));
248 }
249
250 private static void treatmentException(
251 PiTableId tableId, TrafficTreatment treatment, String explanation)
252 throws PiInterpreterException {
253 throw new PiInterpreterException(format(
254 "Invalid treatment for table '%s', %s: %s", tableId, explanation, treatment));
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800255 }
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700256}