blob: 466d363f42d94893afd3bf2e108fd496e52758a1 [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;
Matteo Scandolo3a037a32020-04-01 12:17:50 -070030import org.onosproject.net.ConnectPoint;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000031import org.onosproject.net.DeviceId;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000032import org.onosproject.net.PortNumber;
33import org.onosproject.net.device.DeviceService;
34import org.onosproject.net.flow.DefaultTrafficSelector;
35import org.onosproject.net.flow.DefaultTrafficTreatment;
36import org.onosproject.net.flow.TrafficSelector;
37import org.onosproject.net.flow.TrafficTreatment;
38import org.onosproject.net.flow.criteria.Criteria;
39import org.onosproject.net.flowobjective.DefaultFilteringObjective;
40import org.onosproject.net.flowobjective.DefaultForwardingObjective;
41import org.onosproject.net.flowobjective.FilteringObjective;
42import org.onosproject.net.flowobjective.FlowObjectiveService;
43import org.onosproject.net.flowobjective.ForwardingObjective;
44import org.onosproject.net.flowobjective.Objective;
45import org.onosproject.net.flowobjective.ObjectiveContext;
46import org.onosproject.net.flowobjective.ObjectiveError;
47import org.onosproject.net.meter.MeterId;
Ilayda Ozdemir90a93622021-02-25 09:40:58 +000048import org.onosproject.store.serializers.KryoNamespaces;
49import org.onosproject.store.service.Serializer;
50import org.onosproject.store.service.StorageService;
Tunahan Sezenf0843b92021-04-30 07:13:16 +000051import org.opencord.olt.AccessDevicePort;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000052import org.opencord.olt.internalapi.AccessDeviceFlowService;
53import org.opencord.olt.internalapi.AccessDeviceMeterService;
54import org.opencord.sadis.BandwidthProfileInformation;
55import org.opencord.sadis.BaseInformationService;
56import org.opencord.sadis.SadisService;
57import org.opencord.sadis.SubscriberAndDeviceInformation;
58import org.opencord.sadis.UniTagInformation;
59import org.osgi.service.component.ComponentContext;
60import org.osgi.service.component.annotations.Activate;
61import org.osgi.service.component.annotations.Component;
62import org.osgi.service.component.annotations.Deactivate;
63import org.osgi.service.component.annotations.Modified;
64import org.osgi.service.component.annotations.Reference;
65import org.osgi.service.component.annotations.ReferenceCardinality;
Ilayda Ozdemir90a93622021-02-25 09:40:58 +000066import org.osgi.service.component.annotations.ReferencePolicy;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000067import org.slf4j.Logger;
68
Andrea Campanella7a1d7e72020-11-05 10:40:10 +010069import java.util.Dictionary;
Ilayda Ozdemir90a93622021-02-25 09:40:58 +000070import java.util.Map;
Andrea Campanellabfb47af2021-06-03 11:09:45 +020071import java.util.Optional;
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)
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000191 .register(AccessDevicePort.class)
192 .register(AccessDevicePort.Type.class)
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000193 .register(LinkedBlockingQueue.class)
194 .build();
195 pendingEapolForDevice = storageService.<DeviceId, BlockingQueue<SubscriberFlowInfo>>consistentMapBuilder()
196 .withName("volt-pending-eapol")
197 .withSerializer(Serializer.using(serializer))
198 .withApplicationId(appId)
199 .build().asJavaMap();
Andrea Campanellafee86422020-06-04 16:01:27 +0200200 log.info("started");
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000201 }
202
203
204 @Deactivate
205 public void deactivate(ComponentContext context) {
206 componentConfigService.unregisterProperties(getClass(), false);
Andrea Campanellafee86422020-06-04 16:01:27 +0200207 log.info("stopped");
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000208 }
209
210 @Modified
211 public void modified(ComponentContext context) {
212
213 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
214
Saurav Dasf62cea82020-08-26 17:43:04 -0700215 Boolean o = Tools.isPropertyEnabled(properties, ENABLE_DHCP_ON_NNI);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000216 if (o != null) {
Saurav Dasf62cea82020-08-26 17:43:04 -0700217 enableDhcpOnNni = o;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000218 }
219
Andrea Campanella7c49b792020-05-11 11:36:53 +0200220 Boolean v4 = Tools.isPropertyEnabled(properties, ENABLE_DHCP_V4);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000221 if (v4 != null) {
222 enableDhcpV4 = v4;
223 }
224
Andrea Campanella7c49b792020-05-11 11:36:53 +0200225 Boolean v6 = Tools.isPropertyEnabled(properties, ENABLE_DHCP_V6);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000226 if (v6 != null) {
227 enableDhcpV6 = v6;
228 }
229
Saurav Dasf62cea82020-08-26 17:43:04 -0700230 Boolean p = Tools.isPropertyEnabled(properties, ENABLE_IGMP_ON_NNI);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000231 if (p != null) {
Saurav Dasf62cea82020-08-26 17:43:04 -0700232 enableIgmpOnNni = p;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000233 }
234
Andrea Campanella7c49b792020-05-11 11:36:53 +0200235 Boolean eap = Tools.isPropertyEnabled(properties, ENABLE_EAPOL);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000236 if (eap != null) {
237 enableEapol = eap;
238 }
239
Gustavo Silva5c492dd2021-02-12 10:21:11 -0300240 Boolean pppoe = Tools.isPropertyEnabled(properties, ENABLE_PPPOE);
241 if (pppoe != null) {
242 enablePppoe = pppoe;
243 }
244
Andrea Campanella7c49b792020-05-11 11:36:53 +0200245 String tpId = get(properties, DEFAULT_TP_ID);
246 defaultTechProfileId = isNullOrEmpty(tpId) ? DEFAULT_TP_ID_DEFAULT : Integer.parseInt(tpId.trim());
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000247
Saurav Dasf62cea82020-08-26 17:43:04 -0700248 log.info("modified. Values = enableDhcpOnNni: {}, enableDhcpV4: {}, " +
249 "enableDhcpV6:{}, enableIgmpOnNni:{}, " +
Andrea Campanella438e1ad2021-03-26 11:41:16 +0100250 "enableEapol:{}, enablePppoe:{}, defaultTechProfileId:{}",
Saurav Dasf62cea82020-08-26 17:43:04 -0700251 enableDhcpOnNni, enableDhcpV4, enableDhcpV6,
Gustavo Silva5c492dd2021-02-12 10:21:11 -0300252 enableIgmpOnNni, enableEapol, enablePppoe,
253 defaultTechProfileId);
Andrea Campanellafee86422020-06-04 16:01:27 +0200254
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000255 }
256
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000257 protected void bindSadisService(SadisService service) {
258 sadisService = service;
259 bpService = sadisService.getBandwidthProfileService();
260 subsService = sadisService.getSubscriberInfoService();
261 log.info("Sadis-service binds to onos.");
262 }
263
264 protected void unbindSadisService(SadisService service) {
265 sadisService = null;
266 bpService = null;
267 subsService = null;
268 log.info("Sadis-service unbinds from onos.");
269 }
270
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000271 @Override
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000272 public void processDhcpFilteringObjectives(AccessDevicePort port,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000273 MeterId upstreamMeterId,
274 UniTagInformation tagInformation,
275 boolean install,
Tunahan Sezena07fe962021-02-24 08:24:24 +0000276 boolean upstream,
277 Optional<CompletableFuture<ObjectiveError>> dhcpFuture) {
Saurav Dasf62cea82020-08-26 17:43:04 -0700278 if (upstream) {
279 // for UNI ports
280 if (tagInformation != null && !tagInformation.getIsDhcpRequired()) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000281 log.debug("Dhcp provisioning is disabled for UNI port {} for service {}",
282 port, 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) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000289 log.debug("Dhcp provisioning is disabled for NNI port {}", port);
Tunahan Sezena07fe962021-02-24 08:24:24 +0000290 dhcpFuture.ifPresent(f -> f.complete(null));
Saurav Dasf62cea82020-08-26 17:43:04 -0700291 return;
292 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000293 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000294 int techProfileId = tagInformation != null ? tagInformation.getTechnologyProfileId() : NONE_TP_ID;
295 VlanId cTag = tagInformation != null ? tagInformation.getPonCTag() : VlanId.NONE;
296 VlanId unitagMatch = tagInformation != null ? tagInformation.getUniTagMatch() : VlanId.ANY;
Andrea Campanella3a96ce82021-02-09 12:32:42 +0100297 Byte vlanPcp = tagInformation != null && tagInformation.getUsPonCTagPriority() != NO_PCP
298 ? (byte) tagInformation.getUsPonCTagPriority() : null;
Andrea Campanella0e34f562020-06-11 10:47:10 +0200299
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000300
301 if (enableDhcpV4) {
302 int udpSrc = (upstream) ? 68 : 67;
303 int udpDst = (upstream) ? 67 : 68;
304
305 EthType ethType = EthType.EtherType.IPV4.ethType();
306 byte protocol = IPv4.PROTOCOL_UDP;
307
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000308 addDhcpFilteringObjectives(port, udpSrc, udpDst, ethType,
Andrea Campanella0e34f562020-06-11 10:47:10 +0200309 upstreamMeterId, techProfileId, protocol, cTag, unitagMatch,
Tunahan Sezena07fe962021-02-24 08:24:24 +0000310 vlanPcp, upstream, install, dhcpFuture);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000311 }
312
313 if (enableDhcpV6) {
314 int udpSrc = (upstream) ? 547 : 546;
315 int udpDst = (upstream) ? 546 : 547;
316
317 EthType ethType = EthType.EtherType.IPV6.ethType();
318 byte protocol = IPv6.PROTOCOL_UDP;
319
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000320 addDhcpFilteringObjectives(port, udpSrc, udpDst, ethType,
Andrea Campanella0e34f562020-06-11 10:47:10 +0200321 upstreamMeterId, techProfileId, protocol, cTag, unitagMatch,
Tunahan Sezena07fe962021-02-24 08:24:24 +0000322 vlanPcp, upstream, install, dhcpFuture);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000323 }
324 }
325
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000326 private void addDhcpFilteringObjectives(AccessDevicePort port, int udpSrc, int udpDst,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000327 EthType ethType, MeterId upstreamMeterId, int techProfileId, byte protocol,
Andrea Campanella0e34f562020-06-11 10:47:10 +0200328 VlanId cTag, VlanId unitagMatch,
329 Byte vlanPcp, boolean upstream,
Tunahan Sezena07fe962021-02-24 08:24:24 +0000330 boolean install, Optional<CompletableFuture<ObjectiveError>> dhcpFuture) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000331
332 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
333 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
334
335 if (upstreamMeterId != null) {
336 treatmentBuilder.meter(upstreamMeterId);
337 }
338
339 if (techProfileId != NONE_TP_ID) {
340 treatmentBuilder.writeMetadata(createTechProfValueForWm(unitagMatch, techProfileId), 0);
341 }
342
343 FilteringObjective.Builder dhcpUpstreamBuilder = (install ? builder.permit() : builder.deny())
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000344 .withKey(Criteria.matchInPort(port.number()))
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000345 .addCondition(Criteria.matchEthType(ethType))
346 .addCondition(Criteria.matchIPProtocol(protocol))
347 .addCondition(Criteria.matchUdpSrc(TpPort.tpPort(udpSrc)))
348 .addCondition(Criteria.matchUdpDst(TpPort.tpPort(udpDst)))
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000349 .fromApp(appId)
350 .withPriority(MAX_PRIORITY);
351
Andrea Campanella0e34f562020-06-11 10:47:10 +0200352 //VLAN changes and PCP matching need to happen only in the upstream directions
353 if (upstream) {
354 treatmentBuilder.setVlanId(cTag);
355 if (!VlanId.vlanId(VlanId.NO_VID).equals(unitagMatch)) {
356 dhcpUpstreamBuilder.addCondition(Criteria.matchVlanId(unitagMatch));
357 }
358 if (vlanPcp != null) {
359 treatmentBuilder.setVlanPcp(vlanPcp);
360 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000361 }
362
Andrea Campanella0e34f562020-06-11 10:47:10 +0200363 dhcpUpstreamBuilder.withMeta(treatmentBuilder
364 .setOutput(PortNumber.CONTROLLER).build());
365
366
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000367 FilteringObjective dhcpUpstream = dhcpUpstreamBuilder.add(new ObjectiveContext() {
368 @Override
369 public void onSuccess(Objective objective) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000370 log.info("DHCP {} filter for {} {}.",
371 (ethType.equals(EthType.EtherType.IPV4.ethType())) ? V4 : V6, port,
372 (install) ? INSTALLED : REMOVED);
Tunahan Sezena07fe962021-02-24 08:24:24 +0000373 dhcpFuture.ifPresent(f -> f.complete(null));
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000374 }
375
376 @Override
377 public void onError(Objective objective, ObjectiveError error) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000378 log.error("DHCP {} filter for {} failed {} because {}",
379 (ethType.equals(EthType.EtherType.IPV4.ethType())) ? V4 : V6, port,
380 (install) ? INSTALLATION : REMOVAL,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000381 error);
Tunahan Sezena07fe962021-02-24 08:24:24 +0000382 dhcpFuture.ifPresent(f -> f.complete(error));
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000383 }
384 });
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000385 flowObjectiveService.filter(port.deviceId(), dhcpUpstream);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000386
387 }
388
389 @Override
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000390 public void processPPPoEDFilteringObjectives(AccessDevicePort port,
Gustavo Silva5c492dd2021-02-12 10:21:11 -0300391 MeterId upstreamMeterId,
392 UniTagInformation tagInformation,
393 boolean install,
394 boolean upstream) {
395 if (!enablePppoe) {
396 log.debug("PPPoED filtering is disabled. Ignoring request.");
397 return;
398 }
399
400 int techProfileId = NONE_TP_ID;
401 VlanId cTag = VlanId.NONE;
402 VlanId unitagMatch = VlanId.ANY;
403 Byte vlanPcp = null;
404
405 if (tagInformation != null) {
406 techProfileId = tagInformation.getTechnologyProfileId();
407 cTag = tagInformation.getPonCTag();
408 unitagMatch = tagInformation.getUniTagMatch();
409 if (tagInformation.getUsPonCTagPriority() != NO_PCP) {
410 vlanPcp = (byte) tagInformation.getUsPonCTagPriority();
411 }
412 }
413
414 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
415 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
416 CompletableFuture<Object> meterFuture = new CompletableFuture<>();
417
418 if (upstreamMeterId != null) {
419 treatmentBuilder.meter(upstreamMeterId);
420 }
421
422 if (techProfileId != NONE_TP_ID) {
423 treatmentBuilder.writeMetadata(createTechProfValueForWm(cTag, techProfileId), 0);
424 }
425
426 DefaultFilteringObjective.Builder pppoedBuilder = (install ? builder.permit() : builder.deny())
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000427 .withKey(Criteria.matchInPort(port.number()))
Gustavo Silva5c492dd2021-02-12 10:21:11 -0300428 .addCondition(Criteria.matchEthType(EthType.EtherType.PPPoED.ethType()))
429 .fromApp(appId)
430 .withPriority(10000);
431
432 if (upstream) {
433 treatmentBuilder.setVlanId(cTag);
434 if (!VlanId.vlanId(VlanId.NO_VID).equals(unitagMatch)) {
435 pppoedBuilder.addCondition(Criteria.matchVlanId(unitagMatch));
436 }
437 if (vlanPcp != null) {
438 treatmentBuilder.setVlanPcp(vlanPcp);
439 }
440 }
441 pppoedBuilder = pppoedBuilder.withMeta(treatmentBuilder.setOutput(PortNumber.CONTROLLER).build());
442
443 FilteringObjective pppoed = pppoedBuilder
444 .add(new ObjectiveContext() {
445 @Override
446 public void onSuccess(Objective objective) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000447 log.info("PPPoED filter for {} {}.", port, (install) ? INSTALLED : REMOVED);
Gustavo Silva5c492dd2021-02-12 10:21:11 -0300448 }
449
450 @Override
451 public void onError(Objective objective, ObjectiveError error) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000452 log.info("PPPoED filter for {} failed {} because {}", port,
453 (install) ? INSTALLATION : REMOVAL, error);
Gustavo Silva5c492dd2021-02-12 10:21:11 -0300454 }
455 });
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000456 flowObjectiveService.filter(port.deviceId(), pppoed);
Gustavo Silva5c492dd2021-02-12 10:21:11 -0300457 }
458
459 @Override
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000460 public void processIgmpFilteringObjectives(AccessDevicePort port,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000461 MeterId upstreamMeterId,
462 UniTagInformation tagInformation,
463 boolean install,
464 boolean upstream) {
Saurav Dasf62cea82020-08-26 17:43:04 -0700465 if (upstream) {
466 // for UNI ports
467 if (tagInformation != null && !tagInformation.getIsIgmpRequired()) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000468 log.debug("Igmp provisioning is disabled for UNI port {} for service {}",
469 port, tagInformation.getServiceName());
Saurav Dasf62cea82020-08-26 17:43:04 -0700470 return;
471 }
472 } else {
473 // for NNI ports
474 if (!enableIgmpOnNni) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000475 log.debug("Igmp provisioning is disabled for NNI port {}", port);
Saurav Dasf62cea82020-08-26 17:43:04 -0700476 return;
477 }
Matteo Scandolo34556e52020-05-08 12:34:13 -0700478 }
479
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000480 log.debug("{} IGMP flows on {}", (install) ? "Installing" : "Removing", port);
Andrea Campanella0e34f562020-06-11 10:47:10 +0200481 DefaultFilteringObjective.Builder filterBuilder = DefaultFilteringObjective.builder();
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000482 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
483 if (upstream) {
484
485 if (tagInformation.getTechnologyProfileId() != NONE_TP_ID) {
486 treatmentBuilder.writeMetadata(createTechProfValueForWm(null,
487 tagInformation.getTechnologyProfileId()), 0);
488 }
489
490
491 if (upstreamMeterId != null) {
492 treatmentBuilder.meter(upstreamMeterId);
493 }
494
Andrea Campanella0e34f562020-06-11 10:47:10 +0200495 if (!VlanId.vlanId(VlanId.NO_VID).equals(tagInformation.getUniTagMatch())) {
496 filterBuilder.addCondition(Criteria.matchVlanId(tagInformation.getUniTagMatch()));
497 }
498
499 if (!VlanId.vlanId(VlanId.NO_VID).equals(tagInformation.getPonCTag())) {
500 treatmentBuilder.setVlanId(tagInformation.getPonCTag());
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000501 }
502
503 if (tagInformation.getUsPonCTagPriority() != NO_PCP) {
Andrea Campanella0e34f562020-06-11 10:47:10 +0200504 treatmentBuilder.setVlanPcp((byte) tagInformation.getUsPonCTagPriority());
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000505 }
506 }
507
Andrea Campanella0e34f562020-06-11 10:47:10 +0200508 filterBuilder = install ? filterBuilder.permit() : filterBuilder.deny();
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000509
Andrea Campanella0e34f562020-06-11 10:47:10 +0200510 FilteringObjective igmp = filterBuilder
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000511 .withKey(Criteria.matchInPort(port.number()))
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000512 .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
513 .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_IGMP))
514 .withMeta(treatmentBuilder
515 .setOutput(PortNumber.CONTROLLER).build())
516 .fromApp(appId)
517 .withPriority(MAX_PRIORITY)
518 .add(new ObjectiveContext() {
519 @Override
520 public void onSuccess(Objective objective) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000521 log.info("Igmp filter for {} {}.", port, (install) ? INSTALLED : REMOVED);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000522 }
523
524 @Override
525 public void onError(Objective objective, ObjectiveError error) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000526 log.error("Igmp filter for {} failed {} because {}.", port, (install) ? INSTALLATION : REMOVAL,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000527 error);
528 }
529 });
530
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000531 flowObjectiveService.filter(port.deviceId(), igmp);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000532 }
533
534 @Override
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000535 public void processEapolFilteringObjectives(AccessDevicePort port, String bpId,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000536 CompletableFuture<ObjectiveError> filterFuture,
537 VlanId vlanId, boolean install) {
538
539 if (!enableEapol) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000540 log.debug("Eapol filtering is disabled. Completing filteringFuture immediately for the device {}",
541 port.deviceId());
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000542 if (filterFuture != null) {
543 filterFuture.complete(null);
544 }
545 return;
546 }
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000547 log.info("Processing EAPOL with Bandwidth profile {} on {}", bpId, port);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000548 BandwidthProfileInformation bpInfo = getBandwidthProfileInformation(bpId);
549 if (bpInfo == null) {
550 log.warn("Bandwidth profile {} is not found. Authentication flow"
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000551 + " will not be installed on {}", bpId, port);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000552 if (filterFuture != null) {
553 filterFuture.complete(ObjectiveError.BADPARAMS);
554 }
555 return;
556 }
557
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000558 ConnectPoint cp = new ConnectPoint(port.deviceId(), port.number());
Andrea Campanella0e34f562020-06-11 10:47:10 +0200559 DefaultFilteringObjective.Builder filterBuilder = DefaultFilteringObjective.builder();
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000560 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
561 CompletableFuture<Object> meterFuture = new CompletableFuture<>();
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000562 // check if meter exists and create it only for an install
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000563 final MeterId meterId = oltMeterService.getMeterIdFromBpMapping(port.deviceId(), bpInfo.id());
564 log.info("Meter id {} for Bandwidth profile {} associated to EAPOL on {}",
565 meterId, bpInfo.id(), port.deviceId());
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000566 if (meterId == null) {
567 if (install) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000568 log.debug("Need to install meter for EAPOL with bwp {} on {}", bpInfo.id(), port);
569 SubscriberFlowInfo fi = new SubscriberFlowInfo(null, port,
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200570 new UniTagInformation.Builder()
571 .setPonCTag(vlanId).build(),
572 null, null,
573 null, bpInfo.id());
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000574 pendingEapolForDevice.compute(port.deviceId(), (id, queue) -> {
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100575 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
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000583 if (!oltMeterService.checkAndAddPendingMeter(port.deviceId(), bpInfo)) {
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200584 return;
585 }
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000586 MeterId innerMeterId = oltMeterService.createMeter(port.deviceId(), bpInfo, meterFuture);
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200587 fi.setUpMeterId(innerMeterId);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000588 } else {
589 // this case should not happen as the request to remove an eapol
590 // flow should mean that the flow points to a meter that exists.
591 // Nevertheless we can still delete the flow as we only need the
592 // correct 'match' to do so.
593 log.warn("Unknown meter id for bp {}, still proceeding with "
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000594 + "delete of eapol flow on {}", bpInfo.id(), port);
595 SubscriberFlowInfo fi = new SubscriberFlowInfo(null, port,
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200596 new UniTagInformation.Builder()
597 .setPonCTag(vlanId).build(),
598 null, meterId,
599 null, bpInfo.id());
Andrea Campanella0e34f562020-06-11 10:47:10 +0200600 handleEapol(filterFuture, install, cp, filterBuilder, treatmentBuilder, fi, meterId);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000601 }
602 } else {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000603 log.debug("Meter {} was previously created for bp {} on {}", meterId, bpInfo.id(), port);
604 SubscriberFlowInfo fi = new SubscriberFlowInfo(null, port,
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200605 new UniTagInformation.Builder()
606 .setPonCTag(vlanId).build(),
607 null, meterId,
608 null, bpInfo.id());
Andrea Campanella0e34f562020-06-11 10:47:10 +0200609 handleEapol(filterFuture, install, cp, filterBuilder, treatmentBuilder, fi, meterId);
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200610 //No need for the future, meter is present.
611 return;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000612 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000613 meterFuture.thenAcceptAsync(result -> {
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200614 //for each pending eapol flow we check if the meter is there.
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000615 BlockingQueue<SubscriberFlowInfo> queue = pendingEapolForDevice.get(port.deviceId());
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100616 if (queue != null) {
617 while (true) {
618 SubscriberFlowInfo fi = queue.remove();
619 if (fi == null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000620 pendingEapolForDevice.replace(port.deviceId(), queue);
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100621 break;
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200622 }
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100623 //TODO this might return the reference and not the actual object
624 // so it can be actually swapped underneath us.
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000625 log.debug("handing pending eapol on {} for {}", fi.getUniPort(), fi);
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100626 if (result == null) {
627 MeterId mId = oltMeterService
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000628 .getMeterIdFromBpMapping(port.deviceId(), fi.getUpBpInfo());
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100629 if (mId != null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000630 log.debug("Meter installation completed for subscriber on {}, " +
631 "handling EAPOL trap flow", port);
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100632 handleEapol(filterFuture, install, cp, filterBuilder, treatmentBuilder, fi, mId);
633 }
634 } else {
635 log.warn("Meter installation error while sending EAPOL trap flow to {}. " +
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000636 "Result {} and MeterId {}", port, result,
637 meterId);
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100638 }
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000639 oltMeterService.removeFromPendingMeters(port.deviceId(), bpInfo);
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200640 }
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100641 } else {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000642 log.info("No pending EAPOLs on {}", port.deviceId());
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) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000652 log.info("Meter {} for {} on {} exists. {} EAPOL trap flow",
653 mId, fi.getUpBpInfo(), fi.getUniPort(),
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200654 (install) ? "Installing" : "Removing");
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000655 int techProfileId = getDefaultTechProfileId(fi.getUniPort());
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200656 // 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())
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000662 .withKey(Criteria.matchInPort(fi.getUniPort().number()))
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200663 .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) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000677 log.info("Eapol filter {} for {} on {} with meter {}.",
678 objective.id(), (install) ? INSTALLED : REMOVED, fi.getUniPort(), mId);
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200679 if (filterFuture != null) {
680 filterFuture.complete(null);
681 }
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200682 }
683
684 @Override
685 public void onError(Objective objective, ObjectiveError error) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000686 log.error("Eapol filter {} for {} with meter {} " +
687 "failed {} because {}", objective.id(), fi.getUniPort(), mId,
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200688 (install) ? INSTALLATION : REMOVAL,
689 error);
690 if (filterFuture != null) {
691 filterFuture.complete(error);
692 }
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200693 }
694 });
695 flowObjectiveService.filter(fi.getDevId(), eapol);
696 }
697
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000698 /**
699 * Installs trap filtering objectives for particular traffic types on an
700 * NNI port.
701 *
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000702 * @param nniPort NNI port
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000703 * @param install true to install, false to remove
704 */
705 @Override
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000706 public void processNniFilteringObjectives(AccessDevicePort nniPort, boolean install) {
707 log.info("{} flows for NNI port {}",
708 install ? "Adding" : "Removing", nniPort);
709 processLldpFilteringObjective(nniPort, install);
710 processDhcpFilteringObjectives(nniPort, null, null, install, false, Optional.empty());
711 processIgmpFilteringObjectives(nniPort, null, null, install, false);
712 processPPPoEDFilteringObjectives(nniPort, null, null, install, false);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000713 }
714
715
716 @Override
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000717 public void processLldpFilteringObjective(AccessDevicePort port, boolean install) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000718 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
719
720 FilteringObjective lldp = (install ? builder.permit() : builder.deny())
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000721 .withKey(Criteria.matchInPort(port.number()))
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000722 .addCondition(Criteria.matchEthType(EthType.EtherType.LLDP.ethType()))
723 .withMeta(DefaultTrafficTreatment.builder()
724 .setOutput(PortNumber.CONTROLLER).build())
725 .fromApp(appId)
726 .withPriority(MAX_PRIORITY)
727 .add(new ObjectiveContext() {
728 @Override
729 public void onSuccess(Objective objective) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000730 log.info("LLDP filter for {} {}.", port, (install) ? INSTALLED : REMOVED);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000731 }
732
733 @Override
734 public void onError(Objective objective, ObjectiveError error) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000735 log.error("LLDP filter for {} failed {} because {}", port, (install) ? INSTALLATION : REMOVAL,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000736 error);
737 }
738 });
739
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000740 flowObjectiveService.filter(port.deviceId(), lldp);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000741 }
742
743 @Override
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000744 public ForwardingObjective.Builder createTransparentBuilder(AccessDevicePort uplinkPort,
745 AccessDevicePort subscriberPort,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000746 MeterId meterId,
747 UniTagInformation tagInfo,
748 boolean upstream) {
749
750 TrafficSelector selector = DefaultTrafficSelector.builder()
751 .matchVlanId(tagInfo.getPonSTag())
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000752 .matchInPort(upstream ? subscriberPort.number() : uplinkPort.number())
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000753 .matchInnerVlanId(tagInfo.getPonCTag())
754 .build();
755
756 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
757 if (meterId != null) {
758 tBuilder.meter(meterId);
759 }
760
761 TrafficTreatment treatment = tBuilder
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000762 .setOutput(upstream ? uplinkPort.number() : subscriberPort.number())
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000763 .writeMetadata(createMetadata(upstream ? tagInfo.getPonSTag() : tagInfo.getPonCTag(),
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000764 tagInfo.getTechnologyProfileId(),
765 upstream ? uplinkPort.number() : subscriberPort.number()), 0)
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000766 .build();
767
768 return createForwardingObjectiveBuilder(selector, treatment, MIN_PRIORITY);
769 }
770
771 @Override
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000772 public ForwardingObjective.Builder createUpBuilder(AccessDevicePort uplinkPort,
773 AccessDevicePort subscriberPort,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000774 MeterId upstreamMeterId,
775 UniTagInformation uniTagInformation) {
776
777 TrafficSelector selector = DefaultTrafficSelector.builder()
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000778 .matchInPort(subscriberPort.number())
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000779 .matchVlanId(uniTagInformation.getUniTagMatch())
780 .build();
781
Andrea Campanella327c5722020-01-30 11:34:13 +0100782 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
783 //if the subscriberVlan (cTag) is different than ANY it needs to set.
784 if (uniTagInformation.getPonCTag().toShort() != VlanId.ANY_VALUE) {
785 treatmentBuilder.pushVlan()
786 .setVlanId(uniTagInformation.getPonCTag());
787 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000788
789 if (uniTagInformation.getUsPonCTagPriority() != NO_PCP) {
790 treatmentBuilder.setVlanPcp((byte) uniTagInformation.getUsPonCTagPriority());
791 }
792
793 treatmentBuilder.pushVlan()
794 .setVlanId(uniTagInformation.getPonSTag());
795
796 if (uniTagInformation.getUsPonSTagPriority() != NO_PCP) {
797 treatmentBuilder.setVlanPcp((byte) uniTagInformation.getUsPonSTagPriority());
798 }
799
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000800 treatmentBuilder.setOutput(uplinkPort.number())
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000801 .writeMetadata(createMetadata(uniTagInformation.getPonCTag(),
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000802 uniTagInformation.getTechnologyProfileId(), uplinkPort.number()), 0L);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000803
804 if (upstreamMeterId != null) {
805 treatmentBuilder.meter(upstreamMeterId);
806 }
807
808 return createForwardingObjectiveBuilder(selector, treatmentBuilder.build(), MIN_PRIORITY);
809 }
810
811 @Override
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000812 public ForwardingObjective.Builder createDownBuilder(AccessDevicePort uplinkPort,
813 AccessDevicePort subscriberPort,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000814 MeterId downstreamMeterId,
Tunahan Sezena07fe962021-02-24 08:24:24 +0000815 UniTagInformation tagInformation,
816 Optional<MacAddress> macAddress) {
Andrea Campanella327c5722020-01-30 11:34:13 +0100817
818 //subscriberVlan can be any valid Vlan here including ANY to make sure the packet is tagged
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000819 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder()
820 .matchVlanId(tagInformation.getPonSTag())
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000821 .matchInPort(uplinkPort.number())
Andrea Campanella090e4a02020-02-05 13:53:55 +0100822 .matchInnerVlanId(tagInformation.getPonCTag());
823
824
825 if (tagInformation.getPonCTag().toShort() != VlanId.ANY_VALUE) {
826 selectorBuilder.matchMetadata(tagInformation.getPonCTag().toShort());
827 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000828
829 if (tagInformation.getDsPonSTagPriority() != NO_PCP) {
830 selectorBuilder.matchVlanPcp((byte) tagInformation.getDsPonSTagPriority());
831 }
832
Tunahan Sezena07fe962021-02-24 08:24:24 +0000833 macAddress.ifPresent(selectorBuilder::matchEthDst);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000834
835 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder()
836 .popVlan()
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000837 .setOutput(subscriberPort.number());
Andrea Campanella327c5722020-01-30 11:34:13 +0100838
Andrea Campanella327c5722020-01-30 11:34:13 +0100839 treatmentBuilder.writeMetadata(createMetadata(tagInformation.getPonCTag(),
840 tagInformation.getTechnologyProfileId(),
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000841 subscriberPort.number()), 0);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000842
Andrea Campanella981e86c2021-03-12 11:35:33 +0100843 // Upstream pbit is used to remark inner vlan pbit.
844 // Upstream is used to avoid trusting the BNG to send the packet with correct pbit.
845 // this is done because ds mode 0 is used because ds mode 3 or 6 that allow for
846 // all pbit acceptance are not widely supported by vendors even though present in
847 // the OMCI spec.
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000848 if (tagInformation.getUsPonCTagPriority() != NO_PCP) {
849 treatmentBuilder.setVlanPcp((byte) tagInformation.getUsPonCTagPriority());
850 }
851
Andrea Campanella9a779292020-02-03 19:19:09 +0100852 if (!VlanId.NONE.equals(tagInformation.getUniTagMatch()) &&
853 tagInformation.getPonCTag().toShort() != VlanId.ANY_VALUE) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000854 treatmentBuilder.setVlanId(tagInformation.getUniTagMatch());
855 }
856
857 if (downstreamMeterId != null) {
858 treatmentBuilder.meter(downstreamMeterId);
859 }
860
861 return createForwardingObjectiveBuilder(selectorBuilder.build(), treatmentBuilder.build(), MIN_PRIORITY);
862 }
863
Andrea Campanella600d2e22020-06-22 11:00:31 +0200864 @Override
865 public void clearDeviceState(DeviceId deviceId) {
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100866 pendingEapolForDevice.remove(deviceId);
Andrea Campanella600d2e22020-06-22 11:00:31 +0200867 }
868
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000869 private DefaultForwardingObjective.Builder createForwardingObjectiveBuilder(TrafficSelector selector,
870 TrafficTreatment treatment,
871 Integer priority) {
872 return DefaultForwardingObjective.builder()
873 .withFlag(ForwardingObjective.Flag.VERSATILE)
874 .withPriority(priority)
875 .makePermanent()
876 .withSelector(selector)
877 .fromApp(appId)
878 .withTreatment(treatment);
879 }
880
881 /**
882 * Returns the write metadata value including tech profile reference and innerVlan.
883 * For param cVlan, null can be sent
884 *
885 * @param cVlan c (customer) tag of one subscriber
886 * @param techProfileId tech profile id of one subscriber
887 * @return the write metadata value including tech profile reference and innerVlan
888 */
889 private Long createTechProfValueForWm(VlanId cVlan, int techProfileId) {
890 if (cVlan == null || VlanId.NONE.equals(cVlan)) {
891 return (long) techProfileId << 32;
892 }
893 return ((long) (cVlan.id()) << 48 | (long) techProfileId << 32);
894 }
895
896 private BandwidthProfileInformation getBandwidthProfileInformation(String bandwidthProfile) {
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000897 if (bpService == null) {
898 log.warn(SADIS_NOT_RUNNING);
899 return null;
900 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000901 if (bandwidthProfile == null) {
902 return null;
903 }
904 return bpService.get(bandwidthProfile);
905 }
906
907 /**
908 * It will be used to support AT&T use case (for EAPOL flows).
909 * If multiple services are found in uniServiceList, returns default tech profile id
910 * If one service is found, returns the found one
911 *
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000912 * @param port uni port
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000913 * @return the default technology profile id
914 */
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000915 private int getDefaultTechProfileId(AccessDevicePort port) {
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000916 if (subsService == null) {
917 log.warn(SADIS_NOT_RUNNING);
918 return defaultTechProfileId;
919 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000920 if (port != null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000921 SubscriberAndDeviceInformation info = subsService.get(port.name());
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000922 if (info != null && info.uniTagList().size() == 1) {
923 return info.uniTagList().get(0).getTechnologyProfileId();
924 }
925 }
926 return defaultTechProfileId;
927 }
928
929 /**
930 * Write metadata instruction value (metadata) is 8 bytes.
931 * <p>
932 * MS 2 bytes: C Tag
933 * Next 2 bytes: Technology Profile Id
934 * Next 4 bytes: Port number (uni or nni)
935 */
936 private Long createMetadata(VlanId innerVlan, int techProfileId, PortNumber egressPort) {
937 if (techProfileId == NONE_TP_ID) {
Andrea Campanella7c49b792020-05-11 11:36:53 +0200938 techProfileId = DEFAULT_TP_ID_DEFAULT;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000939 }
940
941 return ((long) (innerVlan.id()) << 48 | (long) techProfileId << 32) | egressPort.toLong();
942 }
943
944
945}