blob: 67d7b3a7f92a130ce02431131a9d74f8f3fec5ce [file] [log] [blame]
Carmelo Casconeb5324e72018-11-25 02:26:32 -08001/*
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.pipeliner;
18
19import com.google.common.collect.Lists;
20import org.onlab.packet.Ethernet;
21import org.onlab.packet.MacAddress;
22import org.onlab.packet.VlanId;
23import org.onosproject.net.DeviceId;
24import org.onosproject.net.PortNumber;
25import org.onosproject.net.flow.DefaultTrafficSelector;
26import org.onosproject.net.flow.DefaultTrafficTreatment;
27import org.onosproject.net.flow.FlowRule;
28import org.onosproject.net.flow.TrafficSelector;
29import org.onosproject.net.flow.TrafficTreatment;
30import org.onosproject.net.flow.criteria.Criterion;
31import org.onosproject.net.flow.criteria.EthCriterion;
32import org.onosproject.net.flow.criteria.PiCriterion;
33import org.onosproject.net.flow.criteria.PortCriterion;
34import org.onosproject.net.flow.criteria.VlanIdCriterion;
35import org.onosproject.net.flowobjective.FilteringObjective;
36import org.onosproject.net.flowobjective.ObjectiveError;
37import org.onosproject.net.pi.runtime.PiAction;
38import org.onosproject.net.pi.runtime.PiActionParam;
39import org.onosproject.pipelines.fabric.FabricCapabilities;
40import org.onosproject.pipelines.fabric.FabricConstants;
41
42import java.util.Collection;
43import java.util.List;
44
45import static java.lang.String.format;
46import static org.onosproject.pipelines.fabric.FabricUtils.criterion;
47
48/**
49 * ObjectiveTranslator implementation for FilteringObjective.
50 */
51class FilteringObjectiveTranslator
52 extends AbstractObjectiveTranslator<FilteringObjective> {
53
54 // Forwarding types from fabric.p4.
55 static final byte FWD_MPLS = 1;
56 static final byte FWD_IPV4_ROUTING = 2;
57 static final byte FWD_IPV6_ROUTING = 3;
58
59 private static final byte[] ONE = new byte[]{1};
60 private static final byte[] ZERO = new byte[]{0};
61
62 private static final PiAction DENY = PiAction.builder()
63 .withId(FabricConstants.FABRIC_INGRESS_FILTERING_DENY)
64 .build();
65
66 private static final PiCriterion VLAN_VALID = PiCriterion.builder()
67 .matchExact(FabricConstants.HDR_VLAN_IS_VALID, ONE)
68 .build();
69 private static final PiCriterion VLAN_INVALID = PiCriterion.builder()
70 .matchExact(FabricConstants.HDR_VLAN_IS_VALID, ZERO)
71 .build();
72
73 FilteringObjectiveTranslator(DeviceId deviceId, FabricCapabilities capabilities) {
74 super(deviceId, capabilities);
75 }
76
77 @Override
78 public ObjectiveTranslation doTranslate(FilteringObjective obj)
79 throws FabricPipelinerException {
80
81 final ObjectiveTranslation.Builder resultBuilder =
82 ObjectiveTranslation.builder();
83
84 if (obj.key() == null || obj.key().type() != Criterion.Type.IN_PORT) {
85 throw new FabricPipelinerException(
86 format("Unsupported or missing filtering key: key=%s", obj.key()),
87 ObjectiveError.BADPARAMS);
88 }
89
90 final PortCriterion inPort = (PortCriterion) obj.key();
91 final VlanIdCriterion vlan = (VlanIdCriterion) criterion(
92 obj.conditions(), Criterion.Type.VLAN_VID);
93 final EthCriterion ethDst = (EthCriterion) criterion(
94 obj.conditions(), Criterion.Type.ETH_DST);
95 final EthCriterion ethDstMasked = (EthCriterion) criterion(
96 obj.conditions(), Criterion.Type.ETH_DST_MASKED);
97
98 ingressPortVlanRule(obj, inPort, vlan, resultBuilder);
99 fwdClassifierRules(obj, inPort, ethDst, ethDstMasked, resultBuilder);
100
101 return resultBuilder.build();
102 }
103
104 private void ingressPortVlanRule(
105 FilteringObjective obj,
106 Criterion inPortCriterion,
107 VlanIdCriterion vlanCriterion,
108 ObjectiveTranslation.Builder resultBuilder)
109 throws FabricPipelinerException {
110
111 final boolean vlanValid = vlanCriterion != null
112 && !vlanCriterion.vlanId().equals(VlanId.NONE);
113
114 final TrafficSelector.Builder selector = DefaultTrafficSelector.builder()
115 .add(inPortCriterion)
116 .add(vlanValid ? VLAN_VALID : VLAN_INVALID);
117 if (vlanValid) {
118 selector.add(vlanCriterion);
119 }
120
121 final TrafficTreatment treatment;
122 if (obj.type().equals(FilteringObjective.Type.DENY)) {
123 treatment = DefaultTrafficTreatment.builder()
124 .piTableAction(DENY)
125 .build();
126 } else {
127 treatment = obj.meta() == null
128 ? DefaultTrafficTreatment.emptyTreatment() : obj.meta();
129 }
130
131 resultBuilder.addFlowRule(flowRule(
132 obj, FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN,
133 selector.build(), treatment));
134 }
135
136 private void fwdClassifierRules(
137 FilteringObjective obj,
138 PortCriterion inPortCriterion,
139 EthCriterion ethDstCriterion,
140 EthCriterion ethDstMaskedCriterion,
141 ObjectiveTranslation.Builder resultBuilder)
142 throws FabricPipelinerException {
143
144 final List<FlowRule> flowRules = Lists.newArrayList();
145
146 final PortNumber inPort = inPortCriterion.port();
147 if (ethDstCriterion == null) {
148 if (ethDstMaskedCriterion == null) {
149 // No match. Do bridging (default action).
150 return;
151 }
152 // Masked fwd classifier rule
153 final MacAddress dstMac = ethDstMaskedCriterion.mac();
154 final MacAddress dstMacMask = ethDstMaskedCriterion.mask();
155 flowRules.add(maskedFwdClassifierRule(inPort, dstMac, dstMacMask, obj));
156 } else {
157 final MacAddress dstMac = ethDstCriterion.mac();
158 flowRules.addAll(ipFwdClassifierRules(inPort, dstMac, obj));
159 flowRules.add(mplsFwdClassifierRule(inPort, dstMac, obj));
160 }
161
162 for (FlowRule f : flowRules) {
163 resultBuilder.addFlowRule(f);
164 }
165 }
166
167 private FlowRule maskedFwdClassifierRule(
168 PortNumber inPort, MacAddress dstMac, MacAddress dstMacMask,
169 FilteringObjective obj)
170 throws FabricPipelinerException {
171 final TrafficTreatment treatment;
172 final short ethType;
173 if (dstMac.equals(MacAddress.IPV4_MULTICAST)
174 && dstMacMask.equals(MacAddress.IPV4_MULTICAST_MASK)) {
175 treatment = fwdClassifierTreatment(FWD_IPV4_ROUTING);
176 ethType = Ethernet.TYPE_IPV4;
177 } else if (dstMac.equals(MacAddress.IPV6_MULTICAST)
178 && dstMacMask.equals(MacAddress.IPV6_MULTICAST_MASK)) {
179 treatment = fwdClassifierTreatment(FWD_IPV6_ROUTING);
180 ethType = Ethernet.TYPE_IPV6;
181 } else {
182 throw new FabricPipelinerException(format(
183 "Unsupported masked Ethernet address for fwd " +
184 "classifier rule (mac=%s, mask=%s)",
185 dstMac, dstMacMask));
186 }
187 return fwdClassifierRule(inPort, ethType, dstMac, dstMacMask, treatment, obj);
188 }
189
190 private Collection<FlowRule> ipFwdClassifierRules(
191 PortNumber inPort, MacAddress dstMac, FilteringObjective obj)
192 throws FabricPipelinerException {
193 final Collection<FlowRule> flowRules = Lists.newArrayList();
194 flowRules.add(fwdClassifierRule(
195 inPort, Ethernet.TYPE_IPV4, dstMac, null,
196 fwdClassifierTreatment(FWD_IPV4_ROUTING), obj));
197 flowRules.add(fwdClassifierRule(
198 inPort, Ethernet.TYPE_IPV6, dstMac, null,
199 fwdClassifierTreatment(FWD_IPV6_ROUTING), obj));
200 return flowRules;
201 }
202
203 private FlowRule mplsFwdClassifierRule(
204 PortNumber inPort, MacAddress dstMac, FilteringObjective obj)
205 throws FabricPipelinerException {
206 return fwdClassifierRule(
207 inPort, Ethernet.MPLS_UNICAST, dstMac, null,
208 fwdClassifierTreatment(FWD_MPLS), obj);
209 }
210
211 private FlowRule fwdClassifierRule(
212 PortNumber inPort, short ethType, MacAddress dstMac, MacAddress dstMacMask,
213 TrafficTreatment treatment, FilteringObjective obj)
214 throws FabricPipelinerException {
215 final TrafficSelector selector = DefaultTrafficSelector.builder()
216 .matchInPort(inPort)
217 .matchEthType(ethType)
218 .matchEthDstMasked(dstMac, dstMacMask == null
219 ? MacAddress.EXACT_MASK : dstMacMask)
220 .build();
221 return flowRule(
222 obj, FabricConstants.FABRIC_INGRESS_FILTERING_FWD_CLASSIFIER,
223 selector, treatment);
224 }
225
226 private TrafficTreatment fwdClassifierTreatment(byte fwdType) {
227 final PiActionParam param = new PiActionParam(FabricConstants.FWD_TYPE, fwdType);
228 final PiAction action = PiAction.builder()
229 .withId(FabricConstants.FABRIC_INGRESS_FILTERING_SET_FORWARDING_TYPE)
230 .withParameter(param)
231 .build();
232 return DefaultTrafficTreatment.builder()
233 .piTableAction(action)
234 .build();
235
236 }
237}