blob: c6b1e81dfdab51fe72cf1b5517e90746a990c5fe [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;
Gamze Abakafe9d54f2019-12-02 06:42:39 +000030import org.onlab.packet.IpPrefix;
alshabibfd430b62015-12-16 18:56:38 -080031import org.onlab.packet.VlanId;
Andrea Campanellad8e07632020-06-18 10:25:59 +020032import org.onlab.util.AbstractAccumulator;
33import org.onlab.util.Accumulator;
alshabibd61b77b2016-02-01 23:30:53 -080034import org.onlab.util.KryoNamespace;
Jonathan Hartdfc3b862015-07-01 14:49:56 -070035import org.onosproject.core.ApplicationId;
36import org.onosproject.core.CoreService;
alshabib0ccde6d2015-05-30 18:22:36 -070037import org.onosproject.net.DeviceId;
38import org.onosproject.net.PortNumber;
alshabibd61b77b2016-02-01 23:30:53 -080039import org.onosproject.net.behaviour.NextGroup;
alshabib0ccde6d2015-05-30 18:22:36 -070040import org.onosproject.net.behaviour.Pipeliner;
41import org.onosproject.net.behaviour.PipelinerContext;
42import org.onosproject.net.driver.AbstractHandlerBehaviour;
Andrea Campanellad8e07632020-06-18 10:25:59 +020043import org.onosproject.net.driver.Driver;
alshabib0ccde6d2015-05-30 18:22:36 -070044import org.onosproject.net.flow.DefaultFlowRule;
Jonathan Hartdfc3b862015-07-01 14:49:56 -070045import org.onosproject.net.flow.DefaultTrafficSelector;
alshabib0ccde6d2015-05-30 18:22:36 -070046import org.onosproject.net.flow.DefaultTrafficTreatment;
47import org.onosproject.net.flow.FlowRule;
48import org.onosproject.net.flow.FlowRuleOperations;
49import org.onosproject.net.flow.FlowRuleOperationsContext;
50import org.onosproject.net.flow.FlowRuleService;
51import org.onosproject.net.flow.TrafficSelector;
52import org.onosproject.net.flow.TrafficTreatment;
alshabibfd430b62015-12-16 18:56:38 -080053import org.onosproject.net.flow.criteria.Criteria;
54import org.onosproject.net.flow.criteria.Criterion;
55import org.onosproject.net.flow.criteria.EthTypeCriterion;
alshabib1aa58142016-02-17 15:37:56 -080056import org.onosproject.net.flow.criteria.IPCriterion;
alshabibfd430b62015-12-16 18:56:38 -080057import org.onosproject.net.flow.criteria.IPProtocolCriterion;
58import org.onosproject.net.flow.criteria.PortCriterion;
Amit Ghoshcbaf8672016-12-23 21:36:19 +000059import org.onosproject.net.flow.criteria.UdpPortCriterion;
alshabib2f74f2c2016-01-14 13:29:35 -080060import org.onosproject.net.flow.criteria.VlanIdCriterion;
alshabibfd430b62015-12-16 18:56:38 -080061import org.onosproject.net.flow.instructions.Instruction;
alshabib0ccde6d2015-05-30 18:22:36 -070062import org.onosproject.net.flow.instructions.Instructions;
alshabibfd430b62015-12-16 18:56:38 -080063import org.onosproject.net.flow.instructions.L2ModificationInstruction;
alshabib0ccde6d2015-05-30 18:22:36 -070064import org.onosproject.net.flowobjective.FilteringObjective;
alshabibd61b77b2016-02-01 23:30:53 -080065import org.onosproject.net.flowobjective.FlowObjectiveStore;
alshabib0ccde6d2015-05-30 18:22:36 -070066import org.onosproject.net.flowobjective.ForwardingObjective;
67import org.onosproject.net.flowobjective.NextObjective;
alshabibfd430b62015-12-16 18:56:38 -080068import org.onosproject.net.flowobjective.Objective;
alshabib0ccde6d2015-05-30 18:22:36 -070069import org.onosproject.net.flowobjective.ObjectiveError;
alshabibd61b77b2016-02-01 23:30:53 -080070import org.onosproject.net.group.DefaultGroupBucket;
71import org.onosproject.net.group.DefaultGroupDescription;
72import org.onosproject.net.group.DefaultGroupKey;
73import org.onosproject.net.group.Group;
74import org.onosproject.net.group.GroupBucket;
75import org.onosproject.net.group.GroupBuckets;
76import org.onosproject.net.group.GroupDescription;
77import org.onosproject.net.group.GroupEvent;
78import org.onosproject.net.group.GroupKey;
79import org.onosproject.net.group.GroupListener;
80import org.onosproject.net.group.GroupService;
81import org.onosproject.store.serializers.KryoNamespaces;
alshabib5ccbe3f2016-03-02 22:36:02 -080082import org.onosproject.store.service.StorageService;
alshabib0ccde6d2015-05-30 18:22:36 -070083import org.slf4j.Logger;
84
Gamze Abakafe9d54f2019-12-02 06:42:39 +000085import java.util.Arrays;
alshabibfd430b62015-12-16 18:56:38 -080086import java.util.Collection;
alshabibd61b77b2016-02-01 23:30:53 -080087import java.util.Collections;
alshabibfd430b62015-12-16 18:56:38 -080088import java.util.List;
Gamze Abakafe9d54f2019-12-02 06:42:39 +000089import java.util.Objects;
alshabibfd430b62015-12-16 18:56:38 -080090import java.util.Optional;
Andrea Campanellad8e07632020-06-18 10:25:59 +020091import java.util.concurrent.ScheduledExecutorService;
92import java.util.Timer;
alshabibd61b77b2016-02-01 23:30:53 -080093import java.util.concurrent.TimeUnit;
alshabibfd430b62015-12-16 18:56:38 -080094import java.util.stream.Collectors;
95
Andrea Campanella969e8af2020-07-09 11:39:08 +020096import static org.onosproject.core.CoreService.CORE_APP_NAME;
Andrea Campanellad8e07632020-06-18 10:25:59 +020097import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
98import static org.onlab.util.Tools.groupedThreads;
alshabib0ccde6d2015-05-30 18:22:36 -070099import static org.slf4j.LoggerFactory.getLogger;
100
101/**
Jonathan Hart64da69d2015-07-15 15:10:28 -0700102 * Pipeliner for OLT device.
alshabib0ccde6d2015-05-30 18:22:36 -0700103 */
alshabibfd430b62015-12-16 18:56:38 -0800104
Jonathan Hartb92cc512015-11-16 23:05:21 -0800105public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
alshabib0ccde6d2015-05-30 18:22:36 -0700106
alshabibfd430b62015-12-16 18:56:38 -0800107 private static final Integer QQ_TABLE = 1;
Gamze Abakadadae722018-09-12 10:55:35 +0000108 private static final int NO_ACTION_PRIORITY = 500;
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000109 private static final String DOWNSTREAM = "downstream";
110 private static final String UPSTREAM = "upstream";
alshabib0ccde6d2015-05-30 18:22:36 -0700111 private final Logger log = getLogger(getClass());
112
113 private ServiceDirectory serviceDirectory;
114 private FlowRuleService flowRuleService;
alshabibd61b77b2016-02-01 23:30:53 -0800115 private GroupService groupService;
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700116 private CoreService coreService;
alshabib5ccbe3f2016-03-02 22:36:02 -0800117 private StorageService storageService;
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700118
alshabibd61b77b2016-02-01 23:30:53 -0800119 private DeviceId deviceId;
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700120 private ApplicationId appId;
alshabib83364472016-03-25 09:59:55 -0700121
alshabib0ccde6d2015-05-30 18:22:36 -0700122
alshabibd61b77b2016-02-01 23:30:53 -0800123 protected FlowObjectiveStore flowObjectiveStore;
124
125 private Cache<GroupKey, NextObjective> pendingGroups;
126
127 protected static KryoNamespace appKryo = new KryoNamespace.Builder()
128 .register(KryoNamespaces.API)
129 .register(GroupKey.class)
130 .register(DefaultGroupKey.class)
131 .register(OLTPipelineGroup.class)
Charles Chaneefdedf2016-05-23 16:45:45 -0700132 .build("OltPipeline");
alshabib2cc73cb2015-06-30 20:26:56 -0700133
Andrea Campanellad8e07632020-06-18 10:25:59 +0200134 private static final Timer TIMER = new Timer("filterobj-batching");
135 private Accumulator<Pair<FilteringObjective, FlowRule>> accumulator;
136
137 // accumulator executor service
138 private ScheduledExecutorService accumulatorExecutorService
139 = newSingleThreadScheduledExecutor(groupedThreads("OltPipeliner", "acc-%d", log));
140
alshabib0ccde6d2015-05-30 18:22:36 -0700141 @Override
142 public void init(DeviceId deviceId, PipelinerContext context) {
alshabibfd430b62015-12-16 18:56:38 -0800143 log.debug("Initiate OLT pipeline");
alshabib0ccde6d2015-05-30 18:22:36 -0700144 this.serviceDirectory = context.directory();
145 this.deviceId = deviceId;
alshabibd61b77b2016-02-01 23:30:53 -0800146
alshabib0ccde6d2015-05-30 18:22:36 -0700147 flowRuleService = serviceDirectory.get(FlowRuleService.class);
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700148 coreService = serviceDirectory.get(CoreService.class);
alshabibd61b77b2016-02-01 23:30:53 -0800149 groupService = serviceDirectory.get(GroupService.class);
150 flowObjectiveStore = context.store();
alshabib5ccbe3f2016-03-02 22:36:02 -0800151 storageService = serviceDirectory.get(StorageService.class);
152
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700153 appId = coreService.registerApplication(
154 "org.onosproject.driver.OLTPipeline");
155
Andrea Campanellad8e07632020-06-18 10:25:59 +0200156 // Init the accumulator, if enabled
157 if (isAccumulatorEnabled()) {
158 log.debug("Building accumulator with maxObjs {}, batchMs {}, idleMs {}",
159 context.accumulatorMaxObjectives(), context.accumulatorMaxBatchMillis(),
160 context.accumulatorMaxIdleMillis());
161 accumulator = new ObjectiveAccumulator(context.accumulatorMaxObjectives(),
162 context.accumulatorMaxBatchMillis(),
163 context.accumulatorMaxIdleMillis());
164 }
165
alshabibd61b77b2016-02-01 23:30:53 -0800166
167 pendingGroups = CacheBuilder.newBuilder()
168 .expireAfterWrite(20, TimeUnit.SECONDS)
169 .removalListener((RemovalNotification<GroupKey, NextObjective> notification) -> {
170 if (notification.getCause() == RemovalCause.EXPIRED) {
171 fail(notification.getValue(), ObjectiveError.GROUPINSTALLATIONFAILED);
172 }
173 }).build();
174
175 groupService.addListener(new InnerGroupListener());
176
alshabibb32cefe2015-06-08 18:15:05 -0700177 }
178
Andrea Campanellad8e07632020-06-18 10:25:59 +0200179 public boolean isAccumulatorEnabled() {
180 Driver driver = super.data().driver();
181 // we cannot determine the property
182 if (driver == null) {
183 return false;
184 }
185 return Boolean.parseBoolean(driver.getProperty(ACCUMULATOR_ENABLED));
186 }
187
alshabib0ccde6d2015-05-30 18:22:36 -0700188 @Override
189 public void filter(FilteringObjective filter) {
alshabibfd430b62015-12-16 18:56:38 -0800190 Instructions.OutputInstruction output;
alshabib0ccde6d2015-05-30 18:22:36 -0700191
alshabibfd430b62015-12-16 18:56:38 -0800192 if (filter.meta() != null && !filter.meta().immediate().isEmpty()) {
193 output = (Instructions.OutputInstruction) filter.meta().immediate().stream()
194 .filter(t -> t.type().equals(Instruction.Type.OUTPUT))
195 .limit(1)
196 .findFirst().get();
alshabib0ccde6d2015-05-30 18:22:36 -0700197
alshabibbb424232016-01-15 12:20:25 -0800198 if (output == null || !output.port().equals(PortNumber.CONTROLLER)) {
dvaddire8e6b89a2017-08-31 21:54:03 +0530199 log.warn("OLT can only filter packet to controller");
alshabibfd430b62015-12-16 18:56:38 -0800200 fail(filter, ObjectiveError.UNSUPPORTED);
201 return;
alshabib0ccde6d2015-05-30 18:22:36 -0700202 }
alshabibfd430b62015-12-16 18:56:38 -0800203 } else {
204 fail(filter, ObjectiveError.BADPARAMS);
alshabib0ccde6d2015-05-30 18:22:36 -0700205 return;
206 }
207
alshabibfd430b62015-12-16 18:56:38 -0800208 if (filter.key().type() != Criterion.Type.IN_PORT) {
209 fail(filter, ObjectiveError.BADPARAMS);
210 return;
211 }
212
213 EthTypeCriterion ethType = (EthTypeCriterion)
214 filterForCriterion(filter.conditions(), Criterion.Type.ETH_TYPE);
215
216 if (ethType == null) {
217 fail(filter, ObjectiveError.BADPARAMS);
218 return;
219 }
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200220 Optional<Instruction> vlanId = filter.meta().immediate().stream()
221 .filter(t -> t.type().equals(Instruction.Type.L2MODIFICATION)
222 && ((L2ModificationInstruction) t).subtype()
223 .equals(L2ModificationInstruction.L2SubType.VLAN_ID))
224 .limit(1)
225 .findFirst();
226
227 Optional<Instruction> vlanPcp = filter.meta().immediate().stream()
228 .filter(t -> t.type().equals(Instruction.Type.L2MODIFICATION)
229 && ((L2ModificationInstruction) t).subtype()
230 .equals(L2ModificationInstruction.L2SubType.VLAN_PCP))
231 .limit(1)
232 .findFirst();
233
234 Optional<Instruction> vlanPush = filter.meta().immediate().stream()
235 .filter(t -> t.type().equals(Instruction.Type.L2MODIFICATION)
236 && ((L2ModificationInstruction) t).subtype()
237 .equals(L2ModificationInstruction.L2SubType.VLAN_PUSH))
238 .limit(1)
239 .findFirst();
alshabibfd430b62015-12-16 18:56:38 -0800240
alshabibbb424232016-01-15 12:20:25 -0800241 if (ethType.ethType().equals(EthType.EtherType.EAPOL.ethType())) {
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200242
243 if (vlanId.isEmpty() || vlanPush.isEmpty()) {
244 log.warn("Missing EAPOL vlan or vlanPush");
245 fail(filter, ObjectiveError.BADPARAMS);
246 return;
247 }
248 provisionEthTypeBasedFilter(filter, ethType, output,
249 (L2ModificationInstruction) vlanId.get(),
250 (L2ModificationInstruction) vlanPush.get());
Amit Ghoshf1f22752018-08-14 07:28:01 +0100251 } else if (ethType.ethType().equals(EthType.EtherType.LLDP.ethType())) {
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200252 provisionEthTypeBasedFilter(filter, ethType, output, null, null);
Amit Ghoshf1f22752018-08-14 07:28:01 +0100253
alshabibbb424232016-01-15 12:20:25 -0800254 } else if (ethType.ethType().equals(EthType.EtherType.IPV4.ethType())) {
alshabibfd430b62015-12-16 18:56:38 -0800255 IPProtocolCriterion ipProto = (IPProtocolCriterion)
256 filterForCriterion(filter.conditions(), Criterion.Type.IP_PROTO);
dvaddire8e6b89a2017-08-31 21:54:03 +0530257 if (ipProto == null) {
258 log.warn("OLT can only filter IGMP and DHCP");
259 fail(filter, ObjectiveError.UNSUPPORTED);
260 return;
261 }
alshabibfd430b62015-12-16 18:56:38 -0800262 if (ipProto.protocol() == IPv4.PROTOCOL_IGMP) {
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200263 provisionIgmp(filter, ethType, ipProto, output,
Andrea Campanella79bc5062020-09-21 14:34:00 +0200264 vlanId.orElse(null),
265 vlanPcp.orElse(null));
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000266 } else if (ipProto.protocol() == IPv4.PROTOCOL_UDP) {
267 UdpPortCriterion udpSrcPort = (UdpPortCriterion)
268 filterForCriterion(filter.conditions(), Criterion.Type.UDP_SRC);
269
270 UdpPortCriterion udpDstPort = (UdpPortCriterion)
271 filterForCriterion(filter.conditions(), Criterion.Type.UDP_DST);
272
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700273 if ((udpSrcPort.udpPort().toInt() == 67 && udpDstPort.udpPort().toInt() == 68) ||
274 (udpSrcPort.udpPort().toInt() == 68 && udpDstPort.udpPort().toInt() == 67)) {
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200275 provisionDhcp(filter, ethType, ipProto, udpSrcPort, udpDstPort, vlanId.orElse(null),
276 vlanPcp.orElse(null), output);
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700277 } else {
278 log.warn("Filtering rule with unsupported UDP src {} or dst {} port", udpSrcPort, udpDstPort);
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000279 fail(filter, ObjectiveError.UNSUPPORTED);
280 }
alshabibbb424232016-01-15 12:20:25 -0800281 } else {
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700282 log.warn("Currently supporting only IGMP and DHCP filters for IPv4 packets");
283 fail(filter, ObjectiveError.UNSUPPORTED);
284 }
285 } else if (ethType.ethType().equals(EthType.EtherType.IPV6.ethType())) {
286 IPProtocolCriterion ipProto = (IPProtocolCriterion)
287 filterForCriterion(filter.conditions(), Criterion.Type.IP_PROTO);
288 if (ipProto == null) {
289 log.warn("OLT can only filter DHCP");
290 fail(filter, ObjectiveError.UNSUPPORTED);
291 return;
292 }
293 if (ipProto.protocol() == IPv6.PROTOCOL_UDP) {
294 UdpPortCriterion udpSrcPort = (UdpPortCriterion)
295 filterForCriterion(filter.conditions(), Criterion.Type.UDP_SRC);
296
297 UdpPortCriterion udpDstPort = (UdpPortCriterion)
298 filterForCriterion(filter.conditions(), Criterion.Type.UDP_DST);
299
300 if ((udpSrcPort.udpPort().toInt() == 546 && udpDstPort.udpPort().toInt() == 547) ||
301 (udpSrcPort.udpPort().toInt() == 547 && udpDstPort.udpPort().toInt() == 546)) {
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200302 provisionDhcp(filter, ethType, ipProto, udpSrcPort, udpDstPort, vlanId.orElse(null),
303 vlanPcp.orElse(null), output);
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700304 } else {
305 log.warn("Filtering rule with unsupported UDP src {} or dst {} port", udpSrcPort, udpDstPort);
306 fail(filter, ObjectiveError.UNSUPPORTED);
307 }
308 } else {
309 log.warn("Currently supporting only DHCP filters for IPv6 packets");
alshabibbb424232016-01-15 12:20:25 -0800310 fail(filter, ObjectiveError.UNSUPPORTED);
alshabibfd430b62015-12-16 18:56:38 -0800311 }
312 } else {
dvaddire8e6b89a2017-08-31 21:54:03 +0530313 log.warn("\nOnly the following are Supported in OLT for filter ->\n"
Amit Ghoshf1f22752018-08-14 07:28:01 +0100314 + "ETH TYPE : EAPOL, LLDP and IPV4\n"
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700315 + "IPV4 TYPE: IGMP and UDP (for DHCP)"
316 + "IPV6 TYPE: UDP (for DHCP)");
alshabibfd430b62015-12-16 18:56:38 -0800317 fail(filter, ObjectiveError.UNSUPPORTED);
318 }
319
320 }
321
322
323 @Override
324 public void forward(ForwardingObjective fwd) {
Andrea Campanella6edac322020-01-29 14:41:42 +0100325 log.debug("Installing forwarding objective {}", fwd);
alshabibd61b77b2016-02-01 23:30:53 -0800326 if (checkForMulticast(fwd)) {
327 processMulticastRule(fwd);
328 return;
329 }
330
alshabib0ccde6d2015-05-30 18:22:36 -0700331 TrafficTreatment treatment = fwd.treatment();
alshabib0ccde6d2015-05-30 18:22:36 -0700332
alshabibfd430b62015-12-16 18:56:38 -0800333 List<Instruction> instructions = treatment.allInstructions();
alshabib0ccde6d2015-05-30 18:22:36 -0700334
Gamze Abakadadae722018-09-12 10:55:35 +0000335 Optional<Instruction> vlanInstruction = instructions.stream()
alshabibfd430b62015-12-16 18:56:38 -0800336 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
337 .filter(i -> ((L2ModificationInstruction) i).subtype() ==
338 L2ModificationInstruction.L2SubType.VLAN_PUSH ||
339 ((L2ModificationInstruction) i).subtype() ==
340 L2ModificationInstruction.L2SubType.VLAN_POP)
341 .findAny();
342
Gamze Abakadadae722018-09-12 10:55:35 +0000343
344 if (!vlanInstruction.isPresent()) {
Amit Ghoshf1f22752018-08-14 07:28:01 +0100345 installNoModificationRules(fwd);
alshabib0ccde6d2015-05-30 18:22:36 -0700346 } else {
Amit Ghoshf1f22752018-08-14 07:28:01 +0100347 L2ModificationInstruction vlanIns =
Gamze Abakadadae722018-09-12 10:55:35 +0000348 (L2ModificationInstruction) vlanInstruction.get();
Amit Ghoshf1f22752018-08-14 07:28:01 +0100349 if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
350 installUpstreamRules(fwd);
351 } else if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP) {
352 installDownstreamRules(fwd);
353 } else {
354 log.error("Unknown OLT operation: {}", fwd);
355 fail(fwd, ObjectiveError.UNSUPPORTED);
356 return;
357 }
alshabib0ccde6d2015-05-30 18:22:36 -0700358 }
359
alshabibfd430b62015-12-16 18:56:38 -0800360 pass(fwd);
alshabib0ccde6d2015-05-30 18:22:36 -0700361
alshabib0ccde6d2015-05-30 18:22:36 -0700362 }
363
alshabibd61b77b2016-02-01 23:30:53 -0800364
alshabib0ccde6d2015-05-30 18:22:36 -0700365 @Override
366 public void next(NextObjective nextObjective) {
alshabibd61b77b2016-02-01 23:30:53 -0800367 if (nextObjective.type() != NextObjective.Type.BROADCAST) {
368 log.error("OLT only supports broadcast groups.");
369 fail(nextObjective, ObjectiveError.BADPARAMS);
Andrea Campanella5908b562020-05-06 16:09:10 +0200370 return;
alshabibd61b77b2016-02-01 23:30:53 -0800371 }
372
Andrea Campanella5908b562020-05-06 16:09:10 +0200373 if (nextObjective.next().size() != 1 && !nextObjective.op().equals(Objective.Operation.REMOVE)) {
alshabibd61b77b2016-02-01 23:30:53 -0800374 log.error("OLT only supports singleton broadcast groups.");
375 fail(nextObjective, ObjectiveError.BADPARAMS);
Andrea Campanella5908b562020-05-06 16:09:10 +0200376 return;
alshabibd61b77b2016-02-01 23:30:53 -0800377 }
378
Andrea Campanella5908b562020-05-06 16:09:10 +0200379 Optional<TrafficTreatment> treatmentOpt = nextObjective.next().stream().findFirst();
380 if (treatmentOpt.isEmpty() && !nextObjective.op().equals(Objective.Operation.REMOVE)) {
381 log.error("Next objective {} does not have a treatment", nextObjective);
382 fail(nextObjective, ObjectiveError.BADPARAMS);
383 return;
384 }
alshabibd61b77b2016-02-01 23:30:53 -0800385
alshabibd61b77b2016-02-01 23:30:53 -0800386 GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id()));
387
alshabibd61b77b2016-02-01 23:30:53 -0800388 pendingGroups.put(key, nextObjective);
Andrea Campanella5908b562020-05-06 16:09:10 +0200389 log.trace("NextObjective Operation {}", nextObjective.op());
alshabibd61b77b2016-02-01 23:30:53 -0800390 switch (nextObjective.op()) {
391 case ADD:
alshabib1aa58142016-02-17 15:37:56 -0800392 GroupDescription groupDesc =
393 new DefaultGroupDescription(deviceId,
394 GroupDescription.Type.ALL,
Andrea Campanella5908b562020-05-06 16:09:10 +0200395 new GroupBuckets(
396 Collections.singletonList(
397 buildBucket(treatmentOpt.get()))),
alshabib1aa58142016-02-17 15:37:56 -0800398 key,
399 null,
400 nextObjective.appId());
alshabibd61b77b2016-02-01 23:30:53 -0800401 groupService.addGroup(groupDesc);
402 break;
403 case REMOVE:
404 groupService.removeGroup(deviceId, key, nextObjective.appId());
405 break;
406 case ADD_TO_EXISTING:
alshabib1aa58142016-02-17 15:37:56 -0800407 groupService.addBucketsToGroup(deviceId, key,
Andrea Campanella5908b562020-05-06 16:09:10 +0200408 new GroupBuckets(
409 Collections.singletonList(
410 buildBucket(treatmentOpt.get()))),
alshabib1aa58142016-02-17 15:37:56 -0800411 key, nextObjective.appId());
412 break;
alshabibd61b77b2016-02-01 23:30:53 -0800413 case REMOVE_FROM_EXISTING:
alshabib1aa58142016-02-17 15:37:56 -0800414 groupService.removeBucketsFromGroup(deviceId, key,
Andrea Campanella5908b562020-05-06 16:09:10 +0200415 new GroupBuckets(
416 Collections.singletonList(
417 buildBucket(treatmentOpt.get()))),
alshabib56efe432016-02-25 17:57:24 -0500418 key, nextObjective.appId());
alshabibd61b77b2016-02-01 23:30:53 -0800419 break;
420 default:
421 log.warn("Unknown next objective operation: {}", nextObjective.op());
422 }
423
424
425 }
426
Andrea Campanella5908b562020-05-06 16:09:10 +0200427 private GroupBucket buildBucket(TrafficTreatment treatment) {
428 return DefaultGroupBucket.createAllGroupBucket(treatment);
429 }
430
alshabibd61b77b2016-02-01 23:30:53 -0800431 private void processMulticastRule(ForwardingObjective fwd) {
432 if (fwd.nextId() == null) {
433 log.error("Multicast objective does not have a next id");
434 fail(fwd, ObjectiveError.BADPARAMS);
435 }
436
alshabib1aa58142016-02-17 15:37:56 -0800437 GroupKey key = getGroupForNextObjective(fwd.nextId());
alshabibd61b77b2016-02-01 23:30:53 -0800438
alshabib1aa58142016-02-17 15:37:56 -0800439 if (key == null) {
alshabibd61b77b2016-02-01 23:30:53 -0800440 log.error("Group for forwarding objective missing: {}", fwd);
441 fail(fwd, ObjectiveError.GROUPMISSING);
442 }
443
alshabib1aa58142016-02-17 15:37:56 -0800444 Group group = groupService.getGroup(deviceId, key);
alshabibd61b77b2016-02-01 23:30:53 -0800445 TrafficTreatment treatment =
446 buildTreatment(Instructions.createGroup(group.id()));
447
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000448 TrafficSelector.Builder selectorBuilder = buildIpv4SelectorForMulticast(fwd);
449
alshabibd61b77b2016-02-01 23:30:53 -0800450 FlowRule rule = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700451 .fromApp(fwd.appId())
alshabibd61b77b2016-02-01 23:30:53 -0800452 .forDevice(deviceId)
453 .forTable(0)
alshabibd61b77b2016-02-01 23:30:53 -0800454 .makePermanent()
455 .withPriority(fwd.priority())
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000456 .withSelector(selectorBuilder.build())
alshabibd61b77b2016-02-01 23:30:53 -0800457 .withTreatment(treatment)
458 .build();
459
460 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
461 switch (fwd.op()) {
462
463 case ADD:
464 builder.add(rule);
465 break;
466 case REMOVE:
467 builder.remove(rule);
468 break;
469 case ADD_TO_EXISTING:
470 case REMOVE_FROM_EXISTING:
471 break;
472 default:
473 log.warn("Unknown forwarding operation: {}", fwd.op());
474 }
475
Andrea Campanellad8e07632020-06-18 10:25:59 +0200476 applyFlowRules(ImmutableList.of(fwd), builder);
477
alshabibd61b77b2016-02-01 23:30:53 -0800478
479 }
480
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000481 private TrafficSelector.Builder buildIpv4SelectorForMulticast(ForwardingObjective fwd) {
482 TrafficSelector.Builder builderToUpdate = DefaultTrafficSelector.builder();
483
484 Optional<Criterion> vlanIdCriterion = readFromSelector(fwd.meta(), Criterion.Type.VLAN_VID);
485 if (vlanIdCriterion.isPresent()) {
486 VlanId assignedVlan = ((VlanIdCriterion) vlanIdCriterion.get()).vlanId();
487 builderToUpdate.matchVlanId(assignedVlan);
488 }
489
Esin Karamanec25a0a2020-03-18 14:29:29 +0000490 Optional<Criterion> innerVlanIdCriterion = readFromSelector(fwd.meta(), Criterion.Type.INNER_VLAN_VID);
491 if (innerVlanIdCriterion.isPresent()) {
492 VlanId assignedInnerVlan = ((VlanIdCriterion) innerVlanIdCriterion.get()).vlanId();
493 builderToUpdate.matchMetadata(assignedInnerVlan.toShort());
494 }
495
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000496 Optional<Criterion> ethTypeCriterion = readFromSelector(fwd.selector(), Criterion.Type.ETH_TYPE);
497 if (ethTypeCriterion.isPresent()) {
498 EthType ethType = ((EthTypeCriterion) ethTypeCriterion.get()).ethType();
499 builderToUpdate.matchEthType(ethType.toShort());
500 }
501
502 Optional<Criterion> ipv4DstCriterion = readFromSelector(fwd.selector(), Criterion.Type.IPV4_DST);
503 if (ipv4DstCriterion.isPresent()) {
504 IpPrefix ipv4Dst = ((IPCriterion) ipv4DstCriterion.get()).ip();
505 builderToUpdate.matchIPDst(ipv4Dst);
506 }
507
508 return builderToUpdate;
509 }
510
511 static Optional<Criterion> readFromSelector(TrafficSelector selector, Criterion.Type type) {
512 if (selector == null) {
513 return Optional.empty();
514 }
515 Criterion criterion = selector.getCriterion(type);
516 return (criterion == null)
517 ? Optional.empty() : Optional.of(criterion);
518 }
519
alshabibd61b77b2016-02-01 23:30:53 -0800520 private boolean checkForMulticast(ForwardingObjective fwd) {
521
alshabib1aa58142016-02-17 15:37:56 -0800522 IPCriterion ip = (IPCriterion) filterForCriterion(fwd.selector().criteria(),
alshabib56efe432016-02-25 17:57:24 -0500523 Criterion.Type.IPV4_DST);
alshabibd61b77b2016-02-01 23:30:53 -0800524
alshabib1aa58142016-02-17 15:37:56 -0800525 if (ip == null) {
526 return false;
527 }
528
Charles Chanaedabfd2016-02-26 09:31:48 -0800529 return ip.ip().isMulticast();
alshabibd61b77b2016-02-01 23:30:53 -0800530
531 }
532
alshabib1aa58142016-02-17 15:37:56 -0800533 private GroupKey getGroupForNextObjective(Integer nextId) {
alshabibd61b77b2016-02-01 23:30:53 -0800534 NextGroup next = flowObjectiveStore.getNextGroup(nextId);
alshabib1aa58142016-02-17 15:37:56 -0800535 return appKryo.deserialize(next.data());
alshabibd61b77b2016-02-01 23:30:53 -0800536
alshabib0ccde6d2015-05-30 18:22:36 -0700537 }
538
Amit Ghoshf1f22752018-08-14 07:28:01 +0100539 private void installNoModificationRules(ForwardingObjective fwd) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000540 Instructions.OutputInstruction output = (Instructions.OutputInstruction) fetchOutput(fwd, DOWNSTREAM);
Gamze Abakaa34469f2019-04-19 08:30:16 +0000541 Instructions.MetadataInstruction writeMetadata = fetchWriteMetadata(fwd);
542 Instructions.MeterInstruction meter = (Instructions.MeterInstruction) fetchMeter(fwd);
Amit Ghoshf1f22752018-08-14 07:28:01 +0100543
544 TrafficSelector selector = fwd.selector();
545
546 Criterion inport = selector.getCriterion(Criterion.Type.IN_PORT);
547 Criterion outerVlan = selector.getCriterion(Criterion.Type.VLAN_VID);
548 Criterion innerVlan = selector.getCriterion(Criterion.Type.INNER_VLAN_VID);
Amit Ghoshf1f22752018-08-14 07:28:01 +0100549
550 if (inport == null || output == null || innerVlan == null || outerVlan == null) {
Andrea Campanella969e8af2020-07-09 11:39:08 +0200551 // Avoid logging a non-error from lldp, bbdp and eapol core flows.
552 if (!fwd.appId().name().equals(CORE_APP_NAME)) {
553 log.error("Forwarding objective is underspecified: {}", fwd);
554 } else {
555 log.debug("Not installing unsupported core generated flow {}", fwd);
556 }
Amit Ghoshf1f22752018-08-14 07:28:01 +0100557 fail(fwd, ObjectiveError.BADPARAMS);
558 return;
559 }
560
Amit Ghoshf1f22752018-08-14 07:28:01 +0100561
562 FlowRule.Builder outer = DefaultFlowRule.builder()
563 .fromApp(fwd.appId())
564 .forDevice(deviceId)
565 .makePermanent()
566 .withPriority(fwd.priority())
Gamze Abakaa34469f2019-04-19 08:30:16 +0000567 .withSelector(buildSelector(inport, outerVlan))
568 .withTreatment(buildTreatment(output, writeMetadata, meter));
Amit Ghoshf1f22752018-08-14 07:28:01 +0100569
570 applyRules(fwd, outer);
571 }
572
alshabibfd430b62015-12-16 18:56:38 -0800573 private void installDownstreamRules(ForwardingObjective fwd) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000574 Instructions.OutputInstruction output = (Instructions.OutputInstruction) fetchOutput(fwd, DOWNSTREAM);
alshabibfd430b62015-12-16 18:56:38 -0800575
576 if (output == null) {
577 return;
578 }
579
alshabibfa0dc662016-01-13 11:23:53 -0800580 TrafficSelector selector = fwd.selector();
581
582 Criterion outerVlan = selector.getCriterion(Criterion.Type.VLAN_VID);
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000583 Criterion outerPbit = selector.getCriterion(Criterion.Type.VLAN_PCP);
Gamze Abakadadae722018-09-12 10:55:35 +0000584 Criterion innerVlanCriterion = selector.getCriterion(Criterion.Type.INNER_VLAN_VID);
alshabibfa0dc662016-01-13 11:23:53 -0800585 Criterion inport = selector.getCriterion(Criterion.Type.IN_PORT);
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000586 Criterion dstMac = selector.getCriterion(Criterion.Type.ETH_DST);
cboling651c6872018-10-05 11:09:22 -0500587
Gamze Abakadadae722018-09-12 10:55:35 +0000588 if (outerVlan == null || innerVlanCriterion == null || inport == null) {
Andrea Campanella969e8af2020-07-09 11:39:08 +0200589 // Avoid logging a non-error from lldp, bbdp and eapol core flows.
590 if (!fwd.appId().name().equals(CORE_APP_NAME)) {
591 log.error("Forwarding objective is underspecified: {}", fwd);
592 } else {
593 log.debug("Not installing unsupported core generated flow {}", fwd);
594 }
alshabibfa0dc662016-01-13 11:23:53 -0800595 fail(fwd, ObjectiveError.BADPARAMS);
596 return;
597 }
598
Gamze Abakadadae722018-09-12 10:55:35 +0000599 VlanId innerVlan = ((VlanIdCriterion) innerVlanCriterion).vlanId();
600 Criterion innerVid = Criteria.matchVlanId(innerVlan);
alshabib2f74f2c2016-01-14 13:29:35 -0800601
Amit Ghosha6859982020-02-12 09:35:45 +0000602 // In the case where the C-tag is the same for all the subscribers,
603 // we add a metadata with the outport in the selector to make the flow unique
604 Criterion innerSelectorMeta = Criteria.matchMetadata(output.port().toLong());
605
Gamze Abakadadae722018-09-12 10:55:35 +0000606 if (innerVlan.toShort() == VlanId.ANY_VALUE) {
Andrea Campanella6edac322020-01-29 14:41:42 +0100607 TrafficSelector outerSelector = buildSelector(inport, outerVlan, outerPbit, dstMac);
Gamze Abakadadae722018-09-12 10:55:35 +0000608 installDownstreamRulesForAnyVlan(fwd, output, outerSelector, buildSelector(inport,
Amit Ghosha6859982020-02-12 09:35:45 +0000609 Criteria.matchVlanId(VlanId.ANY), innerSelectorMeta));
Gamze Abakadadae722018-09-12 10:55:35 +0000610 } else {
Andrea Campanella6edac322020-01-29 14:41:42 +0100611 // Required to differentiate the same match flows
612 // Please note that S tag and S p bit values will be same for the same service - so conflict flows!
613 // Metadata match criteria solves the conflict issue - but not used by the voltha
614 // Maybe - find a better way to solve the above problem
615 Criterion metadata = Criteria.matchMetadata(innerVlan.toShort());
616 TrafficSelector outerSelector = buildSelector(inport, metadata, outerVlan, outerPbit, dstMac);
Amit Ghosha6859982020-02-12 09:35:45 +0000617 installDownstreamRulesForVlans(fwd, output, outerSelector, buildSelector(inport, innerVid,
618 innerSelectorMeta));
Gamze Abakadadae722018-09-12 10:55:35 +0000619 }
620 }
621
622 private void installDownstreamRulesForVlans(ForwardingObjective fwd, Instruction output,
623 TrafficSelector outerSelector, TrafficSelector innerSelector) {
624
625 List<Pair<Instruction, Instruction>> vlanOps =
626 vlanOps(fwd,
627 L2ModificationInstruction.L2SubType.VLAN_POP);
628
629 if (vlanOps == null || vlanOps.isEmpty()) {
630 return;
631 }
632
633 Pair<Instruction, Instruction> popAndRewrite = vlanOps.remove(0);
634
635 TrafficTreatment innerTreatment;
636 VlanId setVlanId = ((L2ModificationInstruction.ModVlanIdInstruction) popAndRewrite.getRight()).vlanId();
637 if (VlanId.NONE.equals(setVlanId)) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000638 innerTreatment = (buildTreatment(popAndRewrite.getLeft(), fetchMeter(fwd),
639 writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000640 } else {
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000641 innerTreatment = (buildTreatment(popAndRewrite.getRight(),
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000642 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000643 }
644
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000645 List<Instruction> setVlanPcps = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_PCP,
646 fwd.treatment().allInstructions());
647
648 Instruction innerPbitSet = null;
649
650 if (setVlanPcps != null && !setVlanPcps.isEmpty()) {
651 innerPbitSet = setVlanPcps.get(0);
652 }
653
654 VlanId remarkInnerVlan = null;
655 Optional<Criterion> vlanIdCriterion = readFromSelector(innerSelector, Criterion.Type.VLAN_VID);
656 if (vlanIdCriterion.isPresent()) {
657 remarkInnerVlan = ((VlanIdCriterion) vlanIdCriterion.get()).vlanId();
658 }
659
660 Instruction modVlanId = null;
661 if (innerPbitSet != null) {
662 modVlanId = Instructions.modVlanId(remarkInnerVlan);
663 }
664
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000665 //match: in port (nni), s-tag
666 //action: pop vlan (s-tag), write metadata, go to table 1, meter
alshabibfa0dc662016-01-13 11:23:53 -0800667 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700668 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800669 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800670 .makePermanent()
671 .withPriority(fwd.priority())
Gamze Abakadadae722018-09-12 10:55:35 +0000672 .withSelector(outerSelector)
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000673 .withTreatment(buildTreatment(popAndRewrite.getLeft(), modVlanId,
674 innerPbitSet, fetchMeter(fwd), fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE)));
alshabibfd430b62015-12-16 18:56:38 -0800675
Gamze Abakadadae722018-09-12 10:55:35 +0000676 //match: in port (nni), c-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000677 //action: immediate: write metadata and pop, meter, output
alshabibfa0dc662016-01-13 11:23:53 -0800678 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700679 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800680 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800681 .forTable(QQ_TABLE)
682 .makePermanent()
683 .withPriority(fwd.priority())
Gamze Abakadadae722018-09-12 10:55:35 +0000684 .withSelector(innerSelector)
685 .withTreatment(innerTreatment);
686 applyRules(fwd, inner, outer);
687 }
688
689 private void installDownstreamRulesForAnyVlan(ForwardingObjective fwd, Instruction output,
690 TrafficSelector outerSelector, TrafficSelector innerSelector) {
691
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000692 //match: in port (nni), s-tag
693 //action: immediate: write metadata, pop vlan, meter and go to table 1
Gamze Abakadadae722018-09-12 10:55:35 +0000694 FlowRule.Builder outer = DefaultFlowRule.builder()
695 .fromApp(fwd.appId())
696 .forDevice(deviceId)
697 .makePermanent()
698 .withPriority(fwd.priority())
699 .withSelector(outerSelector)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000700 .withTreatment(buildTreatment(Instructions.popVlan(), fetchMeter(fwd),
701 fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE)));
Gamze Abakadadae722018-09-12 10:55:35 +0000702
703 //match: in port (nni) and s-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000704 //action: immediate : write metadata, meter and output
Gamze Abakadadae722018-09-12 10:55:35 +0000705 FlowRule.Builder inner = DefaultFlowRule.builder()
706 .fromApp(fwd.appId())
707 .forDevice(deviceId)
708 .forTable(QQ_TABLE)
709 .makePermanent()
710 .withPriority(fwd.priority())
711 .withSelector(innerSelector)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000712 .withTreatment(buildTreatment(fetchMeter(fwd),
713 writeMetadataIncludingOnlyTp(fwd), output));
alshabibfd430b62015-12-16 18:56:38 -0800714
715 applyRules(fwd, inner, outer);
alshabibfd430b62015-12-16 18:56:38 -0800716 }
717
718 private void installUpstreamRules(ForwardingObjective fwd) {
719 List<Pair<Instruction, Instruction>> vlanOps =
720 vlanOps(fwd,
721 L2ModificationInstruction.L2SubType.VLAN_PUSH);
722
Gamze Abakadadae722018-09-12 10:55:35 +0000723 if (vlanOps == null || vlanOps.isEmpty()) {
alshabibfd430b62015-12-16 18:56:38 -0800724 return;
725 }
726
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000727 Instruction output = fetchOutput(fwd, UPSTREAM);
alshabibfd430b62015-12-16 18:56:38 -0800728
729 if (output == null) {
730 return;
731 }
732
alshabibfd430b62015-12-16 18:56:38 -0800733 Pair<Instruction, Instruction> outerPair = vlanOps.remove(0);
734
Gamze Abakadadae722018-09-12 10:55:35 +0000735 boolean noneValueVlanStatus = checkNoneVlanCriteria(fwd);
736 boolean anyValueVlanStatus = checkAnyVlanMatchCriteria(fwd);
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700737
Gamze Abakadadae722018-09-12 10:55:35 +0000738 if (anyValueVlanStatus) {
739 installUpstreamRulesForAnyVlan(fwd, output, outerPair);
740 } else {
Andrea Campanella6edac322020-01-29 14:41:42 +0100741 Pair<Instruction, Instruction> innerPair = outerPair;
742 outerPair = vlanOps.remove(0);
Gamze Abakadadae722018-09-12 10:55:35 +0000743 installUpstreamRulesForVlans(fwd, output, innerPair, outerPair, noneValueVlanStatus);
744 }
745 }
746
747 private void installUpstreamRulesForVlans(ForwardingObjective fwd, Instruction output,
748 Pair<Instruction, Instruction> innerPair,
749 Pair<Instruction, Instruction> outerPair, Boolean noneValueVlanStatus) {
750
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000751 List<Instruction> setVlanPcps = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_PCP,
752 fwd.treatment().allInstructions());
753
754 Instruction innerPbitSet = null;
755 Instruction outerPbitSet = null;
756
757 if (setVlanPcps != null && !setVlanPcps.isEmpty()) {
758 innerPbitSet = setVlanPcps.get(0);
759 outerPbitSet = setVlanPcps.get(1);
760 }
761
Gamze Abakadadae722018-09-12 10:55:35 +0000762 TrafficTreatment innerTreatment;
763 if (noneValueVlanStatus) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000764 innerTreatment = buildTreatment(innerPair.getLeft(), innerPair.getRight(), fetchMeter(fwd),
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000765 fetchWriteMetadata(fwd), innerPbitSet,
766 Instructions.transition(QQ_TABLE));
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700767 } else {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000768 innerTreatment = buildTreatment(innerPair.getRight(), fetchMeter(fwd), fetchWriteMetadata(fwd),
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000769 innerPbitSet, Instructions.transition(QQ_TABLE));
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700770 }
771
Gamze Abakadadae722018-09-12 10:55:35 +0000772 //match: in port, vlanId (0 or None)
773 //action:
774 //if vlanId None, push & set c-tag go to table 1
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000775 //if vlanId 0 or any specific vlan, set c-tag, write metadata, meter and go to table 1
alshabibfd430b62015-12-16 18:56:38 -0800776 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700777 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800778 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800779 .makePermanent()
780 .withPriority(fwd.priority())
781 .withSelector(fwd.selector())
Gamze Abakadadae722018-09-12 10:55:35 +0000782 .withTreatment(innerTreatment);
alshabibfd430b62015-12-16 18:56:38 -0800783
784 PortCriterion inPort = (PortCriterion)
785 fwd.selector().getCriterion(Criterion.Type.IN_PORT);
786
787 VlanId cVlanId = ((L2ModificationInstruction.ModVlanIdInstruction)
788 innerPair.getRight()).vlanId();
789
Gamze Abakadadae722018-09-12 10:55:35 +0000790 //match: in port, c-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000791 //action: immediate: push s-tag, write metadata, meter and output
alshabibfd430b62015-12-16 18:56:38 -0800792 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700793 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800794 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800795 .forTable(QQ_TABLE)
796 .makePermanent()
797 .withPriority(fwd.priority())
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000798 .withTreatment(buildTreatment(outerPair.getLeft(), outerPair.getRight(),
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000799 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd),
800 outerPbitSet, output));
801
802 if (innerPbitSet != null) {
803 byte innerPbit = ((L2ModificationInstruction.ModVlanPcpInstruction)
804 innerPbitSet).vlanPcp();
805 outer.withSelector(buildSelector(inPort, Criteria.matchVlanId(cVlanId), Criteria.matchVlanPcp(innerPbit)));
806 } else {
807 outer.withSelector(buildSelector(inPort, Criteria.matchVlanId(cVlanId)));
808 }
alshabibfd430b62015-12-16 18:56:38 -0800809
810 applyRules(fwd, inner, outer);
Gamze Abakadadae722018-09-12 10:55:35 +0000811 }
alshabibfd430b62015-12-16 18:56:38 -0800812
Gamze Abakadadae722018-09-12 10:55:35 +0000813 private void installUpstreamRulesForAnyVlan(ForwardingObjective fwd, Instruction output,
814 Pair<Instruction, Instruction> outerPair) {
815
816 log.debug("Installing upstream rules for any value vlan");
817
818 //match: in port and any-vlan (coming from OLT app.)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000819 //action: write metadata, go to table 1 and meter
Gamze Abakadadae722018-09-12 10:55:35 +0000820 FlowRule.Builder inner = DefaultFlowRule.builder()
821 .fromApp(fwd.appId())
822 .forDevice(deviceId)
823 .makePermanent()
824 .withPriority(fwd.priority())
825 .withSelector(fwd.selector())
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000826 .withTreatment(buildTreatment(Instructions.transition(QQ_TABLE), fetchMeter(fwd),
827 fetchWriteMetadata(fwd)));
Gamze Abakadadae722018-09-12 10:55:35 +0000828
Gamze Abakadadae722018-09-12 10:55:35 +0000829 //match: in port and any-vlan (coming from OLT app.)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000830 //action: immediate: push:QinQ, vlanId (s-tag), write metadata, meter and output
Gamze Abakadadae722018-09-12 10:55:35 +0000831 FlowRule.Builder outer = DefaultFlowRule.builder()
832 .fromApp(fwd.appId())
833 .forDevice(deviceId)
834 .forTable(QQ_TABLE)
835 .makePermanent()
836 .withPriority(fwd.priority())
837 .withSelector(fwd.selector())
Andrea Campanella6edac322020-01-29 14:41:42 +0100838 .withTreatment(buildTreatment(outerPair.getLeft(), outerPair.getRight(),
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000839 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000840
Andrea Campanella6edac322020-01-29 14:41:42 +0100841 applyRules(fwd, inner, outer);
Gamze Abakadadae722018-09-12 10:55:35 +0000842 }
843
844 private boolean checkNoneVlanCriteria(ForwardingObjective fwd) {
845 // Add the VLAN_PUSH treatment if we're matching on VlanId.NONE
846 Criterion vlanMatchCriterion = filterForCriterion(fwd.selector().criteria(), Criterion.Type.VLAN_VID);
847 boolean noneValueVlanStatus = false;
848 if (vlanMatchCriterion != null) {
849 noneValueVlanStatus = ((VlanIdCriterion) vlanMatchCriterion).vlanId().equals(VlanId.NONE);
850 }
851 return noneValueVlanStatus;
852 }
853
854 private boolean checkAnyVlanMatchCriteria(ForwardingObjective fwd) {
855 Criterion anyValueVlanCriterion = fwd.selector().criteria().stream()
856 .filter(c -> c.type().equals(Criterion.Type.VLAN_VID))
857 .filter(vc -> ((VlanIdCriterion) vc).vlanId().toShort() == VlanId.ANY_VALUE)
858 .findAny().orElse(null);
859
860 if (anyValueVlanCriterion == null) {
Andrea Campanella6edac322020-01-29 14:41:42 +0100861 log.debug("Any value vlan match criteria is not found, criteria {}",
862 fwd.selector().criteria());
Gamze Abakadadae722018-09-12 10:55:35 +0000863 return false;
864 }
865
866 return true;
alshabibfd430b62015-12-16 18:56:38 -0800867 }
868
869 private Instruction fetchOutput(ForwardingObjective fwd, String direction) {
870 Instruction output = fwd.treatment().allInstructions().stream()
871 .filter(i -> i.type() == Instruction.Type.OUTPUT)
872 .findFirst().orElse(null);
873
874 if (output == null) {
875 log.error("OLT {} rule has no output", direction);
876 fail(fwd, ObjectiveError.BADPARAMS);
877 return null;
878 }
879 return output;
880 }
881
Gamze Abakadadae722018-09-12 10:55:35 +0000882 private Instruction fetchMeter(ForwardingObjective fwd) {
883 Instruction meter = fwd.treatment().metered();
884
885 if (meter == null) {
886 log.debug("Meter instruction is not found for the forwarding objective {}", fwd);
887 return null;
888 }
889
890 log.debug("Meter instruction is found.");
891 return meter;
892 }
893
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000894 private Instructions.MetadataInstruction fetchWriteMetadata(ForwardingObjective fwd) {
895 Instructions.MetadataInstruction writeMetadata = fwd.treatment().writeMetadata();
Gamze Abakadadae722018-09-12 10:55:35 +0000896
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000897 if (writeMetadata == null) {
898 log.warn("Write metadata is not found for the forwarding obj");
899 fail(fwd, ObjectiveError.BADPARAMS);
Gamze Abakadadae722018-09-12 10:55:35 +0000900 return null;
901 }
902
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000903 log.debug("Write metadata is found {}", writeMetadata);
904 return writeMetadata;
Gamze Abakadadae722018-09-12 10:55:35 +0000905 }
906
alshabibfd430b62015-12-16 18:56:38 -0800907 private List<Pair<Instruction, Instruction>> vlanOps(ForwardingObjective fwd,
908 L2ModificationInstruction.L2SubType type) {
909
910 List<Pair<Instruction, Instruction>> vlanOps = findVlanOps(
911 fwd.treatment().allInstructions(), type);
912
Gamze Abakadadae722018-09-12 10:55:35 +0000913 if (vlanOps == null || vlanOps.isEmpty()) {
alshabibfd430b62015-12-16 18:56:38 -0800914 String direction = type == L2ModificationInstruction.L2SubType.VLAN_POP
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000915 ? DOWNSTREAM : UPSTREAM;
alshabibfd430b62015-12-16 18:56:38 -0800916 log.error("Missing vlan operations in {} forwarding: {}", direction, fwd);
917 fail(fwd, ObjectiveError.BADPARAMS);
Gamze Abakadadae722018-09-12 10:55:35 +0000918 return ImmutableList.of();
alshabibfd430b62015-12-16 18:56:38 -0800919 }
920 return vlanOps;
921 }
922
923
924 private List<Pair<Instruction, Instruction>> findVlanOps(List<Instruction> instructions,
alshabibd61b77b2016-02-01 23:30:53 -0800925 L2ModificationInstruction.L2SubType type) {
alshabibfd430b62015-12-16 18:56:38 -0800926
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000927 List<Instruction> vlanOperations = findL2Instructions(
alshabibfd430b62015-12-16 18:56:38 -0800928 type,
929 instructions);
930 List<Instruction> vlanSets = findL2Instructions(
931 L2ModificationInstruction.L2SubType.VLAN_ID,
932 instructions);
933
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000934 if (vlanOperations.size() != vlanSets.size()) {
Gamze Abakadadae722018-09-12 10:55:35 +0000935 return ImmutableList.of();
alshabibfd430b62015-12-16 18:56:38 -0800936 }
937
938 List<Pair<Instruction, Instruction>> pairs = Lists.newArrayList();
939
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000940 for (int i = 0; i < vlanOperations.size(); i++) {
941 pairs.add(new ImmutablePair<>(vlanOperations.get(i), vlanSets.get(i)));
alshabibfd430b62015-12-16 18:56:38 -0800942 }
943 return pairs;
944 }
945
946 private List<Instruction> findL2Instructions(L2ModificationInstruction.L2SubType subType,
947 List<Instruction> actions) {
948 return actions.stream()
949 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
950 .filter(i -> ((L2ModificationInstruction) i).subtype() == subType)
951 .collect(Collectors.toList());
952 }
953
Amit Ghoshf1f22752018-08-14 07:28:01 +0100954 private void provisionEthTypeBasedFilter(FilteringObjective filter,
955 EthTypeCriterion ethType,
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200956 Instructions.OutputInstruction output,
957 L2ModificationInstruction vlanId,
958 L2ModificationInstruction vlanPush) {
alshabibfd430b62015-12-16 18:56:38 -0800959
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000960 Instruction meter = filter.meta().metered();
961 Instruction writeMetadata = filter.meta().writeMetadata();
962
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200963 TrafficSelector selector = buildSelector(filter.key(), ethType);
964 TrafficTreatment treatment;
Gamze Abakaf57ef602019-03-11 06:52:48 +0000965
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200966 if (vlanPush == null || vlanId == null) {
967 treatment = buildTreatment(output, meter, writeMetadata);
968 } else {
969 // we need to push the vlan because it came untagged (ATT)
970 treatment = buildTreatment(output, meter, vlanPush, vlanId, writeMetadata);
971 }
972
alshabibfd430b62015-12-16 18:56:38 -0800973 buildAndApplyRule(filter, selector, treatment);
974
975 }
976
Jonathan Hart51539b82015-10-29 09:53:04 -0700977 private void provisionIgmp(FilteringObjective filter, EthTypeCriterion ethType,
alshabibfd430b62015-12-16 18:56:38 -0800978 IPProtocolCriterion ipProto,
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200979 Instructions.OutputInstruction output,
Andrea Campanella79bc5062020-09-21 14:34:00 +0200980 Instruction vlan, Instruction pcp) {
Gamze Abaka7c070c82019-02-21 14:40:18 +0000981
982 Instruction meter = filter.meta().metered();
983 Instruction writeMetadata = filter.meta().writeMetadata();
984
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200985 // uniTagMatch
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000986 VlanIdCriterion vlanId = (VlanIdCriterion) filterForCriterion(filter.conditions(),
987 Criterion.Type.VLAN_VID);
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000988
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200989 TrafficSelector selector = buildSelector(filter.key(), ethType, ipProto, vlanId);
990 TrafficTreatment treatment = buildTreatment(output, vlan, pcp, meter, writeMetadata);
alshabibfd430b62015-12-16 18:56:38 -0800991 buildAndApplyRule(filter, selector, treatment);
992 }
993
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000994 private void provisionDhcp(FilteringObjective filter, EthTypeCriterion ethType,
995 IPProtocolCriterion ipProto,
996 UdpPortCriterion udpSrcPort,
997 UdpPortCriterion udpDstPort,
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200998 Instruction vlanIdInstruction,
999 Instruction vlanPcpInstruction,
Amit Ghoshcbaf8672016-12-23 21:36:19 +00001000 Instructions.OutputInstruction output) {
Gamze Abaka7c070c82019-02-21 14:40:18 +00001001
1002 Instruction meter = filter.meta().metered();
1003 Instruction writeMetadata = filter.meta().writeMetadata();
1004
Andrea Campanellaa93905c2020-06-11 16:09:39 +02001005 VlanIdCriterion matchVlanId = (VlanIdCriterion)
Gamze Abakafe9d54f2019-12-02 06:42:39 +00001006 filterForCriterion(filter.conditions(), Criterion.Type.VLAN_VID);
1007
Andrea Campanellaa93905c2020-06-11 16:09:39 +02001008 TrafficSelector selector;
1009 TrafficTreatment treatment;
1010
1011 if (matchVlanId != null) {
1012 log.debug("Building selector with match VLAN, {}", matchVlanId);
1013 // in case of TT upstream the packet comes tagged and the vlan is swapped.
1014 selector = buildSelector(filter.key(), ethType, ipProto, udpSrcPort,
1015 udpDstPort, matchVlanId);
1016 treatment = buildTreatment(output, meter, writeMetadata,
1017 vlanIdInstruction, vlanPcpInstruction);
1018 } else {
1019 log.debug("Building selector with no VLAN");
1020 // in case of ATT upstream the packet comes in untagged and we need to push the vlan
1021 selector = buildSelector(filter.key(), ethType, ipProto, udpSrcPort, udpDstPort);
1022 treatment = buildTreatment(output, meter, vlanIdInstruction, writeMetadata);
1023 }
1024 //In case of downstream there will be no match on the VLAN, which is null,
1025 // so it will just be output, meter, writeMetadata
1026
Amit Ghoshcbaf8672016-12-23 21:36:19 +00001027 buildAndApplyRule(filter, selector, treatment);
1028 }
Gamze Abakadadae722018-09-12 10:55:35 +00001029
alshabibfd430b62015-12-16 18:56:38 -08001030 private void buildAndApplyRule(FilteringObjective filter, TrafficSelector selector,
1031 TrafficTreatment treatment) {
1032 FlowRule rule = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -07001033 .fromApp(filter.appId())
alshabibfd430b62015-12-16 18:56:38 -08001034 .forDevice(deviceId)
1035 .forTable(0)
alshabibfd430b62015-12-16 18:56:38 -08001036 .makePermanent()
1037 .withSelector(selector)
1038 .withTreatment(treatment)
alshabibbb424232016-01-15 12:20:25 -08001039 .withPriority(filter.priority())
alshabibfd430b62015-12-16 18:56:38 -08001040 .build();
1041
Andrea Campanellad8e07632020-06-18 10:25:59 +02001042 if (accumulator != null) {
1043 if (log.isDebugEnabled()) {
1044 log.debug("Adding pair to batch: {}", Pair.of(filter, rule));
1045 }
1046 accumulator.add(Pair.of(filter, rule));
1047 } else {
1048 FlowRuleOperations.Builder opsBuilder = FlowRuleOperations.builder();
1049 switch (filter.type()) {
1050 case PERMIT:
1051 opsBuilder.add(rule);
1052 break;
1053 case DENY:
1054 opsBuilder.remove(rule);
1055 break;
1056 default:
1057 log.warn("Unknown filter type : {}", filter.type());
1058 fail(filter, ObjectiveError.UNSUPPORTED);
1059 }
1060 applyFlowRules(ImmutableList.of(filter), opsBuilder);
alshabibfd430b62015-12-16 18:56:38 -08001061 }
alshabibfd430b62015-12-16 18:56:38 -08001062 }
1063
Gamze Abakadadae722018-09-12 10:55:35 +00001064 private void applyRules(ForwardingObjective fwd, FlowRule.Builder... fwdBuilders) {
Amit Ghoshf1f22752018-08-14 07:28:01 +01001065 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
1066 switch (fwd.op()) {
1067 case ADD:
Gamze Abakadadae722018-09-12 10:55:35 +00001068 for (FlowRule.Builder fwdBuilder : fwdBuilders) {
1069 builder.add(fwdBuilder.build());
1070 }
Amit Ghoshf1f22752018-08-14 07:28:01 +01001071 break;
1072 case REMOVE:
Gamze Abakadadae722018-09-12 10:55:35 +00001073 for (FlowRule.Builder fwdBuilder : fwdBuilders) {
1074 builder.remove(fwdBuilder.build());
1075 }
alshabibfd430b62015-12-16 18:56:38 -08001076 break;
1077 case ADD_TO_EXISTING:
1078 break;
1079 case REMOVE_FROM_EXISTING:
1080 break;
1081 default:
1082 log.warn("Unknown forwarding operation: {}", fwd.op());
1083 }
1084
Andrea Campanellad8e07632020-06-18 10:25:59 +02001085 applyFlowRules(ImmutableList.of(fwd), builder);
1086
1087
alshabibfd430b62015-12-16 18:56:38 -08001088 }
1089
Andrea Campanellad8e07632020-06-18 10:25:59 +02001090 private void applyFlowRules(List<Objective> objectives, FlowRuleOperations.Builder builder) {
alshabibfd430b62015-12-16 18:56:38 -08001091 flowRuleService.apply(builder.build(new FlowRuleOperationsContext() {
1092 @Override
1093 public void onSuccess(FlowRuleOperations ops) {
Andrea Campanellad8e07632020-06-18 10:25:59 +02001094 objectives.forEach(obj -> {
1095 pass(obj);
1096 });
alshabibfd430b62015-12-16 18:56:38 -08001097 }
1098
1099 @Override
1100 public void onError(FlowRuleOperations ops) {
Andrea Campanellad8e07632020-06-18 10:25:59 +02001101 objectives.forEach(obj -> {
1102 fail(obj, ObjectiveError.FLOWINSTALLATIONFAILED);
1103 });
1104
alshabibfd430b62015-12-16 18:56:38 -08001105 }
1106 }));
1107 }
1108
Andrea Campanellad8e07632020-06-18 10:25:59 +02001109 // Builds the batch using the accumulated flow rules
1110 private void sendFilters(List<Pair<FilteringObjective, FlowRule>> pairs) {
1111 FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
1112 log.debug("Sending batch of {} filter-objs", pairs.size());
1113 List<Objective> filterObjs = Lists.newArrayList();
1114 // Iterates over all accumulated flow rules and then build an unique batch
1115 pairs.forEach(pair -> {
1116 FilteringObjective filter = pair.getLeft();
1117 FlowRule rule = pair.getRight();
1118 switch (filter.type()) {
1119 case PERMIT:
1120 flowOpsBuilder.add(rule);
1121 log.debug("Applying add filter-obj {} to device: {}", filter.id(), deviceId);
1122 filterObjs.add(filter);
1123 break;
1124 case DENY:
1125 flowOpsBuilder.remove(rule);
1126 log.debug("Deleting flow rule {} to device: {}", rule, deviceId);
1127 filterObjs.add(filter);
1128 break;
1129 default:
1130 fail(filter, ObjectiveError.UNKNOWN);
1131 log.warn("Unknown forwarding type {}", filter.type());
1132 }
1133 });
1134 if (log.isDebugEnabled()) {
1135 log.debug("Applying batch {}", flowOpsBuilder.build());
1136 }
1137 // Finally applies the operations
1138 applyFlowRules(filterObjs, flowOpsBuilder);
1139 }
1140
alshabibfd430b62015-12-16 18:56:38 -08001141 private Criterion filterForCriterion(Collection<Criterion> criteria, Criterion.Type type) {
1142 return criteria.stream()
alshabibbb424232016-01-15 12:20:25 -08001143 .filter(c -> c.type().equals(type))
alshabibfd430b62015-12-16 18:56:38 -08001144 .limit(1)
1145 .findFirst().orElse(null);
1146 }
1147
1148 private TrafficSelector buildSelector(Criterion... criteria) {
1149
alshabibfd430b62015-12-16 18:56:38 -08001150 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
1151
Gamze Abakaf57ef602019-03-11 06:52:48 +00001152 Arrays.stream(criteria).filter(Objects::nonNull).forEach(sBuilder::add);
alshabibfd430b62015-12-16 18:56:38 -08001153
1154 return sBuilder.build();
1155 }
1156
1157 private TrafficTreatment buildTreatment(Instruction... instructions) {
1158
alshabibfd430b62015-12-16 18:56:38 -08001159 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1160
Gamze Abaka6c8a71b2018-12-24 13:17:12 +00001161 Arrays.stream(instructions).filter(Objects::nonNull).forEach(tBuilder::add);
alshabibfd430b62015-12-16 18:56:38 -08001162
1163 return tBuilder.build();
1164 }
1165
Gamze Abaka6c8a71b2018-12-24 13:17:12 +00001166 private Instruction writeMetadataIncludingOnlyTp(ForwardingObjective fwd) {
1167
1168 return Instructions.writeMetadata(
1169 fetchWriteMetadata(fwd).metadata() & 0xFFFF00000000L, 0L);
1170 }
alshabibfd430b62015-12-16 18:56:38 -08001171
1172 private void fail(Objective obj, ObjectiveError error) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -08001173 obj.context().ifPresent(context -> context.onError(obj, error));
alshabibfd430b62015-12-16 18:56:38 -08001174 }
1175
1176 private void pass(Objective obj) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -08001177 obj.context().ifPresent(context -> context.onSuccess(obj));
alshabibfd430b62015-12-16 18:56:38 -08001178 }
1179
alshabib2cc73cb2015-06-30 20:26:56 -07001180
alshabibd61b77b2016-02-01 23:30:53 -08001181 private class InnerGroupListener implements GroupListener {
alshabib2cc73cb2015-06-30 20:26:56 -07001182 @Override
alshabibd61b77b2016-02-01 23:30:53 -08001183 public void event(GroupEvent event) {
Andrea Campanella5908b562020-05-06 16:09:10 +02001184 GroupKey key = event.subject().appCookie();
1185 NextObjective obj = pendingGroups.getIfPresent(key);
1186 if (obj == null) {
1187 log.debug("No pending group for {}, moving on", key);
1188 return;
1189 }
1190 log.trace("Event {} for group {}, handling pending" +
1191 "NextGroup {}", event.type(), key, obj.id());
ke hanf5086672016-08-12 11:09:17 +08001192 if (event.type() == GroupEvent.Type.GROUP_ADDED ||
Gamze Abakadadae722018-09-12 10:55:35 +00001193 event.type() == GroupEvent.Type.GROUP_UPDATED) {
alshabibd61b77b2016-02-01 23:30:53 -08001194 flowObjectiveStore.putNextGroup(obj.id(), new OLTPipelineGroup(key));
1195 pass(obj);
1196 pendingGroups.invalidate(key);
Andrea Campanella5908b562020-05-06 16:09:10 +02001197 } else if (event.type() == GroupEvent.Type.GROUP_REMOVED) {
1198 flowObjectiveStore.removeNextGroup(obj.id());
1199 pass(obj);
1200 pendingGroups.invalidate(key);
alshabibd61b77b2016-02-01 23:30:53 -08001201 }
alshabib2cc73cb2015-06-30 20:26:56 -07001202 }
1203 }
1204
alshabibd61b77b2016-02-01 23:30:53 -08001205 private static class OLTPipelineGroup implements NextGroup {
1206
1207 private final GroupKey key;
1208
1209 public OLTPipelineGroup(GroupKey key) {
1210 this.key = key;
1211 }
1212
1213 public GroupKey key() {
1214 return key;
1215 }
1216
1217 @Override
1218 public byte[] data() {
1219 return appKryo.serialize(key);
1220 }
1221
1222 }
Saurav Das24431192016-03-07 19:13:00 -08001223
1224 @Override
1225 public List<String> getNextMappings(NextGroup nextGroup) {
1226 // TODO Implementation deferred to vendor
1227 return null;
1228 }
Andrea Campanellad8e07632020-06-18 10:25:59 +02001229
1230 // Flow rules accumulator for reducing the number of transactions required to the devices.
1231 private final class ObjectiveAccumulator
1232 extends AbstractAccumulator<Pair<FilteringObjective, FlowRule>> {
1233
1234 ObjectiveAccumulator(int maxFilter, int maxBatchMS, int maxIdleMS) {
1235 super(TIMER, maxFilter, maxBatchMS, maxIdleMS);
1236 }
1237
1238 @Override
1239 public void processItems(List<Pair<FilteringObjective, FlowRule>> pairs) {
1240 // Triggers creation of a batch using the list of flowrules generated from objs.
1241 accumulatorExecutorService.execute(new FlowRulesBuilderTask(pairs));
1242 }
1243 }
1244
1245 // Task for building batch of flow rules in a separate thread.
1246 private final class FlowRulesBuilderTask implements Runnable {
1247 private final List<Pair<FilteringObjective, FlowRule>> pairs;
1248
1249 FlowRulesBuilderTask(List<Pair<FilteringObjective, FlowRule>> pairs) {
1250 this.pairs = pairs;
1251 }
1252
1253 @Override
1254 public void run() {
1255 try {
1256 sendFilters(pairs);
1257 } catch (Exception e) {
1258 log.warn("Unable to send objectives", e);
1259 }
1260 }
1261 }
alshabib0ccde6d2015-05-30 18:22:36 -07001262}