blob: 7f7daf04b0f3622265031f3c965ff6862fd1775e [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 Abakab5c60cb2018-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 Scandolod06925c2018-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 Abakab5c60cb2018-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 Abakab5c60cb2018-09-12 10:55:35 +000099 private static final int NO_ACTION_PRIORITY = 500;
Gamze Abakae5b14612018-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
Gamze Abakab5c60cb2018-09-12 10:55:35 +0000186 if (ethType.ethType().equals(EthType.EtherType.EAPOL.ethType())) {
187 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 Scandolod06925c2018-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 Scandolod06925c2018-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"
Jonathan Hart248e7cd2018-08-21 17:53:02 -0700247 + "ETH TYPE : EAPOL, LLDP and IPV4\n"
Matteo Scandolod06925c2018-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 Abakab5c60cb2018-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 Abakab5c60cb2018-09-12 10:55:35 +0000276
277 if (!vlanInstruction.isPresent()) {
Amit Ghoshe68b0ac2018-08-14 07:28:01 +0100278 installNoModificationRules(fwd);
alshabib0ccde6d2015-05-30 18:22:36 -0700279 } else {
Amit Ghoshe68b0ac2018-08-14 07:28:01 +0100280 L2ModificationInstruction vlanIns =
Gamze Abakab5c60cb2018-09-12 10:55:35 +0000281 (L2ModificationInstruction) vlanInstruction.get();
Amit Ghoshe68b0ac2018-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 Ghoshe68b0ac2018-08-14 07:28:01 +0100416 private void installNoModificationRules(ForwardingObjective fwd) {
Gamze Abakae5b14612018-12-24 13:17:12 +0000417 Instructions.OutputInstruction output = (Instructions.OutputInstruction) fetchOutput(fwd, DOWNSTREAM);
Amit Ghoshe68b0ac2018-08-14 07:28:01 +0100418
419 TrafficSelector selector = fwd.selector();
420
421 Criterion inport = selector.getCriterion(Criterion.Type.IN_PORT);
422 Criterion outerVlan = selector.getCriterion(Criterion.Type.VLAN_VID);
423 Criterion innerVlan = selector.getCriterion(Criterion.Type.INNER_VLAN_VID);
424 Criterion metadata;
425
426 if (inport == null || output == null || innerVlan == null || outerVlan == null) {
427 log.error("Forwarding objective is underspecified: {}", fwd);
428 fail(fwd, ObjectiveError.BADPARAMS);
429 return;
430 }
431
432 metadata = Criteria.matchMetadata(((VlanIdCriterion) innerVlan).vlanId().toShort());
433
434 FlowRule.Builder outer = DefaultFlowRule.builder()
435 .fromApp(fwd.appId())
436 .forDevice(deviceId)
437 .makePermanent()
438 .withPriority(fwd.priority())
439 .withSelector(buildSelector(inport, outerVlan, metadata))
440 .withTreatment(buildTreatment(output));
441
442 applyRules(fwd, outer);
443 }
444
alshabibfd430b62015-12-16 18:56:38 -0800445 private void installDownstreamRules(ForwardingObjective fwd) {
Gamze Abakae5b14612018-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 Abakab5c60cb2018-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);
cboling10ebd5b2018-10-05 11:20:56 -0500457
Gamze Abakab5c60cb2018-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 Abakab5c60cb2018-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 Abakae5b14612018-12-24 13:17:12 +0000467 TrafficSelector outerSelector = buildSelector(inport, outerVlan);
Gamze Abakab5c60cb2018-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 Abakae5b14612018-12-24 13:17:12 +0000493 innerTreatment = (buildTreatment(popAndRewrite.getLeft(), fetchMeter(fwd),
494 writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakab5c60cb2018-09-12 10:55:35 +0000495 } else {
Gamze Abakae5b14612018-12-24 13:17:12 +0000496 innerTreatment = (buildTreatment(popAndRewrite.getLeft(), popAndRewrite.getRight(),
497 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakab5c60cb2018-09-12 10:55:35 +0000498 }
499
Gamze Abakae5b14612018-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 Abakab5c60cb2018-09-12 10:55:35 +0000507 .withSelector(outerSelector)
Gamze Abakae5b14612018-12-24 13:17:12 +0000508 .withTreatment(buildTreatment(popAndRewrite.getLeft(), fetchMeter(fwd), fetchWriteMetadata(fwd),
Gamze Abakab5c60cb2018-09-12 10:55:35 +0000509 Instructions.transition(QQ_TABLE)));
alshabibfd430b62015-12-16 18:56:38 -0800510
Gamze Abakab5c60cb2018-09-12 10:55:35 +0000511 //match: in port (nni), c-tag
Gamze Abakae5b14612018-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 Abakab5c60cb2018-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 Abakae5b14612018-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 Abakab5c60cb2018-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 Abakae5b14612018-12-24 13:17:12 +0000535 .withTreatment(buildTreatment(Instructions.popVlan(), fetchMeter(fwd),
536 fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE)));
Gamze Abakab5c60cb2018-09-12 10:55:35 +0000537
538 //match: in port (nni) and s-tag
Gamze Abakae5b14612018-12-24 13:17:12 +0000539 //action: immediate : write metadata, meter and output
Gamze Abakab5c60cb2018-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 Abakae5b14612018-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 Abakab5c60cb2018-09-12 10:55:35 +0000558 if (vlanOps == null || vlanOps.isEmpty()) {
alshabibfd430b62015-12-16 18:56:38 -0800559 return;
560 }
561
Gamze Abakae5b14612018-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 Abakab5c60cb2018-09-12 10:55:35 +0000571 boolean noneValueVlanStatus = checkNoneVlanCriteria(fwd);
572 boolean anyValueVlanStatus = checkAnyVlanMatchCriteria(fwd);
Jonathan Hart3333cc62018-08-15 18:15:45 -0700573
Gamze Abakab5c60cb2018-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 Abakae5b14612018-12-24 13:17:12 +0000587 innerTreatment = buildTreatment(innerPair.getLeft(), innerPair.getRight(), fetchMeter(fwd),
588 fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE));
Jonathan Hart3333cc62018-08-15 18:15:45 -0700589 } else {
Gamze Abakae5b14612018-12-24 13:17:12 +0000590 innerTreatment = buildTreatment(innerPair.getRight(), fetchMeter(fwd), fetchWriteMetadata(fwd),
591 Instructions.transition(QQ_TABLE));
Jonathan Hart3333cc62018-08-15 18:15:45 -0700592 }
593
Gamze Abakab5c60cb2018-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 Abakae5b14612018-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 Abakab5c60cb2018-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 Abakab5c60cb2018-09-12 10:55:35 +0000612 //match: in port, c-tag
Gamze Abakae5b14612018-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 Abakab5c60cb2018-09-12 10:55:35 +0000620 .withSelector(buildSelector(inPort, Criteria.matchVlanId(cVlanId)))
Gamze Abakae5b14612018-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 Abakab5c60cb2018-09-12 10:55:35 +0000625 }
alshabibfd430b62015-12-16 18:56:38 -0800626
Gamze Abakab5c60cb2018-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 Abakae5b14612018-12-24 13:17:12 +0000633 //action: write metadata, go to table 1 and meter
Gamze Abakab5c60cb2018-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 Abakae5b14612018-12-24 13:17:12 +0000640 .withTreatment(buildTreatment(Instructions.transition(QQ_TABLE), fetchMeter(fwd),
641 fetchWriteMetadata(fwd)));
Gamze Abakab5c60cb2018-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 Abakae5b14612018-12-24 13:17:12 +0000662 //action: immediate: push:QinQ, vlanId (s-tag), write metadata, meter and output
Gamze Abakab5c60cb2018-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 Abakae5b14612018-12-24 13:17:12 +0000670 .withTreatment(buildTreatment(qinqInstruction, outerPair.getRight(),
671 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakab5c60cb2018-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 Abakab5c60cb2018-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 Abakae5b14612018-12-24 13:17:12 +0000725 private Instructions.MetadataInstruction fetchWriteMetadata(ForwardingObjective fwd) {
726 Instructions.MetadataInstruction writeMetadata = fwd.treatment().writeMetadata();
Gamze Abakab5c60cb2018-09-12 10:55:35 +0000727
Gamze Abakae5b14612018-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 Abakab5c60cb2018-09-12 10:55:35 +0000731 return null;
732 }
733
Gamze Abakae5b14612018-12-24 13:17:12 +0000734 log.debug("Write metadata is found {}", writeMetadata);
735 return writeMetadata;
Gamze Abakab5c60cb2018-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 Abakab5c60cb2018-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 Abakae5b14612018-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 Abakab5c60cb2018-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 Abakab5c60cb2018-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
Gamze Abakab5c60cb2018-09-12 10:55:35 +0000785 private void provisionEthTypeBasedFilter(FilteringObjective filter,
786 EthTypeCriterion ethType,
787 Instructions.OutputInstruction output) {
alshabibfd430b62015-12-16 18:56:38 -0800788
Gamze Abakae5b14612018-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 Abakae5b14612018-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) {
801 TrafficSelector selector = buildSelector(filter.key(), ethType, ipProto);
802 TrafficTreatment treatment = buildTreatment(output);
803 buildAndApplyRule(filter, selector, treatment);
804 }
805
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000806 private void provisionDhcp(FilteringObjective filter, EthTypeCriterion ethType,
807 IPProtocolCriterion ipProto,
808 UdpPortCriterion udpSrcPort,
809 UdpPortCriterion udpDstPort,
810 Instructions.OutputInstruction output) {
811 TrafficSelector selector = buildSelector(filter.key(), ethType, ipProto, udpSrcPort, udpDstPort);
812 TrafficTreatment treatment = buildTreatment(output);
813 buildAndApplyRule(filter, selector, treatment);
814 }
Gamze Abakab5c60cb2018-09-12 10:55:35 +0000815
alshabibfd430b62015-12-16 18:56:38 -0800816 private void buildAndApplyRule(FilteringObjective filter, TrafficSelector selector,
817 TrafficTreatment treatment) {
818 FlowRule rule = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700819 .fromApp(filter.appId())
alshabibfd430b62015-12-16 18:56:38 -0800820 .forDevice(deviceId)
821 .forTable(0)
alshabibfd430b62015-12-16 18:56:38 -0800822 .makePermanent()
823 .withSelector(selector)
824 .withTreatment(treatment)
alshabibbb424232016-01-15 12:20:25 -0800825 .withPriority(filter.priority())
alshabibfd430b62015-12-16 18:56:38 -0800826 .build();
827
828 FlowRuleOperations.Builder opsBuilder = FlowRuleOperations.builder();
829
830 switch (filter.type()) {
831 case PERMIT:
832 opsBuilder.add(rule);
833 break;
834 case DENY:
835 opsBuilder.remove(rule);
836 break;
837 default:
838 log.warn("Unknown filter type : {}", filter.type());
839 fail(filter, ObjectiveError.UNSUPPORTED);
840 }
841
842 applyFlowRules(opsBuilder, filter);
843 }
844
Gamze Abakab5c60cb2018-09-12 10:55:35 +0000845 private void applyRules(ForwardingObjective fwd, FlowRule.Builder... fwdBuilders) {
Amit Ghoshe68b0ac2018-08-14 07:28:01 +0100846 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
847 switch (fwd.op()) {
848 case ADD:
Gamze Abakab5c60cb2018-09-12 10:55:35 +0000849 for (FlowRule.Builder fwdBuilder : fwdBuilders) {
850 builder.add(fwdBuilder.build());
851 }
Amit Ghoshe68b0ac2018-08-14 07:28:01 +0100852 break;
853 case REMOVE:
Gamze Abakab5c60cb2018-09-12 10:55:35 +0000854 for (FlowRule.Builder fwdBuilder : fwdBuilders) {
855 builder.remove(fwdBuilder.build());
856 }
alshabibfd430b62015-12-16 18:56:38 -0800857 break;
858 case ADD_TO_EXISTING:
859 break;
860 case REMOVE_FROM_EXISTING:
861 break;
862 default:
863 log.warn("Unknown forwarding operation: {}", fwd.op());
864 }
865
866 applyFlowRules(builder, fwd);
867 }
868
869 private void applyFlowRules(FlowRuleOperations.Builder builder,
870 Objective objective) {
871 flowRuleService.apply(builder.build(new FlowRuleOperationsContext() {
872 @Override
873 public void onSuccess(FlowRuleOperations ops) {
874 pass(objective);
875 }
876
877 @Override
878 public void onError(FlowRuleOperations ops) {
879 fail(objective, ObjectiveError.FLOWINSTALLATIONFAILED);
880 }
881 }));
882 }
883
884 private Criterion filterForCriterion(Collection<Criterion> criteria, Criterion.Type type) {
885 return criteria.stream()
alshabibbb424232016-01-15 12:20:25 -0800886 .filter(c -> c.type().equals(type))
alshabibfd430b62015-12-16 18:56:38 -0800887 .limit(1)
888 .findFirst().orElse(null);
889 }
890
891 private TrafficSelector buildSelector(Criterion... criteria) {
892
893
894 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
895
896 for (Criterion c : criteria) {
897 sBuilder.add(c);
898 }
899
900 return sBuilder.build();
901 }
902
903 private TrafficTreatment buildTreatment(Instruction... instructions) {
904
905
906 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
907
Gamze Abakae5b14612018-12-24 13:17:12 +0000908 Arrays.stream(instructions).filter(Objects::nonNull).forEach(tBuilder::add);
alshabibfd430b62015-12-16 18:56:38 -0800909
910 return tBuilder.build();
911 }
912
Gamze Abakae5b14612018-12-24 13:17:12 +0000913 private Instruction writeMetadataIncludingOnlyTp(ForwardingObjective fwd) {
914
915 return Instructions.writeMetadata(
916 fetchWriteMetadata(fwd).metadata() & 0xFFFF00000000L, 0L);
917 }
alshabibfd430b62015-12-16 18:56:38 -0800918
919 private void fail(Objective obj, ObjectiveError error) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800920 obj.context().ifPresent(context -> context.onError(obj, error));
alshabibfd430b62015-12-16 18:56:38 -0800921 }
922
923 private void pass(Objective obj) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800924 obj.context().ifPresent(context -> context.onSuccess(obj));
alshabibfd430b62015-12-16 18:56:38 -0800925 }
926
alshabib2cc73cb2015-06-30 20:26:56 -0700927
alshabibd61b77b2016-02-01 23:30:53 -0800928 private class InnerGroupListener implements GroupListener {
alshabib2cc73cb2015-06-30 20:26:56 -0700929 @Override
alshabibd61b77b2016-02-01 23:30:53 -0800930 public void event(GroupEvent event) {
ke hanf5086672016-08-12 11:09:17 +0800931 if (event.type() == GroupEvent.Type.GROUP_ADDED ||
Gamze Abakab5c60cb2018-09-12 10:55:35 +0000932 event.type() == GroupEvent.Type.GROUP_UPDATED) {
alshabibd61b77b2016-02-01 23:30:53 -0800933 GroupKey key = event.subject().appCookie();
alshabib2cc73cb2015-06-30 20:26:56 -0700934
alshabibd61b77b2016-02-01 23:30:53 -0800935 NextObjective obj = pendingGroups.getIfPresent(key);
936 if (obj != null) {
937 flowObjectiveStore.putNextGroup(obj.id(), new OLTPipelineGroup(key));
938 pass(obj);
939 pendingGroups.invalidate(key);
940 }
941 }
alshabib2cc73cb2015-06-30 20:26:56 -0700942 }
943 }
944
alshabibd61b77b2016-02-01 23:30:53 -0800945 private static class OLTPipelineGroup implements NextGroup {
946
947 private final GroupKey key;
948
949 public OLTPipelineGroup(GroupKey key) {
950 this.key = key;
951 }
952
953 public GroupKey key() {
954 return key;
955 }
956
957 @Override
958 public byte[] data() {
959 return appKryo.serialize(key);
960 }
961
962 }
Saurav Das24431192016-03-07 19:13:00 -0800963
964 @Override
965 public List<String> getNextMappings(NextGroup nextGroup) {
966 // TODO Implementation deferred to vendor
967 return null;
968 }
alshabib0ccde6d2015-05-30 18:22:36 -0700969}