blob: cf5fe14db17b5e65c7687f6e7a680334b6a2dc30 [file] [log] [blame]
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001/*
2 * Copyright 2016-present Open Networking Foundation
3 *
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.opencord.olt.impl;
17
Andrea Campanellacbbb7952019-11-25 06:38:41 +000018import org.onlab.packet.EthType;
19import org.onlab.packet.IPv4;
20import org.onlab.packet.IPv6;
21import org.onlab.packet.MacAddress;
22import org.onlab.packet.TpPort;
23import org.onlab.packet.VlanId;
Ilayda Ozdemir90a93622021-02-25 09:40:58 +000024import org.onlab.util.KryoNamespace;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000025import org.onlab.util.Tools;
26import org.onosproject.cfg.ComponentConfigService;
27import org.onosproject.core.ApplicationId;
28import org.onosproject.core.CoreService;
29import org.onosproject.mastership.MastershipService;
30import org.onosproject.net.AnnotationKeys;
Matteo Scandolo3a037a32020-04-01 12:17:50 -070031import org.onosproject.net.ConnectPoint;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000032import org.onosproject.net.DeviceId;
33import org.onosproject.net.Port;
34import org.onosproject.net.PortNumber;
35import org.onosproject.net.device.DeviceService;
36import org.onosproject.net.flow.DefaultTrafficSelector;
37import org.onosproject.net.flow.DefaultTrafficTreatment;
38import org.onosproject.net.flow.TrafficSelector;
39import org.onosproject.net.flow.TrafficTreatment;
40import org.onosproject.net.flow.criteria.Criteria;
41import org.onosproject.net.flowobjective.DefaultFilteringObjective;
42import org.onosproject.net.flowobjective.DefaultForwardingObjective;
43import org.onosproject.net.flowobjective.FilteringObjective;
44import org.onosproject.net.flowobjective.FlowObjectiveService;
45import org.onosproject.net.flowobjective.ForwardingObjective;
46import org.onosproject.net.flowobjective.Objective;
47import org.onosproject.net.flowobjective.ObjectiveContext;
48import org.onosproject.net.flowobjective.ObjectiveError;
49import org.onosproject.net.meter.MeterId;
Ilayda Ozdemir90a93622021-02-25 09:40:58 +000050import org.onosproject.store.serializers.KryoNamespaces;
51import org.onosproject.store.service.Serializer;
52import org.onosproject.store.service.StorageService;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000053import org.opencord.olt.internalapi.AccessDeviceFlowService;
54import org.opencord.olt.internalapi.AccessDeviceMeterService;
55import org.opencord.sadis.BandwidthProfileInformation;
56import org.opencord.sadis.BaseInformationService;
57import org.opencord.sadis.SadisService;
58import org.opencord.sadis.SubscriberAndDeviceInformation;
59import org.opencord.sadis.UniTagInformation;
60import org.osgi.service.component.ComponentContext;
61import org.osgi.service.component.annotations.Activate;
62import org.osgi.service.component.annotations.Component;
63import org.osgi.service.component.annotations.Deactivate;
64import org.osgi.service.component.annotations.Modified;
65import org.osgi.service.component.annotations.Reference;
66import org.osgi.service.component.annotations.ReferenceCardinality;
Ilayda Ozdemir90a93622021-02-25 09:40:58 +000067import org.osgi.service.component.annotations.ReferencePolicy;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000068import org.slf4j.Logger;
69
Andrea Campanella7a1d7e72020-11-05 10:40:10 +010070import java.util.Dictionary;
Ilayda Ozdemir90a93622021-02-25 09:40:58 +000071import java.util.Map;
Andrea Campanella7a1d7e72020-11-05 10:40:10 +010072import java.util.Properties;
73import java.util.concurrent.BlockingQueue;
74import java.util.concurrent.CompletableFuture;
Andrea Campanella7a1d7e72020-11-05 10:40:10 +010075import java.util.concurrent.LinkedBlockingQueue;
76
77import static com.google.common.base.Strings.isNullOrEmpty;
78import static org.onlab.util.Tools.get;
79import static org.opencord.olt.impl.OsgiPropertyConstants.*;
80import static org.slf4j.LoggerFactory.getLogger;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000081
82/**
83 * Provisions flow rules on access devices.
84 */
85@Component(immediate = true, property = {
Saurav Dasf62cea82020-08-26 17:43:04 -070086 ENABLE_DHCP_ON_NNI + ":Boolean=" + ENABLE_DHCP_ON_NNI_DEFAULT,
Andrea Campanellacbbb7952019-11-25 06:38:41 +000087 ENABLE_DHCP_V4 + ":Boolean=" + ENABLE_DHCP_V4_DEFAULT,
88 ENABLE_DHCP_V6 + ":Boolean=" + ENABLE_DHCP_V6_DEFAULT,
Saurav Dasf62cea82020-08-26 17:43:04 -070089 ENABLE_IGMP_ON_NNI + ":Boolean=" + ENABLE_IGMP_ON_NNI_DEFAULT,
Andrea Campanellacbbb7952019-11-25 06:38:41 +000090 ENABLE_EAPOL + ":Boolean=" + ENABLE_EAPOL_DEFAULT,
Gustavo Silva5c492dd2021-02-12 10:21:11 -030091 ENABLE_PPPOE + ":Boolean=" + ENABLE_PPPOE_DEFAULT,
Andrea Campanellacbbb7952019-11-25 06:38:41 +000092 DEFAULT_TP_ID + ":Integer=" + DEFAULT_TP_ID_DEFAULT
93})
94public class OltFlowService implements AccessDeviceFlowService {
Ilayda Ozdemir90a93622021-02-25 09:40:58 +000095 private static final String SADIS_NOT_RUNNING = "Sadis is not running.";
Andrea Campanellacbbb7952019-11-25 06:38:41 +000096 private static final String APP_NAME = "org.opencord.olt";
97 private static final int NONE_TP_ID = -1;
98 private static final int NO_PCP = -1;
99 private static final Integer MAX_PRIORITY = 10000;
100 private static final Integer MIN_PRIORITY = 1000;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000101 private static final String INSTALLED = "installed";
102 private static final String REMOVED = "removed";
103 private static final String INSTALLATION = "installation";
104 private static final String REMOVAL = "removal";
105 private static final String V4 = "V4";
106 private static final String V6 = "V6";
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000107
108 private final Logger log = getLogger(getClass());
109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY)
111 protected FlowObjectiveService flowObjectiveService;
112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY)
114 protected CoreService coreService;
115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY)
117 protected MastershipService mastershipService;
118
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000119 @Reference(cardinality = ReferenceCardinality.OPTIONAL,
120 bind = "bindSadisService",
121 unbind = "unbindSadisService",
122 policy = ReferencePolicy.DYNAMIC)
123 protected volatile SadisService sadisService;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000124
125 @Reference(cardinality = ReferenceCardinality.MANDATORY)
126 protected DeviceService deviceService;
127
128 @Reference(cardinality = ReferenceCardinality.MANDATORY)
129 protected AccessDeviceMeterService oltMeterService;
130
131 @Reference(cardinality = ReferenceCardinality.MANDATORY)
132 protected ComponentConfigService componentConfigService;
133
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000134 @Reference(cardinality = ReferenceCardinality.MANDATORY)
135 protected StorageService storageService;
136
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000137 /**
Saurav Dasf62cea82020-08-26 17:43:04 -0700138 * Create DHCP trap flow on NNI port(s).
139 */
140 protected boolean enableDhcpOnNni = ENABLE_DHCP_ON_NNI_DEFAULT;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000141
142 /**
Saurav Dasf62cea82020-08-26 17:43:04 -0700143 * Enable flows for DHCP v4 if dhcp is required in sadis config.
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000144 **/
145 protected boolean enableDhcpV4 = ENABLE_DHCP_V4_DEFAULT;
146
147 /**
Saurav Dasf62cea82020-08-26 17:43:04 -0700148 * Enable flows for DHCP v6 if dhcp is required in sadis config.
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000149 **/
150 protected boolean enableDhcpV6 = ENABLE_DHCP_V6_DEFAULT;
151
152 /**
Saurav Dasf62cea82020-08-26 17:43:04 -0700153 * Create IGMP trap flow on NNI port(s).
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000154 **/
Saurav Dasf62cea82020-08-26 17:43:04 -0700155 protected boolean enableIgmpOnNni = ENABLE_IGMP_ON_NNI_DEFAULT;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000156
157 /**
158 * Send EAPOL authentication trap flows before subscriber provisioning.
159 **/
160 protected boolean enableEapol = ENABLE_EAPOL_DEFAULT;
161
162 /**
Gustavo Silva5c492dd2021-02-12 10:21:11 -0300163 * Send PPPoED authentication trap flows before subscriber provisioning.
164 **/
165 protected boolean enablePppoe = ENABLE_PPPOE_DEFAULT;
166
167 /**
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000168 * Default technology profile id that is used for authentication trap flows.
169 **/
170 protected int defaultTechProfileId = DEFAULT_TP_ID_DEFAULT;
171
172 protected ApplicationId appId;
173 protected BaseInformationService<BandwidthProfileInformation> bpService;
174 protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000175 protected Map<DeviceId, BlockingQueue<SubscriberFlowInfo>> pendingEapolForDevice;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000176
177 @Activate
178 public void activate(ComponentContext context) {
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000179 if (sadisService != null) {
180 bpService = sadisService.getBandwidthProfileService();
181 subsService = sadisService.getSubscriberInfoService();
182 } else {
183 log.warn(SADIS_NOT_RUNNING);
184 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000185 componentConfigService.registerProperties(getClass());
186 appId = coreService.getAppId(APP_NAME);
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000187 KryoNamespace serializer = KryoNamespace.newBuilder()
188 .register(KryoNamespaces.API)
189 .register(UniTagInformation.class)
190 .register(SubscriberFlowInfo.class)
191 .register(LinkedBlockingQueue.class)
192 .build();
193 pendingEapolForDevice = storageService.<DeviceId, BlockingQueue<SubscriberFlowInfo>>consistentMapBuilder()
194 .withName("volt-pending-eapol")
195 .withSerializer(Serializer.using(serializer))
196 .withApplicationId(appId)
197 .build().asJavaMap();
Andrea Campanellafee86422020-06-04 16:01:27 +0200198 log.info("started");
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000199 }
200
201
202 @Deactivate
203 public void deactivate(ComponentContext context) {
204 componentConfigService.unregisterProperties(getClass(), false);
Andrea Campanellafee86422020-06-04 16:01:27 +0200205 log.info("stopped");
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000206 }
207
208 @Modified
209 public void modified(ComponentContext context) {
210
211 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
212
Saurav Dasf62cea82020-08-26 17:43:04 -0700213 Boolean o = Tools.isPropertyEnabled(properties, ENABLE_DHCP_ON_NNI);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000214 if (o != null) {
Saurav Dasf62cea82020-08-26 17:43:04 -0700215 enableDhcpOnNni = o;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000216 }
217
Andrea Campanella7c49b792020-05-11 11:36:53 +0200218 Boolean v4 = Tools.isPropertyEnabled(properties, ENABLE_DHCP_V4);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000219 if (v4 != null) {
220 enableDhcpV4 = v4;
221 }
222
Andrea Campanella7c49b792020-05-11 11:36:53 +0200223 Boolean v6 = Tools.isPropertyEnabled(properties, ENABLE_DHCP_V6);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000224 if (v6 != null) {
225 enableDhcpV6 = v6;
226 }
227
Saurav Dasf62cea82020-08-26 17:43:04 -0700228 Boolean p = Tools.isPropertyEnabled(properties, ENABLE_IGMP_ON_NNI);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000229 if (p != null) {
Saurav Dasf62cea82020-08-26 17:43:04 -0700230 enableIgmpOnNni = p;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000231 }
232
Andrea Campanella7c49b792020-05-11 11:36:53 +0200233 Boolean eap = Tools.isPropertyEnabled(properties, ENABLE_EAPOL);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000234 if (eap != null) {
235 enableEapol = eap;
236 }
237
Gustavo Silva5c492dd2021-02-12 10:21:11 -0300238 Boolean pppoe = Tools.isPropertyEnabled(properties, ENABLE_PPPOE);
239 if (pppoe != null) {
240 enablePppoe = pppoe;
241 }
242
Andrea Campanella7c49b792020-05-11 11:36:53 +0200243 String tpId = get(properties, DEFAULT_TP_ID);
244 defaultTechProfileId = isNullOrEmpty(tpId) ? DEFAULT_TP_ID_DEFAULT : Integer.parseInt(tpId.trim());
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000245
Saurav Dasf62cea82020-08-26 17:43:04 -0700246 log.info("modified. Values = enableDhcpOnNni: {}, enableDhcpV4: {}, " +
247 "enableDhcpV6:{}, enableIgmpOnNni:{}, " +
Gustavo Silva5c492dd2021-02-12 10:21:11 -0300248 "enableEapol{}, enablePppoe{}, defaultTechProfileId: {}",
Saurav Dasf62cea82020-08-26 17:43:04 -0700249 enableDhcpOnNni, enableDhcpV4, enableDhcpV6,
Gustavo Silva5c492dd2021-02-12 10:21:11 -0300250 enableIgmpOnNni, enableEapol, enablePppoe,
251 defaultTechProfileId);
Andrea Campanellafee86422020-06-04 16:01:27 +0200252
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000253 }
254
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000255 protected void bindSadisService(SadisService service) {
256 sadisService = service;
257 bpService = sadisService.getBandwidthProfileService();
258 subsService = sadisService.getSubscriberInfoService();
259 log.info("Sadis-service binds to onos.");
260 }
261
262 protected void unbindSadisService(SadisService service) {
263 sadisService = null;
264 bpService = null;
265 subsService = null;
266 log.info("Sadis-service unbinds from onos.");
267 }
268
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000269 @Override
270 public void processDhcpFilteringObjectives(DeviceId devId, PortNumber port,
271 MeterId upstreamMeterId,
272 UniTagInformation tagInformation,
273 boolean install,
274 boolean upstream) {
Saurav Dasf62cea82020-08-26 17:43:04 -0700275 if (upstream) {
276 // for UNI ports
277 if (tagInformation != null && !tagInformation.getIsDhcpRequired()) {
278 log.debug("Dhcp provisioning is disabled for UNI port {} on "
279 + "device {} for service {}", port, devId,
280 tagInformation.getServiceName());
281 return;
282 }
283 } else {
284 // for NNI ports
285 if (!enableDhcpOnNni) {
286 log.debug("Dhcp provisioning is disabled for NNI port {} on "
287 + "device {}", port, devId);
288 return;
289 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000290 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000291 int techProfileId = tagInformation != null ? tagInformation.getTechnologyProfileId() : NONE_TP_ID;
292 VlanId cTag = tagInformation != null ? tagInformation.getPonCTag() : VlanId.NONE;
293 VlanId unitagMatch = tagInformation != null ? tagInformation.getUniTagMatch() : VlanId.ANY;
Andrea Campanella3a96ce82021-02-09 12:32:42 +0100294 Byte vlanPcp = tagInformation != null && tagInformation.getUsPonCTagPriority() != NO_PCP
295 ? (byte) tagInformation.getUsPonCTagPriority() : null;
Andrea Campanella0e34f562020-06-11 10:47:10 +0200296
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000297
298 if (enableDhcpV4) {
299 int udpSrc = (upstream) ? 68 : 67;
300 int udpDst = (upstream) ? 67 : 68;
301
302 EthType ethType = EthType.EtherType.IPV4.ethType();
303 byte protocol = IPv4.PROTOCOL_UDP;
304
Andrea Campanella7c49b792020-05-11 11:36:53 +0200305 addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType,
Andrea Campanella0e34f562020-06-11 10:47:10 +0200306 upstreamMeterId, techProfileId, protocol, cTag, unitagMatch,
307 vlanPcp, upstream, install);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000308 }
309
310 if (enableDhcpV6) {
311 int udpSrc = (upstream) ? 547 : 546;
312 int udpDst = (upstream) ? 546 : 547;
313
314 EthType ethType = EthType.EtherType.IPV6.ethType();
315 byte protocol = IPv6.PROTOCOL_UDP;
316
Andrea Campanella7c49b792020-05-11 11:36:53 +0200317 addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType,
Andrea Campanella0e34f562020-06-11 10:47:10 +0200318 upstreamMeterId, techProfileId, protocol, cTag, unitagMatch,
319 vlanPcp, upstream, install);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000320 }
321 }
322
323 private void addDhcpFilteringObjectives(DeviceId devId, PortNumber port, int udpSrc, int udpDst,
324 EthType ethType, MeterId upstreamMeterId, int techProfileId, byte protocol,
Andrea Campanella0e34f562020-06-11 10:47:10 +0200325 VlanId cTag, VlanId unitagMatch,
326 Byte vlanPcp, boolean upstream,
327 boolean install) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000328
329 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
330 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
331
332 if (upstreamMeterId != null) {
333 treatmentBuilder.meter(upstreamMeterId);
334 }
335
336 if (techProfileId != NONE_TP_ID) {
337 treatmentBuilder.writeMetadata(createTechProfValueForWm(unitagMatch, techProfileId), 0);
338 }
339
340 FilteringObjective.Builder dhcpUpstreamBuilder = (install ? builder.permit() : builder.deny())
341 .withKey(Criteria.matchInPort(port))
342 .addCondition(Criteria.matchEthType(ethType))
343 .addCondition(Criteria.matchIPProtocol(protocol))
344 .addCondition(Criteria.matchUdpSrc(TpPort.tpPort(udpSrc)))
345 .addCondition(Criteria.matchUdpDst(TpPort.tpPort(udpDst)))
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000346 .fromApp(appId)
347 .withPriority(MAX_PRIORITY);
348
Andrea Campanella0e34f562020-06-11 10:47:10 +0200349 //VLAN changes and PCP matching need to happen only in the upstream directions
350 if (upstream) {
351 treatmentBuilder.setVlanId(cTag);
352 if (!VlanId.vlanId(VlanId.NO_VID).equals(unitagMatch)) {
353 dhcpUpstreamBuilder.addCondition(Criteria.matchVlanId(unitagMatch));
354 }
355 if (vlanPcp != null) {
356 treatmentBuilder.setVlanPcp(vlanPcp);
357 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000358 }
359
Andrea Campanella0e34f562020-06-11 10:47:10 +0200360 dhcpUpstreamBuilder.withMeta(treatmentBuilder
361 .setOutput(PortNumber.CONTROLLER).build());
362
363
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000364 FilteringObjective dhcpUpstream = dhcpUpstreamBuilder.add(new ObjectiveContext() {
365 @Override
366 public void onSuccess(Objective objective) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700367 log.info("DHCP {} filter for dev/port {}/{} {}.",
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000368 (ethType.equals(EthType.EtherType.IPV4.ethType())) ? V4 : V6,
369 devId, port, (install) ? INSTALLED : REMOVED);
370 }
371
372 @Override
373 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700374 log.error("DHCP {} filter for dev/port {}/{} failed {} because {}",
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000375 (ethType.equals(EthType.EtherType.IPV4.ethType())) ? V4 : V6,
376 devId, port, (install) ? INSTALLATION : REMOVAL,
377 error);
378 }
379 });
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000380 flowObjectiveService.filter(devId, dhcpUpstream);
381
382 }
383
384 @Override
Gustavo Silva5c492dd2021-02-12 10:21:11 -0300385 public void processPPPoEDFilteringObjectives(DeviceId devId, PortNumber portNumber,
386 MeterId upstreamMeterId,
387 UniTagInformation tagInformation,
388 boolean install,
389 boolean upstream) {
390 if (!enablePppoe) {
391 log.debug("PPPoED filtering is disabled. Ignoring request.");
392 return;
393 }
394
395 int techProfileId = NONE_TP_ID;
396 VlanId cTag = VlanId.NONE;
397 VlanId unitagMatch = VlanId.ANY;
398 Byte vlanPcp = null;
399
400 if (tagInformation != null) {
401 techProfileId = tagInformation.getTechnologyProfileId();
402 cTag = tagInformation.getPonCTag();
403 unitagMatch = tagInformation.getUniTagMatch();
404 if (tagInformation.getUsPonCTagPriority() != NO_PCP) {
405 vlanPcp = (byte) tagInformation.getUsPonCTagPriority();
406 }
407 }
408
409 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
410 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
411 CompletableFuture<Object> meterFuture = new CompletableFuture<>();
412
413 if (upstreamMeterId != null) {
414 treatmentBuilder.meter(upstreamMeterId);
415 }
416
417 if (techProfileId != NONE_TP_ID) {
418 treatmentBuilder.writeMetadata(createTechProfValueForWm(cTag, techProfileId), 0);
419 }
420
421 DefaultFilteringObjective.Builder pppoedBuilder = (install ? builder.permit() : builder.deny())
422 .withKey(Criteria.matchInPort(portNumber))
423 .addCondition(Criteria.matchEthType(EthType.EtherType.PPPoED.ethType()))
424 .fromApp(appId)
425 .withPriority(10000);
426
427 if (upstream) {
428 treatmentBuilder.setVlanId(cTag);
429 if (!VlanId.vlanId(VlanId.NO_VID).equals(unitagMatch)) {
430 pppoedBuilder.addCondition(Criteria.matchVlanId(unitagMatch));
431 }
432 if (vlanPcp != null) {
433 treatmentBuilder.setVlanPcp(vlanPcp);
434 }
435 }
436 pppoedBuilder = pppoedBuilder.withMeta(treatmentBuilder.setOutput(PortNumber.CONTROLLER).build());
437
438 FilteringObjective pppoed = pppoedBuilder
439 .add(new ObjectiveContext() {
440 @Override
441 public void onSuccess(Objective objective) {
442 log.info("PPPoED filter for {} on {} {}.",
443 devId, portNumber, (install) ? INSTALLED : REMOVED);
444 }
445
446 @Override
447 public void onError(Objective objective, ObjectiveError error) {
448 log.info("PPPoED filter for {} on {} failed {} because {}",
449 devId, portNumber, (install) ? INSTALLATION : REMOVAL, error);
450 }
451 });
452 flowObjectiveService.filter(devId, pppoed);
453 }
454
455 @Override
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000456 public void processIgmpFilteringObjectives(DeviceId devId, PortNumber port,
457 MeterId upstreamMeterId,
458 UniTagInformation tagInformation,
459 boolean install,
460 boolean upstream) {
Saurav Dasf62cea82020-08-26 17:43:04 -0700461 if (upstream) {
462 // for UNI ports
463 if (tagInformation != null && !tagInformation.getIsIgmpRequired()) {
464 log.debug("Igmp provisioning is disabled for UNI port {} on "
465 + "device {} for service {}", port, devId,
466 tagInformation.getServiceName());
467 return;
468 }
469 } else {
470 // for NNI ports
471 if (!enableIgmpOnNni) {
472 log.debug("Igmp provisioning is disabled for NNI port {} on device {}",
473 port, devId);
474 return;
475 }
Matteo Scandolo34556e52020-05-08 12:34:13 -0700476 }
477
Andrea Campanellafee86422020-06-04 16:01:27 +0200478 log.debug("{} IGMP flows on {}:{}", (install) ?
479 "Installing" : "Removing", devId, port);
Andrea Campanella0e34f562020-06-11 10:47:10 +0200480 DefaultFilteringObjective.Builder filterBuilder = DefaultFilteringObjective.builder();
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000481 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
482 if (upstream) {
483
484 if (tagInformation.getTechnologyProfileId() != NONE_TP_ID) {
485 treatmentBuilder.writeMetadata(createTechProfValueForWm(null,
486 tagInformation.getTechnologyProfileId()), 0);
487 }
488
489
490 if (upstreamMeterId != null) {
491 treatmentBuilder.meter(upstreamMeterId);
492 }
493
Andrea Campanella0e34f562020-06-11 10:47:10 +0200494 if (!VlanId.vlanId(VlanId.NO_VID).equals(tagInformation.getUniTagMatch())) {
495 filterBuilder.addCondition(Criteria.matchVlanId(tagInformation.getUniTagMatch()));
496 }
497
498 if (!VlanId.vlanId(VlanId.NO_VID).equals(tagInformation.getPonCTag())) {
499 treatmentBuilder.setVlanId(tagInformation.getPonCTag());
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000500 }
501
502 if (tagInformation.getUsPonCTagPriority() != NO_PCP) {
Andrea Campanella0e34f562020-06-11 10:47:10 +0200503 treatmentBuilder.setVlanPcp((byte) tagInformation.getUsPonCTagPriority());
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000504 }
505 }
506
Andrea Campanella0e34f562020-06-11 10:47:10 +0200507 filterBuilder = install ? filterBuilder.permit() : filterBuilder.deny();
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000508
Andrea Campanella0e34f562020-06-11 10:47:10 +0200509 FilteringObjective igmp = filterBuilder
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000510 .withKey(Criteria.matchInPort(port))
511 .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
512 .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_IGMP))
513 .withMeta(treatmentBuilder
514 .setOutput(PortNumber.CONTROLLER).build())
515 .fromApp(appId)
516 .withPriority(MAX_PRIORITY)
517 .add(new ObjectiveContext() {
518 @Override
519 public void onSuccess(Objective objective) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700520 log.info("Igmp filter for dev/port {}/{} {}.",
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000521 devId, port, (install) ? INSTALLED : REMOVED);
522 }
523
524 @Override
525 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700526 log.error("Igmp filter for dev/port {}/{} failed {} because {}.",
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000527 devId, port, (install) ? INSTALLATION : REMOVAL,
528 error);
529 }
530 });
531
532 flowObjectiveService.filter(devId, igmp);
533 }
534
535 @Override
536 public void processEapolFilteringObjectives(DeviceId devId, PortNumber portNumber, String bpId,
537 CompletableFuture<ObjectiveError> filterFuture,
538 VlanId vlanId, boolean install) {
539
540 if (!enableEapol) {
541 log.debug("Eapol filtering is disabled. Completing filteringFuture immediately for the device {}", devId);
542 if (filterFuture != null) {
543 filterFuture.complete(null);
544 }
545 return;
546 }
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700547 log.info("Processing EAPOL with Bandwidth profile {} on {}/{}", bpId,
548 devId, portNumber);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000549 BandwidthProfileInformation bpInfo = getBandwidthProfileInformation(bpId);
550 if (bpInfo == null) {
551 log.warn("Bandwidth profile {} is not found. Authentication flow"
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700552 + " will not be installed on {}/{}", bpId, devId, portNumber);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000553 if (filterFuture != null) {
554 filterFuture.complete(ObjectiveError.BADPARAMS);
555 }
556 return;
557 }
558
Matteo Scandolo3a037a32020-04-01 12:17:50 -0700559 ConnectPoint cp = new ConnectPoint(devId, portNumber);
Andrea Campanella0e34f562020-06-11 10:47:10 +0200560 DefaultFilteringObjective.Builder filterBuilder = DefaultFilteringObjective.builder();
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000561 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
562 CompletableFuture<Object> meterFuture = new CompletableFuture<>();
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000563 // check if meter exists and create it only for an install
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200564 final MeterId meterId = oltMeterService.getMeterIdFromBpMapping(devId, bpInfo.id());
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700565 log.info("Meter id {} for Bandwidth profile {} associated to EAPOL on {}", meterId, bpInfo.id(), devId);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000566 if (meterId == null) {
567 if (install) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700568 log.debug("Need to install meter for EAPOL with bwp {} on dev/port {}", bpInfo.id(), cp.toString());
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200569 SubscriberFlowInfo fi = new SubscriberFlowInfo(devId, null, cp.port(),
570 new UniTagInformation.Builder()
571 .setPonCTag(vlanId).build(),
572 null, null,
573 null, bpInfo.id());
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100574 pendingEapolForDevice.compute(devId, (id, queue) -> {
575 if (queue == null) {
576 queue = new LinkedBlockingQueue<>();
577 }
578 queue.add(fi);
579 return queue;
580 });
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200581
Andrea Campanellad1e26642020-10-23 12:08:32 +0200582 //If false the meter is already being installed, skipping installation
583 if (!oltMeterService.checkAndAddPendingMeter(devId, bpInfo)) {
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200584 return;
585 }
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200586 MeterId innerMeterId = oltMeterService.createMeter(devId, bpInfo,
587 meterFuture);
588 fi.setUpMeterId(innerMeterId);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000589 } else {
590 // this case should not happen as the request to remove an eapol
591 // flow should mean that the flow points to a meter that exists.
592 // Nevertheless we can still delete the flow as we only need the
593 // correct 'match' to do so.
594 log.warn("Unknown meter id for bp {}, still proceeding with "
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700595 + "delete of eapol flow for {}", bpInfo.id(), cp.toString());
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200596 SubscriberFlowInfo fi = new SubscriberFlowInfo(devId, null, cp.port(),
597 new UniTagInformation.Builder()
598 .setPonCTag(vlanId).build(),
599 null, meterId,
600 null, bpInfo.id());
Andrea Campanella0e34f562020-06-11 10:47:10 +0200601 handleEapol(filterFuture, install, cp, filterBuilder, treatmentBuilder, fi, meterId);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000602 }
603 } else {
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700604 log.debug("Meter {} was previously created for bp {} on {}", meterId, bpInfo.id(), cp.toString());
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200605 SubscriberFlowInfo fi = new SubscriberFlowInfo(devId, null, cp.port(),
606 new UniTagInformation.Builder()
607 .setPonCTag(vlanId).build(),
608 null, meterId,
609 null, bpInfo.id());
Andrea Campanella0e34f562020-06-11 10:47:10 +0200610 handleEapol(filterFuture, install, cp, filterBuilder, treatmentBuilder, fi, meterId);
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200611 //No need for the future, meter is present.
612 return;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000613 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000614 meterFuture.thenAcceptAsync(result -> {
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200615 //for each pending eapol flow we check if the meter is there.
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100616 BlockingQueue<SubscriberFlowInfo> queue = pendingEapolForDevice.get(devId);
617 if (queue != null) {
618 while (true) {
619 SubscriberFlowInfo fi = queue.remove();
620 if (fi == null) {
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000621 pendingEapolForDevice.replace(devId, queue);
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100622 break;
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200623 }
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100624 //TODO this might return the reference and not the actual object
625 // so it can be actually swapped underneath us.
626 log.debug("handing pending eapol on {}/{} for {}", fi.getDevId(), fi.getUniPort(), fi);
627 if (result == null) {
628 MeterId mId = oltMeterService
629 .getMeterIdFromBpMapping(devId, fi.getUpBpInfo());
630 if (mId != null) {
631 log.debug("Meter installation completed for subscriber on {}, handling EAPOL trap flow",
632 cp.toString());
633 handleEapol(filterFuture, install, cp, filterBuilder, treatmentBuilder, fi, mId);
634 }
635 } else {
636 log.warn("Meter installation error while sending EAPOL trap flow to {}. " +
637 "Result {} and MeterId {}", cp.toString(), result, meterId);
638 }
639 oltMeterService.removeFromPendingMeters(devId, bpInfo);
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200640 }
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100641 } else {
642 log.info("No pending EAPOLs on {}", devId);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000643 }
644 });
645 }
646
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200647 private void handleEapol(CompletableFuture<ObjectiveError> filterFuture,
648 boolean install, ConnectPoint cp,
Andrea Campanella0e34f562020-06-11 10:47:10 +0200649 DefaultFilteringObjective.Builder filterBuilder,
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200650 TrafficTreatment.Builder treatmentBuilder,
651 SubscriberFlowInfo fi, MeterId mId) {
652 log.info("Meter {} for {} on {}/{} exists. {} EAPOL trap flow",
653 mId, fi.getUpBpInfo(), fi.getDevId(), fi.getUniPort(),
654 (install) ? "Installing" : "Removing");
655 int techProfileId = getDefaultTechProfileId(fi.getDevId(), fi.getUniPort());
656 // can happen in case of removal
657 if (mId != null) {
658 treatmentBuilder.meter(mId);
659 }
660 //Authentication trap flow uses only tech profile id as write metadata value
Andrea Campanella0e34f562020-06-11 10:47:10 +0200661 FilteringObjective eapol = (install ? filterBuilder.permit() : filterBuilder.deny())
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200662 .withKey(Criteria.matchInPort(fi.getUniPort()))
663 .addCondition(Criteria.matchEthType(EthType.EtherType.EAPOL.ethType()))
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200664 .withMeta(treatmentBuilder
665 .writeMetadata(createTechProfValueForWm(
666 fi.getTagInfo().getPonCTag(),
667 techProfileId), 0)
Andrea Campanella0e34f562020-06-11 10:47:10 +0200668 .setOutput(PortNumber.CONTROLLER)
669 .pushVlan()
670 .setVlanId(fi.getTagInfo().getPonCTag())
671 .build())
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200672 .fromApp(appId)
673 .withPriority(MAX_PRIORITY)
674 .add(new ObjectiveContext() {
675 @Override
676 public void onSuccess(Objective objective) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700677 log.info("Eapol filter {} for {} on {}/{} with meter {}.",
Andrea Campanella600d2e22020-06-22 11:00:31 +0200678 objective.id(), fi.getDevId(), fi.getUniPort(),
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200679 (install) ? INSTALLED : REMOVED, mId);
680 if (filterFuture != null) {
681 filterFuture.complete(null);
682 }
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200683 }
684
685 @Override
686 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700687 log.error("Eapol filter {} for {}/{} with meter {} " +
Andrea Campanella600d2e22020-06-22 11:00:31 +0200688 "failed {} because {}", objective.id(),
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200689 fi.getDevId(), fi.getUniPort(), mId,
690 (install) ? INSTALLATION : REMOVAL,
691 error);
692 if (filterFuture != null) {
693 filterFuture.complete(error);
694 }
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200695 }
696 });
697 flowObjectiveService.filter(fi.getDevId(), eapol);
698 }
699
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000700 /**
701 * Installs trap filtering objectives for particular traffic types on an
702 * NNI port.
703 *
704 * @param devId device ID
705 * @param port port number
706 * @param install true to install, false to remove
707 */
708 @Override
709 public void processNniFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
Saurav Dasf62cea82020-08-26 17:43:04 -0700710 log.info("{} flows for NNI port {} on device {}",
711 install ? "Adding" : "Removing", port, devId);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000712 processLldpFilteringObjective(devId, port, install);
713 processDhcpFilteringObjectives(devId, port, null, null, install, false);
714 processIgmpFilteringObjectives(devId, port, null, null, install, false);
Gustavo Silva5c492dd2021-02-12 10:21:11 -0300715 processPPPoEDFilteringObjectives(devId, port, null, null, install, false);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000716 }
717
718
719 @Override
720 public void processLldpFilteringObjective(DeviceId devId, PortNumber port, boolean install) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000721 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
722
723 FilteringObjective lldp = (install ? builder.permit() : builder.deny())
724 .withKey(Criteria.matchInPort(port))
725 .addCondition(Criteria.matchEthType(EthType.EtherType.LLDP.ethType()))
726 .withMeta(DefaultTrafficTreatment.builder()
727 .setOutput(PortNumber.CONTROLLER).build())
728 .fromApp(appId)
729 .withPriority(MAX_PRIORITY)
730 .add(new ObjectiveContext() {
731 @Override
732 public void onSuccess(Objective objective) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700733 log.info("LLDP filter for dev/port {}/{} {}.",
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000734 devId, port, (install) ? INSTALLED : REMOVED);
735 }
736
737 @Override
738 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700739 log.error("LLDP filter for dev/port {}/{} failed {} because {}",
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000740 devId, port, (install) ? INSTALLATION : REMOVAL,
741 error);
742 }
743 });
744
745 flowObjectiveService.filter(devId, lldp);
746 }
747
748 @Override
749 public ForwardingObjective.Builder createTransparentBuilder(PortNumber uplinkPort,
750 PortNumber subscriberPort,
751 MeterId meterId,
752 UniTagInformation tagInfo,
753 boolean upstream) {
754
755 TrafficSelector selector = DefaultTrafficSelector.builder()
756 .matchVlanId(tagInfo.getPonSTag())
757 .matchInPort(upstream ? subscriberPort : uplinkPort)
758 .matchInnerVlanId(tagInfo.getPonCTag())
759 .build();
760
761 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
762 if (meterId != null) {
763 tBuilder.meter(meterId);
764 }
765
766 TrafficTreatment treatment = tBuilder
767 .setOutput(upstream ? uplinkPort : subscriberPort)
768 .writeMetadata(createMetadata(upstream ? tagInfo.getPonSTag() : tagInfo.getPonCTag(),
769 tagInfo.getTechnologyProfileId(), upstream ? uplinkPort : subscriberPort), 0)
770 .build();
771
772 return createForwardingObjectiveBuilder(selector, treatment, MIN_PRIORITY);
773 }
774
775 @Override
776 public ForwardingObjective.Builder createUpBuilder(PortNumber uplinkPort,
777 PortNumber subscriberPort,
778 MeterId upstreamMeterId,
779 UniTagInformation uniTagInformation) {
780
781 TrafficSelector selector = DefaultTrafficSelector.builder()
782 .matchInPort(subscriberPort)
783 .matchVlanId(uniTagInformation.getUniTagMatch())
784 .build();
785
Andrea Campanella327c5722020-01-30 11:34:13 +0100786 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
787 //if the subscriberVlan (cTag) is different than ANY it needs to set.
788 if (uniTagInformation.getPonCTag().toShort() != VlanId.ANY_VALUE) {
789 treatmentBuilder.pushVlan()
790 .setVlanId(uniTagInformation.getPonCTag());
791 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000792
793 if (uniTagInformation.getUsPonCTagPriority() != NO_PCP) {
794 treatmentBuilder.setVlanPcp((byte) uniTagInformation.getUsPonCTagPriority());
795 }
796
797 treatmentBuilder.pushVlan()
798 .setVlanId(uniTagInformation.getPonSTag());
799
800 if (uniTagInformation.getUsPonSTagPriority() != NO_PCP) {
801 treatmentBuilder.setVlanPcp((byte) uniTagInformation.getUsPonSTagPriority());
802 }
803
804 treatmentBuilder.setOutput(uplinkPort)
805 .writeMetadata(createMetadata(uniTagInformation.getPonCTag(),
806 uniTagInformation.getTechnologyProfileId(), uplinkPort), 0L);
807
808 if (upstreamMeterId != null) {
809 treatmentBuilder.meter(upstreamMeterId);
810 }
811
812 return createForwardingObjectiveBuilder(selector, treatmentBuilder.build(), MIN_PRIORITY);
813 }
814
815 @Override
816 public ForwardingObjective.Builder createDownBuilder(PortNumber uplinkPort,
817 PortNumber subscriberPort,
818 MeterId downstreamMeterId,
819 UniTagInformation tagInformation) {
Andrea Campanella327c5722020-01-30 11:34:13 +0100820
821 //subscriberVlan can be any valid Vlan here including ANY to make sure the packet is tagged
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000822 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder()
823 .matchVlanId(tagInformation.getPonSTag())
824 .matchInPort(uplinkPort)
Andrea Campanella090e4a02020-02-05 13:53:55 +0100825 .matchInnerVlanId(tagInformation.getPonCTag());
826
827
828 if (tagInformation.getPonCTag().toShort() != VlanId.ANY_VALUE) {
829 selectorBuilder.matchMetadata(tagInformation.getPonCTag().toShort());
830 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000831
832 if (tagInformation.getDsPonSTagPriority() != NO_PCP) {
833 selectorBuilder.matchVlanPcp((byte) tagInformation.getDsPonSTagPriority());
834 }
835
836 if (tagInformation.getConfiguredMacAddress() != null &&
Daniele Moro7cbf4312020-03-06 17:24:12 -0800837 !tagInformation.getConfiguredMacAddress().equals("") &&
838 !MacAddress.NONE.equals(MacAddress.valueOf(tagInformation.getConfiguredMacAddress()))) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000839 selectorBuilder.matchEthDst(MacAddress.valueOf(tagInformation.getConfiguredMacAddress()));
840 }
841
842 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder()
843 .popVlan()
Andrea Campanella327c5722020-01-30 11:34:13 +0100844 .setOutput(subscriberPort);
845
Andrea Campanella327c5722020-01-30 11:34:13 +0100846 treatmentBuilder.writeMetadata(createMetadata(tagInformation.getPonCTag(),
847 tagInformation.getTechnologyProfileId(),
848 subscriberPort), 0);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000849
Andrea Campanella981e86c2021-03-12 11:35:33 +0100850 // Upstream pbit is used to remark inner vlan pbit.
851 // Upstream is used to avoid trusting the BNG to send the packet with correct pbit.
852 // this is done because ds mode 0 is used because ds mode 3 or 6 that allow for
853 // all pbit acceptance are not widely supported by vendors even though present in
854 // the OMCI spec.
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000855 if (tagInformation.getUsPonCTagPriority() != NO_PCP) {
856 treatmentBuilder.setVlanPcp((byte) tagInformation.getUsPonCTagPriority());
857 }
858
Andrea Campanella9a779292020-02-03 19:19:09 +0100859 if (!VlanId.NONE.equals(tagInformation.getUniTagMatch()) &&
860 tagInformation.getPonCTag().toShort() != VlanId.ANY_VALUE) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000861 treatmentBuilder.setVlanId(tagInformation.getUniTagMatch());
862 }
863
864 if (downstreamMeterId != null) {
865 treatmentBuilder.meter(downstreamMeterId);
866 }
867
868 return createForwardingObjectiveBuilder(selectorBuilder.build(), treatmentBuilder.build(), MIN_PRIORITY);
869 }
870
Andrea Campanella600d2e22020-06-22 11:00:31 +0200871 @Override
872 public void clearDeviceState(DeviceId deviceId) {
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100873 pendingEapolForDevice.remove(deviceId);
Andrea Campanella600d2e22020-06-22 11:00:31 +0200874 }
875
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000876 private DefaultForwardingObjective.Builder createForwardingObjectiveBuilder(TrafficSelector selector,
877 TrafficTreatment treatment,
878 Integer priority) {
879 return DefaultForwardingObjective.builder()
880 .withFlag(ForwardingObjective.Flag.VERSATILE)
881 .withPriority(priority)
882 .makePermanent()
883 .withSelector(selector)
884 .fromApp(appId)
885 .withTreatment(treatment);
886 }
887
888 /**
889 * Returns the write metadata value including tech profile reference and innerVlan.
890 * For param cVlan, null can be sent
891 *
892 * @param cVlan c (customer) tag of one subscriber
893 * @param techProfileId tech profile id of one subscriber
894 * @return the write metadata value including tech profile reference and innerVlan
895 */
896 private Long createTechProfValueForWm(VlanId cVlan, int techProfileId) {
897 if (cVlan == null || VlanId.NONE.equals(cVlan)) {
898 return (long) techProfileId << 32;
899 }
900 return ((long) (cVlan.id()) << 48 | (long) techProfileId << 32);
901 }
902
903 private BandwidthProfileInformation getBandwidthProfileInformation(String bandwidthProfile) {
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000904 if (bpService == null) {
905 log.warn(SADIS_NOT_RUNNING);
906 return null;
907 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000908 if (bandwidthProfile == null) {
909 return null;
910 }
911 return bpService.get(bandwidthProfile);
912 }
913
914 /**
915 * It will be used to support AT&T use case (for EAPOL flows).
916 * If multiple services are found in uniServiceList, returns default tech profile id
917 * If one service is found, returns the found one
918 *
919 * @param devId
920 * @param portNumber
921 * @return the default technology profile id
922 */
923 private int getDefaultTechProfileId(DeviceId devId, PortNumber portNumber) {
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000924 if (subsService == null) {
925 log.warn(SADIS_NOT_RUNNING);
926 return defaultTechProfileId;
927 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000928 Port port = deviceService.getPort(devId, portNumber);
929 if (port != null) {
930 SubscriberAndDeviceInformation info = subsService.get(port.annotations().value(AnnotationKeys.PORT_NAME));
931 if (info != null && info.uniTagList().size() == 1) {
932 return info.uniTagList().get(0).getTechnologyProfileId();
933 }
934 }
935 return defaultTechProfileId;
936 }
937
938 /**
939 * Write metadata instruction value (metadata) is 8 bytes.
940 * <p>
941 * MS 2 bytes: C Tag
942 * Next 2 bytes: Technology Profile Id
943 * Next 4 bytes: Port number (uni or nni)
944 */
945 private Long createMetadata(VlanId innerVlan, int techProfileId, PortNumber egressPort) {
946 if (techProfileId == NONE_TP_ID) {
Andrea Campanella7c49b792020-05-11 11:36:53 +0200947 techProfileId = DEFAULT_TP_ID_DEFAULT;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000948 }
949
950 return ((long) (innerVlan.id()) << 48 | (long) techProfileId << 32) | egressPort.toLong();
951 }
952
953
954}