blob: 90ce2aa39f6777d22250d077af502a03d99ac091 [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());
Gustavo Silva620d6e32021-01-22 13:48:30 -0300218 } else if (ethType.ethType().equals(EthType.EtherType.LLDP.ethType()) ||
219 ethType.ethType().equals(EthType.EtherType.PPPoED.ethType())) {
Andrea Campanellabefc2942020-06-11 16:09:39 +0200220 provisionEthTypeBasedFilter(filter, ethType, output, null, null);
Amit Ghoshf1f22752018-08-14 07:28:01 +0100221
alshabibbb424232016-01-15 12:20:25 -0800222 } else if (ethType.ethType().equals(EthType.EtherType.IPV4.ethType())) {
alshabibfd430b62015-12-16 18:56:38 -0800223 IPProtocolCriterion ipProto = (IPProtocolCriterion)
224 filterForCriterion(filter.conditions(), Criterion.Type.IP_PROTO);
dvaddire8e6b89a2017-08-31 21:54:03 +0530225 if (ipProto == null) {
226 log.warn("OLT can only filter IGMP and DHCP");
227 fail(filter, ObjectiveError.UNSUPPORTED);
228 return;
229 }
alshabibfd430b62015-12-16 18:56:38 -0800230 if (ipProto.protocol() == IPv4.PROTOCOL_IGMP) {
Andrea Campanellabefc2942020-06-11 16:09:39 +0200231 provisionIgmp(filter, ethType, ipProto, output,
Andrea Campanella0956dba2020-09-21 14:34:00 +0200232 vlanId.orElse(null),
233 vlanPcp.orElse(null));
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000234 } else if (ipProto.protocol() == IPv4.PROTOCOL_UDP) {
235 UdpPortCriterion udpSrcPort = (UdpPortCriterion)
236 filterForCriterion(filter.conditions(), Criterion.Type.UDP_SRC);
237
238 UdpPortCriterion udpDstPort = (UdpPortCriterion)
239 filterForCriterion(filter.conditions(), Criterion.Type.UDP_DST);
240
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700241 if ((udpSrcPort.udpPort().toInt() == 67 && udpDstPort.udpPort().toInt() == 68) ||
242 (udpSrcPort.udpPort().toInt() == 68 && udpDstPort.udpPort().toInt() == 67)) {
Andrea Campanellabefc2942020-06-11 16:09:39 +0200243 provisionDhcp(filter, ethType, ipProto, udpSrcPort, udpDstPort, vlanId.orElse(null),
244 vlanPcp.orElse(null), output);
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700245 } else {
246 log.warn("Filtering rule with unsupported UDP src {} or dst {} port", udpSrcPort, udpDstPort);
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000247 fail(filter, ObjectiveError.UNSUPPORTED);
248 }
alshabibbb424232016-01-15 12:20:25 -0800249 } else {
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700250 log.warn("Currently supporting only IGMP and DHCP filters for IPv4 packets");
251 fail(filter, ObjectiveError.UNSUPPORTED);
252 }
253 } else if (ethType.ethType().equals(EthType.EtherType.IPV6.ethType())) {
254 IPProtocolCriterion ipProto = (IPProtocolCriterion)
255 filterForCriterion(filter.conditions(), Criterion.Type.IP_PROTO);
256 if (ipProto == null) {
257 log.warn("OLT can only filter DHCP");
258 fail(filter, ObjectiveError.UNSUPPORTED);
259 return;
260 }
261 if (ipProto.protocol() == IPv6.PROTOCOL_UDP) {
262 UdpPortCriterion udpSrcPort = (UdpPortCriterion)
263 filterForCriterion(filter.conditions(), Criterion.Type.UDP_SRC);
264
265 UdpPortCriterion udpDstPort = (UdpPortCriterion)
266 filterForCriterion(filter.conditions(), Criterion.Type.UDP_DST);
267
268 if ((udpSrcPort.udpPort().toInt() == 546 && udpDstPort.udpPort().toInt() == 547) ||
269 (udpSrcPort.udpPort().toInt() == 547 && udpDstPort.udpPort().toInt() == 546)) {
Andrea Campanellabefc2942020-06-11 16:09:39 +0200270 provisionDhcp(filter, ethType, ipProto, udpSrcPort, udpDstPort, vlanId.orElse(null),
271 vlanPcp.orElse(null), output);
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700272 } else {
273 log.warn("Filtering rule with unsupported UDP src {} or dst {} port", udpSrcPort, udpDstPort);
274 fail(filter, ObjectiveError.UNSUPPORTED);
275 }
276 } else {
277 log.warn("Currently supporting only DHCP filters for IPv6 packets");
alshabibbb424232016-01-15 12:20:25 -0800278 fail(filter, ObjectiveError.UNSUPPORTED);
alshabibfd430b62015-12-16 18:56:38 -0800279 }
280 } else {
dvaddire8e6b89a2017-08-31 21:54:03 +0530281 log.warn("\nOnly the following are Supported in OLT for filter ->\n"
Amit Ghoshf1f22752018-08-14 07:28:01 +0100282 + "ETH TYPE : EAPOL, LLDP and IPV4\n"
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700283 + "IPV4 TYPE: IGMP and UDP (for DHCP)"
284 + "IPV6 TYPE: UDP (for DHCP)");
alshabibfd430b62015-12-16 18:56:38 -0800285 fail(filter, ObjectiveError.UNSUPPORTED);
286 }
287
288 }
289
290
291 @Override
292 public void forward(ForwardingObjective fwd) {
Andrea Campanellabee52b92020-01-29 14:41:42 +0100293 log.debug("Installing forwarding objective {}", fwd);
alshabibd61b77b2016-02-01 23:30:53 -0800294 if (checkForMulticast(fwd)) {
295 processMulticastRule(fwd);
296 return;
297 }
298
alshabib0ccde6d2015-05-30 18:22:36 -0700299 TrafficTreatment treatment = fwd.treatment();
alshabib0ccde6d2015-05-30 18:22:36 -0700300
alshabibfd430b62015-12-16 18:56:38 -0800301 List<Instruction> instructions = treatment.allInstructions();
alshabib0ccde6d2015-05-30 18:22:36 -0700302
Gamze Abakadadae722018-09-12 10:55:35 +0000303 Optional<Instruction> vlanInstruction = instructions.stream()
alshabibfd430b62015-12-16 18:56:38 -0800304 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
305 .filter(i -> ((L2ModificationInstruction) i).subtype() ==
306 L2ModificationInstruction.L2SubType.VLAN_PUSH ||
307 ((L2ModificationInstruction) i).subtype() ==
308 L2ModificationInstruction.L2SubType.VLAN_POP)
309 .findAny();
310
Gamze Abakadadae722018-09-12 10:55:35 +0000311
312 if (!vlanInstruction.isPresent()) {
Amit Ghoshf1f22752018-08-14 07:28:01 +0100313 installNoModificationRules(fwd);
alshabib0ccde6d2015-05-30 18:22:36 -0700314 } else {
Amit Ghoshf1f22752018-08-14 07:28:01 +0100315 L2ModificationInstruction vlanIns =
Gamze Abakadadae722018-09-12 10:55:35 +0000316 (L2ModificationInstruction) vlanInstruction.get();
Amit Ghoshf1f22752018-08-14 07:28:01 +0100317 if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
318 installUpstreamRules(fwd);
319 } else if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP) {
320 installDownstreamRules(fwd);
321 } else {
322 log.error("Unknown OLT operation: {}", fwd);
323 fail(fwd, ObjectiveError.UNSUPPORTED);
324 return;
325 }
alshabib0ccde6d2015-05-30 18:22:36 -0700326 }
327
alshabibfd430b62015-12-16 18:56:38 -0800328 pass(fwd);
alshabib0ccde6d2015-05-30 18:22:36 -0700329
alshabib0ccde6d2015-05-30 18:22:36 -0700330 }
331
alshabibd61b77b2016-02-01 23:30:53 -0800332
alshabib0ccde6d2015-05-30 18:22:36 -0700333 @Override
334 public void next(NextObjective nextObjective) {
alshabibd61b77b2016-02-01 23:30:53 -0800335 if (nextObjective.type() != NextObjective.Type.BROADCAST) {
336 log.error("OLT only supports broadcast groups.");
337 fail(nextObjective, ObjectiveError.BADPARAMS);
Andrea Campanella63b17dc2020-05-06 16:09:10 +0200338 return;
alshabibd61b77b2016-02-01 23:30:53 -0800339 }
340
Andrea Campanella63b17dc2020-05-06 16:09:10 +0200341 if (nextObjective.next().size() != 1 && !nextObjective.op().equals(Objective.Operation.REMOVE)) {
alshabibd61b77b2016-02-01 23:30:53 -0800342 log.error("OLT only supports singleton broadcast groups.");
343 fail(nextObjective, ObjectiveError.BADPARAMS);
Andrea Campanella63b17dc2020-05-06 16:09:10 +0200344 return;
alshabibd61b77b2016-02-01 23:30:53 -0800345 }
346
Andrea Campanella63b17dc2020-05-06 16:09:10 +0200347 Optional<TrafficTreatment> treatmentOpt = nextObjective.next().stream().findFirst();
348 if (treatmentOpt.isEmpty() && !nextObjective.op().equals(Objective.Operation.REMOVE)) {
349 log.error("Next objective {} does not have a treatment", nextObjective);
350 fail(nextObjective, ObjectiveError.BADPARAMS);
351 return;
352 }
alshabibd61b77b2016-02-01 23:30:53 -0800353
alshabibd61b77b2016-02-01 23:30:53 -0800354 GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id()));
355
alshabibd61b77b2016-02-01 23:30:53 -0800356 pendingGroups.put(key, nextObjective);
Andrea Campanella63b17dc2020-05-06 16:09:10 +0200357 log.trace("NextObjective Operation {}", nextObjective.op());
alshabibd61b77b2016-02-01 23:30:53 -0800358 switch (nextObjective.op()) {
359 case ADD:
alshabib1aa58142016-02-17 15:37:56 -0800360 GroupDescription groupDesc =
361 new DefaultGroupDescription(deviceId,
362 GroupDescription.Type.ALL,
Andrea Campanella63b17dc2020-05-06 16:09:10 +0200363 new GroupBuckets(
364 Collections.singletonList(
365 buildBucket(treatmentOpt.get()))),
alshabib1aa58142016-02-17 15:37:56 -0800366 key,
367 null,
368 nextObjective.appId());
alshabibd61b77b2016-02-01 23:30:53 -0800369 groupService.addGroup(groupDesc);
370 break;
371 case REMOVE:
372 groupService.removeGroup(deviceId, key, nextObjective.appId());
373 break;
374 case ADD_TO_EXISTING:
alshabib1aa58142016-02-17 15:37:56 -0800375 groupService.addBucketsToGroup(deviceId, key,
Andrea Campanella63b17dc2020-05-06 16:09:10 +0200376 new GroupBuckets(
377 Collections.singletonList(
378 buildBucket(treatmentOpt.get()))),
alshabib1aa58142016-02-17 15:37:56 -0800379 key, nextObjective.appId());
380 break;
alshabibd61b77b2016-02-01 23:30:53 -0800381 case REMOVE_FROM_EXISTING:
alshabib1aa58142016-02-17 15:37:56 -0800382 groupService.removeBucketsFromGroup(deviceId, key,
Andrea Campanella63b17dc2020-05-06 16:09:10 +0200383 new GroupBuckets(
384 Collections.singletonList(
385 buildBucket(treatmentOpt.get()))),
alshabib56efe432016-02-25 17:57:24 -0500386 key, nextObjective.appId());
alshabibd61b77b2016-02-01 23:30:53 -0800387 break;
388 default:
389 log.warn("Unknown next objective operation: {}", nextObjective.op());
390 }
391
392
393 }
394
Andrea Campanella63b17dc2020-05-06 16:09:10 +0200395 private GroupBucket buildBucket(TrafficTreatment treatment) {
396 return DefaultGroupBucket.createAllGroupBucket(treatment);
397 }
398
alshabibd61b77b2016-02-01 23:30:53 -0800399 private void processMulticastRule(ForwardingObjective fwd) {
400 if (fwd.nextId() == null) {
401 log.error("Multicast objective does not have a next id");
402 fail(fwd, ObjectiveError.BADPARAMS);
403 }
404
alshabib1aa58142016-02-17 15:37:56 -0800405 GroupKey key = getGroupForNextObjective(fwd.nextId());
alshabibd61b77b2016-02-01 23:30:53 -0800406
alshabib1aa58142016-02-17 15:37:56 -0800407 if (key == null) {
alshabibd61b77b2016-02-01 23:30:53 -0800408 log.error("Group for forwarding objective missing: {}", fwd);
409 fail(fwd, ObjectiveError.GROUPMISSING);
410 }
411
alshabib1aa58142016-02-17 15:37:56 -0800412 Group group = groupService.getGroup(deviceId, key);
alshabibd61b77b2016-02-01 23:30:53 -0800413 TrafficTreatment treatment =
414 buildTreatment(Instructions.createGroup(group.id()));
415
Gamze Abaka61269f82019-12-02 06:42:39 +0000416 TrafficSelector.Builder selectorBuilder = buildIpv4SelectorForMulticast(fwd);
417
alshabibd61b77b2016-02-01 23:30:53 -0800418 FlowRule rule = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700419 .fromApp(fwd.appId())
alshabibd61b77b2016-02-01 23:30:53 -0800420 .forDevice(deviceId)
421 .forTable(0)
alshabibd61b77b2016-02-01 23:30:53 -0800422 .makePermanent()
423 .withPriority(fwd.priority())
Gamze Abaka61269f82019-12-02 06:42:39 +0000424 .withSelector(selectorBuilder.build())
alshabibd61b77b2016-02-01 23:30:53 -0800425 .withTreatment(treatment)
426 .build();
427
428 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
429 switch (fwd.op()) {
430
431 case ADD:
432 builder.add(rule);
433 break;
434 case REMOVE:
435 builder.remove(rule);
436 break;
437 case ADD_TO_EXISTING:
438 case REMOVE_FROM_EXISTING:
439 break;
440 default:
441 log.warn("Unknown forwarding operation: {}", fwd.op());
442 }
443
444 applyFlowRules(builder, fwd);
445
446 }
447
Gamze Abaka61269f82019-12-02 06:42:39 +0000448 private TrafficSelector.Builder buildIpv4SelectorForMulticast(ForwardingObjective fwd) {
449 TrafficSelector.Builder builderToUpdate = DefaultTrafficSelector.builder();
450
451 Optional<Criterion> vlanIdCriterion = readFromSelector(fwd.meta(), Criterion.Type.VLAN_VID);
452 if (vlanIdCriterion.isPresent()) {
453 VlanId assignedVlan = ((VlanIdCriterion) vlanIdCriterion.get()).vlanId();
454 builderToUpdate.matchVlanId(assignedVlan);
455 }
456
Esin Karaman27861222020-03-17 17:09:36 +0000457 Optional<Criterion> innerVlanIdCriterion = readFromSelector(fwd.meta(), Criterion.Type.INNER_VLAN_VID);
458 if (innerVlanIdCriterion.isPresent()) {
459 VlanId assignedInnerVlan = ((VlanIdCriterion) innerVlanIdCriterion.get()).vlanId();
460 builderToUpdate.matchMetadata(assignedInnerVlan.toShort());
461 }
462
Gamze Abaka61269f82019-12-02 06:42:39 +0000463 Optional<Criterion> ethTypeCriterion = readFromSelector(fwd.selector(), Criterion.Type.ETH_TYPE);
464 if (ethTypeCriterion.isPresent()) {
465 EthType ethType = ((EthTypeCriterion) ethTypeCriterion.get()).ethType();
466 builderToUpdate.matchEthType(ethType.toShort());
467 }
468
469 Optional<Criterion> ipv4DstCriterion = readFromSelector(fwd.selector(), Criterion.Type.IPV4_DST);
470 if (ipv4DstCriterion.isPresent()) {
471 IpPrefix ipv4Dst = ((IPCriterion) ipv4DstCriterion.get()).ip();
472 builderToUpdate.matchIPDst(ipv4Dst);
473 }
474
475 return builderToUpdate;
476 }
477
478 static Optional<Criterion> readFromSelector(TrafficSelector selector, Criterion.Type type) {
479 if (selector == null) {
480 return Optional.empty();
481 }
482 Criterion criterion = selector.getCriterion(type);
483 return (criterion == null)
484 ? Optional.empty() : Optional.of(criterion);
485 }
486
alshabibd61b77b2016-02-01 23:30:53 -0800487 private boolean checkForMulticast(ForwardingObjective fwd) {
488
alshabib1aa58142016-02-17 15:37:56 -0800489 IPCriterion ip = (IPCriterion) filterForCriterion(fwd.selector().criteria(),
alshabib56efe432016-02-25 17:57:24 -0500490 Criterion.Type.IPV4_DST);
alshabibd61b77b2016-02-01 23:30:53 -0800491
alshabib1aa58142016-02-17 15:37:56 -0800492 if (ip == null) {
493 return false;
494 }
495
Charles Chanaedabfd2016-02-26 09:31:48 -0800496 return ip.ip().isMulticast();
alshabibd61b77b2016-02-01 23:30:53 -0800497
498 }
499
alshabib1aa58142016-02-17 15:37:56 -0800500 private GroupKey getGroupForNextObjective(Integer nextId) {
alshabibd61b77b2016-02-01 23:30:53 -0800501 NextGroup next = flowObjectiveStore.getNextGroup(nextId);
alshabib1aa58142016-02-17 15:37:56 -0800502 return appKryo.deserialize(next.data());
alshabibd61b77b2016-02-01 23:30:53 -0800503
alshabib0ccde6d2015-05-30 18:22:36 -0700504 }
505
Amit Ghoshf1f22752018-08-14 07:28:01 +0100506 private void installNoModificationRules(ForwardingObjective fwd) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000507 Instructions.OutputInstruction output = (Instructions.OutputInstruction) fetchOutput(fwd, DOWNSTREAM);
Gamze Abakaa34469f2019-04-19 08:30:16 +0000508 Instructions.MetadataInstruction writeMetadata = fetchWriteMetadata(fwd);
509 Instructions.MeterInstruction meter = (Instructions.MeterInstruction) fetchMeter(fwd);
Amit Ghoshf1f22752018-08-14 07:28:01 +0100510
511 TrafficSelector selector = fwd.selector();
512
513 Criterion inport = selector.getCriterion(Criterion.Type.IN_PORT);
514 Criterion outerVlan = selector.getCriterion(Criterion.Type.VLAN_VID);
515 Criterion innerVlan = selector.getCriterion(Criterion.Type.INNER_VLAN_VID);
Amit Ghoshf1f22752018-08-14 07:28:01 +0100516
517 if (inport == null || output == null || innerVlan == null || outerVlan == null) {
Andrea Campanellaae6284c2020-07-09 11:39:08 +0200518 // Avoid logging a non-error from lldp, bbdp and eapol core flows.
519 if (!fwd.appId().name().equals(CORE_APP_NAME)) {
520 log.error("Forwarding objective is underspecified: {}", fwd);
521 } else {
522 log.debug("Not installing unsupported core generated flow {}", fwd);
523 }
Amit Ghoshf1f22752018-08-14 07:28:01 +0100524 fail(fwd, ObjectiveError.BADPARAMS);
525 return;
526 }
527
Amit Ghoshf1f22752018-08-14 07:28:01 +0100528
529 FlowRule.Builder outer = DefaultFlowRule.builder()
530 .fromApp(fwd.appId())
531 .forDevice(deviceId)
532 .makePermanent()
533 .withPriority(fwd.priority())
Gamze Abakaa34469f2019-04-19 08:30:16 +0000534 .withSelector(buildSelector(inport, outerVlan))
535 .withTreatment(buildTreatment(output, writeMetadata, meter));
Amit Ghoshf1f22752018-08-14 07:28:01 +0100536
537 applyRules(fwd, outer);
538 }
539
alshabibfd430b62015-12-16 18:56:38 -0800540 private void installDownstreamRules(ForwardingObjective fwd) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000541 Instructions.OutputInstruction output = (Instructions.OutputInstruction) fetchOutput(fwd, DOWNSTREAM);
alshabibfd430b62015-12-16 18:56:38 -0800542
543 if (output == null) {
544 return;
545 }
546
alshabibfa0dc662016-01-13 11:23:53 -0800547 TrafficSelector selector = fwd.selector();
548
549 Criterion outerVlan = selector.getCriterion(Criterion.Type.VLAN_VID);
Gamze Abaka61269f82019-12-02 06:42:39 +0000550 Criterion outerPbit = selector.getCriterion(Criterion.Type.VLAN_PCP);
Gamze Abakadadae722018-09-12 10:55:35 +0000551 Criterion innerVlanCriterion = selector.getCriterion(Criterion.Type.INNER_VLAN_VID);
alshabibfa0dc662016-01-13 11:23:53 -0800552 Criterion inport = selector.getCriterion(Criterion.Type.IN_PORT);
Gamze Abaka61269f82019-12-02 06:42:39 +0000553 Criterion dstMac = selector.getCriterion(Criterion.Type.ETH_DST);
cboling651c6872018-10-05 11:09:22 -0500554
Gamze Abakadadae722018-09-12 10:55:35 +0000555 if (outerVlan == null || innerVlanCriterion == null || inport == null) {
Andrea Campanellaae6284c2020-07-09 11:39:08 +0200556 // Avoid logging a non-error from lldp, bbdp and eapol core flows.
557 if (!fwd.appId().name().equals(CORE_APP_NAME)) {
558 log.error("Forwarding objective is underspecified: {}", fwd);
559 } else {
560 log.debug("Not installing unsupported core generated flow {}", fwd);
561 }
alshabibfa0dc662016-01-13 11:23:53 -0800562 fail(fwd, ObjectiveError.BADPARAMS);
563 return;
564 }
565
Gamze Abakadadae722018-09-12 10:55:35 +0000566 VlanId innerVlan = ((VlanIdCriterion) innerVlanCriterion).vlanId();
567 Criterion innerVid = Criteria.matchVlanId(innerVlan);
alshabib2f74f2c2016-01-14 13:29:35 -0800568
Gamze Abakadadae722018-09-12 10:55:35 +0000569 if (innerVlan.toShort() == VlanId.ANY_VALUE) {
Andrea Campanellabee52b92020-01-29 14:41:42 +0100570 TrafficSelector outerSelector = buildSelector(inport, outerVlan, outerPbit, dstMac);
Gamze Abakadadae722018-09-12 10:55:35 +0000571 installDownstreamRulesForAnyVlan(fwd, output, outerSelector, buildSelector(inport,
572 Criteria.matchVlanId(VlanId.ANY)));
573 } else {
Andrea Campanellabee52b92020-01-29 14:41:42 +0100574 // Required to differentiate the same match flows
575 // Please note that S tag and S p bit values will be same for the same service - so conflict flows!
576 // Metadata match criteria solves the conflict issue - but not used by the voltha
577 // Maybe - find a better way to solve the above problem
578 Criterion metadata = Criteria.matchMetadata(innerVlan.toShort());
579 TrafficSelector outerSelector = buildSelector(inport, metadata, outerVlan, outerPbit, dstMac);
Gamze Abakadadae722018-09-12 10:55:35 +0000580 installDownstreamRulesForVlans(fwd, output, outerSelector, buildSelector(inport, innerVid));
581 }
582 }
583
584 private void installDownstreamRulesForVlans(ForwardingObjective fwd, Instruction output,
585 TrafficSelector outerSelector, TrafficSelector innerSelector) {
586
587 List<Pair<Instruction, Instruction>> vlanOps =
588 vlanOps(fwd,
589 L2ModificationInstruction.L2SubType.VLAN_POP);
590
591 if (vlanOps == null || vlanOps.isEmpty()) {
592 return;
593 }
594
595 Pair<Instruction, Instruction> popAndRewrite = vlanOps.remove(0);
596
597 TrafficTreatment innerTreatment;
598 VlanId setVlanId = ((L2ModificationInstruction.ModVlanIdInstruction) popAndRewrite.getRight()).vlanId();
599 if (VlanId.NONE.equals(setVlanId)) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000600 innerTreatment = (buildTreatment(popAndRewrite.getLeft(), fetchMeter(fwd),
601 writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000602 } else {
Gamze Abaka61269f82019-12-02 06:42:39 +0000603 innerTreatment = (buildTreatment(popAndRewrite.getRight(),
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000604 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000605 }
606
Gamze Abaka61269f82019-12-02 06:42:39 +0000607 List<Instruction> setVlanPcps = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_PCP,
608 fwd.treatment().allInstructions());
609
610 Instruction innerPbitSet = null;
611
612 if (setVlanPcps != null && !setVlanPcps.isEmpty()) {
613 innerPbitSet = setVlanPcps.get(0);
614 }
615
616 VlanId remarkInnerVlan = null;
617 Optional<Criterion> vlanIdCriterion = readFromSelector(innerSelector, Criterion.Type.VLAN_VID);
618 if (vlanIdCriterion.isPresent()) {
619 remarkInnerVlan = ((VlanIdCriterion) vlanIdCriterion.get()).vlanId();
620 }
621
622 Instruction modVlanId = null;
623 if (innerPbitSet != null) {
624 modVlanId = Instructions.modVlanId(remarkInnerVlan);
625 }
626
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000627 //match: in port (nni), s-tag
628 //action: pop vlan (s-tag), write metadata, go to table 1, meter
alshabibfa0dc662016-01-13 11:23:53 -0800629 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700630 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800631 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800632 .makePermanent()
633 .withPriority(fwd.priority())
Gamze Abakadadae722018-09-12 10:55:35 +0000634 .withSelector(outerSelector)
Gamze Abaka61269f82019-12-02 06:42:39 +0000635 .withTreatment(buildTreatment(popAndRewrite.getLeft(), modVlanId,
636 innerPbitSet, fetchMeter(fwd), fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE)));
alshabibfd430b62015-12-16 18:56:38 -0800637
Gamze Abakadadae722018-09-12 10:55:35 +0000638 //match: in port (nni), c-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000639 //action: immediate: write metadata and pop, meter, output
alshabibfa0dc662016-01-13 11:23:53 -0800640 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700641 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800642 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800643 .forTable(QQ_TABLE)
644 .makePermanent()
645 .withPriority(fwd.priority())
Gamze Abakadadae722018-09-12 10:55:35 +0000646 .withSelector(innerSelector)
647 .withTreatment(innerTreatment);
648 applyRules(fwd, inner, outer);
649 }
650
651 private void installDownstreamRulesForAnyVlan(ForwardingObjective fwd, Instruction output,
652 TrafficSelector outerSelector, TrafficSelector innerSelector) {
653
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000654 //match: in port (nni), s-tag
655 //action: immediate: write metadata, pop vlan, meter and go to table 1
Gamze Abakadadae722018-09-12 10:55:35 +0000656 FlowRule.Builder outer = DefaultFlowRule.builder()
657 .fromApp(fwd.appId())
658 .forDevice(deviceId)
659 .makePermanent()
660 .withPriority(fwd.priority())
661 .withSelector(outerSelector)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000662 .withTreatment(buildTreatment(Instructions.popVlan(), fetchMeter(fwd),
663 fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE)));
Gamze Abakadadae722018-09-12 10:55:35 +0000664
665 //match: in port (nni) and s-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000666 //action: immediate : write metadata, meter and output
Gamze Abakadadae722018-09-12 10:55:35 +0000667 FlowRule.Builder inner = DefaultFlowRule.builder()
668 .fromApp(fwd.appId())
669 .forDevice(deviceId)
670 .forTable(QQ_TABLE)
671 .makePermanent()
672 .withPriority(fwd.priority())
673 .withSelector(innerSelector)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000674 .withTreatment(buildTreatment(fetchMeter(fwd),
675 writeMetadataIncludingOnlyTp(fwd), output));
alshabibfd430b62015-12-16 18:56:38 -0800676
677 applyRules(fwd, inner, outer);
alshabibfd430b62015-12-16 18:56:38 -0800678 }
679
680 private void installUpstreamRules(ForwardingObjective fwd) {
681 List<Pair<Instruction, Instruction>> vlanOps =
682 vlanOps(fwd,
683 L2ModificationInstruction.L2SubType.VLAN_PUSH);
684
Gamze Abakadadae722018-09-12 10:55:35 +0000685 if (vlanOps == null || vlanOps.isEmpty()) {
alshabibfd430b62015-12-16 18:56:38 -0800686 return;
687 }
688
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000689 Instruction output = fetchOutput(fwd, UPSTREAM);
alshabibfd430b62015-12-16 18:56:38 -0800690
691 if (output == null) {
692 return;
693 }
694
alshabibfd430b62015-12-16 18:56:38 -0800695 Pair<Instruction, Instruction> outerPair = vlanOps.remove(0);
696
Gamze Abakadadae722018-09-12 10:55:35 +0000697 boolean noneValueVlanStatus = checkNoneVlanCriteria(fwd);
698 boolean anyValueVlanStatus = checkAnyVlanMatchCriteria(fwd);
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700699
Gamze Abakadadae722018-09-12 10:55:35 +0000700 if (anyValueVlanStatus) {
701 installUpstreamRulesForAnyVlan(fwd, output, outerPair);
702 } else {
Andrea Campanellabee52b92020-01-29 14:41:42 +0100703 Pair<Instruction, Instruction> innerPair = outerPair;
704 outerPair = vlanOps.remove(0);
Gamze Abakadadae722018-09-12 10:55:35 +0000705 installUpstreamRulesForVlans(fwd, output, innerPair, outerPair, noneValueVlanStatus);
706 }
707 }
708
709 private void installUpstreamRulesForVlans(ForwardingObjective fwd, Instruction output,
710 Pair<Instruction, Instruction> innerPair,
711 Pair<Instruction, Instruction> outerPair, Boolean noneValueVlanStatus) {
712
Gamze Abaka61269f82019-12-02 06:42:39 +0000713 List<Instruction> setVlanPcps = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_PCP,
714 fwd.treatment().allInstructions());
715
716 Instruction innerPbitSet = null;
717 Instruction outerPbitSet = null;
718
719 if (setVlanPcps != null && !setVlanPcps.isEmpty()) {
720 innerPbitSet = setVlanPcps.get(0);
721 outerPbitSet = setVlanPcps.get(1);
722 }
723
Gamze Abakadadae722018-09-12 10:55:35 +0000724 TrafficTreatment innerTreatment;
725 if (noneValueVlanStatus) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000726 innerTreatment = buildTreatment(innerPair.getLeft(), innerPair.getRight(), fetchMeter(fwd),
Gamze Abaka61269f82019-12-02 06:42:39 +0000727 fetchWriteMetadata(fwd), innerPbitSet,
728 Instructions.transition(QQ_TABLE));
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700729 } else {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000730 innerTreatment = buildTreatment(innerPair.getRight(), fetchMeter(fwd), fetchWriteMetadata(fwd),
Gamze Abaka61269f82019-12-02 06:42:39 +0000731 innerPbitSet, Instructions.transition(QQ_TABLE));
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700732 }
733
Gamze Abakadadae722018-09-12 10:55:35 +0000734 //match: in port, vlanId (0 or None)
735 //action:
736 //if vlanId None, push & set c-tag go to table 1
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000737 //if vlanId 0 or any specific vlan, set c-tag, write metadata, meter and go to table 1
alshabibfd430b62015-12-16 18:56:38 -0800738 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700739 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800740 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800741 .makePermanent()
742 .withPriority(fwd.priority())
743 .withSelector(fwd.selector())
Gamze Abakadadae722018-09-12 10:55:35 +0000744 .withTreatment(innerTreatment);
alshabibfd430b62015-12-16 18:56:38 -0800745
746 PortCriterion inPort = (PortCriterion)
747 fwd.selector().getCriterion(Criterion.Type.IN_PORT);
748
749 VlanId cVlanId = ((L2ModificationInstruction.ModVlanIdInstruction)
750 innerPair.getRight()).vlanId();
751
Gamze Abakadadae722018-09-12 10:55:35 +0000752 //match: in port, c-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000753 //action: immediate: push s-tag, write metadata, meter and output
alshabibfd430b62015-12-16 18:56:38 -0800754 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700755 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800756 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800757 .forTable(QQ_TABLE)
758 .makePermanent()
759 .withPriority(fwd.priority())
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000760 .withTreatment(buildTreatment(outerPair.getLeft(), outerPair.getRight(),
Gamze Abaka61269f82019-12-02 06:42:39 +0000761 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd),
762 outerPbitSet, output));
763
764 if (innerPbitSet != null) {
765 byte innerPbit = ((L2ModificationInstruction.ModVlanPcpInstruction)
766 innerPbitSet).vlanPcp();
767 outer.withSelector(buildSelector(inPort, Criteria.matchVlanId(cVlanId), Criteria.matchVlanPcp(innerPbit)));
768 } else {
769 outer.withSelector(buildSelector(inPort, Criteria.matchVlanId(cVlanId)));
770 }
alshabibfd430b62015-12-16 18:56:38 -0800771
772 applyRules(fwd, inner, outer);
Gamze Abakadadae722018-09-12 10:55:35 +0000773 }
alshabibfd430b62015-12-16 18:56:38 -0800774
Gamze Abakadadae722018-09-12 10:55:35 +0000775 private void installUpstreamRulesForAnyVlan(ForwardingObjective fwd, Instruction output,
776 Pair<Instruction, Instruction> outerPair) {
777
778 log.debug("Installing upstream rules for any value vlan");
779
780 //match: in port and any-vlan (coming from OLT app.)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000781 //action: write metadata, go to table 1 and meter
Gamze Abakadadae722018-09-12 10:55:35 +0000782 FlowRule.Builder inner = DefaultFlowRule.builder()
783 .fromApp(fwd.appId())
784 .forDevice(deviceId)
785 .makePermanent()
786 .withPriority(fwd.priority())
787 .withSelector(fwd.selector())
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000788 .withTreatment(buildTreatment(Instructions.transition(QQ_TABLE), fetchMeter(fwd),
789 fetchWriteMetadata(fwd)));
Gamze Abakadadae722018-09-12 10:55:35 +0000790
Gamze Abakadadae722018-09-12 10:55:35 +0000791 //match: in port and any-vlan (coming from OLT app.)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000792 //action: immediate: push:QinQ, vlanId (s-tag), write metadata, meter and output
Gamze Abakadadae722018-09-12 10:55:35 +0000793 FlowRule.Builder outer = DefaultFlowRule.builder()
794 .fromApp(fwd.appId())
795 .forDevice(deviceId)
796 .forTable(QQ_TABLE)
797 .makePermanent()
798 .withPriority(fwd.priority())
799 .withSelector(fwd.selector())
Andrea Campanellabee52b92020-01-29 14:41:42 +0100800 .withTreatment(buildTreatment(outerPair.getLeft(), outerPair.getRight(),
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000801 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000802
Andrea Campanellabee52b92020-01-29 14:41:42 +0100803 applyRules(fwd, inner, outer);
Gamze Abakadadae722018-09-12 10:55:35 +0000804 }
805
806 private boolean checkNoneVlanCriteria(ForwardingObjective fwd) {
807 // Add the VLAN_PUSH treatment if we're matching on VlanId.NONE
808 Criterion vlanMatchCriterion = filterForCriterion(fwd.selector().criteria(), Criterion.Type.VLAN_VID);
809 boolean noneValueVlanStatus = false;
810 if (vlanMatchCriterion != null) {
811 noneValueVlanStatus = ((VlanIdCriterion) vlanMatchCriterion).vlanId().equals(VlanId.NONE);
812 }
813 return noneValueVlanStatus;
814 }
815
816 private boolean checkAnyVlanMatchCriteria(ForwardingObjective fwd) {
817 Criterion anyValueVlanCriterion = fwd.selector().criteria().stream()
818 .filter(c -> c.type().equals(Criterion.Type.VLAN_VID))
819 .filter(vc -> ((VlanIdCriterion) vc).vlanId().toShort() == VlanId.ANY_VALUE)
820 .findAny().orElse(null);
821
822 if (anyValueVlanCriterion == null) {
Andrea Campanellabee52b92020-01-29 14:41:42 +0100823 log.debug("Any value vlan match criteria is not found, criteria {}",
824 fwd.selector().criteria());
Gamze Abakadadae722018-09-12 10:55:35 +0000825 return false;
826 }
827
828 return true;
alshabibfd430b62015-12-16 18:56:38 -0800829 }
830
831 private Instruction fetchOutput(ForwardingObjective fwd, String direction) {
832 Instruction output = fwd.treatment().allInstructions().stream()
833 .filter(i -> i.type() == Instruction.Type.OUTPUT)
834 .findFirst().orElse(null);
835
836 if (output == null) {
837 log.error("OLT {} rule has no output", direction);
838 fail(fwd, ObjectiveError.BADPARAMS);
839 return null;
840 }
841 return output;
842 }
843
Gamze Abakadadae722018-09-12 10:55:35 +0000844 private Instruction fetchMeter(ForwardingObjective fwd) {
845 Instruction meter = fwd.treatment().metered();
846
847 if (meter == null) {
848 log.debug("Meter instruction is not found for the forwarding objective {}", fwd);
849 return null;
850 }
851
852 log.debug("Meter instruction is found.");
853 return meter;
854 }
855
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000856 private Instructions.MetadataInstruction fetchWriteMetadata(ForwardingObjective fwd) {
857 Instructions.MetadataInstruction writeMetadata = fwd.treatment().writeMetadata();
Gamze Abakadadae722018-09-12 10:55:35 +0000858
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000859 if (writeMetadata == null) {
860 log.warn("Write metadata is not found for the forwarding obj");
861 fail(fwd, ObjectiveError.BADPARAMS);
Gamze Abakadadae722018-09-12 10:55:35 +0000862 return null;
863 }
864
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000865 log.debug("Write metadata is found {}", writeMetadata);
866 return writeMetadata;
Gamze Abakadadae722018-09-12 10:55:35 +0000867 }
868
alshabibfd430b62015-12-16 18:56:38 -0800869 private List<Pair<Instruction, Instruction>> vlanOps(ForwardingObjective fwd,
870 L2ModificationInstruction.L2SubType type) {
871
872 List<Pair<Instruction, Instruction>> vlanOps = findVlanOps(
873 fwd.treatment().allInstructions(), type);
874
Gamze Abakadadae722018-09-12 10:55:35 +0000875 if (vlanOps == null || vlanOps.isEmpty()) {
alshabibfd430b62015-12-16 18:56:38 -0800876 String direction = type == L2ModificationInstruction.L2SubType.VLAN_POP
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000877 ? DOWNSTREAM : UPSTREAM;
alshabibfd430b62015-12-16 18:56:38 -0800878 log.error("Missing vlan operations in {} forwarding: {}", direction, fwd);
879 fail(fwd, ObjectiveError.BADPARAMS);
Gamze Abakadadae722018-09-12 10:55:35 +0000880 return ImmutableList.of();
alshabibfd430b62015-12-16 18:56:38 -0800881 }
882 return vlanOps;
883 }
884
885
886 private List<Pair<Instruction, Instruction>> findVlanOps(List<Instruction> instructions,
alshabibd61b77b2016-02-01 23:30:53 -0800887 L2ModificationInstruction.L2SubType type) {
alshabibfd430b62015-12-16 18:56:38 -0800888
Gamze Abaka61269f82019-12-02 06:42:39 +0000889 List<Instruction> vlanOperations = findL2Instructions(
alshabibfd430b62015-12-16 18:56:38 -0800890 type,
891 instructions);
892 List<Instruction> vlanSets = findL2Instructions(
893 L2ModificationInstruction.L2SubType.VLAN_ID,
894 instructions);
895
Gamze Abaka61269f82019-12-02 06:42:39 +0000896 if (vlanOperations.size() != vlanSets.size()) {
Gamze Abakadadae722018-09-12 10:55:35 +0000897 return ImmutableList.of();
alshabibfd430b62015-12-16 18:56:38 -0800898 }
899
900 List<Pair<Instruction, Instruction>> pairs = Lists.newArrayList();
901
Gamze Abaka61269f82019-12-02 06:42:39 +0000902 for (int i = 0; i < vlanOperations.size(); i++) {
903 pairs.add(new ImmutablePair<>(vlanOperations.get(i), vlanSets.get(i)));
alshabibfd430b62015-12-16 18:56:38 -0800904 }
905 return pairs;
906 }
907
908 private List<Instruction> findL2Instructions(L2ModificationInstruction.L2SubType subType,
909 List<Instruction> actions) {
910 return actions.stream()
911 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
912 .filter(i -> ((L2ModificationInstruction) i).subtype() == subType)
913 .collect(Collectors.toList());
914 }
915
Amit Ghoshf1f22752018-08-14 07:28:01 +0100916 private void provisionEthTypeBasedFilter(FilteringObjective filter,
917 EthTypeCriterion ethType,
Andrea Campanellabefc2942020-06-11 16:09:39 +0200918 Instructions.OutputInstruction output,
919 L2ModificationInstruction vlanId,
920 L2ModificationInstruction vlanPush) {
alshabibfd430b62015-12-16 18:56:38 -0800921
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000922 Instruction meter = filter.meta().metered();
923 Instruction writeMetadata = filter.meta().writeMetadata();
924
Andrea Campanellabefc2942020-06-11 16:09:39 +0200925 TrafficSelector selector = buildSelector(filter.key(), ethType);
926 TrafficTreatment treatment;
Gamze Abakaf57ef602019-03-11 06:52:48 +0000927
Andrea Campanellabefc2942020-06-11 16:09:39 +0200928 if (vlanPush == null || vlanId == null) {
929 treatment = buildTreatment(output, meter, writeMetadata);
930 } else {
931 // we need to push the vlan because it came untagged (ATT)
932 treatment = buildTreatment(output, meter, vlanPush, vlanId, writeMetadata);
933 }
934
alshabibfd430b62015-12-16 18:56:38 -0800935 buildAndApplyRule(filter, selector, treatment);
936
937 }
938
Jonathan Hart51539b82015-10-29 09:53:04 -0700939 private void provisionIgmp(FilteringObjective filter, EthTypeCriterion ethType,
alshabibfd430b62015-12-16 18:56:38 -0800940 IPProtocolCriterion ipProto,
Andrea Campanellabefc2942020-06-11 16:09:39 +0200941 Instructions.OutputInstruction output,
Andrea Campanella0956dba2020-09-21 14:34:00 +0200942 Instruction vlan, Instruction pcp) {
Gamze Abaka7c070c82019-02-21 14:40:18 +0000943
944 Instruction meter = filter.meta().metered();
945 Instruction writeMetadata = filter.meta().writeMetadata();
946
Andrea Campanellabefc2942020-06-11 16:09:39 +0200947 // uniTagMatch
Gamze Abaka61269f82019-12-02 06:42:39 +0000948 VlanIdCriterion vlanId = (VlanIdCriterion) filterForCriterion(filter.conditions(),
949 Criterion.Type.VLAN_VID);
Gamze Abaka61269f82019-12-02 06:42:39 +0000950
Andrea Campanellabefc2942020-06-11 16:09:39 +0200951 TrafficSelector selector = buildSelector(filter.key(), ethType, ipProto, vlanId);
952 TrafficTreatment treatment = buildTreatment(output, vlan, pcp, meter, writeMetadata);
alshabibfd430b62015-12-16 18:56:38 -0800953 buildAndApplyRule(filter, selector, treatment);
954 }
955
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000956 private void provisionDhcp(FilteringObjective filter, EthTypeCriterion ethType,
957 IPProtocolCriterion ipProto,
958 UdpPortCriterion udpSrcPort,
959 UdpPortCriterion udpDstPort,
Andrea Campanellabefc2942020-06-11 16:09:39 +0200960 Instruction vlanIdInstruction,
961 Instruction vlanPcpInstruction,
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000962 Instructions.OutputInstruction output) {
Gamze Abaka7c070c82019-02-21 14:40:18 +0000963
964 Instruction meter = filter.meta().metered();
965 Instruction writeMetadata = filter.meta().writeMetadata();
966
Andrea Campanellabefc2942020-06-11 16:09:39 +0200967 VlanIdCriterion matchVlanId = (VlanIdCriterion)
Gamze Abaka61269f82019-12-02 06:42:39 +0000968 filterForCriterion(filter.conditions(), Criterion.Type.VLAN_VID);
969
Andrea Campanellabefc2942020-06-11 16:09:39 +0200970 TrafficSelector selector;
971 TrafficTreatment treatment;
972
973 if (matchVlanId != null) {
974 log.debug("Building selector with match VLAN, {}", matchVlanId);
975 // in case of TT upstream the packet comes tagged and the vlan is swapped.
976 selector = buildSelector(filter.key(), ethType, ipProto, udpSrcPort,
977 udpDstPort, matchVlanId);
978 treatment = buildTreatment(output, meter, writeMetadata,
979 vlanIdInstruction, vlanPcpInstruction);
980 } else {
981 log.debug("Building selector with no VLAN");
982 // in case of ATT upstream the packet comes in untagged and we need to push the vlan
983 selector = buildSelector(filter.key(), ethType, ipProto, udpSrcPort, udpDstPort);
984 treatment = buildTreatment(output, meter, vlanIdInstruction, writeMetadata);
985 }
986 //In case of downstream there will be no match on the VLAN, which is null,
987 // so it will just be output, meter, writeMetadata
988
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000989 buildAndApplyRule(filter, selector, treatment);
990 }
Gamze Abakadadae722018-09-12 10:55:35 +0000991
alshabibfd430b62015-12-16 18:56:38 -0800992 private void buildAndApplyRule(FilteringObjective filter, TrafficSelector selector,
993 TrafficTreatment treatment) {
994 FlowRule rule = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700995 .fromApp(filter.appId())
alshabibfd430b62015-12-16 18:56:38 -0800996 .forDevice(deviceId)
997 .forTable(0)
alshabibfd430b62015-12-16 18:56:38 -0800998 .makePermanent()
999 .withSelector(selector)
1000 .withTreatment(treatment)
alshabibbb424232016-01-15 12:20:25 -08001001 .withPriority(filter.priority())
alshabibfd430b62015-12-16 18:56:38 -08001002 .build();
1003
1004 FlowRuleOperations.Builder opsBuilder = FlowRuleOperations.builder();
1005
1006 switch (filter.type()) {
1007 case PERMIT:
1008 opsBuilder.add(rule);
1009 break;
1010 case DENY:
1011 opsBuilder.remove(rule);
1012 break;
1013 default:
1014 log.warn("Unknown filter type : {}", filter.type());
1015 fail(filter, ObjectiveError.UNSUPPORTED);
1016 }
1017
1018 applyFlowRules(opsBuilder, filter);
1019 }
1020
Gamze Abakadadae722018-09-12 10:55:35 +00001021 private void applyRules(ForwardingObjective fwd, FlowRule.Builder... fwdBuilders) {
Amit Ghoshf1f22752018-08-14 07:28:01 +01001022 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
1023 switch (fwd.op()) {
1024 case ADD:
Gamze Abakadadae722018-09-12 10:55:35 +00001025 for (FlowRule.Builder fwdBuilder : fwdBuilders) {
1026 builder.add(fwdBuilder.build());
1027 }
Amit Ghoshf1f22752018-08-14 07:28:01 +01001028 break;
1029 case REMOVE:
Gamze Abakadadae722018-09-12 10:55:35 +00001030 for (FlowRule.Builder fwdBuilder : fwdBuilders) {
1031 builder.remove(fwdBuilder.build());
1032 }
alshabibfd430b62015-12-16 18:56:38 -08001033 break;
1034 case ADD_TO_EXISTING:
1035 break;
1036 case REMOVE_FROM_EXISTING:
1037 break;
1038 default:
1039 log.warn("Unknown forwarding operation: {}", fwd.op());
1040 }
1041
1042 applyFlowRules(builder, fwd);
1043 }
1044
1045 private void applyFlowRules(FlowRuleOperations.Builder builder,
1046 Objective objective) {
1047 flowRuleService.apply(builder.build(new FlowRuleOperationsContext() {
1048 @Override
1049 public void onSuccess(FlowRuleOperations ops) {
1050 pass(objective);
1051 }
1052
1053 @Override
1054 public void onError(FlowRuleOperations ops) {
1055 fail(objective, ObjectiveError.FLOWINSTALLATIONFAILED);
1056 }
1057 }));
1058 }
1059
1060 private Criterion filterForCriterion(Collection<Criterion> criteria, Criterion.Type type) {
1061 return criteria.stream()
alshabibbb424232016-01-15 12:20:25 -08001062 .filter(c -> c.type().equals(type))
alshabibfd430b62015-12-16 18:56:38 -08001063 .limit(1)
1064 .findFirst().orElse(null);
1065 }
1066
1067 private TrafficSelector buildSelector(Criterion... criteria) {
1068
alshabibfd430b62015-12-16 18:56:38 -08001069 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
1070
Gamze Abakaf57ef602019-03-11 06:52:48 +00001071 Arrays.stream(criteria).filter(Objects::nonNull).forEach(sBuilder::add);
alshabibfd430b62015-12-16 18:56:38 -08001072
1073 return sBuilder.build();
1074 }
1075
1076 private TrafficTreatment buildTreatment(Instruction... instructions) {
1077
alshabibfd430b62015-12-16 18:56:38 -08001078 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1079
Gamze Abaka6c8a71b2018-12-24 13:17:12 +00001080 Arrays.stream(instructions).filter(Objects::nonNull).forEach(tBuilder::add);
alshabibfd430b62015-12-16 18:56:38 -08001081
1082 return tBuilder.build();
1083 }
1084
Gamze Abaka6c8a71b2018-12-24 13:17:12 +00001085 private Instruction writeMetadataIncludingOnlyTp(ForwardingObjective fwd) {
1086
1087 return Instructions.writeMetadata(
1088 fetchWriteMetadata(fwd).metadata() & 0xFFFF00000000L, 0L);
1089 }
alshabibfd430b62015-12-16 18:56:38 -08001090
1091 private void fail(Objective obj, ObjectiveError error) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -08001092 obj.context().ifPresent(context -> context.onError(obj, error));
alshabibfd430b62015-12-16 18:56:38 -08001093 }
1094
1095 private void pass(Objective obj) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -08001096 obj.context().ifPresent(context -> context.onSuccess(obj));
alshabibfd430b62015-12-16 18:56:38 -08001097 }
1098
alshabib2cc73cb2015-06-30 20:26:56 -07001099
alshabibd61b77b2016-02-01 23:30:53 -08001100 private class InnerGroupListener implements GroupListener {
alshabib2cc73cb2015-06-30 20:26:56 -07001101 @Override
alshabibd61b77b2016-02-01 23:30:53 -08001102 public void event(GroupEvent event) {
Andrea Campanella63b17dc2020-05-06 16:09:10 +02001103 GroupKey key = event.subject().appCookie();
1104 NextObjective obj = pendingGroups.getIfPresent(key);
1105 if (obj == null) {
1106 log.debug("No pending group for {}, moving on", key);
1107 return;
1108 }
1109 log.trace("Event {} for group {}, handling pending" +
1110 "NextGroup {}", event.type(), key, obj.id());
ke hanf5086672016-08-12 11:09:17 +08001111 if (event.type() == GroupEvent.Type.GROUP_ADDED ||
Gamze Abakadadae722018-09-12 10:55:35 +00001112 event.type() == GroupEvent.Type.GROUP_UPDATED) {
alshabibd61b77b2016-02-01 23:30:53 -08001113 flowObjectiveStore.putNextGroup(obj.id(), new OLTPipelineGroup(key));
1114 pass(obj);
1115 pendingGroups.invalidate(key);
Andrea Campanella63b17dc2020-05-06 16:09:10 +02001116 } else if (event.type() == GroupEvent.Type.GROUP_REMOVED) {
1117 flowObjectiveStore.removeNextGroup(obj.id());
1118 pass(obj);
1119 pendingGroups.invalidate(key);
alshabibd61b77b2016-02-01 23:30:53 -08001120 }
alshabib2cc73cb2015-06-30 20:26:56 -07001121 }
1122 }
1123
alshabibd61b77b2016-02-01 23:30:53 -08001124 private static class OLTPipelineGroup implements NextGroup {
1125
1126 private final GroupKey key;
1127
1128 public OLTPipelineGroup(GroupKey key) {
1129 this.key = key;
1130 }
1131
1132 public GroupKey key() {
1133 return key;
1134 }
1135
1136 @Override
1137 public byte[] data() {
1138 return appKryo.serialize(key);
1139 }
1140
1141 }
Saurav Das24431192016-03-07 19:13:00 -08001142
1143 @Override
1144 public List<String> getNextMappings(NextGroup nextGroup) {
1145 // TODO Implementation deferred to vendor
1146 return null;
1147 }
alshabib0ccde6d2015-05-30 18:22:36 -07001148}