blob: 5bf2f752dd7c3e848a96349e57aab8d29930aaed [file] [log] [blame]
alshabib0ccde6d2015-05-30 18:22:36 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
alshabib0ccde6d2015-05-30 18:22:36 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.driver.pipeline;
17
alshabibd61b77b2016-02-01 23:30:53 -080018import com.google.common.cache.Cache;
19import com.google.common.cache.CacheBuilder;
20import com.google.common.cache.RemovalCause;
21import com.google.common.cache.RemovalNotification;
Gamze Abakadadae722018-09-12 10:55:35 +000022import com.google.common.collect.ImmutableList;
alshabibfd430b62015-12-16 18:56:38 -080023import com.google.common.collect.Lists;
24import org.apache.commons.lang3.tuple.ImmutablePair;
25import org.apache.commons.lang3.tuple.Pair;
alshabib0ccde6d2015-05-30 18:22:36 -070026import org.onlab.osgi.ServiceDirectory;
Jonathan Hartdfc3b862015-07-01 14:49:56 -070027import org.onlab.packet.EthType;
alshabibfd430b62015-12-16 18:56:38 -080028import org.onlab.packet.IPv4;
Matteo Scandolo9f4f0072018-11-02 16:09:39 -070029import org.onlab.packet.IPv6;
Gamze Abakafe9d54f2019-12-02 06:42:39 +000030import org.onlab.packet.IpPrefix;
alshabibfd430b62015-12-16 18:56:38 -080031import org.onlab.packet.VlanId;
alshabibd61b77b2016-02-01 23:30:53 -080032import org.onlab.util.KryoNamespace;
Jonathan Hartdfc3b862015-07-01 14:49:56 -070033import org.onosproject.core.ApplicationId;
34import org.onosproject.core.CoreService;
alshabib0ccde6d2015-05-30 18:22:36 -070035import org.onosproject.net.DeviceId;
36import org.onosproject.net.PortNumber;
alshabibd61b77b2016-02-01 23:30:53 -080037import org.onosproject.net.behaviour.NextGroup;
alshabib0ccde6d2015-05-30 18:22:36 -070038import org.onosproject.net.behaviour.Pipeliner;
39import org.onosproject.net.behaviour.PipelinerContext;
40import org.onosproject.net.driver.AbstractHandlerBehaviour;
41import org.onosproject.net.flow.DefaultFlowRule;
Jonathan Hartdfc3b862015-07-01 14:49:56 -070042import org.onosproject.net.flow.DefaultTrafficSelector;
alshabib0ccde6d2015-05-30 18:22:36 -070043import org.onosproject.net.flow.DefaultTrafficTreatment;
44import org.onosproject.net.flow.FlowRule;
45import org.onosproject.net.flow.FlowRuleOperations;
46import org.onosproject.net.flow.FlowRuleOperationsContext;
47import org.onosproject.net.flow.FlowRuleService;
48import org.onosproject.net.flow.TrafficSelector;
49import org.onosproject.net.flow.TrafficTreatment;
alshabibfd430b62015-12-16 18:56:38 -080050import org.onosproject.net.flow.criteria.Criteria;
51import org.onosproject.net.flow.criteria.Criterion;
52import org.onosproject.net.flow.criteria.EthTypeCriterion;
alshabib1aa58142016-02-17 15:37:56 -080053import org.onosproject.net.flow.criteria.IPCriterion;
alshabibfd430b62015-12-16 18:56:38 -080054import org.onosproject.net.flow.criteria.IPProtocolCriterion;
55import org.onosproject.net.flow.criteria.PortCriterion;
Amit Ghoshcbaf8672016-12-23 21:36:19 +000056import org.onosproject.net.flow.criteria.UdpPortCriterion;
alshabib2f74f2c2016-01-14 13:29:35 -080057import org.onosproject.net.flow.criteria.VlanIdCriterion;
alshabibfd430b62015-12-16 18:56:38 -080058import org.onosproject.net.flow.instructions.Instruction;
alshabib0ccde6d2015-05-30 18:22:36 -070059import org.onosproject.net.flow.instructions.Instructions;
alshabibfd430b62015-12-16 18:56:38 -080060import org.onosproject.net.flow.instructions.L2ModificationInstruction;
alshabib0ccde6d2015-05-30 18:22:36 -070061import org.onosproject.net.flowobjective.FilteringObjective;
alshabibd61b77b2016-02-01 23:30:53 -080062import org.onosproject.net.flowobjective.FlowObjectiveStore;
alshabib0ccde6d2015-05-30 18:22:36 -070063import org.onosproject.net.flowobjective.ForwardingObjective;
64import org.onosproject.net.flowobjective.NextObjective;
alshabibfd430b62015-12-16 18:56:38 -080065import org.onosproject.net.flowobjective.Objective;
alshabib0ccde6d2015-05-30 18:22:36 -070066import org.onosproject.net.flowobjective.ObjectiveError;
alshabibd61b77b2016-02-01 23:30:53 -080067import org.onosproject.net.group.DefaultGroupBucket;
68import org.onosproject.net.group.DefaultGroupDescription;
69import org.onosproject.net.group.DefaultGroupKey;
70import org.onosproject.net.group.Group;
71import org.onosproject.net.group.GroupBucket;
72import org.onosproject.net.group.GroupBuckets;
73import org.onosproject.net.group.GroupDescription;
74import org.onosproject.net.group.GroupEvent;
75import org.onosproject.net.group.GroupKey;
76import org.onosproject.net.group.GroupListener;
77import org.onosproject.net.group.GroupService;
78import org.onosproject.store.serializers.KryoNamespaces;
alshabib5ccbe3f2016-03-02 22:36:02 -080079import org.onosproject.store.service.StorageService;
alshabib0ccde6d2015-05-30 18:22:36 -070080import org.slf4j.Logger;
81
Gamze Abakafe9d54f2019-12-02 06:42:39 +000082import java.util.Arrays;
alshabibfd430b62015-12-16 18:56:38 -080083import java.util.Collection;
alshabibd61b77b2016-02-01 23:30:53 -080084import java.util.Collections;
alshabibfd430b62015-12-16 18:56:38 -080085import java.util.List;
Gamze Abakafe9d54f2019-12-02 06:42:39 +000086import java.util.Objects;
alshabibfd430b62015-12-16 18:56:38 -080087import java.util.Optional;
alshabibd61b77b2016-02-01 23:30:53 -080088import java.util.concurrent.TimeUnit;
alshabibfd430b62015-12-16 18:56:38 -080089import java.util.stream.Collectors;
90
Andrea Campanella969e8af2020-07-09 11:39:08 +020091import static org.onosproject.core.CoreService.CORE_APP_NAME;
alshabib0ccde6d2015-05-30 18:22:36 -070092import static org.slf4j.LoggerFactory.getLogger;
93
94/**
Jonathan Hart64da69d2015-07-15 15:10:28 -070095 * Pipeliner for OLT device.
alshabib0ccde6d2015-05-30 18:22:36 -070096 */
alshabibfd430b62015-12-16 18:56:38 -080097
Jonathan Hartb92cc512015-11-16 23:05:21 -080098public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
alshabib0ccde6d2015-05-30 18:22:36 -070099
alshabibfd430b62015-12-16 18:56:38 -0800100 private static final Integer QQ_TABLE = 1;
Gamze Abakadadae722018-09-12 10:55:35 +0000101 private static final int NO_ACTION_PRIORITY = 500;
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000102 private static final String DOWNSTREAM = "downstream";
103 private static final String UPSTREAM = "upstream";
alshabib0ccde6d2015-05-30 18:22:36 -0700104 private final Logger log = getLogger(getClass());
105
106 private ServiceDirectory serviceDirectory;
107 private FlowRuleService flowRuleService;
alshabibd61b77b2016-02-01 23:30:53 -0800108 private GroupService groupService;
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700109 private CoreService coreService;
alshabib5ccbe3f2016-03-02 22:36:02 -0800110 private StorageService storageService;
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700111
alshabibd61b77b2016-02-01 23:30:53 -0800112 private DeviceId deviceId;
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700113 private ApplicationId appId;
alshabib83364472016-03-25 09:59:55 -0700114
alshabib0ccde6d2015-05-30 18:22:36 -0700115
alshabibd61b77b2016-02-01 23:30:53 -0800116 protected FlowObjectiveStore flowObjectiveStore;
117
118 private Cache<GroupKey, NextObjective> pendingGroups;
119
120 protected static KryoNamespace appKryo = new KryoNamespace.Builder()
121 .register(KryoNamespaces.API)
122 .register(GroupKey.class)
123 .register(DefaultGroupKey.class)
124 .register(OLTPipelineGroup.class)
Charles Chaneefdedf2016-05-23 16:45:45 -0700125 .build("OltPipeline");
alshabib2cc73cb2015-06-30 20:26:56 -0700126
alshabib0ccde6d2015-05-30 18:22:36 -0700127 @Override
128 public void init(DeviceId deviceId, PipelinerContext context) {
alshabibfd430b62015-12-16 18:56:38 -0800129 log.debug("Initiate OLT pipeline");
alshabib0ccde6d2015-05-30 18:22:36 -0700130 this.serviceDirectory = context.directory();
131 this.deviceId = deviceId;
alshabibd61b77b2016-02-01 23:30:53 -0800132
alshabib0ccde6d2015-05-30 18:22:36 -0700133 flowRuleService = serviceDirectory.get(FlowRuleService.class);
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700134 coreService = serviceDirectory.get(CoreService.class);
alshabibd61b77b2016-02-01 23:30:53 -0800135 groupService = serviceDirectory.get(GroupService.class);
136 flowObjectiveStore = context.store();
alshabib5ccbe3f2016-03-02 22:36:02 -0800137 storageService = serviceDirectory.get(StorageService.class);
138
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700139 appId = coreService.registerApplication(
140 "org.onosproject.driver.OLTPipeline");
141
alshabibd61b77b2016-02-01 23:30:53 -0800142
143 pendingGroups = CacheBuilder.newBuilder()
144 .expireAfterWrite(20, TimeUnit.SECONDS)
145 .removalListener((RemovalNotification<GroupKey, NextObjective> notification) -> {
146 if (notification.getCause() == RemovalCause.EXPIRED) {
147 fail(notification.getValue(), ObjectiveError.GROUPINSTALLATIONFAILED);
148 }
149 }).build();
150
151 groupService.addListener(new InnerGroupListener());
152
alshabibb32cefe2015-06-08 18:15:05 -0700153 }
154
alshabib0ccde6d2015-05-30 18:22:36 -0700155 @Override
156 public void filter(FilteringObjective filter) {
alshabibfd430b62015-12-16 18:56:38 -0800157 Instructions.OutputInstruction output;
alshabib0ccde6d2015-05-30 18:22:36 -0700158
alshabibfd430b62015-12-16 18:56:38 -0800159 if (filter.meta() != null && !filter.meta().immediate().isEmpty()) {
160 output = (Instructions.OutputInstruction) filter.meta().immediate().stream()
161 .filter(t -> t.type().equals(Instruction.Type.OUTPUT))
162 .limit(1)
163 .findFirst().get();
alshabib0ccde6d2015-05-30 18:22:36 -0700164
alshabibbb424232016-01-15 12:20:25 -0800165 if (output == null || !output.port().equals(PortNumber.CONTROLLER)) {
dvaddire8e6b89a2017-08-31 21:54:03 +0530166 log.warn("OLT can only filter packet to controller");
alshabibfd430b62015-12-16 18:56:38 -0800167 fail(filter, ObjectiveError.UNSUPPORTED);
168 return;
alshabib0ccde6d2015-05-30 18:22:36 -0700169 }
alshabibfd430b62015-12-16 18:56:38 -0800170 } else {
171 fail(filter, ObjectiveError.BADPARAMS);
alshabib0ccde6d2015-05-30 18:22:36 -0700172 return;
173 }
174
alshabibfd430b62015-12-16 18:56:38 -0800175 if (filter.key().type() != Criterion.Type.IN_PORT) {
176 fail(filter, ObjectiveError.BADPARAMS);
177 return;
178 }
179
180 EthTypeCriterion ethType = (EthTypeCriterion)
181 filterForCriterion(filter.conditions(), Criterion.Type.ETH_TYPE);
182
183 if (ethType == null) {
184 fail(filter, ObjectiveError.BADPARAMS);
185 return;
186 }
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200187 Optional<Instruction> vlanId = filter.meta().immediate().stream()
188 .filter(t -> t.type().equals(Instruction.Type.L2MODIFICATION)
189 && ((L2ModificationInstruction) t).subtype()
190 .equals(L2ModificationInstruction.L2SubType.VLAN_ID))
191 .limit(1)
192 .findFirst();
193
194 Optional<Instruction> vlanPcp = filter.meta().immediate().stream()
195 .filter(t -> t.type().equals(Instruction.Type.L2MODIFICATION)
196 && ((L2ModificationInstruction) t).subtype()
197 .equals(L2ModificationInstruction.L2SubType.VLAN_PCP))
198 .limit(1)
199 .findFirst();
200
201 Optional<Instruction> vlanPush = filter.meta().immediate().stream()
202 .filter(t -> t.type().equals(Instruction.Type.L2MODIFICATION)
203 && ((L2ModificationInstruction) t).subtype()
204 .equals(L2ModificationInstruction.L2SubType.VLAN_PUSH))
205 .limit(1)
206 .findFirst();
alshabibfd430b62015-12-16 18:56:38 -0800207
alshabibbb424232016-01-15 12:20:25 -0800208 if (ethType.ethType().equals(EthType.EtherType.EAPOL.ethType())) {
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200209
210 if (vlanId.isEmpty() || vlanPush.isEmpty()) {
211 log.warn("Missing EAPOL vlan or vlanPush");
212 fail(filter, ObjectiveError.BADPARAMS);
213 return;
214 }
215 provisionEthTypeBasedFilter(filter, ethType, output,
216 (L2ModificationInstruction) vlanId.get(),
217 (L2ModificationInstruction) vlanPush.get());
Amit Ghoshf1f22752018-08-14 07:28:01 +0100218 } else if (ethType.ethType().equals(EthType.EtherType.LLDP.ethType())) {
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200219 provisionEthTypeBasedFilter(filter, ethType, output, null, null);
Amit Ghoshf1f22752018-08-14 07:28:01 +0100220
alshabibbb424232016-01-15 12:20:25 -0800221 } else if (ethType.ethType().equals(EthType.EtherType.IPV4.ethType())) {
alshabibfd430b62015-12-16 18:56:38 -0800222 IPProtocolCriterion ipProto = (IPProtocolCriterion)
223 filterForCriterion(filter.conditions(), Criterion.Type.IP_PROTO);
dvaddire8e6b89a2017-08-31 21:54:03 +0530224 if (ipProto == null) {
225 log.warn("OLT can only filter IGMP and DHCP");
226 fail(filter, ObjectiveError.UNSUPPORTED);
227 return;
228 }
alshabibfd430b62015-12-16 18:56:38 -0800229 if (ipProto.protocol() == IPv4.PROTOCOL_IGMP) {
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200230
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 Campanellaa93905c2020-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 Campanellaa93905c2020-06-11 16:09:39 +0200275 provisionDhcp(filter, ethType, ipProto, udpSrcPort, udpDstPort, vlanId.orElse(null),
276 vlanPcp.orElse(null), output);
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700277 } else {
278 log.warn("Filtering rule with unsupported UDP src {} or dst {} port", udpSrcPort, udpDstPort);
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 Campanella6edac322020-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 Campanella5908b562020-05-06 16:09:10 +0200343 return;
alshabibd61b77b2016-02-01 23:30:53 -0800344 }
345
Andrea Campanella5908b562020-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 Campanella5908b562020-05-06 16:09:10 +0200349 return;
alshabibd61b77b2016-02-01 23:30:53 -0800350 }
351
Andrea Campanella5908b562020-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 Campanella5908b562020-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 Campanella5908b562020-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 Campanella5908b562020-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 Campanella5908b562020-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 Campanella5908b562020-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 Abakafe9d54f2019-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 Abakafe9d54f2019-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 Abakafe9d54f2019-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 Karamanec25a0a2020-03-18 14:29:29 +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 Abakafe9d54f2019-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 Campanella969e8af2020-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 Abakafe9d54f2019-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 Abakafe9d54f2019-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 Campanella969e8af2020-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
Amit Ghosha6859982020-02-12 09:35:45 +0000574 // In the case where the C-tag is the same for all the subscribers,
575 // we add a metadata with the outport in the selector to make the flow unique
576 Criterion innerSelectorMeta = Criteria.matchMetadata(output.port().toLong());
577
Gamze Abakadadae722018-09-12 10:55:35 +0000578 if (innerVlan.toShort() == VlanId.ANY_VALUE) {
Andrea Campanella6edac322020-01-29 14:41:42 +0100579 TrafficSelector outerSelector = buildSelector(inport, outerVlan, outerPbit, dstMac);
Gamze Abakadadae722018-09-12 10:55:35 +0000580 installDownstreamRulesForAnyVlan(fwd, output, outerSelector, buildSelector(inport,
Amit Ghosha6859982020-02-12 09:35:45 +0000581 Criteria.matchVlanId(VlanId.ANY), innerSelectorMeta));
Gamze Abakadadae722018-09-12 10:55:35 +0000582 } else {
Andrea Campanella6edac322020-01-29 14:41:42 +0100583 // Required to differentiate the same match flows
584 // Please note that S tag and S p bit values will be same for the same service - so conflict flows!
585 // Metadata match criteria solves the conflict issue - but not used by the voltha
586 // Maybe - find a better way to solve the above problem
587 Criterion metadata = Criteria.matchMetadata(innerVlan.toShort());
588 TrafficSelector outerSelector = buildSelector(inport, metadata, outerVlan, outerPbit, dstMac);
Amit Ghosha6859982020-02-12 09:35:45 +0000589 installDownstreamRulesForVlans(fwd, output, outerSelector, buildSelector(inport, innerVid,
590 innerSelectorMeta));
Gamze Abakadadae722018-09-12 10:55:35 +0000591 }
592 }
593
594 private void installDownstreamRulesForVlans(ForwardingObjective fwd, Instruction output,
595 TrafficSelector outerSelector, TrafficSelector innerSelector) {
596
597 List<Pair<Instruction, Instruction>> vlanOps =
598 vlanOps(fwd,
599 L2ModificationInstruction.L2SubType.VLAN_POP);
600
601 if (vlanOps == null || vlanOps.isEmpty()) {
602 return;
603 }
604
605 Pair<Instruction, Instruction> popAndRewrite = vlanOps.remove(0);
606
607 TrafficTreatment innerTreatment;
608 VlanId setVlanId = ((L2ModificationInstruction.ModVlanIdInstruction) popAndRewrite.getRight()).vlanId();
609 if (VlanId.NONE.equals(setVlanId)) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000610 innerTreatment = (buildTreatment(popAndRewrite.getLeft(), fetchMeter(fwd),
611 writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000612 } else {
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000613 innerTreatment = (buildTreatment(popAndRewrite.getRight(),
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000614 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000615 }
616
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000617 List<Instruction> setVlanPcps = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_PCP,
618 fwd.treatment().allInstructions());
619
620 Instruction innerPbitSet = null;
621
622 if (setVlanPcps != null && !setVlanPcps.isEmpty()) {
623 innerPbitSet = setVlanPcps.get(0);
624 }
625
626 VlanId remarkInnerVlan = null;
627 Optional<Criterion> vlanIdCriterion = readFromSelector(innerSelector, Criterion.Type.VLAN_VID);
628 if (vlanIdCriterion.isPresent()) {
629 remarkInnerVlan = ((VlanIdCriterion) vlanIdCriterion.get()).vlanId();
630 }
631
632 Instruction modVlanId = null;
633 if (innerPbitSet != null) {
634 modVlanId = Instructions.modVlanId(remarkInnerVlan);
635 }
636
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000637 //match: in port (nni), s-tag
638 //action: pop vlan (s-tag), write metadata, go to table 1, meter
alshabibfa0dc662016-01-13 11:23:53 -0800639 FlowRule.Builder outer = 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 .makePermanent()
643 .withPriority(fwd.priority())
Gamze Abakadadae722018-09-12 10:55:35 +0000644 .withSelector(outerSelector)
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000645 .withTreatment(buildTreatment(popAndRewrite.getLeft(), modVlanId,
646 innerPbitSet, fetchMeter(fwd), fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE)));
alshabibfd430b62015-12-16 18:56:38 -0800647
Gamze Abakadadae722018-09-12 10:55:35 +0000648 //match: in port (nni), c-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000649 //action: immediate: write metadata and pop, meter, output
alshabibfa0dc662016-01-13 11:23:53 -0800650 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700651 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800652 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800653 .forTable(QQ_TABLE)
654 .makePermanent()
655 .withPriority(fwd.priority())
Gamze Abakadadae722018-09-12 10:55:35 +0000656 .withSelector(innerSelector)
657 .withTreatment(innerTreatment);
658 applyRules(fwd, inner, outer);
659 }
660
661 private void installDownstreamRulesForAnyVlan(ForwardingObjective fwd, Instruction output,
662 TrafficSelector outerSelector, TrafficSelector innerSelector) {
663
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000664 //match: in port (nni), s-tag
665 //action: immediate: write metadata, pop vlan, meter and go to table 1
Gamze Abakadadae722018-09-12 10:55:35 +0000666 FlowRule.Builder outer = DefaultFlowRule.builder()
667 .fromApp(fwd.appId())
668 .forDevice(deviceId)
669 .makePermanent()
670 .withPriority(fwd.priority())
671 .withSelector(outerSelector)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000672 .withTreatment(buildTreatment(Instructions.popVlan(), fetchMeter(fwd),
673 fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE)));
Gamze Abakadadae722018-09-12 10:55:35 +0000674
675 //match: in port (nni) and s-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000676 //action: immediate : write metadata, meter and output
Gamze Abakadadae722018-09-12 10:55:35 +0000677 FlowRule.Builder inner = DefaultFlowRule.builder()
678 .fromApp(fwd.appId())
679 .forDevice(deviceId)
680 .forTable(QQ_TABLE)
681 .makePermanent()
682 .withPriority(fwd.priority())
683 .withSelector(innerSelector)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000684 .withTreatment(buildTreatment(fetchMeter(fwd),
685 writeMetadataIncludingOnlyTp(fwd), output));
alshabibfd430b62015-12-16 18:56:38 -0800686
687 applyRules(fwd, inner, outer);
alshabibfd430b62015-12-16 18:56:38 -0800688 }
689
690 private void installUpstreamRules(ForwardingObjective fwd) {
691 List<Pair<Instruction, Instruction>> vlanOps =
692 vlanOps(fwd,
693 L2ModificationInstruction.L2SubType.VLAN_PUSH);
694
Gamze Abakadadae722018-09-12 10:55:35 +0000695 if (vlanOps == null || vlanOps.isEmpty()) {
alshabibfd430b62015-12-16 18:56:38 -0800696 return;
697 }
698
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000699 Instruction output = fetchOutput(fwd, UPSTREAM);
alshabibfd430b62015-12-16 18:56:38 -0800700
701 if (output == null) {
702 return;
703 }
704
alshabibfd430b62015-12-16 18:56:38 -0800705 Pair<Instruction, Instruction> outerPair = vlanOps.remove(0);
706
Gamze Abakadadae722018-09-12 10:55:35 +0000707 boolean noneValueVlanStatus = checkNoneVlanCriteria(fwd);
708 boolean anyValueVlanStatus = checkAnyVlanMatchCriteria(fwd);
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700709
Gamze Abakadadae722018-09-12 10:55:35 +0000710 if (anyValueVlanStatus) {
711 installUpstreamRulesForAnyVlan(fwd, output, outerPair);
712 } else {
Andrea Campanella6edac322020-01-29 14:41:42 +0100713 Pair<Instruction, Instruction> innerPair = outerPair;
714 outerPair = vlanOps.remove(0);
Gamze Abakadadae722018-09-12 10:55:35 +0000715 installUpstreamRulesForVlans(fwd, output, innerPair, outerPair, noneValueVlanStatus);
716 }
717 }
718
719 private void installUpstreamRulesForVlans(ForwardingObjective fwd, Instruction output,
720 Pair<Instruction, Instruction> innerPair,
721 Pair<Instruction, Instruction> outerPair, Boolean noneValueVlanStatus) {
722
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000723 List<Instruction> setVlanPcps = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_PCP,
724 fwd.treatment().allInstructions());
725
726 Instruction innerPbitSet = null;
727 Instruction outerPbitSet = null;
728
729 if (setVlanPcps != null && !setVlanPcps.isEmpty()) {
730 innerPbitSet = setVlanPcps.get(0);
731 outerPbitSet = setVlanPcps.get(1);
732 }
733
Gamze Abakadadae722018-09-12 10:55:35 +0000734 TrafficTreatment innerTreatment;
735 if (noneValueVlanStatus) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000736 innerTreatment = buildTreatment(innerPair.getLeft(), innerPair.getRight(), fetchMeter(fwd),
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000737 fetchWriteMetadata(fwd), innerPbitSet,
738 Instructions.transition(QQ_TABLE));
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700739 } else {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000740 innerTreatment = buildTreatment(innerPair.getRight(), fetchMeter(fwd), fetchWriteMetadata(fwd),
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000741 innerPbitSet, Instructions.transition(QQ_TABLE));
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700742 }
743
Gamze Abakadadae722018-09-12 10:55:35 +0000744 //match: in port, vlanId (0 or None)
745 //action:
746 //if vlanId None, push & set c-tag go to table 1
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000747 //if vlanId 0 or any specific vlan, set c-tag, write metadata, meter and go to table 1
alshabibfd430b62015-12-16 18:56:38 -0800748 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700749 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800750 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800751 .makePermanent()
752 .withPriority(fwd.priority())
753 .withSelector(fwd.selector())
Gamze Abakadadae722018-09-12 10:55:35 +0000754 .withTreatment(innerTreatment);
alshabibfd430b62015-12-16 18:56:38 -0800755
756 PortCriterion inPort = (PortCriterion)
757 fwd.selector().getCriterion(Criterion.Type.IN_PORT);
758
759 VlanId cVlanId = ((L2ModificationInstruction.ModVlanIdInstruction)
760 innerPair.getRight()).vlanId();
761
Gamze Abakadadae722018-09-12 10:55:35 +0000762 //match: in port, c-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000763 //action: immediate: push s-tag, write metadata, meter and output
alshabibfd430b62015-12-16 18:56:38 -0800764 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700765 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800766 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800767 .forTable(QQ_TABLE)
768 .makePermanent()
769 .withPriority(fwd.priority())
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000770 .withTreatment(buildTreatment(outerPair.getLeft(), outerPair.getRight(),
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000771 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd),
772 outerPbitSet, output));
773
774 if (innerPbitSet != null) {
775 byte innerPbit = ((L2ModificationInstruction.ModVlanPcpInstruction)
776 innerPbitSet).vlanPcp();
777 outer.withSelector(buildSelector(inPort, Criteria.matchVlanId(cVlanId), Criteria.matchVlanPcp(innerPbit)));
778 } else {
779 outer.withSelector(buildSelector(inPort, Criteria.matchVlanId(cVlanId)));
780 }
alshabibfd430b62015-12-16 18:56:38 -0800781
782 applyRules(fwd, inner, outer);
Gamze Abakadadae722018-09-12 10:55:35 +0000783 }
alshabibfd430b62015-12-16 18:56:38 -0800784
Gamze Abakadadae722018-09-12 10:55:35 +0000785 private void installUpstreamRulesForAnyVlan(ForwardingObjective fwd, Instruction output,
786 Pair<Instruction, Instruction> outerPair) {
787
788 log.debug("Installing upstream rules for any value vlan");
789
790 //match: in port and any-vlan (coming from OLT app.)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000791 //action: write metadata, go to table 1 and meter
Gamze Abakadadae722018-09-12 10:55:35 +0000792 FlowRule.Builder inner = DefaultFlowRule.builder()
793 .fromApp(fwd.appId())
794 .forDevice(deviceId)
795 .makePermanent()
796 .withPriority(fwd.priority())
797 .withSelector(fwd.selector())
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000798 .withTreatment(buildTreatment(Instructions.transition(QQ_TABLE), fetchMeter(fwd),
799 fetchWriteMetadata(fwd)));
Gamze Abakadadae722018-09-12 10:55:35 +0000800
Gamze Abakadadae722018-09-12 10:55:35 +0000801 //match: in port and any-vlan (coming from OLT app.)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000802 //action: immediate: push:QinQ, vlanId (s-tag), write metadata, meter and output
Gamze Abakadadae722018-09-12 10:55:35 +0000803 FlowRule.Builder outer = DefaultFlowRule.builder()
804 .fromApp(fwd.appId())
805 .forDevice(deviceId)
806 .forTable(QQ_TABLE)
807 .makePermanent()
808 .withPriority(fwd.priority())
809 .withSelector(fwd.selector())
Andrea Campanella6edac322020-01-29 14:41:42 +0100810 .withTreatment(buildTreatment(outerPair.getLeft(), outerPair.getRight(),
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000811 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000812
Andrea Campanella6edac322020-01-29 14:41:42 +0100813 applyRules(fwd, inner, outer);
Gamze Abakadadae722018-09-12 10:55:35 +0000814 }
815
816 private boolean checkNoneVlanCriteria(ForwardingObjective fwd) {
817 // Add the VLAN_PUSH treatment if we're matching on VlanId.NONE
818 Criterion vlanMatchCriterion = filterForCriterion(fwd.selector().criteria(), Criterion.Type.VLAN_VID);
819 boolean noneValueVlanStatus = false;
820 if (vlanMatchCriterion != null) {
821 noneValueVlanStatus = ((VlanIdCriterion) vlanMatchCriterion).vlanId().equals(VlanId.NONE);
822 }
823 return noneValueVlanStatus;
824 }
825
826 private boolean checkAnyVlanMatchCriteria(ForwardingObjective fwd) {
827 Criterion anyValueVlanCriterion = fwd.selector().criteria().stream()
828 .filter(c -> c.type().equals(Criterion.Type.VLAN_VID))
829 .filter(vc -> ((VlanIdCriterion) vc).vlanId().toShort() == VlanId.ANY_VALUE)
830 .findAny().orElse(null);
831
832 if (anyValueVlanCriterion == null) {
Andrea Campanella6edac322020-01-29 14:41:42 +0100833 log.debug("Any value vlan match criteria is not found, criteria {}",
834 fwd.selector().criteria());
Gamze Abakadadae722018-09-12 10:55:35 +0000835 return false;
836 }
837
838 return true;
alshabibfd430b62015-12-16 18:56:38 -0800839 }
840
841 private Instruction fetchOutput(ForwardingObjective fwd, String direction) {
842 Instruction output = fwd.treatment().allInstructions().stream()
843 .filter(i -> i.type() == Instruction.Type.OUTPUT)
844 .findFirst().orElse(null);
845
846 if (output == null) {
847 log.error("OLT {} rule has no output", direction);
848 fail(fwd, ObjectiveError.BADPARAMS);
849 return null;
850 }
851 return output;
852 }
853
Gamze Abakadadae722018-09-12 10:55:35 +0000854 private Instruction fetchMeter(ForwardingObjective fwd) {
855 Instruction meter = fwd.treatment().metered();
856
857 if (meter == null) {
858 log.debug("Meter instruction is not found for the forwarding objective {}", fwd);
859 return null;
860 }
861
862 log.debug("Meter instruction is found.");
863 return meter;
864 }
865
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000866 private Instructions.MetadataInstruction fetchWriteMetadata(ForwardingObjective fwd) {
867 Instructions.MetadataInstruction writeMetadata = fwd.treatment().writeMetadata();
Gamze Abakadadae722018-09-12 10:55:35 +0000868
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000869 if (writeMetadata == null) {
870 log.warn("Write metadata is not found for the forwarding obj");
871 fail(fwd, ObjectiveError.BADPARAMS);
Gamze Abakadadae722018-09-12 10:55:35 +0000872 return null;
873 }
874
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000875 log.debug("Write metadata is found {}", writeMetadata);
876 return writeMetadata;
Gamze Abakadadae722018-09-12 10:55:35 +0000877 }
878
alshabibfd430b62015-12-16 18:56:38 -0800879 private List<Pair<Instruction, Instruction>> vlanOps(ForwardingObjective fwd,
880 L2ModificationInstruction.L2SubType type) {
881
882 List<Pair<Instruction, Instruction>> vlanOps = findVlanOps(
883 fwd.treatment().allInstructions(), type);
884
Gamze Abakadadae722018-09-12 10:55:35 +0000885 if (vlanOps == null || vlanOps.isEmpty()) {
alshabibfd430b62015-12-16 18:56:38 -0800886 String direction = type == L2ModificationInstruction.L2SubType.VLAN_POP
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000887 ? DOWNSTREAM : UPSTREAM;
alshabibfd430b62015-12-16 18:56:38 -0800888 log.error("Missing vlan operations in {} forwarding: {}", direction, fwd);
889 fail(fwd, ObjectiveError.BADPARAMS);
Gamze Abakadadae722018-09-12 10:55:35 +0000890 return ImmutableList.of();
alshabibfd430b62015-12-16 18:56:38 -0800891 }
892 return vlanOps;
893 }
894
895
896 private List<Pair<Instruction, Instruction>> findVlanOps(List<Instruction> instructions,
alshabibd61b77b2016-02-01 23:30:53 -0800897 L2ModificationInstruction.L2SubType type) {
alshabibfd430b62015-12-16 18:56:38 -0800898
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000899 List<Instruction> vlanOperations = findL2Instructions(
alshabibfd430b62015-12-16 18:56:38 -0800900 type,
901 instructions);
902 List<Instruction> vlanSets = findL2Instructions(
903 L2ModificationInstruction.L2SubType.VLAN_ID,
904 instructions);
905
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000906 if (vlanOperations.size() != vlanSets.size()) {
Gamze Abakadadae722018-09-12 10:55:35 +0000907 return ImmutableList.of();
alshabibfd430b62015-12-16 18:56:38 -0800908 }
909
910 List<Pair<Instruction, Instruction>> pairs = Lists.newArrayList();
911
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000912 for (int i = 0; i < vlanOperations.size(); i++) {
913 pairs.add(new ImmutablePair<>(vlanOperations.get(i), vlanSets.get(i)));
alshabibfd430b62015-12-16 18:56:38 -0800914 }
915 return pairs;
916 }
917
918 private List<Instruction> findL2Instructions(L2ModificationInstruction.L2SubType subType,
919 List<Instruction> actions) {
920 return actions.stream()
921 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
922 .filter(i -> ((L2ModificationInstruction) i).subtype() == subType)
923 .collect(Collectors.toList());
924 }
925
Amit Ghoshf1f22752018-08-14 07:28:01 +0100926 private void provisionEthTypeBasedFilter(FilteringObjective filter,
927 EthTypeCriterion ethType,
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200928 Instructions.OutputInstruction output,
929 L2ModificationInstruction vlanId,
930 L2ModificationInstruction vlanPush) {
alshabibfd430b62015-12-16 18:56:38 -0800931
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000932 Instruction meter = filter.meta().metered();
933 Instruction writeMetadata = filter.meta().writeMetadata();
934
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200935 TrafficSelector selector = buildSelector(filter.key(), ethType);
936 TrafficTreatment treatment;
Gamze Abakaf57ef602019-03-11 06:52:48 +0000937
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200938 if (vlanPush == null || vlanId == null) {
939 treatment = buildTreatment(output, meter, writeMetadata);
940 } else {
941 // we need to push the vlan because it came untagged (ATT)
942 treatment = buildTreatment(output, meter, vlanPush, vlanId, writeMetadata);
943 }
944
alshabibfd430b62015-12-16 18:56:38 -0800945 buildAndApplyRule(filter, selector, treatment);
946
947 }
948
Jonathan Hart51539b82015-10-29 09:53:04 -0700949 private void provisionIgmp(FilteringObjective filter, EthTypeCriterion ethType,
alshabibfd430b62015-12-16 18:56:38 -0800950 IPProtocolCriterion ipProto,
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200951 Instructions.OutputInstruction output,
952 L2ModificationInstruction vlan, L2ModificationInstruction pcp) {
Gamze Abaka7c070c82019-02-21 14:40:18 +0000953
954 Instruction meter = filter.meta().metered();
955 Instruction writeMetadata = filter.meta().writeMetadata();
956
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200957 // uniTagMatch
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000958 VlanIdCriterion vlanId = (VlanIdCriterion) filterForCriterion(filter.conditions(),
959 Criterion.Type.VLAN_VID);
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000960
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200961 TrafficSelector selector = buildSelector(filter.key(), ethType, ipProto, vlanId);
962 TrafficTreatment treatment = buildTreatment(output, vlan, pcp, meter, writeMetadata);
alshabibfd430b62015-12-16 18:56:38 -0800963 buildAndApplyRule(filter, selector, treatment);
964 }
965
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000966 private void provisionDhcp(FilteringObjective filter, EthTypeCriterion ethType,
967 IPProtocolCriterion ipProto,
968 UdpPortCriterion udpSrcPort,
969 UdpPortCriterion udpDstPort,
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200970 Instruction vlanIdInstruction,
971 Instruction vlanPcpInstruction,
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000972 Instructions.OutputInstruction output) {
Gamze Abaka7c070c82019-02-21 14:40:18 +0000973
974 Instruction meter = filter.meta().metered();
975 Instruction writeMetadata = filter.meta().writeMetadata();
976
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200977 VlanIdCriterion matchVlanId = (VlanIdCriterion)
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000978 filterForCriterion(filter.conditions(), Criterion.Type.VLAN_VID);
979
Andrea Campanellaa93905c2020-06-11 16:09:39 +0200980 TrafficSelector selector;
981 TrafficTreatment treatment;
982
983 if (matchVlanId != null) {
984 log.debug("Building selector with match VLAN, {}", matchVlanId);
985 // in case of TT upstream the packet comes tagged and the vlan is swapped.
986 selector = buildSelector(filter.key(), ethType, ipProto, udpSrcPort,
987 udpDstPort, matchVlanId);
988 treatment = buildTreatment(output, meter, writeMetadata,
989 vlanIdInstruction, vlanPcpInstruction);
990 } else {
991 log.debug("Building selector with no VLAN");
992 // in case of ATT upstream the packet comes in untagged and we need to push the vlan
993 selector = buildSelector(filter.key(), ethType, ipProto, udpSrcPort, udpDstPort);
994 treatment = buildTreatment(output, meter, vlanIdInstruction, writeMetadata);
995 }
996 //In case of downstream there will be no match on the VLAN, which is null,
997 // so it will just be output, meter, writeMetadata
998
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000999 buildAndApplyRule(filter, selector, treatment);
1000 }
Gamze Abakadadae722018-09-12 10:55:35 +00001001
alshabibfd430b62015-12-16 18:56:38 -08001002 private void buildAndApplyRule(FilteringObjective filter, TrafficSelector selector,
1003 TrafficTreatment treatment) {
1004 FlowRule rule = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -07001005 .fromApp(filter.appId())
alshabibfd430b62015-12-16 18:56:38 -08001006 .forDevice(deviceId)
1007 .forTable(0)
alshabibfd430b62015-12-16 18:56:38 -08001008 .makePermanent()
1009 .withSelector(selector)
1010 .withTreatment(treatment)
alshabibbb424232016-01-15 12:20:25 -08001011 .withPriority(filter.priority())
alshabibfd430b62015-12-16 18:56:38 -08001012 .build();
1013
1014 FlowRuleOperations.Builder opsBuilder = FlowRuleOperations.builder();
1015
1016 switch (filter.type()) {
1017 case PERMIT:
1018 opsBuilder.add(rule);
1019 break;
1020 case DENY:
1021 opsBuilder.remove(rule);
1022 break;
1023 default:
1024 log.warn("Unknown filter type : {}", filter.type());
1025 fail(filter, ObjectiveError.UNSUPPORTED);
1026 }
1027
1028 applyFlowRules(opsBuilder, filter);
1029 }
1030
Gamze Abakadadae722018-09-12 10:55:35 +00001031 private void applyRules(ForwardingObjective fwd, FlowRule.Builder... fwdBuilders) {
Amit Ghoshf1f22752018-08-14 07:28:01 +01001032 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
1033 switch (fwd.op()) {
1034 case ADD:
Gamze Abakadadae722018-09-12 10:55:35 +00001035 for (FlowRule.Builder fwdBuilder : fwdBuilders) {
1036 builder.add(fwdBuilder.build());
1037 }
Amit Ghoshf1f22752018-08-14 07:28:01 +01001038 break;
1039 case REMOVE:
Gamze Abakadadae722018-09-12 10:55:35 +00001040 for (FlowRule.Builder fwdBuilder : fwdBuilders) {
1041 builder.remove(fwdBuilder.build());
1042 }
alshabibfd430b62015-12-16 18:56:38 -08001043 break;
1044 case ADD_TO_EXISTING:
1045 break;
1046 case REMOVE_FROM_EXISTING:
1047 break;
1048 default:
1049 log.warn("Unknown forwarding operation: {}", fwd.op());
1050 }
1051
1052 applyFlowRules(builder, fwd);
1053 }
1054
1055 private void applyFlowRules(FlowRuleOperations.Builder builder,
1056 Objective objective) {
1057 flowRuleService.apply(builder.build(new FlowRuleOperationsContext() {
1058 @Override
1059 public void onSuccess(FlowRuleOperations ops) {
1060 pass(objective);
1061 }
1062
1063 @Override
1064 public void onError(FlowRuleOperations ops) {
1065 fail(objective, ObjectiveError.FLOWINSTALLATIONFAILED);
1066 }
1067 }));
1068 }
1069
1070 private Criterion filterForCriterion(Collection<Criterion> criteria, Criterion.Type type) {
1071 return criteria.stream()
alshabibbb424232016-01-15 12:20:25 -08001072 .filter(c -> c.type().equals(type))
alshabibfd430b62015-12-16 18:56:38 -08001073 .limit(1)
1074 .findFirst().orElse(null);
1075 }
1076
1077 private TrafficSelector buildSelector(Criterion... criteria) {
1078
alshabibfd430b62015-12-16 18:56:38 -08001079 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
1080
Gamze Abakaf57ef602019-03-11 06:52:48 +00001081 Arrays.stream(criteria).filter(Objects::nonNull).forEach(sBuilder::add);
alshabibfd430b62015-12-16 18:56:38 -08001082
1083 return sBuilder.build();
1084 }
1085
1086 private TrafficTreatment buildTreatment(Instruction... instructions) {
1087
alshabibfd430b62015-12-16 18:56:38 -08001088 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1089
Gamze Abaka6c8a71b2018-12-24 13:17:12 +00001090 Arrays.stream(instructions).filter(Objects::nonNull).forEach(tBuilder::add);
alshabibfd430b62015-12-16 18:56:38 -08001091
1092 return tBuilder.build();
1093 }
1094
Gamze Abaka6c8a71b2018-12-24 13:17:12 +00001095 private Instruction writeMetadataIncludingOnlyTp(ForwardingObjective fwd) {
1096
1097 return Instructions.writeMetadata(
1098 fetchWriteMetadata(fwd).metadata() & 0xFFFF00000000L, 0L);
1099 }
alshabibfd430b62015-12-16 18:56:38 -08001100
1101 private void fail(Objective obj, ObjectiveError error) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -08001102 obj.context().ifPresent(context -> context.onError(obj, error));
alshabibfd430b62015-12-16 18:56:38 -08001103 }
1104
1105 private void pass(Objective obj) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -08001106 obj.context().ifPresent(context -> context.onSuccess(obj));
alshabibfd430b62015-12-16 18:56:38 -08001107 }
1108
alshabib2cc73cb2015-06-30 20:26:56 -07001109
alshabibd61b77b2016-02-01 23:30:53 -08001110 private class InnerGroupListener implements GroupListener {
alshabib2cc73cb2015-06-30 20:26:56 -07001111 @Override
alshabibd61b77b2016-02-01 23:30:53 -08001112 public void event(GroupEvent event) {
Andrea Campanella5908b562020-05-06 16:09:10 +02001113 GroupKey key = event.subject().appCookie();
1114 NextObjective obj = pendingGroups.getIfPresent(key);
1115 if (obj == null) {
1116 log.debug("No pending group for {}, moving on", key);
1117 return;
1118 }
1119 log.trace("Event {} for group {}, handling pending" +
1120 "NextGroup {}", event.type(), key, obj.id());
ke hanf5086672016-08-12 11:09:17 +08001121 if (event.type() == GroupEvent.Type.GROUP_ADDED ||
Gamze Abakadadae722018-09-12 10:55:35 +00001122 event.type() == GroupEvent.Type.GROUP_UPDATED) {
alshabibd61b77b2016-02-01 23:30:53 -08001123 flowObjectiveStore.putNextGroup(obj.id(), new OLTPipelineGroup(key));
1124 pass(obj);
1125 pendingGroups.invalidate(key);
Andrea Campanella5908b562020-05-06 16:09:10 +02001126 } else if (event.type() == GroupEvent.Type.GROUP_REMOVED) {
1127 flowObjectiveStore.removeNextGroup(obj.id());
1128 pass(obj);
1129 pendingGroups.invalidate(key);
alshabibd61b77b2016-02-01 23:30:53 -08001130 }
alshabib2cc73cb2015-06-30 20:26:56 -07001131 }
1132 }
1133
alshabibd61b77b2016-02-01 23:30:53 -08001134 private static class OLTPipelineGroup implements NextGroup {
1135
1136 private final GroupKey key;
1137
1138 public OLTPipelineGroup(GroupKey key) {
1139 this.key = key;
1140 }
1141
1142 public GroupKey key() {
1143 return key;
1144 }
1145
1146 @Override
1147 public byte[] data() {
1148 return appKryo.serialize(key);
1149 }
1150
1151 }
Saurav Das24431192016-03-07 19:13:00 -08001152
1153 @Override
1154 public List<String> getNextMappings(NextGroup nextGroup) {
1155 // TODO Implementation deferred to vendor
1156 return null;
1157 }
alshabib0ccde6d2015-05-30 18:22:36 -07001158}