blob: 38b7eda7fb8219bad12e73eea0453699414d2754 [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 Abaka61269f82019-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 Abaka61269f82019-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 Abaka61269f82019-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 Campanellaae6284c2020-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 Campanellabefc2942020-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 Campanellabefc2942020-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 Campanellabefc2942020-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 Campanellabefc2942020-06-11 16:09:39 +0200230 provisionIgmp(filter, ethType, ipProto, output,
Andrea Campanella0956dba2020-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 Campanellabefc2942020-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 Campanellabefc2942020-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 Campanellabee52b92020-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 Campanella63b17dc2020-05-06 16:09:10 +0200337 return;
alshabibd61b77b2016-02-01 23:30:53 -0800338 }
339
Andrea Campanella63b17dc2020-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 Campanella63b17dc2020-05-06 16:09:10 +0200343 return;
alshabibd61b77b2016-02-01 23:30:53 -0800344 }
345
Andrea Campanella63b17dc2020-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 Campanella63b17dc2020-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 Campanella63b17dc2020-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 Campanella63b17dc2020-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 Campanella63b17dc2020-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 Campanella63b17dc2020-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 Abaka61269f82019-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 Abaka61269f82019-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 Abaka61269f82019-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 Karaman27861222020-03-17 17:09:36 +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 Abaka61269f82019-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 Campanellaae6284c2020-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 Abaka61269f82019-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 Abaka61269f82019-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 Campanellaae6284c2020-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
Gamze Abakadadae722018-09-12 10:55:35 +0000568 if (innerVlan.toShort() == VlanId.ANY_VALUE) {
Andrea Campanellabee52b92020-01-29 14:41:42 +0100569 TrafficSelector outerSelector = buildSelector(inport, outerVlan, outerPbit, dstMac);
Gamze Abakadadae722018-09-12 10:55:35 +0000570 installDownstreamRulesForAnyVlan(fwd, output, outerSelector, buildSelector(inport,
571 Criteria.matchVlanId(VlanId.ANY)));
572 } else {
Andrea Campanellabee52b92020-01-29 14:41:42 +0100573 // Required to differentiate the same match flows
574 // Please note that S tag and S p bit values will be same for the same service - so conflict flows!
575 // Metadata match criteria solves the conflict issue - but not used by the voltha
576 // Maybe - find a better way to solve the above problem
577 Criterion metadata = Criteria.matchMetadata(innerVlan.toShort());
578 TrafficSelector outerSelector = buildSelector(inport, metadata, outerVlan, outerPbit, dstMac);
Gamze Abakadadae722018-09-12 10:55:35 +0000579 installDownstreamRulesForVlans(fwd, output, outerSelector, buildSelector(inport, innerVid));
580 }
581 }
582
583 private void installDownstreamRulesForVlans(ForwardingObjective fwd, Instruction output,
584 TrafficSelector outerSelector, TrafficSelector innerSelector) {
585
586 List<Pair<Instruction, Instruction>> vlanOps =
587 vlanOps(fwd,
588 L2ModificationInstruction.L2SubType.VLAN_POP);
589
590 if (vlanOps == null || vlanOps.isEmpty()) {
591 return;
592 }
593
594 Pair<Instruction, Instruction> popAndRewrite = vlanOps.remove(0);
595
596 TrafficTreatment innerTreatment;
597 VlanId setVlanId = ((L2ModificationInstruction.ModVlanIdInstruction) popAndRewrite.getRight()).vlanId();
598 if (VlanId.NONE.equals(setVlanId)) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000599 innerTreatment = (buildTreatment(popAndRewrite.getLeft(), fetchMeter(fwd),
600 writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000601 } else {
Gamze Abaka61269f82019-12-02 06:42:39 +0000602 innerTreatment = (buildTreatment(popAndRewrite.getRight(),
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000603 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000604 }
605
Gamze Abaka61269f82019-12-02 06:42:39 +0000606 List<Instruction> setVlanPcps = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_PCP,
607 fwd.treatment().allInstructions());
608
609 Instruction innerPbitSet = null;
610
611 if (setVlanPcps != null && !setVlanPcps.isEmpty()) {
612 innerPbitSet = setVlanPcps.get(0);
613 }
614
615 VlanId remarkInnerVlan = null;
616 Optional<Criterion> vlanIdCriterion = readFromSelector(innerSelector, Criterion.Type.VLAN_VID);
617 if (vlanIdCriterion.isPresent()) {
618 remarkInnerVlan = ((VlanIdCriterion) vlanIdCriterion.get()).vlanId();
619 }
620
621 Instruction modVlanId = null;
622 if (innerPbitSet != null) {
623 modVlanId = Instructions.modVlanId(remarkInnerVlan);
624 }
625
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000626 //match: in port (nni), s-tag
627 //action: pop vlan (s-tag), write metadata, go to table 1, meter
alshabibfa0dc662016-01-13 11:23:53 -0800628 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700629 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800630 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800631 .makePermanent()
632 .withPriority(fwd.priority())
Gamze Abakadadae722018-09-12 10:55:35 +0000633 .withSelector(outerSelector)
Gamze Abaka61269f82019-12-02 06:42:39 +0000634 .withTreatment(buildTreatment(popAndRewrite.getLeft(), modVlanId,
635 innerPbitSet, fetchMeter(fwd), fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE)));
alshabibfd430b62015-12-16 18:56:38 -0800636
Gamze Abakadadae722018-09-12 10:55:35 +0000637 //match: in port (nni), c-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000638 //action: immediate: write metadata and pop, meter, output
alshabibfa0dc662016-01-13 11:23:53 -0800639 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700640 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800641 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800642 .forTable(QQ_TABLE)
643 .makePermanent()
644 .withPriority(fwd.priority())
Gamze Abakadadae722018-09-12 10:55:35 +0000645 .withSelector(innerSelector)
646 .withTreatment(innerTreatment);
647 applyRules(fwd, inner, outer);
648 }
649
650 private void installDownstreamRulesForAnyVlan(ForwardingObjective fwd, Instruction output,
651 TrafficSelector outerSelector, TrafficSelector innerSelector) {
652
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000653 //match: in port (nni), s-tag
654 //action: immediate: write metadata, pop vlan, meter and go to table 1
Gamze Abakadadae722018-09-12 10:55:35 +0000655 FlowRule.Builder outer = DefaultFlowRule.builder()
656 .fromApp(fwd.appId())
657 .forDevice(deviceId)
658 .makePermanent()
659 .withPriority(fwd.priority())
660 .withSelector(outerSelector)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000661 .withTreatment(buildTreatment(Instructions.popVlan(), fetchMeter(fwd),
662 fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE)));
Gamze Abakadadae722018-09-12 10:55:35 +0000663
664 //match: in port (nni) and s-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000665 //action: immediate : write metadata, meter and output
Gamze Abakadadae722018-09-12 10:55:35 +0000666 FlowRule.Builder inner = DefaultFlowRule.builder()
667 .fromApp(fwd.appId())
668 .forDevice(deviceId)
669 .forTable(QQ_TABLE)
670 .makePermanent()
671 .withPriority(fwd.priority())
672 .withSelector(innerSelector)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000673 .withTreatment(buildTreatment(fetchMeter(fwd),
674 writeMetadataIncludingOnlyTp(fwd), output));
alshabibfd430b62015-12-16 18:56:38 -0800675
676 applyRules(fwd, inner, outer);
alshabibfd430b62015-12-16 18:56:38 -0800677 }
678
679 private void installUpstreamRules(ForwardingObjective fwd) {
680 List<Pair<Instruction, Instruction>> vlanOps =
681 vlanOps(fwd,
682 L2ModificationInstruction.L2SubType.VLAN_PUSH);
683
Gamze Abakadadae722018-09-12 10:55:35 +0000684 if (vlanOps == null || vlanOps.isEmpty()) {
alshabibfd430b62015-12-16 18:56:38 -0800685 return;
686 }
687
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000688 Instruction output = fetchOutput(fwd, UPSTREAM);
alshabibfd430b62015-12-16 18:56:38 -0800689
690 if (output == null) {
691 return;
692 }
693
alshabibfd430b62015-12-16 18:56:38 -0800694 Pair<Instruction, Instruction> outerPair = vlanOps.remove(0);
695
Gamze Abakadadae722018-09-12 10:55:35 +0000696 boolean noneValueVlanStatus = checkNoneVlanCriteria(fwd);
697 boolean anyValueVlanStatus = checkAnyVlanMatchCriteria(fwd);
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700698
Gamze Abakadadae722018-09-12 10:55:35 +0000699 if (anyValueVlanStatus) {
700 installUpstreamRulesForAnyVlan(fwd, output, outerPair);
701 } else {
Andrea Campanellabee52b92020-01-29 14:41:42 +0100702 Pair<Instruction, Instruction> innerPair = outerPair;
703 outerPair = vlanOps.remove(0);
Gamze Abakadadae722018-09-12 10:55:35 +0000704 installUpstreamRulesForVlans(fwd, output, innerPair, outerPair, noneValueVlanStatus);
705 }
706 }
707
708 private void installUpstreamRulesForVlans(ForwardingObjective fwd, Instruction output,
709 Pair<Instruction, Instruction> innerPair,
710 Pair<Instruction, Instruction> outerPair, Boolean noneValueVlanStatus) {
711
Gamze Abaka61269f82019-12-02 06:42:39 +0000712 List<Instruction> setVlanPcps = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_PCP,
713 fwd.treatment().allInstructions());
714
715 Instruction innerPbitSet = null;
716 Instruction outerPbitSet = null;
717
718 if (setVlanPcps != null && !setVlanPcps.isEmpty()) {
719 innerPbitSet = setVlanPcps.get(0);
720 outerPbitSet = setVlanPcps.get(1);
721 }
722
Gamze Abakadadae722018-09-12 10:55:35 +0000723 TrafficTreatment innerTreatment;
724 if (noneValueVlanStatus) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000725 innerTreatment = buildTreatment(innerPair.getLeft(), innerPair.getRight(), fetchMeter(fwd),
Gamze Abaka61269f82019-12-02 06:42:39 +0000726 fetchWriteMetadata(fwd), innerPbitSet,
727 Instructions.transition(QQ_TABLE));
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700728 } else {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000729 innerTreatment = buildTreatment(innerPair.getRight(), fetchMeter(fwd), fetchWriteMetadata(fwd),
Gamze Abaka61269f82019-12-02 06:42:39 +0000730 innerPbitSet, Instructions.transition(QQ_TABLE));
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700731 }
732
Gamze Abakadadae722018-09-12 10:55:35 +0000733 //match: in port, vlanId (0 or None)
734 //action:
735 //if vlanId None, push & set c-tag go to table 1
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000736 //if vlanId 0 or any specific vlan, set c-tag, write metadata, meter and go to table 1
alshabibfd430b62015-12-16 18:56:38 -0800737 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700738 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800739 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800740 .makePermanent()
741 .withPriority(fwd.priority())
742 .withSelector(fwd.selector())
Gamze Abakadadae722018-09-12 10:55:35 +0000743 .withTreatment(innerTreatment);
alshabibfd430b62015-12-16 18:56:38 -0800744
745 PortCriterion inPort = (PortCriterion)
746 fwd.selector().getCriterion(Criterion.Type.IN_PORT);
747
748 VlanId cVlanId = ((L2ModificationInstruction.ModVlanIdInstruction)
749 innerPair.getRight()).vlanId();
750
Gamze Abakadadae722018-09-12 10:55:35 +0000751 //match: in port, c-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000752 //action: immediate: push s-tag, write metadata, meter and output
alshabibfd430b62015-12-16 18:56:38 -0800753 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700754 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800755 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800756 .forTable(QQ_TABLE)
757 .makePermanent()
758 .withPriority(fwd.priority())
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000759 .withTreatment(buildTreatment(outerPair.getLeft(), outerPair.getRight(),
Gamze Abaka61269f82019-12-02 06:42:39 +0000760 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd),
761 outerPbitSet, output));
762
763 if (innerPbitSet != null) {
764 byte innerPbit = ((L2ModificationInstruction.ModVlanPcpInstruction)
765 innerPbitSet).vlanPcp();
766 outer.withSelector(buildSelector(inPort, Criteria.matchVlanId(cVlanId), Criteria.matchVlanPcp(innerPbit)));
767 } else {
768 outer.withSelector(buildSelector(inPort, Criteria.matchVlanId(cVlanId)));
769 }
alshabibfd430b62015-12-16 18:56:38 -0800770
771 applyRules(fwd, inner, outer);
Gamze Abakadadae722018-09-12 10:55:35 +0000772 }
alshabibfd430b62015-12-16 18:56:38 -0800773
Gamze Abakadadae722018-09-12 10:55:35 +0000774 private void installUpstreamRulesForAnyVlan(ForwardingObjective fwd, Instruction output,
775 Pair<Instruction, Instruction> outerPair) {
776
777 log.debug("Installing upstream rules for any value vlan");
778
779 //match: in port and any-vlan (coming from OLT app.)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000780 //action: write metadata, go to table 1 and meter
Gamze Abakadadae722018-09-12 10:55:35 +0000781 FlowRule.Builder inner = DefaultFlowRule.builder()
782 .fromApp(fwd.appId())
783 .forDevice(deviceId)
784 .makePermanent()
785 .withPriority(fwd.priority())
786 .withSelector(fwd.selector())
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000787 .withTreatment(buildTreatment(Instructions.transition(QQ_TABLE), fetchMeter(fwd),
788 fetchWriteMetadata(fwd)));
Gamze Abakadadae722018-09-12 10:55:35 +0000789
Gamze Abakadadae722018-09-12 10:55:35 +0000790 //match: in port and any-vlan (coming from OLT app.)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000791 //action: immediate: push:QinQ, vlanId (s-tag), write metadata, meter and output
Gamze Abakadadae722018-09-12 10:55:35 +0000792 FlowRule.Builder outer = DefaultFlowRule.builder()
793 .fromApp(fwd.appId())
794 .forDevice(deviceId)
795 .forTable(QQ_TABLE)
796 .makePermanent()
797 .withPriority(fwd.priority())
798 .withSelector(fwd.selector())
Andrea Campanellabee52b92020-01-29 14:41:42 +0100799 .withTreatment(buildTreatment(outerPair.getLeft(), outerPair.getRight(),
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000800 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000801
Andrea Campanellabee52b92020-01-29 14:41:42 +0100802 applyRules(fwd, inner, outer);
Gamze Abakadadae722018-09-12 10:55:35 +0000803 }
804
805 private boolean checkNoneVlanCriteria(ForwardingObjective fwd) {
806 // Add the VLAN_PUSH treatment if we're matching on VlanId.NONE
807 Criterion vlanMatchCriterion = filterForCriterion(fwd.selector().criteria(), Criterion.Type.VLAN_VID);
808 boolean noneValueVlanStatus = false;
809 if (vlanMatchCriterion != null) {
810 noneValueVlanStatus = ((VlanIdCriterion) vlanMatchCriterion).vlanId().equals(VlanId.NONE);
811 }
812 return noneValueVlanStatus;
813 }
814
815 private boolean checkAnyVlanMatchCriteria(ForwardingObjective fwd) {
816 Criterion anyValueVlanCriterion = fwd.selector().criteria().stream()
817 .filter(c -> c.type().equals(Criterion.Type.VLAN_VID))
818 .filter(vc -> ((VlanIdCriterion) vc).vlanId().toShort() == VlanId.ANY_VALUE)
819 .findAny().orElse(null);
820
821 if (anyValueVlanCriterion == null) {
Andrea Campanellabee52b92020-01-29 14:41:42 +0100822 log.debug("Any value vlan match criteria is not found, criteria {}",
823 fwd.selector().criteria());
Gamze Abakadadae722018-09-12 10:55:35 +0000824 return false;
825 }
826
827 return true;
alshabibfd430b62015-12-16 18:56:38 -0800828 }
829
830 private Instruction fetchOutput(ForwardingObjective fwd, String direction) {
831 Instruction output = fwd.treatment().allInstructions().stream()
832 .filter(i -> i.type() == Instruction.Type.OUTPUT)
833 .findFirst().orElse(null);
834
835 if (output == null) {
836 log.error("OLT {} rule has no output", direction);
837 fail(fwd, ObjectiveError.BADPARAMS);
838 return null;
839 }
840 return output;
841 }
842
Gamze Abakadadae722018-09-12 10:55:35 +0000843 private Instruction fetchMeter(ForwardingObjective fwd) {
844 Instruction meter = fwd.treatment().metered();
845
846 if (meter == null) {
847 log.debug("Meter instruction is not found for the forwarding objective {}", fwd);
848 return null;
849 }
850
851 log.debug("Meter instruction is found.");
852 return meter;
853 }
854
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000855 private Instructions.MetadataInstruction fetchWriteMetadata(ForwardingObjective fwd) {
856 Instructions.MetadataInstruction writeMetadata = fwd.treatment().writeMetadata();
Gamze Abakadadae722018-09-12 10:55:35 +0000857
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000858 if (writeMetadata == null) {
859 log.warn("Write metadata is not found for the forwarding obj");
860 fail(fwd, ObjectiveError.BADPARAMS);
Gamze Abakadadae722018-09-12 10:55:35 +0000861 return null;
862 }
863
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000864 log.debug("Write metadata is found {}", writeMetadata);
865 return writeMetadata;
Gamze Abakadadae722018-09-12 10:55:35 +0000866 }
867
alshabibfd430b62015-12-16 18:56:38 -0800868 private List<Pair<Instruction, Instruction>> vlanOps(ForwardingObjective fwd,
869 L2ModificationInstruction.L2SubType type) {
870
871 List<Pair<Instruction, Instruction>> vlanOps = findVlanOps(
872 fwd.treatment().allInstructions(), type);
873
Gamze Abakadadae722018-09-12 10:55:35 +0000874 if (vlanOps == null || vlanOps.isEmpty()) {
alshabibfd430b62015-12-16 18:56:38 -0800875 String direction = type == L2ModificationInstruction.L2SubType.VLAN_POP
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000876 ? DOWNSTREAM : UPSTREAM;
alshabibfd430b62015-12-16 18:56:38 -0800877 log.error("Missing vlan operations in {} forwarding: {}", direction, fwd);
878 fail(fwd, ObjectiveError.BADPARAMS);
Gamze Abakadadae722018-09-12 10:55:35 +0000879 return ImmutableList.of();
alshabibfd430b62015-12-16 18:56:38 -0800880 }
881 return vlanOps;
882 }
883
884
885 private List<Pair<Instruction, Instruction>> findVlanOps(List<Instruction> instructions,
alshabibd61b77b2016-02-01 23:30:53 -0800886 L2ModificationInstruction.L2SubType type) {
alshabibfd430b62015-12-16 18:56:38 -0800887
Gamze Abaka61269f82019-12-02 06:42:39 +0000888 List<Instruction> vlanOperations = findL2Instructions(
alshabibfd430b62015-12-16 18:56:38 -0800889 type,
890 instructions);
891 List<Instruction> vlanSets = findL2Instructions(
892 L2ModificationInstruction.L2SubType.VLAN_ID,
893 instructions);
894
Gamze Abaka61269f82019-12-02 06:42:39 +0000895 if (vlanOperations.size() != vlanSets.size()) {
Gamze Abakadadae722018-09-12 10:55:35 +0000896 return ImmutableList.of();
alshabibfd430b62015-12-16 18:56:38 -0800897 }
898
899 List<Pair<Instruction, Instruction>> pairs = Lists.newArrayList();
900
Gamze Abaka61269f82019-12-02 06:42:39 +0000901 for (int i = 0; i < vlanOperations.size(); i++) {
902 pairs.add(new ImmutablePair<>(vlanOperations.get(i), vlanSets.get(i)));
alshabibfd430b62015-12-16 18:56:38 -0800903 }
904 return pairs;
905 }
906
907 private List<Instruction> findL2Instructions(L2ModificationInstruction.L2SubType subType,
908 List<Instruction> actions) {
909 return actions.stream()
910 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
911 .filter(i -> ((L2ModificationInstruction) i).subtype() == subType)
912 .collect(Collectors.toList());
913 }
914
Amit Ghoshf1f22752018-08-14 07:28:01 +0100915 private void provisionEthTypeBasedFilter(FilteringObjective filter,
916 EthTypeCriterion ethType,
Andrea Campanellabefc2942020-06-11 16:09:39 +0200917 Instructions.OutputInstruction output,
918 L2ModificationInstruction vlanId,
919 L2ModificationInstruction vlanPush) {
alshabibfd430b62015-12-16 18:56:38 -0800920
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000921 Instruction meter = filter.meta().metered();
922 Instruction writeMetadata = filter.meta().writeMetadata();
923
Andrea Campanellabefc2942020-06-11 16:09:39 +0200924 TrafficSelector selector = buildSelector(filter.key(), ethType);
925 TrafficTreatment treatment;
Gamze Abakaf57ef602019-03-11 06:52:48 +0000926
Andrea Campanellabefc2942020-06-11 16:09:39 +0200927 if (vlanPush == null || vlanId == null) {
928 treatment = buildTreatment(output, meter, writeMetadata);
929 } else {
930 // we need to push the vlan because it came untagged (ATT)
931 treatment = buildTreatment(output, meter, vlanPush, vlanId, writeMetadata);
932 }
933
alshabibfd430b62015-12-16 18:56:38 -0800934 buildAndApplyRule(filter, selector, treatment);
935
936 }
937
Jonathan Hart51539b82015-10-29 09:53:04 -0700938 private void provisionIgmp(FilteringObjective filter, EthTypeCriterion ethType,
alshabibfd430b62015-12-16 18:56:38 -0800939 IPProtocolCriterion ipProto,
Andrea Campanellabefc2942020-06-11 16:09:39 +0200940 Instructions.OutputInstruction output,
Andrea Campanella0956dba2020-09-21 14:34:00 +0200941 Instruction vlan, Instruction pcp) {
Gamze Abaka7c070c82019-02-21 14:40:18 +0000942
943 Instruction meter = filter.meta().metered();
944 Instruction writeMetadata = filter.meta().writeMetadata();
945
Andrea Campanellabefc2942020-06-11 16:09:39 +0200946 // uniTagMatch
Gamze Abaka61269f82019-12-02 06:42:39 +0000947 VlanIdCriterion vlanId = (VlanIdCriterion) filterForCriterion(filter.conditions(),
948 Criterion.Type.VLAN_VID);
Gamze Abaka61269f82019-12-02 06:42:39 +0000949
Andrea Campanellabefc2942020-06-11 16:09:39 +0200950 TrafficSelector selector = buildSelector(filter.key(), ethType, ipProto, vlanId);
951 TrafficTreatment treatment = buildTreatment(output, vlan, pcp, meter, writeMetadata);
alshabibfd430b62015-12-16 18:56:38 -0800952 buildAndApplyRule(filter, selector, treatment);
953 }
954
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000955 private void provisionDhcp(FilteringObjective filter, EthTypeCriterion ethType,
956 IPProtocolCriterion ipProto,
957 UdpPortCriterion udpSrcPort,
958 UdpPortCriterion udpDstPort,
Andrea Campanellabefc2942020-06-11 16:09:39 +0200959 Instruction vlanIdInstruction,
960 Instruction vlanPcpInstruction,
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000961 Instructions.OutputInstruction output) {
Gamze Abaka7c070c82019-02-21 14:40:18 +0000962
963 Instruction meter = filter.meta().metered();
964 Instruction writeMetadata = filter.meta().writeMetadata();
965
Andrea Campanellabefc2942020-06-11 16:09:39 +0200966 VlanIdCriterion matchVlanId = (VlanIdCriterion)
Gamze Abaka61269f82019-12-02 06:42:39 +0000967 filterForCriterion(filter.conditions(), Criterion.Type.VLAN_VID);
968
Andrea Campanellabefc2942020-06-11 16:09:39 +0200969 TrafficSelector selector;
970 TrafficTreatment treatment;
971
972 if (matchVlanId != null) {
973 log.debug("Building selector with match VLAN, {}", matchVlanId);
974 // in case of TT upstream the packet comes tagged and the vlan is swapped.
975 selector = buildSelector(filter.key(), ethType, ipProto, udpSrcPort,
976 udpDstPort, matchVlanId);
977 treatment = buildTreatment(output, meter, writeMetadata,
978 vlanIdInstruction, vlanPcpInstruction);
979 } else {
980 log.debug("Building selector with no VLAN");
981 // in case of ATT upstream the packet comes in untagged and we need to push the vlan
982 selector = buildSelector(filter.key(), ethType, ipProto, udpSrcPort, udpDstPort);
983 treatment = buildTreatment(output, meter, vlanIdInstruction, writeMetadata);
984 }
985 //In case of downstream there will be no match on the VLAN, which is null,
986 // so it will just be output, meter, writeMetadata
987
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000988 buildAndApplyRule(filter, selector, treatment);
989 }
Gamze Abakadadae722018-09-12 10:55:35 +0000990
alshabibfd430b62015-12-16 18:56:38 -0800991 private void buildAndApplyRule(FilteringObjective filter, TrafficSelector selector,
992 TrafficTreatment treatment) {
993 FlowRule rule = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700994 .fromApp(filter.appId())
alshabibfd430b62015-12-16 18:56:38 -0800995 .forDevice(deviceId)
996 .forTable(0)
alshabibfd430b62015-12-16 18:56:38 -0800997 .makePermanent()
998 .withSelector(selector)
999 .withTreatment(treatment)
alshabibbb424232016-01-15 12:20:25 -08001000 .withPriority(filter.priority())
alshabibfd430b62015-12-16 18:56:38 -08001001 .build();
1002
1003 FlowRuleOperations.Builder opsBuilder = FlowRuleOperations.builder();
1004
1005 switch (filter.type()) {
1006 case PERMIT:
1007 opsBuilder.add(rule);
1008 break;
1009 case DENY:
1010 opsBuilder.remove(rule);
1011 break;
1012 default:
1013 log.warn("Unknown filter type : {}", filter.type());
1014 fail(filter, ObjectiveError.UNSUPPORTED);
1015 }
1016
1017 applyFlowRules(opsBuilder, filter);
1018 }
1019
Gamze Abakadadae722018-09-12 10:55:35 +00001020 private void applyRules(ForwardingObjective fwd, FlowRule.Builder... fwdBuilders) {
Amit Ghoshf1f22752018-08-14 07:28:01 +01001021 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
1022 switch (fwd.op()) {
1023 case ADD:
Gamze Abakadadae722018-09-12 10:55:35 +00001024 for (FlowRule.Builder fwdBuilder : fwdBuilders) {
1025 builder.add(fwdBuilder.build());
1026 }
Amit Ghoshf1f22752018-08-14 07:28:01 +01001027 break;
1028 case REMOVE:
Gamze Abakadadae722018-09-12 10:55:35 +00001029 for (FlowRule.Builder fwdBuilder : fwdBuilders) {
1030 builder.remove(fwdBuilder.build());
1031 }
alshabibfd430b62015-12-16 18:56:38 -08001032 break;
1033 case ADD_TO_EXISTING:
1034 break;
1035 case REMOVE_FROM_EXISTING:
1036 break;
1037 default:
1038 log.warn("Unknown forwarding operation: {}", fwd.op());
1039 }
1040
1041 applyFlowRules(builder, fwd);
1042 }
1043
1044 private void applyFlowRules(FlowRuleOperations.Builder builder,
1045 Objective objective) {
1046 flowRuleService.apply(builder.build(new FlowRuleOperationsContext() {
1047 @Override
1048 public void onSuccess(FlowRuleOperations ops) {
1049 pass(objective);
1050 }
1051
1052 @Override
1053 public void onError(FlowRuleOperations ops) {
1054 fail(objective, ObjectiveError.FLOWINSTALLATIONFAILED);
1055 }
1056 }));
1057 }
1058
1059 private Criterion filterForCriterion(Collection<Criterion> criteria, Criterion.Type type) {
1060 return criteria.stream()
alshabibbb424232016-01-15 12:20:25 -08001061 .filter(c -> c.type().equals(type))
alshabibfd430b62015-12-16 18:56:38 -08001062 .limit(1)
1063 .findFirst().orElse(null);
1064 }
1065
1066 private TrafficSelector buildSelector(Criterion... criteria) {
1067
alshabibfd430b62015-12-16 18:56:38 -08001068 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
1069
Gamze Abakaf57ef602019-03-11 06:52:48 +00001070 Arrays.stream(criteria).filter(Objects::nonNull).forEach(sBuilder::add);
alshabibfd430b62015-12-16 18:56:38 -08001071
1072 return sBuilder.build();
1073 }
1074
1075 private TrafficTreatment buildTreatment(Instruction... instructions) {
1076
alshabibfd430b62015-12-16 18:56:38 -08001077 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1078
Gamze Abaka6c8a71b2018-12-24 13:17:12 +00001079 Arrays.stream(instructions).filter(Objects::nonNull).forEach(tBuilder::add);
alshabibfd430b62015-12-16 18:56:38 -08001080
1081 return tBuilder.build();
1082 }
1083
Gamze Abaka6c8a71b2018-12-24 13:17:12 +00001084 private Instruction writeMetadataIncludingOnlyTp(ForwardingObjective fwd) {
1085
1086 return Instructions.writeMetadata(
1087 fetchWriteMetadata(fwd).metadata() & 0xFFFF00000000L, 0L);
1088 }
alshabibfd430b62015-12-16 18:56:38 -08001089
1090 private void fail(Objective obj, ObjectiveError error) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -08001091 obj.context().ifPresent(context -> context.onError(obj, error));
alshabibfd430b62015-12-16 18:56:38 -08001092 }
1093
1094 private void pass(Objective obj) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -08001095 obj.context().ifPresent(context -> context.onSuccess(obj));
alshabibfd430b62015-12-16 18:56:38 -08001096 }
1097
alshabib2cc73cb2015-06-30 20:26:56 -07001098
alshabibd61b77b2016-02-01 23:30:53 -08001099 private class InnerGroupListener implements GroupListener {
alshabib2cc73cb2015-06-30 20:26:56 -07001100 @Override
alshabibd61b77b2016-02-01 23:30:53 -08001101 public void event(GroupEvent event) {
Andrea Campanella63b17dc2020-05-06 16:09:10 +02001102 GroupKey key = event.subject().appCookie();
1103 NextObjective obj = pendingGroups.getIfPresent(key);
1104 if (obj == null) {
1105 log.debug("No pending group for {}, moving on", key);
1106 return;
1107 }
1108 log.trace("Event {} for group {}, handling pending" +
1109 "NextGroup {}", event.type(), key, obj.id());
ke hanf5086672016-08-12 11:09:17 +08001110 if (event.type() == GroupEvent.Type.GROUP_ADDED ||
Gamze Abakadadae722018-09-12 10:55:35 +00001111 event.type() == GroupEvent.Type.GROUP_UPDATED) {
alshabibd61b77b2016-02-01 23:30:53 -08001112 flowObjectiveStore.putNextGroup(obj.id(), new OLTPipelineGroup(key));
1113 pass(obj);
1114 pendingGroups.invalidate(key);
Andrea Campanella63b17dc2020-05-06 16:09:10 +02001115 } else if (event.type() == GroupEvent.Type.GROUP_REMOVED) {
1116 flowObjectiveStore.removeNextGroup(obj.id());
1117 pass(obj);
1118 pendingGroups.invalidate(key);
alshabibd61b77b2016-02-01 23:30:53 -08001119 }
alshabib2cc73cb2015-06-30 20:26:56 -07001120 }
1121 }
1122
alshabibd61b77b2016-02-01 23:30:53 -08001123 private static class OLTPipelineGroup implements NextGroup {
1124
1125 private final GroupKey key;
1126
1127 public OLTPipelineGroup(GroupKey key) {
1128 this.key = key;
1129 }
1130
1131 public GroupKey key() {
1132 return key;
1133 }
1134
1135 @Override
1136 public byte[] data() {
1137 return appKryo.serialize(key);
1138 }
1139
1140 }
Saurav Das24431192016-03-07 19:13:00 -08001141
1142 @Override
1143 public List<String> getNextMappings(NextGroup nextGroup) {
1144 // TODO Implementation deferred to vendor
1145 return null;
1146 }
alshabib0ccde6d2015-05-30 18:22:36 -07001147}