blob: a54a1404c433dd09c3719f7a955ef27722085c1a [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
abakagamze124d6a12019-05-31 15:42:22 +0300467 // Required to differentiate the same match flows
468 // Please note that S tag and S p bit values will be same for the same service - so conflict flows!
469 // Metadata match criteria solves the conflict issue - but not used by the voltha
470 // Maybe - find a better way to solve the above problem
471 Criterion metadata = Criteria.matchMetadata(innerVlan.toShort());
472
473 TrafficSelector outerSelector = buildSelector(inport, metadata, outerVlan);
Gamze Abakadadae722018-09-12 10:55:35 +0000474
475 if (innerVlan.toShort() == VlanId.ANY_VALUE) {
476 installDownstreamRulesForAnyVlan(fwd, output, outerSelector, buildSelector(inport,
477 Criteria.matchVlanId(VlanId.ANY)));
478 } else {
479 installDownstreamRulesForVlans(fwd, output, outerSelector, buildSelector(inport, innerVid));
480 }
481 }
482
483 private void installDownstreamRulesForVlans(ForwardingObjective fwd, Instruction output,
484 TrafficSelector outerSelector, TrafficSelector innerSelector) {
485
486 List<Pair<Instruction, Instruction>> vlanOps =
487 vlanOps(fwd,
488 L2ModificationInstruction.L2SubType.VLAN_POP);
489
490 if (vlanOps == null || vlanOps.isEmpty()) {
491 return;
492 }
493
494 Pair<Instruction, Instruction> popAndRewrite = vlanOps.remove(0);
495
496 TrafficTreatment innerTreatment;
497 VlanId setVlanId = ((L2ModificationInstruction.ModVlanIdInstruction) popAndRewrite.getRight()).vlanId();
498 if (VlanId.NONE.equals(setVlanId)) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000499 innerTreatment = (buildTreatment(popAndRewrite.getLeft(), fetchMeter(fwd),
500 writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000501 } else {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000502 innerTreatment = (buildTreatment(popAndRewrite.getLeft(), popAndRewrite.getRight(),
503 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000504 }
505
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000506 //match: in port (nni), s-tag
507 //action: pop vlan (s-tag), write metadata, go to table 1, meter
alshabibfa0dc662016-01-13 11:23:53 -0800508 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700509 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800510 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800511 .makePermanent()
512 .withPriority(fwd.priority())
Gamze Abakadadae722018-09-12 10:55:35 +0000513 .withSelector(outerSelector)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000514 .withTreatment(buildTreatment(popAndRewrite.getLeft(), fetchMeter(fwd), fetchWriteMetadata(fwd),
Gamze Abakadadae722018-09-12 10:55:35 +0000515 Instructions.transition(QQ_TABLE)));
alshabibfd430b62015-12-16 18:56:38 -0800516
Gamze Abakadadae722018-09-12 10:55:35 +0000517 //match: in port (nni), c-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000518 //action: immediate: write metadata and pop, meter, output
alshabibfa0dc662016-01-13 11:23:53 -0800519 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700520 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800521 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800522 .forTable(QQ_TABLE)
523 .makePermanent()
524 .withPriority(fwd.priority())
Gamze Abakadadae722018-09-12 10:55:35 +0000525 .withSelector(innerSelector)
526 .withTreatment(innerTreatment);
527 applyRules(fwd, inner, outer);
528 }
529
530 private void installDownstreamRulesForAnyVlan(ForwardingObjective fwd, Instruction output,
531 TrafficSelector outerSelector, TrafficSelector innerSelector) {
532
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000533 //match: in port (nni), s-tag
534 //action: immediate: write metadata, pop vlan, meter and go to table 1
Gamze Abakadadae722018-09-12 10:55:35 +0000535 FlowRule.Builder outer = DefaultFlowRule.builder()
536 .fromApp(fwd.appId())
537 .forDevice(deviceId)
538 .makePermanent()
539 .withPriority(fwd.priority())
540 .withSelector(outerSelector)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000541 .withTreatment(buildTreatment(Instructions.popVlan(), fetchMeter(fwd),
542 fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE)));
Gamze Abakadadae722018-09-12 10:55:35 +0000543
544 //match: in port (nni) and s-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000545 //action: immediate : write metadata, meter and output
Gamze Abakadadae722018-09-12 10:55:35 +0000546 FlowRule.Builder inner = DefaultFlowRule.builder()
547 .fromApp(fwd.appId())
548 .forDevice(deviceId)
549 .forTable(QQ_TABLE)
550 .makePermanent()
551 .withPriority(fwd.priority())
552 .withSelector(innerSelector)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000553 .withTreatment(buildTreatment(fetchMeter(fwd),
554 writeMetadataIncludingOnlyTp(fwd), output));
alshabibfd430b62015-12-16 18:56:38 -0800555
556 applyRules(fwd, inner, outer);
alshabibfd430b62015-12-16 18:56:38 -0800557 }
558
559 private void installUpstreamRules(ForwardingObjective fwd) {
560 List<Pair<Instruction, Instruction>> vlanOps =
561 vlanOps(fwd,
562 L2ModificationInstruction.L2SubType.VLAN_PUSH);
563
Gamze Abakadadae722018-09-12 10:55:35 +0000564 if (vlanOps == null || vlanOps.isEmpty()) {
alshabibfd430b62015-12-16 18:56:38 -0800565 return;
566 }
567
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000568 Instruction output = fetchOutput(fwd, UPSTREAM);
alshabibfd430b62015-12-16 18:56:38 -0800569
570 if (output == null) {
571 return;
572 }
573
574 Pair<Instruction, Instruction> innerPair = vlanOps.remove(0);
alshabibfd430b62015-12-16 18:56:38 -0800575 Pair<Instruction, Instruction> outerPair = vlanOps.remove(0);
576
Gamze Abakadadae722018-09-12 10:55:35 +0000577 boolean noneValueVlanStatus = checkNoneVlanCriteria(fwd);
578 boolean anyValueVlanStatus = checkAnyVlanMatchCriteria(fwd);
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700579
Gamze Abakadadae722018-09-12 10:55:35 +0000580 if (anyValueVlanStatus) {
581 installUpstreamRulesForAnyVlan(fwd, output, outerPair);
582 } else {
583 installUpstreamRulesForVlans(fwd, output, innerPair, outerPair, noneValueVlanStatus);
584 }
585 }
586
587 private void installUpstreamRulesForVlans(ForwardingObjective fwd, Instruction output,
588 Pair<Instruction, Instruction> innerPair,
589 Pair<Instruction, Instruction> outerPair, Boolean noneValueVlanStatus) {
590
591 TrafficTreatment innerTreatment;
592 if (noneValueVlanStatus) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000593 innerTreatment = buildTreatment(innerPair.getLeft(), innerPair.getRight(), fetchMeter(fwd),
594 fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE));
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700595 } else {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000596 innerTreatment = buildTreatment(innerPair.getRight(), fetchMeter(fwd), fetchWriteMetadata(fwd),
597 Instructions.transition(QQ_TABLE));
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700598 }
599
Gamze Abakadadae722018-09-12 10:55:35 +0000600 //match: in port, vlanId (0 or None)
601 //action:
602 //if vlanId None, push & set c-tag go to table 1
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000603 //if vlanId 0 or any specific vlan, set c-tag, write metadata, meter and go to table 1
alshabibfd430b62015-12-16 18:56:38 -0800604 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700605 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800606 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800607 .makePermanent()
608 .withPriority(fwd.priority())
609 .withSelector(fwd.selector())
Gamze Abakadadae722018-09-12 10:55:35 +0000610 .withTreatment(innerTreatment);
alshabibfd430b62015-12-16 18:56:38 -0800611
612 PortCriterion inPort = (PortCriterion)
613 fwd.selector().getCriterion(Criterion.Type.IN_PORT);
614
615 VlanId cVlanId = ((L2ModificationInstruction.ModVlanIdInstruction)
616 innerPair.getRight()).vlanId();
617
Gamze Abakadadae722018-09-12 10:55:35 +0000618 //match: in port, c-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000619 //action: immediate: push s-tag, write metadata, meter and output
alshabibfd430b62015-12-16 18:56:38 -0800620 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700621 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800622 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800623 .forTable(QQ_TABLE)
624 .makePermanent()
625 .withPriority(fwd.priority())
Gamze Abakadadae722018-09-12 10:55:35 +0000626 .withSelector(buildSelector(inPort, Criteria.matchVlanId(cVlanId)))
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000627 .withTreatment(buildTreatment(outerPair.getLeft(), outerPair.getRight(),
628 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd), output));
alshabibfd430b62015-12-16 18:56:38 -0800629
630 applyRules(fwd, inner, outer);
Gamze Abakadadae722018-09-12 10:55:35 +0000631 }
alshabibfd430b62015-12-16 18:56:38 -0800632
Gamze Abakadadae722018-09-12 10:55:35 +0000633 private void installUpstreamRulesForAnyVlan(ForwardingObjective fwd, Instruction output,
634 Pair<Instruction, Instruction> outerPair) {
635
636 log.debug("Installing upstream rules for any value vlan");
637
638 //match: in port and any-vlan (coming from OLT app.)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000639 //action: write metadata, go to table 1 and meter
Gamze Abakadadae722018-09-12 10:55:35 +0000640 FlowRule.Builder inner = DefaultFlowRule.builder()
641 .fromApp(fwd.appId())
642 .forDevice(deviceId)
643 .makePermanent()
644 .withPriority(fwd.priority())
645 .withSelector(fwd.selector())
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000646 .withTreatment(buildTreatment(Instructions.transition(QQ_TABLE), fetchMeter(fwd),
647 fetchWriteMetadata(fwd)));
Gamze Abakadadae722018-09-12 10:55:35 +0000648
649
650 TrafficSelector defaultSelector = DefaultTrafficSelector.builder()
651 .matchInPort(((PortCriterion) fwd.selector().getCriterion(Criterion.Type.IN_PORT)).port())
652 .build();
653
654 //drop the packets that don't have vlan
655 //match: in port
656 //action: no action
657 FlowRule.Builder defaultInner = DefaultFlowRule.builder()
658 .fromApp(fwd.appId())
659 .forDevice(deviceId)
660 .makePermanent()
661 .withPriority(NO_ACTION_PRIORITY)
662 .withSelector(defaultSelector)
663 .withTreatment(DefaultTrafficTreatment.emptyTreatment());
664
665 Instruction qinqInstruction = Instructions.pushVlan(EthType.EtherType.QINQ.ethType());
666
667 //match: in port and any-vlan (coming from OLT app.)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000668 //action: immediate: push:QinQ, vlanId (s-tag), write metadata, meter and output
Gamze Abakadadae722018-09-12 10:55:35 +0000669 FlowRule.Builder outer = DefaultFlowRule.builder()
670 .fromApp(fwd.appId())
671 .forDevice(deviceId)
672 .forTable(QQ_TABLE)
673 .makePermanent()
674 .withPriority(fwd.priority())
675 .withSelector(fwd.selector())
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000676 .withTreatment(buildTreatment(qinqInstruction, outerPair.getRight(),
677 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000678
679 applyRules(fwd, inner, defaultInner, outer);
680 }
681
682 private boolean checkNoneVlanCriteria(ForwardingObjective fwd) {
683 // Add the VLAN_PUSH treatment if we're matching on VlanId.NONE
684 Criterion vlanMatchCriterion = filterForCriterion(fwd.selector().criteria(), Criterion.Type.VLAN_VID);
685 boolean noneValueVlanStatus = false;
686 if (vlanMatchCriterion != null) {
687 noneValueVlanStatus = ((VlanIdCriterion) vlanMatchCriterion).vlanId().equals(VlanId.NONE);
688 }
689 return noneValueVlanStatus;
690 }
691
692 private boolean checkAnyVlanMatchCriteria(ForwardingObjective fwd) {
693 Criterion anyValueVlanCriterion = fwd.selector().criteria().stream()
694 .filter(c -> c.type().equals(Criterion.Type.VLAN_VID))
695 .filter(vc -> ((VlanIdCriterion) vc).vlanId().toShort() == VlanId.ANY_VALUE)
696 .findAny().orElse(null);
697
698 if (anyValueVlanCriterion == null) {
699 log.debug("Any value vlan match criteria is not found");
700 return false;
701 }
702
703 return true;
alshabibfd430b62015-12-16 18:56:38 -0800704 }
705
706 private Instruction fetchOutput(ForwardingObjective fwd, String direction) {
707 Instruction output = fwd.treatment().allInstructions().stream()
708 .filter(i -> i.type() == Instruction.Type.OUTPUT)
709 .findFirst().orElse(null);
710
711 if (output == null) {
712 log.error("OLT {} rule has no output", direction);
713 fail(fwd, ObjectiveError.BADPARAMS);
714 return null;
715 }
716 return output;
717 }
718
Gamze Abakadadae722018-09-12 10:55:35 +0000719 private Instruction fetchMeter(ForwardingObjective fwd) {
720 Instruction meter = fwd.treatment().metered();
721
722 if (meter == null) {
723 log.debug("Meter instruction is not found for the forwarding objective {}", fwd);
724 return null;
725 }
726
727 log.debug("Meter instruction is found.");
728 return meter;
729 }
730
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000731 private Instructions.MetadataInstruction fetchWriteMetadata(ForwardingObjective fwd) {
732 Instructions.MetadataInstruction writeMetadata = fwd.treatment().writeMetadata();
Gamze Abakadadae722018-09-12 10:55:35 +0000733
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000734 if (writeMetadata == null) {
735 log.warn("Write metadata is not found for the forwarding obj");
736 fail(fwd, ObjectiveError.BADPARAMS);
Gamze Abakadadae722018-09-12 10:55:35 +0000737 return null;
738 }
739
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000740 log.debug("Write metadata is found {}", writeMetadata);
741 return writeMetadata;
Gamze Abakadadae722018-09-12 10:55:35 +0000742 }
743
alshabibfd430b62015-12-16 18:56:38 -0800744 private List<Pair<Instruction, Instruction>> vlanOps(ForwardingObjective fwd,
745 L2ModificationInstruction.L2SubType type) {
746
747 List<Pair<Instruction, Instruction>> vlanOps = findVlanOps(
748 fwd.treatment().allInstructions(), type);
749
Gamze Abakadadae722018-09-12 10:55:35 +0000750 if (vlanOps == null || vlanOps.isEmpty()) {
alshabibfd430b62015-12-16 18:56:38 -0800751 String direction = type == L2ModificationInstruction.L2SubType.VLAN_POP
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000752 ? DOWNSTREAM : UPSTREAM;
alshabibfd430b62015-12-16 18:56:38 -0800753 log.error("Missing vlan operations in {} forwarding: {}", direction, fwd);
754 fail(fwd, ObjectiveError.BADPARAMS);
Gamze Abakadadae722018-09-12 10:55:35 +0000755 return ImmutableList.of();
alshabibfd430b62015-12-16 18:56:38 -0800756 }
757 return vlanOps;
758 }
759
760
761 private List<Pair<Instruction, Instruction>> findVlanOps(List<Instruction> instructions,
alshabibd61b77b2016-02-01 23:30:53 -0800762 L2ModificationInstruction.L2SubType type) {
alshabibfd430b62015-12-16 18:56:38 -0800763
764 List<Instruction> vlanPushs = findL2Instructions(
765 type,
766 instructions);
767 List<Instruction> vlanSets = findL2Instructions(
768 L2ModificationInstruction.L2SubType.VLAN_ID,
769 instructions);
770
771 if (vlanPushs.size() != vlanSets.size()) {
Gamze Abakadadae722018-09-12 10:55:35 +0000772 return ImmutableList.of();
alshabibfd430b62015-12-16 18:56:38 -0800773 }
774
775 List<Pair<Instruction, Instruction>> pairs = Lists.newArrayList();
776
777 for (int i = 0; i < vlanPushs.size(); i++) {
778 pairs.add(new ImmutablePair<>(vlanPushs.get(i), vlanSets.get(i)));
779 }
780 return pairs;
781 }
782
783 private List<Instruction> findL2Instructions(L2ModificationInstruction.L2SubType subType,
784 List<Instruction> actions) {
785 return actions.stream()
786 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
787 .filter(i -> ((L2ModificationInstruction) i).subtype() == subType)
788 .collect(Collectors.toList());
789 }
790
Amit Ghoshf1f22752018-08-14 07:28:01 +0100791 private void provisionEthTypeBasedFilter(FilteringObjective filter,
792 EthTypeCriterion ethType,
793 Instructions.OutputInstruction output) {
alshabibfd430b62015-12-16 18:56:38 -0800794
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000795 Instruction meter = filter.meta().metered();
796 Instruction writeMetadata = filter.meta().writeMetadata();
797
Gamze Abakaf57ef602019-03-11 06:52:48 +0000798 Criterion vlanId = filterForCriterion(filter.conditions(), Criterion.Type.VLAN_VID);
799
800 TrafficSelector selector = buildSelector(filter.key(), ethType, vlanId);
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000801 TrafficTreatment treatment = buildTreatment(output, meter, writeMetadata);
alshabibfd430b62015-12-16 18:56:38 -0800802 buildAndApplyRule(filter, selector, treatment);
803
804 }
805
Jonathan Hart51539b82015-10-29 09:53:04 -0700806 private void provisionIgmp(FilteringObjective filter, EthTypeCriterion ethType,
alshabibfd430b62015-12-16 18:56:38 -0800807 IPProtocolCriterion ipProto,
808 Instructions.OutputInstruction output) {
Gamze Abaka7c070c82019-02-21 14:40:18 +0000809
810 Instruction meter = filter.meta().metered();
811 Instruction writeMetadata = filter.meta().writeMetadata();
812
alshabibfd430b62015-12-16 18:56:38 -0800813 TrafficSelector selector = buildSelector(filter.key(), ethType, ipProto);
Gamze Abaka7c070c82019-02-21 14:40:18 +0000814 TrafficTreatment treatment = buildTreatment(output, meter, writeMetadata);
alshabibfd430b62015-12-16 18:56:38 -0800815 buildAndApplyRule(filter, selector, treatment);
816 }
817
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000818 private void provisionDhcp(FilteringObjective filter, EthTypeCriterion ethType,
819 IPProtocolCriterion ipProto,
820 UdpPortCriterion udpSrcPort,
821 UdpPortCriterion udpDstPort,
822 Instructions.OutputInstruction output) {
Gamze Abaka7c070c82019-02-21 14:40:18 +0000823
824 Instruction meter = filter.meta().metered();
825 Instruction writeMetadata = filter.meta().writeMetadata();
826
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000827 TrafficSelector selector = buildSelector(filter.key(), ethType, ipProto, udpSrcPort, udpDstPort);
Gamze Abaka7c070c82019-02-21 14:40:18 +0000828 TrafficTreatment treatment = buildTreatment(output, meter, writeMetadata);
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000829 buildAndApplyRule(filter, selector, treatment);
830 }
Gamze Abakadadae722018-09-12 10:55:35 +0000831
alshabibfd430b62015-12-16 18:56:38 -0800832 private void buildAndApplyRule(FilteringObjective filter, TrafficSelector selector,
833 TrafficTreatment treatment) {
834 FlowRule rule = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700835 .fromApp(filter.appId())
alshabibfd430b62015-12-16 18:56:38 -0800836 .forDevice(deviceId)
837 .forTable(0)
alshabibfd430b62015-12-16 18:56:38 -0800838 .makePermanent()
839 .withSelector(selector)
840 .withTreatment(treatment)
alshabibbb424232016-01-15 12:20:25 -0800841 .withPriority(filter.priority())
alshabibfd430b62015-12-16 18:56:38 -0800842 .build();
843
844 FlowRuleOperations.Builder opsBuilder = FlowRuleOperations.builder();
845
846 switch (filter.type()) {
847 case PERMIT:
848 opsBuilder.add(rule);
849 break;
850 case DENY:
851 opsBuilder.remove(rule);
852 break;
853 default:
854 log.warn("Unknown filter type : {}", filter.type());
855 fail(filter, ObjectiveError.UNSUPPORTED);
856 }
857
858 applyFlowRules(opsBuilder, filter);
859 }
860
Gamze Abakadadae722018-09-12 10:55:35 +0000861 private void applyRules(ForwardingObjective fwd, FlowRule.Builder... fwdBuilders) {
Amit Ghoshf1f22752018-08-14 07:28:01 +0100862 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
863 switch (fwd.op()) {
864 case ADD:
Gamze Abakadadae722018-09-12 10:55:35 +0000865 for (FlowRule.Builder fwdBuilder : fwdBuilders) {
866 builder.add(fwdBuilder.build());
867 }
Amit Ghoshf1f22752018-08-14 07:28:01 +0100868 break;
869 case REMOVE:
Gamze Abakadadae722018-09-12 10:55:35 +0000870 for (FlowRule.Builder fwdBuilder : fwdBuilders) {
871 builder.remove(fwdBuilder.build());
872 }
alshabibfd430b62015-12-16 18:56:38 -0800873 break;
874 case ADD_TO_EXISTING:
875 break;
876 case REMOVE_FROM_EXISTING:
877 break;
878 default:
879 log.warn("Unknown forwarding operation: {}", fwd.op());
880 }
881
882 applyFlowRules(builder, fwd);
883 }
884
885 private void applyFlowRules(FlowRuleOperations.Builder builder,
886 Objective objective) {
887 flowRuleService.apply(builder.build(new FlowRuleOperationsContext() {
888 @Override
889 public void onSuccess(FlowRuleOperations ops) {
890 pass(objective);
891 }
892
893 @Override
894 public void onError(FlowRuleOperations ops) {
895 fail(objective, ObjectiveError.FLOWINSTALLATIONFAILED);
896 }
897 }));
898 }
899
900 private Criterion filterForCriterion(Collection<Criterion> criteria, Criterion.Type type) {
901 return criteria.stream()
alshabibbb424232016-01-15 12:20:25 -0800902 .filter(c -> c.type().equals(type))
alshabibfd430b62015-12-16 18:56:38 -0800903 .limit(1)
904 .findFirst().orElse(null);
905 }
906
907 private TrafficSelector buildSelector(Criterion... criteria) {
908
alshabibfd430b62015-12-16 18:56:38 -0800909 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
910
Gamze Abakaf57ef602019-03-11 06:52:48 +0000911 Arrays.stream(criteria).filter(Objects::nonNull).forEach(sBuilder::add);
alshabibfd430b62015-12-16 18:56:38 -0800912
913 return sBuilder.build();
914 }
915
916 private TrafficTreatment buildTreatment(Instruction... instructions) {
917
alshabibfd430b62015-12-16 18:56:38 -0800918 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
919
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000920 Arrays.stream(instructions).filter(Objects::nonNull).forEach(tBuilder::add);
alshabibfd430b62015-12-16 18:56:38 -0800921
922 return tBuilder.build();
923 }
924
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000925 private Instruction writeMetadataIncludingOnlyTp(ForwardingObjective fwd) {
926
927 return Instructions.writeMetadata(
928 fetchWriteMetadata(fwd).metadata() & 0xFFFF00000000L, 0L);
929 }
alshabibfd430b62015-12-16 18:56:38 -0800930
931 private void fail(Objective obj, ObjectiveError error) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800932 obj.context().ifPresent(context -> context.onError(obj, error));
alshabibfd430b62015-12-16 18:56:38 -0800933 }
934
935 private void pass(Objective obj) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800936 obj.context().ifPresent(context -> context.onSuccess(obj));
alshabibfd430b62015-12-16 18:56:38 -0800937 }
938
alshabib2cc73cb2015-06-30 20:26:56 -0700939
alshabibd61b77b2016-02-01 23:30:53 -0800940 private class InnerGroupListener implements GroupListener {
alshabib2cc73cb2015-06-30 20:26:56 -0700941 @Override
alshabibd61b77b2016-02-01 23:30:53 -0800942 public void event(GroupEvent event) {
ke hanf5086672016-08-12 11:09:17 +0800943 if (event.type() == GroupEvent.Type.GROUP_ADDED ||
Gamze Abakadadae722018-09-12 10:55:35 +0000944 event.type() == GroupEvent.Type.GROUP_UPDATED) {
alshabibd61b77b2016-02-01 23:30:53 -0800945 GroupKey key = event.subject().appCookie();
alshabib2cc73cb2015-06-30 20:26:56 -0700946
alshabibd61b77b2016-02-01 23:30:53 -0800947 NextObjective obj = pendingGroups.getIfPresent(key);
948 if (obj != null) {
949 flowObjectiveStore.putNextGroup(obj.id(), new OLTPipelineGroup(key));
950 pass(obj);
951 pendingGroups.invalidate(key);
952 }
953 }
alshabib2cc73cb2015-06-30 20:26:56 -0700954 }
955 }
956
alshabibd61b77b2016-02-01 23:30:53 -0800957 private static class OLTPipelineGroup implements NextGroup {
958
959 private final GroupKey key;
960
961 public OLTPipelineGroup(GroupKey key) {
962 this.key = key;
963 }
964
965 public GroupKey key() {
966 return key;
967 }
968
969 @Override
970 public byte[] data() {
971 return appKryo.serialize(key);
972 }
973
974 }
Saurav Das24431192016-03-07 19:13:00 -0800975
976 @Override
977 public List<String> getNextMappings(NextGroup nextGroup) {
978 // TODO Implementation deferred to vendor
979 return null;
980 }
alshabib0ccde6d2015-05-30 18:22:36 -0700981}