blob: 4155f2772a0fd806f9c69e2e24cc5cf4310e7944 [file] [log] [blame]
alshabib0ccde6d2015-05-30 18:22:36 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
alshabib0ccde6d2015-05-30 18:22:36 -07003 *
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 */
16package org.onosproject.driver.pipeline;
17
alshabibd61b77b2016-02-01 23:30:53 -080018import com.google.common.cache.Cache;
19import com.google.common.cache.CacheBuilder;
20import com.google.common.cache.RemovalCause;
21import com.google.common.cache.RemovalNotification;
Gamze Abakadadae722018-09-12 10:55:35 +000022import com.google.common.collect.ImmutableList;
alshabibfd430b62015-12-16 18:56:38 -080023import com.google.common.collect.Lists;
24import org.apache.commons.lang3.tuple.ImmutablePair;
25import org.apache.commons.lang3.tuple.Pair;
alshabib0ccde6d2015-05-30 18:22:36 -070026import org.onlab.osgi.ServiceDirectory;
Jonathan Hartdfc3b862015-07-01 14:49:56 -070027import org.onlab.packet.EthType;
alshabibfd430b62015-12-16 18:56:38 -080028import org.onlab.packet.IPv4;
Matteo Scandolo9f4f0072018-11-02 16:09:39 -070029import org.onlab.packet.IPv6;
alshabibfd430b62015-12-16 18:56:38 -080030import org.onlab.packet.VlanId;
alshabibd61b77b2016-02-01 23:30:53 -080031import org.onlab.util.KryoNamespace;
Jonathan Hartdfc3b862015-07-01 14:49:56 -070032import org.onosproject.core.ApplicationId;
33import org.onosproject.core.CoreService;
alshabib0ccde6d2015-05-30 18:22:36 -070034import org.onosproject.net.DeviceId;
35import org.onosproject.net.PortNumber;
alshabibd61b77b2016-02-01 23:30:53 -080036import org.onosproject.net.behaviour.NextGroup;
alshabib0ccde6d2015-05-30 18:22:36 -070037import org.onosproject.net.behaviour.Pipeliner;
38import org.onosproject.net.behaviour.PipelinerContext;
39import org.onosproject.net.driver.AbstractHandlerBehaviour;
40import org.onosproject.net.flow.DefaultFlowRule;
Jonathan Hartdfc3b862015-07-01 14:49:56 -070041import org.onosproject.net.flow.DefaultTrafficSelector;
alshabib0ccde6d2015-05-30 18:22:36 -070042import org.onosproject.net.flow.DefaultTrafficTreatment;
43import org.onosproject.net.flow.FlowRule;
44import org.onosproject.net.flow.FlowRuleOperations;
45import org.onosproject.net.flow.FlowRuleOperationsContext;
46import org.onosproject.net.flow.FlowRuleService;
47import org.onosproject.net.flow.TrafficSelector;
48import org.onosproject.net.flow.TrafficTreatment;
alshabibfd430b62015-12-16 18:56:38 -080049import org.onosproject.net.flow.criteria.Criteria;
50import org.onosproject.net.flow.criteria.Criterion;
51import org.onosproject.net.flow.criteria.EthTypeCriterion;
alshabib1aa58142016-02-17 15:37:56 -080052import org.onosproject.net.flow.criteria.IPCriterion;
alshabibfd430b62015-12-16 18:56:38 -080053import org.onosproject.net.flow.criteria.IPProtocolCriterion;
54import org.onosproject.net.flow.criteria.PortCriterion;
Amit Ghoshcbaf8672016-12-23 21:36:19 +000055import org.onosproject.net.flow.criteria.UdpPortCriterion;
alshabib2f74f2c2016-01-14 13:29:35 -080056import org.onosproject.net.flow.criteria.VlanIdCriterion;
alshabibfd430b62015-12-16 18:56:38 -080057import org.onosproject.net.flow.instructions.Instruction;
alshabib0ccde6d2015-05-30 18:22:36 -070058import org.onosproject.net.flow.instructions.Instructions;
alshabibfd430b62015-12-16 18:56:38 -080059import org.onosproject.net.flow.instructions.L2ModificationInstruction;
alshabib0ccde6d2015-05-30 18:22:36 -070060import org.onosproject.net.flowobjective.FilteringObjective;
alshabibd61b77b2016-02-01 23:30:53 -080061import org.onosproject.net.flowobjective.FlowObjectiveStore;
alshabib0ccde6d2015-05-30 18:22:36 -070062import org.onosproject.net.flowobjective.ForwardingObjective;
63import org.onosproject.net.flowobjective.NextObjective;
alshabibfd430b62015-12-16 18:56:38 -080064import org.onosproject.net.flowobjective.Objective;
alshabib0ccde6d2015-05-30 18:22:36 -070065import org.onosproject.net.flowobjective.ObjectiveError;
alshabibd61b77b2016-02-01 23:30:53 -080066import org.onosproject.net.group.DefaultGroupBucket;
67import org.onosproject.net.group.DefaultGroupDescription;
68import org.onosproject.net.group.DefaultGroupKey;
69import org.onosproject.net.group.Group;
70import org.onosproject.net.group.GroupBucket;
71import org.onosproject.net.group.GroupBuckets;
72import org.onosproject.net.group.GroupDescription;
73import org.onosproject.net.group.GroupEvent;
74import org.onosproject.net.group.GroupKey;
75import org.onosproject.net.group.GroupListener;
76import org.onosproject.net.group.GroupService;
77import org.onosproject.store.serializers.KryoNamespaces;
alshabib5ccbe3f2016-03-02 22:36:02 -080078import org.onosproject.store.service.StorageService;
alshabib0ccde6d2015-05-30 18:22:36 -070079import org.slf4j.Logger;
80
alshabibfd430b62015-12-16 18:56:38 -080081import java.util.Collection;
alshabibd61b77b2016-02-01 23:30:53 -080082import java.util.Collections;
alshabibfd430b62015-12-16 18:56:38 -080083import java.util.List;
84import java.util.Optional;
alshabibd61b77b2016-02-01 23:30:53 -080085import java.util.concurrent.TimeUnit;
alshabibfd430b62015-12-16 18:56:38 -080086import java.util.stream.Collectors;
Gamze Abakadadae722018-09-12 10:55:35 +000087import java.util.Arrays;
88import java.util.Objects;
alshabibfd430b62015-12-16 18:56:38 -080089
alshabib0ccde6d2015-05-30 18:22:36 -070090import static org.slf4j.LoggerFactory.getLogger;
91
92/**
Jonathan Hart64da69d2015-07-15 15:10:28 -070093 * Pipeliner for OLT device.
alshabib0ccde6d2015-05-30 18:22:36 -070094 */
alshabibfd430b62015-12-16 18:56:38 -080095
Jonathan Hartb92cc512015-11-16 23:05:21 -080096public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
alshabib0ccde6d2015-05-30 18:22:36 -070097
alshabibfd430b62015-12-16 18:56:38 -080098 private static final Integer QQ_TABLE = 1;
Gamze Abakadadae722018-09-12 10:55:35 +000099 private static final int NO_ACTION_PRIORITY = 500;
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000100 private static final String DOWNSTREAM = "downstream";
101 private static final String UPSTREAM = "upstream";
alshabib0ccde6d2015-05-30 18:22:36 -0700102 private final Logger log = getLogger(getClass());
103
104 private ServiceDirectory serviceDirectory;
105 private FlowRuleService flowRuleService;
alshabibd61b77b2016-02-01 23:30:53 -0800106 private GroupService groupService;
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700107 private CoreService coreService;
alshabib5ccbe3f2016-03-02 22:36:02 -0800108 private StorageService storageService;
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700109
alshabibd61b77b2016-02-01 23:30:53 -0800110 private DeviceId deviceId;
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700111 private ApplicationId appId;
alshabib83364472016-03-25 09:59:55 -0700112
alshabib0ccde6d2015-05-30 18:22:36 -0700113
alshabibd61b77b2016-02-01 23:30:53 -0800114 protected FlowObjectiveStore flowObjectiveStore;
115
116 private Cache<GroupKey, NextObjective> pendingGroups;
117
118 protected static KryoNamespace appKryo = new KryoNamespace.Builder()
119 .register(KryoNamespaces.API)
120 .register(GroupKey.class)
121 .register(DefaultGroupKey.class)
122 .register(OLTPipelineGroup.class)
Charles Chaneefdedf2016-05-23 16:45:45 -0700123 .build("OltPipeline");
alshabib2cc73cb2015-06-30 20:26:56 -0700124
alshabib0ccde6d2015-05-30 18:22:36 -0700125 @Override
126 public void init(DeviceId deviceId, PipelinerContext context) {
alshabibfd430b62015-12-16 18:56:38 -0800127 log.debug("Initiate OLT pipeline");
alshabib0ccde6d2015-05-30 18:22:36 -0700128 this.serviceDirectory = context.directory();
129 this.deviceId = deviceId;
alshabibd61b77b2016-02-01 23:30:53 -0800130
alshabib0ccde6d2015-05-30 18:22:36 -0700131 flowRuleService = serviceDirectory.get(FlowRuleService.class);
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700132 coreService = serviceDirectory.get(CoreService.class);
alshabibd61b77b2016-02-01 23:30:53 -0800133 groupService = serviceDirectory.get(GroupService.class);
134 flowObjectiveStore = context.store();
alshabib5ccbe3f2016-03-02 22:36:02 -0800135 storageService = serviceDirectory.get(StorageService.class);
136
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700137 appId = coreService.registerApplication(
138 "org.onosproject.driver.OLTPipeline");
139
alshabibd61b77b2016-02-01 23:30:53 -0800140
141 pendingGroups = CacheBuilder.newBuilder()
142 .expireAfterWrite(20, TimeUnit.SECONDS)
143 .removalListener((RemovalNotification<GroupKey, NextObjective> notification) -> {
144 if (notification.getCause() == RemovalCause.EXPIRED) {
145 fail(notification.getValue(), ObjectiveError.GROUPINSTALLATIONFAILED);
146 }
147 }).build();
148
149 groupService.addListener(new InnerGroupListener());
150
alshabibb32cefe2015-06-08 18:15:05 -0700151 }
152
alshabib0ccde6d2015-05-30 18:22:36 -0700153 @Override
154 public void filter(FilteringObjective filter) {
alshabibfd430b62015-12-16 18:56:38 -0800155 Instructions.OutputInstruction output;
alshabib0ccde6d2015-05-30 18:22:36 -0700156
alshabibfd430b62015-12-16 18:56:38 -0800157 if (filter.meta() != null && !filter.meta().immediate().isEmpty()) {
158 output = (Instructions.OutputInstruction) filter.meta().immediate().stream()
159 .filter(t -> t.type().equals(Instruction.Type.OUTPUT))
160 .limit(1)
161 .findFirst().get();
alshabib0ccde6d2015-05-30 18:22:36 -0700162
alshabibbb424232016-01-15 12:20:25 -0800163 if (output == null || !output.port().equals(PortNumber.CONTROLLER)) {
dvaddire8e6b89a2017-08-31 21:54:03 +0530164 log.warn("OLT can only filter packet to controller");
alshabibfd430b62015-12-16 18:56:38 -0800165 fail(filter, ObjectiveError.UNSUPPORTED);
166 return;
alshabib0ccde6d2015-05-30 18:22:36 -0700167 }
alshabibfd430b62015-12-16 18:56:38 -0800168 } else {
169 fail(filter, ObjectiveError.BADPARAMS);
alshabib0ccde6d2015-05-30 18:22:36 -0700170 return;
171 }
172
alshabibfd430b62015-12-16 18:56:38 -0800173 if (filter.key().type() != Criterion.Type.IN_PORT) {
174 fail(filter, ObjectiveError.BADPARAMS);
175 return;
176 }
177
178 EthTypeCriterion ethType = (EthTypeCriterion)
179 filterForCriterion(filter.conditions(), Criterion.Type.ETH_TYPE);
180
181 if (ethType == null) {
182 fail(filter, ObjectiveError.BADPARAMS);
183 return;
184 }
185
alshabibbb424232016-01-15 12:20:25 -0800186 if (ethType.ethType().equals(EthType.EtherType.EAPOL.ethType())) {
Amit Ghoshf1f22752018-08-14 07:28:01 +0100187 provisionEthTypeBasedFilter(filter, ethType, output);
188 } else if (ethType.ethType().equals(EthType.EtherType.LLDP.ethType())) {
189 provisionEthTypeBasedFilter(filter, ethType, output);
190
alshabibbb424232016-01-15 12:20:25 -0800191 } else if (ethType.ethType().equals(EthType.EtherType.IPV4.ethType())) {
alshabibfd430b62015-12-16 18:56:38 -0800192 IPProtocolCriterion ipProto = (IPProtocolCriterion)
193 filterForCriterion(filter.conditions(), Criterion.Type.IP_PROTO);
dvaddire8e6b89a2017-08-31 21:54:03 +0530194 if (ipProto == null) {
195 log.warn("OLT can only filter IGMP and DHCP");
196 fail(filter, ObjectiveError.UNSUPPORTED);
197 return;
198 }
alshabibfd430b62015-12-16 18:56:38 -0800199 if (ipProto.protocol() == IPv4.PROTOCOL_IGMP) {
Jonathan Hart51539b82015-10-29 09:53:04 -0700200 provisionIgmp(filter, ethType, ipProto, output);
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000201 } else if (ipProto.protocol() == IPv4.PROTOCOL_UDP) {
202 UdpPortCriterion udpSrcPort = (UdpPortCriterion)
203 filterForCriterion(filter.conditions(), Criterion.Type.UDP_SRC);
204
205 UdpPortCriterion udpDstPort = (UdpPortCriterion)
206 filterForCriterion(filter.conditions(), Criterion.Type.UDP_DST);
207
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700208 if ((udpSrcPort.udpPort().toInt() == 67 && udpDstPort.udpPort().toInt() == 68) ||
209 (udpSrcPort.udpPort().toInt() == 68 && udpDstPort.udpPort().toInt() == 67)) {
210 provisionDhcp(filter, ethType, ipProto, udpSrcPort, udpDstPort, output);
211 } else {
212 log.warn("Filtering rule with unsupported UDP src {} or dst {} port", udpSrcPort, udpDstPort);
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000213 fail(filter, ObjectiveError.UNSUPPORTED);
214 }
alshabibbb424232016-01-15 12:20:25 -0800215 } else {
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700216 log.warn("Currently supporting only IGMP and DHCP filters for IPv4 packets");
217 fail(filter, ObjectiveError.UNSUPPORTED);
218 }
219 } else if (ethType.ethType().equals(EthType.EtherType.IPV6.ethType())) {
220 IPProtocolCriterion ipProto = (IPProtocolCriterion)
221 filterForCriterion(filter.conditions(), Criterion.Type.IP_PROTO);
222 if (ipProto == null) {
223 log.warn("OLT can only filter DHCP");
224 fail(filter, ObjectiveError.UNSUPPORTED);
225 return;
226 }
227 if (ipProto.protocol() == IPv6.PROTOCOL_UDP) {
228 UdpPortCriterion udpSrcPort = (UdpPortCriterion)
229 filterForCriterion(filter.conditions(), Criterion.Type.UDP_SRC);
230
231 UdpPortCriterion udpDstPort = (UdpPortCriterion)
232 filterForCriterion(filter.conditions(), Criterion.Type.UDP_DST);
233
234 if ((udpSrcPort.udpPort().toInt() == 546 && udpDstPort.udpPort().toInt() == 547) ||
235 (udpSrcPort.udpPort().toInt() == 547 && udpDstPort.udpPort().toInt() == 546)) {
236 provisionDhcp(filter, ethType, ipProto, udpSrcPort, udpDstPort, output);
237 } else {
238 log.warn("Filtering rule with unsupported UDP src {} or dst {} port", udpSrcPort, udpDstPort);
239 fail(filter, ObjectiveError.UNSUPPORTED);
240 }
241 } else {
242 log.warn("Currently supporting only DHCP filters for IPv6 packets");
alshabibbb424232016-01-15 12:20:25 -0800243 fail(filter, ObjectiveError.UNSUPPORTED);
alshabibfd430b62015-12-16 18:56:38 -0800244 }
245 } else {
dvaddire8e6b89a2017-08-31 21:54:03 +0530246 log.warn("\nOnly the following are Supported in OLT for filter ->\n"
Amit Ghoshf1f22752018-08-14 07:28:01 +0100247 + "ETH TYPE : EAPOL, LLDP and IPV4\n"
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700248 + "IPV4 TYPE: IGMP and UDP (for DHCP)"
249 + "IPV6 TYPE: UDP (for DHCP)");
alshabibfd430b62015-12-16 18:56:38 -0800250 fail(filter, ObjectiveError.UNSUPPORTED);
251 }
252
253 }
254
255
256 @Override
257 public void forward(ForwardingObjective fwd) {
alshabibd61b77b2016-02-01 23:30:53 -0800258
259 if (checkForMulticast(fwd)) {
260 processMulticastRule(fwd);
261 return;
262 }
263
alshabib0ccde6d2015-05-30 18:22:36 -0700264 TrafficTreatment treatment = fwd.treatment();
alshabib0ccde6d2015-05-30 18:22:36 -0700265
alshabibfd430b62015-12-16 18:56:38 -0800266 List<Instruction> instructions = treatment.allInstructions();
alshabib0ccde6d2015-05-30 18:22:36 -0700267
Gamze Abakadadae722018-09-12 10:55:35 +0000268 Optional<Instruction> vlanInstruction = instructions.stream()
alshabibfd430b62015-12-16 18:56:38 -0800269 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
270 .filter(i -> ((L2ModificationInstruction) i).subtype() ==
271 L2ModificationInstruction.L2SubType.VLAN_PUSH ||
272 ((L2ModificationInstruction) i).subtype() ==
273 L2ModificationInstruction.L2SubType.VLAN_POP)
274 .findAny();
275
Gamze Abakadadae722018-09-12 10:55:35 +0000276
277 if (!vlanInstruction.isPresent()) {
Amit Ghoshf1f22752018-08-14 07:28:01 +0100278 installNoModificationRules(fwd);
alshabib0ccde6d2015-05-30 18:22:36 -0700279 } else {
Amit Ghoshf1f22752018-08-14 07:28:01 +0100280 L2ModificationInstruction vlanIns =
Gamze Abakadadae722018-09-12 10:55:35 +0000281 (L2ModificationInstruction) vlanInstruction.get();
Amit Ghoshf1f22752018-08-14 07:28:01 +0100282 if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
283 installUpstreamRules(fwd);
284 } else if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP) {
285 installDownstreamRules(fwd);
286 } else {
287 log.error("Unknown OLT operation: {}", fwd);
288 fail(fwd, ObjectiveError.UNSUPPORTED);
289 return;
290 }
alshabib0ccde6d2015-05-30 18:22:36 -0700291 }
292
alshabibfd430b62015-12-16 18:56:38 -0800293 pass(fwd);
alshabib0ccde6d2015-05-30 18:22:36 -0700294
alshabib0ccde6d2015-05-30 18:22:36 -0700295 }
296
alshabibd61b77b2016-02-01 23:30:53 -0800297
alshabib0ccde6d2015-05-30 18:22:36 -0700298 @Override
299 public void next(NextObjective nextObjective) {
alshabibd61b77b2016-02-01 23:30:53 -0800300 if (nextObjective.type() != NextObjective.Type.BROADCAST) {
301 log.error("OLT only supports broadcast groups.");
302 fail(nextObjective, ObjectiveError.BADPARAMS);
303 }
304
305 if (nextObjective.next().size() != 1) {
306 log.error("OLT only supports singleton broadcast groups.");
307 fail(nextObjective, ObjectiveError.BADPARAMS);
308 }
309
310 TrafficTreatment treatment = nextObjective.next().stream().findFirst().get();
311
312
313 GroupBucket bucket = DefaultGroupBucket.createAllGroupBucket(treatment);
314 GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id()));
315
alshabib1aa58142016-02-17 15:37:56 -0800316
alshabibd61b77b2016-02-01 23:30:53 -0800317 pendingGroups.put(key, nextObjective);
318
319 switch (nextObjective.op()) {
320 case ADD:
alshabib1aa58142016-02-17 15:37:56 -0800321 GroupDescription groupDesc =
322 new DefaultGroupDescription(deviceId,
323 GroupDescription.Type.ALL,
324 new GroupBuckets(Collections.singletonList(bucket)),
325 key,
326 null,
327 nextObjective.appId());
alshabibd61b77b2016-02-01 23:30:53 -0800328 groupService.addGroup(groupDesc);
329 break;
330 case REMOVE:
331 groupService.removeGroup(deviceId, key, nextObjective.appId());
332 break;
333 case ADD_TO_EXISTING:
alshabib1aa58142016-02-17 15:37:56 -0800334 groupService.addBucketsToGroup(deviceId, key,
335 new GroupBuckets(Collections.singletonList(bucket)),
336 key, nextObjective.appId());
337 break;
alshabibd61b77b2016-02-01 23:30:53 -0800338 case REMOVE_FROM_EXISTING:
alshabib1aa58142016-02-17 15:37:56 -0800339 groupService.removeBucketsFromGroup(deviceId, key,
alshabib56efe432016-02-25 17:57:24 -0500340 new GroupBuckets(Collections.singletonList(bucket)),
341 key, nextObjective.appId());
alshabibd61b77b2016-02-01 23:30:53 -0800342 break;
343 default:
344 log.warn("Unknown next objective operation: {}", nextObjective.op());
345 }
346
347
348 }
349
350 private void processMulticastRule(ForwardingObjective fwd) {
351 if (fwd.nextId() == null) {
352 log.error("Multicast objective does not have a next id");
353 fail(fwd, ObjectiveError.BADPARAMS);
354 }
355
alshabib1aa58142016-02-17 15:37:56 -0800356 GroupKey key = getGroupForNextObjective(fwd.nextId());
alshabibd61b77b2016-02-01 23:30:53 -0800357
alshabib1aa58142016-02-17 15:37:56 -0800358 if (key == null) {
alshabibd61b77b2016-02-01 23:30:53 -0800359 log.error("Group for forwarding objective missing: {}", fwd);
360 fail(fwd, ObjectiveError.GROUPMISSING);
361 }
362
alshabib1aa58142016-02-17 15:37:56 -0800363 Group group = groupService.getGroup(deviceId, key);
alshabibd61b77b2016-02-01 23:30:53 -0800364 TrafficTreatment treatment =
365 buildTreatment(Instructions.createGroup(group.id()));
366
367 FlowRule rule = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700368 .fromApp(fwd.appId())
alshabibd61b77b2016-02-01 23:30:53 -0800369 .forDevice(deviceId)
370 .forTable(0)
alshabibd61b77b2016-02-01 23:30:53 -0800371 .makePermanent()
372 .withPriority(fwd.priority())
373 .withSelector(fwd.selector())
374 .withTreatment(treatment)
375 .build();
376
377 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
378 switch (fwd.op()) {
379
380 case ADD:
381 builder.add(rule);
382 break;
383 case REMOVE:
384 builder.remove(rule);
385 break;
386 case ADD_TO_EXISTING:
387 case REMOVE_FROM_EXISTING:
388 break;
389 default:
390 log.warn("Unknown forwarding operation: {}", fwd.op());
391 }
392
393 applyFlowRules(builder, fwd);
394
395 }
396
397 private boolean checkForMulticast(ForwardingObjective fwd) {
398
alshabib1aa58142016-02-17 15:37:56 -0800399 IPCriterion ip = (IPCriterion) filterForCriterion(fwd.selector().criteria(),
alshabib56efe432016-02-25 17:57:24 -0500400 Criterion.Type.IPV4_DST);
alshabibd61b77b2016-02-01 23:30:53 -0800401
alshabib1aa58142016-02-17 15:37:56 -0800402 if (ip == null) {
403 return false;
404 }
405
Charles Chanaedabfd2016-02-26 09:31:48 -0800406 return ip.ip().isMulticast();
alshabibd61b77b2016-02-01 23:30:53 -0800407
408 }
409
alshabib1aa58142016-02-17 15:37:56 -0800410 private GroupKey getGroupForNextObjective(Integer nextId) {
alshabibd61b77b2016-02-01 23:30:53 -0800411 NextGroup next = flowObjectiveStore.getNextGroup(nextId);
alshabib1aa58142016-02-17 15:37:56 -0800412 return appKryo.deserialize(next.data());
alshabibd61b77b2016-02-01 23:30:53 -0800413
alshabib0ccde6d2015-05-30 18:22:36 -0700414 }
415
Amit Ghoshf1f22752018-08-14 07:28:01 +0100416 private void installNoModificationRules(ForwardingObjective fwd) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000417 Instructions.OutputInstruction output = (Instructions.OutputInstruction) fetchOutput(fwd, DOWNSTREAM);
Gamze Abakaa34469f2019-04-19 08:30:16 +0000418 Instructions.MetadataInstruction writeMetadata = fetchWriteMetadata(fwd);
419 Instructions.MeterInstruction meter = (Instructions.MeterInstruction) fetchMeter(fwd);
Amit Ghoshf1f22752018-08-14 07:28:01 +0100420
421 TrafficSelector selector = fwd.selector();
422
423 Criterion inport = selector.getCriterion(Criterion.Type.IN_PORT);
424 Criterion outerVlan = selector.getCriterion(Criterion.Type.VLAN_VID);
425 Criterion innerVlan = selector.getCriterion(Criterion.Type.INNER_VLAN_VID);
Amit Ghoshf1f22752018-08-14 07:28:01 +0100426
427 if (inport == null || output == null || innerVlan == null || outerVlan == null) {
428 log.error("Forwarding objective is underspecified: {}", fwd);
429 fail(fwd, ObjectiveError.BADPARAMS);
430 return;
431 }
432
Amit Ghoshf1f22752018-08-14 07:28:01 +0100433
434 FlowRule.Builder outer = DefaultFlowRule.builder()
435 .fromApp(fwd.appId())
436 .forDevice(deviceId)
437 .makePermanent()
438 .withPriority(fwd.priority())
Gamze Abakaa34469f2019-04-19 08:30:16 +0000439 .withSelector(buildSelector(inport, outerVlan))
440 .withTreatment(buildTreatment(output, writeMetadata, meter));
Amit Ghoshf1f22752018-08-14 07:28:01 +0100441
442 applyRules(fwd, outer);
443 }
444
alshabibfd430b62015-12-16 18:56:38 -0800445 private void installDownstreamRules(ForwardingObjective fwd) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000446 Instructions.OutputInstruction output = (Instructions.OutputInstruction) fetchOutput(fwd, DOWNSTREAM);
alshabibfd430b62015-12-16 18:56:38 -0800447
448 if (output == null) {
449 return;
450 }
451
alshabibfa0dc662016-01-13 11:23:53 -0800452 TrafficSelector selector = fwd.selector();
453
454 Criterion outerVlan = selector.getCriterion(Criterion.Type.VLAN_VID);
Gamze Abakadadae722018-09-12 10:55:35 +0000455 Criterion innerVlanCriterion = selector.getCriterion(Criterion.Type.INNER_VLAN_VID);
alshabibfa0dc662016-01-13 11:23:53 -0800456 Criterion inport = selector.getCriterion(Criterion.Type.IN_PORT);
cboling651c6872018-10-05 11:09:22 -0500457
Gamze Abakadadae722018-09-12 10:55:35 +0000458 if (outerVlan == null || innerVlanCriterion == null || inport == null) {
alshabibfa0dc662016-01-13 11:23:53 -0800459 log.error("Forwarding objective is underspecified: {}", fwd);
460 fail(fwd, ObjectiveError.BADPARAMS);
461 return;
462 }
463
Gamze Abakadadae722018-09-12 10:55:35 +0000464 VlanId innerVlan = ((VlanIdCriterion) innerVlanCriterion).vlanId();
465 Criterion innerVid = Criteria.matchVlanId(innerVlan);
alshabib2f74f2c2016-01-14 13:29:35 -0800466
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000467 TrafficSelector outerSelector = buildSelector(inport, outerVlan);
Gamze Abakadadae722018-09-12 10:55:35 +0000468
469 if (innerVlan.toShort() == VlanId.ANY_VALUE) {
470 installDownstreamRulesForAnyVlan(fwd, output, outerSelector, buildSelector(inport,
471 Criteria.matchVlanId(VlanId.ANY)));
472 } else {
473 installDownstreamRulesForVlans(fwd, output, outerSelector, buildSelector(inport, innerVid));
474 }
475 }
476
477 private void installDownstreamRulesForVlans(ForwardingObjective fwd, Instruction output,
478 TrafficSelector outerSelector, TrafficSelector innerSelector) {
479
480 List<Pair<Instruction, Instruction>> vlanOps =
481 vlanOps(fwd,
482 L2ModificationInstruction.L2SubType.VLAN_POP);
483
484 if (vlanOps == null || vlanOps.isEmpty()) {
485 return;
486 }
487
488 Pair<Instruction, Instruction> popAndRewrite = vlanOps.remove(0);
489
490 TrafficTreatment innerTreatment;
491 VlanId setVlanId = ((L2ModificationInstruction.ModVlanIdInstruction) popAndRewrite.getRight()).vlanId();
492 if (VlanId.NONE.equals(setVlanId)) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000493 innerTreatment = (buildTreatment(popAndRewrite.getLeft(), fetchMeter(fwd),
494 writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000495 } else {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000496 innerTreatment = (buildTreatment(popAndRewrite.getLeft(), popAndRewrite.getRight(),
497 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000498 }
499
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000500 //match: in port (nni), s-tag
501 //action: pop vlan (s-tag), write metadata, go to table 1, meter
alshabibfa0dc662016-01-13 11:23:53 -0800502 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700503 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800504 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800505 .makePermanent()
506 .withPriority(fwd.priority())
Gamze Abakadadae722018-09-12 10:55:35 +0000507 .withSelector(outerSelector)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000508 .withTreatment(buildTreatment(popAndRewrite.getLeft(), fetchMeter(fwd), fetchWriteMetadata(fwd),
Gamze Abakadadae722018-09-12 10:55:35 +0000509 Instructions.transition(QQ_TABLE)));
alshabibfd430b62015-12-16 18:56:38 -0800510
Gamze Abakadadae722018-09-12 10:55:35 +0000511 //match: in port (nni), c-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000512 //action: immediate: write metadata and pop, meter, output
alshabibfa0dc662016-01-13 11:23:53 -0800513 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700514 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800515 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800516 .forTable(QQ_TABLE)
517 .makePermanent()
518 .withPriority(fwd.priority())
Gamze Abakadadae722018-09-12 10:55:35 +0000519 .withSelector(innerSelector)
520 .withTreatment(innerTreatment);
521 applyRules(fwd, inner, outer);
522 }
523
524 private void installDownstreamRulesForAnyVlan(ForwardingObjective fwd, Instruction output,
525 TrafficSelector outerSelector, TrafficSelector innerSelector) {
526
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000527 //match: in port (nni), s-tag
528 //action: immediate: write metadata, pop vlan, meter and go to table 1
Gamze Abakadadae722018-09-12 10:55:35 +0000529 FlowRule.Builder outer = DefaultFlowRule.builder()
530 .fromApp(fwd.appId())
531 .forDevice(deviceId)
532 .makePermanent()
533 .withPriority(fwd.priority())
534 .withSelector(outerSelector)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000535 .withTreatment(buildTreatment(Instructions.popVlan(), fetchMeter(fwd),
536 fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE)));
Gamze Abakadadae722018-09-12 10:55:35 +0000537
538 //match: in port (nni) and s-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000539 //action: immediate : write metadata, meter and output
Gamze Abakadadae722018-09-12 10:55:35 +0000540 FlowRule.Builder inner = DefaultFlowRule.builder()
541 .fromApp(fwd.appId())
542 .forDevice(deviceId)
543 .forTable(QQ_TABLE)
544 .makePermanent()
545 .withPriority(fwd.priority())
546 .withSelector(innerSelector)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000547 .withTreatment(buildTreatment(fetchMeter(fwd),
548 writeMetadataIncludingOnlyTp(fwd), output));
alshabibfd430b62015-12-16 18:56:38 -0800549
550 applyRules(fwd, inner, outer);
alshabibfd430b62015-12-16 18:56:38 -0800551 }
552
553 private void installUpstreamRules(ForwardingObjective fwd) {
554 List<Pair<Instruction, Instruction>> vlanOps =
555 vlanOps(fwd,
556 L2ModificationInstruction.L2SubType.VLAN_PUSH);
557
Gamze Abakadadae722018-09-12 10:55:35 +0000558 if (vlanOps == null || vlanOps.isEmpty()) {
alshabibfd430b62015-12-16 18:56:38 -0800559 return;
560 }
561
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000562 Instruction output = fetchOutput(fwd, UPSTREAM);
alshabibfd430b62015-12-16 18:56:38 -0800563
564 if (output == null) {
565 return;
566 }
567
568 Pair<Instruction, Instruction> innerPair = vlanOps.remove(0);
alshabibfd430b62015-12-16 18:56:38 -0800569 Pair<Instruction, Instruction> outerPair = vlanOps.remove(0);
570
Gamze Abakadadae722018-09-12 10:55:35 +0000571 boolean noneValueVlanStatus = checkNoneVlanCriteria(fwd);
572 boolean anyValueVlanStatus = checkAnyVlanMatchCriteria(fwd);
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700573
Gamze Abakadadae722018-09-12 10:55:35 +0000574 if (anyValueVlanStatus) {
575 installUpstreamRulesForAnyVlan(fwd, output, outerPair);
576 } else {
577 installUpstreamRulesForVlans(fwd, output, innerPair, outerPair, noneValueVlanStatus);
578 }
579 }
580
581 private void installUpstreamRulesForVlans(ForwardingObjective fwd, Instruction output,
582 Pair<Instruction, Instruction> innerPair,
583 Pair<Instruction, Instruction> outerPair, Boolean noneValueVlanStatus) {
584
585 TrafficTreatment innerTreatment;
586 if (noneValueVlanStatus) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000587 innerTreatment = buildTreatment(innerPair.getLeft(), innerPair.getRight(), fetchMeter(fwd),
588 fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE));
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700589 } else {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000590 innerTreatment = buildTreatment(innerPair.getRight(), fetchMeter(fwd), fetchWriteMetadata(fwd),
591 Instructions.transition(QQ_TABLE));
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700592 }
593
Gamze Abakadadae722018-09-12 10:55:35 +0000594 //match: in port, vlanId (0 or None)
595 //action:
596 //if vlanId None, push & set c-tag go to table 1
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000597 //if vlanId 0 or any specific vlan, set c-tag, write metadata, meter and go to table 1
alshabibfd430b62015-12-16 18:56:38 -0800598 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700599 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800600 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800601 .makePermanent()
602 .withPriority(fwd.priority())
603 .withSelector(fwd.selector())
Gamze Abakadadae722018-09-12 10:55:35 +0000604 .withTreatment(innerTreatment);
alshabibfd430b62015-12-16 18:56:38 -0800605
606 PortCriterion inPort = (PortCriterion)
607 fwd.selector().getCriterion(Criterion.Type.IN_PORT);
608
609 VlanId cVlanId = ((L2ModificationInstruction.ModVlanIdInstruction)
610 innerPair.getRight()).vlanId();
611
Gamze Abakadadae722018-09-12 10:55:35 +0000612 //match: in port, c-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000613 //action: immediate: push s-tag, write metadata, meter and output
alshabibfd430b62015-12-16 18:56:38 -0800614 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700615 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800616 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800617 .forTable(QQ_TABLE)
618 .makePermanent()
619 .withPriority(fwd.priority())
Gamze Abakadadae722018-09-12 10:55:35 +0000620 .withSelector(buildSelector(inPort, Criteria.matchVlanId(cVlanId)))
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000621 .withTreatment(buildTreatment(outerPair.getLeft(), outerPair.getRight(),
622 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd), output));
alshabibfd430b62015-12-16 18:56:38 -0800623
624 applyRules(fwd, inner, outer);
Gamze Abakadadae722018-09-12 10:55:35 +0000625 }
alshabibfd430b62015-12-16 18:56:38 -0800626
Gamze Abakadadae722018-09-12 10:55:35 +0000627 private void installUpstreamRulesForAnyVlan(ForwardingObjective fwd, Instruction output,
628 Pair<Instruction, Instruction> outerPair) {
629
630 log.debug("Installing upstream rules for any value vlan");
631
632 //match: in port and any-vlan (coming from OLT app.)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000633 //action: write metadata, go to table 1 and meter
Gamze Abakadadae722018-09-12 10:55:35 +0000634 FlowRule.Builder inner = DefaultFlowRule.builder()
635 .fromApp(fwd.appId())
636 .forDevice(deviceId)
637 .makePermanent()
638 .withPriority(fwd.priority())
639 .withSelector(fwd.selector())
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000640 .withTreatment(buildTreatment(Instructions.transition(QQ_TABLE), fetchMeter(fwd),
641 fetchWriteMetadata(fwd)));
Gamze Abakadadae722018-09-12 10:55:35 +0000642
643
644 TrafficSelector defaultSelector = DefaultTrafficSelector.builder()
645 .matchInPort(((PortCriterion) fwd.selector().getCriterion(Criterion.Type.IN_PORT)).port())
646 .build();
647
648 //drop the packets that don't have vlan
649 //match: in port
650 //action: no action
651 FlowRule.Builder defaultInner = DefaultFlowRule.builder()
652 .fromApp(fwd.appId())
653 .forDevice(deviceId)
654 .makePermanent()
655 .withPriority(NO_ACTION_PRIORITY)
656 .withSelector(defaultSelector)
657 .withTreatment(DefaultTrafficTreatment.emptyTreatment());
658
659 Instruction qinqInstruction = Instructions.pushVlan(EthType.EtherType.QINQ.ethType());
660
661 //match: in port and any-vlan (coming from OLT app.)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000662 //action: immediate: push:QinQ, vlanId (s-tag), write metadata, meter and output
Gamze Abakadadae722018-09-12 10:55:35 +0000663 FlowRule.Builder outer = DefaultFlowRule.builder()
664 .fromApp(fwd.appId())
665 .forDevice(deviceId)
666 .forTable(QQ_TABLE)
667 .makePermanent()
668 .withPriority(fwd.priority())
669 .withSelector(fwd.selector())
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000670 .withTreatment(buildTreatment(qinqInstruction, outerPair.getRight(),
671 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000672
673 applyRules(fwd, inner, defaultInner, outer);
674 }
675
676 private boolean checkNoneVlanCriteria(ForwardingObjective fwd) {
677 // Add the VLAN_PUSH treatment if we're matching on VlanId.NONE
678 Criterion vlanMatchCriterion = filterForCriterion(fwd.selector().criteria(), Criterion.Type.VLAN_VID);
679 boolean noneValueVlanStatus = false;
680 if (vlanMatchCriterion != null) {
681 noneValueVlanStatus = ((VlanIdCriterion) vlanMatchCriterion).vlanId().equals(VlanId.NONE);
682 }
683 return noneValueVlanStatus;
684 }
685
686 private boolean checkAnyVlanMatchCriteria(ForwardingObjective fwd) {
687 Criterion anyValueVlanCriterion = fwd.selector().criteria().stream()
688 .filter(c -> c.type().equals(Criterion.Type.VLAN_VID))
689 .filter(vc -> ((VlanIdCriterion) vc).vlanId().toShort() == VlanId.ANY_VALUE)
690 .findAny().orElse(null);
691
692 if (anyValueVlanCriterion == null) {
693 log.debug("Any value vlan match criteria is not found");
694 return false;
695 }
696
697 return true;
alshabibfd430b62015-12-16 18:56:38 -0800698 }
699
700 private Instruction fetchOutput(ForwardingObjective fwd, String direction) {
701 Instruction output = fwd.treatment().allInstructions().stream()
702 .filter(i -> i.type() == Instruction.Type.OUTPUT)
703 .findFirst().orElse(null);
704
705 if (output == null) {
706 log.error("OLT {} rule has no output", direction);
707 fail(fwd, ObjectiveError.BADPARAMS);
708 return null;
709 }
710 return output;
711 }
712
Gamze Abakadadae722018-09-12 10:55:35 +0000713 private Instruction fetchMeter(ForwardingObjective fwd) {
714 Instruction meter = fwd.treatment().metered();
715
716 if (meter == null) {
717 log.debug("Meter instruction is not found for the forwarding objective {}", fwd);
718 return null;
719 }
720
721 log.debug("Meter instruction is found.");
722 return meter;
723 }
724
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000725 private Instructions.MetadataInstruction fetchWriteMetadata(ForwardingObjective fwd) {
726 Instructions.MetadataInstruction writeMetadata = fwd.treatment().writeMetadata();
Gamze Abakadadae722018-09-12 10:55:35 +0000727
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000728 if (writeMetadata == null) {
729 log.warn("Write metadata is not found for the forwarding obj");
730 fail(fwd, ObjectiveError.BADPARAMS);
Gamze Abakadadae722018-09-12 10:55:35 +0000731 return null;
732 }
733
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000734 log.debug("Write metadata is found {}", writeMetadata);
735 return writeMetadata;
Gamze Abakadadae722018-09-12 10:55:35 +0000736 }
737
alshabibfd430b62015-12-16 18:56:38 -0800738 private List<Pair<Instruction, Instruction>> vlanOps(ForwardingObjective fwd,
739 L2ModificationInstruction.L2SubType type) {
740
741 List<Pair<Instruction, Instruction>> vlanOps = findVlanOps(
742 fwd.treatment().allInstructions(), type);
743
Gamze Abakadadae722018-09-12 10:55:35 +0000744 if (vlanOps == null || vlanOps.isEmpty()) {
alshabibfd430b62015-12-16 18:56:38 -0800745 String direction = type == L2ModificationInstruction.L2SubType.VLAN_POP
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000746 ? DOWNSTREAM : UPSTREAM;
alshabibfd430b62015-12-16 18:56:38 -0800747 log.error("Missing vlan operations in {} forwarding: {}", direction, fwd);
748 fail(fwd, ObjectiveError.BADPARAMS);
Gamze Abakadadae722018-09-12 10:55:35 +0000749 return ImmutableList.of();
alshabibfd430b62015-12-16 18:56:38 -0800750 }
751 return vlanOps;
752 }
753
754
755 private List<Pair<Instruction, Instruction>> findVlanOps(List<Instruction> instructions,
alshabibd61b77b2016-02-01 23:30:53 -0800756 L2ModificationInstruction.L2SubType type) {
alshabibfd430b62015-12-16 18:56:38 -0800757
758 List<Instruction> vlanPushs = findL2Instructions(
759 type,
760 instructions);
761 List<Instruction> vlanSets = findL2Instructions(
762 L2ModificationInstruction.L2SubType.VLAN_ID,
763 instructions);
764
765 if (vlanPushs.size() != vlanSets.size()) {
Gamze Abakadadae722018-09-12 10:55:35 +0000766 return ImmutableList.of();
alshabibfd430b62015-12-16 18:56:38 -0800767 }
768
769 List<Pair<Instruction, Instruction>> pairs = Lists.newArrayList();
770
771 for (int i = 0; i < vlanPushs.size(); i++) {
772 pairs.add(new ImmutablePair<>(vlanPushs.get(i), vlanSets.get(i)));
773 }
774 return pairs;
775 }
776
777 private List<Instruction> findL2Instructions(L2ModificationInstruction.L2SubType subType,
778 List<Instruction> actions) {
779 return actions.stream()
780 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
781 .filter(i -> ((L2ModificationInstruction) i).subtype() == subType)
782 .collect(Collectors.toList());
783 }
784
Amit Ghoshf1f22752018-08-14 07:28:01 +0100785 private void provisionEthTypeBasedFilter(FilteringObjective filter,
786 EthTypeCriterion ethType,
787 Instructions.OutputInstruction output) {
alshabibfd430b62015-12-16 18:56:38 -0800788
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000789 Instruction meter = filter.meta().metered();
790 Instruction writeMetadata = filter.meta().writeMetadata();
791
alshabibfd430b62015-12-16 18:56:38 -0800792 TrafficSelector selector = buildSelector(filter.key(), ethType);
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000793 TrafficTreatment treatment = buildTreatment(output, meter, writeMetadata);
alshabibfd430b62015-12-16 18:56:38 -0800794 buildAndApplyRule(filter, selector, treatment);
795
796 }
797
Jonathan Hart51539b82015-10-29 09:53:04 -0700798 private void provisionIgmp(FilteringObjective filter, EthTypeCriterion ethType,
alshabibfd430b62015-12-16 18:56:38 -0800799 IPProtocolCriterion ipProto,
800 Instructions.OutputInstruction output) {
Gamze Abaka7c070c82019-02-21 14:40:18 +0000801
802 Instruction meter = filter.meta().metered();
803 Instruction writeMetadata = filter.meta().writeMetadata();
804
alshabibfd430b62015-12-16 18:56:38 -0800805 TrafficSelector selector = buildSelector(filter.key(), ethType, ipProto);
Gamze Abaka7c070c82019-02-21 14:40:18 +0000806 TrafficTreatment treatment = buildTreatment(output, meter, writeMetadata);
alshabibfd430b62015-12-16 18:56:38 -0800807 buildAndApplyRule(filter, selector, treatment);
808 }
809
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000810 private void provisionDhcp(FilteringObjective filter, EthTypeCriterion ethType,
811 IPProtocolCriterion ipProto,
812 UdpPortCriterion udpSrcPort,
813 UdpPortCriterion udpDstPort,
814 Instructions.OutputInstruction output) {
Gamze Abaka7c070c82019-02-21 14:40:18 +0000815
816 Instruction meter = filter.meta().metered();
817 Instruction writeMetadata = filter.meta().writeMetadata();
818
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000819 TrafficSelector selector = buildSelector(filter.key(), ethType, ipProto, udpSrcPort, udpDstPort);
Gamze Abaka7c070c82019-02-21 14:40:18 +0000820 TrafficTreatment treatment = buildTreatment(output, meter, writeMetadata);
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000821 buildAndApplyRule(filter, selector, treatment);
822 }
Gamze Abakadadae722018-09-12 10:55:35 +0000823
alshabibfd430b62015-12-16 18:56:38 -0800824 private void buildAndApplyRule(FilteringObjective filter, TrafficSelector selector,
825 TrafficTreatment treatment) {
826 FlowRule rule = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700827 .fromApp(filter.appId())
alshabibfd430b62015-12-16 18:56:38 -0800828 .forDevice(deviceId)
829 .forTable(0)
alshabibfd430b62015-12-16 18:56:38 -0800830 .makePermanent()
831 .withSelector(selector)
832 .withTreatment(treatment)
alshabibbb424232016-01-15 12:20:25 -0800833 .withPriority(filter.priority())
alshabibfd430b62015-12-16 18:56:38 -0800834 .build();
835
836 FlowRuleOperations.Builder opsBuilder = FlowRuleOperations.builder();
837
838 switch (filter.type()) {
839 case PERMIT:
840 opsBuilder.add(rule);
841 break;
842 case DENY:
843 opsBuilder.remove(rule);
844 break;
845 default:
846 log.warn("Unknown filter type : {}", filter.type());
847 fail(filter, ObjectiveError.UNSUPPORTED);
848 }
849
850 applyFlowRules(opsBuilder, filter);
851 }
852
Gamze Abakadadae722018-09-12 10:55:35 +0000853 private void applyRules(ForwardingObjective fwd, FlowRule.Builder... fwdBuilders) {
Amit Ghoshf1f22752018-08-14 07:28:01 +0100854 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
855 switch (fwd.op()) {
856 case ADD:
Gamze Abakadadae722018-09-12 10:55:35 +0000857 for (FlowRule.Builder fwdBuilder : fwdBuilders) {
858 builder.add(fwdBuilder.build());
859 }
Amit Ghoshf1f22752018-08-14 07:28:01 +0100860 break;
861 case REMOVE:
Gamze Abakadadae722018-09-12 10:55:35 +0000862 for (FlowRule.Builder fwdBuilder : fwdBuilders) {
863 builder.remove(fwdBuilder.build());
864 }
alshabibfd430b62015-12-16 18:56:38 -0800865 break;
866 case ADD_TO_EXISTING:
867 break;
868 case REMOVE_FROM_EXISTING:
869 break;
870 default:
871 log.warn("Unknown forwarding operation: {}", fwd.op());
872 }
873
874 applyFlowRules(builder, fwd);
875 }
876
877 private void applyFlowRules(FlowRuleOperations.Builder builder,
878 Objective objective) {
879 flowRuleService.apply(builder.build(new FlowRuleOperationsContext() {
880 @Override
881 public void onSuccess(FlowRuleOperations ops) {
882 pass(objective);
883 }
884
885 @Override
886 public void onError(FlowRuleOperations ops) {
887 fail(objective, ObjectiveError.FLOWINSTALLATIONFAILED);
888 }
889 }));
890 }
891
892 private Criterion filterForCriterion(Collection<Criterion> criteria, Criterion.Type type) {
893 return criteria.stream()
alshabibbb424232016-01-15 12:20:25 -0800894 .filter(c -> c.type().equals(type))
alshabibfd430b62015-12-16 18:56:38 -0800895 .limit(1)
896 .findFirst().orElse(null);
897 }
898
899 private TrafficSelector buildSelector(Criterion... criteria) {
900
901
902 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
903
904 for (Criterion c : criteria) {
905 sBuilder.add(c);
906 }
907
908 return sBuilder.build();
909 }
910
911 private TrafficTreatment buildTreatment(Instruction... instructions) {
912
913
914 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
915
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000916 Arrays.stream(instructions).filter(Objects::nonNull).forEach(tBuilder::add);
alshabibfd430b62015-12-16 18:56:38 -0800917
918 return tBuilder.build();
919 }
920
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000921 private Instruction writeMetadataIncludingOnlyTp(ForwardingObjective fwd) {
922
923 return Instructions.writeMetadata(
924 fetchWriteMetadata(fwd).metadata() & 0xFFFF00000000L, 0L);
925 }
alshabibfd430b62015-12-16 18:56:38 -0800926
927 private void fail(Objective obj, ObjectiveError error) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800928 obj.context().ifPresent(context -> context.onError(obj, error));
alshabibfd430b62015-12-16 18:56:38 -0800929 }
930
931 private void pass(Objective obj) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800932 obj.context().ifPresent(context -> context.onSuccess(obj));
alshabibfd430b62015-12-16 18:56:38 -0800933 }
934
alshabib2cc73cb2015-06-30 20:26:56 -0700935
alshabibd61b77b2016-02-01 23:30:53 -0800936 private class InnerGroupListener implements GroupListener {
alshabib2cc73cb2015-06-30 20:26:56 -0700937 @Override
alshabibd61b77b2016-02-01 23:30:53 -0800938 public void event(GroupEvent event) {
ke hanf5086672016-08-12 11:09:17 +0800939 if (event.type() == GroupEvent.Type.GROUP_ADDED ||
Gamze Abakadadae722018-09-12 10:55:35 +0000940 event.type() == GroupEvent.Type.GROUP_UPDATED) {
alshabibd61b77b2016-02-01 23:30:53 -0800941 GroupKey key = event.subject().appCookie();
alshabib2cc73cb2015-06-30 20:26:56 -0700942
alshabibd61b77b2016-02-01 23:30:53 -0800943 NextObjective obj = pendingGroups.getIfPresent(key);
944 if (obj != null) {
945 flowObjectiveStore.putNextGroup(obj.id(), new OLTPipelineGroup(key));
946 pass(obj);
947 pendingGroups.invalidate(key);
948 }
949 }
alshabib2cc73cb2015-06-30 20:26:56 -0700950 }
951 }
952
alshabibd61b77b2016-02-01 23:30:53 -0800953 private static class OLTPipelineGroup implements NextGroup {
954
955 private final GroupKey key;
956
957 public OLTPipelineGroup(GroupKey key) {
958 this.key = key;
959 }
960
961 public GroupKey key() {
962 return key;
963 }
964
965 @Override
966 public byte[] data() {
967 return appKryo.serialize(key);
968 }
969
970 }
Saurav Das24431192016-03-07 19:13:00 -0800971
972 @Override
973 public List<String> getNextMappings(NextGroup nextGroup) {
974 // TODO Implementation deferred to vendor
975 return null;
976 }
alshabib0ccde6d2015-05-30 18:22:36 -0700977}