blob: 7a1cdc7a8f25664d39eb575362019761c6af05d1 [file] [log] [blame]
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001/*
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07002 * Copyright 2021-present Open Networking Foundation
Andrea Campanellacbbb7952019-11-25 06:38:41 +00003 *
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 */
Matteo Scandoloaa2adde2021-09-13 12:45:32 -070016
Andrea Campanellacbbb7952019-11-25 06:38:41 +000017package org.opencord.olt.impl;
18
Matteo Scandoloaa2adde2021-09-13 12:45:32 -070019import com.google.common.collect.ImmutableMap;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000020import org.onlab.packet.EthType;
21import org.onlab.packet.IPv4;
22import org.onlab.packet.IPv6;
23import org.onlab.packet.MacAddress;
24import org.onlab.packet.TpPort;
25import org.onlab.packet.VlanId;
Ilayda Ozdemir90a93622021-02-25 09:40:58 +000026import org.onlab.util.KryoNamespace;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000027import org.onlab.util.Tools;
28import org.onosproject.cfg.ComponentConfigService;
29import org.onosproject.core.ApplicationId;
30import org.onosproject.core.CoreService;
Andrea Campanella40d2b342022-02-04 18:13:37 +010031import org.onosproject.net.AnnotationKeys;
yasin saplib4b8ee12021-06-13 18:25:20 +000032import org.onosproject.net.Annotations;
Matteo Scandolo3a037a32020-04-01 12:17:50 -070033import org.onosproject.net.ConnectPoint;
yasin saplib4b8ee12021-06-13 18:25:20 +000034import org.onosproject.net.DefaultAnnotations;
Andrea Campanella40d2b342022-02-04 18:13:37 +010035import org.onosproject.net.DefaultPort;
Matteo Scandoloaa2adde2021-09-13 12:45:32 -070036import org.onosproject.net.Device;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000037import org.onosproject.net.DeviceId;
Matteo Scandoloaa2adde2021-09-13 12:45:32 -070038import org.onosproject.net.Host;
39import org.onosproject.net.Port;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000040import org.onosproject.net.PortNumber;
41import org.onosproject.net.device.DeviceService;
42import org.onosproject.net.flow.DefaultTrafficSelector;
43import org.onosproject.net.flow.DefaultTrafficTreatment;
Matteo Scandoloaa2adde2021-09-13 12:45:32 -070044import org.onosproject.net.flow.FlowRule;
45import org.onosproject.net.flow.FlowRuleEvent;
46import org.onosproject.net.flow.FlowRuleListener;
47import org.onosproject.net.flow.FlowRuleService;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000048import org.onosproject.net.flow.TrafficSelector;
49import org.onosproject.net.flow.TrafficTreatment;
50import org.onosproject.net.flow.criteria.Criteria;
Matteo Scandoloaa2adde2021-09-13 12:45:32 -070051import org.onosproject.net.flow.criteria.Criterion;
Matteo Scandoloaa2adde2021-09-13 12:45:32 -070052import org.onosproject.net.flow.criteria.VlanIdCriterion;
53import org.onosproject.net.flow.instructions.L2ModificationInstruction;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000054import org.onosproject.net.flowobjective.DefaultFilteringObjective;
55import org.onosproject.net.flowobjective.DefaultForwardingObjective;
56import org.onosproject.net.flowobjective.FilteringObjective;
57import org.onosproject.net.flowobjective.FlowObjectiveService;
58import org.onosproject.net.flowobjective.ForwardingObjective;
59import org.onosproject.net.flowobjective.Objective;
60import org.onosproject.net.flowobjective.ObjectiveContext;
61import org.onosproject.net.flowobjective.ObjectiveError;
Matteo Scandoloaa2adde2021-09-13 12:45:32 -070062import org.onosproject.net.host.HostService;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000063import org.onosproject.net.meter.MeterId;
Ilayda Ozdemir90a93622021-02-25 09:40:58 +000064import org.onosproject.store.serializers.KryoNamespaces;
65import org.onosproject.store.service.Serializer;
66import org.onosproject.store.service.StorageService;
Gustavo Silva29fb20e2022-05-26 09:59:54 -030067import org.opencord.olt.AccessDevicePort;
68import org.opencord.olt.DiscoveredSubscriber;
69import org.opencord.olt.OltDeviceServiceInterface;
70import org.opencord.olt.OltFlowServiceInterface;
71import org.opencord.olt.OltMeterServiceInterface;
72import org.opencord.olt.OltPortStatus;
73import org.opencord.olt.ServiceKey;
74import org.opencord.olt.OltFlowsStatus;
75import org.opencord.olt.FlowDirection;
76import org.opencord.olt.FlowOperation;
Harsh Awasthic1e4bf52022-02-09 14:14:14 +053077import org.opencord.olt.impl.fttb.FttbUtils;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000078import org.opencord.sadis.BandwidthProfileInformation;
79import org.opencord.sadis.BaseInformationService;
80import org.opencord.sadis.SadisService;
81import org.opencord.sadis.SubscriberAndDeviceInformation;
82import org.opencord.sadis.UniTagInformation;
83import org.osgi.service.component.ComponentContext;
84import org.osgi.service.component.annotations.Activate;
85import org.osgi.service.component.annotations.Component;
86import org.osgi.service.component.annotations.Deactivate;
87import org.osgi.service.component.annotations.Modified;
88import org.osgi.service.component.annotations.Reference;
89import org.osgi.service.component.annotations.ReferenceCardinality;
Ilayda Ozdemir90a93622021-02-25 09:40:58 +000090import org.osgi.service.component.annotations.ReferencePolicy;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000091import org.slf4j.Logger;
Matteo Scandoloaa2adde2021-09-13 12:45:32 -070092import org.slf4j.LoggerFactory;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000093
Matteo Scandolo2542e5d2021-12-01 16:53:41 -080094import java.util.ArrayList;
Andrea Campanella7a1d7e72020-11-05 10:40:10 +010095import java.util.Dictionary;
Matteo Scandoloaa2adde2021-09-13 12:45:32 -070096import java.util.HashMap;
Andrea Campanella61650a12022-01-24 18:09:44 -080097import java.util.HashSet;
Matteo Scandoloaa2adde2021-09-13 12:45:32 -070098import java.util.Iterator;
Matteo Scandolo2542e5d2021-12-01 16:53:41 -080099import java.util.List;
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000100import java.util.Map;
Andrea Campanellabfb47af2021-06-03 11:09:45 +0200101import java.util.Optional;
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100102import java.util.Properties;
Andrea Campanella61650a12022-01-24 18:09:44 -0800103import java.util.Set;
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700104import java.util.concurrent.atomic.AtomicBoolean;
105import java.util.concurrent.locks.Lock;
106import java.util.concurrent.locks.ReentrantReadWriteLock;
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100107
108import static com.google.common.base.Strings.isNullOrEmpty;
109import static org.onlab.util.Tools.get;
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700110import static org.opencord.olt.impl.OltUtils.completeFlowOpToString;
111import static org.opencord.olt.impl.OltUtils.flowOpToString;
112import static org.opencord.olt.impl.OltUtils.getPortName;
113import static org.opencord.olt.impl.OltUtils.portWithName;
114import static org.opencord.olt.impl.OsgiPropertyConstants.DEFAULT_TP_ID;
115import static org.opencord.olt.impl.OsgiPropertyConstants.DEFAULT_TP_ID_DEFAULT;
116import static org.opencord.olt.impl.OsgiPropertyConstants.DOWNSTREAM_OLT;
117import static org.opencord.olt.impl.OsgiPropertyConstants.DOWNSTREAM_ONU;
118import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_DHCP_ON_NNI;
119import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_DHCP_ON_NNI_DEFAULT;
120import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_DHCP_V4;
121import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_DHCP_V4_DEFAULT;
122import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_DHCP_V6;
123import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_DHCP_V6_DEFAULT;
124import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_EAPOL;
125import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_EAPOL_DEFAULT;
126import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_IGMP_ON_NNI;
127import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_IGMP_ON_NNI_DEFAULT;
yasin sapli0823c932022-01-26 11:26:09 +0000128import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_PPPOE_ON_NNI;
129import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_PPPOE_ON_NNI_DEFAULT;
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700130import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_PPPOE;
131import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_PPPOE_DEFAULT;
Harsh Awasthic1e4bf52022-02-09 14:14:14 +0530132import static org.opencord.olt.impl.fttb.FttbUtils.FTTB_FLOW_DIRECTION;
133import static org.opencord.olt.impl.fttb.FttbUtils.FTTB_FLOW_DOWNSTREAM;
134import static org.opencord.olt.impl.fttb.FttbUtils.FTTB_FLOW_UPSTREAM;
135import static org.opencord.olt.impl.fttb.FttbUtils.FTTB_SERVICE_DPU_ANCP_TRAFFIC;
136import static org.opencord.olt.impl.fttb.FttbUtils.FTTB_SERVICE_DPU_MGMT_TRAFFIC;
137import static org.opencord.olt.impl.fttb.FttbUtils.FTTB_SERVICE_NAME;
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700138import static org.opencord.olt.impl.OsgiPropertyConstants.UPSTREAM_OLT;
139import static org.opencord.olt.impl.OsgiPropertyConstants.UPSTREAM_ONU;
140import static org.opencord.olt.impl.OsgiPropertyConstants.WAIT_FOR_REMOVAL;
141import static org.opencord.olt.impl.OsgiPropertyConstants.WAIT_FOR_REMOVAL_DEFAULT;
Harsh Awasthic1e4bf52022-02-09 14:14:14 +0530142import static org.opencord.olt.impl.fttb.FttbUtils.FTTB_SERVICE_SUBSCRIBER_TRAFFIC;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000143
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000144@Component(immediate = true, property = {
Saurav Dasf62cea82020-08-26 17:43:04 -0700145 ENABLE_DHCP_ON_NNI + ":Boolean=" + ENABLE_DHCP_ON_NNI_DEFAULT,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000146 ENABLE_DHCP_V4 + ":Boolean=" + ENABLE_DHCP_V4_DEFAULT,
147 ENABLE_DHCP_V6 + ":Boolean=" + ENABLE_DHCP_V6_DEFAULT,
Saurav Dasf62cea82020-08-26 17:43:04 -0700148 ENABLE_IGMP_ON_NNI + ":Boolean=" + ENABLE_IGMP_ON_NNI_DEFAULT,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000149 ENABLE_EAPOL + ":Boolean=" + ENABLE_EAPOL_DEFAULT,
yasin sapli0823c932022-01-26 11:26:09 +0000150 ENABLE_PPPOE_ON_NNI + ":Boolean=" + ENABLE_PPPOE_ON_NNI_DEFAULT,
Gustavo Silva5c492dd2021-02-12 10:21:11 -0300151 ENABLE_PPPOE + ":Boolean=" + ENABLE_PPPOE_DEFAULT,
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700152 DEFAULT_TP_ID + ":Integer=" + DEFAULT_TP_ID_DEFAULT,
153 // FIXME remove this option as potentially dangerous in production
154 WAIT_FOR_REMOVAL + ":Boolean=" + WAIT_FOR_REMOVAL_DEFAULT
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000155})
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700156public class OltFlowService implements OltFlowServiceInterface {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000157
158 @Reference(cardinality = ReferenceCardinality.MANDATORY)
159 protected CoreService coreService;
160
161 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700162 protected ComponentConfigService cfgService;
163
164 @Reference(cardinality = ReferenceCardinality.MANDATORY)
165 protected FlowObjectiveService flowObjectiveService;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000166
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000167 @Reference(cardinality = ReferenceCardinality.OPTIONAL,
168 bind = "bindSadisService",
169 unbind = "unbindSadisService",
170 policy = ReferencePolicy.DYNAMIC)
171 protected volatile SadisService sadisService;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000172
173 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700174 protected OltMeterServiceInterface oltMeterService;
175
176 @Reference(cardinality = ReferenceCardinality.MANDATORY)
177 protected OltDeviceServiceInterface oltDeviceService;
178
179 @Reference(cardinality = ReferenceCardinality.MANDATORY)
180 protected FlowRuleService flowRuleService;
181
182 @Reference(cardinality = ReferenceCardinality.MANDATORY)
183 protected HostService hostService;
184
185 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000186 protected DeviceService deviceService;
187
188 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000189 protected StorageService storageService;
190
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700191 protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
192 protected BaseInformationService<BandwidthProfileInformation> bpService;
193
194 private static final String APP_NAME = "org.opencord.olt";
195 protected ApplicationId appId;
196 private static final Integer MAX_PRIORITY = 10000;
197 private static final Integer MIN_PRIORITY = 1000;
Harsh Awasthic1e4bf52022-02-09 14:14:14 +0530198 public static final short EAPOL_DEFAULT_VLAN = 4091;
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700199 private static final int NONE_TP_ID = -1;
200 private static final String V4 = "V4";
201 private static final String V6 = "V6";
202 private final Logger log = LoggerFactory.getLogger(getClass());
203
204 protected UniTagInformation defaultEapolUniTag = new UniTagInformation.Builder()
205 .setServiceName("defaultEapol").build();
206 protected UniTagInformation nniUniTag = new UniTagInformation.Builder()
207 .setServiceName("nni")
208 .setTechnologyProfileId(NONE_TP_ID)
209 .setPonCTag(VlanId.NONE)
210 .setUniTagMatch(VlanId.ANY)
211 .setUsPonCTagPriority(-1)
212 .build();
213
214 /**
215 * Connect Point status map.
216 * Used to keep track of which cp has flows that needs to be removed when the status changes.
217 */
218 protected Map<ServiceKey, OltPortStatus> cpStatus;
219 private final ReentrantReadWriteLock cpStatusLock = new ReentrantReadWriteLock();
220 private final Lock cpStatusWriteLock = cpStatusLock.writeLock();
221 private final Lock cpStatusReadLock = cpStatusLock.readLock();
222
223 /**
224 * This map contains the subscriber that have been provisioned by the operator.
225 * They may or may not have flows, depending on the port status.
226 * The map is used to define whether flows need to be provisioned when a port comes up.
227 */
228 protected Map<ServiceKey, Boolean> provisionedSubscribers;
229 private final ReentrantReadWriteLock provisionedSubscribersLock = new ReentrantReadWriteLock();
230 private final Lock provisionedSubscribersWriteLock = provisionedSubscribersLock.writeLock();
231 private final Lock provisionedSubscribersReadLock = provisionedSubscribersLock.readLock();
232
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000233 /**
amit.ghosh74a4bb22022-06-14 11:34:52 +0200234 * For storing the mapping of ConnectPoints to FTTB DPU MAC addresses.
235 */
236 protected Map<ConnectPoint, MacAddress> fttbMacAddresses;
237 private final ReentrantReadWriteLock fttbMacAddressesLock = new ReentrantReadWriteLock();
238 private final Lock fttbMacAddressesWriteLock = fttbMacAddressesLock.writeLock();
239
240 /**
Saurav Dasf62cea82020-08-26 17:43:04 -0700241 * Create DHCP trap flow on NNI port(s).
242 */
243 protected boolean enableDhcpOnNni = ENABLE_DHCP_ON_NNI_DEFAULT;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000244
245 /**
Saurav Dasf62cea82020-08-26 17:43:04 -0700246 * Enable flows for DHCP v4 if dhcp is required in sadis config.
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000247 **/
248 protected boolean enableDhcpV4 = ENABLE_DHCP_V4_DEFAULT;
249
250 /**
Saurav Dasf62cea82020-08-26 17:43:04 -0700251 * Enable flows for DHCP v6 if dhcp is required in sadis config.
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000252 **/
253 protected boolean enableDhcpV6 = ENABLE_DHCP_V6_DEFAULT;
254
255 /**
Saurav Dasf62cea82020-08-26 17:43:04 -0700256 * Create IGMP trap flow on NNI port(s).
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000257 **/
Saurav Dasf62cea82020-08-26 17:43:04 -0700258 protected boolean enableIgmpOnNni = ENABLE_IGMP_ON_NNI_DEFAULT;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000259
260 /**
261 * Send EAPOL authentication trap flows before subscriber provisioning.
262 **/
263 protected boolean enableEapol = ENABLE_EAPOL_DEFAULT;
264
265 /**
Gustavo Silva5c492dd2021-02-12 10:21:11 -0300266 * Send PPPoED authentication trap flows before subscriber provisioning.
267 **/
yasin sapli0823c932022-01-26 11:26:09 +0000268 protected boolean enablePppoeOnNni = ENABLE_PPPOE_ON_NNI_DEFAULT;
269
270 /**
271 * Enable flows for PPPoE if it is required in sadis config.
272 **/
Gustavo Silva5c492dd2021-02-12 10:21:11 -0300273 protected boolean enablePppoe = ENABLE_PPPOE_DEFAULT;
274
275 /**
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000276 * Default technology profile id that is used for authentication trap flows.
277 **/
278 protected int defaultTechProfileId = DEFAULT_TP_ID_DEFAULT;
279
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700280 protected boolean waitForRemoval = WAIT_FOR_REMOVAL_DEFAULT;
281
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700282 protected InternalFlowListener internalFlowListener;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000283
284 @Activate
285 public void activate(ComponentContext context) {
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700286 cfgService.registerProperties(getClass());
287 appId = coreService.registerApplication(APP_NAME);
288 internalFlowListener = new InternalFlowListener();
289
290 modified(context);
291
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000292 KryoNamespace serializer = KryoNamespace.newBuilder()
293 .register(KryoNamespaces.API)
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700294 .register(OltFlowsStatus.class)
295 .register(FlowDirection.class)
296 .register(OltPortStatus.class)
297 .register(OltFlowsStatus.class)
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000298 .register(AccessDevicePort.class)
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700299 .register(new ServiceKeySerializer(), ServiceKey.class)
300 .register(UniTagInformation.class)
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000301 .build();
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000302
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700303 cpStatus = storageService.<ServiceKey, OltPortStatus>consistentMapBuilder()
304 .withName("volt-cp-status")
305 .withApplicationId(appId)
306 .withSerializer(Serializer.using(serializer))
307 .build().asJavaMap();
308
309 provisionedSubscribers = storageService.<ServiceKey, Boolean>consistentMapBuilder()
310 .withName("volt-provisioned-subscriber")
311 .withApplicationId(appId)
312 .withSerializer(Serializer.using(serializer))
313 .build().asJavaMap();
314
amit.ghosh74a4bb22022-06-14 11:34:52 +0200315 KryoNamespace fttbMacSerializer = KryoNamespace.newBuilder()
316 .register(KryoNamespaces.API)
317 .register(ConnectPoint.class)
318 .register(MacAddress.class)
319 .build();
320
321 fttbMacAddresses = storageService.<ConnectPoint, MacAddress>consistentMapBuilder()
322 .withName("fttb-mac-addresses")
323 .withApplicationId(appId)
324 .withSerializer(Serializer.using(fttbMacSerializer))
325 .build().asJavaMap();
326
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700327 flowRuleService.addListener(internalFlowListener);
328
329 log.info("Started");
330 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000331
332 @Deactivate
333 public void deactivate(ComponentContext context) {
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700334 cfgService.unregisterProperties(getClass(), false);
335 flowRuleService.removeListener(internalFlowListener);
336 log.info("Stopped");
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000337 }
338
339 @Modified
340 public void modified(ComponentContext context) {
341
342 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
343
Saurav Dasf62cea82020-08-26 17:43:04 -0700344 Boolean o = Tools.isPropertyEnabled(properties, ENABLE_DHCP_ON_NNI);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000345 if (o != null) {
Saurav Dasf62cea82020-08-26 17:43:04 -0700346 enableDhcpOnNni = o;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000347 }
348
Andrea Campanella7c49b792020-05-11 11:36:53 +0200349 Boolean v4 = Tools.isPropertyEnabled(properties, ENABLE_DHCP_V4);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000350 if (v4 != null) {
351 enableDhcpV4 = v4;
352 }
353
Andrea Campanella7c49b792020-05-11 11:36:53 +0200354 Boolean v6 = Tools.isPropertyEnabled(properties, ENABLE_DHCP_V6);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000355 if (v6 != null) {
356 enableDhcpV6 = v6;
357 }
358
Saurav Dasf62cea82020-08-26 17:43:04 -0700359 Boolean p = Tools.isPropertyEnabled(properties, ENABLE_IGMP_ON_NNI);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000360 if (p != null) {
Saurav Dasf62cea82020-08-26 17:43:04 -0700361 enableIgmpOnNni = p;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000362 }
363
Andrea Campanella7c49b792020-05-11 11:36:53 +0200364 Boolean eap = Tools.isPropertyEnabled(properties, ENABLE_EAPOL);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000365 if (eap != null) {
366 enableEapol = eap;
367 }
368
yasin sapli0823c932022-01-26 11:26:09 +0000369 Boolean pppoeInNni = Tools.isPropertyEnabled(properties, ENABLE_PPPOE_ON_NNI);
370 if (pppoeInNni != null) {
371 enablePppoeOnNni = pppoeInNni;
372 }
373
Gustavo Silva5c492dd2021-02-12 10:21:11 -0300374 Boolean pppoe = Tools.isPropertyEnabled(properties, ENABLE_PPPOE);
375 if (pppoe != null) {
376 enablePppoe = pppoe;
377 }
378
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700379 Boolean wait = Tools.isPropertyEnabled(properties, WAIT_FOR_REMOVAL);
380 if (wait != null) {
381 waitForRemoval = wait;
382 }
383
Andrea Campanella7c49b792020-05-11 11:36:53 +0200384 String tpId = get(properties, DEFAULT_TP_ID);
385 defaultTechProfileId = isNullOrEmpty(tpId) ? DEFAULT_TP_ID_DEFAULT : Integer.parseInt(tpId.trim());
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000386
yasin sapli0823c932022-01-26 11:26:09 +0000387 log.info("Modified. Values = enableDhcpOnNni: {}, enableDhcpV4: {}, " + "enableDhcpV6:{}, " +
388 "enableIgmpOnNni:{}, " + "enableEapol:{}, enablePppoeOnNni: {}, enablePppoe:{}, " +
389 "defaultTechProfileId:{}," + "waitForRemoval:{}",
390 enableDhcpOnNni, enableDhcpV4, enableDhcpV6, enableIgmpOnNni, enableEapol,
391 enablePppoeOnNni, enablePppoe, defaultTechProfileId, waitForRemoval);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000392 }
393
394 @Override
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700395 public ImmutableMap<ServiceKey, OltPortStatus> getConnectPointStatus() {
396 try {
397 cpStatusReadLock.lock();
398 return ImmutableMap.copyOf(cpStatus);
399 } finally {
400 cpStatusReadLock.unlock();
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000401 }
402 }
403
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700404 @Override
405 public ImmutableMap<ServiceKey, UniTagInformation> getProgrammedSubscribers() {
406 // NOTE we might want to remove this conversion and directly use cpStatus as it contains
Matteo Scandolo2542e5d2021-12-01 16:53:41 -0800407 // all the required information about subscribers
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700408 Map<ServiceKey, UniTagInformation> subscribers =
409 new HashMap<>();
410 try {
411 cpStatusReadLock.lock();
412
413 cpStatus.forEach((sk, status) -> {
414 if (
415 // not NNI Port
416 !oltDeviceService.isNniPort(deviceService.getDevice(sk.getPort().connectPoint().deviceId()),
417 sk.getPort().connectPoint().port()) &&
418 // not EAPOL flow
Andrea Campanella982fd332022-01-19 09:14:12 +0100419 !sk.getService().equals(defaultEapolUniTag) &&
420 !status.subscriberFlowsStatus.equals(OltFlowsStatus.PENDING_REMOVE)
421 && !status.subscriberFlowsStatus.equals(OltFlowsStatus.REMOVED)
Matteo Scandolo2542e5d2021-12-01 16:53:41 -0800422
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700423 ) {
424 subscribers.put(sk, sk.getService());
425 }
426 });
427
428 return ImmutableMap.copyOf(subscribers);
429 } finally {
430 cpStatusReadLock.unlock();
431 }
432 }
433
434 @Override
435 public Map<ServiceKey, Boolean> getRequestedSubscribers() {
436 try {
437 provisionedSubscribersReadLock.lock();
438 return ImmutableMap.copyOf(provisionedSubscribers);
439 } finally {
440 provisionedSubscribersReadLock.unlock();
441 }
442 }
443
444 @Override
445 public void handleNniFlows(Device device, Port port, FlowOperation action) {
446
447 // always handle the LLDP flow
Matteo Scandolod7aa89c2021-12-07 10:21:34 -0800448 log.debug("{} LLDP trap flow on NNI {} for device {}", flowOpToString(action), portWithName(port), device.id());
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700449 processLldpFilteringObjective(device.id(), port, action);
450
451 if (enableDhcpOnNni) {
452 if (enableDhcpV4) {
Matteo Scandolod7aa89c2021-12-07 10:21:34 -0800453 log.debug("{} DHCPv4 trap flow on NNI {} for device {}", flowOpToString(action),
454 portWithName(port), device.id());
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700455 processDhcpFilteringObjectives(device.id(), port, action, FlowDirection.DOWNSTREAM,
456 67, 68, EthType.EtherType.IPV4.ethType(), IPv4.PROTOCOL_UDP,
457 null, null, nniUniTag);
458 }
459 if (enableDhcpV6) {
Matteo Scandolod7aa89c2021-12-07 10:21:34 -0800460 log.debug("{} DHCPv6 trap flow on NNI {} for device {}", flowOpToString(action),
461 portWithName(port), device.id());
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700462 processDhcpFilteringObjectives(device.id(), port, action, FlowDirection.DOWNSTREAM,
463 546, 547, EthType.EtherType.IPV6.ethType(), IPv6.PROTOCOL_UDP,
464 null, null, nniUniTag);
465 }
466 } else {
Matteo Scandolo1f8de332021-12-06 12:18:24 -0800467 log.debug("DHCP is not required on NNI {} for device {}", portWithName(port), device.id());
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700468 }
469
470 if (enableIgmpOnNni) {
Matteo Scandolod7aa89c2021-12-07 10:21:34 -0800471 log.debug("{} IGMP flow on NNI {} for device {}", flowOpToString(action), portWithName(port), device.id());
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700472 processIgmpFilteringObjectives(device.id(), port, action, FlowDirection.DOWNSTREAM,
473 null, null, NONE_TP_ID, VlanId.NONE, VlanId.ANY, -1);
474 }
475
yasin sapli0823c932022-01-26 11:26:09 +0000476 if (enablePppoeOnNni) {
Matteo Scandolod7aa89c2021-12-07 10:21:34 -0800477 log.debug("{} PPPoE flow on NNI {} for device {}", flowOpToString(action), port.number(), device.id());
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700478 processPPPoEDFilteringObjectives(device.id(), port, action, FlowDirection.DOWNSTREAM,
479 null, null, NONE_TP_ID, VlanId.NONE, VlanId.ANY, null);
480 }
481 }
482
483 @Override
484 public boolean handleBasicPortFlows(DiscoveredSubscriber sub, String bandwidthProfileId,
485 String oltBandwidthProfileId) {
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700486 // we only need to something if EAPOL is enabled
487 if (!enableEapol) {
Andrea Campanellaccb32862022-02-17 16:29:10 +0100488 log.debug("Eapol is disabled for {}", portWithName(sub.port));
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700489 return true;
490 }
491
492 if (sub.status == DiscoveredSubscriber.Status.ADDED) {
493 return addDefaultFlows(sub, bandwidthProfileId, oltBandwidthProfileId);
494 } else if (sub.status == DiscoveredSubscriber.Status.REMOVED) {
495 return removeDefaultFlows(sub, bandwidthProfileId, oltBandwidthProfileId);
496 } else {
497 log.error("Unknown Status {} on DiscoveredSubscriber {}", sub.status, sub);
498 return false;
499 }
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700500 }
501
502 private boolean addDefaultFlows(DiscoveredSubscriber sub, String bandwidthProfileId, String oltBandwidthProfileId) {
Andrea Campanellaccb32862022-02-17 16:29:10 +0100503 log.debug("Adding default flows for {}, status {}", portWithName(sub.port), sub.status);
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700504 if (!oltMeterService.createMeter(sub.device.id(), bandwidthProfileId)) {
505 if (log.isTraceEnabled()) {
506 log.trace("waiting on meter for bp {} and sub {}", bandwidthProfileId, sub);
507 }
508 return false;
509 }
510 if (hasDefaultEapol(sub.port)) {
Andrea Campanellaccb32862022-02-17 16:29:10 +0100511 OltPortStatus status = getOltPortStatus(sub.port, defaultEapolUniTag);
512 log.debug("Eapol is already present for {} with status {}", portWithName(sub.port), status);
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700513 return true;
514 }
515 return handleEapolFlow(sub, bandwidthProfileId,
516 oltBandwidthProfileId, FlowOperation.ADD, VlanId.vlanId(EAPOL_DEFAULT_VLAN));
517
518 }
519
520 private boolean removeDefaultFlows(DiscoveredSubscriber sub, String bandwidthProfile, String oltBandwidthProfile) {
521 // NOTE that we are not checking for meters as they must have been created to install the flow in first place
522 return handleEapolFlow(sub, bandwidthProfile, oltBandwidthProfile,
523 FlowOperation.REMOVE, VlanId.vlanId(EAPOL_DEFAULT_VLAN));
524 }
525
526 @Override
527 public boolean handleSubscriberFlows(DiscoveredSubscriber sub, String defaultBandwidthProfile,
528 String multicastServiceName) {
529 // NOTE that we are taking defaultBandwithProfile as a parameter as that can be configured in the Olt component
530 if (sub.status == DiscoveredSubscriber.Status.ADDED) {
531 return addSubscriberFlows(sub, defaultBandwidthProfile, multicastServiceName);
Andrea Campanella34ce61a2022-04-28 18:55:46 +0200532 } else if (sub.status == DiscoveredSubscriber.Status.REMOVED ||
533 sub.status == DiscoveredSubscriber.Status.ADMIN_REMOVED) {
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700534 return removeSubscriberFlows(sub, defaultBandwidthProfile, multicastServiceName);
535 } else {
536 log.error("don't know how to handle {}", sub);
537 return false;
538 }
539 }
540
541 private boolean addSubscriberFlows(DiscoveredSubscriber sub, String defaultBandwithProfile,
542 String multicastServiceName) {
543 if (log.isTraceEnabled()) {
544 log.trace("Provisioning of subscriber on {} started", portWithName(sub.port));
545 }
546 if (enableEapol) {
547 if (hasDefaultEapol(sub.port)) {
548 // remove EAPOL flow and throw exception so that we'll retry later
549 if (!isDefaultEapolPendingRemoval(sub.port)) {
550 removeDefaultFlows(sub, defaultBandwithProfile, defaultBandwithProfile);
551 }
552
553 if (waitForRemoval) {
554 // NOTE wait for removal is a flag only needed to make sure VOLTHA
555 // does not explode with the flows remove/add in the same batch
556 log.debug("Awaiting for default flows removal for {}", portWithName(sub.port));
557 return false;
558 } else {
559 log.warn("continuing provisioning on {}", portWithName(sub.port));
560 }
561 }
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700562 }
563
564 // NOTE createMeters will return if the meters are not installed
565 if (!oltMeterService.createMeters(sub.device.id(),
Matteo Scandolo88df8ae2021-11-23 13:12:29 -0800566 sub.subscriberAndDeviceInformation, multicastServiceName)) {
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700567 return false;
568 }
569
570 // NOTE we need to add the DHCP flow regardless so that the host can be discovered and the MacAddress added
571 handleSubscriberDhcpFlows(sub.device.id(), sub.port, FlowOperation.ADD,
572 sub.subscriberAndDeviceInformation);
573
574 if (isMacLearningEnabled(sub.subscriberAndDeviceInformation)
575 && !isMacAddressAvailable(sub.device.id(), sub.port,
576 sub.subscriberAndDeviceInformation)) {
577 log.debug("Awaiting for macAddress on {}", portWithName(sub.port));
578 return false;
579 }
580
Matteo Scandolo8a91c0f2021-12-03 10:58:14 -0800581 // NOTE that the EAPOL flows handling is based on the data-plane flows status
582 // always process them before
583 handleSubscriberEapolFlows(sub, FlowOperation.ADD, sub.subscriberAndDeviceInformation);
584
yasin sapli0823c932022-01-26 11:26:09 +0000585 handleSubscriberPppoeFlows(sub.device.id(), sub.port, FlowOperation.ADD, sub.subscriberAndDeviceInformation);
586
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700587 handleSubscriberDataFlows(sub.device, sub.port, FlowOperation.ADD,
588 sub.subscriberAndDeviceInformation, multicastServiceName);
589
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700590 handleSubscriberIgmpFlows(sub, FlowOperation.ADD);
591
592 log.info("Provisioning of subscriber on {} completed", portWithName(sub.port));
593 return true;
594 }
595
Matteo Scandolo97449bb2021-12-09 15:33:46 -0800596 protected boolean removeSubscriberFlows(DiscoveredSubscriber sub, String defaultBandwithProfile,
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700597 String multicastServiceName) {
598
599 if (log.isTraceEnabled()) {
600 log.trace("Removal of subscriber on {} started",
601 portWithName(sub.port));
602 }
Matteo Scandolo97449bb2021-12-09 15:33:46 -0800603 SubscriberAndDeviceInformation si = sub.subscriberAndDeviceInformation;
Andrea Campanella34ce61a2022-04-28 18:55:46 +0200604 //If the port has been removed the device service will return null, while it will be true if it's just disabled
605 boolean isPortPresent = deviceService.getPort(new ConnectPoint(sub.device.id(), sub.port.number())) != null;
606 if (log.isTraceEnabled()) {
607 log.trace("Port {} present: ", portWithName(sub.port), isPortPresent);
608 }
609 // Always remove the EAPOL flow in case of port disable,remove or subscriber remove.
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700610 if (enableEapol) {
611 // remove the tagged eapol
612 handleSubscriberEapolFlows(sub, FlowOperation.REMOVE, si);
Andrea Campanella34ce61a2022-04-28 18:55:46 +0200613 log.info("Removal of eapol flow for subscriber on {} completed", portWithName(sub.port));
614
Matteo Scandolo97449bb2021-12-09 15:33:46 -0800615 }
Andrea Campanella34ce61a2022-04-28 18:55:46 +0200616 // If the port is gone entirely (onu delete) or it's enabled (subscriber remove request) remove all the flows
617 // In the case the port is just disabled we remove only the EAPOL flow because the ONU disable only represents
618 // the UNI side of the ONU going down, either for RG cable detach or for an administrative decision, but the PON
619 // side is still up as nothing changed, so no need to add/remove flows, when and if the UNI comes up
620 // we will re-push the EAPOL flow to require the subscriber to auth again.
621 // When the subscriber is admin removed from REST or CLI we ignore the port status.
Andrea Campanella7ef88992022-05-17 12:38:00 +0200622 // Check the admin Status of the port
Andrea Campanella34ce61a2022-04-28 18:55:46 +0200623 if (!isPortPresent || sub.port.isEnabled() || sub.status == DiscoveredSubscriber.Status.ADMIN_REMOVED) {
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700624
Andrea Campanella34ce61a2022-04-28 18:55:46 +0200625 handleSubscriberDhcpFlows(sub.device.id(), sub.port, FlowOperation.REMOVE, si);
Matteo Scandolo97449bb2021-12-09 15:33:46 -0800626
Andrea Campanella34ce61a2022-04-28 18:55:46 +0200627 handleSubscriberPppoeFlows(sub.device.id(), sub.port, FlowOperation.REMOVE,
628 sub.subscriberAndDeviceInformation);
Matteo Scandolo97449bb2021-12-09 15:33:46 -0800629
Andrea Campanella34ce61a2022-04-28 18:55:46 +0200630 handleSubscriberDataFlows(sub.device, sub.port, FlowOperation.REMOVE, si, multicastServiceName);
631
632 handleSubscriberIgmpFlows(sub, FlowOperation.REMOVE);
633
634
635 if (enableEapol) {
636
637 // if any of the services still has flows, return false
638 Iterator<UniTagInformation> iter = sub.subscriberAndDeviceInformation.uniTagList().iterator();
639 while (iter.hasNext()) {
640 UniTagInformation entry = iter.next();
641 if (areSubscriberFlowsPendingRemoval(sub.port, entry, enableEapol)) {
642 log.info("Subscriber {} still have flows on service {}, postpone default EAPOL installation.",
643 portWithName(sub.port), entry.getServiceName());
644 return false;
645 }
646 }
647
648 // once the flows are removed add the default one back
649 // (only if the port is ENABLED and still present on the device)
650 if (sub.port.isEnabled() && deviceService.getPort(sub.device.id(), sub.port.number()) != null) {
651
652 // NOTE we remove the subscriber when the port goes down
653 // but in that case we don't need to add default eapol
654 handleEapolFlow(sub, defaultBandwithProfile, defaultBandwithProfile,
655 FlowOperation.ADD, VlanId.vlanId(EAPOL_DEFAULT_VLAN));
Matteo Scandolo97449bb2021-12-09 15:33:46 -0800656 }
657 }
Andrea Campanella34ce61a2022-04-28 18:55:46 +0200658 // FIXME check the return status of the flow and return accordingly
659 log.info("Removal of subscriber on {} completed", portWithName(sub.port));
660 return true;
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700661 }
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700662 return true;
663 }
664
665 @Override
666 public boolean hasDefaultEapol(Port port) {
667 OltPortStatus status = getOltPortStatus(port, defaultEapolUniTag);
668 // NOTE we consider ERROR as a present EAPOL flow as ONOS
669 // will keep trying to add it
670 return status != null && (status.defaultEapolStatus == OltFlowsStatus.ADDED ||
671 status.defaultEapolStatus == OltFlowsStatus.PENDING_ADD ||
672 status.defaultEapolStatus == OltFlowsStatus.ERROR);
673 }
674
675 private OltPortStatus getOltPortStatus(Port port, UniTagInformation uniTagInformation) {
676 try {
677 cpStatusReadLock.lock();
678 ServiceKey sk = new ServiceKey(new AccessDevicePort(port), uniTagInformation);
679 OltPortStatus status = cpStatus.get(sk);
680 return status;
681 } finally {
682 cpStatusReadLock.unlock();
683 }
684 }
685
686 public boolean isDefaultEapolPendingRemoval(Port port) {
687 OltPortStatus status = getOltPortStatus(port, defaultEapolUniTag);
688 if (log.isTraceEnabled()) {
689 log.trace("Status during EAPOL flow check {} for port {} and UniTagInformation {}",
690 status, portWithName(port), defaultEapolUniTag);
691 }
692 return status != null && status.defaultEapolStatus == OltFlowsStatus.PENDING_REMOVE;
693 }
694
695 @Override
696 public boolean hasDhcpFlows(Port port, UniTagInformation uti) {
697 OltPortStatus status = getOltPortStatus(port, uti);
698 if (log.isTraceEnabled()) {
699 log.trace("Status during DHCP flow check {} for port {} and service {}",
700 status, portWithName(port), uti.getServiceName());
701 }
702 return status != null &&
703 (status.dhcpStatus == OltFlowsStatus.ADDED ||
704 status.dhcpStatus == OltFlowsStatus.PENDING_ADD);
705 }
706
707 @Override
yasin sapli0823c932022-01-26 11:26:09 +0000708 public boolean hasPppoeFlows(Port port, UniTagInformation uti) {
709 OltPortStatus status = getOltPortStatus(port, uti);
710 if (log.isTraceEnabled()) {
711 log.trace("Status during PPPoE flow check {} for port {} and service {}",
712 status, portWithName(port), uti.getServiceName());
713 }
714 return status != null &&
715 (status.pppoeStatus == OltFlowsStatus.ADDED ||
716 status.pppoeStatus == OltFlowsStatus.PENDING_ADD);
717 }
718
719 @Override
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700720 public boolean hasSubscriberFlows(Port port, UniTagInformation uti) {
721
722 OltPortStatus status = getOltPortStatus(port, uti);
723 if (log.isTraceEnabled()) {
724 log.trace("Status during subscriber flow check {} for port {} and service {}",
725 status, portWithName(port), uti.getServiceName());
726 }
727 return status != null && (status.subscriberFlowsStatus == OltFlowsStatus.ADDED ||
728 status.subscriberFlowsStatus == OltFlowsStatus.PENDING_ADD);
729 }
730
Andrea Campanella87241ae2022-03-11 11:20:24 +0100731 public boolean areSubscriberFlowsPendingRemoval(Port port, UniTagInformation uti, boolean enableEapol) {
Matteo Scandolo97449bb2021-12-09 15:33:46 -0800732 OltPortStatus status = getOltPortStatus(port, uti);
733 if (log.isTraceEnabled()) {
734 log.trace("Status during pending_remove flow check {} for port {} and UniTagInformation {}",
735 status, portWithName(port), uti);
736 }
Andrea Campanella87241ae2022-03-11 11:20:24 +0100737 return status != null && (status.subscriberFlowsStatus == OltFlowsStatus.PENDING_REMOVE ||
738 (enableEapol && status.subscriberEapolStatus == OltFlowsStatus.PENDING_REMOVE) ||
739 (uti.getIsDhcpRequired() && status.dhcpStatus == OltFlowsStatus.PENDING_REMOVE));
Matteo Scandolo97449bb2021-12-09 15:33:46 -0800740 }
741
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700742 @Override
743 public void purgeDeviceFlows(DeviceId deviceId) {
744 log.debug("Purging flows on device {}", deviceId);
Matteo Scandolob6981dc2021-12-02 16:31:44 -0800745 flowRuleService.purgeFlowRules(deviceId);
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700746
747 // removing the status from the cpStatus map
Matteo Scandolo2542e5d2021-12-01 16:53:41 -0800748 if (log.isTraceEnabled()) {
749 log.trace("Clearing cp status from device {}", deviceId);
750 }
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700751 try {
752 cpStatusWriteLock.lock();
753 Iterator<Map.Entry<ServiceKey, OltPortStatus>> iter = cpStatus.entrySet().iterator();
754 while (iter.hasNext()) {
755 Map.Entry<ServiceKey, OltPortStatus> entry = iter.next();
756 if (entry.getKey().getPort().connectPoint().deviceId().equals(deviceId)) {
757 cpStatus.remove(entry.getKey());
758 }
759 }
760 } finally {
761 cpStatusWriteLock.unlock();
762 }
763
764 // removing subscribers from the provisioned map
Matteo Scandolo2542e5d2021-12-01 16:53:41 -0800765 if (log.isTraceEnabled()) {
766 log.trace("Clearing provisioned subscribers from device {}", deviceId);
767 }
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700768 try {
769 provisionedSubscribersWriteLock.lock();
770 Iterator<Map.Entry<ServiceKey, Boolean>> iter = provisionedSubscribers.entrySet().iterator();
771 while (iter.hasNext()) {
772 Map.Entry<ServiceKey, Boolean> entry = iter.next();
773 if (entry.getKey().getPort().connectPoint().deviceId().equals(deviceId)) {
774 provisionedSubscribers.remove(entry.getKey());
775 }
776 }
777 } finally {
778 provisionedSubscribersWriteLock.unlock();
779 }
Matteo Scandolo2542e5d2021-12-01 16:53:41 -0800780 log.debug("Done clearing up device flows and subscribers");
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700781 }
782
783 @Override
784 public boolean isSubscriberServiceProvisioned(AccessDevicePort cp) {
Andrea Campanella61650a12022-01-24 18:09:44 -0800785 Set<Map.Entry<ServiceKey, Boolean>> subs;
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700786 try {
787 provisionedSubscribersReadLock.lock();
Andrea Campanella61650a12022-01-24 18:09:44 -0800788 subs = new HashSet<>(provisionedSubscribers.entrySet());
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700789 } finally {
790 provisionedSubscribersReadLock.unlock();
791 }
Andrea Campanella61650a12022-01-24 18:09:44 -0800792
793 for (Map.Entry<ServiceKey, Boolean> entry : subs) {
794 if (entry.getKey().getPort().equals(cp) && entry.getValue()) {
795 return true;
796 }
797 }
798 return false;
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700799 }
800
801 @Override
802 public boolean isSubscriberServiceProvisioned(ServiceKey sk) {
803 try {
804 provisionedSubscribersReadLock.lock();
805 Boolean provisioned = provisionedSubscribers.get(sk);
806 if (provisioned == null || !provisioned) {
807 return false;
808 }
809 } finally {
810 provisionedSubscribersReadLock.unlock();
811 }
812 return true;
813 }
814
815 @Override
816 public void updateProvisionedSubscriberStatus(ServiceKey sk, Boolean status) {
817 try {
818 provisionedSubscribersWriteLock.lock();
819 provisionedSubscribers.put(sk, status);
820 } finally {
821 provisionedSubscribersWriteLock.unlock();
822 }
823 }
824
Matteo Scandolo97449bb2021-12-09 15:33:46 -0800825 protected boolean handleEapolFlow(DiscoveredSubscriber sub, String bandwidthProfile,
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700826 String oltBandwidthProfile, FlowOperation action, VlanId vlanId) {
827
828 // create a subscriberKey for the EAPOL flow
829 ServiceKey sk = new ServiceKey(new AccessDevicePort(sub.port), defaultEapolUniTag);
Andrea Campanella87241ae2022-03-11 11:20:24 +0100830 OltFlowsStatus status = action == FlowOperation.ADD ?
831 OltFlowsStatus.PENDING_ADD : OltFlowsStatus.PENDING_REMOVE;
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700832 if (vlanId.id().equals(EAPOL_DEFAULT_VLAN)) {
Andrea Campanella87241ae2022-03-11 11:20:24 +0100833 updateConnectPointStatus(sk, status, OltFlowsStatus.NONE, OltFlowsStatus.NONE,
834 OltFlowsStatus.NONE, OltFlowsStatus.NONE);
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700835
Andrea Campanella87241ae2022-03-11 11:20:24 +0100836 } else {
837 updateConnectPointStatus(sk, OltFlowsStatus.NONE, status, OltFlowsStatus.NONE,
838 OltFlowsStatus.NONE, OltFlowsStatus.NONE);
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700839 }
840
841 DefaultFilteringObjective.Builder filterBuilder = DefaultFilteringObjective.builder();
842 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
843
844 int techProfileId = getDefaultTechProfileId(sub.port);
845 MeterId meterId = oltMeterService.getMeterIdForBandwidthProfile(sub.device.id(), bandwidthProfile);
846
847 // in the delete case the meter should still be there as we remove
848 // the meters only if no flows are pointing to them
849 if (meterId == null) {
850 log.debug("MeterId is null for BandwidthProfile {} on device {}",
851 bandwidthProfile, sub.device.id());
852 return false;
853 }
854
855 MeterId oltMeterId = oltMeterService.getMeterIdForBandwidthProfile(sub.device.id(), oltBandwidthProfile);
856 if (oltMeterId == null) {
857 log.debug("MeterId is null for OltBandwidthProfile {} on device {}",
858 oltBandwidthProfile, sub.device.id());
859 return false;
860 }
861
862 log.info("{} EAPOL flow for {} with vlanId {} and BandwidthProfile {} (meterId {})",
863 flowOpToString(action), portWithName(sub.port), vlanId, bandwidthProfile, meterId);
864
865 FilteringObjective.Builder eapolAction;
866
867 if (action == FlowOperation.ADD) {
868 eapolAction = filterBuilder.permit();
869 } else if (action == FlowOperation.REMOVE) {
870 eapolAction = filterBuilder.deny();
871 } else {
872 log.error("Operation {} not supported", action);
873 return false;
874 }
875
876 FilteringObjective.Builder baseEapol = eapolAction
877 .withKey(Criteria.matchInPort(sub.port.number()))
878 .addCondition(Criteria.matchEthType(EthType.EtherType.EAPOL.ethType()));
879
880 // NOTE we only need to add the treatment to install the flow,
881 // we can remove it based in the match
882 FilteringObjective.Builder eapol;
883
Harsh Awasthi498b5c62022-03-21 23:19:46 +0530884 // Setting VlanId.NONE as cvlan in the metadata as the packet will be single tagged
885 // and cvlan should not be filled.
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700886 TrafficTreatment treatment = treatmentBuilder
887 .meter(meterId)
Harsh Awasthic1e4bf52022-02-09 14:14:14 +0530888 .writeMetadata(OltFlowServiceUtils.createTechProfValueForWriteMetadata(
Harsh Awasthi498b5c62022-03-21 23:19:46 +0530889 VlanId.NONE,
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700890 techProfileId, oltMeterId), 0)
891 .setOutput(PortNumber.CONTROLLER)
892 .pushVlan()
893 .setVlanId(vlanId)
894 .build();
895 eapol = baseEapol
896 .withMeta(treatment);
897
898 FilteringObjective eapolObjective = eapol
899 .fromApp(appId)
900 .withPriority(MAX_PRIORITY)
901 .add(new ObjectiveContext() {
902 @Override
903 public void onSuccess(Objective objective) {
904 log.info("EAPOL flow objective {} for {}",
905 completeFlowOpToString(action), portWithName(sub.port));
906 if (log.isTraceEnabled()) {
907 log.trace("EAPOL flow details for port {}: {}", portWithName(sub.port), objective);
908 }
909 }
910
911 @Override
912 public void onError(Objective objective, ObjectiveError error) {
913 log.error("Cannot {} eapol flow for {} : {}", action,
914 portWithName(sub.port), error);
915
916 if (vlanId.id().equals(EAPOL_DEFAULT_VLAN)) {
917 updateConnectPointStatus(sk,
Andrea Campanella87241ae2022-03-11 11:20:24 +0100918 OltFlowsStatus.ERROR, null, null, null, null);
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700919 }
920 }
921 });
922
923 flowObjectiveService.filter(sub.device.id(), eapolObjective);
924
925 log.info("{} EAPOL filter for {}", completeFlowOpToString(action), portWithName(sub.port));
926 return true;
927 }
928
929 // FIXME it's confusing that si is not necessarily inside the DiscoveredSubscriber
Matteo Scandolo97449bb2021-12-09 15:33:46 -0800930 protected boolean handleSubscriberEapolFlows(DiscoveredSubscriber sub, FlowOperation action,
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700931 SubscriberAndDeviceInformation si) {
932 if (!enableEapol) {
933 return true;
934 }
935 // TODO verify we need an EAPOL flow for EACH service
936 AtomicBoolean success = new AtomicBoolean(true);
937 si.uniTagList().forEach(u -> {
Andrea Campanella34ce61a2022-04-28 18:55:46 +0200938 //Always act on the eapol flow
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700939 log.info("{} EAPOL flows for subscriber {} on {} and service {}",
940 flowOpToString(action), si.id(), portWithName(sub.port), u.getServiceName());
941 if (!handleEapolFlow(sub, u.getUpstreamBandwidthProfile(),
942 u.getUpstreamOltBandwidthProfile(),
943 action, u.getPonCTag())) {
944 //
Andrea Campanella87241ae2022-03-11 11:20:24 +0100945 log.error("Failed to {} EAPOL with subscriber tags", action);
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700946 //TODO this sets it for all services, maybe some services succeeded.
947 success.set(false);
948 }
949 });
950 return success.get();
951 }
952
Matteo Scandolo97449bb2021-12-09 15:33:46 -0800953 protected void handleSubscriberIgmpFlows(DiscoveredSubscriber sub, FlowOperation action) {
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700954 sub.subscriberAndDeviceInformation.uniTagList().forEach(uti -> {
955 if (uti.getIsIgmpRequired()) {
956 DeviceId deviceId = sub.device.id();
957 // if we reached here a meter already exists
958 MeterId meterId = oltMeterService
959 .getMeterIdForBandwidthProfile(deviceId, uti.getUpstreamBandwidthProfile());
960 MeterId oltMeterId = oltMeterService
961 .getMeterIdForBandwidthProfile(deviceId, uti.getUpstreamOltBandwidthProfile());
962
963 processIgmpFilteringObjectives(deviceId, sub.port,
964 action, FlowDirection.UPSTREAM, meterId, oltMeterId, uti.getTechnologyProfileId(),
965 uti.getPonCTag(), uti.getUniTagMatch(), uti.getUsPonCTagPriority());
966 }
967 });
968 }
969
970 private boolean checkSadisRunning() {
971 if (bpService == null) {
972 log.warn("Sadis is not running");
973 return false;
974 }
975 return true;
976 }
977
978 private int getDefaultTechProfileId(Port port) {
979 if (!checkSadisRunning()) {
980 return defaultTechProfileId;
981 }
982 if (port != null) {
983 SubscriberAndDeviceInformation info = subsService.get(getPortName(port));
984 if (info != null && info.uniTagList().size() == 1) {
985 return info.uniTagList().get(0).getTechnologyProfileId();
986 }
987 }
988 return defaultTechProfileId;
989 }
990
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700991 private void processLldpFilteringObjective(DeviceId deviceId, Port port, FlowOperation action) {
992 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
993
994 FilteringObjective lldp = (action == FlowOperation.ADD ? builder.permit() : builder.deny())
995 .withKey(Criteria.matchInPort(port.number()))
996 .addCondition(Criteria.matchEthType(EthType.EtherType.LLDP.ethType()))
997 .withMeta(DefaultTrafficTreatment.builder()
998 .setOutput(PortNumber.CONTROLLER).build())
999 .fromApp(appId)
1000 .withPriority(MAX_PRIORITY)
1001 .add(new ObjectiveContext() {
1002 @Override
1003 public void onSuccess(Objective objective) {
1004 log.info("{} LLDP filter for {}.", completeFlowOpToString(action), portWithName(port));
1005 }
1006
1007 @Override
1008 public void onError(Objective objective, ObjectiveError error) {
1009 log.error("Falied to {} LLDP filter on {} because {}", action, portWithName(port),
1010 error);
1011 }
1012 });
1013
1014 flowObjectiveService.filter(deviceId, lldp);
1015 }
1016
1017 protected void handleSubscriberDhcpFlows(DeviceId deviceId, Port port,
1018 FlowOperation action,
1019 SubscriberAndDeviceInformation si) {
1020 si.uniTagList().forEach(uti -> {
1021
1022 if (!uti.getIsDhcpRequired()) {
1023 return;
1024 }
1025
1026 // if it's an ADD skip if flows are there,
1027 // if it's a DELETE skip if flows are not there
1028 boolean hasFlows = hasDhcpFlows(port, uti);
1029 if (action == FlowOperation.ADD && hasFlows ||
1030 action == FlowOperation.REMOVE && !hasFlows) {
1031 log.debug("Not dealing with DHCP {} on {} as DHCP flow status is {}", action,
1032 uti.getServiceName(), hasFlows);
1033 return;
1034 }
1035
1036 log.info("{} DHCP flows for subscriber on {} and service {}",
1037 flowOpToString(action), portWithName(port), uti.getServiceName());
1038
1039 // if we reached here a meter already exists
1040 MeterId meterId = oltMeterService
1041 .getMeterIdForBandwidthProfile(deviceId, uti.getUpstreamBandwidthProfile());
1042 MeterId oltMeterId = oltMeterService
1043 .getMeterIdForBandwidthProfile(deviceId, uti.getUpstreamOltBandwidthProfile());
1044
1045 if (enableDhcpV4) {
1046 processDhcpFilteringObjectives(deviceId, port, action, FlowDirection.UPSTREAM, 68, 67,
1047 EthType.EtherType.IPV4.ethType(), IPv4.PROTOCOL_UDP, meterId, oltMeterId,
1048 uti);
1049 }
1050 if (enableDhcpV6) {
1051 log.error("DHCP V6 not supported for subscribers");
1052 }
1053 });
1054 }
1055
yasin sapli0823c932022-01-26 11:26:09 +00001056 protected void handleSubscriberPppoeFlows(DeviceId deviceId, Port port,
1057 FlowOperation action,
1058 SubscriberAndDeviceInformation si) {
1059 si.uniTagList().forEach(uti -> {
1060
1061 if (!uti.getIsPppoeRequired()) {
1062 return;
1063 }
1064
1065 // if it's an ADD skip if flows are there,
1066 // if it's a DELETE skip if flows are not there
1067 boolean hasFlows = hasPppoeFlows(port, uti);
1068 if (action == FlowOperation.ADD && hasFlows ||
1069 action == FlowOperation.REMOVE && !hasFlows) {
1070 log.debug("Not dealing with PPPoE {} on {} as PPPoE flow status is {}", action,
1071 uti.getServiceName(), hasFlows);
1072 return;
1073 }
1074
1075 log.info("{} PPPoE flows for subscriber on {} and service {}",
1076 flowOpToString(action), portWithName(port), uti.getServiceName());
1077
1078 // if we reached here a meter already exists
1079 MeterId meterId = oltMeterService
1080 .getMeterIdForBandwidthProfile(deviceId, uti.getUpstreamBandwidthProfile());
1081 MeterId oltMeterId = oltMeterService
1082 .getMeterIdForBandwidthProfile(deviceId, uti.getUpstreamOltBandwidthProfile());
1083
1084 if (enablePppoe) {
1085 processPPPoEDFilteringObjectives(deviceId, port, action, FlowDirection.UPSTREAM, meterId, oltMeterId,
1086 uti.getTechnologyProfileId(), uti.getPonCTag(), uti.getUniTagMatch(),
1087 (byte) uti.getUsPonCTagPriority());
1088 }
1089 });
1090 }
1091
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001092 // FIXME return boolean, if this fails we need to retry
1093 protected void handleSubscriberDataFlows(Device device, Port port,
1094 FlowOperation action,
1095 SubscriberAndDeviceInformation si, String multicastServiceName) {
1096
1097 Optional<Port> nniPort = oltDeviceService.getNniPort(device);
Matteo Scandolo97449bb2021-12-09 15:33:46 -08001098 if (nniPort == null || nniPort.isEmpty()) {
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001099 log.error("Cannot configure DP flows as upstream port is not configured for subscriber {} on {}",
1100 si.id(), portWithName(port));
1101 return;
1102 }
1103 si.uniTagList().forEach(uti -> {
1104
1105 boolean hasFlows = hasSubscriberFlows(port, uti);
1106 if (action == FlowOperation.ADD && hasFlows ||
1107 action == FlowOperation.REMOVE && !hasFlows) {
1108 log.debug("Not dealing with DP flows {} on {} as subscriber flow status is {}", action,
1109 uti.getServiceName(), hasFlows);
1110 return;
1111 }
1112
1113 if (multicastServiceName.equals(uti.getServiceName())) {
1114 log.debug("This is the multicast service ({}) for subscriber {} on {}, " +
1115 "dataplane flows are not needed",
1116 uti.getServiceName(), si.id(), portWithName(port));
1117 return;
1118 }
1119
1120 log.info("{} Data plane flows for subscriber {} on {} and service {}",
1121 flowOpToString(action), si.id(), portWithName(port), uti.getServiceName());
Matteo Scandolo80f5e972021-12-02 14:59:15 -08001122 ServiceKey sk = new ServiceKey(new AccessDevicePort(port), uti);
1123 OltFlowsStatus status = action.equals(FlowOperation.ADD) ?
1124 OltFlowsStatus.PENDING_ADD : OltFlowsStatus.PENDING_REMOVE;
Andrea Campanella87241ae2022-03-11 11:20:24 +01001125 updateConnectPointStatus(sk, null, null, status, null, null);
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001126
1127 // upstream flows
1128 MeterId usMeterId = oltMeterService
1129 .getMeterIdForBandwidthProfile(device.id(), uti.getUpstreamBandwidthProfile());
1130 MeterId oltUsMeterId = oltMeterService
1131 .getMeterIdForBandwidthProfile(device.id(), uti.getUpstreamOltBandwidthProfile());
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301132
1133 if (FttbUtils.isFttbService(uti)) {
1134 processFttbUpstreamDataFilteringObjects(device.id(), port, nniPort.get(), action,
1135 usMeterId, oltUsMeterId, uti, si);
1136 } else {
1137 processUpstreamDataFilteringObjects(device.id(), port, nniPort.get(), action, usMeterId,
1138 oltUsMeterId, uti);
1139 }
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001140
1141 // downstream flows
1142 MeterId dsMeterId = oltMeterService
1143 .getMeterIdForBandwidthProfile(device.id(), uti.getDownstreamBandwidthProfile());
1144 MeterId oltDsMeterId = oltMeterService
1145 .getMeterIdForBandwidthProfile(device.id(), uti.getDownstreamOltBandwidthProfile());
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301146
1147 if (FttbUtils.isFttbService(uti)) {
1148 processFttbDownstreamDataFilteringObjects(device.id(), port, nniPort.get(),
1149 action, dsMeterId, oltDsMeterId, uti, si);
1150 } else {
1151 processDownstreamDataFilteringObjects(device.id(), port, nniPort.get(), action, dsMeterId,
1152 oltDsMeterId, uti, getMacAddress(device.id(), port, uti));
1153 }
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001154 });
1155 }
1156
1157 private void processDhcpFilteringObjectives(DeviceId deviceId, Port port,
1158 FlowOperation action, FlowDirection direction,
1159 int udpSrc, int udpDst, EthType ethType, byte protocol,
1160 MeterId meterId, MeterId oltMeterId, UniTagInformation uti) {
1161 ServiceKey sk = new ServiceKey(new AccessDevicePort(port), uti);
1162 log.debug("{} DHCP filtering objectives on {}", flowOpToString(action), sk);
1163
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301164 String serviceName = uti.getServiceName();
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001165
1166 OltFlowsStatus status = action.equals(FlowOperation.ADD) ?
1167 OltFlowsStatus.PENDING_ADD : OltFlowsStatus.PENDING_REMOVE;
Andrea Campanella87241ae2022-03-11 11:20:24 +01001168 updateConnectPointStatus(sk, null, null, null, status, null);
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001169
1170 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
1171 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
1172
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001173 if (meterId != null) {
1174 treatmentBuilder.meter(meterId);
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001175 }
1176
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001177 FilteringObjective.Builder dhcpBuilder = (action == FlowOperation.ADD ? builder.permit() : builder.deny())
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001178 .withKey(Criteria.matchInPort(port.number()))
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001179 .addCondition(Criteria.matchEthType(ethType))
1180 .addCondition(Criteria.matchIPProtocol(protocol))
1181 .addCondition(Criteria.matchUdpSrc(TpPort.tpPort(udpSrc)))
1182 .addCondition(Criteria.matchUdpDst(TpPort.tpPort(udpDst)))
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001183 .fromApp(appId)
1184 .withPriority(MAX_PRIORITY);
1185
Andrea Campanella0e34f562020-06-11 10:47:10 +02001186 //VLAN changes and PCP matching need to happen only in the upstream directions
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001187 if (direction == FlowDirection.UPSTREAM) {
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301188 if (serviceName != null && serviceName.equals(FTTB_SERVICE_DPU_MGMT_TRAFFIC)) {
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301189 FttbUtils.addUpstreamDhcpCondition(dhcpBuilder, uti);
1190 FttbUtils.addUpstreamDhcpTreatment(treatmentBuilder, uti);
1191 } else {
1192 treatmentBuilder.setVlanId(uti.getPonCTag());
1193 if (!VlanId.vlanId(VlanId.NO_VID).equals(uti.getUniTagMatch())) {
1194 dhcpBuilder.addCondition(Criteria.matchVlanId(uti.getUniTagMatch()));
1195 }
1196 if (uti.getUsPonCTagPriority() != -1) {
1197 treatmentBuilder.setVlanPcp((byte) uti.getUsPonCTagPriority());
1198 }
Andrea Campanella0e34f562020-06-11 10:47:10 +02001199 }
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301200 } else if (direction == FlowDirection.DOWNSTREAM) {
1201 // Down stream DHCP vid to be matched if OLT Sadis info contains Vlan id in nniDhcpTrapVid.
1202 Device device = deviceService.getDevice(deviceId);
1203 SubscriberAndDeviceInformation oltSub = subsService.get(device.serialNumber());
1204 VlanId nniDhcpTrapVid = oltSub.nniDhcpTrapVid();
1205
1206 if (nniDhcpTrapVid != null && !VlanId.vlanId(VlanId.NO_VID).equals(nniDhcpTrapVid)) {
1207 dhcpBuilder.addCondition(Criteria.matchVlanId(nniDhcpTrapVid));
Andrea Campanella0e34f562020-06-11 10:47:10 +02001208 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001209 }
1210
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301211 if (uti.getTechnologyProfileId() != NONE_TP_ID) {
Harsh Awasthi498b5c62022-03-21 23:19:46 +05301212 // Setting VlanId.NONE as cvlan, as the packet will be single tagged and cvlan should not be filled.
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301213 treatmentBuilder.writeMetadata(
Harsh Awasthi498b5c62022-03-21 23:19:46 +05301214 OltFlowServiceUtils.createTechProfValueForWriteMetadata(VlanId.NONE,
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301215 uti.getTechnologyProfileId(), oltMeterId), 0);
1216 }
1217
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001218 dhcpBuilder.withMeta(treatmentBuilder
1219 .setOutput(PortNumber.CONTROLLER).build());
Andrea Campanella0e34f562020-06-11 10:47:10 +02001220
1221
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001222 FilteringObjective dhcpUpstream = dhcpBuilder.add(new ObjectiveContext() {
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001223 @Override
1224 public void onSuccess(Objective objective) {
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001225 log.info("{} DHCP {} filter for {}.",
1226 completeFlowOpToString(action), (ethType.equals(EthType.EtherType.IPV4.ethType())) ? V4 : V6,
1227 portWithName(port));
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001228 }
1229
1230 @Override
1231 public void onError(Objective objective, ObjectiveError error) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001232 log.error("DHCP {} filter for {} failed {} because {}",
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001233 (ethType.equals(EthType.EtherType.IPV4.ethType())) ? V4 : V6,
1234 portWithName(port),
1235 action,
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001236 error);
Andrea Campanella87241ae2022-03-11 11:20:24 +01001237 updateConnectPointStatus(sk, null, null, null, OltFlowsStatus.ERROR, null);
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001238 }
1239 });
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001240 flowObjectiveService.filter(deviceId, dhcpUpstream);
1241 }
1242
1243 private void processIgmpFilteringObjectives(DeviceId deviceId, Port port,
1244 FlowOperation action, FlowDirection direction,
1245 MeterId meterId, MeterId oltMeterId, int techProfileId,
1246 VlanId cTag, VlanId unitagMatch, int vlanPcp) {
1247
1248 DefaultFilteringObjective.Builder filterBuilder = DefaultFilteringObjective.builder();
1249 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
1250 if (direction == FlowDirection.UPSTREAM) {
1251
1252 if (techProfileId != NONE_TP_ID) {
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301253 treatmentBuilder.writeMetadata(OltFlowServiceUtils.createTechProfValueForWriteMetadata(null,
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001254 techProfileId, oltMeterId), 0);
1255 }
1256
1257
1258 if (meterId != null) {
1259 treatmentBuilder.meter(meterId);
1260 }
1261
1262 if (!VlanId.vlanId(VlanId.NO_VID).equals(unitagMatch)) {
1263 filterBuilder.addCondition(Criteria.matchVlanId(unitagMatch));
1264 }
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001265 if (!VlanId.vlanId(VlanId.NO_VID).equals(cTag)) {
1266 treatmentBuilder.setVlanId(cTag);
1267 }
1268
1269 if (vlanPcp != -1) {
1270 treatmentBuilder.setVlanPcp((byte) vlanPcp);
1271 }
1272 }
1273
1274 filterBuilder = (action == FlowOperation.ADD) ? filterBuilder.permit() : filterBuilder.deny();
1275
1276 FilteringObjective igmp = filterBuilder
1277 .withKey(Criteria.matchInPort(port.number()))
1278 .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
1279 .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_IGMP))
1280 .withMeta(treatmentBuilder
1281 .setOutput(PortNumber.CONTROLLER).build())
1282 .fromApp(appId)
1283 .withPriority(MAX_PRIORITY)
1284 .add(new ObjectiveContext() {
1285 @Override
1286 public void onSuccess(Objective objective) {
1287 log.info("Igmp filter for {} {}.", portWithName(port), action);
1288 }
1289
1290 @Override
1291 public void onError(Objective objective, ObjectiveError error) {
1292 log.error("Igmp filter for {} failed {} because {}.", portWithName(port), action,
1293 error);
1294 }
1295 });
1296
1297 flowObjectiveService.filter(deviceId, igmp);
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001298
1299 }
1300
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001301 private void processPPPoEDFilteringObjectives(DeviceId deviceId, Port port,
1302 FlowOperation action, FlowDirection direction,
1303 MeterId meterId, MeterId oltMeterId, int techProfileId,
1304 VlanId cTag, VlanId unitagMatch, Byte vlanPcp) {
Gustavo Silva5c492dd2021-02-12 10:21:11 -03001305
1306 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
1307 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
Gustavo Silva5c492dd2021-02-12 10:21:11 -03001308
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001309 if (meterId != null) {
1310 treatmentBuilder.meter(meterId);
Gustavo Silva5c492dd2021-02-12 10:21:11 -03001311 }
1312
1313 if (techProfileId != NONE_TP_ID) {
Harsh Awasthi498b5c62022-03-21 23:19:46 +05301314 // Setting VlanId.NONE as cvlan as the packet will be single tagged and cvlan should not be filled.
1315 treatmentBuilder.writeMetadata(OltFlowServiceUtils.createTechProfValueForWriteMetadata(VlanId.NONE,
1316 techProfileId, oltMeterId), 0);
Gustavo Silva5c492dd2021-02-12 10:21:11 -03001317 }
1318
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001319 DefaultFilteringObjective.Builder pppoedBuilder = ((action == FlowOperation.ADD)
1320 ? builder.permit() : builder.deny())
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001321 .withKey(Criteria.matchInPort(port.number()))
Gustavo Silva5c492dd2021-02-12 10:21:11 -03001322 .addCondition(Criteria.matchEthType(EthType.EtherType.PPPoED.ethType()))
1323 .fromApp(appId)
1324 .withPriority(10000);
1325
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001326 if (direction == FlowDirection.UPSTREAM) {
Gustavo Silva5c492dd2021-02-12 10:21:11 -03001327 treatmentBuilder.setVlanId(cTag);
1328 if (!VlanId.vlanId(VlanId.NO_VID).equals(unitagMatch)) {
1329 pppoedBuilder.addCondition(Criteria.matchVlanId(unitagMatch));
1330 }
1331 if (vlanPcp != null) {
1332 treatmentBuilder.setVlanPcp(vlanPcp);
1333 }
1334 }
1335 pppoedBuilder = pppoedBuilder.withMeta(treatmentBuilder.setOutput(PortNumber.CONTROLLER).build());
1336
1337 FilteringObjective pppoed = pppoedBuilder
1338 .add(new ObjectiveContext() {
1339 @Override
1340 public void onSuccess(Objective objective) {
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001341 log.info("PPPoED filter for {} {}.", portWithName(port), action);
Gustavo Silva5c492dd2021-02-12 10:21:11 -03001342 }
1343
1344 @Override
1345 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001346 log.info("PPPoED filter for {} failed {} because {}", portWithName(port),
1347 action, error);
Gustavo Silva5c492dd2021-02-12 10:21:11 -03001348 }
1349 });
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001350 flowObjectiveService.filter(deviceId, pppoed);
Gustavo Silva5c492dd2021-02-12 10:21:11 -03001351 }
1352
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001353 private void processUpstreamDataFilteringObjects(DeviceId deviceId, Port port, Port nniPort,
1354 FlowOperation action,
1355 MeterId upstreamMeterId,
1356 MeterId upstreamOltMeterId,
1357 UniTagInformation uti) {
1358 ServiceKey sk = new ServiceKey(new AccessDevicePort(port), uti);
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001359 TrafficSelector selector = DefaultTrafficSelector.builder()
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001360 .matchInPort(port.number())
1361 .matchVlanId(uti.getUniTagMatch())
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001362 .build();
1363
Andrea Campanella327c5722020-01-30 11:34:13 +01001364 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
1365 //if the subscriberVlan (cTag) is different than ANY it needs to set.
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001366 if (uti.getPonCTag().toShort() != VlanId.ANY_VALUE) {
Andrea Campanella327c5722020-01-30 11:34:13 +01001367 treatmentBuilder.pushVlan()
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001368 .setVlanId(uti.getPonCTag());
Andrea Campanella327c5722020-01-30 11:34:13 +01001369 }
Maria Carmela Cascino067ee4d2021-11-02 13:14:43 +01001370 if (uti.getPonSTag().toShort() == VlanId.ANY_VALUE) {
1371 treatmentBuilder.popVlan();
1372 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001373
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001374 if (uti.getUsPonCTagPriority() != -1) {
1375 treatmentBuilder.setVlanPcp((byte) uti.getUsPonCTagPriority());
Maria Carmela Cascino067ee4d2021-11-02 13:14:43 +01001376
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001377 }
1378
1379 treatmentBuilder.pushVlan()
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001380 .setVlanId(uti.getPonSTag());
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001381
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001382 if (uti.getUsPonSTagPriority() != -1) {
1383 treatmentBuilder.setVlanPcp((byte) uti.getUsPonSTagPriority());
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001384 }
1385
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001386 treatmentBuilder.setOutput(nniPort.number())
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301387 .writeMetadata(OltFlowServiceUtils.createMetadata(uti.getPonCTag(),
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001388 uti.getTechnologyProfileId(), nniPort.number()), 0L);
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001389
yasin saplib4b8ee12021-06-13 18:25:20 +00001390 DefaultAnnotations.Builder annotationBuilder = DefaultAnnotations.builder();
1391
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001392 if (upstreamMeterId != null) {
1393 treatmentBuilder.meter(upstreamMeterId);
yasin saplib4b8ee12021-06-13 18:25:20 +00001394 annotationBuilder.set(UPSTREAM_ONU, upstreamMeterId.toString());
1395 }
1396 if (upstreamOltMeterId != null) {
1397 treatmentBuilder.meter(upstreamOltMeterId);
1398 annotationBuilder.set(UPSTREAM_OLT, upstreamOltMeterId.toString());
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001399 }
1400
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001401 DefaultForwardingObjective.Builder flowBuilder = createForwardingObjectiveBuilder(selector,
1402 treatmentBuilder.build(), MIN_PRIORITY,
yasin saplib4b8ee12021-06-13 18:25:20 +00001403 annotationBuilder.build());
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001404
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301405 ObjectiveContext context = getSubscriberFlowBuilderContext(sk, action, FlowDirection.UPSTREAM);
1406 processForwardingRule(action, flowBuilder, context, deviceId);
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001407 }
1408
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001409 private void processDownstreamDataFilteringObjects(DeviceId deviceId, Port port, Port nniPort,
1410 FlowOperation action,
1411 MeterId downstreamMeterId,
1412 MeterId downstreamOltMeterId,
1413 UniTagInformation uti,
1414 MacAddress macAddress) {
1415 ServiceKey sk = new ServiceKey(new AccessDevicePort(port), uti);
Andrea Campanella327c5722020-01-30 11:34:13 +01001416 //subscriberVlan can be any valid Vlan here including ANY to make sure the packet is tagged
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001417 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder()
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001418 .matchVlanId(uti.getPonSTag())
1419 .matchInPort(nniPort.number())
1420 .matchInnerVlanId(uti.getPonCTag());
Andrea Campanella090e4a02020-02-05 13:53:55 +01001421
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001422 if (uti.getPonCTag().toShort() != VlanId.ANY_VALUE) {
1423 selectorBuilder.matchMetadata(uti.getPonCTag().toShort());
Andrea Campanella090e4a02020-02-05 13:53:55 +01001424 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001425
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001426 if (uti.getDsPonCTagPriority() != -1) {
1427 selectorBuilder.matchVlanPcp((byte) uti.getDsPonCTagPriority());
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001428 }
1429
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001430 if (macAddress != null) {
1431 selectorBuilder.matchEthDst(macAddress);
1432 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001433
1434 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder()
1435 .popVlan()
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001436 .setOutput(port.number());
Andrea Campanella327c5722020-01-30 11:34:13 +01001437
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301438 treatmentBuilder.writeMetadata(OltFlowServiceUtils.createMetadata(uti.getPonCTag(),
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001439 uti.getTechnologyProfileId(),
1440 port.number()), 0);
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001441
Andrea Campanella981e86c2021-03-12 11:35:33 +01001442 // Upstream pbit is used to remark inner vlan pbit.
1443 // Upstream is used to avoid trusting the BNG to send the packet with correct pbit.
1444 // this is done because ds mode 0 is used because ds mode 3 or 6 that allow for
1445 // all pbit acceptance are not widely supported by vendors even though present in
1446 // the OMCI spec.
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001447 if (uti.getUsPonCTagPriority() != -1) {
1448 treatmentBuilder.setVlanPcp((byte) uti.getUsPonCTagPriority());
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001449 }
1450
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001451 if (!VlanId.NONE.equals(uti.getUniTagMatch()) &&
1452 uti.getPonCTag().toShort() != VlanId.ANY_VALUE) {
1453 treatmentBuilder.setVlanId(uti.getUniTagMatch());
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001454 }
1455
yasin saplib4b8ee12021-06-13 18:25:20 +00001456 DefaultAnnotations.Builder annotationBuilder = DefaultAnnotations.builder();
1457
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001458 if (downstreamMeterId != null) {
1459 treatmentBuilder.meter(downstreamMeterId);
yasin saplib4b8ee12021-06-13 18:25:20 +00001460 annotationBuilder.set(DOWNSTREAM_ONU, downstreamMeterId.toString());
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001461 }
1462
yasin saplib4b8ee12021-06-13 18:25:20 +00001463 if (downstreamOltMeterId != null) {
1464 treatmentBuilder.meter(downstreamOltMeterId);
1465 annotationBuilder.set(DOWNSTREAM_OLT, downstreamOltMeterId.toString());
1466 }
1467
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001468 DefaultForwardingObjective.Builder flowBuilder = createForwardingObjectiveBuilder(selectorBuilder.build(),
1469 treatmentBuilder.build(), MIN_PRIORITY, annotationBuilder.build());
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001470
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301471 ObjectiveContext context = getSubscriberFlowBuilderContext(sk, action, FlowDirection.DOWNSTREAM);
1472 processForwardingRule(action, flowBuilder, context, deviceId);
Andrea Campanella600d2e22020-06-22 11:00:31 +02001473 }
1474
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001475 private DefaultForwardingObjective.Builder createForwardingObjectiveBuilder(TrafficSelector selector,
1476 TrafficTreatment treatment,
yasin saplib4b8ee12021-06-13 18:25:20 +00001477 Integer priority,
1478 Annotations annotations) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001479 return DefaultForwardingObjective.builder()
1480 .withFlag(ForwardingObjective.Flag.VERSATILE)
1481 .withPriority(priority)
1482 .makePermanent()
1483 .withSelector(selector)
yasin saplib4b8ee12021-06-13 18:25:20 +00001484 .withAnnotations(annotations)
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001485 .fromApp(appId)
1486 .withTreatment(treatment);
1487 }
1488
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001489 private boolean isMacLearningEnabled(SubscriberAndDeviceInformation si) {
1490 AtomicBoolean requiresMacLearning = new AtomicBoolean();
1491 requiresMacLearning.set(false);
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001492
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001493 si.uniTagList().forEach(uniTagInfo -> {
1494 if (uniTagInfo.getEnableMacLearning()) {
1495 requiresMacLearning.set(true);
1496 }
1497 });
1498
1499 return requiresMacLearning.get();
1500 }
1501
1502 /**
1503 * Checks whether the subscriber has the MacAddress configured or discovered.
1504 *
1505 * @param deviceId DeviceId for this subscriber
1506 * @param port Port for this subscriber
1507 * @param si SubscriberAndDeviceInformation
1508 * @return boolean
1509 */
1510 protected boolean isMacAddressAvailable(DeviceId deviceId, Port port, SubscriberAndDeviceInformation si) {
1511 AtomicBoolean isConfigured = new AtomicBoolean();
1512 isConfigured.set(true);
1513
1514 si.uniTagList().forEach(uniTagInfo -> {
1515 boolean isMacLearningEnabled = uniTagInfo.getEnableMacLearning();
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301516 boolean configureMac = OltFlowServiceUtils.isMacAddressValid(uniTagInfo);
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001517 boolean discoveredMac = false;
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301518
1519 final VlanId vlan;
1520
1521 if (FttbUtils.isFttbDpuOrAncpService(uniTagInfo)) {
1522 // Using S tag, as C tag is replaced by Stag by ONU.
1523 vlan = uniTagInfo.getPonSTag();
1524 } else {
1525 vlan = uniTagInfo.getPonCTag();
1526 }
1527
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001528 Optional<Host> optHost = hostService.getConnectedHosts(new ConnectPoint(deviceId, port.number()))
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301529 .stream().filter(host -> host.vlan().equals(vlan)).findFirst();
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001530 if (optHost.isPresent() && optHost.get().mac() != null) {
1531 discoveredMac = true;
1532 }
1533 if (isMacLearningEnabled && !configureMac && !discoveredMac) {
1534 log.debug("Awaiting for macAddress on {} for service {}",
1535 portWithName(port), uniTagInfo.getServiceName());
1536 isConfigured.set(false);
1537 }
1538 });
1539
1540 return isConfigured.get();
1541 }
1542
1543 protected MacAddress getMacAddress(DeviceId deviceId, Port port, UniTagInformation uniTagInfo) {
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301544 boolean configuredMac = OltFlowServiceUtils.isMacAddressValid(uniTagInfo);
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001545 if (configuredMac) {
1546 return MacAddress.valueOf(uniTagInfo.getConfiguredMacAddress());
1547 } else if (uniTagInfo.getEnableMacLearning()) {
1548 Optional<Host> optHost = hostService.getConnectedHosts(new ConnectPoint(deviceId, port.number()))
1549 .stream().filter(host -> host.vlan().equals(uniTagInfo.getPonCTag())).findFirst();
1550 if (optHost.isPresent() && optHost.get().mac() != null) {
1551 return optHost.get().mac();
1552 }
1553 }
1554 return null;
1555 }
1556
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001557 protected void updateConnectPointStatus(ServiceKey key, OltFlowsStatus eapolStatus,
Andrea Campanella87241ae2022-03-11 11:20:24 +01001558 OltFlowsStatus subscriberEapolStatus,
yasin sapli0823c932022-01-26 11:26:09 +00001559 OltFlowsStatus subscriberFlowsStatus, OltFlowsStatus dhcpStatus,
1560 OltFlowsStatus pppoeStatus) {
Matteo Scandolo2542e5d2021-12-01 16:53:41 -08001561 if (log.isTraceEnabled()) {
Andrea Campanella87241ae2022-03-11 11:20:24 +01001562 log.trace("Updating cpStatus {} with values: eapolFlow={}, " +
1563 "subscriberEapolStatus={}, subscriberFlows={}, dhcpFlow={}",
1564 key, eapolStatus, subscriberEapolStatus, subscriberFlowsStatus, dhcpStatus);
Matteo Scandolo2542e5d2021-12-01 16:53:41 -08001565 }
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001566 try {
1567 cpStatusWriteLock.lock();
1568 OltPortStatus status = cpStatus.get(key);
1569
Matteo Scandolo2542e5d2021-12-01 16:53:41 -08001570
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001571 if (status == null) {
Matteo Scandolo2542e5d2021-12-01 16:53:41 -08001572 // if we don't have status for the connectPoint
1573 // and we're only updating status to PENDING_REMOVE or ERROR
1574 // do not create it. This is because this case will only happen when a device is removed
1575 // and it's status cleaned
1576 List<OltFlowsStatus> statusesToIgnore = new ArrayList<>();
1577 statusesToIgnore.add(OltFlowsStatus.PENDING_REMOVE);
1578 statusesToIgnore.add(OltFlowsStatus.ERROR);
1579
1580 if (
1581 (statusesToIgnore.contains(subscriberFlowsStatus) && dhcpStatus == null) ||
1582 (subscriberFlowsStatus == null && statusesToIgnore.contains(dhcpStatus))
1583 ) {
1584 if (log.isTraceEnabled()) {
1585 log.trace("Ignoring cpStatus update as status is meaningless");
1586 }
1587 return;
1588 }
1589
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001590 status = new OltPortStatus(
1591 eapolStatus != null ? eapolStatus : OltFlowsStatus.NONE,
Andrea Campanella87241ae2022-03-11 11:20:24 +01001592 subscriberEapolStatus != null ? subscriberEapolStatus : OltFlowsStatus.NONE,
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001593 subscriberFlowsStatus != null ? subscriberFlowsStatus : OltFlowsStatus.NONE,
yasin sapli0823c932022-01-26 11:26:09 +00001594 dhcpStatus != null ? dhcpStatus : OltFlowsStatus.NONE,
1595 pppoeStatus != null ? pppoeStatus : OltFlowsStatus.NONE
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001596 );
1597 } else {
1598 if (eapolStatus != null) {
1599 status.defaultEapolStatus = eapolStatus;
1600 }
1601 if (subscriberFlowsStatus != null) {
1602 status.subscriberFlowsStatus = subscriberFlowsStatus;
1603 }
1604 if (dhcpStatus != null) {
1605 status.dhcpStatus = dhcpStatus;
1606 }
1607 }
1608
1609 cpStatus.put(key, status);
1610 } finally {
1611 cpStatusWriteLock.unlock();
1612 }
1613 }
1614
1615 protected class InternalFlowListener implements FlowRuleListener {
1616 @Override
1617 public void event(FlowRuleEvent event) {
1618 if (appId.id() != (event.subject().appId())) {
1619 return;
1620 }
1621
1622 if (!oltDeviceService.isLocalLeader(event.subject().deviceId())) {
1623 if (log.isTraceEnabled()) {
1624 log.trace("ignoring flow event {} " +
1625 "as not leader for {}", event, event.subject().deviceId());
1626 }
1627 return;
1628 }
1629
1630 switch (event.type()) {
1631 case RULE_ADDED:
1632 case RULE_REMOVED:
Andrea Campanella40d2b342022-02-04 18:13:37 +01001633 DeviceId deviceId = event.subject().deviceId();
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001634 Port port = getCpFromFlowRule(event.subject());
1635 if (port == null) {
Andrea Campanella40d2b342022-02-04 18:13:37 +01001636 log.warn("Port is gone in ONOS, " +
1637 "manually creating it {}", event.subject());
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301638 PortNumber inPort = OltFlowServiceUtils.getPortNumberFromFlowRule(event.subject());
Andrea Campanella40d2b342022-02-04 18:13:37 +01001639 cpStatusReadLock.lock();
1640 Optional<ServiceKey> keyWithPort = cpStatus.keySet()
1641 .stream().filter(key -> key.getPort().connectPoint()
1642 .deviceId().equals(deviceId)
1643 && key.getPort().connectPoint().port()
1644 .equals(inPort)).findFirst();
1645 cpStatusReadLock.unlock();
1646 if (keyWithPort.isPresent()) {
1647 port = new DefaultPort(deviceService.getDevice(deviceId),
1648 inPort, false,
1649 DefaultAnnotations.builder()
1650 .set(AnnotationKeys.PORT_NAME,
1651 keyWithPort.get().getPort().name())
1652 .build());
1653 } else {
1654 log.warn("Can't find corresponding status for {}/{}", deviceId, inPort);
1655 return;
1656 }
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001657 }
1658 if (log.isTraceEnabled()) {
1659 log.trace("flow event {} on cp {}: {}", event.type(),
1660 portWithName(port), event.subject());
1661 }
1662 updateCpStatus(event.type(), port, event.subject());
1663 return;
1664 case RULE_ADD_REQUESTED:
1665 case RULE_REMOVE_REQUESTED:
1666 // NOTE that PENDING_ADD/REMOVE is set when we create the flowObjective
1667 return;
1668 default:
1669 return;
1670 }
1671 }
1672
1673 protected void updateCpStatus(FlowRuleEvent.Type type, Port port, FlowRule flowRule) {
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301674 OltFlowsStatus status = OltFlowServiceUtils.flowRuleStatusToOltFlowStatus(type);
1675 if (OltFlowServiceUtils.isDefaultEapolFlow(flowRule)) {
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001676 ServiceKey sk = new ServiceKey(new AccessDevicePort(port),
1677 defaultEapolUniTag);
1678 if (log.isTraceEnabled()) {
1679 log.trace("update defaultEapolStatus {} on {}", status, sk);
1680 }
Andrea Campanella87241ae2022-03-11 11:20:24 +01001681 updateConnectPointStatus(sk, status, null, null, null, null);
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301682 } else if (OltFlowServiceUtils.isSubscriberEapolFlow(flowRule)) {
Andrea Campanella87241ae2022-03-11 11:20:24 +01001683 ServiceKey sk = getSubscriberKeyFromFlowRule(flowRule, port);
1684 if (sk == null) {
1685 return;
1686 }
1687 if (log.isTraceEnabled()) {
1688 log.trace("update subscriberEapolStatus {} on {}", status, sk);
1689 }
Andrea Campanella34ce61a2022-04-28 18:55:46 +02001690 updateConnectPointStatus(sk, null, status, null, null, null);
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301691 } else if (OltFlowServiceUtils.isDhcpFlow(flowRule)) {
Andrea Campanella40d2b342022-02-04 18:13:37 +01001692 ServiceKey sk = getSubscriberKeyFromFlowRule(flowRule, port);
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001693 if (sk == null) {
1694 return;
1695 }
1696 if (log.isTraceEnabled()) {
1697 log.trace("update dhcpStatus {} on {}", status, sk);
1698 }
Andrea Campanella87241ae2022-03-11 11:20:24 +01001699 updateConnectPointStatus(sk, null, null, null, status, null);
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301700 } else if (OltFlowServiceUtils.isPppoeFlow(flowRule)) {
Andrea Campanella40d2b342022-02-04 18:13:37 +01001701 ServiceKey sk = getSubscriberKeyFromFlowRule(flowRule, port);
yasin sapli0823c932022-01-26 11:26:09 +00001702 if (sk == null) {
1703 return;
1704 }
1705 if (log.isTraceEnabled()) {
1706 log.trace("update pppoeStatus {} on {}", status, sk);
1707 }
Andrea Campanella87241ae2022-03-11 11:20:24 +01001708 updateConnectPointStatus(sk, null, null, null, null, status);
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301709 } else if (OltFlowServiceUtils.isDataFlow(flowRule)) {
1710 PortNumber number = OltFlowServiceUtils.getPortNumberFromFlowRule(flowRule);
Andrea Campanella40d2b342022-02-04 18:13:37 +01001711 if (number == null) {
1712 log.error("Can't capture the port number from flow {}", flowRule);
1713 return;
1714 }
1715 if (oltDeviceService.isNniPort(deviceService.getDevice(flowRule.deviceId()), number)) {
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001716 // the NNI has data-plane for every subscriber, doesn't make sense to track them
1717 return;
1718 }
1719
Andrea Campanella40d2b342022-02-04 18:13:37 +01001720 ServiceKey sk = getSubscriberKeyFromFlowRule(flowRule, port);
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001721 if (sk == null) {
1722 return;
1723 }
1724 if (log.isTraceEnabled()) {
1725 log.trace("update dataplaneStatus {} on {}", status, sk);
1726 }
Andrea Campanella87241ae2022-03-11 11:20:24 +01001727 updateConnectPointStatus(sk, null, null, status, null, null);
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001728 }
1729 }
1730
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001731
Andrea Campanella87241ae2022-03-11 11:20:24 +01001732
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001733 private Port getCpFromFlowRule(FlowRule flowRule) {
1734 DeviceId deviceId = flowRule.deviceId();
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301735 PortNumber inPort = OltFlowServiceUtils.getPortNumberFromFlowRule(flowRule);
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001736 if (inPort != null) {
Andrea Campanella40d2b342022-02-04 18:13:37 +01001737 return deviceService.getPort(deviceId, inPort);
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001738 }
1739 return null;
1740 }
1741
Andrea Campanella40d2b342022-02-04 18:13:37 +01001742 private ServiceKey getSubscriberKeyFromFlowRule(FlowRule flowRule, Port flowPort) {
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001743 SubscriberAndDeviceInformation si = subsService.get(getPortName(flowPort));
1744
1745 Boolean isNni = oltDeviceService.isNniPort(deviceService.getDevice(flowRule.deviceId()), flowPort.number());
1746 if (si == null && !isNni) {
1747 log.error("Subscriber information not found in sadis for port {}", portWithName(flowPort));
1748 return null;
1749 }
1750
1751 if (isNni) {
1752 return new ServiceKey(new AccessDevicePort(flowPort), nniUniTag);
1753 }
1754
1755 Optional<UniTagInformation> found = Optional.empty();
1756 VlanId flowVlan = null;
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301757 if (OltFlowServiceUtils.isDhcpFlow(flowRule)) {
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001758 // we need to make a special case for DHCP as in the ATT workflow DHCP flows don't match on tags
1759 L2ModificationInstruction.ModVlanIdInstruction instruction =
1760 (L2ModificationInstruction.ModVlanIdInstruction) flowRule.treatment().immediate().get(1);
1761 flowVlan = instruction.vlanId();
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301762 } else if (OltFlowServiceUtils.isSubscriberEapolFlow(flowRule)) {
Andrea Campanella87241ae2022-03-11 11:20:24 +01001763 // we need to make a special case for EAPOL as in the ATT workflow EAPOL flows don't match on tags
1764 L2ModificationInstruction.ModVlanIdInstruction instruction =
1765 (L2ModificationInstruction.ModVlanIdInstruction) flowRule.treatment().immediate().get(2);
1766 flowVlan = instruction.vlanId();
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001767 } else {
1768 // for now we assume that if it's not DHCP it's dataplane (or at least tagged)
1769 VlanIdCriterion vlanIdCriterion =
1770 (VlanIdCriterion) flowRule.selector().getCriterion(Criterion.Type.VLAN_VID);
1771 if (vlanIdCriterion == null) {
1772 log.warn("cannot match the flow to a subscriber service as it does not carry vlans");
1773 return null;
1774 }
1775 flowVlan = vlanIdCriterion.vlanId();
1776 }
1777
1778 VlanId finalFlowVlan = flowVlan;
1779 found = si.uniTagList().stream().filter(uti ->
1780 uti.getPonCTag().equals(finalFlowVlan) ||
1781 uti.getPonSTag().equals(finalFlowVlan) ||
1782 uti.getUniTagMatch().equals(finalFlowVlan)
1783 ).findFirst();
1784
1785
1786 if (found.isEmpty()) {
1787 log.warn("Cannot map flow rule {} to Service in {}", flowRule, si);
1788 }
1789
1790 return found.isPresent() ? new ServiceKey(new AccessDevicePort(flowPort), found.get()) : null;
1791
1792 }
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001793 }
1794
1795 protected void bindSadisService(SadisService service) {
1796 this.subsService = service.getSubscriberInfoService();
1797 this.bpService = service.getBandwidthProfileService();
1798 log.info("Sadis service is loaded");
1799 }
1800
1801 protected void unbindSadisService(SadisService service) {
1802 this.subsService = null;
1803 this.bpService = null;
1804 log.info("Sadis service is unloaded");
1805 }
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301806
1807 private void processFttbUpstreamDataFilteringObjects(DeviceId deviceId, Port port, Port nniPort,
1808 FlowOperation action,
1809 MeterId upstreamMeterId,
1810 MeterId upstreamOltMeterId,
1811 UniTagInformation uti,
1812 SubscriberAndDeviceInformation si) {
1813 String serviceName = uti.getServiceName();
1814 ServiceKey sk = new ServiceKey(new AccessDevicePort(port), uti);
1815 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder()
1816 .matchInPort(port.number())
1817 .matchVlanId(uti.getPonCTag());
1818
1819 if (uti.getUsPonCTagPriority() != -1) {
1820 selectorBuilder.matchVlanPcp((byte) uti.getUsPonCTagPriority());
1821 }
1822
1823 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
1824
1825 treatmentBuilder.setVlanId(uti.getPonSTag());
1826 if (uti.getUsPonSTagPriority() != -1) {
1827 treatmentBuilder.setVlanPcp((byte) uti.getUsPonSTagPriority());
1828 }
1829
1830 DefaultAnnotations.Builder annotationBuilder = DefaultAnnotations.builder();
1831 annotationBuilder.set(FTTB_SERVICE_NAME, serviceName);
1832 annotationBuilder.set(FTTB_FLOW_DIRECTION, FTTB_FLOW_UPSTREAM);
1833
1834 if (upstreamMeterId != null) {
1835 treatmentBuilder.meter(upstreamMeterId);
1836 annotationBuilder.set(UPSTREAM_ONU, upstreamMeterId.toString());
1837 }
1838 if (upstreamOltMeterId != null) {
1839 treatmentBuilder.meter(upstreamOltMeterId);
1840 annotationBuilder.set(UPSTREAM_OLT, upstreamOltMeterId.toString());
1841 }
1842
1843 VlanId innerVlan = null;
Andrea Campanella7ef88992022-05-17 12:38:00 +02001844 treatmentBuilder.setOutput(nniPort.number());
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301845 if (serviceName.equals(FTTB_SERVICE_DPU_MGMT_TRAFFIC) || serviceName.equals(FTTB_SERVICE_DPU_ANCP_TRAFFIC)) {
amit.ghosh74a4bb22022-06-14 11:34:52 +02001846 fttbMacAddressesWriteLock.lock();
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301847 MacAddress mac = FttbUtils.getMacAddressFromDhcpEnabledUti(
amit.ghosh74a4bb22022-06-14 11:34:52 +02001848 hostService, si, deviceId, port, fttbMacAddresses);
1849 fttbMacAddressesWriteLock.unlock();
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301850
1851 if (mac == null) {
1852 log.error("Mac address not found port:{}, vlan:{}, service:{}",
1853 port, uti.getPonSTag(), serviceName);
1854 return;
1855 }
1856
1857 selectorBuilder.matchEthSrc(mac);
Andrea Campanella7ef88992022-05-17 12:38:00 +02001858
1859 treatmentBuilder.writeMetadata(OltFlowServiceUtils.createMetadata(VlanId.NONE,
1860 uti.getTechnologyProfileId(), nniPort.number()), 0L);
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301861
1862 } else if (serviceName.equals(FTTB_SERVICE_SUBSCRIBER_TRAFFIC)) {
Andrea Campanella7ef88992022-05-17 12:38:00 +02001863 treatmentBuilder.writeMetadata(OltFlowServiceUtils.createMetadata(VlanId.ANY,
1864 uti.getTechnologyProfileId(), nniPort.number()), 0L);
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301865 }
1866
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301867 DefaultForwardingObjective.Builder flowBuilder = createForwardingObjectiveBuilder(selectorBuilder.build(),
1868 treatmentBuilder.build(), MIN_PRIORITY,
1869 annotationBuilder.build());
1870
1871 ObjectiveContext context = getSubscriberFlowBuilderContext(sk, action, FlowDirection.UPSTREAM);
1872 processForwardingRule(action, flowBuilder, context, deviceId);
1873 }
1874
1875 private void processFttbDownstreamDataFilteringObjects(DeviceId deviceId, Port port, Port nniPort,
1876 FlowOperation action,
1877 MeterId downstreamMeterId,
1878 MeterId downstreamOltMeterId,
1879 UniTagInformation uti, SubscriberAndDeviceInformation si) {
1880 String serviceName = uti.getServiceName();
1881 ServiceKey sk = new ServiceKey(new AccessDevicePort(port), uti);
1882 //subscriberVlan can be any valid Vlan here including ANY to make sure the packet is tagged
1883 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder()
1884 .matchVlanId(uti.getPonSTag())
1885 .matchInPort(nniPort.number());
1886
1887 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder()
1888 .setVlanId(uti.getPonCTag())
1889 .setOutput(port.number());
1890
1891 DefaultAnnotations.Builder annotationBuilder = DefaultAnnotations.builder();
1892 annotationBuilder.set(FTTB_SERVICE_NAME, uti.getServiceName());
1893 annotationBuilder.set(FTTB_FLOW_DIRECTION, FTTB_FLOW_DOWNSTREAM);
1894
1895 if (downstreamMeterId != null) {
1896 treatmentBuilder.meter(downstreamMeterId);
1897 annotationBuilder.set(DOWNSTREAM_ONU, downstreamMeterId.toString());
1898 }
1899
1900 if (downstreamOltMeterId != null) {
1901 treatmentBuilder.meter(downstreamOltMeterId);
1902 annotationBuilder.set(DOWNSTREAM_OLT, downstreamOltMeterId.toString());
1903 }
1904
1905 VlanId innerVlan = null;
1906
1907 if (serviceName.equals(FTTB_SERVICE_DPU_MGMT_TRAFFIC) || serviceName.equals(FTTB_SERVICE_DPU_ANCP_TRAFFIC)) {
amit.ghosh74a4bb22022-06-14 11:34:52 +02001908 fttbMacAddressesWriteLock.lock();
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301909 MacAddress mac = FttbUtils.getMacAddressFromDhcpEnabledUti(
amit.ghosh74a4bb22022-06-14 11:34:52 +02001910 hostService, si, deviceId, port, fttbMacAddresses);
1911 fttbMacAddressesWriteLock.unlock();
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301912
1913 if (mac == null) {
1914 log.error("Mac address not found port:{}, vlan:{}, service:{}",
1915 port, uti.getPonSTag(), serviceName);
1916 return;
1917 }
1918
1919 selectorBuilder.matchEthDst(mac);
1920 innerVlan = VlanId.NONE;
Andrea Campanella7ef88992022-05-17 12:38:00 +02001921 treatmentBuilder.writeMetadata(OltFlowServiceUtils.createMetadata(innerVlan,
1922 uti.getTechnologyProfileId(),
1923 port.number()), 0);
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301924
1925 } else if (serviceName.equals(FTTB_SERVICE_SUBSCRIBER_TRAFFIC)) {
Andrea Campanella7ef88992022-05-17 12:38:00 +02001926 selectorBuilder.matchMetadata(uti.getPonCTag().toShort());
1927 treatmentBuilder.writeMetadata(OltFlowServiceUtils.createMetadata(VlanId.ANY,
1928 uti.getTechnologyProfileId(),
1929 port.number()), 0);
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301930 }
1931
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301932 DefaultForwardingObjective.Builder flowBuilder = createForwardingObjectiveBuilder(selectorBuilder.build(),
1933 treatmentBuilder.build(), MIN_PRIORITY, annotationBuilder.build());
1934
1935 ObjectiveContext context = getSubscriberFlowBuilderContext(sk, action, FlowDirection.DOWNSTREAM);
1936 processForwardingRule(action, flowBuilder, context, deviceId);
1937 }
1938
1939 private ObjectiveContext getSubscriberFlowBuilderContext(ServiceKey sk, FlowOperation action,
1940 FlowDirection flowDirection) {
1941 ObjectiveContext context = new ObjectiveContext() {
1942 @Override
1943 public void onSuccess(Objective objective) {
1944 log.info("{} {} Data plane filter for {}.",
1945 completeFlowOpToString(action), flowDirection, sk);
1946 }
1947
1948 @Override
1949 public void onError(Objective objective, ObjectiveError error) {
1950 log.info("{} Data plane filter for {} failed {} because {}.",
1951 flowDirection, sk, action, error);
1952 updateConnectPointStatus(sk, null, null, OltFlowsStatus.ERROR, null, null);
1953 }
1954 };
1955
1956 return context;
1957 }
1958
1959 private void processForwardingRule(FlowOperation action, DefaultForwardingObjective.Builder flowBuilder,
1960 ObjectiveContext context, DeviceId deviceId) {
1961 ForwardingObjective flow = null;
1962 if (action == FlowOperation.ADD) {
1963 flow = flowBuilder.add(context);
1964 } else if (action == FlowOperation.REMOVE) {
1965 flow = flowBuilder.remove(context);
1966 } else {
1967 log.error("Flow action not supported: {}", action);
1968 }
1969
1970 if (flow != null) {
1971 if (log.isTraceEnabled()) {
1972 log.trace("Forwarding rule {}", flow);
1973 }
1974 flowObjectiveService.forward(deviceId, flow);
1975 }
1976 }
amit.ghosh74a4bb22022-06-14 11:34:52 +02001977}