blob: 7d6ad40ae5d2c8959924a65e62a9a0cf7017f81e [file] [log] [blame]
Yi Tseng0b809722017-11-03 10:23:26 -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.pipeliner;
18
Yi Tseng27b9bc02018-04-12 14:52:40 +080019import com.google.common.collect.Lists;
Yi Tseng0b809722017-11-03 10:23:26 -070020import org.onlab.packet.Ethernet;
21import org.onlab.packet.MacAddress;
22import org.onlab.packet.VlanId;
23import org.onlab.util.ImmutableByteSequence;
24import org.onosproject.net.DeviceId;
25import org.onosproject.net.PortNumber;
26import org.onosproject.net.flow.DefaultFlowRule;
27import org.onosproject.net.flow.DefaultTrafficSelector;
28import org.onosproject.net.flow.DefaultTrafficTreatment;
29import org.onosproject.net.flow.FlowRule;
30import org.onosproject.net.flow.TrafficSelector;
31import org.onosproject.net.flow.TrafficTreatment;
32import org.onosproject.net.flow.criteria.Criterion;
33import org.onosproject.net.flow.criteria.EthCriterion;
34import org.onosproject.net.flow.criteria.PiCriterion;
35import org.onosproject.net.flow.criteria.PortCriterion;
36import org.onosproject.net.flow.criteria.VlanIdCriterion;
37import org.onosproject.net.flowobjective.FilteringObjective;
38import org.onosproject.net.flowobjective.ObjectiveError;
39import org.onosproject.net.pi.runtime.PiAction;
40import org.onosproject.net.pi.runtime.PiActionParam;
41import org.onosproject.pipelines.fabric.FabricConstants;
42import org.slf4j.Logger;
43
44import java.util.Collection;
45
46import static org.slf4j.LoggerFactory.getLogger;
47
48/**
49 * Handling filtering objective for fabric pipeliner.
50 */
51public class FabricFilteringPipeliner {
52 private static final Logger log = getLogger(FabricFilteringPipeliner.class);
53 // Forwarding types
Charles Chan384aea22018-08-23 22:08:02 -070054 static final byte FWD_BRIDGING = 0;
55 static final byte FWD_MPLS = 1;
56 static final byte FWD_IPV4_ROUTING = 2;
57 static final byte FWD_IPV6_ROUTING = 3;
Yi Tseng0b809722017-11-03 10:23:26 -070058 private static final PiCriterion VLAN_VALID = PiCriterion.builder()
Yi Tseng43ee7e82018-04-12 16:37:34 +080059 .matchExact(FabricConstants.HDR_VLAN_TAG_IS_VALID, new byte[]{1})
Yi Tseng0b809722017-11-03 10:23:26 -070060 .build();
61 private static final PiCriterion VLAN_INVALID = PiCriterion.builder()
Yi Tseng43ee7e82018-04-12 16:37:34 +080062 .matchExact(FabricConstants.HDR_VLAN_TAG_IS_VALID, new byte[]{0})
Yi Tseng0b809722017-11-03 10:23:26 -070063 .build();
64
65 protected DeviceId deviceId;
66
67 public FabricFilteringPipeliner(DeviceId deviceId) {
68 this.deviceId = deviceId;
69 }
70
71 /**
72 * Translates filtering objective to flows and groups.
73 *
74 * @param filterObjective the filtering objective
75 * @return translation result, contains flows, groups or error it generated
76 */
77 public PipelinerTranslationResult filter(FilteringObjective filterObjective) {
78 PipelinerTranslationResult.Builder resultBuilder = PipelinerTranslationResult.builder();
79 // maps selector and treatment from filtering objective to filtering
80 // control block.
81
82 if (filterObjective.type() == FilteringObjective.Type.DENY) {
83 log.warn("Unsupported filtering objective type {}", filterObjective.type());
84 resultBuilder.setError(ObjectiveError.UNSUPPORTED);
85 return resultBuilder.build();
86 }
87
88 if (filterObjective.key() == null ||
89 filterObjective.key().type() != Criterion.Type.IN_PORT) {
90 log.warn("Unsupported filter key {}", filterObjective.key());
91 resultBuilder.setError(ObjectiveError.BADPARAMS);
92 return resultBuilder.build();
93 }
94 PortCriterion inPortCriterion = (PortCriterion) filterObjective.key();
95 VlanIdCriterion vlanCriterion = filterObjective.conditions().stream()
96 .filter(criterion -> criterion.type() == Criterion.Type.VLAN_VID)
97 .map(criterion -> (VlanIdCriterion) criterion)
98 .findFirst()
99 .orElse(null);
100 EthCriterion ethDstCriterion = filterObjective.conditions().stream()
101 .filter(criterion -> criterion.type() == Criterion.Type.ETH_DST)
102 .map(criterion -> (EthCriterion) criterion)
103 .findFirst()
104 .orElse(null);
Charles Chan384aea22018-08-23 22:08:02 -0700105 EthCriterion ethDstMaskedCriterion = filterObjective.conditions().stream()
106 .filter(criterion -> criterion.type() == Criterion.Type.ETH_DST_MASKED)
107 .map(criterion -> (EthCriterion) criterion)
108 .findFirst()
109 .orElse(null);
Yi Tseng0b809722017-11-03 10:23:26 -0700110
111 FlowRule inPortVlanTableRule = createInPortVlanTable(inPortCriterion, vlanCriterion,
112 filterObjective);
113 Collection<FlowRule> fwdClassifierRules = createFwdClassifierRules(inPortCriterion, ethDstCriterion,
Charles Chan384aea22018-08-23 22:08:02 -0700114 ethDstMaskedCriterion, filterObjective);
Yi Tseng0b809722017-11-03 10:23:26 -0700115
116 resultBuilder.addFlowRule(inPortVlanTableRule);
117 fwdClassifierRules.forEach(resultBuilder::addFlowRule);
118 return resultBuilder.build();
119 }
120
121 private FlowRule createInPortVlanTable(Criterion inPortCriterion,
122 VlanIdCriterion vlanCriterion,
123 FilteringObjective filterObjective) {
124 Criterion vlanIsVlalidCriterion;
125 TrafficSelector.Builder selector = DefaultTrafficSelector.builder()
126 .add(inPortCriterion);
127
128 VlanId vlanId = null;
129 if (vlanCriterion != null) {
130 vlanId = vlanCriterion.vlanId();
131 }
132
133 vlanIsVlalidCriterion = VLAN_VALID;
134 if (vlanId == null || vlanId.equals(VlanId.NONE)) {
135 // untag vlan, match in port only
136 vlanIsVlalidCriterion = VLAN_INVALID;
137 }
138
139 selector.add(vlanIsVlalidCriterion);
140
141 // TODO: check if this treatment is valid or not
142 TrafficTreatment treatment = filterObjective.meta();
143 if (treatment == null) {
144 treatment = DefaultTrafficTreatment.emptyTreatment();
145 }
146
147 return DefaultFlowRule.builder()
148 .fromApp(filterObjective.appId())
149 .withPriority(filterObjective.priority())
150 .withSelector(selector.build())
151 .withTreatment(treatment)
152 .withPriority(filterObjective.priority())
Yi Tseng43ee7e82018-04-12 16:37:34 +0800153 .forTable(FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN)
Yi Tseng0b809722017-11-03 10:23:26 -0700154 .forDevice(deviceId)
155 .makePermanent()
156 .build();
157 }
158
159 private Collection<FlowRule> createFwdClassifierRules(PortCriterion inPortCriterion,
160 EthCriterion ethDstCriterion,
Charles Chan384aea22018-08-23 22:08:02 -0700161 EthCriterion ethDstMaskedCriterion,
Yi Tseng0b809722017-11-03 10:23:26 -0700162 FilteringObjective filterObjective) {
Charles Chan384aea22018-08-23 22:08:02 -0700163 PortNumber port = inPortCriterion.port();
164
Yi Tseng27b9bc02018-04-12 14:52:40 +0800165 Collection<FlowRule> flowRules = Lists.newArrayList();
Yi Tseng0b809722017-11-03 10:23:26 -0700166 if (ethDstCriterion == null) {
Charles Chan384aea22018-08-23 22:08:02 -0700167 if (ethDstMaskedCriterion == null) {
168 // Bridging table, do nothing
169 return flowRules;
170 }
171 // Masked fwd classifier rule
172 MacAddress dstMac = ethDstMaskedCriterion.mac();
173 MacAddress dstMacMask = ethDstMaskedCriterion.mask();
174 FlowRule flow = createMaskedFwdClassifierRule(port, dstMac, dstMacMask, filterObjective);
175 if (flow != null) {
176 flowRules.add(flow);
177 }
Yi Tseng0b809722017-11-03 10:23:26 -0700178 return flowRules;
179 }
Yi Tseng0b809722017-11-03 10:23:26 -0700180 MacAddress dstMac = ethDstCriterion.mac();
Yi Tseng0b809722017-11-03 10:23:26 -0700181 flowRules.addAll(createIpFwdClassifierRules(port, dstMac, filterObjective));
182 flowRules.add(createMplsFwdClassifierRule(port, dstMac, filterObjective));
183 return flowRules;
184 }
185
Charles Chan384aea22018-08-23 22:08:02 -0700186 private FlowRule createMaskedFwdClassifierRule(PortNumber inPort, MacAddress dstMac, MacAddress dstMacMask,
187 FilteringObjective filterObjective) {
Yi Tseng0b809722017-11-03 10:23:26 -0700188 TrafficTreatment treatment;
189 short ethType;
Charles Chan384aea22018-08-23 22:08:02 -0700190 if (dstMac.equals(MacAddress.IPV4_MULTICAST) && dstMacMask.equals(MacAddress.IPV4_MULTICAST_MASK)) {
191 treatment = createFwdClassifierTreatment(FWD_IPV4_ROUTING);
Yi Tseng0b809722017-11-03 10:23:26 -0700192 ethType = Ethernet.TYPE_IPV4;
Charles Chan384aea22018-08-23 22:08:02 -0700193 } else if (dstMac.equals(MacAddress.IPV6_MULTICAST) && dstMacMask.equals(MacAddress.IPV6_MULTICAST_MASK)) {
194 treatment = createFwdClassifierTreatment(FWD_IPV6_ROUTING);
Yi Tseng0b809722017-11-03 10:23:26 -0700195 ethType = Ethernet.TYPE_IPV6;
Charles Chan384aea22018-08-23 22:08:02 -0700196 } else {
197 log.warn("Unsupported masked fwd classifier rule. mac={}. mask={}", dstMac, dstMacMask);
198 return null;
Yi Tseng0b809722017-11-03 10:23:26 -0700199 }
Charles Chan384aea22018-08-23 22:08:02 -0700200 return createFwdClassifierRule(inPort, ethType, dstMac, dstMacMask, treatment, filterObjective);
Yi Tseng0b809722017-11-03 10:23:26 -0700201 }
202
203 private Collection<FlowRule> createIpFwdClassifierRules(PortNumber inPort,
204 MacAddress dstMac,
205 FilteringObjective filterObjective) {
Yi Tseng27b9bc02018-04-12 14:52:40 +0800206 Collection<FlowRule> flowRules = Lists.newArrayList();
Yi Tseng0b809722017-11-03 10:23:26 -0700207 TrafficTreatment treatment;
Charles Chan384aea22018-08-23 22:08:02 -0700208 treatment = createFwdClassifierTreatment(FWD_IPV4_ROUTING);
209 flowRules.add(createFwdClassifierRule(inPort, Ethernet.TYPE_IPV4, dstMac, null, treatment, filterObjective));
210 treatment = createFwdClassifierTreatment(FWD_IPV6_ROUTING);
211 flowRules.add(createFwdClassifierRule(inPort, Ethernet.TYPE_IPV6, dstMac, null, treatment, filterObjective));
Yi Tseng0b809722017-11-03 10:23:26 -0700212 return flowRules;
213 }
214
215 private FlowRule createMplsFwdClassifierRule(PortNumber inPort,
216 MacAddress dstMac,
217 FilteringObjective filterObjective) {
218 TrafficTreatment treatment = createFwdClassifierTreatment(FWD_MPLS);
Charles Chan384aea22018-08-23 22:08:02 -0700219 return createFwdClassifierRule(inPort, Ethernet.MPLS_UNICAST, dstMac, null, treatment, filterObjective);
Yi Tseng0b809722017-11-03 10:23:26 -0700220 }
221
222 private FlowRule createFwdClassifierRule(PortNumber inPort,
223 short ethType,
224 MacAddress dstMac,
Charles Chan384aea22018-08-23 22:08:02 -0700225 MacAddress dstMacMask,
Yi Tseng0b809722017-11-03 10:23:26 -0700226 TrafficTreatment treatment,
227 FilteringObjective filterObjective) {
228 TrafficSelector.Builder selector = DefaultTrafficSelector.builder()
229 .matchInPort(inPort)
Yi Tseng0b809722017-11-03 10:23:26 -0700230 .matchEthType(ethType);
Charles Chan384aea22018-08-23 22:08:02 -0700231 if (dstMacMask != null) {
232 selector.matchEthDstMasked(dstMac, dstMacMask);
233 } else {
234 selector.matchEthDstMasked(dstMac, MacAddress.EXACT_MASK);
235 }
Yi Tseng0b809722017-11-03 10:23:26 -0700236
237 return DefaultFlowRule.builder()
238 .withSelector(selector.build())
239 .withTreatment(treatment)
240 .fromApp(filterObjective.appId())
241 .withPriority(filterObjective.priority())
242 .forDevice(deviceId)
243 .makePermanent()
Yi Tseng43ee7e82018-04-12 16:37:34 +0800244 .forTable(FabricConstants.FABRIC_INGRESS_FILTERING_FWD_CLASSIFIER)
Yi Tseng0b809722017-11-03 10:23:26 -0700245 .build();
246 }
247
248 private TrafficTreatment createFwdClassifierTreatment(byte fwdType) {
Yi Tseng43ee7e82018-04-12 16:37:34 +0800249 PiActionParam param = new PiActionParam(FabricConstants.FWD_TYPE,
Yi Tseng0b809722017-11-03 10:23:26 -0700250 ImmutableByteSequence.copyFrom(fwdType));
251 PiAction action = PiAction.builder()
Yi Tseng43ee7e82018-04-12 16:37:34 +0800252 .withId(FabricConstants.FABRIC_INGRESS_FILTERING_SET_FORWARDING_TYPE)
Yi Tseng0b809722017-11-03 10:23:26 -0700253 .withParameter(param)
254 .build();
255 return DefaultTrafficTreatment.builder()
256 .piTableAction(action)
257 .build();
258
259 }
260}