blob: dd72436c44ba60565bc68bdddded6500962782c4 [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;
alshabibd61b77b2016-02-01 23:30:53 -080032import org.onlab.util.KryoNamespace;
Jonathan Hartdfc3b862015-07-01 14:49:56 -070033import org.onosproject.core.ApplicationId;
34import org.onosproject.core.CoreService;
alshabib0ccde6d2015-05-30 18:22:36 -070035import org.onosproject.net.DeviceId;
36import org.onosproject.net.PortNumber;
alshabibd61b77b2016-02-01 23:30:53 -080037import org.onosproject.net.behaviour.NextGroup;
alshabib0ccde6d2015-05-30 18:22:36 -070038import org.onosproject.net.behaviour.Pipeliner;
39import org.onosproject.net.behaviour.PipelinerContext;
40import org.onosproject.net.driver.AbstractHandlerBehaviour;
41import org.onosproject.net.flow.DefaultFlowRule;
Jonathan Hartdfc3b862015-07-01 14:49:56 -070042import org.onosproject.net.flow.DefaultTrafficSelector;
alshabib0ccde6d2015-05-30 18:22:36 -070043import org.onosproject.net.flow.DefaultTrafficTreatment;
44import org.onosproject.net.flow.FlowRule;
45import org.onosproject.net.flow.FlowRuleOperations;
46import org.onosproject.net.flow.FlowRuleOperationsContext;
47import org.onosproject.net.flow.FlowRuleService;
48import org.onosproject.net.flow.TrafficSelector;
49import org.onosproject.net.flow.TrafficTreatment;
alshabibfd430b62015-12-16 18:56:38 -080050import org.onosproject.net.flow.criteria.Criteria;
51import org.onosproject.net.flow.criteria.Criterion;
52import org.onosproject.net.flow.criteria.EthTypeCriterion;
alshabib1aa58142016-02-17 15:37:56 -080053import org.onosproject.net.flow.criteria.IPCriterion;
alshabibfd430b62015-12-16 18:56:38 -080054import org.onosproject.net.flow.criteria.IPProtocolCriterion;
55import org.onosproject.net.flow.criteria.PortCriterion;
Amit Ghoshcbaf8672016-12-23 21:36:19 +000056import org.onosproject.net.flow.criteria.UdpPortCriterion;
alshabib2f74f2c2016-01-14 13:29:35 -080057import org.onosproject.net.flow.criteria.VlanIdCriterion;
alshabibfd430b62015-12-16 18:56:38 -080058import org.onosproject.net.flow.instructions.Instruction;
alshabib0ccde6d2015-05-30 18:22:36 -070059import org.onosproject.net.flow.instructions.Instructions;
alshabibfd430b62015-12-16 18:56:38 -080060import org.onosproject.net.flow.instructions.L2ModificationInstruction;
alshabib0ccde6d2015-05-30 18:22:36 -070061import org.onosproject.net.flowobjective.FilteringObjective;
alshabibd61b77b2016-02-01 23:30:53 -080062import org.onosproject.net.flowobjective.FlowObjectiveStore;
alshabib0ccde6d2015-05-30 18:22:36 -070063import org.onosproject.net.flowobjective.ForwardingObjective;
64import org.onosproject.net.flowobjective.NextObjective;
alshabibfd430b62015-12-16 18:56:38 -080065import org.onosproject.net.flowobjective.Objective;
alshabib0ccde6d2015-05-30 18:22:36 -070066import org.onosproject.net.flowobjective.ObjectiveError;
alshabibd61b77b2016-02-01 23:30:53 -080067import org.onosproject.net.group.DefaultGroupBucket;
68import org.onosproject.net.group.DefaultGroupDescription;
69import org.onosproject.net.group.DefaultGroupKey;
70import org.onosproject.net.group.Group;
71import org.onosproject.net.group.GroupBucket;
72import org.onosproject.net.group.GroupBuckets;
73import org.onosproject.net.group.GroupDescription;
74import org.onosproject.net.group.GroupEvent;
75import org.onosproject.net.group.GroupKey;
76import org.onosproject.net.group.GroupListener;
77import org.onosproject.net.group.GroupService;
78import org.onosproject.store.serializers.KryoNamespaces;
alshabib5ccbe3f2016-03-02 22:36:02 -080079import org.onosproject.store.service.StorageService;
alshabib0ccde6d2015-05-30 18:22:36 -070080import org.slf4j.Logger;
81
Gamze Abakafe9d54f2019-12-02 06:42:39 +000082import java.util.Arrays;
alshabibfd430b62015-12-16 18:56:38 -080083import java.util.Collection;
alshabibd61b77b2016-02-01 23:30:53 -080084import java.util.Collections;
alshabibfd430b62015-12-16 18:56:38 -080085import java.util.List;
Gamze Abakafe9d54f2019-12-02 06:42:39 +000086import java.util.Objects;
alshabibfd430b62015-12-16 18:56:38 -080087import java.util.Optional;
alshabibd61b77b2016-02-01 23:30:53 -080088import java.util.concurrent.TimeUnit;
alshabibfd430b62015-12-16 18:56:38 -080089import java.util.stream.Collectors;
90
Andrea Campanella969e8af2020-07-09 11:39:08 +020091import static org.onosproject.core.CoreService.CORE_APP_NAME;
alshabib0ccde6d2015-05-30 18:22:36 -070092import static org.slf4j.LoggerFactory.getLogger;
93
94/**
Jonathan Hart64da69d2015-07-15 15:10:28 -070095 * Pipeliner for OLT device.
alshabib0ccde6d2015-05-30 18:22:36 -070096 */
alshabibfd430b62015-12-16 18:56:38 -080097
Jonathan Hartb92cc512015-11-16 23:05:21 -080098public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
alshabib0ccde6d2015-05-30 18:22:36 -070099
alshabibfd430b62015-12-16 18:56:38 -0800100 private static final Integer QQ_TABLE = 1;
Gamze Abakadadae722018-09-12 10:55:35 +0000101 private static final int NO_ACTION_PRIORITY = 500;
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000102 private static final String DOWNSTREAM = "downstream";
103 private static final String UPSTREAM = "upstream";
alshabib0ccde6d2015-05-30 18:22:36 -0700104 private final Logger log = getLogger(getClass());
105
106 private ServiceDirectory serviceDirectory;
107 private FlowRuleService flowRuleService;
alshabibd61b77b2016-02-01 23:30:53 -0800108 private GroupService groupService;
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700109 private CoreService coreService;
alshabib5ccbe3f2016-03-02 22:36:02 -0800110 private StorageService storageService;
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700111
alshabibd61b77b2016-02-01 23:30:53 -0800112 private DeviceId deviceId;
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700113 private ApplicationId appId;
alshabib83364472016-03-25 09:59:55 -0700114
alshabib0ccde6d2015-05-30 18:22:36 -0700115
alshabibd61b77b2016-02-01 23:30:53 -0800116 protected FlowObjectiveStore flowObjectiveStore;
117
118 private Cache<GroupKey, NextObjective> pendingGroups;
119
120 protected static KryoNamespace appKryo = new KryoNamespace.Builder()
121 .register(KryoNamespaces.API)
122 .register(GroupKey.class)
123 .register(DefaultGroupKey.class)
124 .register(OLTPipelineGroup.class)
Charles Chaneefdedf2016-05-23 16:45:45 -0700125 .build("OltPipeline");
alshabib2cc73cb2015-06-30 20:26:56 -0700126
alshabib0ccde6d2015-05-30 18:22:36 -0700127 @Override
128 public void init(DeviceId deviceId, PipelinerContext context) {
alshabibfd430b62015-12-16 18:56:38 -0800129 log.debug("Initiate OLT pipeline");
alshabib0ccde6d2015-05-30 18:22:36 -0700130 this.serviceDirectory = context.directory();
131 this.deviceId = deviceId;
alshabibd61b77b2016-02-01 23:30:53 -0800132
alshabib0ccde6d2015-05-30 18:22:36 -0700133 flowRuleService = serviceDirectory.get(FlowRuleService.class);
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700134 coreService = serviceDirectory.get(CoreService.class);
alshabibd61b77b2016-02-01 23:30:53 -0800135 groupService = serviceDirectory.get(GroupService.class);
136 flowObjectiveStore = context.store();
alshabib5ccbe3f2016-03-02 22:36:02 -0800137 storageService = serviceDirectory.get(StorageService.class);
138
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700139 appId = coreService.registerApplication(
140 "org.onosproject.driver.OLTPipeline");
141
alshabibd61b77b2016-02-01 23:30:53 -0800142
143 pendingGroups = CacheBuilder.newBuilder()
144 .expireAfterWrite(20, TimeUnit.SECONDS)
145 .removalListener((RemovalNotification<GroupKey, NextObjective> notification) -> {
146 if (notification.getCause() == RemovalCause.EXPIRED) {
147 fail(notification.getValue(), ObjectiveError.GROUPINSTALLATIONFAILED);
148 }
149 }).build();
150
151 groupService.addListener(new InnerGroupListener());
152
alshabibb32cefe2015-06-08 18:15:05 -0700153 }
154
alshabib0ccde6d2015-05-30 18:22:36 -0700155 @Override
156 public void filter(FilteringObjective filter) {
alshabibfd430b62015-12-16 18:56:38 -0800157 Instructions.OutputInstruction output;
alshabib0ccde6d2015-05-30 18:22:36 -0700158
alshabibfd430b62015-12-16 18:56:38 -0800159 if (filter.meta() != null && !filter.meta().immediate().isEmpty()) {
160 output = (Instructions.OutputInstruction) filter.meta().immediate().stream()
161 .filter(t -> t.type().equals(Instruction.Type.OUTPUT))
162 .limit(1)
163 .findFirst().get();
alshabib0ccde6d2015-05-30 18:22:36 -0700164
alshabibbb424232016-01-15 12:20:25 -0800165 if (output == null || !output.port().equals(PortNumber.CONTROLLER)) {
dvaddire8e6b89a2017-08-31 21:54:03 +0530166 log.warn("OLT can only filter packet to controller");
alshabibfd430b62015-12-16 18:56:38 -0800167 fail(filter, ObjectiveError.UNSUPPORTED);
168 return;
alshabib0ccde6d2015-05-30 18:22:36 -0700169 }
alshabibfd430b62015-12-16 18:56:38 -0800170 } else {
171 fail(filter, ObjectiveError.BADPARAMS);
alshabib0ccde6d2015-05-30 18:22:36 -0700172 return;
173 }
174
alshabibfd430b62015-12-16 18:56:38 -0800175 if (filter.key().type() != Criterion.Type.IN_PORT) {
176 fail(filter, ObjectiveError.BADPARAMS);
177 return;
178 }
179
180 EthTypeCriterion ethType = (EthTypeCriterion)
181 filterForCriterion(filter.conditions(), Criterion.Type.ETH_TYPE);
182
183 if (ethType == null) {
184 fail(filter, ObjectiveError.BADPARAMS);
185 return;
186 }
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200187 Optional<Instruction> vlanId = filter.meta().immediate().stream()
188 .filter(t -> t.type().equals(Instruction.Type.L2MODIFICATION)
189 && ((L2ModificationInstruction) t).subtype()
190 .equals(L2ModificationInstruction.L2SubType.VLAN_ID))
191 .limit(1)
192 .findFirst();
193
194 Optional<Instruction> vlanPcp = filter.meta().immediate().stream()
195 .filter(t -> t.type().equals(Instruction.Type.L2MODIFICATION)
196 && ((L2ModificationInstruction) t).subtype()
197 .equals(L2ModificationInstruction.L2SubType.VLAN_PCP))
198 .limit(1)
199 .findFirst();
200
201 Optional<Instruction> vlanPush = filter.meta().immediate().stream()
202 .filter(t -> t.type().equals(Instruction.Type.L2MODIFICATION)
203 && ((L2ModificationInstruction) t).subtype()
204 .equals(L2ModificationInstruction.L2SubType.VLAN_PUSH))
205 .limit(1)
206 .findFirst();
alshabibfd430b62015-12-16 18:56:38 -0800207
alshabibbb424232016-01-15 12:20:25 -0800208 if (ethType.ethType().equals(EthType.EtherType.EAPOL.ethType())) {
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200209
210 if (vlanId.isEmpty() || vlanPush.isEmpty()) {
211 log.warn("Missing EAPOL vlan or vlanPush");
212 fail(filter, ObjectiveError.BADPARAMS);
213 return;
214 }
215 provisionEthTypeBasedFilter(filter, ethType, output,
216 (L2ModificationInstruction) vlanId.get(),
217 (L2ModificationInstruction) vlanPush.get());
Amit Ghoshf1f22752018-08-14 07:28:01 +0100218 } else if (ethType.ethType().equals(EthType.EtherType.LLDP.ethType())) {
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200219 provisionEthTypeBasedFilter(filter, ethType, output, null, null);
Amit Ghoshf1f22752018-08-14 07:28:01 +0100220
alshabibbb424232016-01-15 12:20:25 -0800221 } else if (ethType.ethType().equals(EthType.EtherType.IPV4.ethType())) {
alshabibfd430b62015-12-16 18:56:38 -0800222 IPProtocolCriterion ipProto = (IPProtocolCriterion)
223 filterForCriterion(filter.conditions(), Criterion.Type.IP_PROTO);
dvaddire8e6b89a2017-08-31 21:54:03 +0530224 if (ipProto == null) {
225 log.warn("OLT can only filter IGMP and DHCP");
226 fail(filter, ObjectiveError.UNSUPPORTED);
227 return;
228 }
alshabibfd430b62015-12-16 18:56:38 -0800229 if (ipProto.protocol() == IPv4.PROTOCOL_IGMP) {
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200230 provisionIgmp(filter, ethType, ipProto, output,
Andrea Campanella79bc5062020-09-21 14:34:00 +0200231 vlanId.orElse(null),
232 vlanPcp.orElse(null));
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000233 } else if (ipProto.protocol() == IPv4.PROTOCOL_UDP) {
234 UdpPortCriterion udpSrcPort = (UdpPortCriterion)
235 filterForCriterion(filter.conditions(), Criterion.Type.UDP_SRC);
236
237 UdpPortCriterion udpDstPort = (UdpPortCriterion)
238 filterForCriterion(filter.conditions(), Criterion.Type.UDP_DST);
239
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700240 if ((udpSrcPort.udpPort().toInt() == 67 && udpDstPort.udpPort().toInt() == 68) ||
241 (udpSrcPort.udpPort().toInt() == 68 && udpDstPort.udpPort().toInt() == 67)) {
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200242 provisionDhcp(filter, ethType, ipProto, udpSrcPort, udpDstPort, vlanId.orElse(null),
243 vlanPcp.orElse(null), output);
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700244 } else {
245 log.warn("Filtering rule with unsupported UDP src {} or dst {} port", udpSrcPort, udpDstPort);
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000246 fail(filter, ObjectiveError.UNSUPPORTED);
247 }
alshabibbb424232016-01-15 12:20:25 -0800248 } else {
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700249 log.warn("Currently supporting only IGMP and DHCP filters for IPv4 packets");
250 fail(filter, ObjectiveError.UNSUPPORTED);
251 }
252 } else if (ethType.ethType().equals(EthType.EtherType.IPV6.ethType())) {
253 IPProtocolCriterion ipProto = (IPProtocolCriterion)
254 filterForCriterion(filter.conditions(), Criterion.Type.IP_PROTO);
255 if (ipProto == null) {
256 log.warn("OLT can only filter DHCP");
257 fail(filter, ObjectiveError.UNSUPPORTED);
258 return;
259 }
260 if (ipProto.protocol() == IPv6.PROTOCOL_UDP) {
261 UdpPortCriterion udpSrcPort = (UdpPortCriterion)
262 filterForCriterion(filter.conditions(), Criterion.Type.UDP_SRC);
263
264 UdpPortCriterion udpDstPort = (UdpPortCriterion)
265 filterForCriterion(filter.conditions(), Criterion.Type.UDP_DST);
266
267 if ((udpSrcPort.udpPort().toInt() == 546 && udpDstPort.udpPort().toInt() == 547) ||
268 (udpSrcPort.udpPort().toInt() == 547 && udpDstPort.udpPort().toInt() == 546)) {
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200269 provisionDhcp(filter, ethType, ipProto, udpSrcPort, udpDstPort, vlanId.orElse(null),
270 vlanPcp.orElse(null), output);
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700271 } else {
272 log.warn("Filtering rule with unsupported UDP src {} or dst {} port", udpSrcPort, udpDstPort);
273 fail(filter, ObjectiveError.UNSUPPORTED);
274 }
275 } else {
276 log.warn("Currently supporting only DHCP filters for IPv6 packets");
alshabibbb424232016-01-15 12:20:25 -0800277 fail(filter, ObjectiveError.UNSUPPORTED);
alshabibfd430b62015-12-16 18:56:38 -0800278 }
279 } else {
dvaddire8e6b89a2017-08-31 21:54:03 +0530280 log.warn("\nOnly the following are Supported in OLT for filter ->\n"
Amit Ghoshf1f22752018-08-14 07:28:01 +0100281 + "ETH TYPE : EAPOL, LLDP and IPV4\n"
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700282 + "IPV4 TYPE: IGMP and UDP (for DHCP)"
283 + "IPV6 TYPE: UDP (for DHCP)");
alshabibfd430b62015-12-16 18:56:38 -0800284 fail(filter, ObjectiveError.UNSUPPORTED);
285 }
286
287 }
288
289
290 @Override
291 public void forward(ForwardingObjective fwd) {
Andrea Campanella6edac322020-01-29 14:41:42 +0100292 log.debug("Installing forwarding objective {}", fwd);
alshabibd61b77b2016-02-01 23:30:53 -0800293 if (checkForMulticast(fwd)) {
294 processMulticastRule(fwd);
295 return;
296 }
297
alshabib0ccde6d2015-05-30 18:22:36 -0700298 TrafficTreatment treatment = fwd.treatment();
alshabib0ccde6d2015-05-30 18:22:36 -0700299
alshabibfd430b62015-12-16 18:56:38 -0800300 List<Instruction> instructions = treatment.allInstructions();
alshabib0ccde6d2015-05-30 18:22:36 -0700301
Gamze Abakadadae722018-09-12 10:55:35 +0000302 Optional<Instruction> vlanInstruction = instructions.stream()
alshabibfd430b62015-12-16 18:56:38 -0800303 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
304 .filter(i -> ((L2ModificationInstruction) i).subtype() ==
305 L2ModificationInstruction.L2SubType.VLAN_PUSH ||
306 ((L2ModificationInstruction) i).subtype() ==
307 L2ModificationInstruction.L2SubType.VLAN_POP)
308 .findAny();
309
Gamze Abakadadae722018-09-12 10:55:35 +0000310
311 if (!vlanInstruction.isPresent()) {
Amit Ghoshf1f22752018-08-14 07:28:01 +0100312 installNoModificationRules(fwd);
alshabib0ccde6d2015-05-30 18:22:36 -0700313 } else {
Amit Ghoshf1f22752018-08-14 07:28:01 +0100314 L2ModificationInstruction vlanIns =
Gamze Abakadadae722018-09-12 10:55:35 +0000315 (L2ModificationInstruction) vlanInstruction.get();
Amit Ghoshf1f22752018-08-14 07:28:01 +0100316 if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
317 installUpstreamRules(fwd);
318 } else if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP) {
319 installDownstreamRules(fwd);
320 } else {
321 log.error("Unknown OLT operation: {}", fwd);
322 fail(fwd, ObjectiveError.UNSUPPORTED);
323 return;
324 }
alshabib0ccde6d2015-05-30 18:22:36 -0700325 }
326
alshabibfd430b62015-12-16 18:56:38 -0800327 pass(fwd);
alshabib0ccde6d2015-05-30 18:22:36 -0700328
alshabib0ccde6d2015-05-30 18:22:36 -0700329 }
330
alshabibd61b77b2016-02-01 23:30:53 -0800331
alshabib0ccde6d2015-05-30 18:22:36 -0700332 @Override
333 public void next(NextObjective nextObjective) {
alshabibd61b77b2016-02-01 23:30:53 -0800334 if (nextObjective.type() != NextObjective.Type.BROADCAST) {
335 log.error("OLT only supports broadcast groups.");
336 fail(nextObjective, ObjectiveError.BADPARAMS);
Andrea Campanella5908b562020-05-06 16:09:10 +0200337 return;
alshabibd61b77b2016-02-01 23:30:53 -0800338 }
339
Andrea Campanella5908b562020-05-06 16:09:10 +0200340 if (nextObjective.next().size() != 1 && !nextObjective.op().equals(Objective.Operation.REMOVE)) {
alshabibd61b77b2016-02-01 23:30:53 -0800341 log.error("OLT only supports singleton broadcast groups.");
342 fail(nextObjective, ObjectiveError.BADPARAMS);
Andrea Campanella5908b562020-05-06 16:09:10 +0200343 return;
alshabibd61b77b2016-02-01 23:30:53 -0800344 }
345
Andrea Campanella5908b562020-05-06 16:09:10 +0200346 Optional<TrafficTreatment> treatmentOpt = nextObjective.next().stream().findFirst();
347 if (treatmentOpt.isEmpty() && !nextObjective.op().equals(Objective.Operation.REMOVE)) {
348 log.error("Next objective {} does not have a treatment", nextObjective);
349 fail(nextObjective, ObjectiveError.BADPARAMS);
350 return;
351 }
alshabibd61b77b2016-02-01 23:30:53 -0800352
alshabibd61b77b2016-02-01 23:30:53 -0800353 GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id()));
354
alshabibd61b77b2016-02-01 23:30:53 -0800355 pendingGroups.put(key, nextObjective);
Andrea Campanella5908b562020-05-06 16:09:10 +0200356 log.trace("NextObjective Operation {}", nextObjective.op());
alshabibd61b77b2016-02-01 23:30:53 -0800357 switch (nextObjective.op()) {
358 case ADD:
alshabib1aa58142016-02-17 15:37:56 -0800359 GroupDescription groupDesc =
360 new DefaultGroupDescription(deviceId,
361 GroupDescription.Type.ALL,
Andrea Campanella5908b562020-05-06 16:09:10 +0200362 new GroupBuckets(
363 Collections.singletonList(
364 buildBucket(treatmentOpt.get()))),
alshabib1aa58142016-02-17 15:37:56 -0800365 key,
366 null,
367 nextObjective.appId());
alshabibd61b77b2016-02-01 23:30:53 -0800368 groupService.addGroup(groupDesc);
369 break;
370 case REMOVE:
371 groupService.removeGroup(deviceId, key, nextObjective.appId());
372 break;
373 case ADD_TO_EXISTING:
alshabib1aa58142016-02-17 15:37:56 -0800374 groupService.addBucketsToGroup(deviceId, key,
Andrea Campanella5908b562020-05-06 16:09:10 +0200375 new GroupBuckets(
376 Collections.singletonList(
377 buildBucket(treatmentOpt.get()))),
alshabib1aa58142016-02-17 15:37:56 -0800378 key, nextObjective.appId());
379 break;
alshabibd61b77b2016-02-01 23:30:53 -0800380 case REMOVE_FROM_EXISTING:
alshabib1aa58142016-02-17 15:37:56 -0800381 groupService.removeBucketsFromGroup(deviceId, key,
Andrea Campanella5908b562020-05-06 16:09:10 +0200382 new GroupBuckets(
383 Collections.singletonList(
384 buildBucket(treatmentOpt.get()))),
alshabib56efe432016-02-25 17:57:24 -0500385 key, nextObjective.appId());
alshabibd61b77b2016-02-01 23:30:53 -0800386 break;
387 default:
388 log.warn("Unknown next objective operation: {}", nextObjective.op());
389 }
390
391
392 }
393
Andrea Campanella5908b562020-05-06 16:09:10 +0200394 private GroupBucket buildBucket(TrafficTreatment treatment) {
395 return DefaultGroupBucket.createAllGroupBucket(treatment);
396 }
397
alshabibd61b77b2016-02-01 23:30:53 -0800398 private void processMulticastRule(ForwardingObjective fwd) {
399 if (fwd.nextId() == null) {
400 log.error("Multicast objective does not have a next id");
401 fail(fwd, ObjectiveError.BADPARAMS);
402 }
403
alshabib1aa58142016-02-17 15:37:56 -0800404 GroupKey key = getGroupForNextObjective(fwd.nextId());
alshabibd61b77b2016-02-01 23:30:53 -0800405
alshabib1aa58142016-02-17 15:37:56 -0800406 if (key == null) {
alshabibd61b77b2016-02-01 23:30:53 -0800407 log.error("Group for forwarding objective missing: {}", fwd);
408 fail(fwd, ObjectiveError.GROUPMISSING);
409 }
410
alshabib1aa58142016-02-17 15:37:56 -0800411 Group group = groupService.getGroup(deviceId, key);
alshabibd61b77b2016-02-01 23:30:53 -0800412 TrafficTreatment treatment =
413 buildTreatment(Instructions.createGroup(group.id()));
414
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000415 TrafficSelector.Builder selectorBuilder = buildIpv4SelectorForMulticast(fwd);
416
alshabibd61b77b2016-02-01 23:30:53 -0800417 FlowRule rule = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700418 .fromApp(fwd.appId())
alshabibd61b77b2016-02-01 23:30:53 -0800419 .forDevice(deviceId)
420 .forTable(0)
alshabibd61b77b2016-02-01 23:30:53 -0800421 .makePermanent()
422 .withPriority(fwd.priority())
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000423 .withSelector(selectorBuilder.build())
alshabibd61b77b2016-02-01 23:30:53 -0800424 .withTreatment(treatment)
425 .build();
426
427 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
428 switch (fwd.op()) {
429
430 case ADD:
431 builder.add(rule);
432 break;
433 case REMOVE:
434 builder.remove(rule);
435 break;
436 case ADD_TO_EXISTING:
437 case REMOVE_FROM_EXISTING:
438 break;
439 default:
440 log.warn("Unknown forwarding operation: {}", fwd.op());
441 }
442
443 applyFlowRules(builder, fwd);
444
445 }
446
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000447 private TrafficSelector.Builder buildIpv4SelectorForMulticast(ForwardingObjective fwd) {
448 TrafficSelector.Builder builderToUpdate = DefaultTrafficSelector.builder();
449
450 Optional<Criterion> vlanIdCriterion = readFromSelector(fwd.meta(), Criterion.Type.VLAN_VID);
451 if (vlanIdCriterion.isPresent()) {
452 VlanId assignedVlan = ((VlanIdCriterion) vlanIdCriterion.get()).vlanId();
453 builderToUpdate.matchVlanId(assignedVlan);
454 }
455
Esin Karamanec25a0a2020-03-18 14:29:29 +0000456 Optional<Criterion> innerVlanIdCriterion = readFromSelector(fwd.meta(), Criterion.Type.INNER_VLAN_VID);
457 if (innerVlanIdCriterion.isPresent()) {
458 VlanId assignedInnerVlan = ((VlanIdCriterion) innerVlanIdCriterion.get()).vlanId();
459 builderToUpdate.matchMetadata(assignedInnerVlan.toShort());
460 }
461
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000462 Optional<Criterion> ethTypeCriterion = readFromSelector(fwd.selector(), Criterion.Type.ETH_TYPE);
463 if (ethTypeCriterion.isPresent()) {
464 EthType ethType = ((EthTypeCriterion) ethTypeCriterion.get()).ethType();
465 builderToUpdate.matchEthType(ethType.toShort());
466 }
467
468 Optional<Criterion> ipv4DstCriterion = readFromSelector(fwd.selector(), Criterion.Type.IPV4_DST);
469 if (ipv4DstCriterion.isPresent()) {
470 IpPrefix ipv4Dst = ((IPCriterion) ipv4DstCriterion.get()).ip();
471 builderToUpdate.matchIPDst(ipv4Dst);
472 }
473
474 return builderToUpdate;
475 }
476
477 static Optional<Criterion> readFromSelector(TrafficSelector selector, Criterion.Type type) {
478 if (selector == null) {
479 return Optional.empty();
480 }
481 Criterion criterion = selector.getCriterion(type);
482 return (criterion == null)
483 ? Optional.empty() : Optional.of(criterion);
484 }
485
alshabibd61b77b2016-02-01 23:30:53 -0800486 private boolean checkForMulticast(ForwardingObjective fwd) {
487
alshabib1aa58142016-02-17 15:37:56 -0800488 IPCriterion ip = (IPCriterion) filterForCriterion(fwd.selector().criteria(),
alshabib56efe432016-02-25 17:57:24 -0500489 Criterion.Type.IPV4_DST);
alshabibd61b77b2016-02-01 23:30:53 -0800490
alshabib1aa58142016-02-17 15:37:56 -0800491 if (ip == null) {
492 return false;
493 }
494
Charles Chanaedabfd2016-02-26 09:31:48 -0800495 return ip.ip().isMulticast();
alshabibd61b77b2016-02-01 23:30:53 -0800496
497 }
498
alshabib1aa58142016-02-17 15:37:56 -0800499 private GroupKey getGroupForNextObjective(Integer nextId) {
alshabibd61b77b2016-02-01 23:30:53 -0800500 NextGroup next = flowObjectiveStore.getNextGroup(nextId);
alshabib1aa58142016-02-17 15:37:56 -0800501 return appKryo.deserialize(next.data());
alshabibd61b77b2016-02-01 23:30:53 -0800502
alshabib0ccde6d2015-05-30 18:22:36 -0700503 }
504
Amit Ghoshf1f22752018-08-14 07:28:01 +0100505 private void installNoModificationRules(ForwardingObjective fwd) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000506 Instructions.OutputInstruction output = (Instructions.OutputInstruction) fetchOutput(fwd, DOWNSTREAM);
Gamze Abakaa34469f2019-04-19 08:30:16 +0000507 Instructions.MetadataInstruction writeMetadata = fetchWriteMetadata(fwd);
508 Instructions.MeterInstruction meter = (Instructions.MeterInstruction) fetchMeter(fwd);
Amit Ghoshf1f22752018-08-14 07:28:01 +0100509
510 TrafficSelector selector = fwd.selector();
511
512 Criterion inport = selector.getCriterion(Criterion.Type.IN_PORT);
513 Criterion outerVlan = selector.getCriterion(Criterion.Type.VLAN_VID);
514 Criterion innerVlan = selector.getCriterion(Criterion.Type.INNER_VLAN_VID);
Amit Ghoshf1f22752018-08-14 07:28:01 +0100515
516 if (inport == null || output == null || innerVlan == null || outerVlan == null) {
Andrea Campanella969e8af2020-07-09 11:39:08 +0200517 // Avoid logging a non-error from lldp, bbdp and eapol core flows.
518 if (!fwd.appId().name().equals(CORE_APP_NAME)) {
519 log.error("Forwarding objective is underspecified: {}", fwd);
520 } else {
521 log.debug("Not installing unsupported core generated flow {}", fwd);
522 }
Amit Ghoshf1f22752018-08-14 07:28:01 +0100523 fail(fwd, ObjectiveError.BADPARAMS);
524 return;
525 }
526
Amit Ghoshf1f22752018-08-14 07:28:01 +0100527
528 FlowRule.Builder outer = DefaultFlowRule.builder()
529 .fromApp(fwd.appId())
530 .forDevice(deviceId)
531 .makePermanent()
532 .withPriority(fwd.priority())
Gamze Abakaa34469f2019-04-19 08:30:16 +0000533 .withSelector(buildSelector(inport, outerVlan))
534 .withTreatment(buildTreatment(output, writeMetadata, meter));
Amit Ghoshf1f22752018-08-14 07:28:01 +0100535
536 applyRules(fwd, outer);
537 }
538
alshabibfd430b62015-12-16 18:56:38 -0800539 private void installDownstreamRules(ForwardingObjective fwd) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000540 Instructions.OutputInstruction output = (Instructions.OutputInstruction) fetchOutput(fwd, DOWNSTREAM);
alshabibfd430b62015-12-16 18:56:38 -0800541
542 if (output == null) {
543 return;
544 }
545
alshabibfa0dc662016-01-13 11:23:53 -0800546 TrafficSelector selector = fwd.selector();
547
548 Criterion outerVlan = selector.getCriterion(Criterion.Type.VLAN_VID);
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000549 Criterion outerPbit = selector.getCriterion(Criterion.Type.VLAN_PCP);
Gamze Abakadadae722018-09-12 10:55:35 +0000550 Criterion innerVlanCriterion = selector.getCriterion(Criterion.Type.INNER_VLAN_VID);
alshabibfa0dc662016-01-13 11:23:53 -0800551 Criterion inport = selector.getCriterion(Criterion.Type.IN_PORT);
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000552 Criterion dstMac = selector.getCriterion(Criterion.Type.ETH_DST);
cboling651c6872018-10-05 11:09:22 -0500553
Gamze Abakadadae722018-09-12 10:55:35 +0000554 if (outerVlan == null || innerVlanCriterion == null || inport == null) {
Andrea Campanella969e8af2020-07-09 11:39:08 +0200555 // Avoid logging a non-error from lldp, bbdp and eapol core flows.
556 if (!fwd.appId().name().equals(CORE_APP_NAME)) {
557 log.error("Forwarding objective is underspecified: {}", fwd);
558 } else {
559 log.debug("Not installing unsupported core generated flow {}", fwd);
560 }
alshabibfa0dc662016-01-13 11:23:53 -0800561 fail(fwd, ObjectiveError.BADPARAMS);
562 return;
563 }
564
Gamze Abakadadae722018-09-12 10:55:35 +0000565 VlanId innerVlan = ((VlanIdCriterion) innerVlanCriterion).vlanId();
566 Criterion innerVid = Criteria.matchVlanId(innerVlan);
alshabib2f74f2c2016-01-14 13:29:35 -0800567
Amit Ghosha6859982020-02-12 09:35:45 +0000568 // In the case where the C-tag is the same for all the subscribers,
569 // we add a metadata with the outport in the selector to make the flow unique
570 Criterion innerSelectorMeta = Criteria.matchMetadata(output.port().toLong());
571
Gamze Abakadadae722018-09-12 10:55:35 +0000572 if (innerVlan.toShort() == VlanId.ANY_VALUE) {
Andrea Campanella6edac322020-01-29 14:41:42 +0100573 TrafficSelector outerSelector = buildSelector(inport, outerVlan, outerPbit, dstMac);
Gamze Abakadadae722018-09-12 10:55:35 +0000574 installDownstreamRulesForAnyVlan(fwd, output, outerSelector, buildSelector(inport,
Amit Ghosha6859982020-02-12 09:35:45 +0000575 Criteria.matchVlanId(VlanId.ANY), innerSelectorMeta));
Gamze Abakadadae722018-09-12 10:55:35 +0000576 } else {
Andrea Campanella6edac322020-01-29 14:41:42 +0100577 // Required to differentiate the same match flows
578 // Please note that S tag and S p bit values will be same for the same service - so conflict flows!
579 // Metadata match criteria solves the conflict issue - but not used by the voltha
580 // Maybe - find a better way to solve the above problem
581 Criterion metadata = Criteria.matchMetadata(innerVlan.toShort());
582 TrafficSelector outerSelector = buildSelector(inport, metadata, outerVlan, outerPbit, dstMac);
Amit Ghosha6859982020-02-12 09:35:45 +0000583 installDownstreamRulesForVlans(fwd, output, outerSelector, buildSelector(inport, innerVid,
584 innerSelectorMeta));
Gamze Abakadadae722018-09-12 10:55:35 +0000585 }
586 }
587
588 private void installDownstreamRulesForVlans(ForwardingObjective fwd, Instruction output,
589 TrafficSelector outerSelector, TrafficSelector innerSelector) {
590
591 List<Pair<Instruction, Instruction>> vlanOps =
592 vlanOps(fwd,
593 L2ModificationInstruction.L2SubType.VLAN_POP);
594
595 if (vlanOps == null || vlanOps.isEmpty()) {
596 return;
597 }
598
599 Pair<Instruction, Instruction> popAndRewrite = vlanOps.remove(0);
600
601 TrafficTreatment innerTreatment;
602 VlanId setVlanId = ((L2ModificationInstruction.ModVlanIdInstruction) popAndRewrite.getRight()).vlanId();
603 if (VlanId.NONE.equals(setVlanId)) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000604 innerTreatment = (buildTreatment(popAndRewrite.getLeft(), fetchMeter(fwd),
605 writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000606 } else {
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000607 innerTreatment = (buildTreatment(popAndRewrite.getRight(),
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000608 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000609 }
610
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000611 List<Instruction> setVlanPcps = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_PCP,
612 fwd.treatment().allInstructions());
613
614 Instruction innerPbitSet = null;
615
616 if (setVlanPcps != null && !setVlanPcps.isEmpty()) {
617 innerPbitSet = setVlanPcps.get(0);
618 }
619
620 VlanId remarkInnerVlan = null;
621 Optional<Criterion> vlanIdCriterion = readFromSelector(innerSelector, Criterion.Type.VLAN_VID);
622 if (vlanIdCriterion.isPresent()) {
623 remarkInnerVlan = ((VlanIdCriterion) vlanIdCriterion.get()).vlanId();
624 }
625
626 Instruction modVlanId = null;
627 if (innerPbitSet != null) {
628 modVlanId = Instructions.modVlanId(remarkInnerVlan);
629 }
630
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000631 //match: in port (nni), s-tag
632 //action: pop vlan (s-tag), write metadata, go to table 1, meter
alshabibfa0dc662016-01-13 11:23:53 -0800633 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700634 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800635 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800636 .makePermanent()
637 .withPriority(fwd.priority())
Gamze Abakadadae722018-09-12 10:55:35 +0000638 .withSelector(outerSelector)
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000639 .withTreatment(buildTreatment(popAndRewrite.getLeft(), modVlanId,
640 innerPbitSet, fetchMeter(fwd), fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE)));
alshabibfd430b62015-12-16 18:56:38 -0800641
Gamze Abakadadae722018-09-12 10:55:35 +0000642 //match: in port (nni), c-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000643 //action: immediate: write metadata and pop, meter, output
alshabibfa0dc662016-01-13 11:23:53 -0800644 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700645 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800646 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800647 .forTable(QQ_TABLE)
648 .makePermanent()
649 .withPriority(fwd.priority())
Gamze Abakadadae722018-09-12 10:55:35 +0000650 .withSelector(innerSelector)
651 .withTreatment(innerTreatment);
652 applyRules(fwd, inner, outer);
653 }
654
655 private void installDownstreamRulesForAnyVlan(ForwardingObjective fwd, Instruction output,
656 TrafficSelector outerSelector, TrafficSelector innerSelector) {
657
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000658 //match: in port (nni), s-tag
659 //action: immediate: write metadata, pop vlan, meter and go to table 1
Gamze Abakadadae722018-09-12 10:55:35 +0000660 FlowRule.Builder outer = DefaultFlowRule.builder()
661 .fromApp(fwd.appId())
662 .forDevice(deviceId)
663 .makePermanent()
664 .withPriority(fwd.priority())
665 .withSelector(outerSelector)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000666 .withTreatment(buildTreatment(Instructions.popVlan(), fetchMeter(fwd),
667 fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE)));
Gamze Abakadadae722018-09-12 10:55:35 +0000668
669 //match: in port (nni) and s-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000670 //action: immediate : write metadata, meter and output
Gamze Abakadadae722018-09-12 10:55:35 +0000671 FlowRule.Builder inner = DefaultFlowRule.builder()
672 .fromApp(fwd.appId())
673 .forDevice(deviceId)
674 .forTable(QQ_TABLE)
675 .makePermanent()
676 .withPriority(fwd.priority())
677 .withSelector(innerSelector)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000678 .withTreatment(buildTreatment(fetchMeter(fwd),
679 writeMetadataIncludingOnlyTp(fwd), output));
alshabibfd430b62015-12-16 18:56:38 -0800680
681 applyRules(fwd, inner, outer);
alshabibfd430b62015-12-16 18:56:38 -0800682 }
683
684 private void installUpstreamRules(ForwardingObjective fwd) {
685 List<Pair<Instruction, Instruction>> vlanOps =
686 vlanOps(fwd,
687 L2ModificationInstruction.L2SubType.VLAN_PUSH);
688
Gamze Abakadadae722018-09-12 10:55:35 +0000689 if (vlanOps == null || vlanOps.isEmpty()) {
alshabibfd430b62015-12-16 18:56:38 -0800690 return;
691 }
692
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000693 Instruction output = fetchOutput(fwd, UPSTREAM);
alshabibfd430b62015-12-16 18:56:38 -0800694
695 if (output == null) {
696 return;
697 }
698
alshabibfd430b62015-12-16 18:56:38 -0800699 Pair<Instruction, Instruction> outerPair = vlanOps.remove(0);
700
Gamze Abakadadae722018-09-12 10:55:35 +0000701 boolean noneValueVlanStatus = checkNoneVlanCriteria(fwd);
702 boolean anyValueVlanStatus = checkAnyVlanMatchCriteria(fwd);
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700703
Gamze Abakadadae722018-09-12 10:55:35 +0000704 if (anyValueVlanStatus) {
705 installUpstreamRulesForAnyVlan(fwd, output, outerPair);
706 } else {
Andrea Campanella6edac322020-01-29 14:41:42 +0100707 Pair<Instruction, Instruction> innerPair = outerPair;
708 outerPair = vlanOps.remove(0);
Gamze Abakadadae722018-09-12 10:55:35 +0000709 installUpstreamRulesForVlans(fwd, output, innerPair, outerPair, noneValueVlanStatus);
710 }
711 }
712
713 private void installUpstreamRulesForVlans(ForwardingObjective fwd, Instruction output,
714 Pair<Instruction, Instruction> innerPair,
715 Pair<Instruction, Instruction> outerPair, Boolean noneValueVlanStatus) {
716
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000717 List<Instruction> setVlanPcps = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_PCP,
718 fwd.treatment().allInstructions());
719
720 Instruction innerPbitSet = null;
721 Instruction outerPbitSet = null;
722
723 if (setVlanPcps != null && !setVlanPcps.isEmpty()) {
724 innerPbitSet = setVlanPcps.get(0);
725 outerPbitSet = setVlanPcps.get(1);
726 }
727
Gamze Abakadadae722018-09-12 10:55:35 +0000728 TrafficTreatment innerTreatment;
729 if (noneValueVlanStatus) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000730 innerTreatment = buildTreatment(innerPair.getLeft(), innerPair.getRight(), fetchMeter(fwd),
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000731 fetchWriteMetadata(fwd), innerPbitSet,
732 Instructions.transition(QQ_TABLE));
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700733 } else {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000734 innerTreatment = buildTreatment(innerPair.getRight(), fetchMeter(fwd), fetchWriteMetadata(fwd),
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000735 innerPbitSet, Instructions.transition(QQ_TABLE));
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700736 }
737
Gamze Abakadadae722018-09-12 10:55:35 +0000738 //match: in port, vlanId (0 or None)
739 //action:
740 //if vlanId None, push & set c-tag go to table 1
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000741 //if vlanId 0 or any specific vlan, set c-tag, write metadata, meter and go to table 1
alshabibfd430b62015-12-16 18:56:38 -0800742 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700743 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800744 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800745 .makePermanent()
746 .withPriority(fwd.priority())
747 .withSelector(fwd.selector())
Gamze Abakadadae722018-09-12 10:55:35 +0000748 .withTreatment(innerTreatment);
alshabibfd430b62015-12-16 18:56:38 -0800749
750 PortCriterion inPort = (PortCriterion)
751 fwd.selector().getCriterion(Criterion.Type.IN_PORT);
752
753 VlanId cVlanId = ((L2ModificationInstruction.ModVlanIdInstruction)
754 innerPair.getRight()).vlanId();
755
Gamze Abakadadae722018-09-12 10:55:35 +0000756 //match: in port, c-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000757 //action: immediate: push s-tag, write metadata, meter and output
alshabibfd430b62015-12-16 18:56:38 -0800758 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700759 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800760 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800761 .forTable(QQ_TABLE)
762 .makePermanent()
763 .withPriority(fwd.priority())
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000764 .withTreatment(buildTreatment(outerPair.getLeft(), outerPair.getRight(),
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000765 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd),
766 outerPbitSet, output));
767
768 if (innerPbitSet != null) {
769 byte innerPbit = ((L2ModificationInstruction.ModVlanPcpInstruction)
770 innerPbitSet).vlanPcp();
771 outer.withSelector(buildSelector(inPort, Criteria.matchVlanId(cVlanId), Criteria.matchVlanPcp(innerPbit)));
772 } else {
773 outer.withSelector(buildSelector(inPort, Criteria.matchVlanId(cVlanId)));
774 }
alshabibfd430b62015-12-16 18:56:38 -0800775
776 applyRules(fwd, inner, outer);
Gamze Abakadadae722018-09-12 10:55:35 +0000777 }
alshabibfd430b62015-12-16 18:56:38 -0800778
Gamze Abakadadae722018-09-12 10:55:35 +0000779 private void installUpstreamRulesForAnyVlan(ForwardingObjective fwd, Instruction output,
780 Pair<Instruction, Instruction> outerPair) {
781
782 log.debug("Installing upstream rules for any value vlan");
783
784 //match: in port and any-vlan (coming from OLT app.)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000785 //action: write metadata, go to table 1 and meter
Gamze Abakadadae722018-09-12 10:55:35 +0000786 FlowRule.Builder inner = DefaultFlowRule.builder()
787 .fromApp(fwd.appId())
788 .forDevice(deviceId)
789 .makePermanent()
790 .withPriority(fwd.priority())
791 .withSelector(fwd.selector())
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000792 .withTreatment(buildTreatment(Instructions.transition(QQ_TABLE), fetchMeter(fwd),
793 fetchWriteMetadata(fwd)));
Gamze Abakadadae722018-09-12 10:55:35 +0000794
Gamze Abakadadae722018-09-12 10:55:35 +0000795 //match: in port and any-vlan (coming from OLT app.)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000796 //action: immediate: push:QinQ, vlanId (s-tag), write metadata, meter and output
Gamze Abakadadae722018-09-12 10:55:35 +0000797 FlowRule.Builder outer = DefaultFlowRule.builder()
798 .fromApp(fwd.appId())
799 .forDevice(deviceId)
800 .forTable(QQ_TABLE)
801 .makePermanent()
802 .withPriority(fwd.priority())
803 .withSelector(fwd.selector())
Andrea Campanella6edac322020-01-29 14:41:42 +0100804 .withTreatment(buildTreatment(outerPair.getLeft(), outerPair.getRight(),
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000805 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000806
Andrea Campanella6edac322020-01-29 14:41:42 +0100807 applyRules(fwd, inner, outer);
Gamze Abakadadae722018-09-12 10:55:35 +0000808 }
809
810 private boolean checkNoneVlanCriteria(ForwardingObjective fwd) {
811 // Add the VLAN_PUSH treatment if we're matching on VlanId.NONE
812 Criterion vlanMatchCriterion = filterForCriterion(fwd.selector().criteria(), Criterion.Type.VLAN_VID);
813 boolean noneValueVlanStatus = false;
814 if (vlanMatchCriterion != null) {
815 noneValueVlanStatus = ((VlanIdCriterion) vlanMatchCriterion).vlanId().equals(VlanId.NONE);
816 }
817 return noneValueVlanStatus;
818 }
819
820 private boolean checkAnyVlanMatchCriteria(ForwardingObjective fwd) {
821 Criterion anyValueVlanCriterion = fwd.selector().criteria().stream()
822 .filter(c -> c.type().equals(Criterion.Type.VLAN_VID))
823 .filter(vc -> ((VlanIdCriterion) vc).vlanId().toShort() == VlanId.ANY_VALUE)
824 .findAny().orElse(null);
825
826 if (anyValueVlanCriterion == null) {
Andrea Campanella6edac322020-01-29 14:41:42 +0100827 log.debug("Any value vlan match criteria is not found, criteria {}",
828 fwd.selector().criteria());
Gamze Abakadadae722018-09-12 10:55:35 +0000829 return false;
830 }
831
832 return true;
alshabibfd430b62015-12-16 18:56:38 -0800833 }
834
835 private Instruction fetchOutput(ForwardingObjective fwd, String direction) {
836 Instruction output = fwd.treatment().allInstructions().stream()
837 .filter(i -> i.type() == Instruction.Type.OUTPUT)
838 .findFirst().orElse(null);
839
840 if (output == null) {
841 log.error("OLT {} rule has no output", direction);
842 fail(fwd, ObjectiveError.BADPARAMS);
843 return null;
844 }
845 return output;
846 }
847
Gamze Abakadadae722018-09-12 10:55:35 +0000848 private Instruction fetchMeter(ForwardingObjective fwd) {
849 Instruction meter = fwd.treatment().metered();
850
851 if (meter == null) {
852 log.debug("Meter instruction is not found for the forwarding objective {}", fwd);
853 return null;
854 }
855
856 log.debug("Meter instruction is found.");
857 return meter;
858 }
859
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000860 private Instructions.MetadataInstruction fetchWriteMetadata(ForwardingObjective fwd) {
861 Instructions.MetadataInstruction writeMetadata = fwd.treatment().writeMetadata();
Gamze Abakadadae722018-09-12 10:55:35 +0000862
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000863 if (writeMetadata == null) {
864 log.warn("Write metadata is not found for the forwarding obj");
865 fail(fwd, ObjectiveError.BADPARAMS);
Gamze Abakadadae722018-09-12 10:55:35 +0000866 return null;
867 }
868
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000869 log.debug("Write metadata is found {}", writeMetadata);
870 return writeMetadata;
Gamze Abakadadae722018-09-12 10:55:35 +0000871 }
872
alshabibfd430b62015-12-16 18:56:38 -0800873 private List<Pair<Instruction, Instruction>> vlanOps(ForwardingObjective fwd,
874 L2ModificationInstruction.L2SubType type) {
875
876 List<Pair<Instruction, Instruction>> vlanOps = findVlanOps(
877 fwd.treatment().allInstructions(), type);
878
Gamze Abakadadae722018-09-12 10:55:35 +0000879 if (vlanOps == null || vlanOps.isEmpty()) {
alshabibfd430b62015-12-16 18:56:38 -0800880 String direction = type == L2ModificationInstruction.L2SubType.VLAN_POP
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000881 ? DOWNSTREAM : UPSTREAM;
alshabibfd430b62015-12-16 18:56:38 -0800882 log.error("Missing vlan operations in {} forwarding: {}", direction, fwd);
883 fail(fwd, ObjectiveError.BADPARAMS);
Gamze Abakadadae722018-09-12 10:55:35 +0000884 return ImmutableList.of();
alshabibfd430b62015-12-16 18:56:38 -0800885 }
886 return vlanOps;
887 }
888
889
890 private List<Pair<Instruction, Instruction>> findVlanOps(List<Instruction> instructions,
alshabibd61b77b2016-02-01 23:30:53 -0800891 L2ModificationInstruction.L2SubType type) {
alshabibfd430b62015-12-16 18:56:38 -0800892
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000893 List<Instruction> vlanOperations = findL2Instructions(
alshabibfd430b62015-12-16 18:56:38 -0800894 type,
895 instructions);
896 List<Instruction> vlanSets = findL2Instructions(
897 L2ModificationInstruction.L2SubType.VLAN_ID,
898 instructions);
899
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000900 if (vlanOperations.size() != vlanSets.size()) {
Gamze Abakadadae722018-09-12 10:55:35 +0000901 return ImmutableList.of();
alshabibfd430b62015-12-16 18:56:38 -0800902 }
903
904 List<Pair<Instruction, Instruction>> pairs = Lists.newArrayList();
905
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000906 for (int i = 0; i < vlanOperations.size(); i++) {
907 pairs.add(new ImmutablePair<>(vlanOperations.get(i), vlanSets.get(i)));
alshabibfd430b62015-12-16 18:56:38 -0800908 }
909 return pairs;
910 }
911
912 private List<Instruction> findL2Instructions(L2ModificationInstruction.L2SubType subType,
913 List<Instruction> actions) {
914 return actions.stream()
915 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
916 .filter(i -> ((L2ModificationInstruction) i).subtype() == subType)
917 .collect(Collectors.toList());
918 }
919
Amit Ghoshf1f22752018-08-14 07:28:01 +0100920 private void provisionEthTypeBasedFilter(FilteringObjective filter,
921 EthTypeCriterion ethType,
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200922 Instructions.OutputInstruction output,
923 L2ModificationInstruction vlanId,
924 L2ModificationInstruction vlanPush) {
alshabibfd430b62015-12-16 18:56:38 -0800925
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000926 Instruction meter = filter.meta().metered();
927 Instruction writeMetadata = filter.meta().writeMetadata();
928
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200929 TrafficSelector selector = buildSelector(filter.key(), ethType);
930 TrafficTreatment treatment;
Gamze Abakaf57ef602019-03-11 06:52:48 +0000931
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200932 if (vlanPush == null || vlanId == null) {
933 treatment = buildTreatment(output, meter, writeMetadata);
934 } else {
935 // we need to push the vlan because it came untagged (ATT)
936 treatment = buildTreatment(output, meter, vlanPush, vlanId, writeMetadata);
937 }
938
alshabibfd430b62015-12-16 18:56:38 -0800939 buildAndApplyRule(filter, selector, treatment);
940
941 }
942
Jonathan Hart51539b82015-10-29 09:53:04 -0700943 private void provisionIgmp(FilteringObjective filter, EthTypeCriterion ethType,
alshabibfd430b62015-12-16 18:56:38 -0800944 IPProtocolCriterion ipProto,
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200945 Instructions.OutputInstruction output,
Andrea Campanella79bc5062020-09-21 14:34:00 +0200946 Instruction vlan, Instruction pcp) {
Gamze Abaka7c070c82019-02-21 14:40:18 +0000947
948 Instruction meter = filter.meta().metered();
949 Instruction writeMetadata = filter.meta().writeMetadata();
950
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200951 // uniTagMatch
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000952 VlanIdCriterion vlanId = (VlanIdCriterion) filterForCriterion(filter.conditions(),
953 Criterion.Type.VLAN_VID);
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000954
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200955 TrafficSelector selector = buildSelector(filter.key(), ethType, ipProto, vlanId);
956 TrafficTreatment treatment = buildTreatment(output, vlan, pcp, meter, writeMetadata);
alshabibfd430b62015-12-16 18:56:38 -0800957 buildAndApplyRule(filter, selector, treatment);
958 }
959
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000960 private void provisionDhcp(FilteringObjective filter, EthTypeCriterion ethType,
961 IPProtocolCriterion ipProto,
962 UdpPortCriterion udpSrcPort,
963 UdpPortCriterion udpDstPort,
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200964 Instruction vlanIdInstruction,
965 Instruction vlanPcpInstruction,
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000966 Instructions.OutputInstruction output) {
Gamze Abaka7c070c82019-02-21 14:40:18 +0000967
968 Instruction meter = filter.meta().metered();
969 Instruction writeMetadata = filter.meta().writeMetadata();
970
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200971 VlanIdCriterion matchVlanId = (VlanIdCriterion)
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000972 filterForCriterion(filter.conditions(), Criterion.Type.VLAN_VID);
973
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200974 TrafficSelector selector;
975 TrafficTreatment treatment;
976
977 if (matchVlanId != null) {
978 log.debug("Building selector with match VLAN, {}", matchVlanId);
979 // in case of TT upstream the packet comes tagged and the vlan is swapped.
980 selector = buildSelector(filter.key(), ethType, ipProto, udpSrcPort,
981 udpDstPort, matchVlanId);
982 treatment = buildTreatment(output, meter, writeMetadata,
983 vlanIdInstruction, vlanPcpInstruction);
984 } else {
985 log.debug("Building selector with no VLAN");
986 // in case of ATT upstream the packet comes in untagged and we need to push the vlan
987 selector = buildSelector(filter.key(), ethType, ipProto, udpSrcPort, udpDstPort);
988 treatment = buildTreatment(output, meter, vlanIdInstruction, writeMetadata);
989 }
990 //In case of downstream there will be no match on the VLAN, which is null,
991 // so it will just be output, meter, writeMetadata
992
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000993 buildAndApplyRule(filter, selector, treatment);
994 }
Gamze Abakadadae722018-09-12 10:55:35 +0000995
alshabibfd430b62015-12-16 18:56:38 -0800996 private void buildAndApplyRule(FilteringObjective filter, TrafficSelector selector,
997 TrafficTreatment treatment) {
998 FlowRule rule = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700999 .fromApp(filter.appId())
alshabibfd430b62015-12-16 18:56:38 -08001000 .forDevice(deviceId)
1001 .forTable(0)
alshabibfd430b62015-12-16 18:56:38 -08001002 .makePermanent()
1003 .withSelector(selector)
1004 .withTreatment(treatment)
alshabibbb424232016-01-15 12:20:25 -08001005 .withPriority(filter.priority())
alshabibfd430b62015-12-16 18:56:38 -08001006 .build();
1007
1008 FlowRuleOperations.Builder opsBuilder = FlowRuleOperations.builder();
1009
1010 switch (filter.type()) {
1011 case PERMIT:
1012 opsBuilder.add(rule);
1013 break;
1014 case DENY:
1015 opsBuilder.remove(rule);
1016 break;
1017 default:
1018 log.warn("Unknown filter type : {}", filter.type());
1019 fail(filter, ObjectiveError.UNSUPPORTED);
1020 }
1021
1022 applyFlowRules(opsBuilder, filter);
1023 }
1024
Gamze Abakadadae722018-09-12 10:55:35 +00001025 private void applyRules(ForwardingObjective fwd, FlowRule.Builder... fwdBuilders) {
Amit Ghoshf1f22752018-08-14 07:28:01 +01001026 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
1027 switch (fwd.op()) {
1028 case ADD:
Gamze Abakadadae722018-09-12 10:55:35 +00001029 for (FlowRule.Builder fwdBuilder : fwdBuilders) {
1030 builder.add(fwdBuilder.build());
1031 }
Amit Ghoshf1f22752018-08-14 07:28:01 +01001032 break;
1033 case REMOVE:
Gamze Abakadadae722018-09-12 10:55:35 +00001034 for (FlowRule.Builder fwdBuilder : fwdBuilders) {
1035 builder.remove(fwdBuilder.build());
1036 }
alshabibfd430b62015-12-16 18:56:38 -08001037 break;
1038 case ADD_TO_EXISTING:
1039 break;
1040 case REMOVE_FROM_EXISTING:
1041 break;
1042 default:
1043 log.warn("Unknown forwarding operation: {}", fwd.op());
1044 }
1045
1046 applyFlowRules(builder, fwd);
1047 }
1048
1049 private void applyFlowRules(FlowRuleOperations.Builder builder,
1050 Objective objective) {
1051 flowRuleService.apply(builder.build(new FlowRuleOperationsContext() {
1052 @Override
1053 public void onSuccess(FlowRuleOperations ops) {
1054 pass(objective);
1055 }
1056
1057 @Override
1058 public void onError(FlowRuleOperations ops) {
1059 fail(objective, ObjectiveError.FLOWINSTALLATIONFAILED);
1060 }
1061 }));
1062 }
1063
1064 private Criterion filterForCriterion(Collection<Criterion> criteria, Criterion.Type type) {
1065 return criteria.stream()
alshabibbb424232016-01-15 12:20:25 -08001066 .filter(c -> c.type().equals(type))
alshabibfd430b62015-12-16 18:56:38 -08001067 .limit(1)
1068 .findFirst().orElse(null);
1069 }
1070
1071 private TrafficSelector buildSelector(Criterion... criteria) {
1072
alshabibfd430b62015-12-16 18:56:38 -08001073 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
1074
Gamze Abakaf57ef602019-03-11 06:52:48 +00001075 Arrays.stream(criteria).filter(Objects::nonNull).forEach(sBuilder::add);
alshabibfd430b62015-12-16 18:56:38 -08001076
1077 return sBuilder.build();
1078 }
1079
1080 private TrafficTreatment buildTreatment(Instruction... instructions) {
1081
alshabibfd430b62015-12-16 18:56:38 -08001082 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1083
Gamze Abaka6c8a71b2018-12-24 13:17:12 +00001084 Arrays.stream(instructions).filter(Objects::nonNull).forEach(tBuilder::add);
alshabibfd430b62015-12-16 18:56:38 -08001085
1086 return tBuilder.build();
1087 }
1088
Gamze Abaka6c8a71b2018-12-24 13:17:12 +00001089 private Instruction writeMetadataIncludingOnlyTp(ForwardingObjective fwd) {
1090
1091 return Instructions.writeMetadata(
1092 fetchWriteMetadata(fwd).metadata() & 0xFFFF00000000L, 0L);
1093 }
alshabibfd430b62015-12-16 18:56:38 -08001094
1095 private void fail(Objective obj, ObjectiveError error) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -08001096 obj.context().ifPresent(context -> context.onError(obj, error));
alshabibfd430b62015-12-16 18:56:38 -08001097 }
1098
1099 private void pass(Objective obj) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -08001100 obj.context().ifPresent(context -> context.onSuccess(obj));
alshabibfd430b62015-12-16 18:56:38 -08001101 }
1102
alshabib2cc73cb2015-06-30 20:26:56 -07001103
alshabibd61b77b2016-02-01 23:30:53 -08001104 private class InnerGroupListener implements GroupListener {
alshabib2cc73cb2015-06-30 20:26:56 -07001105 @Override
alshabibd61b77b2016-02-01 23:30:53 -08001106 public void event(GroupEvent event) {
Andrea Campanella5908b562020-05-06 16:09:10 +02001107 GroupKey key = event.subject().appCookie();
1108 NextObjective obj = pendingGroups.getIfPresent(key);
1109 if (obj == null) {
1110 log.debug("No pending group for {}, moving on", key);
1111 return;
1112 }
1113 log.trace("Event {} for group {}, handling pending" +
1114 "NextGroup {}", event.type(), key, obj.id());
ke hanf5086672016-08-12 11:09:17 +08001115 if (event.type() == GroupEvent.Type.GROUP_ADDED ||
Gamze Abakadadae722018-09-12 10:55:35 +00001116 event.type() == GroupEvent.Type.GROUP_UPDATED) {
alshabibd61b77b2016-02-01 23:30:53 -08001117 flowObjectiveStore.putNextGroup(obj.id(), new OLTPipelineGroup(key));
1118 pass(obj);
1119 pendingGroups.invalidate(key);
Andrea Campanella5908b562020-05-06 16:09:10 +02001120 } else if (event.type() == GroupEvent.Type.GROUP_REMOVED) {
1121 flowObjectiveStore.removeNextGroup(obj.id());
1122 pass(obj);
1123 pendingGroups.invalidate(key);
alshabibd61b77b2016-02-01 23:30:53 -08001124 }
alshabib2cc73cb2015-06-30 20:26:56 -07001125 }
1126 }
1127
alshabibd61b77b2016-02-01 23:30:53 -08001128 private static class OLTPipelineGroup implements NextGroup {
1129
1130 private final GroupKey key;
1131
1132 public OLTPipelineGroup(GroupKey key) {
1133 this.key = key;
1134 }
1135
1136 public GroupKey key() {
1137 return key;
1138 }
1139
1140 @Override
1141 public byte[] data() {
1142 return appKryo.serialize(key);
1143 }
1144
1145 }
Saurav Das24431192016-03-07 19:13:00 -08001146
1147 @Override
1148 public List<String> getNextMappings(NextGroup nextGroup) {
1149 // TODO Implementation deferred to vendor
1150 return null;
1151 }
alshabib0ccde6d2015-05-30 18:22:36 -07001152}