blob: fb3bd4e29f83b950c3278e8d21e4fbcc969eeda8 [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
231 if (vlanId.isEmpty() || vlanPcp.isEmpty()) {
232 log.warn("Missing IGMP vlan or pcp");
233 fail(filter, ObjectiveError.BADPARAMS);
234 return;
235 }
236 provisionIgmp(filter, ethType, ipProto, output,
237 (L2ModificationInstruction) vlanId.get(),
238 (L2ModificationInstruction) vlanPcp.get());
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000239 } else if (ipProto.protocol() == IPv4.PROTOCOL_UDP) {
240 UdpPortCriterion udpSrcPort = (UdpPortCriterion)
241 filterForCriterion(filter.conditions(), Criterion.Type.UDP_SRC);
242
243 UdpPortCriterion udpDstPort = (UdpPortCriterion)
244 filterForCriterion(filter.conditions(), Criterion.Type.UDP_DST);
245
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700246 if ((udpSrcPort.udpPort().toInt() == 67 && udpDstPort.udpPort().toInt() == 68) ||
247 (udpSrcPort.udpPort().toInt() == 68 && udpDstPort.udpPort().toInt() == 67)) {
Andrea Campanellabefc2942020-06-11 16:09:39 +0200248 provisionDhcp(filter, ethType, ipProto, udpSrcPort, udpDstPort, vlanId.orElse(null),
249 vlanPcp.orElse(null), output);
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700250 } else {
251 log.warn("Filtering rule with unsupported UDP src {} or dst {} port", udpSrcPort, udpDstPort);
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000252 fail(filter, ObjectiveError.UNSUPPORTED);
253 }
alshabibbb424232016-01-15 12:20:25 -0800254 } else {
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700255 log.warn("Currently supporting only IGMP and DHCP filters for IPv4 packets");
256 fail(filter, ObjectiveError.UNSUPPORTED);
257 }
258 } else if (ethType.ethType().equals(EthType.EtherType.IPV6.ethType())) {
259 IPProtocolCriterion ipProto = (IPProtocolCriterion)
260 filterForCriterion(filter.conditions(), Criterion.Type.IP_PROTO);
261 if (ipProto == null) {
262 log.warn("OLT can only filter DHCP");
263 fail(filter, ObjectiveError.UNSUPPORTED);
264 return;
265 }
266 if (ipProto.protocol() == IPv6.PROTOCOL_UDP) {
267 UdpPortCriterion udpSrcPort = (UdpPortCriterion)
268 filterForCriterion(filter.conditions(), Criterion.Type.UDP_SRC);
269
270 UdpPortCriterion udpDstPort = (UdpPortCriterion)
271 filterForCriterion(filter.conditions(), Criterion.Type.UDP_DST);
272
273 if ((udpSrcPort.udpPort().toInt() == 546 && udpDstPort.udpPort().toInt() == 547) ||
274 (udpSrcPort.udpPort().toInt() == 547 && udpDstPort.udpPort().toInt() == 546)) {
Andrea Campanellabefc2942020-06-11 16:09:39 +0200275 provisionDhcp(filter, ethType, ipProto, udpSrcPort, udpDstPort, vlanId.orElse(null),
276 vlanPcp.orElse(null), output);
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700277 } else {
278 log.warn("Filtering rule with unsupported UDP src {} or dst {} port", udpSrcPort, udpDstPort);
279 fail(filter, ObjectiveError.UNSUPPORTED);
280 }
281 } else {
282 log.warn("Currently supporting only DHCP filters for IPv6 packets");
alshabibbb424232016-01-15 12:20:25 -0800283 fail(filter, ObjectiveError.UNSUPPORTED);
alshabibfd430b62015-12-16 18:56:38 -0800284 }
285 } else {
dvaddire8e6b89a2017-08-31 21:54:03 +0530286 log.warn("\nOnly the following are Supported in OLT for filter ->\n"
Amit Ghoshf1f22752018-08-14 07:28:01 +0100287 + "ETH TYPE : EAPOL, LLDP and IPV4\n"
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700288 + "IPV4 TYPE: IGMP and UDP (for DHCP)"
289 + "IPV6 TYPE: UDP (for DHCP)");
alshabibfd430b62015-12-16 18:56:38 -0800290 fail(filter, ObjectiveError.UNSUPPORTED);
291 }
292
293 }
294
295
296 @Override
297 public void forward(ForwardingObjective fwd) {
Andrea Campanellabee52b92020-01-29 14:41:42 +0100298 log.debug("Installing forwarding objective {}", fwd);
alshabibd61b77b2016-02-01 23:30:53 -0800299 if (checkForMulticast(fwd)) {
300 processMulticastRule(fwd);
301 return;
302 }
303
alshabib0ccde6d2015-05-30 18:22:36 -0700304 TrafficTreatment treatment = fwd.treatment();
alshabib0ccde6d2015-05-30 18:22:36 -0700305
alshabibfd430b62015-12-16 18:56:38 -0800306 List<Instruction> instructions = treatment.allInstructions();
alshabib0ccde6d2015-05-30 18:22:36 -0700307
Gamze Abakadadae722018-09-12 10:55:35 +0000308 Optional<Instruction> vlanInstruction = instructions.stream()
alshabibfd430b62015-12-16 18:56:38 -0800309 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
310 .filter(i -> ((L2ModificationInstruction) i).subtype() ==
311 L2ModificationInstruction.L2SubType.VLAN_PUSH ||
312 ((L2ModificationInstruction) i).subtype() ==
313 L2ModificationInstruction.L2SubType.VLAN_POP)
314 .findAny();
315
Gamze Abakadadae722018-09-12 10:55:35 +0000316
317 if (!vlanInstruction.isPresent()) {
Amit Ghoshf1f22752018-08-14 07:28:01 +0100318 installNoModificationRules(fwd);
alshabib0ccde6d2015-05-30 18:22:36 -0700319 } else {
Amit Ghoshf1f22752018-08-14 07:28:01 +0100320 L2ModificationInstruction vlanIns =
Gamze Abakadadae722018-09-12 10:55:35 +0000321 (L2ModificationInstruction) vlanInstruction.get();
Amit Ghoshf1f22752018-08-14 07:28:01 +0100322 if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
323 installUpstreamRules(fwd);
324 } else if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP) {
325 installDownstreamRules(fwd);
326 } else {
327 log.error("Unknown OLT operation: {}", fwd);
328 fail(fwd, ObjectiveError.UNSUPPORTED);
329 return;
330 }
alshabib0ccde6d2015-05-30 18:22:36 -0700331 }
332
alshabibfd430b62015-12-16 18:56:38 -0800333 pass(fwd);
alshabib0ccde6d2015-05-30 18:22:36 -0700334
alshabib0ccde6d2015-05-30 18:22:36 -0700335 }
336
alshabibd61b77b2016-02-01 23:30:53 -0800337
alshabib0ccde6d2015-05-30 18:22:36 -0700338 @Override
339 public void next(NextObjective nextObjective) {
alshabibd61b77b2016-02-01 23:30:53 -0800340 if (nextObjective.type() != NextObjective.Type.BROADCAST) {
341 log.error("OLT only supports 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 if (nextObjective.next().size() != 1 && !nextObjective.op().equals(Objective.Operation.REMOVE)) {
alshabibd61b77b2016-02-01 23:30:53 -0800347 log.error("OLT only supports singleton broadcast groups.");
348 fail(nextObjective, ObjectiveError.BADPARAMS);
Andrea Campanella63b17dc2020-05-06 16:09:10 +0200349 return;
alshabibd61b77b2016-02-01 23:30:53 -0800350 }
351
Andrea Campanella63b17dc2020-05-06 16:09:10 +0200352 Optional<TrafficTreatment> treatmentOpt = nextObjective.next().stream().findFirst();
353 if (treatmentOpt.isEmpty() && !nextObjective.op().equals(Objective.Operation.REMOVE)) {
354 log.error("Next objective {} does not have a treatment", nextObjective);
355 fail(nextObjective, ObjectiveError.BADPARAMS);
356 return;
357 }
alshabibd61b77b2016-02-01 23:30:53 -0800358
alshabibd61b77b2016-02-01 23:30:53 -0800359 GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id()));
360
alshabibd61b77b2016-02-01 23:30:53 -0800361 pendingGroups.put(key, nextObjective);
Andrea Campanella63b17dc2020-05-06 16:09:10 +0200362 log.trace("NextObjective Operation {}", nextObjective.op());
alshabibd61b77b2016-02-01 23:30:53 -0800363 switch (nextObjective.op()) {
364 case ADD:
alshabib1aa58142016-02-17 15:37:56 -0800365 GroupDescription groupDesc =
366 new DefaultGroupDescription(deviceId,
367 GroupDescription.Type.ALL,
Andrea Campanella63b17dc2020-05-06 16:09:10 +0200368 new GroupBuckets(
369 Collections.singletonList(
370 buildBucket(treatmentOpt.get()))),
alshabib1aa58142016-02-17 15:37:56 -0800371 key,
372 null,
373 nextObjective.appId());
alshabibd61b77b2016-02-01 23:30:53 -0800374 groupService.addGroup(groupDesc);
375 break;
376 case REMOVE:
377 groupService.removeGroup(deviceId, key, nextObjective.appId());
378 break;
379 case ADD_TO_EXISTING:
alshabib1aa58142016-02-17 15:37:56 -0800380 groupService.addBucketsToGroup(deviceId, key,
Andrea Campanella63b17dc2020-05-06 16:09:10 +0200381 new GroupBuckets(
382 Collections.singletonList(
383 buildBucket(treatmentOpt.get()))),
alshabib1aa58142016-02-17 15:37:56 -0800384 key, nextObjective.appId());
385 break;
alshabibd61b77b2016-02-01 23:30:53 -0800386 case REMOVE_FROM_EXISTING:
alshabib1aa58142016-02-17 15:37:56 -0800387 groupService.removeBucketsFromGroup(deviceId, key,
Andrea Campanella63b17dc2020-05-06 16:09:10 +0200388 new GroupBuckets(
389 Collections.singletonList(
390 buildBucket(treatmentOpt.get()))),
alshabib56efe432016-02-25 17:57:24 -0500391 key, nextObjective.appId());
alshabibd61b77b2016-02-01 23:30:53 -0800392 break;
393 default:
394 log.warn("Unknown next objective operation: {}", nextObjective.op());
395 }
396
397
398 }
399
Andrea Campanella63b17dc2020-05-06 16:09:10 +0200400 private GroupBucket buildBucket(TrafficTreatment treatment) {
401 return DefaultGroupBucket.createAllGroupBucket(treatment);
402 }
403
alshabibd61b77b2016-02-01 23:30:53 -0800404 private void processMulticastRule(ForwardingObjective fwd) {
405 if (fwd.nextId() == null) {
406 log.error("Multicast objective does not have a next id");
407 fail(fwd, ObjectiveError.BADPARAMS);
408 }
409
alshabib1aa58142016-02-17 15:37:56 -0800410 GroupKey key = getGroupForNextObjective(fwd.nextId());
alshabibd61b77b2016-02-01 23:30:53 -0800411
alshabib1aa58142016-02-17 15:37:56 -0800412 if (key == null) {
alshabibd61b77b2016-02-01 23:30:53 -0800413 log.error("Group for forwarding objective missing: {}", fwd);
414 fail(fwd, ObjectiveError.GROUPMISSING);
415 }
416
alshabib1aa58142016-02-17 15:37:56 -0800417 Group group = groupService.getGroup(deviceId, key);
alshabibd61b77b2016-02-01 23:30:53 -0800418 TrafficTreatment treatment =
419 buildTreatment(Instructions.createGroup(group.id()));
420
Gamze Abaka61269f82019-12-02 06:42:39 +0000421 TrafficSelector.Builder selectorBuilder = buildIpv4SelectorForMulticast(fwd);
422
alshabibd61b77b2016-02-01 23:30:53 -0800423 FlowRule rule = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700424 .fromApp(fwd.appId())
alshabibd61b77b2016-02-01 23:30:53 -0800425 .forDevice(deviceId)
426 .forTable(0)
alshabibd61b77b2016-02-01 23:30:53 -0800427 .makePermanent()
428 .withPriority(fwd.priority())
Gamze Abaka61269f82019-12-02 06:42:39 +0000429 .withSelector(selectorBuilder.build())
alshabibd61b77b2016-02-01 23:30:53 -0800430 .withTreatment(treatment)
431 .build();
432
433 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
434 switch (fwd.op()) {
435
436 case ADD:
437 builder.add(rule);
438 break;
439 case REMOVE:
440 builder.remove(rule);
441 break;
442 case ADD_TO_EXISTING:
443 case REMOVE_FROM_EXISTING:
444 break;
445 default:
446 log.warn("Unknown forwarding operation: {}", fwd.op());
447 }
448
449 applyFlowRules(builder, fwd);
450
451 }
452
Gamze Abaka61269f82019-12-02 06:42:39 +0000453 private TrafficSelector.Builder buildIpv4SelectorForMulticast(ForwardingObjective fwd) {
454 TrafficSelector.Builder builderToUpdate = DefaultTrafficSelector.builder();
455
456 Optional<Criterion> vlanIdCriterion = readFromSelector(fwd.meta(), Criterion.Type.VLAN_VID);
457 if (vlanIdCriterion.isPresent()) {
458 VlanId assignedVlan = ((VlanIdCriterion) vlanIdCriterion.get()).vlanId();
459 builderToUpdate.matchVlanId(assignedVlan);
460 }
461
Esin Karaman27861222020-03-17 17:09:36 +0000462 Optional<Criterion> innerVlanIdCriterion = readFromSelector(fwd.meta(), Criterion.Type.INNER_VLAN_VID);
463 if (innerVlanIdCriterion.isPresent()) {
464 VlanId assignedInnerVlan = ((VlanIdCriterion) innerVlanIdCriterion.get()).vlanId();
465 builderToUpdate.matchMetadata(assignedInnerVlan.toShort());
466 }
467
Gamze Abaka61269f82019-12-02 06:42:39 +0000468 Optional<Criterion> ethTypeCriterion = readFromSelector(fwd.selector(), Criterion.Type.ETH_TYPE);
469 if (ethTypeCriterion.isPresent()) {
470 EthType ethType = ((EthTypeCriterion) ethTypeCriterion.get()).ethType();
471 builderToUpdate.matchEthType(ethType.toShort());
472 }
473
474 Optional<Criterion> ipv4DstCriterion = readFromSelector(fwd.selector(), Criterion.Type.IPV4_DST);
475 if (ipv4DstCriterion.isPresent()) {
476 IpPrefix ipv4Dst = ((IPCriterion) ipv4DstCriterion.get()).ip();
477 builderToUpdate.matchIPDst(ipv4Dst);
478 }
479
480 return builderToUpdate;
481 }
482
483 static Optional<Criterion> readFromSelector(TrafficSelector selector, Criterion.Type type) {
484 if (selector == null) {
485 return Optional.empty();
486 }
487 Criterion criterion = selector.getCriterion(type);
488 return (criterion == null)
489 ? Optional.empty() : Optional.of(criterion);
490 }
491
alshabibd61b77b2016-02-01 23:30:53 -0800492 private boolean checkForMulticast(ForwardingObjective fwd) {
493
alshabib1aa58142016-02-17 15:37:56 -0800494 IPCriterion ip = (IPCriterion) filterForCriterion(fwd.selector().criteria(),
alshabib56efe432016-02-25 17:57:24 -0500495 Criterion.Type.IPV4_DST);
alshabibd61b77b2016-02-01 23:30:53 -0800496
alshabib1aa58142016-02-17 15:37:56 -0800497 if (ip == null) {
498 return false;
499 }
500
Charles Chanaedabfd2016-02-26 09:31:48 -0800501 return ip.ip().isMulticast();
alshabibd61b77b2016-02-01 23:30:53 -0800502
503 }
504
alshabib1aa58142016-02-17 15:37:56 -0800505 private GroupKey getGroupForNextObjective(Integer nextId) {
alshabibd61b77b2016-02-01 23:30:53 -0800506 NextGroup next = flowObjectiveStore.getNextGroup(nextId);
alshabib1aa58142016-02-17 15:37:56 -0800507 return appKryo.deserialize(next.data());
alshabibd61b77b2016-02-01 23:30:53 -0800508
alshabib0ccde6d2015-05-30 18:22:36 -0700509 }
510
Amit Ghoshf1f22752018-08-14 07:28:01 +0100511 private void installNoModificationRules(ForwardingObjective fwd) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000512 Instructions.OutputInstruction output = (Instructions.OutputInstruction) fetchOutput(fwd, DOWNSTREAM);
Gamze Abakaa34469f2019-04-19 08:30:16 +0000513 Instructions.MetadataInstruction writeMetadata = fetchWriteMetadata(fwd);
514 Instructions.MeterInstruction meter = (Instructions.MeterInstruction) fetchMeter(fwd);
Amit Ghoshf1f22752018-08-14 07:28:01 +0100515
516 TrafficSelector selector = fwd.selector();
517
518 Criterion inport = selector.getCriterion(Criterion.Type.IN_PORT);
519 Criterion outerVlan = selector.getCriterion(Criterion.Type.VLAN_VID);
520 Criterion innerVlan = selector.getCriterion(Criterion.Type.INNER_VLAN_VID);
Amit Ghoshf1f22752018-08-14 07:28:01 +0100521
522 if (inport == null || output == null || innerVlan == null || outerVlan == null) {
Andrea Campanellaae6284c2020-07-09 11:39:08 +0200523 // Avoid logging a non-error from lldp, bbdp and eapol core flows.
524 if (!fwd.appId().name().equals(CORE_APP_NAME)) {
525 log.error("Forwarding objective is underspecified: {}", fwd);
526 } else {
527 log.debug("Not installing unsupported core generated flow {}", fwd);
528 }
Amit Ghoshf1f22752018-08-14 07:28:01 +0100529 fail(fwd, ObjectiveError.BADPARAMS);
530 return;
531 }
532
Amit Ghoshf1f22752018-08-14 07:28:01 +0100533
534 FlowRule.Builder outer = DefaultFlowRule.builder()
535 .fromApp(fwd.appId())
536 .forDevice(deviceId)
537 .makePermanent()
538 .withPriority(fwd.priority())
Gamze Abakaa34469f2019-04-19 08:30:16 +0000539 .withSelector(buildSelector(inport, outerVlan))
540 .withTreatment(buildTreatment(output, writeMetadata, meter));
Amit Ghoshf1f22752018-08-14 07:28:01 +0100541
542 applyRules(fwd, outer);
543 }
544
alshabibfd430b62015-12-16 18:56:38 -0800545 private void installDownstreamRules(ForwardingObjective fwd) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000546 Instructions.OutputInstruction output = (Instructions.OutputInstruction) fetchOutput(fwd, DOWNSTREAM);
alshabibfd430b62015-12-16 18:56:38 -0800547
548 if (output == null) {
549 return;
550 }
551
alshabibfa0dc662016-01-13 11:23:53 -0800552 TrafficSelector selector = fwd.selector();
553
554 Criterion outerVlan = selector.getCriterion(Criterion.Type.VLAN_VID);
Gamze Abaka61269f82019-12-02 06:42:39 +0000555 Criterion outerPbit = selector.getCriterion(Criterion.Type.VLAN_PCP);
Gamze Abakadadae722018-09-12 10:55:35 +0000556 Criterion innerVlanCriterion = selector.getCriterion(Criterion.Type.INNER_VLAN_VID);
alshabibfa0dc662016-01-13 11:23:53 -0800557 Criterion inport = selector.getCriterion(Criterion.Type.IN_PORT);
Gamze Abaka61269f82019-12-02 06:42:39 +0000558 Criterion dstMac = selector.getCriterion(Criterion.Type.ETH_DST);
cboling651c6872018-10-05 11:09:22 -0500559
Gamze Abakadadae722018-09-12 10:55:35 +0000560 if (outerVlan == null || innerVlanCriterion == null || inport == null) {
Andrea Campanellaae6284c2020-07-09 11:39:08 +0200561 // Avoid logging a non-error from lldp, bbdp and eapol core flows.
562 if (!fwd.appId().name().equals(CORE_APP_NAME)) {
563 log.error("Forwarding objective is underspecified: {}", fwd);
564 } else {
565 log.debug("Not installing unsupported core generated flow {}", fwd);
566 }
alshabibfa0dc662016-01-13 11:23:53 -0800567 fail(fwd, ObjectiveError.BADPARAMS);
568 return;
569 }
570
Gamze Abakadadae722018-09-12 10:55:35 +0000571 VlanId innerVlan = ((VlanIdCriterion) innerVlanCriterion).vlanId();
572 Criterion innerVid = Criteria.matchVlanId(innerVlan);
alshabib2f74f2c2016-01-14 13:29:35 -0800573
Gamze Abakadadae722018-09-12 10:55:35 +0000574 if (innerVlan.toShort() == VlanId.ANY_VALUE) {
Andrea Campanellabee52b92020-01-29 14:41:42 +0100575 TrafficSelector outerSelector = buildSelector(inport, outerVlan, outerPbit, dstMac);
Gamze Abakadadae722018-09-12 10:55:35 +0000576 installDownstreamRulesForAnyVlan(fwd, output, outerSelector, buildSelector(inport,
577 Criteria.matchVlanId(VlanId.ANY)));
578 } else {
Andrea Campanellabee52b92020-01-29 14:41:42 +0100579 // Required to differentiate the same match flows
580 // Please note that S tag and S p bit values will be same for the same service - so conflict flows!
581 // Metadata match criteria solves the conflict issue - but not used by the voltha
582 // Maybe - find a better way to solve the above problem
583 Criterion metadata = Criteria.matchMetadata(innerVlan.toShort());
584 TrafficSelector outerSelector = buildSelector(inport, metadata, outerVlan, outerPbit, dstMac);
Gamze Abakadadae722018-09-12 10:55:35 +0000585 installDownstreamRulesForVlans(fwd, output, outerSelector, buildSelector(inport, innerVid));
586 }
587 }
588
589 private void installDownstreamRulesForVlans(ForwardingObjective fwd, Instruction output,
590 TrafficSelector outerSelector, TrafficSelector innerSelector) {
591
592 List<Pair<Instruction, Instruction>> vlanOps =
593 vlanOps(fwd,
594 L2ModificationInstruction.L2SubType.VLAN_POP);
595
596 if (vlanOps == null || vlanOps.isEmpty()) {
597 return;
598 }
599
600 Pair<Instruction, Instruction> popAndRewrite = vlanOps.remove(0);
601
602 TrafficTreatment innerTreatment;
603 VlanId setVlanId = ((L2ModificationInstruction.ModVlanIdInstruction) popAndRewrite.getRight()).vlanId();
604 if (VlanId.NONE.equals(setVlanId)) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000605 innerTreatment = (buildTreatment(popAndRewrite.getLeft(), fetchMeter(fwd),
606 writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000607 } else {
Gamze Abaka61269f82019-12-02 06:42:39 +0000608 innerTreatment = (buildTreatment(popAndRewrite.getRight(),
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000609 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000610 }
611
Gamze Abaka61269f82019-12-02 06:42:39 +0000612 List<Instruction> setVlanPcps = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_PCP,
613 fwd.treatment().allInstructions());
614
615 Instruction innerPbitSet = null;
616
617 if (setVlanPcps != null && !setVlanPcps.isEmpty()) {
618 innerPbitSet = setVlanPcps.get(0);
619 }
620
621 VlanId remarkInnerVlan = null;
622 Optional<Criterion> vlanIdCriterion = readFromSelector(innerSelector, Criterion.Type.VLAN_VID);
623 if (vlanIdCriterion.isPresent()) {
624 remarkInnerVlan = ((VlanIdCriterion) vlanIdCriterion.get()).vlanId();
625 }
626
627 Instruction modVlanId = null;
628 if (innerPbitSet != null) {
629 modVlanId = Instructions.modVlanId(remarkInnerVlan);
630 }
631
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000632 //match: in port (nni), s-tag
633 //action: pop vlan (s-tag), write metadata, go to table 1, meter
alshabibfa0dc662016-01-13 11:23:53 -0800634 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700635 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800636 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800637 .makePermanent()
638 .withPriority(fwd.priority())
Gamze Abakadadae722018-09-12 10:55:35 +0000639 .withSelector(outerSelector)
Gamze Abaka61269f82019-12-02 06:42:39 +0000640 .withTreatment(buildTreatment(popAndRewrite.getLeft(), modVlanId,
641 innerPbitSet, fetchMeter(fwd), fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE)));
alshabibfd430b62015-12-16 18:56:38 -0800642
Gamze Abakadadae722018-09-12 10:55:35 +0000643 //match: in port (nni), c-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000644 //action: immediate: write metadata and pop, meter, output
alshabibfa0dc662016-01-13 11:23:53 -0800645 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700646 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800647 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800648 .forTable(QQ_TABLE)
649 .makePermanent()
650 .withPriority(fwd.priority())
Gamze Abakadadae722018-09-12 10:55:35 +0000651 .withSelector(innerSelector)
652 .withTreatment(innerTreatment);
653 applyRules(fwd, inner, outer);
654 }
655
656 private void installDownstreamRulesForAnyVlan(ForwardingObjective fwd, Instruction output,
657 TrafficSelector outerSelector, TrafficSelector innerSelector) {
658
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000659 //match: in port (nni), s-tag
660 //action: immediate: write metadata, pop vlan, meter and go to table 1
Gamze Abakadadae722018-09-12 10:55:35 +0000661 FlowRule.Builder outer = DefaultFlowRule.builder()
662 .fromApp(fwd.appId())
663 .forDevice(deviceId)
664 .makePermanent()
665 .withPriority(fwd.priority())
666 .withSelector(outerSelector)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000667 .withTreatment(buildTreatment(Instructions.popVlan(), fetchMeter(fwd),
668 fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE)));
Gamze Abakadadae722018-09-12 10:55:35 +0000669
670 //match: in port (nni) and s-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000671 //action: immediate : write metadata, meter and output
Gamze Abakadadae722018-09-12 10:55:35 +0000672 FlowRule.Builder inner = DefaultFlowRule.builder()
673 .fromApp(fwd.appId())
674 .forDevice(deviceId)
675 .forTable(QQ_TABLE)
676 .makePermanent()
677 .withPriority(fwd.priority())
678 .withSelector(innerSelector)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000679 .withTreatment(buildTreatment(fetchMeter(fwd),
680 writeMetadataIncludingOnlyTp(fwd), output));
alshabibfd430b62015-12-16 18:56:38 -0800681
682 applyRules(fwd, inner, outer);
alshabibfd430b62015-12-16 18:56:38 -0800683 }
684
685 private void installUpstreamRules(ForwardingObjective fwd) {
686 List<Pair<Instruction, Instruction>> vlanOps =
687 vlanOps(fwd,
688 L2ModificationInstruction.L2SubType.VLAN_PUSH);
689
Gamze Abakadadae722018-09-12 10:55:35 +0000690 if (vlanOps == null || vlanOps.isEmpty()) {
alshabibfd430b62015-12-16 18:56:38 -0800691 return;
692 }
693
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000694 Instruction output = fetchOutput(fwd, UPSTREAM);
alshabibfd430b62015-12-16 18:56:38 -0800695
696 if (output == null) {
697 return;
698 }
699
alshabibfd430b62015-12-16 18:56:38 -0800700 Pair<Instruction, Instruction> outerPair = vlanOps.remove(0);
701
Gamze Abakadadae722018-09-12 10:55:35 +0000702 boolean noneValueVlanStatus = checkNoneVlanCriteria(fwd);
703 boolean anyValueVlanStatus = checkAnyVlanMatchCriteria(fwd);
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700704
Gamze Abakadadae722018-09-12 10:55:35 +0000705 if (anyValueVlanStatus) {
706 installUpstreamRulesForAnyVlan(fwd, output, outerPair);
707 } else {
Andrea Campanellabee52b92020-01-29 14:41:42 +0100708 Pair<Instruction, Instruction> innerPair = outerPair;
709 outerPair = vlanOps.remove(0);
Gamze Abakadadae722018-09-12 10:55:35 +0000710 installUpstreamRulesForVlans(fwd, output, innerPair, outerPair, noneValueVlanStatus);
711 }
712 }
713
714 private void installUpstreamRulesForVlans(ForwardingObjective fwd, Instruction output,
715 Pair<Instruction, Instruction> innerPair,
716 Pair<Instruction, Instruction> outerPair, Boolean noneValueVlanStatus) {
717
Gamze Abaka61269f82019-12-02 06:42:39 +0000718 List<Instruction> setVlanPcps = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_PCP,
719 fwd.treatment().allInstructions());
720
721 Instruction innerPbitSet = null;
722 Instruction outerPbitSet = null;
723
724 if (setVlanPcps != null && !setVlanPcps.isEmpty()) {
725 innerPbitSet = setVlanPcps.get(0);
726 outerPbitSet = setVlanPcps.get(1);
727 }
728
Gamze Abakadadae722018-09-12 10:55:35 +0000729 TrafficTreatment innerTreatment;
730 if (noneValueVlanStatus) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000731 innerTreatment = buildTreatment(innerPair.getLeft(), innerPair.getRight(), fetchMeter(fwd),
Gamze Abaka61269f82019-12-02 06:42:39 +0000732 fetchWriteMetadata(fwd), innerPbitSet,
733 Instructions.transition(QQ_TABLE));
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700734 } else {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000735 innerTreatment = buildTreatment(innerPair.getRight(), fetchMeter(fwd), fetchWriteMetadata(fwd),
Gamze Abaka61269f82019-12-02 06:42:39 +0000736 innerPbitSet, Instructions.transition(QQ_TABLE));
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700737 }
738
Gamze Abakadadae722018-09-12 10:55:35 +0000739 //match: in port, vlanId (0 or None)
740 //action:
741 //if vlanId None, push & set c-tag go to table 1
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000742 //if vlanId 0 or any specific vlan, set c-tag, write metadata, meter and go to table 1
alshabibfd430b62015-12-16 18:56:38 -0800743 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700744 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800745 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800746 .makePermanent()
747 .withPriority(fwd.priority())
748 .withSelector(fwd.selector())
Gamze Abakadadae722018-09-12 10:55:35 +0000749 .withTreatment(innerTreatment);
alshabibfd430b62015-12-16 18:56:38 -0800750
751 PortCriterion inPort = (PortCriterion)
752 fwd.selector().getCriterion(Criterion.Type.IN_PORT);
753
754 VlanId cVlanId = ((L2ModificationInstruction.ModVlanIdInstruction)
755 innerPair.getRight()).vlanId();
756
Gamze Abakadadae722018-09-12 10:55:35 +0000757 //match: in port, c-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000758 //action: immediate: push s-tag, write metadata, meter and output
alshabibfd430b62015-12-16 18:56:38 -0800759 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700760 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800761 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800762 .forTable(QQ_TABLE)
763 .makePermanent()
764 .withPriority(fwd.priority())
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000765 .withTreatment(buildTreatment(outerPair.getLeft(), outerPair.getRight(),
Gamze Abaka61269f82019-12-02 06:42:39 +0000766 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd),
767 outerPbitSet, output));
768
769 if (innerPbitSet != null) {
770 byte innerPbit = ((L2ModificationInstruction.ModVlanPcpInstruction)
771 innerPbitSet).vlanPcp();
772 outer.withSelector(buildSelector(inPort, Criteria.matchVlanId(cVlanId), Criteria.matchVlanPcp(innerPbit)));
773 } else {
774 outer.withSelector(buildSelector(inPort, Criteria.matchVlanId(cVlanId)));
775 }
alshabibfd430b62015-12-16 18:56:38 -0800776
777 applyRules(fwd, inner, outer);
Gamze Abakadadae722018-09-12 10:55:35 +0000778 }
alshabibfd430b62015-12-16 18:56:38 -0800779
Gamze Abakadadae722018-09-12 10:55:35 +0000780 private void installUpstreamRulesForAnyVlan(ForwardingObjective fwd, Instruction output,
781 Pair<Instruction, Instruction> outerPair) {
782
783 log.debug("Installing upstream rules for any value vlan");
784
785 //match: in port and any-vlan (coming from OLT app.)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000786 //action: write metadata, go to table 1 and meter
Gamze Abakadadae722018-09-12 10:55:35 +0000787 FlowRule.Builder inner = DefaultFlowRule.builder()
788 .fromApp(fwd.appId())
789 .forDevice(deviceId)
790 .makePermanent()
791 .withPriority(fwd.priority())
792 .withSelector(fwd.selector())
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000793 .withTreatment(buildTreatment(Instructions.transition(QQ_TABLE), fetchMeter(fwd),
794 fetchWriteMetadata(fwd)));
Gamze Abakadadae722018-09-12 10:55:35 +0000795
Gamze Abakadadae722018-09-12 10:55:35 +0000796 //match: in port and any-vlan (coming from OLT app.)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000797 //action: immediate: push:QinQ, vlanId (s-tag), write metadata, meter and output
Gamze Abakadadae722018-09-12 10:55:35 +0000798 FlowRule.Builder outer = DefaultFlowRule.builder()
799 .fromApp(fwd.appId())
800 .forDevice(deviceId)
801 .forTable(QQ_TABLE)
802 .makePermanent()
803 .withPriority(fwd.priority())
804 .withSelector(fwd.selector())
Andrea Campanellabee52b92020-01-29 14:41:42 +0100805 .withTreatment(buildTreatment(outerPair.getLeft(), outerPair.getRight(),
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000806 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000807
Andrea Campanellabee52b92020-01-29 14:41:42 +0100808 applyRules(fwd, inner, outer);
Gamze Abakadadae722018-09-12 10:55:35 +0000809 }
810
811 private boolean checkNoneVlanCriteria(ForwardingObjective fwd) {
812 // Add the VLAN_PUSH treatment if we're matching on VlanId.NONE
813 Criterion vlanMatchCriterion = filterForCriterion(fwd.selector().criteria(), Criterion.Type.VLAN_VID);
814 boolean noneValueVlanStatus = false;
815 if (vlanMatchCriterion != null) {
816 noneValueVlanStatus = ((VlanIdCriterion) vlanMatchCriterion).vlanId().equals(VlanId.NONE);
817 }
818 return noneValueVlanStatus;
819 }
820
821 private boolean checkAnyVlanMatchCriteria(ForwardingObjective fwd) {
822 Criterion anyValueVlanCriterion = fwd.selector().criteria().stream()
823 .filter(c -> c.type().equals(Criterion.Type.VLAN_VID))
824 .filter(vc -> ((VlanIdCriterion) vc).vlanId().toShort() == VlanId.ANY_VALUE)
825 .findAny().orElse(null);
826
827 if (anyValueVlanCriterion == null) {
Andrea Campanellabee52b92020-01-29 14:41:42 +0100828 log.debug("Any value vlan match criteria is not found, criteria {}",
829 fwd.selector().criteria());
Gamze Abakadadae722018-09-12 10:55:35 +0000830 return false;
831 }
832
833 return true;
alshabibfd430b62015-12-16 18:56:38 -0800834 }
835
836 private Instruction fetchOutput(ForwardingObjective fwd, String direction) {
837 Instruction output = fwd.treatment().allInstructions().stream()
838 .filter(i -> i.type() == Instruction.Type.OUTPUT)
839 .findFirst().orElse(null);
840
841 if (output == null) {
842 log.error("OLT {} rule has no output", direction);
843 fail(fwd, ObjectiveError.BADPARAMS);
844 return null;
845 }
846 return output;
847 }
848
Gamze Abakadadae722018-09-12 10:55:35 +0000849 private Instruction fetchMeter(ForwardingObjective fwd) {
850 Instruction meter = fwd.treatment().metered();
851
852 if (meter == null) {
853 log.debug("Meter instruction is not found for the forwarding objective {}", fwd);
854 return null;
855 }
856
857 log.debug("Meter instruction is found.");
858 return meter;
859 }
860
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000861 private Instructions.MetadataInstruction fetchWriteMetadata(ForwardingObjective fwd) {
862 Instructions.MetadataInstruction writeMetadata = fwd.treatment().writeMetadata();
Gamze Abakadadae722018-09-12 10:55:35 +0000863
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000864 if (writeMetadata == null) {
865 log.warn("Write metadata is not found for the forwarding obj");
866 fail(fwd, ObjectiveError.BADPARAMS);
Gamze Abakadadae722018-09-12 10:55:35 +0000867 return null;
868 }
869
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000870 log.debug("Write metadata is found {}", writeMetadata);
871 return writeMetadata;
Gamze Abakadadae722018-09-12 10:55:35 +0000872 }
873
alshabibfd430b62015-12-16 18:56:38 -0800874 private List<Pair<Instruction, Instruction>> vlanOps(ForwardingObjective fwd,
875 L2ModificationInstruction.L2SubType type) {
876
877 List<Pair<Instruction, Instruction>> vlanOps = findVlanOps(
878 fwd.treatment().allInstructions(), type);
879
Gamze Abakadadae722018-09-12 10:55:35 +0000880 if (vlanOps == null || vlanOps.isEmpty()) {
alshabibfd430b62015-12-16 18:56:38 -0800881 String direction = type == L2ModificationInstruction.L2SubType.VLAN_POP
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000882 ? DOWNSTREAM : UPSTREAM;
alshabibfd430b62015-12-16 18:56:38 -0800883 log.error("Missing vlan operations in {} forwarding: {}", direction, fwd);
884 fail(fwd, ObjectiveError.BADPARAMS);
Gamze Abakadadae722018-09-12 10:55:35 +0000885 return ImmutableList.of();
alshabibfd430b62015-12-16 18:56:38 -0800886 }
887 return vlanOps;
888 }
889
890
891 private List<Pair<Instruction, Instruction>> findVlanOps(List<Instruction> instructions,
alshabibd61b77b2016-02-01 23:30:53 -0800892 L2ModificationInstruction.L2SubType type) {
alshabibfd430b62015-12-16 18:56:38 -0800893
Gamze Abaka61269f82019-12-02 06:42:39 +0000894 List<Instruction> vlanOperations = findL2Instructions(
alshabibfd430b62015-12-16 18:56:38 -0800895 type,
896 instructions);
897 List<Instruction> vlanSets = findL2Instructions(
898 L2ModificationInstruction.L2SubType.VLAN_ID,
899 instructions);
900
Gamze Abaka61269f82019-12-02 06:42:39 +0000901 if (vlanOperations.size() != vlanSets.size()) {
Gamze Abakadadae722018-09-12 10:55:35 +0000902 return ImmutableList.of();
alshabibfd430b62015-12-16 18:56:38 -0800903 }
904
905 List<Pair<Instruction, Instruction>> pairs = Lists.newArrayList();
906
Gamze Abaka61269f82019-12-02 06:42:39 +0000907 for (int i = 0; i < vlanOperations.size(); i++) {
908 pairs.add(new ImmutablePair<>(vlanOperations.get(i), vlanSets.get(i)));
alshabibfd430b62015-12-16 18:56:38 -0800909 }
910 return pairs;
911 }
912
913 private List<Instruction> findL2Instructions(L2ModificationInstruction.L2SubType subType,
914 List<Instruction> actions) {
915 return actions.stream()
916 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
917 .filter(i -> ((L2ModificationInstruction) i).subtype() == subType)
918 .collect(Collectors.toList());
919 }
920
Amit Ghoshf1f22752018-08-14 07:28:01 +0100921 private void provisionEthTypeBasedFilter(FilteringObjective filter,
922 EthTypeCriterion ethType,
Andrea Campanellabefc2942020-06-11 16:09:39 +0200923 Instructions.OutputInstruction output,
924 L2ModificationInstruction vlanId,
925 L2ModificationInstruction vlanPush) {
alshabibfd430b62015-12-16 18:56:38 -0800926
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000927 Instruction meter = filter.meta().metered();
928 Instruction writeMetadata = filter.meta().writeMetadata();
929
Andrea Campanellabefc2942020-06-11 16:09:39 +0200930 TrafficSelector selector = buildSelector(filter.key(), ethType);
931 TrafficTreatment treatment;
Gamze Abakaf57ef602019-03-11 06:52:48 +0000932
Andrea Campanellabefc2942020-06-11 16:09:39 +0200933 if (vlanPush == null || vlanId == null) {
934 treatment = buildTreatment(output, meter, writeMetadata);
935 } else {
936 // we need to push the vlan because it came untagged (ATT)
937 treatment = buildTreatment(output, meter, vlanPush, vlanId, writeMetadata);
938 }
939
alshabibfd430b62015-12-16 18:56:38 -0800940 buildAndApplyRule(filter, selector, treatment);
941
942 }
943
Jonathan Hart51539b82015-10-29 09:53:04 -0700944 private void provisionIgmp(FilteringObjective filter, EthTypeCriterion ethType,
alshabibfd430b62015-12-16 18:56:38 -0800945 IPProtocolCriterion ipProto,
Andrea Campanellabefc2942020-06-11 16:09:39 +0200946 Instructions.OutputInstruction output,
947 L2ModificationInstruction vlan, L2ModificationInstruction pcp) {
Gamze Abaka7c070c82019-02-21 14:40:18 +0000948
949 Instruction meter = filter.meta().metered();
950 Instruction writeMetadata = filter.meta().writeMetadata();
951
Andrea Campanellabefc2942020-06-11 16:09:39 +0200952 // uniTagMatch
Gamze Abaka61269f82019-12-02 06:42:39 +0000953 VlanIdCriterion vlanId = (VlanIdCriterion) filterForCriterion(filter.conditions(),
954 Criterion.Type.VLAN_VID);
Gamze Abaka61269f82019-12-02 06:42:39 +0000955
Andrea Campanellabefc2942020-06-11 16:09:39 +0200956 TrafficSelector selector = buildSelector(filter.key(), ethType, ipProto, vlanId);
957 TrafficTreatment treatment = buildTreatment(output, vlan, pcp, meter, writeMetadata);
alshabibfd430b62015-12-16 18:56:38 -0800958 buildAndApplyRule(filter, selector, treatment);
959 }
960
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000961 private void provisionDhcp(FilteringObjective filter, EthTypeCriterion ethType,
962 IPProtocolCriterion ipProto,
963 UdpPortCriterion udpSrcPort,
964 UdpPortCriterion udpDstPort,
Andrea Campanellabefc2942020-06-11 16:09:39 +0200965 Instruction vlanIdInstruction,
966 Instruction vlanPcpInstruction,
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000967 Instructions.OutputInstruction output) {
Gamze Abaka7c070c82019-02-21 14:40:18 +0000968
969 Instruction meter = filter.meta().metered();
970 Instruction writeMetadata = filter.meta().writeMetadata();
971
Andrea Campanellabefc2942020-06-11 16:09:39 +0200972 VlanIdCriterion matchVlanId = (VlanIdCriterion)
Gamze Abaka61269f82019-12-02 06:42:39 +0000973 filterForCriterion(filter.conditions(), Criterion.Type.VLAN_VID);
974
Andrea Campanellabefc2942020-06-11 16:09:39 +0200975 TrafficSelector selector;
976 TrafficTreatment treatment;
977
978 if (matchVlanId != null) {
979 log.debug("Building selector with match VLAN, {}", matchVlanId);
980 // in case of TT upstream the packet comes tagged and the vlan is swapped.
981 selector = buildSelector(filter.key(), ethType, ipProto, udpSrcPort,
982 udpDstPort, matchVlanId);
983 treatment = buildTreatment(output, meter, writeMetadata,
984 vlanIdInstruction, vlanPcpInstruction);
985 } else {
986 log.debug("Building selector with no VLAN");
987 // in case of ATT upstream the packet comes in untagged and we need to push the vlan
988 selector = buildSelector(filter.key(), ethType, ipProto, udpSrcPort, udpDstPort);
989 treatment = buildTreatment(output, meter, vlanIdInstruction, writeMetadata);
990 }
991 //In case of downstream there will be no match on the VLAN, which is null,
992 // so it will just be output, meter, writeMetadata
993
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000994 buildAndApplyRule(filter, selector, treatment);
995 }
Gamze Abakadadae722018-09-12 10:55:35 +0000996
alshabibfd430b62015-12-16 18:56:38 -0800997 private void buildAndApplyRule(FilteringObjective filter, TrafficSelector selector,
998 TrafficTreatment treatment) {
999 FlowRule rule = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -07001000 .fromApp(filter.appId())
alshabibfd430b62015-12-16 18:56:38 -08001001 .forDevice(deviceId)
1002 .forTable(0)
alshabibfd430b62015-12-16 18:56:38 -08001003 .makePermanent()
1004 .withSelector(selector)
1005 .withTreatment(treatment)
alshabibbb424232016-01-15 12:20:25 -08001006 .withPriority(filter.priority())
alshabibfd430b62015-12-16 18:56:38 -08001007 .build();
1008
1009 FlowRuleOperations.Builder opsBuilder = FlowRuleOperations.builder();
1010
1011 switch (filter.type()) {
1012 case PERMIT:
1013 opsBuilder.add(rule);
1014 break;
1015 case DENY:
1016 opsBuilder.remove(rule);
1017 break;
1018 default:
1019 log.warn("Unknown filter type : {}", filter.type());
1020 fail(filter, ObjectiveError.UNSUPPORTED);
1021 }
1022
1023 applyFlowRules(opsBuilder, filter);
1024 }
1025
Gamze Abakadadae722018-09-12 10:55:35 +00001026 private void applyRules(ForwardingObjective fwd, FlowRule.Builder... fwdBuilders) {
Amit Ghoshf1f22752018-08-14 07:28:01 +01001027 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
1028 switch (fwd.op()) {
1029 case ADD:
Gamze Abakadadae722018-09-12 10:55:35 +00001030 for (FlowRule.Builder fwdBuilder : fwdBuilders) {
1031 builder.add(fwdBuilder.build());
1032 }
Amit Ghoshf1f22752018-08-14 07:28:01 +01001033 break;
1034 case REMOVE:
Gamze Abakadadae722018-09-12 10:55:35 +00001035 for (FlowRule.Builder fwdBuilder : fwdBuilders) {
1036 builder.remove(fwdBuilder.build());
1037 }
alshabibfd430b62015-12-16 18:56:38 -08001038 break;
1039 case ADD_TO_EXISTING:
1040 break;
1041 case REMOVE_FROM_EXISTING:
1042 break;
1043 default:
1044 log.warn("Unknown forwarding operation: {}", fwd.op());
1045 }
1046
1047 applyFlowRules(builder, fwd);
1048 }
1049
1050 private void applyFlowRules(FlowRuleOperations.Builder builder,
1051 Objective objective) {
1052 flowRuleService.apply(builder.build(new FlowRuleOperationsContext() {
1053 @Override
1054 public void onSuccess(FlowRuleOperations ops) {
1055 pass(objective);
1056 }
1057
1058 @Override
1059 public void onError(FlowRuleOperations ops) {
1060 fail(objective, ObjectiveError.FLOWINSTALLATIONFAILED);
1061 }
1062 }));
1063 }
1064
1065 private Criterion filterForCriterion(Collection<Criterion> criteria, Criterion.Type type) {
1066 return criteria.stream()
alshabibbb424232016-01-15 12:20:25 -08001067 .filter(c -> c.type().equals(type))
alshabibfd430b62015-12-16 18:56:38 -08001068 .limit(1)
1069 .findFirst().orElse(null);
1070 }
1071
1072 private TrafficSelector buildSelector(Criterion... criteria) {
1073
alshabibfd430b62015-12-16 18:56:38 -08001074 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
1075
Gamze Abakaf57ef602019-03-11 06:52:48 +00001076 Arrays.stream(criteria).filter(Objects::nonNull).forEach(sBuilder::add);
alshabibfd430b62015-12-16 18:56:38 -08001077
1078 return sBuilder.build();
1079 }
1080
1081 private TrafficTreatment buildTreatment(Instruction... instructions) {
1082
alshabibfd430b62015-12-16 18:56:38 -08001083 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1084
Gamze Abaka6c8a71b2018-12-24 13:17:12 +00001085 Arrays.stream(instructions).filter(Objects::nonNull).forEach(tBuilder::add);
alshabibfd430b62015-12-16 18:56:38 -08001086
1087 return tBuilder.build();
1088 }
1089
Gamze Abaka6c8a71b2018-12-24 13:17:12 +00001090 private Instruction writeMetadataIncludingOnlyTp(ForwardingObjective fwd) {
1091
1092 return Instructions.writeMetadata(
1093 fetchWriteMetadata(fwd).metadata() & 0xFFFF00000000L, 0L);
1094 }
alshabibfd430b62015-12-16 18:56:38 -08001095
1096 private void fail(Objective obj, ObjectiveError error) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -08001097 obj.context().ifPresent(context -> context.onError(obj, error));
alshabibfd430b62015-12-16 18:56:38 -08001098 }
1099
1100 private void pass(Objective obj) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -08001101 obj.context().ifPresent(context -> context.onSuccess(obj));
alshabibfd430b62015-12-16 18:56:38 -08001102 }
1103
alshabib2cc73cb2015-06-30 20:26:56 -07001104
alshabibd61b77b2016-02-01 23:30:53 -08001105 private class InnerGroupListener implements GroupListener {
alshabib2cc73cb2015-06-30 20:26:56 -07001106 @Override
alshabibd61b77b2016-02-01 23:30:53 -08001107 public void event(GroupEvent event) {
Andrea Campanella63b17dc2020-05-06 16:09:10 +02001108 GroupKey key = event.subject().appCookie();
1109 NextObjective obj = pendingGroups.getIfPresent(key);
1110 if (obj == null) {
1111 log.debug("No pending group for {}, moving on", key);
1112 return;
1113 }
1114 log.trace("Event {} for group {}, handling pending" +
1115 "NextGroup {}", event.type(), key, obj.id());
ke hanf5086672016-08-12 11:09:17 +08001116 if (event.type() == GroupEvent.Type.GROUP_ADDED ||
Gamze Abakadadae722018-09-12 10:55:35 +00001117 event.type() == GroupEvent.Type.GROUP_UPDATED) {
alshabibd61b77b2016-02-01 23:30:53 -08001118 flowObjectiveStore.putNextGroup(obj.id(), new OLTPipelineGroup(key));
1119 pass(obj);
1120 pendingGroups.invalidate(key);
Andrea Campanella63b17dc2020-05-06 16:09:10 +02001121 } else if (event.type() == GroupEvent.Type.GROUP_REMOVED) {
1122 flowObjectiveStore.removeNextGroup(obj.id());
1123 pass(obj);
1124 pendingGroups.invalidate(key);
alshabibd61b77b2016-02-01 23:30:53 -08001125 }
alshabib2cc73cb2015-06-30 20:26:56 -07001126 }
1127 }
1128
alshabibd61b77b2016-02-01 23:30:53 -08001129 private static class OLTPipelineGroup implements NextGroup {
1130
1131 private final GroupKey key;
1132
1133 public OLTPipelineGroup(GroupKey key) {
1134 this.key = key;
1135 }
1136
1137 public GroupKey key() {
1138 return key;
1139 }
1140
1141 @Override
1142 public byte[] data() {
1143 return appKryo.serialize(key);
1144 }
1145
1146 }
Saurav Das24431192016-03-07 19:13:00 -08001147
1148 @Override
1149 public List<String> getNextMappings(NextGroup nextGroup) {
1150 // TODO Implementation deferred to vendor
1151 return null;
1152 }
alshabib0ccde6d2015-05-30 18:22:36 -07001153}