blob: caeab289011f547e0c53130671a0d9b85ecccf0c [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;
Tunahan Sezena07fe962021-02-24 08:24:24 +000071import java.util.Optional;
Ilayda Ozdemir90a93622021-02-25 09:40:58 +000072import java.util.Map;
Andrea Campanella7a1d7e72020-11-05 10:40:10 +010073import java.util.Properties;
74import java.util.concurrent.BlockingQueue;
75import java.util.concurrent.CompletableFuture;
Andrea Campanella7a1d7e72020-11-05 10:40:10 +010076import java.util.concurrent.LinkedBlockingQueue;
77
78import static com.google.common.base.Strings.isNullOrEmpty;
79import static org.onlab.util.Tools.get;
80import static org.opencord.olt.impl.OsgiPropertyConstants.*;
81import static org.slf4j.LoggerFactory.getLogger;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000082
83/**
84 * Provisions flow rules on access devices.
85 */
86@Component(immediate = true, property = {
Saurav Dasf62cea82020-08-26 17:43:04 -070087 ENABLE_DHCP_ON_NNI + ":Boolean=" + ENABLE_DHCP_ON_NNI_DEFAULT,
Andrea Campanellacbbb7952019-11-25 06:38:41 +000088 ENABLE_DHCP_V4 + ":Boolean=" + ENABLE_DHCP_V4_DEFAULT,
89 ENABLE_DHCP_V6 + ":Boolean=" + ENABLE_DHCP_V6_DEFAULT,
Saurav Dasf62cea82020-08-26 17:43:04 -070090 ENABLE_IGMP_ON_NNI + ":Boolean=" + ENABLE_IGMP_ON_NNI_DEFAULT,
Andrea Campanellacbbb7952019-11-25 06:38:41 +000091 ENABLE_EAPOL + ":Boolean=" + ENABLE_EAPOL_DEFAULT,
Gustavo Silva5c492dd2021-02-12 10:21:11 -030092 ENABLE_PPPOE + ":Boolean=" + ENABLE_PPPOE_DEFAULT,
Andrea Campanellacbbb7952019-11-25 06:38:41 +000093 DEFAULT_TP_ID + ":Integer=" + DEFAULT_TP_ID_DEFAULT
94})
95public class OltFlowService implements AccessDeviceFlowService {
Ilayda Ozdemir90a93622021-02-25 09:40:58 +000096 private static final String SADIS_NOT_RUNNING = "Sadis is not running.";
Andrea Campanellacbbb7952019-11-25 06:38:41 +000097 private static final String APP_NAME = "org.opencord.olt";
98 private static final int NONE_TP_ID = -1;
99 private static final int NO_PCP = -1;
100 private static final Integer MAX_PRIORITY = 10000;
101 private static final Integer MIN_PRIORITY = 1000;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000102 private static final String INSTALLED = "installed";
103 private static final String REMOVED = "removed";
104 private static final String INSTALLATION = "installation";
105 private static final String REMOVAL = "removal";
106 private static final String V4 = "V4";
107 private static final String V6 = "V6";
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000108
109 private final Logger log = getLogger(getClass());
110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY)
112 protected FlowObjectiveService flowObjectiveService;
113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY)
115 protected CoreService coreService;
116
117 @Reference(cardinality = ReferenceCardinality.MANDATORY)
118 protected MastershipService mastershipService;
119
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000120 @Reference(cardinality = ReferenceCardinality.OPTIONAL,
121 bind = "bindSadisService",
122 unbind = "unbindSadisService",
123 policy = ReferencePolicy.DYNAMIC)
124 protected volatile SadisService sadisService;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000125
126 @Reference(cardinality = ReferenceCardinality.MANDATORY)
127 protected DeviceService deviceService;
128
129 @Reference(cardinality = ReferenceCardinality.MANDATORY)
130 protected AccessDeviceMeterService oltMeterService;
131
132 @Reference(cardinality = ReferenceCardinality.MANDATORY)
133 protected ComponentConfigService componentConfigService;
134
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000135 @Reference(cardinality = ReferenceCardinality.MANDATORY)
136 protected StorageService storageService;
137
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000138 /**
Saurav Dasf62cea82020-08-26 17:43:04 -0700139 * Create DHCP trap flow on NNI port(s).
140 */
141 protected boolean enableDhcpOnNni = ENABLE_DHCP_ON_NNI_DEFAULT;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000142
143 /**
Saurav Dasf62cea82020-08-26 17:43:04 -0700144 * Enable flows for DHCP v4 if dhcp is required in sadis config.
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000145 **/
146 protected boolean enableDhcpV4 = ENABLE_DHCP_V4_DEFAULT;
147
148 /**
Saurav Dasf62cea82020-08-26 17:43:04 -0700149 * Enable flows for DHCP v6 if dhcp is required in sadis config.
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000150 **/
151 protected boolean enableDhcpV6 = ENABLE_DHCP_V6_DEFAULT;
152
153 /**
Saurav Dasf62cea82020-08-26 17:43:04 -0700154 * Create IGMP trap flow on NNI port(s).
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000155 **/
Saurav Dasf62cea82020-08-26 17:43:04 -0700156 protected boolean enableIgmpOnNni = ENABLE_IGMP_ON_NNI_DEFAULT;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000157
158 /**
159 * Send EAPOL authentication trap flows before subscriber provisioning.
160 **/
161 protected boolean enableEapol = ENABLE_EAPOL_DEFAULT;
162
163 /**
Gustavo Silva5c492dd2021-02-12 10:21:11 -0300164 * Send PPPoED authentication trap flows before subscriber provisioning.
165 **/
166 protected boolean enablePppoe = ENABLE_PPPOE_DEFAULT;
167
168 /**
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000169 * Default technology profile id that is used for authentication trap flows.
170 **/
171 protected int defaultTechProfileId = DEFAULT_TP_ID_DEFAULT;
172
173 protected ApplicationId appId;
174 protected BaseInformationService<BandwidthProfileInformation> bpService;
175 protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000176 protected Map<DeviceId, BlockingQueue<SubscriberFlowInfo>> pendingEapolForDevice;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000177
178 @Activate
179 public void activate(ComponentContext context) {
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000180 if (sadisService != null) {
181 bpService = sadisService.getBandwidthProfileService();
182 subsService = sadisService.getSubscriberInfoService();
183 } else {
184 log.warn(SADIS_NOT_RUNNING);
185 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000186 componentConfigService.registerProperties(getClass());
187 appId = coreService.getAppId(APP_NAME);
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000188 KryoNamespace serializer = KryoNamespace.newBuilder()
189 .register(KryoNamespaces.API)
190 .register(UniTagInformation.class)
191 .register(SubscriberFlowInfo.class)
192 .register(LinkedBlockingQueue.class)
193 .build();
194 pendingEapolForDevice = storageService.<DeviceId, BlockingQueue<SubscriberFlowInfo>>consistentMapBuilder()
195 .withName("volt-pending-eapol")
196 .withSerializer(Serializer.using(serializer))
197 .withApplicationId(appId)
198 .build().asJavaMap();
Andrea Campanellafee86422020-06-04 16:01:27 +0200199 log.info("started");
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000200 }
201
202
203 @Deactivate
204 public void deactivate(ComponentContext context) {
205 componentConfigService.unregisterProperties(getClass(), false);
Andrea Campanellafee86422020-06-04 16:01:27 +0200206 log.info("stopped");
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000207 }
208
209 @Modified
210 public void modified(ComponentContext context) {
211
212 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
213
Saurav Dasf62cea82020-08-26 17:43:04 -0700214 Boolean o = Tools.isPropertyEnabled(properties, ENABLE_DHCP_ON_NNI);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000215 if (o != null) {
Saurav Dasf62cea82020-08-26 17:43:04 -0700216 enableDhcpOnNni = o;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000217 }
218
Andrea Campanella7c49b792020-05-11 11:36:53 +0200219 Boolean v4 = Tools.isPropertyEnabled(properties, ENABLE_DHCP_V4);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000220 if (v4 != null) {
221 enableDhcpV4 = v4;
222 }
223
Andrea Campanella7c49b792020-05-11 11:36:53 +0200224 Boolean v6 = Tools.isPropertyEnabled(properties, ENABLE_DHCP_V6);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000225 if (v6 != null) {
226 enableDhcpV6 = v6;
227 }
228
Saurav Dasf62cea82020-08-26 17:43:04 -0700229 Boolean p = Tools.isPropertyEnabled(properties, ENABLE_IGMP_ON_NNI);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000230 if (p != null) {
Saurav Dasf62cea82020-08-26 17:43:04 -0700231 enableIgmpOnNni = p;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000232 }
233
Andrea Campanella7c49b792020-05-11 11:36:53 +0200234 Boolean eap = Tools.isPropertyEnabled(properties, ENABLE_EAPOL);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000235 if (eap != null) {
236 enableEapol = eap;
237 }
238
Gustavo Silva5c492dd2021-02-12 10:21:11 -0300239 Boolean pppoe = Tools.isPropertyEnabled(properties, ENABLE_PPPOE);
240 if (pppoe != null) {
241 enablePppoe = pppoe;
242 }
243
Andrea Campanella7c49b792020-05-11 11:36:53 +0200244 String tpId = get(properties, DEFAULT_TP_ID);
245 defaultTechProfileId = isNullOrEmpty(tpId) ? DEFAULT_TP_ID_DEFAULT : Integer.parseInt(tpId.trim());
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000246
Saurav Dasf62cea82020-08-26 17:43:04 -0700247 log.info("modified. Values = enableDhcpOnNni: {}, enableDhcpV4: {}, " +
248 "enableDhcpV6:{}, enableIgmpOnNni:{}, " +
Gustavo Silva5c492dd2021-02-12 10:21:11 -0300249 "enableEapol{}, enablePppoe{}, defaultTechProfileId: {}",
Saurav Dasf62cea82020-08-26 17:43:04 -0700250 enableDhcpOnNni, enableDhcpV4, enableDhcpV6,
Gustavo Silva5c492dd2021-02-12 10:21:11 -0300251 enableIgmpOnNni, enableEapol, enablePppoe,
252 defaultTechProfileId);
Andrea Campanellafee86422020-06-04 16:01:27 +0200253
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000254 }
255
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000256 protected void bindSadisService(SadisService service) {
257 sadisService = service;
258 bpService = sadisService.getBandwidthProfileService();
259 subsService = sadisService.getSubscriberInfoService();
260 log.info("Sadis-service binds to onos.");
261 }
262
263 protected void unbindSadisService(SadisService service) {
264 sadisService = null;
265 bpService = null;
266 subsService = null;
267 log.info("Sadis-service unbinds from onos.");
268 }
269
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000270 @Override
271 public void processDhcpFilteringObjectives(DeviceId devId, PortNumber port,
272 MeterId upstreamMeterId,
273 UniTagInformation tagInformation,
274 boolean install,
Tunahan Sezena07fe962021-02-24 08:24:24 +0000275 boolean upstream,
276 Optional<CompletableFuture<ObjectiveError>> dhcpFuture) {
Saurav Dasf62cea82020-08-26 17:43:04 -0700277 if (upstream) {
278 // for UNI ports
279 if (tagInformation != null && !tagInformation.getIsDhcpRequired()) {
280 log.debug("Dhcp provisioning is disabled for UNI port {} on "
281 + "device {} for service {}", port, devId,
282 tagInformation.getServiceName());
Tunahan Sezena07fe962021-02-24 08:24:24 +0000283 dhcpFuture.ifPresent(f -> f.complete(null));
Saurav Dasf62cea82020-08-26 17:43:04 -0700284 return;
285 }
286 } else {
287 // for NNI ports
288 if (!enableDhcpOnNni) {
289 log.debug("Dhcp provisioning is disabled for NNI port {} on "
290 + "device {}", port, devId);
Tunahan Sezena07fe962021-02-24 08:24:24 +0000291 dhcpFuture.ifPresent(f -> f.complete(null));
Saurav Dasf62cea82020-08-26 17:43:04 -0700292 return;
293 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000294 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000295 int techProfileId = tagInformation != null ? tagInformation.getTechnologyProfileId() : NONE_TP_ID;
296 VlanId cTag = tagInformation != null ? tagInformation.getPonCTag() : VlanId.NONE;
297 VlanId unitagMatch = tagInformation != null ? tagInformation.getUniTagMatch() : VlanId.ANY;
Andrea Campanella3a96ce82021-02-09 12:32:42 +0100298 Byte vlanPcp = tagInformation != null && tagInformation.getUsPonCTagPriority() != NO_PCP
299 ? (byte) tagInformation.getUsPonCTagPriority() : null;
Andrea Campanella0e34f562020-06-11 10:47:10 +0200300
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000301
302 if (enableDhcpV4) {
303 int udpSrc = (upstream) ? 68 : 67;
304 int udpDst = (upstream) ? 67 : 68;
305
306 EthType ethType = EthType.EtherType.IPV4.ethType();
307 byte protocol = IPv4.PROTOCOL_UDP;
308
Andrea Campanella7c49b792020-05-11 11:36:53 +0200309 addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType,
Andrea Campanella0e34f562020-06-11 10:47:10 +0200310 upstreamMeterId, techProfileId, protocol, cTag, unitagMatch,
Tunahan Sezena07fe962021-02-24 08:24:24 +0000311 vlanPcp, upstream, install, dhcpFuture);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000312 }
313
314 if (enableDhcpV6) {
315 int udpSrc = (upstream) ? 547 : 546;
316 int udpDst = (upstream) ? 546 : 547;
317
318 EthType ethType = EthType.EtherType.IPV6.ethType();
319 byte protocol = IPv6.PROTOCOL_UDP;
320
Andrea Campanella7c49b792020-05-11 11:36:53 +0200321 addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType,
Andrea Campanella0e34f562020-06-11 10:47:10 +0200322 upstreamMeterId, techProfileId, protocol, cTag, unitagMatch,
Tunahan Sezena07fe962021-02-24 08:24:24 +0000323 vlanPcp, upstream, install, dhcpFuture);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000324 }
325 }
326
327 private void addDhcpFilteringObjectives(DeviceId devId, PortNumber port, int udpSrc, int udpDst,
328 EthType ethType, MeterId upstreamMeterId, int techProfileId, byte protocol,
Andrea Campanella0e34f562020-06-11 10:47:10 +0200329 VlanId cTag, VlanId unitagMatch,
330 Byte vlanPcp, boolean upstream,
Tunahan Sezena07fe962021-02-24 08:24:24 +0000331 boolean install, Optional<CompletableFuture<ObjectiveError>> dhcpFuture) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000332
333 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
334 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
335
336 if (upstreamMeterId != null) {
337 treatmentBuilder.meter(upstreamMeterId);
338 }
339
340 if (techProfileId != NONE_TP_ID) {
341 treatmentBuilder.writeMetadata(createTechProfValueForWm(unitagMatch, techProfileId), 0);
342 }
343
344 FilteringObjective.Builder dhcpUpstreamBuilder = (install ? builder.permit() : builder.deny())
345 .withKey(Criteria.matchInPort(port))
346 .addCondition(Criteria.matchEthType(ethType))
347 .addCondition(Criteria.matchIPProtocol(protocol))
348 .addCondition(Criteria.matchUdpSrc(TpPort.tpPort(udpSrc)))
349 .addCondition(Criteria.matchUdpDst(TpPort.tpPort(udpDst)))
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000350 .fromApp(appId)
351 .withPriority(MAX_PRIORITY);
352
Andrea Campanella0e34f562020-06-11 10:47:10 +0200353 //VLAN changes and PCP matching need to happen only in the upstream directions
354 if (upstream) {
355 treatmentBuilder.setVlanId(cTag);
356 if (!VlanId.vlanId(VlanId.NO_VID).equals(unitagMatch)) {
357 dhcpUpstreamBuilder.addCondition(Criteria.matchVlanId(unitagMatch));
358 }
359 if (vlanPcp != null) {
360 treatmentBuilder.setVlanPcp(vlanPcp);
361 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000362 }
363
Andrea Campanella0e34f562020-06-11 10:47:10 +0200364 dhcpUpstreamBuilder.withMeta(treatmentBuilder
365 .setOutput(PortNumber.CONTROLLER).build());
366
367
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000368 FilteringObjective dhcpUpstream = dhcpUpstreamBuilder.add(new ObjectiveContext() {
369 @Override
370 public void onSuccess(Objective objective) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700371 log.info("DHCP {} filter for dev/port {}/{} {}.",
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000372 (ethType.equals(EthType.EtherType.IPV4.ethType())) ? V4 : V6,
373 devId, port, (install) ? INSTALLED : REMOVED);
Tunahan Sezena07fe962021-02-24 08:24:24 +0000374 dhcpFuture.ifPresent(f -> f.complete(null));
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000375 }
376
377 @Override
378 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700379 log.error("DHCP {} filter for dev/port {}/{} failed {} because {}",
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000380 (ethType.equals(EthType.EtherType.IPV4.ethType())) ? V4 : V6,
381 devId, port, (install) ? INSTALLATION : REMOVAL,
382 error);
Tunahan Sezena07fe962021-02-24 08:24:24 +0000383 dhcpFuture.ifPresent(f -> f.complete(error));
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000384 }
385 });
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000386 flowObjectiveService.filter(devId, dhcpUpstream);
387
388 }
389
390 @Override
Gustavo Silva5c492dd2021-02-12 10:21:11 -0300391 public void processPPPoEDFilteringObjectives(DeviceId devId, PortNumber portNumber,
392 MeterId upstreamMeterId,
393 UniTagInformation tagInformation,
394 boolean install,
395 boolean upstream) {
396 if (!enablePppoe) {
397 log.debug("PPPoED filtering is disabled. Ignoring request.");
398 return;
399 }
400
401 int techProfileId = NONE_TP_ID;
402 VlanId cTag = VlanId.NONE;
403 VlanId unitagMatch = VlanId.ANY;
404 Byte vlanPcp = null;
405
406 if (tagInformation != null) {
407 techProfileId = tagInformation.getTechnologyProfileId();
408 cTag = tagInformation.getPonCTag();
409 unitagMatch = tagInformation.getUniTagMatch();
410 if (tagInformation.getUsPonCTagPriority() != NO_PCP) {
411 vlanPcp = (byte) tagInformation.getUsPonCTagPriority();
412 }
413 }
414
415 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
416 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
417 CompletableFuture<Object> meterFuture = new CompletableFuture<>();
418
419 if (upstreamMeterId != null) {
420 treatmentBuilder.meter(upstreamMeterId);
421 }
422
423 if (techProfileId != NONE_TP_ID) {
424 treatmentBuilder.writeMetadata(createTechProfValueForWm(cTag, techProfileId), 0);
425 }
426
427 DefaultFilteringObjective.Builder pppoedBuilder = (install ? builder.permit() : builder.deny())
428 .withKey(Criteria.matchInPort(portNumber))
429 .addCondition(Criteria.matchEthType(EthType.EtherType.PPPoED.ethType()))
430 .fromApp(appId)
431 .withPriority(10000);
432
433 if (upstream) {
434 treatmentBuilder.setVlanId(cTag);
435 if (!VlanId.vlanId(VlanId.NO_VID).equals(unitagMatch)) {
436 pppoedBuilder.addCondition(Criteria.matchVlanId(unitagMatch));
437 }
438 if (vlanPcp != null) {
439 treatmentBuilder.setVlanPcp(vlanPcp);
440 }
441 }
442 pppoedBuilder = pppoedBuilder.withMeta(treatmentBuilder.setOutput(PortNumber.CONTROLLER).build());
443
444 FilteringObjective pppoed = pppoedBuilder
445 .add(new ObjectiveContext() {
446 @Override
447 public void onSuccess(Objective objective) {
448 log.info("PPPoED filter for {} on {} {}.",
449 devId, portNumber, (install) ? INSTALLED : REMOVED);
450 }
451
452 @Override
453 public void onError(Objective objective, ObjectiveError error) {
454 log.info("PPPoED filter for {} on {} failed {} because {}",
455 devId, portNumber, (install) ? INSTALLATION : REMOVAL, error);
456 }
457 });
458 flowObjectiveService.filter(devId, pppoed);
459 }
460
461 @Override
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000462 public void processIgmpFilteringObjectives(DeviceId devId, PortNumber port,
463 MeterId upstreamMeterId,
464 UniTagInformation tagInformation,
465 boolean install,
466 boolean upstream) {
Saurav Dasf62cea82020-08-26 17:43:04 -0700467 if (upstream) {
468 // for UNI ports
469 if (tagInformation != null && !tagInformation.getIsIgmpRequired()) {
470 log.debug("Igmp provisioning is disabled for UNI port {} on "
471 + "device {} for service {}", port, devId,
472 tagInformation.getServiceName());
473 return;
474 }
475 } else {
476 // for NNI ports
477 if (!enableIgmpOnNni) {
478 log.debug("Igmp provisioning is disabled for NNI port {} on device {}",
479 port, devId);
480 return;
481 }
Matteo Scandolo34556e52020-05-08 12:34:13 -0700482 }
483
Andrea Campanellafee86422020-06-04 16:01:27 +0200484 log.debug("{} IGMP flows on {}:{}", (install) ?
485 "Installing" : "Removing", devId, port);
Andrea Campanella0e34f562020-06-11 10:47:10 +0200486 DefaultFilteringObjective.Builder filterBuilder = DefaultFilteringObjective.builder();
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000487 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
488 if (upstream) {
489
490 if (tagInformation.getTechnologyProfileId() != NONE_TP_ID) {
491 treatmentBuilder.writeMetadata(createTechProfValueForWm(null,
492 tagInformation.getTechnologyProfileId()), 0);
493 }
494
495
496 if (upstreamMeterId != null) {
497 treatmentBuilder.meter(upstreamMeterId);
498 }
499
Andrea Campanella0e34f562020-06-11 10:47:10 +0200500 if (!VlanId.vlanId(VlanId.NO_VID).equals(tagInformation.getUniTagMatch())) {
501 filterBuilder.addCondition(Criteria.matchVlanId(tagInformation.getUniTagMatch()));
502 }
503
504 if (!VlanId.vlanId(VlanId.NO_VID).equals(tagInformation.getPonCTag())) {
505 treatmentBuilder.setVlanId(tagInformation.getPonCTag());
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000506 }
507
508 if (tagInformation.getUsPonCTagPriority() != NO_PCP) {
Andrea Campanella0e34f562020-06-11 10:47:10 +0200509 treatmentBuilder.setVlanPcp((byte) tagInformation.getUsPonCTagPriority());
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000510 }
511 }
512
Andrea Campanella0e34f562020-06-11 10:47:10 +0200513 filterBuilder = install ? filterBuilder.permit() : filterBuilder.deny();
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000514
Andrea Campanella0e34f562020-06-11 10:47:10 +0200515 FilteringObjective igmp = filterBuilder
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000516 .withKey(Criteria.matchInPort(port))
517 .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
518 .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_IGMP))
519 .withMeta(treatmentBuilder
520 .setOutput(PortNumber.CONTROLLER).build())
521 .fromApp(appId)
522 .withPriority(MAX_PRIORITY)
523 .add(new ObjectiveContext() {
524 @Override
525 public void onSuccess(Objective objective) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700526 log.info("Igmp filter for dev/port {}/{} {}.",
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000527 devId, port, (install) ? INSTALLED : REMOVED);
528 }
529
530 @Override
531 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700532 log.error("Igmp filter for dev/port {}/{} failed {} because {}.",
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000533 devId, port, (install) ? INSTALLATION : REMOVAL,
534 error);
535 }
536 });
537
538 flowObjectiveService.filter(devId, igmp);
539 }
540
541 @Override
542 public void processEapolFilteringObjectives(DeviceId devId, PortNumber portNumber, String bpId,
543 CompletableFuture<ObjectiveError> filterFuture,
544 VlanId vlanId, boolean install) {
545
546 if (!enableEapol) {
547 log.debug("Eapol filtering is disabled. Completing filteringFuture immediately for the device {}", devId);
548 if (filterFuture != null) {
549 filterFuture.complete(null);
550 }
551 return;
552 }
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700553 log.info("Processing EAPOL with Bandwidth profile {} on {}/{}", bpId,
554 devId, portNumber);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000555 BandwidthProfileInformation bpInfo = getBandwidthProfileInformation(bpId);
556 if (bpInfo == null) {
557 log.warn("Bandwidth profile {} is not found. Authentication flow"
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700558 + " will not be installed on {}/{}", bpId, devId, portNumber);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000559 if (filterFuture != null) {
560 filterFuture.complete(ObjectiveError.BADPARAMS);
561 }
562 return;
563 }
564
Matteo Scandolo3a037a32020-04-01 12:17:50 -0700565 ConnectPoint cp = new ConnectPoint(devId, portNumber);
Andrea Campanella0e34f562020-06-11 10:47:10 +0200566 DefaultFilteringObjective.Builder filterBuilder = DefaultFilteringObjective.builder();
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000567 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
568 CompletableFuture<Object> meterFuture = new CompletableFuture<>();
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000569 // check if meter exists and create it only for an install
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200570 final MeterId meterId = oltMeterService.getMeterIdFromBpMapping(devId, bpInfo.id());
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700571 log.info("Meter id {} for Bandwidth profile {} associated to EAPOL on {}", meterId, bpInfo.id(), devId);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000572 if (meterId == null) {
573 if (install) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700574 log.debug("Need to install meter for EAPOL with bwp {} on dev/port {}", bpInfo.id(), cp.toString());
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200575 SubscriberFlowInfo fi = new SubscriberFlowInfo(devId, null, cp.port(),
576 new UniTagInformation.Builder()
577 .setPonCTag(vlanId).build(),
578 null, null,
579 null, bpInfo.id());
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100580 pendingEapolForDevice.compute(devId, (id, queue) -> {
581 if (queue == null) {
582 queue = new LinkedBlockingQueue<>();
583 }
584 queue.add(fi);
585 return queue;
586 });
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200587
Andrea Campanellad1e26642020-10-23 12:08:32 +0200588 //If false the meter is already being installed, skipping installation
589 if (!oltMeterService.checkAndAddPendingMeter(devId, bpInfo)) {
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200590 return;
591 }
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200592 MeterId innerMeterId = oltMeterService.createMeter(devId, bpInfo,
593 meterFuture);
594 fi.setUpMeterId(innerMeterId);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000595 } else {
596 // this case should not happen as the request to remove an eapol
597 // flow should mean that the flow points to a meter that exists.
598 // Nevertheless we can still delete the flow as we only need the
599 // correct 'match' to do so.
600 log.warn("Unknown meter id for bp {}, still proceeding with "
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700601 + "delete of eapol flow for {}", bpInfo.id(), cp.toString());
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200602 SubscriberFlowInfo fi = new SubscriberFlowInfo(devId, null, cp.port(),
603 new UniTagInformation.Builder()
604 .setPonCTag(vlanId).build(),
605 null, meterId,
606 null, bpInfo.id());
Andrea Campanella0e34f562020-06-11 10:47:10 +0200607 handleEapol(filterFuture, install, cp, filterBuilder, treatmentBuilder, fi, meterId);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000608 }
609 } else {
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700610 log.debug("Meter {} was previously created for bp {} on {}", meterId, bpInfo.id(), cp.toString());
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200611 SubscriberFlowInfo fi = new SubscriberFlowInfo(devId, null, cp.port(),
612 new UniTagInformation.Builder()
613 .setPonCTag(vlanId).build(),
614 null, meterId,
615 null, bpInfo.id());
Andrea Campanella0e34f562020-06-11 10:47:10 +0200616 handleEapol(filterFuture, install, cp, filterBuilder, treatmentBuilder, fi, meterId);
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200617 //No need for the future, meter is present.
618 return;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000619 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000620 meterFuture.thenAcceptAsync(result -> {
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200621 //for each pending eapol flow we check if the meter is there.
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100622 BlockingQueue<SubscriberFlowInfo> queue = pendingEapolForDevice.get(devId);
623 if (queue != null) {
624 while (true) {
625 SubscriberFlowInfo fi = queue.remove();
626 if (fi == null) {
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000627 pendingEapolForDevice.replace(devId, queue);
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100628 break;
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200629 }
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100630 //TODO this might return the reference and not the actual object
631 // so it can be actually swapped underneath us.
632 log.debug("handing pending eapol on {}/{} for {}", fi.getDevId(), fi.getUniPort(), fi);
633 if (result == null) {
634 MeterId mId = oltMeterService
635 .getMeterIdFromBpMapping(devId, fi.getUpBpInfo());
636 if (mId != null) {
637 log.debug("Meter installation completed for subscriber on {}, handling EAPOL trap flow",
638 cp.toString());
639 handleEapol(filterFuture, install, cp, filterBuilder, treatmentBuilder, fi, mId);
640 }
641 } else {
642 log.warn("Meter installation error while sending EAPOL trap flow to {}. " +
643 "Result {} and MeterId {}", cp.toString(), result, meterId);
644 }
645 oltMeterService.removeFromPendingMeters(devId, bpInfo);
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200646 }
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100647 } else {
648 log.info("No pending EAPOLs on {}", devId);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000649 }
650 });
651 }
652
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200653 private void handleEapol(CompletableFuture<ObjectiveError> filterFuture,
654 boolean install, ConnectPoint cp,
Andrea Campanella0e34f562020-06-11 10:47:10 +0200655 DefaultFilteringObjective.Builder filterBuilder,
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200656 TrafficTreatment.Builder treatmentBuilder,
657 SubscriberFlowInfo fi, MeterId mId) {
658 log.info("Meter {} for {} on {}/{} exists. {} EAPOL trap flow",
659 mId, fi.getUpBpInfo(), fi.getDevId(), fi.getUniPort(),
660 (install) ? "Installing" : "Removing");
661 int techProfileId = getDefaultTechProfileId(fi.getDevId(), fi.getUniPort());
662 // can happen in case of removal
663 if (mId != null) {
664 treatmentBuilder.meter(mId);
665 }
666 //Authentication trap flow uses only tech profile id as write metadata value
Andrea Campanella0e34f562020-06-11 10:47:10 +0200667 FilteringObjective eapol = (install ? filterBuilder.permit() : filterBuilder.deny())
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200668 .withKey(Criteria.matchInPort(fi.getUniPort()))
669 .addCondition(Criteria.matchEthType(EthType.EtherType.EAPOL.ethType()))
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200670 .withMeta(treatmentBuilder
671 .writeMetadata(createTechProfValueForWm(
672 fi.getTagInfo().getPonCTag(),
673 techProfileId), 0)
Andrea Campanella0e34f562020-06-11 10:47:10 +0200674 .setOutput(PortNumber.CONTROLLER)
675 .pushVlan()
676 .setVlanId(fi.getTagInfo().getPonCTag())
677 .build())
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200678 .fromApp(appId)
679 .withPriority(MAX_PRIORITY)
680 .add(new ObjectiveContext() {
681 @Override
682 public void onSuccess(Objective objective) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700683 log.info("Eapol filter {} for {} on {}/{} with meter {}.",
Andrea Campanella600d2e22020-06-22 11:00:31 +0200684 objective.id(), fi.getDevId(), fi.getUniPort(),
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200685 (install) ? INSTALLED : REMOVED, mId);
686 if (filterFuture != null) {
687 filterFuture.complete(null);
688 }
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200689 }
690
691 @Override
692 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700693 log.error("Eapol filter {} for {}/{} with meter {} " +
Andrea Campanella600d2e22020-06-22 11:00:31 +0200694 "failed {} because {}", objective.id(),
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200695 fi.getDevId(), fi.getUniPort(), mId,
696 (install) ? INSTALLATION : REMOVAL,
697 error);
698 if (filterFuture != null) {
699 filterFuture.complete(error);
700 }
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200701 }
702 });
703 flowObjectiveService.filter(fi.getDevId(), eapol);
704 }
705
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000706 /**
707 * Installs trap filtering objectives for particular traffic types on an
708 * NNI port.
709 *
710 * @param devId device ID
711 * @param port port number
712 * @param install true to install, false to remove
713 */
714 @Override
715 public void processNniFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
Saurav Dasf62cea82020-08-26 17:43:04 -0700716 log.info("{} flows for NNI port {} on device {}",
717 install ? "Adding" : "Removing", port, devId);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000718 processLldpFilteringObjective(devId, port, install);
Tunahan Sezena07fe962021-02-24 08:24:24 +0000719 processDhcpFilteringObjectives(devId, port, null, null, install, false, Optional.empty());
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000720 processIgmpFilteringObjectives(devId, port, null, null, install, false);
Gustavo Silva5c492dd2021-02-12 10:21:11 -0300721 processPPPoEDFilteringObjectives(devId, port, null, null, install, false);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000722 }
723
724
725 @Override
726 public void processLldpFilteringObjective(DeviceId devId, PortNumber port, boolean install) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000727 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
728
729 FilteringObjective lldp = (install ? builder.permit() : builder.deny())
730 .withKey(Criteria.matchInPort(port))
731 .addCondition(Criteria.matchEthType(EthType.EtherType.LLDP.ethType()))
732 .withMeta(DefaultTrafficTreatment.builder()
733 .setOutput(PortNumber.CONTROLLER).build())
734 .fromApp(appId)
735 .withPriority(MAX_PRIORITY)
736 .add(new ObjectiveContext() {
737 @Override
738 public void onSuccess(Objective objective) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700739 log.info("LLDP filter for dev/port {}/{} {}.",
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000740 devId, port, (install) ? INSTALLED : REMOVED);
741 }
742
743 @Override
744 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700745 log.error("LLDP filter for dev/port {}/{} failed {} because {}",
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000746 devId, port, (install) ? INSTALLATION : REMOVAL,
747 error);
748 }
749 });
750
751 flowObjectiveService.filter(devId, lldp);
752 }
753
754 @Override
755 public ForwardingObjective.Builder createTransparentBuilder(PortNumber uplinkPort,
756 PortNumber subscriberPort,
757 MeterId meterId,
758 UniTagInformation tagInfo,
759 boolean upstream) {
760
761 TrafficSelector selector = DefaultTrafficSelector.builder()
762 .matchVlanId(tagInfo.getPonSTag())
763 .matchInPort(upstream ? subscriberPort : uplinkPort)
764 .matchInnerVlanId(tagInfo.getPonCTag())
765 .build();
766
767 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
768 if (meterId != null) {
769 tBuilder.meter(meterId);
770 }
771
772 TrafficTreatment treatment = tBuilder
773 .setOutput(upstream ? uplinkPort : subscriberPort)
774 .writeMetadata(createMetadata(upstream ? tagInfo.getPonSTag() : tagInfo.getPonCTag(),
775 tagInfo.getTechnologyProfileId(), upstream ? uplinkPort : subscriberPort), 0)
776 .build();
777
778 return createForwardingObjectiveBuilder(selector, treatment, MIN_PRIORITY);
779 }
780
781 @Override
782 public ForwardingObjective.Builder createUpBuilder(PortNumber uplinkPort,
783 PortNumber subscriberPort,
784 MeterId upstreamMeterId,
785 UniTagInformation uniTagInformation) {
786
787 TrafficSelector selector = DefaultTrafficSelector.builder()
788 .matchInPort(subscriberPort)
789 .matchVlanId(uniTagInformation.getUniTagMatch())
790 .build();
791
Andrea Campanella327c5722020-01-30 11:34:13 +0100792 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
793 //if the subscriberVlan (cTag) is different than ANY it needs to set.
794 if (uniTagInformation.getPonCTag().toShort() != VlanId.ANY_VALUE) {
795 treatmentBuilder.pushVlan()
796 .setVlanId(uniTagInformation.getPonCTag());
797 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000798
799 if (uniTagInformation.getUsPonCTagPriority() != NO_PCP) {
800 treatmentBuilder.setVlanPcp((byte) uniTagInformation.getUsPonCTagPriority());
801 }
802
803 treatmentBuilder.pushVlan()
804 .setVlanId(uniTagInformation.getPonSTag());
805
806 if (uniTagInformation.getUsPonSTagPriority() != NO_PCP) {
807 treatmentBuilder.setVlanPcp((byte) uniTagInformation.getUsPonSTagPriority());
808 }
809
810 treatmentBuilder.setOutput(uplinkPort)
811 .writeMetadata(createMetadata(uniTagInformation.getPonCTag(),
812 uniTagInformation.getTechnologyProfileId(), uplinkPort), 0L);
813
814 if (upstreamMeterId != null) {
815 treatmentBuilder.meter(upstreamMeterId);
816 }
817
818 return createForwardingObjectiveBuilder(selector, treatmentBuilder.build(), MIN_PRIORITY);
819 }
820
821 @Override
822 public ForwardingObjective.Builder createDownBuilder(PortNumber uplinkPort,
823 PortNumber subscriberPort,
824 MeterId downstreamMeterId,
Tunahan Sezena07fe962021-02-24 08:24:24 +0000825 UniTagInformation tagInformation,
826 Optional<MacAddress> macAddress) {
Andrea Campanella327c5722020-01-30 11:34:13 +0100827
828 //subscriberVlan can be any valid Vlan here including ANY to make sure the packet is tagged
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000829 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder()
830 .matchVlanId(tagInformation.getPonSTag())
831 .matchInPort(uplinkPort)
Andrea Campanella090e4a02020-02-05 13:53:55 +0100832 .matchInnerVlanId(tagInformation.getPonCTag());
833
834
835 if (tagInformation.getPonCTag().toShort() != VlanId.ANY_VALUE) {
836 selectorBuilder.matchMetadata(tagInformation.getPonCTag().toShort());
837 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000838
839 if (tagInformation.getDsPonSTagPriority() != NO_PCP) {
840 selectorBuilder.matchVlanPcp((byte) tagInformation.getDsPonSTagPriority());
841 }
842
Tunahan Sezena07fe962021-02-24 08:24:24 +0000843 macAddress.ifPresent(selectorBuilder::matchEthDst);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000844
845 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder()
846 .popVlan()
Andrea Campanella327c5722020-01-30 11:34:13 +0100847 .setOutput(subscriberPort);
848
Andrea Campanella327c5722020-01-30 11:34:13 +0100849 treatmentBuilder.writeMetadata(createMetadata(tagInformation.getPonCTag(),
850 tagInformation.getTechnologyProfileId(),
851 subscriberPort), 0);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000852
Andrea Campanella981e86c2021-03-12 11:35:33 +0100853 // Upstream pbit is used to remark inner vlan pbit.
854 // Upstream is used to avoid trusting the BNG to send the packet with correct pbit.
855 // this is done because ds mode 0 is used because ds mode 3 or 6 that allow for
856 // all pbit acceptance are not widely supported by vendors even though present in
857 // the OMCI spec.
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000858 if (tagInformation.getUsPonCTagPriority() != NO_PCP) {
859 treatmentBuilder.setVlanPcp((byte) tagInformation.getUsPonCTagPriority());
860 }
861
Andrea Campanella9a779292020-02-03 19:19:09 +0100862 if (!VlanId.NONE.equals(tagInformation.getUniTagMatch()) &&
863 tagInformation.getPonCTag().toShort() != VlanId.ANY_VALUE) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000864 treatmentBuilder.setVlanId(tagInformation.getUniTagMatch());
865 }
866
867 if (downstreamMeterId != null) {
868 treatmentBuilder.meter(downstreamMeterId);
869 }
870
871 return createForwardingObjectiveBuilder(selectorBuilder.build(), treatmentBuilder.build(), MIN_PRIORITY);
872 }
873
Andrea Campanella600d2e22020-06-22 11:00:31 +0200874 @Override
875 public void clearDeviceState(DeviceId deviceId) {
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100876 pendingEapolForDevice.remove(deviceId);
Andrea Campanella600d2e22020-06-22 11:00:31 +0200877 }
878
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000879 private DefaultForwardingObjective.Builder createForwardingObjectiveBuilder(TrafficSelector selector,
880 TrafficTreatment treatment,
881 Integer priority) {
882 return DefaultForwardingObjective.builder()
883 .withFlag(ForwardingObjective.Flag.VERSATILE)
884 .withPriority(priority)
885 .makePermanent()
886 .withSelector(selector)
887 .fromApp(appId)
888 .withTreatment(treatment);
889 }
890
891 /**
892 * Returns the write metadata value including tech profile reference and innerVlan.
893 * For param cVlan, null can be sent
894 *
895 * @param cVlan c (customer) tag of one subscriber
896 * @param techProfileId tech profile id of one subscriber
897 * @return the write metadata value including tech profile reference and innerVlan
898 */
899 private Long createTechProfValueForWm(VlanId cVlan, int techProfileId) {
900 if (cVlan == null || VlanId.NONE.equals(cVlan)) {
901 return (long) techProfileId << 32;
902 }
903 return ((long) (cVlan.id()) << 48 | (long) techProfileId << 32);
904 }
905
906 private BandwidthProfileInformation getBandwidthProfileInformation(String bandwidthProfile) {
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000907 if (bpService == null) {
908 log.warn(SADIS_NOT_RUNNING);
909 return null;
910 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000911 if (bandwidthProfile == null) {
912 return null;
913 }
914 return bpService.get(bandwidthProfile);
915 }
916
917 /**
918 * It will be used to support AT&T use case (for EAPOL flows).
919 * If multiple services are found in uniServiceList, returns default tech profile id
920 * If one service is found, returns the found one
921 *
922 * @param devId
923 * @param portNumber
924 * @return the default technology profile id
925 */
926 private int getDefaultTechProfileId(DeviceId devId, PortNumber portNumber) {
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000927 if (subsService == null) {
928 log.warn(SADIS_NOT_RUNNING);
929 return defaultTechProfileId;
930 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000931 Port port = deviceService.getPort(devId, portNumber);
932 if (port != null) {
933 SubscriberAndDeviceInformation info = subsService.get(port.annotations().value(AnnotationKeys.PORT_NAME));
934 if (info != null && info.uniTagList().size() == 1) {
935 return info.uniTagList().get(0).getTechnologyProfileId();
936 }
937 }
938 return defaultTechProfileId;
939 }
940
941 /**
942 * Write metadata instruction value (metadata) is 8 bytes.
943 * <p>
944 * MS 2 bytes: C Tag
945 * Next 2 bytes: Technology Profile Id
946 * Next 4 bytes: Port number (uni or nni)
947 */
948 private Long createMetadata(VlanId innerVlan, int techProfileId, PortNumber egressPort) {
949 if (techProfileId == NONE_TP_ID) {
Andrea Campanella7c49b792020-05-11 11:36:53 +0200950 techProfileId = DEFAULT_TP_ID_DEFAULT;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000951 }
952
953 return ((long) (innerVlan.id()) << 48 | (long) techProfileId << 32) | egressPort.toLong();
954 }
955
956
957}