blob: b7ee4c5428782484b0b3bc4bc48fa393f92e828c [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;
Yi Tsengfa4a1c72017-11-03 10:22:38 -070045
Carmelo Casconeb5324e72018-11-25 02:26:32 -080046/**
47 * Treatment translation logic.
48 */
Yi Tsengfa4a1c72017-11-03 10:22:38 -070049final class FabricTreatmentInterpreter {
Yi Tseng20f9e7b2018-05-24 23:27:39 +080050
Carmelo Casconeb5324e72018-11-25 02:26:32 -080051 private static final ImmutableMap<PiTableId, PiActionId> NOP_ACTIONS =
52 ImmutableMap.<PiTableId, PiActionId>builder()
53 .put(FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN,
54 FabricConstants.FABRIC_INGRESS_FILTERING_PERMIT)
55 .put(FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V4,
56 FabricConstants.FABRIC_INGRESS_FORWARDING_NOP_ROUTING_V4)
57 .put(FabricConstants.FABRIC_INGRESS_ACL_ACL,
58 FabricConstants.FABRIC_INGRESS_ACL_NOP_ACL)
59 .put(FabricConstants.FABRIC_EGRESS_EGRESS_NEXT_EGRESS_VLAN,
60 FabricConstants.FABRIC_EGRESS_EGRESS_NEXT_POP_VLAN)
61 .build();
Yi Tsengfa4a1c72017-11-03 10:22:38 -070062
Carmelo Casconeb5324e72018-11-25 02:26:32 -080063 private FabricTreatmentInterpreter() {
64 // Hide default constructor
Yi Tsengfa4a1c72017-11-03 10:22:38 -070065 }
66
Yi Tseng47eac892018-07-11 02:17:04 +080067 static PiAction mapFilteringTreatment(TrafficTreatment treatment, PiTableId tableId)
Yi Tsengfa4a1c72017-11-03 10:22:38 -070068 throws PiInterpreterException {
Carmelo Casconeb5324e72018-11-25 02:26:32 -080069
70 if (!tableId.equals(FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN)) {
71 // Mapping for other tables of the filtering block must be handled
72 // in the pipeliner.
73 tableException(tableId);
Yi Tsengfa4a1c72017-11-03 10:22:38 -070074 }
75
Carmelo Casconeb5324e72018-11-25 02:26:32 -080076 if (isNoAction(treatment)) {
77 // Permit action if table is ingress_port_vlan;
78 return nop(tableId);
Yi Tsengfa4a1c72017-11-03 10:22:38 -070079 }
80
Carmelo Casconeb5324e72018-11-25 02:26:32 -080081 final ModVlanIdInstruction setVlanInst = (ModVlanIdInstruction) l2InstructionOrFail(
82 treatment, VLAN_ID, tableId);
Yi Tsengfa4a1c72017-11-03 10:22:38 -070083 return PiAction.builder()
Carmelo Casconeb5324e72018-11-25 02:26:32 -080084 .withId(FabricConstants.FABRIC_INGRESS_FILTERING_PERMIT_WITH_INTERNAL_VLAN)
85 .withParameter(new PiActionParam(
86 FabricConstants.VLAN_ID, setVlanInst.vlanId().toShort()))
Yi Tsengfa4a1c72017-11-03 10:22:38 -070087 .build();
88 }
89
Yi Tsengfa4a1c72017-11-03 10:22:38 -070090
Carmelo Casconeb5324e72018-11-25 02:26:32 -080091 static PiAction mapForwardingTreatment(TrafficTreatment treatment, PiTableId tableId)
Yi Tsengfa4a1c72017-11-03 10:22:38 -070092 throws PiInterpreterException {
Carmelo Casconeb5324e72018-11-25 02:26:32 -080093 if (isNoAction(treatment)) {
94 return nop(tableId);
Yi Tsengdf3eec52018-02-15 14:56:02 -080095 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -080096 treatmentException(
97 tableId, treatment,
98 "supports mapping only for empty/no-action treatments");
99 return null;
100 }
101
102 static PiAction mapNextTreatment(TrafficTreatment treatment, PiTableId tableId)
103 throws PiInterpreterException {
104 if (tableId == FabricConstants.FABRIC_INGRESS_NEXT_NEXT_VLAN) {
105 return mapNextVlanTreatment(treatment, tableId);
106 } else if (tableId == FabricConstants.FABRIC_INGRESS_NEXT_HASHED) {
107 return mapNextHashedOrSimpleTreatment(treatment, tableId, false);
108 } else if (tableId == FabricConstants.FABRIC_INGRESS_NEXT_SIMPLE) {
109 return mapNextHashedOrSimpleTreatment(treatment, tableId, true);
Carmelo Cascone45cc0862018-11-26 11:50:41 -0800110 } else if (tableId == FabricConstants.FABRIC_INGRESS_NEXT_XCONNECT) {
111 return mapNextXconnect(treatment, tableId);
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800112 }
113 throw new PiInterpreterException(format(
114 "Treatment mapping not supported for table '%s'", tableId));
115 }
116
117 private static PiAction mapNextVlanTreatment(TrafficTreatment treatment, PiTableId tableId)
118 throws PiInterpreterException {
119 final ModVlanIdInstruction modVlanIdInst = (ModVlanIdInstruction)
120 l2InstructionOrFail(treatment, VLAN_ID, tableId);
121 return PiAction.builder()
122 .withId(FabricConstants.FABRIC_INGRESS_NEXT_SET_VLAN)
123 .withParameter(new PiActionParam(
124 FabricConstants.VLAN_ID,
125 modVlanIdInst.vlanId().toShort()))
126 .build();
127 }
128
129 private static PiAction mapNextHashedOrSimpleTreatment(
130 TrafficTreatment treatment, PiTableId tableId, boolean simple)
131 throws PiInterpreterException {
132 // Provide mapping for output_hashed, routing_hashed, and
133 // mpls_routing_hashed. multicast_hashed can only be invoked with
134 // PiAction, hence no mapping. outPort required for all actions. Presence
135 // of other instructions will determine which action to map to.
136 final PortNumber outPort = ((OutputInstruction) instructionOrFail(
137 treatment, OUTPUT, tableId)).port();
138 final ModEtherInstruction ethDst = (ModEtherInstruction) l2Instruction(
139 treatment, ETH_DST);
140 final ModEtherInstruction ethSrc = (ModEtherInstruction) l2Instruction(
141 treatment, ETH_SRC);
142 final Instruction mplsPush = l2Instruction(
143 treatment, MPLS_PUSH);
144 final ModMplsLabelInstruction mplsLabel = (ModMplsLabelInstruction) l2Instruction(
145 treatment, MPLS_LABEL);
146
147 final PiAction.Builder actionBuilder = PiAction.builder()
148 .withParameter(new PiActionParam(FabricConstants.PORT_NUM, outPort.toLong()));
149
150 if (ethDst != null && ethSrc != null) {
151 actionBuilder.withParameter(new PiActionParam(
152 FabricConstants.SMAC, ethSrc.mac().toBytes()));
153 actionBuilder.withParameter(new PiActionParam(
154 FabricConstants.DMAC, ethDst.mac().toBytes()));
155 if (mplsLabel != null) {
156 // mpls_routing_hashed
157 return actionBuilder
158 .withParameter(new PiActionParam(FabricConstants.LABEL, mplsLabel.label().toInt()))
159 .withId(simple ? FabricConstants.FABRIC_INGRESS_NEXT_MPLS_ROUTING_SIMPLE
160 : FabricConstants.FABRIC_INGRESS_NEXT_MPLS_ROUTING_HASHED)
161 .build();
162 } else {
163 // routing_hashed
164 return actionBuilder
165 .withId(simple ? FabricConstants.FABRIC_INGRESS_NEXT_ROUTING_SIMPLE
166 : FabricConstants.FABRIC_INGRESS_NEXT_ROUTING_HASHED)
167 .build();
168 }
169 } else {
170 // output_hashed
171 return actionBuilder
172 .withId(simple ? FabricConstants.FABRIC_INGRESS_NEXT_OUTPUT_SIMPLE
173 : FabricConstants.FABRIC_INGRESS_NEXT_OUTPUT_HASHED)
174 .build();
175 }
176 }
177
Carmelo Cascone45cc0862018-11-26 11:50:41 -0800178 private static PiAction mapNextXconnect(
179 TrafficTreatment treatment, PiTableId tableId)
180 throws PiInterpreterException {
181 final PortNumber outPort = ((OutputInstruction) instructionOrFail(
182 treatment, OUTPUT, tableId)).port();
183 return PiAction.builder()
184 .withId(FabricConstants.FABRIC_INGRESS_NEXT_OUTPUT_XCONNECT)
185 .withParameter(new PiActionParam(
186 FabricConstants.PORT_NUM, outPort.toLong()))
187 .build();
188 }
189
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800190 static PiAction mapAclTreatment(TrafficTreatment treatment, PiTableId tableId)
191 throws PiInterpreterException {
192 if (isNoAction(treatment)) {
193 return nop(tableId);
194 }
Daniele Moro01ca2ab2019-06-25 11:48:48 -0700195 treatmentException(
196 tableId, treatment,
197 "unsupported treatment");
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800198
Daniele Moro01ca2ab2019-06-25 11:48:48 -0700199 // This function will never return null
200 return null;
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700201 }
202
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700203
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800204 static PiAction mapEgressNextTreatment(
205 TrafficTreatment treatment, PiTableId tableId)
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700206 throws PiInterpreterException {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800207 l2InstructionOrFail(treatment, VLAN_POP, tableId);
208 return PiAction.builder()
209 .withId(FabricConstants.FABRIC_EGRESS_EGRESS_NEXT_POP_VLAN)
210 .build();
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700211
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700212 }
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800213
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800214 private static PiAction nop(PiTableId tableId) throws PiInterpreterException {
215 if (!NOP_ACTIONS.containsKey(tableId)) {
216 throw new PiInterpreterException(format("table '%s' doe not specify a nop action", tableId));
217 }
218 return PiAction.builder().withId(NOP_ACTIONS.get(tableId)).build();
219 }
220
221 private static boolean isNoAction(TrafficTreatment treatment) {
222 return treatment.equals(DefaultTrafficTreatment.emptyTreatment()) ||
223 treatment.allInstructions().isEmpty();
224 }
225
226 private static Instruction l2InstructionOrFail(
227 TrafficTreatment treatment,
228 L2ModificationInstruction.L2SubType subType, PiTableId tableId)
229 throws PiInterpreterException {
230 final Instruction inst = l2Instruction(treatment, subType);
231 if (inst == null) {
232 treatmentException(tableId, treatment, format("missing %s instruction", subType));
233 }
234 return inst;
235 }
236
237 private static Instruction instructionOrFail(
238 TrafficTreatment treatment, Instruction.Type type, PiTableId tableId)
239 throws PiInterpreterException {
240 final Instruction inst = instruction(treatment, type);
241 if (inst == null) {
242 treatmentException(tableId, treatment, format("missing %s instruction", type));
243 }
244 return inst;
245 }
246
247 private static void tableException(PiTableId tableId)
248 throws PiInterpreterException {
249 throw new PiInterpreterException(format("Table '%s' not supported", tableId));
250 }
251
252 private static void treatmentException(
253 PiTableId tableId, TrafficTreatment treatment, String explanation)
254 throws PiInterpreterException {
255 throw new PiInterpreterException(format(
256 "Invalid treatment for table '%s', %s: %s", tableId, explanation, treatment));
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800257 }
Yi Tsengfa4a1c72017-11-03 10:22:38 -0700258}