blob: d3e9ebb08161a29a00d3a2e29896d3c193b0d885 [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());
Gustavo Silva2bcc8052021-01-22 13:48:30 -0300251 } else if (ethType.ethType().equals(EthType.EtherType.LLDP.ethType()) ||
252 ethType.ethType().equals(EthType.EtherType.PPPoED.ethType())) {
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200253 provisionEthTypeBasedFilter(filter, ethType, output, null, null);
Amit Ghoshf1f22752018-08-14 07:28:01 +0100254
alshabibbb424232016-01-15 12:20:25 -0800255 } else if (ethType.ethType().equals(EthType.EtherType.IPV4.ethType())) {
alshabibfd430b62015-12-16 18:56:38 -0800256 IPProtocolCriterion ipProto = (IPProtocolCriterion)
257 filterForCriterion(filter.conditions(), Criterion.Type.IP_PROTO);
dvaddire8e6b89a2017-08-31 21:54:03 +0530258 if (ipProto == null) {
259 log.warn("OLT can only filter IGMP and DHCP");
260 fail(filter, ObjectiveError.UNSUPPORTED);
261 return;
262 }
alshabibfd430b62015-12-16 18:56:38 -0800263 if (ipProto.protocol() == IPv4.PROTOCOL_IGMP) {
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200264 provisionIgmp(filter, ethType, ipProto, output,
Andrea Campanella79bc5062020-09-21 14:34:00 +0200265 vlanId.orElse(null),
266 vlanPcp.orElse(null));
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000267 } else if (ipProto.protocol() == IPv4.PROTOCOL_UDP) {
268 UdpPortCriterion udpSrcPort = (UdpPortCriterion)
269 filterForCriterion(filter.conditions(), Criterion.Type.UDP_SRC);
270
271 UdpPortCriterion udpDstPort = (UdpPortCriterion)
272 filterForCriterion(filter.conditions(), Criterion.Type.UDP_DST);
273
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700274 if ((udpSrcPort.udpPort().toInt() == 67 && udpDstPort.udpPort().toInt() == 68) ||
275 (udpSrcPort.udpPort().toInt() == 68 && udpDstPort.udpPort().toInt() == 67)) {
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200276 provisionDhcp(filter, ethType, ipProto, udpSrcPort, udpDstPort, vlanId.orElse(null),
277 vlanPcp.orElse(null), output);
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700278 } else {
279 log.warn("Filtering rule with unsupported UDP src {} or dst {} port", udpSrcPort, udpDstPort);
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000280 fail(filter, ObjectiveError.UNSUPPORTED);
281 }
alshabibbb424232016-01-15 12:20:25 -0800282 } else {
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700283 log.warn("Currently supporting only IGMP and DHCP filters for IPv4 packets");
284 fail(filter, ObjectiveError.UNSUPPORTED);
285 }
286 } else if (ethType.ethType().equals(EthType.EtherType.IPV6.ethType())) {
287 IPProtocolCriterion ipProto = (IPProtocolCriterion)
288 filterForCriterion(filter.conditions(), Criterion.Type.IP_PROTO);
289 if (ipProto == null) {
290 log.warn("OLT can only filter DHCP");
291 fail(filter, ObjectiveError.UNSUPPORTED);
292 return;
293 }
294 if (ipProto.protocol() == IPv6.PROTOCOL_UDP) {
295 UdpPortCriterion udpSrcPort = (UdpPortCriterion)
296 filterForCriterion(filter.conditions(), Criterion.Type.UDP_SRC);
297
298 UdpPortCriterion udpDstPort = (UdpPortCriterion)
299 filterForCriterion(filter.conditions(), Criterion.Type.UDP_DST);
300
301 if ((udpSrcPort.udpPort().toInt() == 546 && udpDstPort.udpPort().toInt() == 547) ||
302 (udpSrcPort.udpPort().toInt() == 547 && udpDstPort.udpPort().toInt() == 546)) {
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200303 provisionDhcp(filter, ethType, ipProto, udpSrcPort, udpDstPort, vlanId.orElse(null),
304 vlanPcp.orElse(null), output);
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700305 } else {
306 log.warn("Filtering rule with unsupported UDP src {} or dst {} port", udpSrcPort, udpDstPort);
307 fail(filter, ObjectiveError.UNSUPPORTED);
308 }
309 } else {
310 log.warn("Currently supporting only DHCP filters for IPv6 packets");
alshabibbb424232016-01-15 12:20:25 -0800311 fail(filter, ObjectiveError.UNSUPPORTED);
alshabibfd430b62015-12-16 18:56:38 -0800312 }
313 } else {
dvaddire8e6b89a2017-08-31 21:54:03 +0530314 log.warn("\nOnly the following are Supported in OLT for filter ->\n"
Amit Ghoshf1f22752018-08-14 07:28:01 +0100315 + "ETH TYPE : EAPOL, LLDP and IPV4\n"
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700316 + "IPV4 TYPE: IGMP and UDP (for DHCP)"
317 + "IPV6 TYPE: UDP (for DHCP)");
alshabibfd430b62015-12-16 18:56:38 -0800318 fail(filter, ObjectiveError.UNSUPPORTED);
319 }
320
321 }
322
323
324 @Override
325 public void forward(ForwardingObjective fwd) {
Andrea Campanella6edac322020-01-29 14:41:42 +0100326 log.debug("Installing forwarding objective {}", fwd);
alshabibd61b77b2016-02-01 23:30:53 -0800327 if (checkForMulticast(fwd)) {
328 processMulticastRule(fwd);
329 return;
330 }
331
alshabib0ccde6d2015-05-30 18:22:36 -0700332 TrafficTreatment treatment = fwd.treatment();
alshabib0ccde6d2015-05-30 18:22:36 -0700333
alshabibfd430b62015-12-16 18:56:38 -0800334 List<Instruction> instructions = treatment.allInstructions();
alshabib0ccde6d2015-05-30 18:22:36 -0700335
Gamze Abakadadae722018-09-12 10:55:35 +0000336 Optional<Instruction> vlanInstruction = instructions.stream()
alshabibfd430b62015-12-16 18:56:38 -0800337 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
338 .filter(i -> ((L2ModificationInstruction) i).subtype() ==
339 L2ModificationInstruction.L2SubType.VLAN_PUSH ||
340 ((L2ModificationInstruction) i).subtype() ==
341 L2ModificationInstruction.L2SubType.VLAN_POP)
342 .findAny();
343
Gamze Abakadadae722018-09-12 10:55:35 +0000344
345 if (!vlanInstruction.isPresent()) {
Amit Ghoshf1f22752018-08-14 07:28:01 +0100346 installNoModificationRules(fwd);
alshabib0ccde6d2015-05-30 18:22:36 -0700347 } else {
Amit Ghoshf1f22752018-08-14 07:28:01 +0100348 L2ModificationInstruction vlanIns =
Gamze Abakadadae722018-09-12 10:55:35 +0000349 (L2ModificationInstruction) vlanInstruction.get();
Amit Ghoshf1f22752018-08-14 07:28:01 +0100350 if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
351 installUpstreamRules(fwd);
352 } else if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP) {
353 installDownstreamRules(fwd);
354 } else {
355 log.error("Unknown OLT operation: {}", fwd);
356 fail(fwd, ObjectiveError.UNSUPPORTED);
357 return;
358 }
alshabib0ccde6d2015-05-30 18:22:36 -0700359 }
360
alshabibfd430b62015-12-16 18:56:38 -0800361 pass(fwd);
alshabib0ccde6d2015-05-30 18:22:36 -0700362
alshabib0ccde6d2015-05-30 18:22:36 -0700363 }
364
alshabibd61b77b2016-02-01 23:30:53 -0800365
alshabib0ccde6d2015-05-30 18:22:36 -0700366 @Override
367 public void next(NextObjective nextObjective) {
alshabibd61b77b2016-02-01 23:30:53 -0800368 if (nextObjective.type() != NextObjective.Type.BROADCAST) {
369 log.error("OLT only supports broadcast groups.");
370 fail(nextObjective, ObjectiveError.BADPARAMS);
Andrea Campanella5908b562020-05-06 16:09:10 +0200371 return;
alshabibd61b77b2016-02-01 23:30:53 -0800372 }
373
Andrea Campanella5908b562020-05-06 16:09:10 +0200374 if (nextObjective.next().size() != 1 && !nextObjective.op().equals(Objective.Operation.REMOVE)) {
alshabibd61b77b2016-02-01 23:30:53 -0800375 log.error("OLT only supports singleton broadcast groups.");
376 fail(nextObjective, ObjectiveError.BADPARAMS);
Andrea Campanella5908b562020-05-06 16:09:10 +0200377 return;
alshabibd61b77b2016-02-01 23:30:53 -0800378 }
379
Andrea Campanella5908b562020-05-06 16:09:10 +0200380 Optional<TrafficTreatment> treatmentOpt = nextObjective.next().stream().findFirst();
381 if (treatmentOpt.isEmpty() && !nextObjective.op().equals(Objective.Operation.REMOVE)) {
382 log.error("Next objective {} does not have a treatment", nextObjective);
383 fail(nextObjective, ObjectiveError.BADPARAMS);
384 return;
385 }
alshabibd61b77b2016-02-01 23:30:53 -0800386
alshabibd61b77b2016-02-01 23:30:53 -0800387 GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id()));
388
alshabibd61b77b2016-02-01 23:30:53 -0800389 pendingGroups.put(key, nextObjective);
Andrea Campanella5908b562020-05-06 16:09:10 +0200390 log.trace("NextObjective Operation {}", nextObjective.op());
alshabibd61b77b2016-02-01 23:30:53 -0800391 switch (nextObjective.op()) {
392 case ADD:
alshabib1aa58142016-02-17 15:37:56 -0800393 GroupDescription groupDesc =
394 new DefaultGroupDescription(deviceId,
395 GroupDescription.Type.ALL,
Andrea Campanella5908b562020-05-06 16:09:10 +0200396 new GroupBuckets(
397 Collections.singletonList(
398 buildBucket(treatmentOpt.get()))),
alshabib1aa58142016-02-17 15:37:56 -0800399 key,
400 null,
401 nextObjective.appId());
alshabibd61b77b2016-02-01 23:30:53 -0800402 groupService.addGroup(groupDesc);
403 break;
404 case REMOVE:
405 groupService.removeGroup(deviceId, key, nextObjective.appId());
406 break;
407 case ADD_TO_EXISTING:
alshabib1aa58142016-02-17 15:37:56 -0800408 groupService.addBucketsToGroup(deviceId, key,
Andrea Campanella5908b562020-05-06 16:09:10 +0200409 new GroupBuckets(
410 Collections.singletonList(
411 buildBucket(treatmentOpt.get()))),
alshabib1aa58142016-02-17 15:37:56 -0800412 key, nextObjective.appId());
413 break;
alshabibd61b77b2016-02-01 23:30:53 -0800414 case REMOVE_FROM_EXISTING:
alshabib1aa58142016-02-17 15:37:56 -0800415 groupService.removeBucketsFromGroup(deviceId, key,
Andrea Campanella5908b562020-05-06 16:09:10 +0200416 new GroupBuckets(
417 Collections.singletonList(
418 buildBucket(treatmentOpt.get()))),
alshabib56efe432016-02-25 17:57:24 -0500419 key, nextObjective.appId());
alshabibd61b77b2016-02-01 23:30:53 -0800420 break;
421 default:
422 log.warn("Unknown next objective operation: {}", nextObjective.op());
423 }
424
425
426 }
427
Andrea Campanella5908b562020-05-06 16:09:10 +0200428 private GroupBucket buildBucket(TrafficTreatment treatment) {
429 return DefaultGroupBucket.createAllGroupBucket(treatment);
430 }
431
alshabibd61b77b2016-02-01 23:30:53 -0800432 private void processMulticastRule(ForwardingObjective fwd) {
433 if (fwd.nextId() == null) {
434 log.error("Multicast objective does not have a next id");
435 fail(fwd, ObjectiveError.BADPARAMS);
436 }
437
alshabib1aa58142016-02-17 15:37:56 -0800438 GroupKey key = getGroupForNextObjective(fwd.nextId());
alshabibd61b77b2016-02-01 23:30:53 -0800439
alshabib1aa58142016-02-17 15:37:56 -0800440 if (key == null) {
alshabibd61b77b2016-02-01 23:30:53 -0800441 log.error("Group for forwarding objective missing: {}", fwd);
442 fail(fwd, ObjectiveError.GROUPMISSING);
443 }
444
alshabib1aa58142016-02-17 15:37:56 -0800445 Group group = groupService.getGroup(deviceId, key);
alshabibd61b77b2016-02-01 23:30:53 -0800446 TrafficTreatment treatment =
447 buildTreatment(Instructions.createGroup(group.id()));
448
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000449 TrafficSelector.Builder selectorBuilder = buildIpv4SelectorForMulticast(fwd);
450
alshabibd61b77b2016-02-01 23:30:53 -0800451 FlowRule rule = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700452 .fromApp(fwd.appId())
alshabibd61b77b2016-02-01 23:30:53 -0800453 .forDevice(deviceId)
454 .forTable(0)
alshabibd61b77b2016-02-01 23:30:53 -0800455 .makePermanent()
456 .withPriority(fwd.priority())
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000457 .withSelector(selectorBuilder.build())
alshabibd61b77b2016-02-01 23:30:53 -0800458 .withTreatment(treatment)
459 .build();
460
461 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
462 switch (fwd.op()) {
463
464 case ADD:
465 builder.add(rule);
466 break;
467 case REMOVE:
468 builder.remove(rule);
469 break;
470 case ADD_TO_EXISTING:
471 case REMOVE_FROM_EXISTING:
472 break;
473 default:
474 log.warn("Unknown forwarding operation: {}", fwd.op());
475 }
476
Andrea Campanellad8e07632020-06-18 10:25:59 +0200477 applyFlowRules(ImmutableList.of(fwd), builder);
478
alshabibd61b77b2016-02-01 23:30:53 -0800479
480 }
481
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000482 private TrafficSelector.Builder buildIpv4SelectorForMulticast(ForwardingObjective fwd) {
483 TrafficSelector.Builder builderToUpdate = DefaultTrafficSelector.builder();
484
485 Optional<Criterion> vlanIdCriterion = readFromSelector(fwd.meta(), Criterion.Type.VLAN_VID);
486 if (vlanIdCriterion.isPresent()) {
487 VlanId assignedVlan = ((VlanIdCriterion) vlanIdCriterion.get()).vlanId();
488 builderToUpdate.matchVlanId(assignedVlan);
489 }
490
Esin Karamanec25a0a2020-03-18 14:29:29 +0000491 Optional<Criterion> innerVlanIdCriterion = readFromSelector(fwd.meta(), Criterion.Type.INNER_VLAN_VID);
492 if (innerVlanIdCriterion.isPresent()) {
493 VlanId assignedInnerVlan = ((VlanIdCriterion) innerVlanIdCriterion.get()).vlanId();
494 builderToUpdate.matchMetadata(assignedInnerVlan.toShort());
495 }
496
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000497 Optional<Criterion> ethTypeCriterion = readFromSelector(fwd.selector(), Criterion.Type.ETH_TYPE);
498 if (ethTypeCriterion.isPresent()) {
499 EthType ethType = ((EthTypeCriterion) ethTypeCriterion.get()).ethType();
500 builderToUpdate.matchEthType(ethType.toShort());
501 }
502
503 Optional<Criterion> ipv4DstCriterion = readFromSelector(fwd.selector(), Criterion.Type.IPV4_DST);
504 if (ipv4DstCriterion.isPresent()) {
505 IpPrefix ipv4Dst = ((IPCriterion) ipv4DstCriterion.get()).ip();
506 builderToUpdate.matchIPDst(ipv4Dst);
507 }
508
509 return builderToUpdate;
510 }
511
512 static Optional<Criterion> readFromSelector(TrafficSelector selector, Criterion.Type type) {
513 if (selector == null) {
514 return Optional.empty();
515 }
516 Criterion criterion = selector.getCriterion(type);
517 return (criterion == null)
518 ? Optional.empty() : Optional.of(criterion);
519 }
520
alshabibd61b77b2016-02-01 23:30:53 -0800521 private boolean checkForMulticast(ForwardingObjective fwd) {
522
alshabib1aa58142016-02-17 15:37:56 -0800523 IPCriterion ip = (IPCriterion) filterForCriterion(fwd.selector().criteria(),
alshabib56efe432016-02-25 17:57:24 -0500524 Criterion.Type.IPV4_DST);
alshabibd61b77b2016-02-01 23:30:53 -0800525
alshabib1aa58142016-02-17 15:37:56 -0800526 if (ip == null) {
527 return false;
528 }
529
Charles Chanaedabfd2016-02-26 09:31:48 -0800530 return ip.ip().isMulticast();
alshabibd61b77b2016-02-01 23:30:53 -0800531
532 }
533
alshabib1aa58142016-02-17 15:37:56 -0800534 private GroupKey getGroupForNextObjective(Integer nextId) {
alshabibd61b77b2016-02-01 23:30:53 -0800535 NextGroup next = flowObjectiveStore.getNextGroup(nextId);
alshabib1aa58142016-02-17 15:37:56 -0800536 return appKryo.deserialize(next.data());
alshabibd61b77b2016-02-01 23:30:53 -0800537
alshabib0ccde6d2015-05-30 18:22:36 -0700538 }
539
Amit Ghoshf1f22752018-08-14 07:28:01 +0100540 private void installNoModificationRules(ForwardingObjective fwd) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000541 Instructions.OutputInstruction output = (Instructions.OutputInstruction) fetchOutput(fwd, DOWNSTREAM);
Gamze Abakaa34469f2019-04-19 08:30:16 +0000542 Instructions.MetadataInstruction writeMetadata = fetchWriteMetadata(fwd);
543 Instructions.MeterInstruction meter = (Instructions.MeterInstruction) fetchMeter(fwd);
Amit Ghoshf1f22752018-08-14 07:28:01 +0100544
545 TrafficSelector selector = fwd.selector();
546
547 Criterion inport = selector.getCriterion(Criterion.Type.IN_PORT);
548 Criterion outerVlan = selector.getCriterion(Criterion.Type.VLAN_VID);
549 Criterion innerVlan = selector.getCriterion(Criterion.Type.INNER_VLAN_VID);
Amit Ghoshf1f22752018-08-14 07:28:01 +0100550
551 if (inport == null || output == null || innerVlan == null || outerVlan == null) {
Andrea Campanella969e8af2020-07-09 11:39:08 +0200552 // Avoid logging a non-error from lldp, bbdp and eapol core flows.
553 if (!fwd.appId().name().equals(CORE_APP_NAME)) {
554 log.error("Forwarding objective is underspecified: {}", fwd);
555 } else {
556 log.debug("Not installing unsupported core generated flow {}", fwd);
557 }
Amit Ghoshf1f22752018-08-14 07:28:01 +0100558 fail(fwd, ObjectiveError.BADPARAMS);
559 return;
560 }
561
Amit Ghoshf1f22752018-08-14 07:28:01 +0100562
563 FlowRule.Builder outer = DefaultFlowRule.builder()
564 .fromApp(fwd.appId())
565 .forDevice(deviceId)
566 .makePermanent()
567 .withPriority(fwd.priority())
Gamze Abakaa34469f2019-04-19 08:30:16 +0000568 .withSelector(buildSelector(inport, outerVlan))
569 .withTreatment(buildTreatment(output, writeMetadata, meter));
Amit Ghoshf1f22752018-08-14 07:28:01 +0100570
571 applyRules(fwd, outer);
572 }
573
alshabibfd430b62015-12-16 18:56:38 -0800574 private void installDownstreamRules(ForwardingObjective fwd) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000575 Instructions.OutputInstruction output = (Instructions.OutputInstruction) fetchOutput(fwd, DOWNSTREAM);
alshabibfd430b62015-12-16 18:56:38 -0800576
577 if (output == null) {
578 return;
579 }
580
alshabibfa0dc662016-01-13 11:23:53 -0800581 TrafficSelector selector = fwd.selector();
582
583 Criterion outerVlan = selector.getCriterion(Criterion.Type.VLAN_VID);
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000584 Criterion outerPbit = selector.getCriterion(Criterion.Type.VLAN_PCP);
Gamze Abakadadae722018-09-12 10:55:35 +0000585 Criterion innerVlanCriterion = selector.getCriterion(Criterion.Type.INNER_VLAN_VID);
alshabibfa0dc662016-01-13 11:23:53 -0800586 Criterion inport = selector.getCriterion(Criterion.Type.IN_PORT);
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000587 Criterion dstMac = selector.getCriterion(Criterion.Type.ETH_DST);
cboling651c6872018-10-05 11:09:22 -0500588
Gamze Abakadadae722018-09-12 10:55:35 +0000589 if (outerVlan == null || innerVlanCriterion == null || inport == null) {
Andrea Campanella969e8af2020-07-09 11:39:08 +0200590 // Avoid logging a non-error from lldp, bbdp and eapol core flows.
591 if (!fwd.appId().name().equals(CORE_APP_NAME)) {
592 log.error("Forwarding objective is underspecified: {}", fwd);
593 } else {
594 log.debug("Not installing unsupported core generated flow {}", fwd);
595 }
alshabibfa0dc662016-01-13 11:23:53 -0800596 fail(fwd, ObjectiveError.BADPARAMS);
597 return;
598 }
599
Gamze Abakadadae722018-09-12 10:55:35 +0000600 VlanId innerVlan = ((VlanIdCriterion) innerVlanCriterion).vlanId();
601 Criterion innerVid = Criteria.matchVlanId(innerVlan);
alshabib2f74f2c2016-01-14 13:29:35 -0800602
Amit Ghosha6859982020-02-12 09:35:45 +0000603 // In the case where the C-tag is the same for all the subscribers,
604 // we add a metadata with the outport in the selector to make the flow unique
605 Criterion innerSelectorMeta = Criteria.matchMetadata(output.port().toLong());
606
Gamze Abakadadae722018-09-12 10:55:35 +0000607 if (innerVlan.toShort() == VlanId.ANY_VALUE) {
Andrea Campanella6edac322020-01-29 14:41:42 +0100608 TrafficSelector outerSelector = buildSelector(inport, outerVlan, outerPbit, dstMac);
Gamze Abakadadae722018-09-12 10:55:35 +0000609 installDownstreamRulesForAnyVlan(fwd, output, outerSelector, buildSelector(inport,
Amit Ghosha6859982020-02-12 09:35:45 +0000610 Criteria.matchVlanId(VlanId.ANY), innerSelectorMeta));
Gamze Abakadadae722018-09-12 10:55:35 +0000611 } else {
Andrea Campanella6edac322020-01-29 14:41:42 +0100612 // Required to differentiate the same match flows
613 // Please note that S tag and S p bit values will be same for the same service - so conflict flows!
614 // Metadata match criteria solves the conflict issue - but not used by the voltha
615 // Maybe - find a better way to solve the above problem
616 Criterion metadata = Criteria.matchMetadata(innerVlan.toShort());
617 TrafficSelector outerSelector = buildSelector(inport, metadata, outerVlan, outerPbit, dstMac);
Amit Ghosha6859982020-02-12 09:35:45 +0000618 installDownstreamRulesForVlans(fwd, output, outerSelector, buildSelector(inport, innerVid,
619 innerSelectorMeta));
Gamze Abakadadae722018-09-12 10:55:35 +0000620 }
621 }
622
623 private void installDownstreamRulesForVlans(ForwardingObjective fwd, Instruction output,
624 TrafficSelector outerSelector, TrafficSelector innerSelector) {
625
626 List<Pair<Instruction, Instruction>> vlanOps =
627 vlanOps(fwd,
628 L2ModificationInstruction.L2SubType.VLAN_POP);
629
630 if (vlanOps == null || vlanOps.isEmpty()) {
631 return;
632 }
633
634 Pair<Instruction, Instruction> popAndRewrite = vlanOps.remove(0);
635
636 TrafficTreatment innerTreatment;
637 VlanId setVlanId = ((L2ModificationInstruction.ModVlanIdInstruction) popAndRewrite.getRight()).vlanId();
638 if (VlanId.NONE.equals(setVlanId)) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000639 innerTreatment = (buildTreatment(popAndRewrite.getLeft(), fetchMeter(fwd),
640 writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000641 } else {
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000642 innerTreatment = (buildTreatment(popAndRewrite.getRight(),
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000643 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000644 }
645
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000646 List<Instruction> setVlanPcps = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_PCP,
647 fwd.treatment().allInstructions());
648
649 Instruction innerPbitSet = null;
650
651 if (setVlanPcps != null && !setVlanPcps.isEmpty()) {
652 innerPbitSet = setVlanPcps.get(0);
653 }
654
655 VlanId remarkInnerVlan = null;
656 Optional<Criterion> vlanIdCriterion = readFromSelector(innerSelector, Criterion.Type.VLAN_VID);
657 if (vlanIdCriterion.isPresent()) {
658 remarkInnerVlan = ((VlanIdCriterion) vlanIdCriterion.get()).vlanId();
659 }
660
661 Instruction modVlanId = null;
662 if (innerPbitSet != null) {
663 modVlanId = Instructions.modVlanId(remarkInnerVlan);
664 }
665
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000666 //match: in port (nni), s-tag
667 //action: pop vlan (s-tag), write metadata, go to table 1, meter
alshabibfa0dc662016-01-13 11:23:53 -0800668 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700669 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800670 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800671 .makePermanent()
672 .withPriority(fwd.priority())
Gamze Abakadadae722018-09-12 10:55:35 +0000673 .withSelector(outerSelector)
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000674 .withTreatment(buildTreatment(popAndRewrite.getLeft(), modVlanId,
675 innerPbitSet, fetchMeter(fwd), fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE)));
alshabibfd430b62015-12-16 18:56:38 -0800676
Gamze Abakadadae722018-09-12 10:55:35 +0000677 //match: in port (nni), c-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000678 //action: immediate: write metadata and pop, meter, output
alshabibfa0dc662016-01-13 11:23:53 -0800679 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700680 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800681 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800682 .forTable(QQ_TABLE)
683 .makePermanent()
684 .withPriority(fwd.priority())
Gamze Abakadadae722018-09-12 10:55:35 +0000685 .withSelector(innerSelector)
686 .withTreatment(innerTreatment);
687 applyRules(fwd, inner, outer);
688 }
689
690 private void installDownstreamRulesForAnyVlan(ForwardingObjective fwd, Instruction output,
691 TrafficSelector outerSelector, TrafficSelector innerSelector) {
692
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000693 //match: in port (nni), s-tag
694 //action: immediate: write metadata, pop vlan, meter and go to table 1
Gamze Abakadadae722018-09-12 10:55:35 +0000695 FlowRule.Builder outer = DefaultFlowRule.builder()
696 .fromApp(fwd.appId())
697 .forDevice(deviceId)
698 .makePermanent()
699 .withPriority(fwd.priority())
700 .withSelector(outerSelector)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000701 .withTreatment(buildTreatment(Instructions.popVlan(), fetchMeter(fwd),
702 fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE)));
Gamze Abakadadae722018-09-12 10:55:35 +0000703
704 //match: in port (nni) and s-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000705 //action: immediate : write metadata, meter and output
Gamze Abakadadae722018-09-12 10:55:35 +0000706 FlowRule.Builder inner = DefaultFlowRule.builder()
707 .fromApp(fwd.appId())
708 .forDevice(deviceId)
709 .forTable(QQ_TABLE)
710 .makePermanent()
711 .withPriority(fwd.priority())
712 .withSelector(innerSelector)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000713 .withTreatment(buildTreatment(fetchMeter(fwd),
714 writeMetadataIncludingOnlyTp(fwd), output));
alshabibfd430b62015-12-16 18:56:38 -0800715
716 applyRules(fwd, inner, outer);
alshabibfd430b62015-12-16 18:56:38 -0800717 }
718
719 private void installUpstreamRules(ForwardingObjective fwd) {
720 List<Pair<Instruction, Instruction>> vlanOps =
721 vlanOps(fwd,
722 L2ModificationInstruction.L2SubType.VLAN_PUSH);
723
Gamze Abakadadae722018-09-12 10:55:35 +0000724 if (vlanOps == null || vlanOps.isEmpty()) {
alshabibfd430b62015-12-16 18:56:38 -0800725 return;
726 }
727
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000728 Instruction output = fetchOutput(fwd, UPSTREAM);
alshabibfd430b62015-12-16 18:56:38 -0800729
730 if (output == null) {
731 return;
732 }
733
alshabibfd430b62015-12-16 18:56:38 -0800734 Pair<Instruction, Instruction> outerPair = vlanOps.remove(0);
735
Gamze Abakadadae722018-09-12 10:55:35 +0000736 boolean noneValueVlanStatus = checkNoneVlanCriteria(fwd);
737 boolean anyValueVlanStatus = checkAnyVlanMatchCriteria(fwd);
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700738
Gamze Abakadadae722018-09-12 10:55:35 +0000739 if (anyValueVlanStatus) {
740 installUpstreamRulesForAnyVlan(fwd, output, outerPair);
741 } else {
Andrea Campanella6edac322020-01-29 14:41:42 +0100742 Pair<Instruction, Instruction> innerPair = outerPair;
743 outerPair = vlanOps.remove(0);
Gamze Abakadadae722018-09-12 10:55:35 +0000744 installUpstreamRulesForVlans(fwd, output, innerPair, outerPair, noneValueVlanStatus);
745 }
746 }
747
748 private void installUpstreamRulesForVlans(ForwardingObjective fwd, Instruction output,
749 Pair<Instruction, Instruction> innerPair,
750 Pair<Instruction, Instruction> outerPair, Boolean noneValueVlanStatus) {
751
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000752 List<Instruction> setVlanPcps = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_PCP,
753 fwd.treatment().allInstructions());
754
755 Instruction innerPbitSet = null;
756 Instruction outerPbitSet = null;
757
758 if (setVlanPcps != null && !setVlanPcps.isEmpty()) {
759 innerPbitSet = setVlanPcps.get(0);
760 outerPbitSet = setVlanPcps.get(1);
761 }
762
Gamze Abakadadae722018-09-12 10:55:35 +0000763 TrafficTreatment innerTreatment;
764 if (noneValueVlanStatus) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000765 innerTreatment = buildTreatment(innerPair.getLeft(), innerPair.getRight(), fetchMeter(fwd),
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000766 fetchWriteMetadata(fwd), innerPbitSet,
767 Instructions.transition(QQ_TABLE));
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700768 } else {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000769 innerTreatment = buildTreatment(innerPair.getRight(), fetchMeter(fwd), fetchWriteMetadata(fwd),
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000770 innerPbitSet, Instructions.transition(QQ_TABLE));
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700771 }
772
Gamze Abakadadae722018-09-12 10:55:35 +0000773 //match: in port, vlanId (0 or None)
774 //action:
775 //if vlanId None, push & set c-tag go to table 1
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000776 //if vlanId 0 or any specific vlan, set c-tag, write metadata, meter and go to table 1
alshabibfd430b62015-12-16 18:56:38 -0800777 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700778 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800779 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800780 .makePermanent()
781 .withPriority(fwd.priority())
782 .withSelector(fwd.selector())
Gamze Abakadadae722018-09-12 10:55:35 +0000783 .withTreatment(innerTreatment);
alshabibfd430b62015-12-16 18:56:38 -0800784
785 PortCriterion inPort = (PortCriterion)
786 fwd.selector().getCriterion(Criterion.Type.IN_PORT);
787
788 VlanId cVlanId = ((L2ModificationInstruction.ModVlanIdInstruction)
789 innerPair.getRight()).vlanId();
790
Gamze Abakadadae722018-09-12 10:55:35 +0000791 //match: in port, c-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000792 //action: immediate: push s-tag, write metadata, meter and output
alshabibfd430b62015-12-16 18:56:38 -0800793 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700794 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800795 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800796 .forTable(QQ_TABLE)
797 .makePermanent()
798 .withPriority(fwd.priority())
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000799 .withTreatment(buildTreatment(outerPair.getLeft(), outerPair.getRight(),
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000800 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd),
801 outerPbitSet, output));
802
803 if (innerPbitSet != null) {
804 byte innerPbit = ((L2ModificationInstruction.ModVlanPcpInstruction)
805 innerPbitSet).vlanPcp();
806 outer.withSelector(buildSelector(inPort, Criteria.matchVlanId(cVlanId), Criteria.matchVlanPcp(innerPbit)));
807 } else {
808 outer.withSelector(buildSelector(inPort, Criteria.matchVlanId(cVlanId)));
809 }
alshabibfd430b62015-12-16 18:56:38 -0800810
811 applyRules(fwd, inner, outer);
Gamze Abakadadae722018-09-12 10:55:35 +0000812 }
alshabibfd430b62015-12-16 18:56:38 -0800813
Gamze Abakadadae722018-09-12 10:55:35 +0000814 private void installUpstreamRulesForAnyVlan(ForwardingObjective fwd, Instruction output,
815 Pair<Instruction, Instruction> outerPair) {
816
817 log.debug("Installing upstream rules for any value vlan");
818
819 //match: in port and any-vlan (coming from OLT app.)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000820 //action: write metadata, go to table 1 and meter
Gamze Abakadadae722018-09-12 10:55:35 +0000821 FlowRule.Builder inner = DefaultFlowRule.builder()
822 .fromApp(fwd.appId())
823 .forDevice(deviceId)
824 .makePermanent()
825 .withPriority(fwd.priority())
826 .withSelector(fwd.selector())
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000827 .withTreatment(buildTreatment(Instructions.transition(QQ_TABLE), fetchMeter(fwd),
828 fetchWriteMetadata(fwd)));
Gamze Abakadadae722018-09-12 10:55:35 +0000829
Gamze Abakadadae722018-09-12 10:55:35 +0000830 //match: in port and any-vlan (coming from OLT app.)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000831 //action: immediate: push:QinQ, vlanId (s-tag), write metadata, meter and output
Gamze Abakadadae722018-09-12 10:55:35 +0000832 FlowRule.Builder outer = DefaultFlowRule.builder()
833 .fromApp(fwd.appId())
834 .forDevice(deviceId)
835 .forTable(QQ_TABLE)
836 .makePermanent()
837 .withPriority(fwd.priority())
838 .withSelector(fwd.selector())
Andrea Campanella6edac322020-01-29 14:41:42 +0100839 .withTreatment(buildTreatment(outerPair.getLeft(), outerPair.getRight(),
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000840 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000841
Andrea Campanella6edac322020-01-29 14:41:42 +0100842 applyRules(fwd, inner, outer);
Gamze Abakadadae722018-09-12 10:55:35 +0000843 }
844
845 private boolean checkNoneVlanCriteria(ForwardingObjective fwd) {
846 // Add the VLAN_PUSH treatment if we're matching on VlanId.NONE
847 Criterion vlanMatchCriterion = filterForCriterion(fwd.selector().criteria(), Criterion.Type.VLAN_VID);
848 boolean noneValueVlanStatus = false;
849 if (vlanMatchCriterion != null) {
850 noneValueVlanStatus = ((VlanIdCriterion) vlanMatchCriterion).vlanId().equals(VlanId.NONE);
851 }
852 return noneValueVlanStatus;
853 }
854
855 private boolean checkAnyVlanMatchCriteria(ForwardingObjective fwd) {
856 Criterion anyValueVlanCriterion = fwd.selector().criteria().stream()
857 .filter(c -> c.type().equals(Criterion.Type.VLAN_VID))
858 .filter(vc -> ((VlanIdCriterion) vc).vlanId().toShort() == VlanId.ANY_VALUE)
859 .findAny().orElse(null);
860
861 if (anyValueVlanCriterion == null) {
Andrea Campanella6edac322020-01-29 14:41:42 +0100862 log.debug("Any value vlan match criteria is not found, criteria {}",
863 fwd.selector().criteria());
Gamze Abakadadae722018-09-12 10:55:35 +0000864 return false;
865 }
866
867 return true;
alshabibfd430b62015-12-16 18:56:38 -0800868 }
869
870 private Instruction fetchOutput(ForwardingObjective fwd, String direction) {
871 Instruction output = fwd.treatment().allInstructions().stream()
872 .filter(i -> i.type() == Instruction.Type.OUTPUT)
873 .findFirst().orElse(null);
874
875 if (output == null) {
876 log.error("OLT {} rule has no output", direction);
877 fail(fwd, ObjectiveError.BADPARAMS);
878 return null;
879 }
880 return output;
881 }
882
Gamze Abakadadae722018-09-12 10:55:35 +0000883 private Instruction fetchMeter(ForwardingObjective fwd) {
884 Instruction meter = fwd.treatment().metered();
885
886 if (meter == null) {
887 log.debug("Meter instruction is not found for the forwarding objective {}", fwd);
888 return null;
889 }
890
891 log.debug("Meter instruction is found.");
892 return meter;
893 }
894
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000895 private Instructions.MetadataInstruction fetchWriteMetadata(ForwardingObjective fwd) {
896 Instructions.MetadataInstruction writeMetadata = fwd.treatment().writeMetadata();
Gamze Abakadadae722018-09-12 10:55:35 +0000897
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000898 if (writeMetadata == null) {
899 log.warn("Write metadata is not found for the forwarding obj");
900 fail(fwd, ObjectiveError.BADPARAMS);
Gamze Abakadadae722018-09-12 10:55:35 +0000901 return null;
902 }
903
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000904 log.debug("Write metadata is found {}", writeMetadata);
905 return writeMetadata;
Gamze Abakadadae722018-09-12 10:55:35 +0000906 }
907
alshabibfd430b62015-12-16 18:56:38 -0800908 private List<Pair<Instruction, Instruction>> vlanOps(ForwardingObjective fwd,
909 L2ModificationInstruction.L2SubType type) {
910
911 List<Pair<Instruction, Instruction>> vlanOps = findVlanOps(
912 fwd.treatment().allInstructions(), type);
913
Gamze Abakadadae722018-09-12 10:55:35 +0000914 if (vlanOps == null || vlanOps.isEmpty()) {
alshabibfd430b62015-12-16 18:56:38 -0800915 String direction = type == L2ModificationInstruction.L2SubType.VLAN_POP
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000916 ? DOWNSTREAM : UPSTREAM;
alshabibfd430b62015-12-16 18:56:38 -0800917 log.error("Missing vlan operations in {} forwarding: {}", direction, fwd);
918 fail(fwd, ObjectiveError.BADPARAMS);
Gamze Abakadadae722018-09-12 10:55:35 +0000919 return ImmutableList.of();
alshabibfd430b62015-12-16 18:56:38 -0800920 }
921 return vlanOps;
922 }
923
924
925 private List<Pair<Instruction, Instruction>> findVlanOps(List<Instruction> instructions,
alshabibd61b77b2016-02-01 23:30:53 -0800926 L2ModificationInstruction.L2SubType type) {
alshabibfd430b62015-12-16 18:56:38 -0800927
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000928 List<Instruction> vlanOperations = findL2Instructions(
alshabibfd430b62015-12-16 18:56:38 -0800929 type,
930 instructions);
931 List<Instruction> vlanSets = findL2Instructions(
932 L2ModificationInstruction.L2SubType.VLAN_ID,
933 instructions);
934
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000935 if (vlanOperations.size() != vlanSets.size()) {
Gamze Abakadadae722018-09-12 10:55:35 +0000936 return ImmutableList.of();
alshabibfd430b62015-12-16 18:56:38 -0800937 }
938
939 List<Pair<Instruction, Instruction>> pairs = Lists.newArrayList();
940
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000941 for (int i = 0; i < vlanOperations.size(); i++) {
942 pairs.add(new ImmutablePair<>(vlanOperations.get(i), vlanSets.get(i)));
alshabibfd430b62015-12-16 18:56:38 -0800943 }
944 return pairs;
945 }
946
947 private List<Instruction> findL2Instructions(L2ModificationInstruction.L2SubType subType,
948 List<Instruction> actions) {
949 return actions.stream()
950 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
951 .filter(i -> ((L2ModificationInstruction) i).subtype() == subType)
952 .collect(Collectors.toList());
953 }
954
Amit Ghoshf1f22752018-08-14 07:28:01 +0100955 private void provisionEthTypeBasedFilter(FilteringObjective filter,
956 EthTypeCriterion ethType,
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200957 Instructions.OutputInstruction output,
958 L2ModificationInstruction vlanId,
959 L2ModificationInstruction vlanPush) {
alshabibfd430b62015-12-16 18:56:38 -0800960
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000961 Instruction meter = filter.meta().metered();
962 Instruction writeMetadata = filter.meta().writeMetadata();
963
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200964 TrafficSelector selector = buildSelector(filter.key(), ethType);
965 TrafficTreatment treatment;
Gamze Abakaf57ef602019-03-11 06:52:48 +0000966
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200967 if (vlanPush == null || vlanId == null) {
968 treatment = buildTreatment(output, meter, writeMetadata);
969 } else {
970 // we need to push the vlan because it came untagged (ATT)
971 treatment = buildTreatment(output, meter, vlanPush, vlanId, writeMetadata);
972 }
973
alshabibfd430b62015-12-16 18:56:38 -0800974 buildAndApplyRule(filter, selector, treatment);
975
976 }
977
Jonathan Hart51539b82015-10-29 09:53:04 -0700978 private void provisionIgmp(FilteringObjective filter, EthTypeCriterion ethType,
alshabibfd430b62015-12-16 18:56:38 -0800979 IPProtocolCriterion ipProto,
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200980 Instructions.OutputInstruction output,
Andrea Campanella79bc5062020-09-21 14:34:00 +0200981 Instruction vlan, Instruction pcp) {
Gamze Abaka7c070c82019-02-21 14:40:18 +0000982
983 Instruction meter = filter.meta().metered();
984 Instruction writeMetadata = filter.meta().writeMetadata();
985
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200986 // uniTagMatch
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000987 VlanIdCriterion vlanId = (VlanIdCriterion) filterForCriterion(filter.conditions(),
988 Criterion.Type.VLAN_VID);
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000989
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200990 TrafficSelector selector = buildSelector(filter.key(), ethType, ipProto, vlanId);
991 TrafficTreatment treatment = buildTreatment(output, vlan, pcp, meter, writeMetadata);
alshabibfd430b62015-12-16 18:56:38 -0800992 buildAndApplyRule(filter, selector, treatment);
993 }
994
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000995 private void provisionDhcp(FilteringObjective filter, EthTypeCriterion ethType,
996 IPProtocolCriterion ipProto,
997 UdpPortCriterion udpSrcPort,
998 UdpPortCriterion udpDstPort,
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200999 Instruction vlanIdInstruction,
1000 Instruction vlanPcpInstruction,
Amit Ghoshcbaf8672016-12-23 21:36:19 +00001001 Instructions.OutputInstruction output) {
Gamze Abaka7c070c82019-02-21 14:40:18 +00001002
1003 Instruction meter = filter.meta().metered();
1004 Instruction writeMetadata = filter.meta().writeMetadata();
1005
Andrea Campanellaa93905c2020-06-11 16:09:39 +02001006 VlanIdCriterion matchVlanId = (VlanIdCriterion)
Gamze Abakafe9d54f2019-12-02 06:42:39 +00001007 filterForCriterion(filter.conditions(), Criterion.Type.VLAN_VID);
1008
Andrea Campanellaa93905c2020-06-11 16:09:39 +02001009 TrafficSelector selector;
1010 TrafficTreatment treatment;
1011
1012 if (matchVlanId != null) {
1013 log.debug("Building selector with match VLAN, {}", matchVlanId);
1014 // in case of TT upstream the packet comes tagged and the vlan is swapped.
1015 selector = buildSelector(filter.key(), ethType, ipProto, udpSrcPort,
1016 udpDstPort, matchVlanId);
1017 treatment = buildTreatment(output, meter, writeMetadata,
1018 vlanIdInstruction, vlanPcpInstruction);
1019 } else {
1020 log.debug("Building selector with no VLAN");
1021 // in case of ATT upstream the packet comes in untagged and we need to push the vlan
1022 selector = buildSelector(filter.key(), ethType, ipProto, udpSrcPort, udpDstPort);
1023 treatment = buildTreatment(output, meter, vlanIdInstruction, writeMetadata);
1024 }
1025 //In case of downstream there will be no match on the VLAN, which is null,
1026 // so it will just be output, meter, writeMetadata
1027
Amit Ghoshcbaf8672016-12-23 21:36:19 +00001028 buildAndApplyRule(filter, selector, treatment);
1029 }
Gamze Abakadadae722018-09-12 10:55:35 +00001030
alshabibfd430b62015-12-16 18:56:38 -08001031 private void buildAndApplyRule(FilteringObjective filter, TrafficSelector selector,
1032 TrafficTreatment treatment) {
1033 FlowRule rule = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -07001034 .fromApp(filter.appId())
alshabibfd430b62015-12-16 18:56:38 -08001035 .forDevice(deviceId)
1036 .forTable(0)
alshabibfd430b62015-12-16 18:56:38 -08001037 .makePermanent()
1038 .withSelector(selector)
1039 .withTreatment(treatment)
alshabibbb424232016-01-15 12:20:25 -08001040 .withPriority(filter.priority())
alshabibfd430b62015-12-16 18:56:38 -08001041 .build();
1042
Andrea Campanellad8e07632020-06-18 10:25:59 +02001043 if (accumulator != null) {
1044 if (log.isDebugEnabled()) {
1045 log.debug("Adding pair to batch: {}", Pair.of(filter, rule));
1046 }
1047 accumulator.add(Pair.of(filter, rule));
1048 } else {
1049 FlowRuleOperations.Builder opsBuilder = FlowRuleOperations.builder();
1050 switch (filter.type()) {
1051 case PERMIT:
1052 opsBuilder.add(rule);
1053 break;
1054 case DENY:
1055 opsBuilder.remove(rule);
1056 break;
1057 default:
1058 log.warn("Unknown filter type : {}", filter.type());
1059 fail(filter, ObjectiveError.UNSUPPORTED);
1060 }
1061 applyFlowRules(ImmutableList.of(filter), opsBuilder);
alshabibfd430b62015-12-16 18:56:38 -08001062 }
alshabibfd430b62015-12-16 18:56:38 -08001063 }
1064
Gamze Abakadadae722018-09-12 10:55:35 +00001065 private void applyRules(ForwardingObjective fwd, FlowRule.Builder... fwdBuilders) {
Amit Ghoshf1f22752018-08-14 07:28:01 +01001066 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
1067 switch (fwd.op()) {
1068 case ADD:
Gamze Abakadadae722018-09-12 10:55:35 +00001069 for (FlowRule.Builder fwdBuilder : fwdBuilders) {
1070 builder.add(fwdBuilder.build());
1071 }
Amit Ghoshf1f22752018-08-14 07:28:01 +01001072 break;
1073 case REMOVE:
Gamze Abakadadae722018-09-12 10:55:35 +00001074 for (FlowRule.Builder fwdBuilder : fwdBuilders) {
1075 builder.remove(fwdBuilder.build());
1076 }
alshabibfd430b62015-12-16 18:56:38 -08001077 break;
1078 case ADD_TO_EXISTING:
1079 break;
1080 case REMOVE_FROM_EXISTING:
1081 break;
1082 default:
1083 log.warn("Unknown forwarding operation: {}", fwd.op());
1084 }
1085
Andrea Campanellad8e07632020-06-18 10:25:59 +02001086 applyFlowRules(ImmutableList.of(fwd), builder);
1087
1088
alshabibfd430b62015-12-16 18:56:38 -08001089 }
1090
Andrea Campanellad8e07632020-06-18 10:25:59 +02001091 private void applyFlowRules(List<Objective> objectives, FlowRuleOperations.Builder builder) {
alshabibfd430b62015-12-16 18:56:38 -08001092 flowRuleService.apply(builder.build(new FlowRuleOperationsContext() {
1093 @Override
1094 public void onSuccess(FlowRuleOperations ops) {
Andrea Campanellad8e07632020-06-18 10:25:59 +02001095 objectives.forEach(obj -> {
1096 pass(obj);
1097 });
alshabibfd430b62015-12-16 18:56:38 -08001098 }
1099
1100 @Override
1101 public void onError(FlowRuleOperations ops) {
Andrea Campanellad8e07632020-06-18 10:25:59 +02001102 objectives.forEach(obj -> {
1103 fail(obj, ObjectiveError.FLOWINSTALLATIONFAILED);
1104 });
1105
alshabibfd430b62015-12-16 18:56:38 -08001106 }
1107 }));
1108 }
1109
Andrea Campanellad8e07632020-06-18 10:25:59 +02001110 // Builds the batch using the accumulated flow rules
1111 private void sendFilters(List<Pair<FilteringObjective, FlowRule>> pairs) {
1112 FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
1113 log.debug("Sending batch of {} filter-objs", pairs.size());
1114 List<Objective> filterObjs = Lists.newArrayList();
1115 // Iterates over all accumulated flow rules and then build an unique batch
1116 pairs.forEach(pair -> {
1117 FilteringObjective filter = pair.getLeft();
1118 FlowRule rule = pair.getRight();
1119 switch (filter.type()) {
1120 case PERMIT:
1121 flowOpsBuilder.add(rule);
1122 log.debug("Applying add filter-obj {} to device: {}", filter.id(), deviceId);
1123 filterObjs.add(filter);
1124 break;
1125 case DENY:
1126 flowOpsBuilder.remove(rule);
1127 log.debug("Deleting flow rule {} to device: {}", rule, deviceId);
1128 filterObjs.add(filter);
1129 break;
1130 default:
1131 fail(filter, ObjectiveError.UNKNOWN);
1132 log.warn("Unknown forwarding type {}", filter.type());
1133 }
1134 });
1135 if (log.isDebugEnabled()) {
1136 log.debug("Applying batch {}", flowOpsBuilder.build());
1137 }
1138 // Finally applies the operations
1139 applyFlowRules(filterObjs, flowOpsBuilder);
1140 }
1141
alshabibfd430b62015-12-16 18:56:38 -08001142 private Criterion filterForCriterion(Collection<Criterion> criteria, Criterion.Type type) {
1143 return criteria.stream()
alshabibbb424232016-01-15 12:20:25 -08001144 .filter(c -> c.type().equals(type))
alshabibfd430b62015-12-16 18:56:38 -08001145 .limit(1)
1146 .findFirst().orElse(null);
1147 }
1148
1149 private TrafficSelector buildSelector(Criterion... criteria) {
1150
alshabibfd430b62015-12-16 18:56:38 -08001151 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
1152
Gamze Abakaf57ef602019-03-11 06:52:48 +00001153 Arrays.stream(criteria).filter(Objects::nonNull).forEach(sBuilder::add);
alshabibfd430b62015-12-16 18:56:38 -08001154
1155 return sBuilder.build();
1156 }
1157
1158 private TrafficTreatment buildTreatment(Instruction... instructions) {
1159
alshabibfd430b62015-12-16 18:56:38 -08001160 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1161
Gamze Abaka6c8a71b2018-12-24 13:17:12 +00001162 Arrays.stream(instructions).filter(Objects::nonNull).forEach(tBuilder::add);
alshabibfd430b62015-12-16 18:56:38 -08001163
1164 return tBuilder.build();
1165 }
1166
Gamze Abaka6c8a71b2018-12-24 13:17:12 +00001167 private Instruction writeMetadataIncludingOnlyTp(ForwardingObjective fwd) {
1168
1169 return Instructions.writeMetadata(
1170 fetchWriteMetadata(fwd).metadata() & 0xFFFF00000000L, 0L);
1171 }
alshabibfd430b62015-12-16 18:56:38 -08001172
1173 private void fail(Objective obj, ObjectiveError error) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -08001174 obj.context().ifPresent(context -> context.onError(obj, error));
alshabibfd430b62015-12-16 18:56:38 -08001175 }
1176
1177 private void pass(Objective obj) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -08001178 obj.context().ifPresent(context -> context.onSuccess(obj));
alshabibfd430b62015-12-16 18:56:38 -08001179 }
1180
alshabib2cc73cb2015-06-30 20:26:56 -07001181
alshabibd61b77b2016-02-01 23:30:53 -08001182 private class InnerGroupListener implements GroupListener {
alshabib2cc73cb2015-06-30 20:26:56 -07001183 @Override
alshabibd61b77b2016-02-01 23:30:53 -08001184 public void event(GroupEvent event) {
Andrea Campanella5908b562020-05-06 16:09:10 +02001185 GroupKey key = event.subject().appCookie();
1186 NextObjective obj = pendingGroups.getIfPresent(key);
1187 if (obj == null) {
1188 log.debug("No pending group for {}, moving on", key);
1189 return;
1190 }
1191 log.trace("Event {} for group {}, handling pending" +
1192 "NextGroup {}", event.type(), key, obj.id());
ke hanf5086672016-08-12 11:09:17 +08001193 if (event.type() == GroupEvent.Type.GROUP_ADDED ||
Gamze Abakadadae722018-09-12 10:55:35 +00001194 event.type() == GroupEvent.Type.GROUP_UPDATED) {
alshabibd61b77b2016-02-01 23:30:53 -08001195 flowObjectiveStore.putNextGroup(obj.id(), new OLTPipelineGroup(key));
1196 pass(obj);
1197 pendingGroups.invalidate(key);
Andrea Campanella5908b562020-05-06 16:09:10 +02001198 } else if (event.type() == GroupEvent.Type.GROUP_REMOVED) {
1199 flowObjectiveStore.removeNextGroup(obj.id());
1200 pass(obj);
1201 pendingGroups.invalidate(key);
alshabibd61b77b2016-02-01 23:30:53 -08001202 }
alshabib2cc73cb2015-06-30 20:26:56 -07001203 }
1204 }
1205
alshabibd61b77b2016-02-01 23:30:53 -08001206 private static class OLTPipelineGroup implements NextGroup {
1207
1208 private final GroupKey key;
1209
1210 public OLTPipelineGroup(GroupKey key) {
1211 this.key = key;
1212 }
1213
1214 public GroupKey key() {
1215 return key;
1216 }
1217
1218 @Override
1219 public byte[] data() {
1220 return appKryo.serialize(key);
1221 }
1222
1223 }
Saurav Das24431192016-03-07 19:13:00 -08001224
1225 @Override
1226 public List<String> getNextMappings(NextGroup nextGroup) {
1227 // TODO Implementation deferred to vendor
1228 return null;
1229 }
Andrea Campanellad8e07632020-06-18 10:25:59 +02001230
1231 // Flow rules accumulator for reducing the number of transactions required to the devices.
1232 private final class ObjectiveAccumulator
1233 extends AbstractAccumulator<Pair<FilteringObjective, FlowRule>> {
1234
1235 ObjectiveAccumulator(int maxFilter, int maxBatchMS, int maxIdleMS) {
1236 super(TIMER, maxFilter, maxBatchMS, maxIdleMS);
1237 }
1238
1239 @Override
1240 public void processItems(List<Pair<FilteringObjective, FlowRule>> pairs) {
1241 // Triggers creation of a batch using the list of flowrules generated from objs.
1242 accumulatorExecutorService.execute(new FlowRulesBuilderTask(pairs));
1243 }
1244 }
1245
1246 // Task for building batch of flow rules in a separate thread.
1247 private final class FlowRulesBuilderTask implements Runnable {
1248 private final List<Pair<FilteringObjective, FlowRule>> pairs;
1249
1250 FlowRulesBuilderTask(List<Pair<FilteringObjective, FlowRule>> pairs) {
1251 this.pairs = pairs;
1252 }
1253
1254 @Override
1255 public void run() {
1256 try {
1257 sendFilters(pairs);
1258 } catch (Exception e) {
1259 log.warn("Unable to send objectives", e);
1260 }
1261 }
1262 }
alshabib0ccde6d2015-05-30 18:22:36 -07001263}