blob: 74c58115c66a2e8adfc9bf1699c0f070c98645f2 [file] [log] [blame]
alshabibf0e7e702015-05-30 18:22:36 -07001/*
Brian O'Connord6a135a2017-08-03 22:46:05 -07002 * Copyright 2016-present Open Networking Foundation
alshabibf0e7e702015-05-30 18:22:36 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
alshabib36a4d732016-06-01 16:03:59 -070016package org.opencord.olt.impl;
alshabibf0e7e702015-05-30 18:22:36 -070017
Andrea Campanella7a1d7e72020-11-05 10:40:10 +010018import com.google.common.collect.ImmutableMap;
19import com.google.common.collect.Sets;
Tunahan Sezena07fe962021-02-24 08:24:24 +000020import org.onlab.packet.MacAddress;
alshabibf0e7e702015-05-30 18:22:36 -070021import org.onlab.packet.VlanId;
Jonathan Hart4f178fa2020-02-03 10:46:01 -080022import org.onlab.util.KryoNamespace;
Gamze Abaka1f62dd92020-05-07 08:58:13 +000023import org.onosproject.cfg.ComponentConfigService;
Jonathan Hart4f178fa2020-02-03 10:46:01 -080024import org.onosproject.cluster.ClusterEvent;
25import org.onosproject.cluster.ClusterEventListener;
26import org.onosproject.cluster.ClusterService;
27import org.onosproject.cluster.ControllerNode;
Andrea Campanellaaf39b4c2020-05-13 14:07:44 +020028import org.onosproject.cluster.LeadershipService;
Jonathan Hart4f178fa2020-02-03 10:46:01 -080029import org.onosproject.cluster.NodeId;
alshabibf0e7e702015-05-30 18:22:36 -070030import org.onosproject.core.ApplicationId;
31import org.onosproject.core.CoreService;
alshabib8e4fd2f2016-01-12 15:55:53 -080032import org.onosproject.event.AbstractListenerManager;
Andrea Campanellaaf39b4c2020-05-13 14:07:44 +020033import org.onosproject.mastership.MastershipService;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010034import org.onosproject.net.AnnotationKeys;
Jonathan Harte533a422015-10-20 17:31:24 -070035import org.onosproject.net.ConnectPoint;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010036import org.onosproject.net.Device;
alshabibf0e7e702015-05-30 18:22:36 -070037import org.onosproject.net.DeviceId;
Tunahan Sezena07fe962021-02-24 08:24:24 +000038import org.onosproject.net.Host;
alshabibdec2e252016-01-15 12:20:25 -080039import org.onosproject.net.Port;
alshabibf0e7e702015-05-30 18:22:36 -070040import org.onosproject.net.PortNumber;
41import org.onosproject.net.device.DeviceEvent;
42import org.onosproject.net.device.DeviceListener;
43import org.onosproject.net.device.DeviceService;
Andrea Campanella438e1ad2021-03-26 11:41:16 +010044import org.onosproject.net.driver.DriverService;
Hardik Windlassa58fbee2020-03-12 18:33:55 +053045import org.onosproject.net.flow.FlowRuleService;
alshabibf0e7e702015-05-30 18:22:36 -070046import org.onosproject.net.flowobjective.FlowObjectiveService;
47import org.onosproject.net.flowobjective.ForwardingObjective;
alshabib3ea82642016-01-12 18:06:53 -080048import org.onosproject.net.flowobjective.Objective;
49import org.onosproject.net.flowobjective.ObjectiveContext;
50import org.onosproject.net.flowobjective.ObjectiveError;
Tunahan Sezena07fe962021-02-24 08:24:24 +000051import org.onosproject.net.host.HostEvent;
52import org.onosproject.net.host.HostListener;
53import org.onosproject.net.host.HostService;
Saurav Daseae48de2019-06-19 13:26:15 -070054import org.onosproject.net.meter.MeterId;
Andrea Campanella51118232021-07-01 17:18:02 +020055import org.onosproject.store.primitives.DefaultConsistentMap;
Jonathan Hart4f178fa2020-02-03 10:46:01 -080056import org.onosproject.store.serializers.KryoNamespaces;
57import org.onosproject.store.service.ConsistentMultimap;
58import org.onosproject.store.service.Serializer;
59import org.onosproject.store.service.StorageService;
alshabib36a4d732016-06-01 16:03:59 -070060import org.opencord.olt.AccessDeviceEvent;
61import org.opencord.olt.AccessDeviceListener;
Tunahan Sezenf0843b92021-04-30 07:13:16 +000062import org.opencord.olt.AccessDevicePort;
alshabib36a4d732016-06-01 16:03:59 -070063import org.opencord.olt.AccessDeviceService;
Amit Ghosh31939522018-08-16 13:28:21 +010064import org.opencord.olt.AccessSubscriberId;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000065import org.opencord.olt.internalapi.AccessDeviceFlowService;
66import org.opencord.olt.internalapi.AccessDeviceMeterService;
Gamze Abaka641fc072018-09-04 09:16:27 +000067import org.opencord.sadis.BandwidthProfileInformation;
68import org.opencord.sadis.BaseInformationService;
69import org.opencord.sadis.SadisService;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010070import org.opencord.sadis.SubscriberAndDeviceInformation;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000071import org.opencord.sadis.UniTagInformation;
alshabibe0559672016-02-21 14:49:51 -080072import org.osgi.service.component.ComponentContext;
Carmelo Casconeca931162019-07-15 18:22:24 -070073import org.osgi.service.component.annotations.Activate;
74import org.osgi.service.component.annotations.Component;
75import org.osgi.service.component.annotations.Deactivate;
76import org.osgi.service.component.annotations.Modified;
77import org.osgi.service.component.annotations.Reference;
78import org.osgi.service.component.annotations.ReferenceCardinality;
Ilayda Ozdemir90a93622021-02-25 09:40:58 +000079import org.osgi.service.component.annotations.ReferencePolicy;
alshabibf0e7e702015-05-30 18:22:36 -070080import org.slf4j.Logger;
81
Andrea Campanella7a1d7e72020-11-05 10:40:10 +010082import java.util.ArrayList;
83import java.util.Collection;
84import java.util.Dictionary;
85import java.util.List;
86import java.util.Map;
87import java.util.Optional;
88import java.util.Properties;
89import java.util.Set;
90import java.util.concurrent.BlockingQueue;
91import java.util.concurrent.CompletableFuture;
Andrea Campanella7a1d7e72020-11-05 10:40:10 +010092import java.util.concurrent.ExecutorService;
93import java.util.concurrent.Executors;
94import java.util.concurrent.LinkedBlockingQueue;
95import java.util.concurrent.ScheduledExecutorService;
96import java.util.concurrent.TimeUnit;
97import java.util.concurrent.atomic.AtomicBoolean;
98
99import static com.google.common.base.Preconditions.checkNotNull;
100import static com.google.common.base.Strings.isNullOrEmpty;
101import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
102import static java.util.stream.Collectors.*;
103import static org.onlab.util.Tools.get;
104import static org.onlab.util.Tools.groupedThreads;
105import static org.opencord.olt.impl.OsgiPropertyConstants.*;
106import static org.slf4j.LoggerFactory.getLogger;
alshabibf0e7e702015-05-30 18:22:36 -0700107
108/**
Jonathan Harte533a422015-10-20 17:31:24 -0700109 * Provisions rules on access devices.
alshabibf0e7e702015-05-30 18:22:36 -0700110 */
Carmelo Casconeca931162019-07-15 18:22:24 -0700111@Component(immediate = true,
112 property = {
Carmelo Casconeca931162019-07-15 18:22:24 -0700113 DEFAULT_BP_ID + ":String=" + DEFAULT_BP_ID_DEFAULT,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000114 DEFAULT_MCAST_SERVICE_NAME + ":String=" + DEFAULT_MCAST_SERVICE_NAME_DEFAULT,
Saurav Das2d3777a2020-08-07 18:48:51 -0700115 EAPOL_DELETE_RETRY_MAX_ATTEMPS + ":Integer=" +
116 EAPOL_DELETE_RETRY_MAX_ATTEMPS_DEFAULT,
Matteo Scandoloa4aaa972020-10-23 15:24:38 -0700117 PROVISION_DELAY + ":Integer=" + PROVISION_DELAY_DEFAULT,
Carmelo Casconeca931162019-07-15 18:22:24 -0700118 })
alshabib8e4fd2f2016-01-12 15:55:53 -0800119public class Olt
120 extends AbstractListenerManager<AccessDeviceEvent, AccessDeviceListener>
121 implements AccessDeviceService {
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000122 private static final String SADIS_NOT_RUNNING = "Sadis is not running.";
Charles Chan54f110f2017-01-20 11:22:42 -0800123 private static final String APP_NAME = "org.opencord.olt";
alshabibe0559672016-02-21 14:49:51 -0800124
Gamze Abakada282b42019-03-11 13:16:48 +0000125 private static final short EAPOL_DEFAULT_VLAN = 4091;
Gamze Abaka838d8142019-02-21 07:06:55 +0000126 private static final String NO_UPLINK_PORT = "No uplink port found for OLT device {}";
alshabibe0559672016-02-21 14:49:51 -0800127
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800128 public static final int HASH_WEIGHT = 10;
Andrea Campanella51118232021-07-01 17:18:02 +0200129 public static final long PENDING_SUBS_MAP_TIMEOUT_MILLIS = 30000L;
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800130
alshabibf0e7e702015-05-30 18:22:36 -0700131 private final Logger log = getLogger(getClass());
132
Thomas Lee Sd7735f92020-02-20 19:21:47 +0530133 private static final String NNI = "nni-";
134
Carmelo Casconeca931162019-07-15 18:22:24 -0700135 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabibf0e7e702015-05-30 18:22:36 -0700136 protected FlowObjectiveService flowObjectiveService;
137
Carmelo Casconeca931162019-07-15 18:22:24 -0700138 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabibf0e7e702015-05-30 18:22:36 -0700139 protected DeviceService deviceService;
140
Andrea Campanella438e1ad2021-03-26 11:41:16 +0100141
Carmelo Casconeca931162019-07-15 18:22:24 -0700142 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabibf0e7e702015-05-30 18:22:36 -0700143 protected CoreService coreService;
144
Andrea Campanella438e1ad2021-03-26 11:41:16 +0100145 //Dependency on driver service is to ensure correct startup order
146 @Reference(cardinality = ReferenceCardinality.MANDATORY)
147 protected DriverService driverService;
148
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000149 @Reference(cardinality = ReferenceCardinality.OPTIONAL,
150 bind = "bindSadisService",
151 unbind = "unbindSadisService",
152 policy = ReferencePolicy.DYNAMIC)
153 protected volatile SadisService sadisService;
Gamze Abaka641fc072018-09-04 09:16:27 +0000154
Carmelo Casconeca931162019-07-15 18:22:24 -0700155 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000156 protected AccessDeviceFlowService oltFlowService;
alshabibe0559672016-02-21 14:49:51 -0800157
Carmelo Casconeca931162019-07-15 18:22:24 -0700158 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000159 protected AccessDeviceMeterService oltMeterService;
Gamze Abakaad329652018-12-20 10:12:21 +0000160
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800161 @Reference(cardinality = ReferenceCardinality.MANDATORY)
162 protected StorageService storageService;
163
164 @Reference(cardinality = ReferenceCardinality.MANDATORY)
165 protected ClusterService clusterService;
166
Hardik Windlassa58fbee2020-03-12 18:33:55 +0530167 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andrea Campanellaaf39b4c2020-05-13 14:07:44 +0200168 protected MastershipService mastershipService;
169
170 @Reference(cardinality = ReferenceCardinality.MANDATORY)
171 protected LeadershipService leadershipService;
172
173 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hardik Windlassa58fbee2020-03-12 18:33:55 +0530174 protected FlowRuleService flowRuleService;
175
Gamze Abaka1f62dd92020-05-07 08:58:13 +0000176 @Reference(cardinality = ReferenceCardinality.MANDATORY)
177 protected ComponentConfigService componentConfigService;
178
Tunahan Sezena07fe962021-02-24 08:24:24 +0000179 @Reference(cardinality = ReferenceCardinality.MANDATORY)
180 protected HostService hostService;
181
Carmelo Casconeca931162019-07-15 18:22:24 -0700182 /**
Carmelo Cascone95ff5122019-11-14 14:19:13 -0800183 * Default bandwidth profile id that is used for authentication trap flows.
Carmelo Casconeca931162019-07-15 18:22:24 -0700184 **/
185 protected String defaultBpId = DEFAULT_BP_ID_DEFAULT;
Gamze Abakaad329652018-12-20 10:12:21 +0000186
Carmelo Casconeca931162019-07-15 18:22:24 -0700187 /**
Gamze Abaka51a34e82020-05-08 13:03:14 +0000188 * Default multicast service name.
Carmelo Casconeca931162019-07-15 18:22:24 -0700189 **/
Gamze Abaka51a34e82020-05-08 13:03:14 +0000190 protected String multicastServiceName = DEFAULT_MCAST_SERVICE_NAME_DEFAULT;
Gamze Abaka33feef52019-02-27 08:16:47 +0000191
Saurav Das2d3777a2020-08-07 18:48:51 -0700192 /**
193 * Default amounts of eapol retry.
194 **/
195 protected int eapolDeleteRetryMaxAttempts = EAPOL_DELETE_RETRY_MAX_ATTEMPS_DEFAULT;
196
Matteo Scandoloa4aaa972020-10-23 15:24:38 -0700197 /**
198 * Delay between EAPOL removal and data plane flows provisioning.
199 */
200 protected int provisionDelay = PROVISION_DELAY_DEFAULT;
201
alshabibf0e7e702015-05-30 18:22:36 -0700202 private final DeviceListener deviceListener = new InternalDeviceListener();
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800203 private final ClusterEventListener clusterListener = new InternalClusterListener();
Tunahan Sezena07fe962021-02-24 08:24:24 +0000204 private final HostListener hostListener = new InternalHostListener();
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800205
206 private ConsistentHasher hasher;
alshabibf0e7e702015-05-30 18:22:36 -0700207
Gamze Abaka641fc072018-09-04 09:16:27 +0000208 protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
209 private BaseInformationService<BandwidthProfileInformation> bpService;
alshabibf0e7e702015-05-30 18:22:36 -0700210
Gamze Abaka641fc072018-09-04 09:16:27 +0000211 private ExecutorService oltInstallers = Executors.newFixedThreadPool(4,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000212 groupedThreads("onos/olt-service",
213 "olt-installer-%d"));
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100214
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700215 protected ExecutorService eventExecutor;
Tunahan Sezena07fe962021-02-24 08:24:24 +0000216 protected ExecutorService hostEventExecutor;
Saurav Das2d3777a2020-08-07 18:48:51 -0700217 protected ExecutorService retryExecutor;
Matteo Scandoloa4aaa972020-10-23 15:24:38 -0700218 protected ScheduledExecutorService provisionExecutor;
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700219
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800220 private ConsistentMultimap<ConnectPoint, UniTagInformation> programmedSubs;
Saurav Das2d3777a2020-08-07 18:48:51 -0700221 private ConsistentMultimap<ConnectPoint, UniTagInformation> failedSubs;
Saurav Dasa9d5f442019-03-06 19:32:48 -0800222
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000223 protected Map<DeviceId, BlockingQueue<SubscriberFlowInfo>> pendingSubscribersForDevice;
Tunahan Sezena07fe962021-02-24 08:24:24 +0000224 private ConsistentMultimap<ConnectPoint, SubscriberFlowInfo> waitingMacSubscribers;
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700225
alshabibf0e7e702015-05-30 18:22:36 -0700226 @Activate
alshabibe0559672016-02-21 14:49:51 -0800227 public void activate(ComponentContext context) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000228 eventExecutor = newSingleThreadScheduledExecutor(groupedThreads("onos/olt",
229 "events-%d", log));
Tunahan Sezena07fe962021-02-24 08:24:24 +0000230 hostEventExecutor = Executors.newFixedThreadPool(8, groupedThreads("onos/olt", "mac-events-%d", log));
Saurav Das2d3777a2020-08-07 18:48:51 -0700231 retryExecutor = Executors.newCachedThreadPool();
Matteo Scandoloa4aaa972020-10-23 15:24:38 -0700232 provisionExecutor = Executors.newSingleThreadScheduledExecutor(groupedThreads("onos/olt",
233 "provision-%d", log));
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700234
alshabibe0559672016-02-21 14:49:51 -0800235 modified(context);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000236 ApplicationId appId = coreService.registerApplication(APP_NAME);
Gamze Abaka1f62dd92020-05-07 08:58:13 +0000237 componentConfigService.registerProperties(getClass());
Saurav Das62ad75e2019-03-05 12:22:22 -0800238
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800239 KryoNamespace serializer = KryoNamespace.newBuilder()
240 .register(KryoNamespaces.API)
241 .register(UniTagInformation.class)
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000242 .register(SubscriberFlowInfo.class)
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000243 .register(AccessDevicePort.class)
244 .register(AccessDevicePort.Type.class)
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000245 .register(LinkedBlockingQueue.class)
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800246 .build();
247
248 programmedSubs = storageService.<ConnectPoint, UniTagInformation>consistentMultimapBuilder()
249 .withName("volt-programmed-subs")
250 .withSerializer(Serializer.using(serializer))
251 .withApplicationId(appId)
252 .build();
alshabibc4dfe852015-06-05 13:35:13 -0700253
Saurav Das2d3777a2020-08-07 18:48:51 -0700254 failedSubs = storageService.<ConnectPoint, UniTagInformation>consistentMultimapBuilder()
255 .withName("volt-failed-subs")
256 .withSerializer(Serializer.using(serializer))
257 .withApplicationId(appId)
258 .build();
259
Tunahan Sezena07fe962021-02-24 08:24:24 +0000260 KryoNamespace macSerializer = KryoNamespace.newBuilder()
261 .register(KryoNamespaces.API)
262 .register(SubscriberFlowInfo.class)
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000263 .register(AccessDevicePort.class)
264 .register(AccessDevicePort.Type.class)
Tunahan Sezena07fe962021-02-24 08:24:24 +0000265 .register(UniTagInformation.class)
266 .build();
267
268 waitingMacSubscribers = storageService.<ConnectPoint, SubscriberFlowInfo>consistentMultimapBuilder()
269 .withName("volt-waiting-mac-subs")
270 .withSerializer(Serializer.using(macSerializer))
271 .withApplicationId(appId)
272 .build();
Andrea Campanella51118232021-07-01 17:18:02 +0200273 //TODO possibly use consistent multimap with compute on key and element to avoid
274 // lock on all objects of the map, while instead obtaining and releasing the lock
275 // on a per subscriber basis.
276 pendingSubscribersForDevice = new DefaultConsistentMap<>(
277 storageService.<DeviceId, BlockingQueue<SubscriberFlowInfo>>consistentMapBuilder()
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000278 .withName("volt-pending-subs")
279 .withSerializer(Serializer.using(serializer))
280 .withApplicationId(appId)
Andrea Campanella51118232021-07-01 17:18:02 +0200281 .buildAsyncMap(), PENDING_SUBS_MAP_TIMEOUT_MILLIS).asJavaMap();
alshabib8e4fd2f2016-01-12 15:55:53 -0800282 eventDispatcher.addSink(AccessDeviceEvent.class, listenerRegistry);
283
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000284 if (sadisService != null) {
285 subsService = sadisService.getSubscriberInfoService();
286 bpService = sadisService.getBandwidthProfileService();
287 } else {
288 log.warn(SADIS_NOT_RUNNING);
289 }
Gamze Abaka641fc072018-09-04 09:16:27 +0000290
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800291 List<NodeId> readyNodes = clusterService.getNodes().stream()
292 .filter(c -> clusterService.getState(c.id()) == ControllerNode.State.READY)
293 .map(ControllerNode::id)
294 .collect(toList());
295 hasher = new ConsistentHasher(readyNodes, HASH_WEIGHT);
296 clusterService.addListener(clusterListener);
297
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100298 // look for all provisioned devices in Sadis and create EAPOL flows for the
299 // UNI ports
300 Iterable<Device> devices = deviceService.getDevices();
301 for (Device d : devices) {
Andrea Campanellaaf39b4c2020-05-13 14:07:44 +0200302 if (isLocalLeader(d.id())) {
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800303 checkAndCreateDeviceFlows(d);
304 }
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100305 }
alshabib4ceaed32016-03-03 18:00:58 -0800306
alshabibba357492016-01-27 13:49:46 -0800307 deviceService.addListener(deviceListener);
Tunahan Sezena07fe962021-02-24 08:24:24 +0000308 hostService.addListener(hostListener);
alshabibf0e7e702015-05-30 18:22:36 -0700309 log.info("Started with Application ID {}", appId.id());
310 }
311
312 @Deactivate
313 public void deactivate() {
Gamze Abaka1f62dd92020-05-07 08:58:13 +0000314 componentConfigService.unregisterProperties(getClass(), false);
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800315 clusterService.removeListener(clusterListener);
alshabib62e9ce72016-02-11 17:31:36 -0800316 deviceService.removeListener(deviceListener);
Tunahan Sezena07fe962021-02-24 08:24:24 +0000317 hostService.removeListener(hostListener);
Jonathan Hart5f1c8142018-07-24 17:31:59 -0700318 eventDispatcher.removeSink(AccessDeviceEvent.class);
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700319 eventExecutor.shutdown();
Tunahan Sezena07fe962021-02-24 08:24:24 +0000320 hostEventExecutor.shutdown();
Saurav Das2d3777a2020-08-07 18:48:51 -0700321 retryExecutor.shutdown();
Matteo Scandoloa4aaa972020-10-23 15:24:38 -0700322 provisionExecutor.shutdown();
alshabibf0e7e702015-05-30 18:22:36 -0700323 log.info("Stopped");
324 }
325
alshabibe0559672016-02-21 14:49:51 -0800326 @Modified
327 public void modified(ComponentContext context) {
328 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
329
330 try {
Andrea Campanella971d5b92020-05-07 11:20:43 +0200331 String bpId = get(properties, DEFAULT_BP_ID);
332 defaultBpId = isNullOrEmpty(bpId) ? defaultBpId : bpId;
Gamze Abakaad329652018-12-20 10:12:21 +0000333
Andrea Campanella971d5b92020-05-07 11:20:43 +0200334 String mcastSN = get(properties, DEFAULT_MCAST_SERVICE_NAME);
335 multicastServiceName = isNullOrEmpty(mcastSN) ? multicastServiceName : mcastSN;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000336
Saurav Das2d3777a2020-08-07 18:48:51 -0700337 String eapolDeleteRetryNew = get(properties, EAPOL_DELETE_RETRY_MAX_ATTEMPS);
338 eapolDeleteRetryMaxAttempts = isNullOrEmpty(eapolDeleteRetryNew) ? EAPOL_DELETE_RETRY_MAX_ATTEMPS_DEFAULT :
339 Integer.parseInt(eapolDeleteRetryNew.trim());
340
341 log.debug("OLT properties: DefaultBpId: {}, MulticastServiceName: {}, EapolDeleteRetryMaxAttempts: {}",
342 defaultBpId, multicastServiceName, eapolDeleteRetryMaxAttempts);
Gamze Abaka33feef52019-02-27 08:16:47 +0000343
alshabibe0559672016-02-21 14:49:51 -0800344 } catch (Exception e) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000345 log.error("Error while modifying the properties", e);
Andrea Campanella971d5b92020-05-07 11:20:43 +0200346 defaultBpId = DEFAULT_BP_ID_DEFAULT;
347 multicastServiceName = DEFAULT_MCAST_SERVICE_NAME_DEFAULT;
alshabibe0559672016-02-21 14:49:51 -0800348 }
349 }
350
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000351 protected void bindSadisService(SadisService service) {
352 sadisService = service;
353 bpService = sadisService.getBandwidthProfileService();
354 subsService = sadisService.getSubscriberInfoService();
355 log.info("Sadis-service binds to onos.");
356 }
357
358 protected void unbindSadisService(SadisService service) {
359 sadisService = null;
360 bpService = null;
361 subsService = null;
362 log.info("Sadis-service unbinds from onos.");
363 }
364
alshabib32232c82016-02-25 17:57:24 -0500365 @Override
Gamze Abaka838d8142019-02-21 07:06:55 +0000366 public boolean provisionSubscriber(ConnectPoint connectPoint) {
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200367 log.info("Call to provision subscriber at {}", connectPoint);
Gamze Abaka838d8142019-02-21 07:06:55 +0000368 DeviceId deviceId = connectPoint.deviceId();
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000369 Port subscriberPortOnos = deviceService.getPort(deviceId, connectPoint.port());
370 checkNotNull(subscriberPortOnos, "Invalid connect point:" + connectPoint);
371 AccessDevicePort subscriberPort = new AccessDevicePort(subscriberPortOnos, AccessDevicePort.Type.UNI);
Hardik Windlass395ff372019-06-13 05:16:00 +0000372
Saurav Das026650f2020-09-21 18:56:35 -0700373 if (isSubscriberInstalled(connectPoint)) {
374 log.warn("Subscriber at {} already provisioned or in the process .."
375 + " not taking any more action", connectPoint);
376 return true;
377 }
378
379 // Find the subscriber config at this connect point
Gamze Abaka838d8142019-02-21 07:06:55 +0000380 SubscriberAndDeviceInformation sub = getSubscriber(connectPoint);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100381 if (sub == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000382 log.warn("No subscriber found for {}", connectPoint);
Amit Ghosh31939522018-08-16 13:28:21 +0100383 return false;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100384 }
Jonathan Harte533a422015-10-20 17:31:24 -0700385
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100386 // Get the uplink port
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000387 AccessDevicePort uplinkPort = getUplinkPort(deviceService.getDevice(deviceId));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100388 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000389 log.warn(NO_UPLINK_PORT, deviceId);
Amit Ghosh31939522018-08-16 13:28:21 +0100390 return false;
Jonathan Harte533a422015-10-20 17:31:24 -0700391 }
392
Saurav Das2d3777a2020-08-07 18:48:51 -0700393 // delete Eapol authentication flow with default bandwidth
394 // wait until Eapol rule with defaultBpId is removed to install subscriber-based rules
395 // retry deletion if it fails/times-out
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000396 retryExecutor.execute(new DeleteEapolInstallSub(subscriberPort, uplinkPort, sub, 1));
Amit Ghosh31939522018-08-16 13:28:21 +0100397 return true;
alshabibb7a9e172016-01-13 11:23:53 -0800398 }
399
Saurav Das026650f2020-09-21 18:56:35 -0700400 // returns true if subscriber is programmed or in the process of being programmed
401 private boolean isSubscriberInstalled(ConnectPoint connectPoint) {
402 Collection<? extends UniTagInformation> uniTagInformationSet =
403 programmedSubs.get(connectPoint).value();
404 if (!uniTagInformationSet.isEmpty()) {
405 return true;
406 }
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100407 //Check if the subscriber is already getting provisioned
408 // so we do not provision twice
409 AtomicBoolean isPending = new AtomicBoolean(false);
410 pendingSubscribersForDevice.computeIfPresent(connectPoint.deviceId(), (id, infos) -> {
411 for (SubscriberFlowInfo fi : infos) {
412 if (fi.getUniPort().equals(connectPoint.port())) {
yasin saplib4b8ee12021-06-13 18:25:20 +0000413 log.debug("Subscriber is already pending, {}", fi);
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100414 isPending.set(true);
415 break;
416 }
Saurav Das026650f2020-09-21 18:56:35 -0700417 }
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100418 return infos;
419 });
Saurav Das026650f2020-09-21 18:56:35 -0700420
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100421 return isPending.get();
Saurav Das026650f2020-09-21 18:56:35 -0700422 }
423
Saurav Das2d3777a2020-08-07 18:48:51 -0700424 private class DeleteEapolInstallSub implements Runnable {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000425 AccessDevicePort subscriberPort;
426 AccessDevicePort uplinkPort;
Saurav Das2d3777a2020-08-07 18:48:51 -0700427 SubscriberAndDeviceInformation sub;
428 private int attemptNumber;
429
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000430 DeleteEapolInstallSub(AccessDevicePort subscriberPort, AccessDevicePort uplinkPort,
Saurav Das2d3777a2020-08-07 18:48:51 -0700431 SubscriberAndDeviceInformation sub,
432 int attemptNumber) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000433 this.subscriberPort = subscriberPort;
Saurav Das2d3777a2020-08-07 18:48:51 -0700434 this.uplinkPort = uplinkPort;
435 this.sub = sub;
436 this.attemptNumber = attemptNumber;
437 }
438
439 @Override
440 public void run() {
Tunahan Sezena07fe962021-02-24 08:24:24 +0000441 CompletableFuture<ObjectiveError> filterFuture = new CompletableFuture<>();
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000442 oltFlowService.processEapolFilteringObjectives(subscriberPort,
yasin saplib4b8ee12021-06-13 18:25:20 +0000443 defaultBpId, Optional.empty(), filterFuture,
Saurav Das2d3777a2020-08-07 18:48:51 -0700444 VlanId.vlanId(EAPOL_DEFAULT_VLAN),
445 false);
446 filterFuture.thenAcceptAsync(filterStatus -> {
447 if (filterStatus == null) {
448 log.info("Default eapol flow deleted in attempt {} of {}"
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000449 + "... provisioning subscriber flows on {}",
450 attemptNumber, eapolDeleteRetryMaxAttempts, subscriberPort);
Matteo Scandoloa4aaa972020-10-23 15:24:38 -0700451
452 // FIXME this is needed to prevent that default EAPOL flow removal and
453 // data plane flows install are received by the device at the same time
454 provisionExecutor.schedule(
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000455 () -> provisionUniTagList(subscriberPort, uplinkPort, sub),
Matteo Scandoloa4aaa972020-10-23 15:24:38 -0700456 provisionDelay, TimeUnit.MILLISECONDS);
Saurav Das2d3777a2020-08-07 18:48:51 -0700457 } else {
458 if (attemptNumber <= eapolDeleteRetryMaxAttempts) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000459 log.warn("The filtering future failed {} for subscriber on {}"
Saurav Das2d3777a2020-08-07 18:48:51 -0700460 + "... retrying {} of {} attempts",
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000461 filterStatus, subscriberPort, attemptNumber, eapolDeleteRetryMaxAttempts);
Saurav Das2d3777a2020-08-07 18:48:51 -0700462 retryExecutor.execute(
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000463 new DeleteEapolInstallSub(subscriberPort, uplinkPort, sub,
Saurav Das2d3777a2020-08-07 18:48:51 -0700464 attemptNumber + 1));
465 } else {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000466 log.error("The filtering future failed {} for subscriber on {}"
Saurav Das2d3777a2020-08-07 18:48:51 -0700467 + "after {} attempts. Subscriber provisioning failed",
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000468 filterStatus, subscriberPort, eapolDeleteRetryMaxAttempts);
469 sub.uniTagList().forEach(ut ->
470 failedSubs.put(
471 new ConnectPoint(subscriberPort.deviceId(), subscriberPort.number()), ut));
Saurav Das2d3777a2020-08-07 18:48:51 -0700472 }
473 }
474 });
475 }
476
477 }
478
alshabibb7a9e172016-01-13 11:23:53 -0800479 @Override
Gamze Abaka838d8142019-02-21 07:06:55 +0000480 public boolean removeSubscriber(ConnectPoint connectPoint) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000481 Port subscriberPort = deviceService.getPort(connectPoint);
482 if (subscriberPort == null) {
483 log.error("Subscriber port not found at: {}", connectPoint);
484 return false;
485 }
486 return removeSubscriber(new AccessDevicePort(subscriberPort, AccessDevicePort.Type.UNI));
487 }
488
489 private boolean removeSubscriber(AccessDevicePort subscriberPort) {
490 log.info("Call to un-provision subscriber at {}", subscriberPort);
Andrea Campanella51118232021-07-01 17:18:02 +0200491 //TODO we need to check if the subscriber is pending
Saurav Daseae48de2019-06-19 13:26:15 -0700492 // Get the subscriber connected to this port from the local cache
493 // If we don't know about the subscriber there's no need to remove it
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000494 DeviceId deviceId = subscriberPort.deviceId();
Gamze Abaka838d8142019-02-21 07:06:55 +0000495
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000496 ConnectPoint connectPoint = new ConnectPoint(deviceId, subscriberPort.number());
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800497 Collection<? extends UniTagInformation> uniTagInformationSet = programmedSubs.get(connectPoint).value();
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000498 if (uniTagInformationSet == null || uniTagInformationSet.isEmpty()) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000499 log.warn("Subscriber on connectionPoint {} was not previously programmed, " +
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000500 "no need to remove it", connectPoint);
Matteo Scandolo962a6ad2018-12-11 15:39:42 -0800501 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800502 }
503
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100504 // Get the uplink port
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000505 AccessDevicePort uplinkPort = getUplinkPort(deviceService.getDevice(deviceId));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100506 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000507 log.warn(NO_UPLINK_PORT, deviceId);
Amit Ghosh31939522018-08-16 13:28:21 +0100508 return false;
alshabib4ceaed32016-03-03 18:00:58 -0800509 }
510
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000511 for (UniTagInformation uniTag : uniTagInformationSet) {
Amit Ghosh95e2f652017-08-23 12:49:46 +0100512
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000513 if (multicastServiceName.equals(uniTag.getServiceName())) {
514 continue;
515 }
Gamze Abaka838d8142019-02-21 07:06:55 +0000516
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000517 unprovisionVlans(uplinkPort, subscriberPort, uniTag);
alshabibbf23a1f2016-01-14 17:27:11 -0800518
Saurav Das9da7d522020-03-23 19:14:35 -0700519 // remove eapol with subscriber bandwidth profile
yasin saplib4b8ee12021-06-13 18:25:20 +0000520 Optional<String> upstreamOltBw = uniTag.getUpstreamOltBandwidthProfile() == null ?
521 Optional.empty() : Optional.of(uniTag.getUpstreamOltBandwidthProfile());
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000522 oltFlowService.processEapolFilteringObjectives(subscriberPort,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000523 uniTag.getUpstreamBandwidthProfile(),
yasin saplib4b8ee12021-06-13 18:25:20 +0000524 upstreamOltBw,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000525 null, uniTag.getPonCTag(), false);
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100526
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000527 if (subscriberPort.port() != null && subscriberPort.isEnabled()) {
Saurav Das9da7d522020-03-23 19:14:35 -0700528 // reinstall eapol with default bandwidth profile
yasin saplib4b8ee12021-06-13 18:25:20 +0000529 oltFlowService.processEapolFilteringObjectives(subscriberPort, defaultBpId, Optional.empty(),
530 null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000531 } else {
532 log.debug("Port {} is no longer enabled or it's unavailable. Not "
533 + "reprogramming default eapol flow", connectPoint);
534 }
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100535 }
Amit Ghosh31939522018-08-16 13:28:21 +0100536 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800537 }
538
Gamze Abakaf59c0912019-04-19 08:24:28 +0000539
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000540 @Override
541 public boolean provisionSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag,
542 Optional<VlanId> cTag, Optional<Integer> tpId) {
543
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000544 log.info("Provisioning subscriber using subscriberId {}, sTag {}, cTag {}, tpId {}",
545 subscriberId, sTag, cTag, tpId);
Gamze Abakaf59c0912019-04-19 08:24:28 +0000546
Amit Ghosh31939522018-08-16 13:28:21 +0100547 // Check if we can find the connect point to which this subscriber is connected
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000548 ConnectPoint cp = findSubscriberConnectPoint(subscriberId.toString());
549 if (cp == null) {
Amit Ghosh31939522018-08-16 13:28:21 +0100550 log.warn("ConnectPoint for {} not found", subscriberId);
551 return false;
552 }
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000553 AccessDevicePort subscriberPort = new AccessDevicePort(deviceService.getPort(cp), AccessDevicePort.Type.UNI);
Amit Ghosh31939522018-08-16 13:28:21 +0100554
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100555 if (!sTag.isPresent() && !cTag.isPresent()) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000556 return provisionSubscriber(cp);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000557 } else if (sTag.isPresent() && cTag.isPresent() && tpId.isPresent()) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000558 AccessDevicePort uplinkPort = getUplinkPort(deviceService.getDevice(cp.deviceId()));
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100559 if (uplinkPort == null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000560 log.warn(NO_UPLINK_PORT, cp.deviceId());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100561 return false;
562 }
563
Gamze Abakaf59c0912019-04-19 08:24:28 +0000564 //delete Eapol authentication flow with default bandwidth
565 //wait until Eapol rule with defaultBpId is removed to install subscriber-based rules
Gamze Abakaf59c0912019-04-19 08:24:28 +0000566 //install subscriber flows
Tunahan Sezena07fe962021-02-24 08:24:24 +0000567 CompletableFuture<ObjectiveError> filterFuture = new CompletableFuture<>();
yasin saplib4b8ee12021-06-13 18:25:20 +0000568 oltFlowService.processEapolFilteringObjectives(subscriberPort, defaultBpId, Optional.empty(),
569 filterFuture, VlanId.vlanId(EAPOL_DEFAULT_VLAN), false);
Gamze Abakaf59c0912019-04-19 08:24:28 +0000570 filterFuture.thenAcceptAsync(filterStatus -> {
571 if (filterStatus == null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000572 provisionUniTagInformation(uplinkPort, subscriberPort, cTag.get(), sTag.get(), tpId.get());
Gamze Abakaf59c0912019-04-19 08:24:28 +0000573 }
574 });
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100575 return true;
576 } else {
577 log.warn("Provisioning failed for subscriber: {}", subscriberId);
578 return false;
579 }
Amit Ghosh31939522018-08-16 13:28:21 +0100580 }
Amit Ghosh95e2f652017-08-23 12:49:46 +0100581
alshabibe0559672016-02-21 14:49:51 -0800582 @Override
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000583 public boolean removeSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag,
584 Optional<VlanId> cTag, Optional<Integer> tpId) {
Amit Ghosh31939522018-08-16 13:28:21 +0100585 // Check if we can find the connect point to which this subscriber is connected
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000586 ConnectPoint cp = findSubscriberConnectPoint(subscriberId.toString());
587 if (cp == null) {
Amit Ghosh31939522018-08-16 13:28:21 +0100588 log.warn("ConnectPoint for {} not found", subscriberId);
589 return false;
590 }
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000591 AccessDevicePort subscriberPort = new AccessDevicePort(deviceService.getPort(cp), AccessDevicePort.Type.UNI);
Amit Ghosh31939522018-08-16 13:28:21 +0100592
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100593 if (!sTag.isPresent() && !cTag.isPresent()) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000594 return removeSubscriber(cp);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000595 } else if (sTag.isPresent() && cTag.isPresent() && tpId.isPresent()) {
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100596 // Get the uplink port
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000597 AccessDevicePort uplinkPort = getUplinkPort(deviceService.getDevice(cp.deviceId()));
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100598 if (uplinkPort == null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000599 log.warn(NO_UPLINK_PORT, cp.deviceId());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100600 return false;
601 }
602
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000603 Optional<UniTagInformation> tagInfo = getUniTagInformation(subscriberPort, cTag.get(),
604 sTag.get(), tpId.get());
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000605 if (!tagInfo.isPresent()) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000606 log.warn("UniTagInformation does not exist for {}, cTag {}, sTag {}, tpId {}",
607 subscriberPort, cTag, sTag, tpId);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000608 return false;
609 }
Gamze Abakaf59c0912019-04-19 08:24:28 +0000610
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000611 unprovisionVlans(uplinkPort, subscriberPort, tagInfo.get());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100612 return true;
613 } else {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000614 log.warn("Removing subscriber is not possible - please check the provided information" +
615 "for the subscriber: {}", subscriberId);
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100616 return false;
617 }
Amit Ghosh31939522018-08-16 13:28:21 +0100618 }
619
620 @Override
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000621 public ImmutableMap<ConnectPoint, Set<UniTagInformation>> getProgSubs() {
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800622 return programmedSubs.stream()
623 .collect(collectingAndThen(
624 groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, toSet())),
625 ImmutableMap::copyOf));
Saurav Das82b8e6d2018-10-04 15:25:12 -0700626 }
627
628 @Override
Saurav Das2d3777a2020-08-07 18:48:51 -0700629 public ImmutableMap<ConnectPoint, Set<UniTagInformation>> getFailedSubs() {
630 return failedSubs.stream()
631 .collect(collectingAndThen(
632 groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, toSet())),
633 ImmutableMap::copyOf));
634 }
635
636 @Override
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100637 public List<DeviceId> fetchOlts() {
638 // look through all the devices and find the ones that are OLTs as per Sadis
639 List<DeviceId> olts = new ArrayList<>();
640 Iterable<Device> devices = deviceService.getDevices();
641 for (Device d : devices) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700642 if (getOltInfo(d) != null) {
643 // So this is indeed an OLT device
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100644 olts.add(d.id());
645 }
646 }
647 return olts;
alshabibe0559672016-02-21 14:49:51 -0800648 }
649
Amit Ghosh31939522018-08-16 13:28:21 +0100650 /**
651 * Finds the connect point to which a subscriber is connected.
652 *
653 * @param id The id of the subscriber, this is the same ID as in Sadis
654 * @return Subscribers ConnectPoint if found else null
655 */
656 private ConnectPoint findSubscriberConnectPoint(String id) {
657
658 Iterable<Device> devices = deviceService.getDevices();
659 for (Device d : devices) {
660 for (Port p : deviceService.getPorts(d.id())) {
661 log.trace("Comparing {} with {}", p.annotations().value(AnnotationKeys.PORT_NAME), id);
662 if (p.annotations().value(AnnotationKeys.PORT_NAME).equals(id)) {
663 log.debug("Found on device {} port {}", d.id(), p.number());
664 return new ConnectPoint(d.id(), p.number());
665 }
666 }
667 }
668 return null;
669 }
670
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000671 /**
672 * Gets the context of the bandwidth profile information for the given parameter.
673 *
674 * @param bandwidthProfile the bandwidth profile id
675 * @return the context of the bandwidth profile information
676 */
Gamze Abaka641fc072018-09-04 09:16:27 +0000677 private BandwidthProfileInformation getBandwidthProfileInformation(String bandwidthProfile) {
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000678 if (bpService == null) {
679 log.warn(SADIS_NOT_RUNNING);
680 return null;
681 }
Gamze Abaka641fc072018-09-04 09:16:27 +0000682 if (bandwidthProfile == null) {
683 return null;
684 }
685 return bpService.get(bandwidthProfile);
686 }
687
Gamze Abaka838d8142019-02-21 07:06:55 +0000688 /**
Gamze Abaka33feef52019-02-27 08:16:47 +0000689 * Removes subscriber vlan flows.
Gamze Abaka838d8142019-02-21 07:06:55 +0000690 *
Gamze Abaka838d8142019-02-21 07:06:55 +0000691 * @param uplink uplink port of the OLT
692 * @param subscriberPort uni port
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000693 * @param uniTag uni tag information
Gamze Abaka838d8142019-02-21 07:06:55 +0000694 */
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000695 private void unprovisionVlans(AccessDevicePort uplink, AccessDevicePort subscriberPort, UniTagInformation uniTag) {
696 log.info("Unprovisioning vlans for {} at {}", uniTag, subscriberPort);
697 DeviceId deviceId = subscriberPort.deviceId();
alshabibbf23a1f2016-01-14 17:27:11 -0800698
Tunahan Sezena07fe962021-02-24 08:24:24 +0000699 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture<>();
700 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture<>();
alshabibbf23a1f2016-01-14 17:27:11 -0800701
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000702 VlanId deviceVlan = uniTag.getPonSTag();
703 VlanId subscriberVlan = uniTag.getPonCTag();
Gamze Abaka641fc072018-09-04 09:16:27 +0000704
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000705 MeterId upstreamMeterId = oltMeterService
706 .getMeterIdFromBpMapping(deviceId, uniTag.getUpstreamBandwidthProfile());
707 MeterId downstreamMeterId = oltMeterService
708 .getMeterIdFromBpMapping(deviceId, uniTag.getDownstreamBandwidthProfile());
yasin saplib4b8ee12021-06-13 18:25:20 +0000709 MeterId upstreamOltMeterId = oltMeterService
710 .getMeterIdFromBpMapping(deviceId, uniTag.getUpstreamOltBandwidthProfile());
711 MeterId downstreamOltMeterId = oltMeterService
712 .getMeterIdFromBpMapping(deviceId, uniTag.getDownstreamOltBandwidthProfile());
Gamze Abaka641fc072018-09-04 09:16:27 +0000713
Tunahan Sezena07fe962021-02-24 08:24:24 +0000714 Optional<SubscriberFlowInfo> waitingMacSubFlowInfo =
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000715 getAndRemoveWaitingMacSubFlowInfoForCTag(new ConnectPoint(deviceId, subscriberPort.number()),
716 subscriberVlan);
Tunahan Sezena07fe962021-02-24 08:24:24 +0000717 if (waitingMacSubFlowInfo.isPresent()) {
718 // only dhcp objectives applied previously, so only dhcp uninstallation objective will be processed
719 log.debug("Waiting MAC service removed and dhcp uninstallation objective will be processed. " +
720 "waitingMacSubFlowInfo:{}", waitingMacSubFlowInfo.get());
721 CompletableFuture<ObjectiveError> dhcpFuture = new CompletableFuture<>();
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000722 oltFlowService.processDhcpFilteringObjectives(subscriberPort,
yasin saplib4b8ee12021-06-13 18:25:20 +0000723 upstreamMeterId, upstreamOltMeterId, uniTag, false, true, Optional.of(dhcpFuture));
Tunahan Sezena07fe962021-02-24 08:24:24 +0000724 dhcpFuture.thenAcceptAsync(dhcpStatus -> {
725 AccessDeviceEvent.Type type;
726 if (dhcpStatus == null) {
727 type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_UNREGISTERED;
728 log.debug("Dhcp uninstallation objective was processed successfully for cTag {}, sTag {}, " +
729 "tpId {} and Device/Port:{}", uniTag.getPonCTag(), uniTag.getPonSTag(),
730 uniTag.getTechnologyProfileId(), subscriberPort);
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000731 updateProgrammedSubscriber(subscriberPort, uniTag, false);
Tunahan Sezena07fe962021-02-24 08:24:24 +0000732 } else {
733 type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_UNREGISTRATION_FAILED;
734 log.error("Dhcp uninstallation objective was failed for cTag {}, sTag {}, " +
735 "tpId {} and Device/Port:{} :{}", uniTag.getPonCTag(), uniTag.getPonSTag(),
736 uniTag.getTechnologyProfileId(), subscriberPort, dhcpStatus);
737 }
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000738 post(new AccessDeviceEvent(type, deviceId, subscriberPort.port(),
Tunahan Sezena07fe962021-02-24 08:24:24 +0000739 deviceVlan, subscriberVlan, uniTag.getTechnologyProfileId()));
740 });
741 return;
742 } else {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000743 log.debug("There is no waiting MAC service for {} and subscriberVlan: {}", subscriberPort, subscriberVlan);
Tunahan Sezena07fe962021-02-24 08:24:24 +0000744 }
745
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000746 ForwardingObjective.Builder upFwd =
yasin saplib4b8ee12021-06-13 18:25:20 +0000747 oltFlowService.createUpBuilder(uplink, subscriberPort, upstreamMeterId, upstreamOltMeterId, uniTag);
Tunahan Sezena07fe962021-02-24 08:24:24 +0000748
749 Optional<MacAddress> macAddress = getMacAddress(deviceId, subscriberPort, uniTag);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000750 ForwardingObjective.Builder downFwd =
yasin saplib4b8ee12021-06-13 18:25:20 +0000751 oltFlowService.createDownBuilder(uplink, subscriberPort, downstreamMeterId, downstreamOltMeterId,
752 uniTag, macAddress);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000753
yasin saplib4b8ee12021-06-13 18:25:20 +0000754 oltFlowService.processIgmpFilteringObjectives(subscriberPort, upstreamMeterId, upstreamOltMeterId, uniTag,
755 false, true);
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000756 oltFlowService.processDhcpFilteringObjectives(subscriberPort,
yasin saplib4b8ee12021-06-13 18:25:20 +0000757 upstreamMeterId, upstreamOltMeterId, uniTag, false, true, Optional.empty());
758 oltFlowService.processPPPoEDFilteringObjectives(subscriberPort, upstreamMeterId, upstreamOltMeterId, uniTag,
759 false, true);
alshabibbf23a1f2016-01-14 17:27:11 -0800760
alshabib4ceaed32016-03-03 18:00:58 -0800761 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
762 @Override
763 public void onSuccess(Objective objective) {
764 upFuture.complete(null);
765 }
alshabibbf23a1f2016-01-14 17:27:11 -0800766
alshabib4ceaed32016-03-03 18:00:58 -0800767 @Override
768 public void onError(Objective objective, ObjectiveError error) {
769 upFuture.complete(error);
770 }
771 }));
772
773 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
774 @Override
775 public void onSuccess(Objective objective) {
776 downFuture.complete(null);
777 }
778
779 @Override
780 public void onError(Objective objective, ObjectiveError error) {
781 downFuture.complete(error);
782 }
783 }));
alshabibbf23a1f2016-01-14 17:27:11 -0800784
785 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000786 AccessDeviceEvent.Type type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_UNREGISTERED;
alshabibbf23a1f2016-01-14 17:27:11 -0800787 if (upStatus == null && downStatus == null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000788 log.debug("Uni tag information is unregistered successfully for cTag {}, sTag {}, tpId {} on {}",
789 uniTag.getPonCTag(), uniTag.getPonSTag(), uniTag.getTechnologyProfileId(), subscriberPort);
790 updateProgrammedSubscriber(subscriberPort, uniTag, false);
alshabibbf23a1f2016-01-14 17:27:11 -0800791 } else if (downStatus != null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000792 log.error("Subscriber with vlan {} on {} failed downstream uninstallation: {}",
793 subscriberVlan, subscriberPort, downStatus);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000794 type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_UNREGISTRATION_FAILED;
alshabibbf23a1f2016-01-14 17:27:11 -0800795 } else if (upStatus != null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000796 log.error("Subscriber with vlan {} on {} failed upstream uninstallation: {}",
797 subscriberVlan, subscriberPort, upStatus);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000798 type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_UNREGISTRATION_FAILED;
alshabibbf23a1f2016-01-14 17:27:11 -0800799 }
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000800 post(new AccessDeviceEvent(type, deviceId, subscriberPort.port(), deviceVlan, subscriberVlan,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000801 uniTag.getTechnologyProfileId()));
alshabibbf23a1f2016-01-14 17:27:11 -0800802 }, oltInstallers);
Jonathan Harte533a422015-10-20 17:31:24 -0700803 }
804
Tunahan Sezena07fe962021-02-24 08:24:24 +0000805 private Optional<SubscriberFlowInfo> getAndRemoveWaitingMacSubFlowInfoForCTag(ConnectPoint cp, VlanId cTag) {
806 SubscriberFlowInfo returnSubFlowInfo = null;
807 Collection<? extends SubscriberFlowInfo> subFlowInfoSet = waitingMacSubscribers.get(cp).value();
808 for (SubscriberFlowInfo subFlowInfo : subFlowInfoSet) {
809 if (subFlowInfo.getTagInfo().getPonCTag().equals(cTag)) {
810 returnSubFlowInfo = subFlowInfo;
811 break;
812 }
813 }
814 if (returnSubFlowInfo != null) {
815 waitingMacSubscribers.remove(cp, returnSubFlowInfo);
816 return Optional.of(returnSubFlowInfo);
817 }
818 return Optional.empty();
819 }
820
Gamze Abaka838d8142019-02-21 07:06:55 +0000821 /**
Gamze Abaka33feef52019-02-27 08:16:47 +0000822 * Adds subscriber vlan flows, dhcp, eapol and igmp trap flows for the related uni port.
Gamze Abaka838d8142019-02-21 07:06:55 +0000823 *
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000824 * @param subPort the connection point of the subscriber
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000825 * @param uplinkPort uplink port of the OLT (the nni port)
826 * @param sub subscriber information that includes s, c tags, tech profile and bandwidth profile references
Gamze Abaka838d8142019-02-21 07:06:55 +0000827 */
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000828 private void provisionUniTagList(AccessDevicePort subPort, AccessDevicePort uplinkPort,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000829 SubscriberAndDeviceInformation sub) {
Gamze Abaka641fc072018-09-04 09:16:27 +0000830
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000831 log.debug("Provisioning vlans for subscriber on {}", subPort);
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700832 if (log.isTraceEnabled()) {
833 log.trace("Subscriber informations {}", sub);
834 }
Gamze Abaka641fc072018-09-04 09:16:27 +0000835
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000836 if (sub.uniTagList() == null || sub.uniTagList().isEmpty()) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000837 log.warn("Unitaglist doesn't exist for the subscriber {} on {}", sub.id(), subPort);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000838 return;
839 }
Gamze Abaka641fc072018-09-04 09:16:27 +0000840
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000841 for (UniTagInformation uniTag : sub.uniTagList()) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000842 handleSubscriberFlows(uplinkPort, subPort, uniTag);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000843 }
844 }
alshabib3ea82642016-01-12 18:06:53 -0800845
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000846 /**
847 * Finds the uni tag information and provisions the found information.
848 * If the uni tag information is not found, returns
849 *
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000850 * @param uplinkPort the nni port
851 * @param subscriberPort the uni port
852 * @param innerVlan the pon c tag
853 * @param outerVlan the pon s tag
854 * @param tpId the technology profile id
855 */
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000856 private void provisionUniTagInformation(AccessDevicePort uplinkPort,
857 AccessDevicePort subscriberPort,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000858 VlanId innerVlan,
859 VlanId outerVlan,
860 Integer tpId) {
Jonathan Harte533a422015-10-20 17:31:24 -0700861
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000862 Optional<UniTagInformation> gotTagInformation = getUniTagInformation(subscriberPort, innerVlan,
863 outerVlan, tpId);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000864 if (!gotTagInformation.isPresent()) {
865 return;
866 }
867 UniTagInformation tagInformation = gotTagInformation.get();
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000868 handleSubscriberFlows(uplinkPort, subscriberPort, tagInformation);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000869 }
alshabib3ea82642016-01-12 18:06:53 -0800870
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000871 private void updateProgrammedSubscriber(AccessDevicePort port, UniTagInformation tagInformation, boolean add) {
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800872 if (add) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000873 programmedSubs.put(new ConnectPoint(port.deviceId(), port.number()), tagInformation);
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800874 } else {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000875 programmedSubs.remove(new ConnectPoint(port.deviceId(), port.number()), tagInformation);
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800876 }
Jonathan Harte533a422015-10-20 17:31:24 -0700877 }
878
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000879 /**
880 * Installs a uni tag information flow.
881 *
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000882 * @param uplinkPort the nni port
883 * @param subscriberPort the uni port
884 * @param tagInfo the uni tag information
885 */
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000886 private void handleSubscriberFlows(AccessDevicePort uplinkPort, AccessDevicePort subscriberPort,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000887 UniTagInformation tagInfo) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000888 log.debug("Provisioning vlan-based flows for the uniTagInformation {} on {}", tagInfo, subscriberPort);
889 DeviceId deviceId = subscriberPort.deviceId();
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000890
891 if (multicastServiceName.equals(tagInfo.getServiceName())) {
892 // IGMP flows are taken care of along with VOD service
893 // Please note that for each service, Subscriber Registered event will be sent
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000894 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_REGISTERED, deviceId,
895 subscriberPort.port(), tagInfo.getPonSTag(), tagInfo.getPonCTag(),
896 tagInfo.getTechnologyProfileId()));
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000897 return;
Gamze Abaka641fc072018-09-04 09:16:27 +0000898 }
899
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000900 BandwidthProfileInformation upstreamBpInfo =
901 getBandwidthProfileInformation(tagInfo.getUpstreamBandwidthProfile());
902 BandwidthProfileInformation downstreamBpInfo =
903 getBandwidthProfileInformation(tagInfo.getDownstreamBandwidthProfile());
yasin saplib4b8ee12021-06-13 18:25:20 +0000904 BandwidthProfileInformation upstreamOltBpInfo =
905 getBandwidthProfileInformation(tagInfo.getUpstreamOltBandwidthProfile());
906 BandwidthProfileInformation downstreamOltBpInfo =
907 getBandwidthProfileInformation(tagInfo.getDownstreamOltBandwidthProfile());
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700908 if (upstreamBpInfo == null) {
909 log.warn("No meter installed since no Upstream BW Profile definition found for "
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000910 + "ctag {} stag {} tpId {} on {}",
911 tagInfo.getPonCTag(), tagInfo.getPonSTag(), tagInfo.getTechnologyProfileId(), subscriberPort);
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700912 return;
913 }
914 if (downstreamBpInfo == null) {
915 log.warn("No meter installed since no Downstream BW Profile definition found for "
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000916 + "ctag {} stag {} tpId {} on {}",
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700917 tagInfo.getPonCTag(), tagInfo.getPonSTag(),
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000918 tagInfo.getTechnologyProfileId(), subscriberPort);
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700919 return;
920 }
yasin saplib4b8ee12021-06-13 18:25:20 +0000921 if ((upstreamOltBpInfo != null && downstreamOltBpInfo == null) ||
922 (upstreamOltBpInfo == null && downstreamOltBpInfo != null)) {
923 log.warn("No meter installed since only one olt BW Profile definition found for "
924 + "ctag {} stag {} tpId {} and Device/port: {}:{}",
925 tagInfo.getPonCTag(), tagInfo.getPonSTag(),
926 tagInfo.getTechnologyProfileId(), deviceId,
927 subscriberPort);
928 return;
929 }
930
931 MeterId upOltMeterId = null;
932 MeterId downOltMeterId = null;
Gamze Abakaf59c0912019-04-19 08:24:28 +0000933
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700934 // check for meterIds for the upstream and downstream bandwidth profiles
935 MeterId upMeterId = oltMeterService
936 .getMeterIdFromBpMapping(deviceId, upstreamBpInfo.id());
937 MeterId downMeterId = oltMeterService
938 .getMeterIdFromBpMapping(deviceId, downstreamBpInfo.id());
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700939
yasin saplib4b8ee12021-06-13 18:25:20 +0000940 if (upstreamOltBpInfo != null) {
941 // Multi UNI service
942 upOltMeterId = oltMeterService
943 .getMeterIdFromBpMapping(deviceId, upstreamOltBpInfo.id());
944 downOltMeterId = oltMeterService
945 .getMeterIdFromBpMapping(deviceId, downstreamOltBpInfo.id());
946 } else {
947 // NOT Multi UNI service
948 log.debug("OLT bandwidth profiles fields are set to ONU bandwidth profiles");
949 upstreamOltBpInfo = upstreamBpInfo;
950 downstreamOltBpInfo = downstreamBpInfo;
951 upOltMeterId = upMeterId;
952 downOltMeterId = downMeterId;
953 }
954 SubscriberFlowInfo fi = new SubscriberFlowInfo(uplinkPort, subscriberPort,
955 tagInfo, downMeterId, upMeterId, downOltMeterId, upOltMeterId,
956 downstreamBpInfo.id(), upstreamBpInfo.id(),
957 downstreamOltBpInfo.id(), upstreamOltBpInfo.id());
958
959 if (upMeterId != null && downMeterId != null && upOltMeterId != null && downOltMeterId != null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000960 log.debug("Meters are existing for upstream {} and downstream {} on {}",
961 upstreamBpInfo.id(), downstreamBpInfo.id(), subscriberPort);
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700962 handleSubFlowsWithMeters(fi);
963 } else {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000964 log.debug("Adding {} on {} to pending subs", fi, subscriberPort);
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700965 // one or both meters are not ready. It's possible they are in the process of being
966 // created for other subscribers that share the same bandwidth profile.
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100967 pendingSubscribersForDevice.compute(deviceId, (id, queue) -> {
968 if (queue == null) {
969 queue = new LinkedBlockingQueue<>();
970 }
971 queue.add(fi);
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000972 log.info("Added {} to pending subscribers on {}", fi, subscriberPort);
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100973 return queue;
974 });
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700975
yasin saplib4b8ee12021-06-13 18:25:20 +0000976 List<BandwidthProfileInformation> bws = new ArrayList<>();
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700977 // queue up the meters to be created
978 if (upMeterId == null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000979 log.debug("Missing meter for upstream {} on {}", upstreamBpInfo.id(), subscriberPort);
yasin saplib4b8ee12021-06-13 18:25:20 +0000980 bws.add(upstreamBpInfo);
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700981 }
982 if (downMeterId == null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000983 log.debug("Missing meter for downstream {} on {}", downstreamBpInfo.id(), subscriberPort);
yasin saplib4b8ee12021-06-13 18:25:20 +0000984 bws.add(downstreamBpInfo);
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700985 }
yasin saplib4b8ee12021-06-13 18:25:20 +0000986 if (upOltMeterId == null) {
987 log.debug("Missing meter for upstreamOlt {} on {}", upstreamOltBpInfo.id(), subscriberPort);
988 bws.add(upstreamOltBpInfo);
989 }
990 if (downOltMeterId == null) {
991 log.debug("Missing meter for downstreamOlt {} on {}", downstreamOltBpInfo.id(), subscriberPort);
992 bws.add(downstreamOltBpInfo);
993 }
994 bws.stream().distinct().forEach(bw -> checkAndCreateDevMeter(deviceId, bw));
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700995 }
996 }
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000997
Andrea Campanella600d2e22020-06-22 11:00:31 +0200998 private void checkAndCreateDevMeter(DeviceId deviceId, BandwidthProfileInformation bwpInfo) {
yasin saplib4b8ee12021-06-13 18:25:20 +0000999 log.debug("Checking and Creating Meter with {} on {}", bwpInfo, deviceId);
1000 if (bwpInfo == null) {
1001 log.error("Can't create meter. Bandwidth profile is null for device : {}", deviceId);
1002 return;
1003 }
Andrea Campanellad1e26642020-10-23 12:08:32 +02001004 //If false the meter is already being installed, skipping installation
1005 if (!oltMeterService.checkAndAddPendingMeter(deviceId, bwpInfo)) {
yasin saplib4b8ee12021-06-13 18:25:20 +00001006 log.debug("Meter is already being installed on {} for {}", deviceId, bwpInfo);
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001007 return;
1008 }
Andrea Campanella600d2e22020-06-22 11:00:31 +02001009 createMeter(deviceId, bwpInfo);
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001010 }
1011
Andrea Campanella600d2e22020-06-22 11:00:31 +02001012 private void createMeter(DeviceId deviceId, BandwidthProfileInformation bwpInfo) {
Andrea Campanella51118232021-07-01 17:18:02 +02001013 log.info("Creating Meter with {} on {}", bwpInfo, deviceId);
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001014 CompletableFuture<Object> meterFuture = new CompletableFuture<>();
Andrea Campanella3ce4d282020-06-09 13:46:58 +02001015
Andrea Campanella600d2e22020-06-22 11:00:31 +02001016 MeterId meterId = oltMeterService.createMeter(deviceId, bwpInfo,
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001017 meterFuture);
1018
1019 meterFuture.thenAcceptAsync(result -> {
Andrea Campanella51118232021-07-01 17:18:02 +02001020 log.info("Meter Future for {} has completed", meterId);
yasin saplib4b8ee12021-06-13 18:25:20 +00001021 pendingSubscribersForDevice.compute(deviceId, (id, queue) -> {
1022 // iterate through the subscribers on hold
1023 if (queue != null && !queue.isEmpty()) {
1024 while (true) {
1025 //TODO this might return the reference and not the actual object so
1026 // it can be actually swapped underneath us.
1027 SubscriberFlowInfo fi = queue.peek();
1028 if (fi == null) {
Andrea Campanella51118232021-07-01 17:18:02 +02001029 log.info("No more subscribers pending on {}", deviceId);
yasin saplib4b8ee12021-06-13 18:25:20 +00001030 queue = new LinkedBlockingQueue<>();
1031 break;
1032 }
1033 if (result == null) {
1034 // meter install sent to device
1035 log.debug("Meter {} installed for bw {} on {}", meterId, bwpInfo, deviceId);
Andrea Campanella7a1d7e72020-11-05 10:40:10 +01001036
yasin saplib4b8ee12021-06-13 18:25:20 +00001037 MeterId upMeterId = oltMeterService
1038 .getMeterIdFromBpMapping(deviceId, fi.getUpBpInfo());
1039 MeterId downMeterId = oltMeterService
1040 .getMeterIdFromBpMapping(deviceId, fi.getDownBpInfo());
1041 MeterId upOltMeterId = oltMeterService
1042 .getMeterIdFromBpMapping(deviceId, fi.getUpOltBpInfo());
1043 MeterId downOltMeterId = oltMeterService
1044 .getMeterIdFromBpMapping(deviceId, fi.getDownOltBpInfo());
1045 if (upMeterId != null && downMeterId != null &&
1046 upOltMeterId != null && downOltMeterId != null) {
1047 log.debug("Provisioning subscriber after meter {} " +
1048 "installation and all meters are present " +
1049 "upstream {} , downstream {} , oltUpstream {} " +
1050 "and oltDownstream {} on {}",
1051 meterId, upMeterId, downMeterId, upOltMeterId,
1052 downOltMeterId, fi.getUniPort());
1053 // put in the meterIds because when fi was first
1054 // created there may or may not have been a meterId
1055 // depending on whether the meter was created or
1056 // not at that time.
Andrea Campanella51118232021-07-01 17:18:02 +02001057 //TODO possibly spawn this in a separate thread.
yasin saplib4b8ee12021-06-13 18:25:20 +00001058 fi.setUpMeterId(upMeterId);
1059 fi.setDownMeterId(downMeterId);
1060 fi.setUpOltMeterId(upOltMeterId);
1061 fi.setDownOltMeterId(downOltMeterId);
1062 handleSubFlowsWithMeters(fi);
1063 queue.remove(fi);
1064 } else {
1065 log.debug("Not all meters for {} are yet installed up {}, " +
1066 "down {}, oltUp {}, oltDown {}", fi, upMeterId,
1067 downMeterId, upOltMeterId, downOltMeterId);
1068 }
1069 oltMeterService.removeFromPendingMeters(deviceId, bwpInfo);
1070 } else {
1071 // meter install failed
1072 log.error("Addition of subscriber {} on {} failed due to meter " +
1073 "{} with result {}", fi, fi.getUniPort(), meterId, result);
1074 oltMeterService.removeFromPendingMeters(deviceId, bwpInfo);
Andrea Campanella7a1d7e72020-11-05 10:40:10 +01001075 queue.remove(fi);
1076 }
Andrea Campanella7a1d7e72020-11-05 10:40:10 +01001077 }
yasin saplib4b8ee12021-06-13 18:25:20 +00001078 } else {
1079 log.info("No pending subscribers on {}", deviceId);
1080 queue = new LinkedBlockingQueue<>();
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001081 }
yasin saplib4b8ee12021-06-13 18:25:20 +00001082 return queue;
1083 });
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001084 });
Andrea Campanella7a1d7e72020-11-05 10:40:10 +01001085
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001086 }
Ilayda Ozdemir90a93622021-02-25 09:40:58 +00001087
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001088 /**
1089 * Add subscriber flows given meter information for both upstream and
1090 * downstream directions.
1091 *
1092 * @param subscriberFlowInfo relevant information for subscriber
1093 */
1094 private void handleSubFlowsWithMeters(SubscriberFlowInfo subscriberFlowInfo) {
Andrea Campanella51118232021-07-01 17:18:02 +02001095 log.info("Provisioning subscriber flows based on {}", subscriberFlowInfo);
Tunahan Sezena07fe962021-02-24 08:24:24 +00001096 UniTagInformation tagInfo = subscriberFlowInfo.getTagInfo();
1097 if (tagInfo.getIsDhcpRequired()) {
1098 Optional<MacAddress> macAddress =
1099 getMacAddress(subscriberFlowInfo.getDevId(), subscriberFlowInfo.getUniPort(), tagInfo);
1100 if (subscriberFlowInfo.getTagInfo().getEnableMacLearning()) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001101 ConnectPoint cp = new ConnectPoint(subscriberFlowInfo.getDevId(),
1102 subscriberFlowInfo.getUniPort().number());
Tunahan Sezena07fe962021-02-24 08:24:24 +00001103 if (macAddress.isPresent()) {
1104 log.debug("MAC Address {} obtained for {}", macAddress.get(), subscriberFlowInfo);
1105 } else {
1106 waitingMacSubscribers.put(cp, subscriberFlowInfo);
1107 log.debug("Adding sub to waiting mac map: {}", subscriberFlowInfo);
1108 }
1109
1110 CompletableFuture<ObjectiveError> dhcpFuture = new CompletableFuture<>();
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001111 oltFlowService.processDhcpFilteringObjectives(subscriberFlowInfo.getUniPort(),
yasin saplib4b8ee12021-06-13 18:25:20 +00001112 subscriberFlowInfo.getUpId(), subscriberFlowInfo.getUpOltId(),
1113 tagInfo, true, true, Optional.of(dhcpFuture));
Tunahan Sezena07fe962021-02-24 08:24:24 +00001114 dhcpFuture.thenAcceptAsync(dhcpStatus -> {
1115 if (dhcpStatus != null) {
1116 log.error("Dhcp Objective failed for {}: {}", subscriberFlowInfo, dhcpStatus);
1117 if (macAddress.isEmpty()) {
1118 waitingMacSubscribers.remove(cp, subscriberFlowInfo);
1119 }
1120 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_REGISTRATION_FAILED,
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001121 subscriberFlowInfo.getDevId(), subscriberFlowInfo.getUniPort().port(),
Tunahan Sezena07fe962021-02-24 08:24:24 +00001122 tagInfo.getPonSTag(), tagInfo.getPonCTag(), tagInfo.getTechnologyProfileId()));
1123 } else {
1124 log.debug("Dhcp Objective success for: {}", subscriberFlowInfo);
1125 if (macAddress.isPresent()) {
1126 continueProvisioningSubs(subscriberFlowInfo, macAddress);
1127 }
1128 }
1129 });
1130 } else {
1131 log.debug("Dynamic MAC Learning disabled, so will not learn for: {}", subscriberFlowInfo);
1132 // dhcp flows will handle after data plane flows
1133 continueProvisioningSubs(subscriberFlowInfo, macAddress);
1134 }
1135 } else {
1136 // dhcp not required for this service
1137 continueProvisioningSubs(subscriberFlowInfo, Optional.empty());
1138 }
1139 }
1140
1141 private void continueProvisioningSubs(SubscriberFlowInfo subscriberFlowInfo, Optional<MacAddress> macAddress) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001142 AccessDevicePort uniPort = subscriberFlowInfo.getUniPort();
1143 log.debug("Provisioning subscriber flows on {} based on {}", uniPort, subscriberFlowInfo);
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001144 UniTagInformation tagInfo = subscriberFlowInfo.getTagInfo();
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001145 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture<>();
1146 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture<>();
Gamze Abakaf59c0912019-04-19 08:24:28 +00001147
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001148 ForwardingObjective.Builder upFwd =
yasin saplib4b8ee12021-06-13 18:25:20 +00001149 oltFlowService.createUpBuilder(subscriberFlowInfo.getNniPort(), uniPort, subscriberFlowInfo.getUpId(),
1150 subscriberFlowInfo.getUpOltId(), subscriberFlowInfo.getTagInfo());
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001151 flowObjectiveService.forward(subscriberFlowInfo.getDevId(), upFwd.add(new ObjectiveContext() {
1152 @Override
1153 public void onSuccess(Objective objective) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001154 log.debug("Upstream HSIA flow {} installed successfully on {}", subscriberFlowInfo, uniPort);
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001155 upFuture.complete(null);
Gamze Abakaf59c0912019-04-19 08:24:28 +00001156 }
Gamze Abakaf59c0912019-04-19 08:24:28 +00001157
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001158 @Override
1159 public void onError(Objective objective, ObjectiveError error) {
1160 upFuture.complete(error);
Gamze Abakaf59c0912019-04-19 08:24:28 +00001161 }
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001162 }));
1163
1164 ForwardingObjective.Builder downFwd =
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001165 oltFlowService.createDownBuilder(subscriberFlowInfo.getNniPort(), uniPort,
yasin saplib4b8ee12021-06-13 18:25:20 +00001166 subscriberFlowInfo.getDownId(), subscriberFlowInfo.getDownOltId(),
1167 subscriberFlowInfo.getTagInfo(), macAddress);
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001168 flowObjectiveService.forward(subscriberFlowInfo.getDevId(), downFwd.add(new ObjectiveContext() {
1169 @Override
1170 public void onSuccess(Objective objective) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001171 log.debug("Downstream HSIA flow {} installed successfully on {}", subscriberFlowInfo, uniPort);
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001172 downFuture.complete(null);
1173 }
1174
1175 @Override
1176 public void onError(Objective objective, ObjectiveError error) {
1177 downFuture.complete(error);
1178 }
1179 }));
Gamze Abakaf59c0912019-04-19 08:24:28 +00001180
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001181 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001182 AccessDeviceEvent.Type type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_REGISTERED;
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001183 if (downStatus != null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001184 log.error("Flow with innervlan {} and outerVlan {} on {} failed downstream installation: {}",
1185 tagInfo.getPonCTag(), tagInfo.getPonSTag(), uniPort, downStatus);
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001186 type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_REGISTRATION_FAILED;
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001187 } else if (upStatus != null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001188 log.error("Flow with innervlan {} and outerVlan {} on {} failed upstream installation: {}",
1189 tagInfo.getPonCTag(), tagInfo.getPonSTag(), uniPort, upStatus);
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001190 type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_REGISTRATION_FAILED;
Gamze Abakaf59c0912019-04-19 08:24:28 +00001191 } else {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001192 log.debug("Upstream and downstream data plane flows are installed successfully on {}", uniPort);
yasin saplib4b8ee12021-06-13 18:25:20 +00001193 Optional<String> upstreamOltBw = tagInfo.getUpstreamOltBandwidthProfile() == null ?
1194 Optional.empty() : Optional.of(tagInfo.getUpstreamOltBandwidthProfile());
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001195 oltFlowService.processEapolFilteringObjectives(uniPort, tagInfo.getUpstreamBandwidthProfile(),
yasin saplib4b8ee12021-06-13 18:25:20 +00001196 upstreamOltBw, null,
1197 tagInfo.getPonCTag(), true);
Tunahan Sezena07fe962021-02-24 08:24:24 +00001198
1199 if (!tagInfo.getEnableMacLearning()) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001200 oltFlowService.processDhcpFilteringObjectives(uniPort, subscriberFlowInfo.getUpId(),
yasin saplib4b8ee12021-06-13 18:25:20 +00001201 subscriberFlowInfo.getUpOltId(), tagInfo, true, true, Optional.empty());
Tunahan Sezena07fe962021-02-24 08:24:24 +00001202 }
Gamze Abakaf59c0912019-04-19 08:24:28 +00001203
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001204 oltFlowService.processIgmpFilteringObjectives(uniPort, subscriberFlowInfo.getUpId(),
yasin saplib4b8ee12021-06-13 18:25:20 +00001205 subscriberFlowInfo.getUpOltId(), tagInfo, true, true);
Gustavo Silva5c492dd2021-02-12 10:21:11 -03001206
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001207 oltFlowService.processPPPoEDFilteringObjectives(uniPort, subscriberFlowInfo.getUpId(),
yasin saplib4b8ee12021-06-13 18:25:20 +00001208 subscriberFlowInfo.getUpOltId(), tagInfo, true, true);
1209
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001210 updateProgrammedSubscriber(uniPort, tagInfo, true);
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001211 }
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001212 post(new AccessDeviceEvent(type, subscriberFlowInfo.getDevId(), uniPort.port(),
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001213 tagInfo.getPonSTag(), tagInfo.getPonCTag(),
1214 tagInfo.getTechnologyProfileId()));
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001215 }, oltInstallers);
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001216 }
1217
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001218 /**
Tunahan Sezena07fe962021-02-24 08:24:24 +00001219 * Gets mac address from tag info if present, else checks the host service.
1220 *
1221 * @param deviceId device ID
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001222 * @param port uni port
Tunahan Sezena07fe962021-02-24 08:24:24 +00001223 * @param tagInformation tag info
1224 * @return MAC Address of subscriber
1225 */
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001226 private Optional<MacAddress> getMacAddress(DeviceId deviceId, AccessDevicePort port,
Tunahan Sezena07fe962021-02-24 08:24:24 +00001227 UniTagInformation tagInformation) {
1228 if (isMacAddressValid(tagInformation)) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001229 log.debug("Got MAC Address {} from the uniTagInformation for {} and cTag {}",
1230 tagInformation.getConfiguredMacAddress(), port, tagInformation.getPonCTag());
Tunahan Sezena07fe962021-02-24 08:24:24 +00001231 return Optional.of(MacAddress.valueOf(tagInformation.getConfiguredMacAddress()));
1232 } else if (tagInformation.getEnableMacLearning()) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001233 Optional<Host> optHost = hostService.getConnectedHosts(new ConnectPoint(deviceId, port.number()))
Tunahan Sezena07fe962021-02-24 08:24:24 +00001234 .stream().filter(host -> host.vlan().equals(tagInformation.getPonCTag())).findFirst();
1235 if (optHost.isPresent()) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001236 log.debug("Got MAC Address {} from the hostService for {} and cTag {}",
1237 optHost.get().mac(), port, tagInformation.getPonCTag());
Tunahan Sezena07fe962021-02-24 08:24:24 +00001238 return Optional.of(optHost.get().mac());
1239 }
1240 }
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001241 log.debug("Could not obtain MAC Address for {} and cTag {}", port, tagInformation.getPonCTag());
Tunahan Sezena07fe962021-02-24 08:24:24 +00001242 return Optional.empty();
1243 }
1244
1245 private boolean isMacAddressValid(UniTagInformation tagInformation) {
1246 return tagInformation.getConfiguredMacAddress() != null &&
1247 !tagInformation.getConfiguredMacAddress().trim().equals("") &&
1248 !MacAddress.NONE.equals(MacAddress.valueOf(tagInformation.getConfiguredMacAddress()));
1249 }
1250
1251 /**
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001252 * Checks the subscriber uni tag list and find the uni tag information.
1253 * using the pon c tag, pon s tag and the technology profile id
1254 * May return Optional<null>
1255 *
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001256 * @param port port of the subscriber
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001257 * @param innerVlan pon c tag
1258 * @param outerVlan pon s tag
1259 * @param tpId the technology profile id
1260 * @return the found uni tag information
1261 */
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001262 private Optional<UniTagInformation> getUniTagInformation(AccessDevicePort port, VlanId innerVlan,
1263 VlanId outerVlan, int tpId) {
1264 log.debug("Getting uni tag information for {}, innerVlan: {}, outerVlan: {}, tpId: {}",
1265 port, innerVlan, outerVlan, tpId);
1266 SubscriberAndDeviceInformation subInfo = getSubscriber(new ConnectPoint(port.deviceId(), port.number()));
Gamze Abakaf59c0912019-04-19 08:24:28 +00001267 if (subInfo == null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001268 log.warn("Subscriber information doesn't exist for {}", port);
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001269 return Optional.empty();
Gamze Abakaf59c0912019-04-19 08:24:28 +00001270 }
1271
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001272 List<UniTagInformation> uniTagList = subInfo.uniTagList();
1273 if (uniTagList == null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001274 log.warn("Uni tag list is not found for the subscriber {} on {}", subInfo.id(), port);
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001275 return Optional.empty();
1276 }
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001277
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001278 UniTagInformation service = null;
1279 for (UniTagInformation tagInfo : subInfo.uniTagList()) {
1280 if (innerVlan.equals(tagInfo.getPonCTag()) && outerVlan.equals(tagInfo.getPonSTag())
1281 && tpId == tagInfo.getTechnologyProfileId()) {
1282 service = tagInfo;
1283 break;
Andy Bavier160e8682019-05-07 18:32:22 -07001284 }
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001285 }
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001286
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001287 if (service == null) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -07001288 log.warn("SADIS doesn't include the service with ponCtag {} ponStag {} and tpId {} on {}",
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001289 innerVlan, outerVlan, tpId, port);
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001290 return Optional.empty();
Gamze Abaka33feef52019-02-27 08:16:47 +00001291 }
1292
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001293 return Optional.of(service);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001294 }
1295
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001296 /**
Jonathan Hart403372d2018-08-22 11:44:13 -07001297 * Creates trap flows for device, including DHCP and LLDP trap on NNI and
1298 * EAPOL trap on the UNIs, if device is present in Sadis config.
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001299 *
1300 * @param dev Device to look for
1301 */
Jonathan Hart403372d2018-08-22 11:44:13 -07001302 private void checkAndCreateDeviceFlows(Device dev) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001303 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +00001304 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001305 log.info("checkAndCreateDeviceFlows: deviceInfo {}", deviceInfo);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001306
1307 if (deviceInfo != null) {
Andrea Campanella438e1ad2021-03-26 11:41:16 +01001308 log.debug("Driver for device {} is {}", dev.id(),
1309 driverService.getDriver(dev.id()));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001310 for (Port p : deviceService.getPorts(dev.id())) {
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001311 if (PortNumber.LOCAL.equals(p.number()) || !p.isEnabled()) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001312 continue;
1313 }
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001314 if (isUniPort(dev, p)) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001315 AccessDevicePort port = new AccessDevicePort(p, AccessDevicePort.Type.UNI);
Andrea Campanellaa2491782020-03-13 18:09:31 +01001316 if (!programmedSubs.containsKey(new ConnectPoint(dev.id(), p.number()))) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001317 log.info("Creating Eapol on {}", port);
yasin saplib4b8ee12021-06-13 18:25:20 +00001318 oltFlowService.processEapolFilteringObjectives(port, defaultBpId, Optional.empty(),
1319 null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
Andrea Campanellaa2491782020-03-13 18:09:31 +01001320 } else {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001321 log.debug("Subscriber Eapol on {} is already provisioned, not installing default", port);
Andrea Campanellaa2491782020-03-13 18:09:31 +01001322 }
Jonathan Hart403372d2018-08-22 11:44:13 -07001323 } else {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001324 AccessDevicePort port = new AccessDevicePort(p, AccessDevicePort.Type.NNI);
1325 oltFlowService.processNniFilteringObjectives(port, true);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001326 }
1327 }
1328 }
1329 }
1330
Jonathan Hart403372d2018-08-22 11:44:13 -07001331
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001332 /**
1333 * Get the uplink for of the OLT device.
Gamze Abakaad329652018-12-20 10:12:21 +00001334 * <p>
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001335 * This assumes that the OLT has a single uplink port. When more uplink ports need to be supported
1336 * this logic needs to be changed
1337 *
1338 * @param dev Device to look for
1339 * @return The uplink Port of the OLT
1340 */
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001341 private AccessDevicePort getUplinkPort(Device dev) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001342 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +00001343 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Saurav Daseae48de2019-06-19 13:26:15 -07001344 log.trace("getUplinkPort: deviceInfo {}", deviceInfo);
Saurav Das82b8e6d2018-10-04 15:25:12 -07001345 if (deviceInfo == null) {
1346 log.warn("Device {} is not configured in SADIS .. cannot fetch device"
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001347 + " info", dev.id());
Saurav Das82b8e6d2018-10-04 15:25:12 -07001348 return null;
1349 }
1350 // Return the port that has been configured as the uplink port of this OLT in Sadis
kdarapuaa5da252020-04-10 15:58:05 +05301351 Optional<Port> optionalPort = deviceService.getPorts(dev.id()).stream()
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001352 .filter(port -> isNniPort(port) ||
1353 (port.number().toLong() == deviceInfo.uplinkPort()))
1354 .findFirst();
kdarapuaa5da252020-04-10 15:58:05 +05301355 if (optionalPort.isPresent()) {
1356 log.trace("getUplinkPort: Found port {}", optionalPort.get());
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001357 return new AccessDevicePort(optionalPort.get(), AccessDevicePort.Type.NNI);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001358 }
1359
Saurav Daseae48de2019-06-19 13:26:15 -07001360 log.warn("getUplinkPort: " + NO_UPLINK_PORT, dev.id());
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001361 return null;
1362 }
1363
1364 /**
1365 * Return the subscriber on a port.
1366 *
Matteo Scandolo962a6ad2018-12-11 15:39:42 -08001367 * @param cp ConnectPoint on which to find the subscriber
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001368 * @return subscriber if found else null
1369 */
Ilayda Ozdemir90a93622021-02-25 09:40:58 +00001370 protected SubscriberAndDeviceInformation getSubscriber(ConnectPoint cp) {
1371 if (subsService == null) {
1372 log.warn(SADIS_NOT_RUNNING);
1373 return null;
1374 }
Matteo Scandolo962a6ad2018-12-11 15:39:42 -08001375 Port port = deviceService.getPort(cp);
1376 checkNotNull(port, "Invalid connect point");
1377 String portName = port.annotations().value(AnnotationKeys.PORT_NAME);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001378 return subsService.get(portName);
1379 }
1380
Gamze Abakaad329652018-12-20 10:12:21 +00001381 /**
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001382 * Checks whether the given port of the device is a uni port or not.
1383 *
1384 * @param d the access device
1385 * @param p the port of the device
1386 * @return true if the given port is a uni port
Gamze Abakaad329652018-12-20 10:12:21 +00001387 */
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001388 private boolean isUniPort(Device d, Port p) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001389 AccessDevicePort ulPort = getUplinkPort(d);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001390 if (ulPort != null) {
1391 return (ulPort.number().toLong() != p.number().toLong());
1392 }
Thomas Lee Sd7735f92020-02-20 19:21:47 +05301393 //handles a special case where NNI port is misconfigured in SADIS and getUplinkPort(d) returns null
1394 //checks whether the port name starts with nni- which is the signature of an NNI Port
1395 if (p.annotations().value(AnnotationKeys.PORT_NAME) != null &&
1396 p.annotations().value(AnnotationKeys.PORT_NAME).startsWith(NNI)) {
1397 log.error("NNI port number {} is not matching with configured value", p.number().toLong());
1398 return false;
1399 }
1400 return true;
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001401 }
1402
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001403 /**
1404 * Gets the given device details from SADIS.
1405 * If the device is not found, returns null
1406 *
1407 * @param dev the access device
1408 * @return the olt information
1409 */
Jonathan Hart4c538002018-08-23 10:11:54 -07001410 private SubscriberAndDeviceInformation getOltInfo(Device dev) {
Ilayda Ozdemir90a93622021-02-25 09:40:58 +00001411 if (subsService == null) {
1412 log.warn(SADIS_NOT_RUNNING);
1413 return null;
1414 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001415 String devSerialNo = dev.serialNumber();
Gamze Abaka641fc072018-09-04 09:16:27 +00001416 return subsService.get(devSerialNo);
Jonathan Hart4c538002018-08-23 10:11:54 -07001417 }
1418
Andrea Campanella1edf8832021-05-06 12:51:33 +02001419 /**
1420 * Checks for mastership or falls back to leadership on deviceId.
1421 * If the device is available use mastership,
1422 * otherwise fallback on leadership.
1423 * Leadership on the device topic is needed because the master can be NONE
1424 * in case the device went away, we still need to handle events
1425 * consistently
1426 */
Andrea Campanellaaf39b4c2020-05-13 14:07:44 +02001427 private boolean isLocalLeader(DeviceId deviceId) {
Andrea Campanella1edf8832021-05-06 12:51:33 +02001428 if (deviceService.isAvailable(deviceId)) {
1429 return mastershipService.isLocalMaster(deviceId);
1430 } else {
Andrea Campanellaaf39b4c2020-05-13 14:07:44 +02001431 // Fallback with Leadership service - device id is used as topic
1432 NodeId leader = leadershipService.runForLeadership(
1433 deviceId.toString()).leaderNodeId();
1434 // Verify if this node is the leader
1435 return clusterService.getLocalNode().id().equals(leader);
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001436 }
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001437 }
1438
kdarapuaa5da252020-04-10 15:58:05 +05301439 private boolean isNniPort(Port port) {
1440 if (port.annotations().keys().contains(AnnotationKeys.PORT_NAME)) {
1441 return port.annotations().value(AnnotationKeys.PORT_NAME).contains(NNI);
1442 }
1443 return false;
1444 }
1445
Tunahan Sezena07fe962021-02-24 08:24:24 +00001446 private class InternalHostListener implements HostListener {
1447 @Override
1448 public void event(HostEvent event) {
1449 hostEventExecutor.execute(() -> {
1450 Host host = event.subject();
1451 switch (event.type()) {
1452 case HOST_ADDED:
1453 ConnectPoint cp = new ConnectPoint(host.location().deviceId(), host.location().port());
1454 Optional<SubscriberFlowInfo> optSubFlowInfo =
1455 getAndRemoveWaitingMacSubFlowInfoForCTag(cp, host.vlan());
1456 if (optSubFlowInfo.isPresent()) {
1457 log.debug("Continuing provisioning for waiting mac service. event: {}", event);
1458 continueProvisioningSubs(optSubFlowInfo.get(), Optional.of(host.mac()));
1459 } else {
1460 log.debug("There is no waiting mac sub. event: {}", event);
1461 }
1462 break;
1463 case HOST_UPDATED:
1464 if (event.prevSubject() != null && !event.prevSubject().mac().equals(event.subject().mac())) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001465 log.debug("Subscriber's MAC address changed from {} to {}. " +
1466 "devId/portNumber: {}/{} vlan: {}", event.prevSubject().mac(),
1467 event.subject().mac(), host.location().deviceId(), host.location().port(),
1468 host.vlan());
Tunahan Sezena07fe962021-02-24 08:24:24 +00001469 // TODO handle subscriber MAC Address changed
1470 } else {
1471 log.debug("Unhandled HOST_UPDATED event: {}", event);
1472 }
1473 break;
1474 default:
1475 log.debug("Unhandled host event received. event: {}", event);
1476 }
1477 });
1478 }
1479
1480 @Override
1481 public boolean isRelevant(HostEvent event) {
1482 return isLocalLeader(event.subject().location().deviceId());
1483 }
1484 }
1485
alshabibf0e7e702015-05-30 18:22:36 -07001486 private class InternalDeviceListener implements DeviceListener {
Saurav Dasa9d5f442019-03-06 19:32:48 -08001487 private Set<DeviceId> programmedDevices = Sets.newConcurrentHashSet();
1488
alshabibf0e7e702015-05-30 18:22:36 -07001489 @Override
1490 public void event(DeviceEvent event) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001491 eventExecutor.execute(() -> {
1492 DeviceId devId = event.subject().id();
1493 Device dev = event.subject();
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001494 Port p = event.port();
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001495 DeviceEvent.Type eventType = event.type();
Jonathan Hart4c538002018-08-23 10:11:54 -07001496
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001497 if (DeviceEvent.Type.PORT_STATS_UPDATED.equals(eventType) ||
1498 DeviceEvent.Type.DEVICE_SUSPENDED.equals(eventType) ||
1499 DeviceEvent.Type.DEVICE_UPDATED.equals(eventType)) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001500 return;
1501 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001502
Andrea Campanellaaf39b4c2020-05-13 14:07:44 +02001503 boolean isLocalLeader = isLocalLeader(devId);
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001504 // Only handle the event if the device belongs to us
Andrea Campanellaaf39b4c2020-05-13 14:07:44 +02001505 if (!isLocalLeader && event.type().equals(DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED)
1506 && !deviceService.isAvailable(devId) && deviceService.getPorts(devId).isEmpty()) {
1507 log.info("Cleaning local state for non master instance upon " +
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001508 "device disconnection {}", devId);
Andrea Campanellaaf39b4c2020-05-13 14:07:44 +02001509 // Since no mastership of the device is present upon disconnection
1510 // the method in the FlowRuleManager only empties the local copy
1511 // of the DeviceFlowTable thus this method needs to get called
1512 // on every instance, see how it's done in the InternalDeviceListener
1513 // in FlowRuleManager: no mastership check for purgeOnDisconnection
Andrea Campanella3f34c992020-07-15 10:54:10 +02001514 handleDeviceDisconnection(dev, false, false);
Andrea Campanellaaf39b4c2020-05-13 14:07:44 +02001515 return;
1516 } else if (!isLocalLeader) {
Andrea Campanella506df202020-05-21 10:26:12 +02001517 log.debug("Not handling event because instance is not leader for {}", devId);
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001518 return;
1519 }
1520
Matteo Scandolo19b56f62020-10-29 13:29:21 -07001521 log.debug("OLT got {} event for {}/{}", eventType, event.subject(), event.port());
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001522
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001523 if (getOltInfo(dev) == null) {
Saurav Dasa9d5f442019-03-06 19:32:48 -08001524 // it's possible that we got an event for a previously
1525 // programmed OLT that is no longer available in SADIS
1526 // we let such events go through
1527 if (!programmedDevices.contains(devId)) {
1528 log.warn("No device info found for {}, this is either "
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001529 + "not an OLT or not known to sadis", dev);
Saurav Dasa9d5f442019-03-06 19:32:48 -08001530 return;
1531 }
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001532 }
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001533 AccessDevicePort port = null;
1534 if (p != null) {
1535 if (isUniPort(dev, p)) {
1536 port = new AccessDevicePort(p, AccessDevicePort.Type.UNI);
1537 } else {
1538 port = new AccessDevicePort(p, AccessDevicePort.Type.NNI);
1539 }
1540 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001541
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001542 switch (event.type()) {
1543 //TODO: Port handling and bookkeeping should be improved once
1544 // olt firmware handles correct behaviour.
1545 case PORT_ADDED:
Andrea Campanella3f34c992020-07-15 10:54:10 +02001546 if (!deviceService.isAvailable(devId)) {
1547 log.warn("Received {} for disconnected device {}, ignoring", event, devId);
1548 return;
1549 }
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001550 if (port.type().equals(AccessDevicePort.Type.UNI)) {
1551 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, port.port()));
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001552
1553 if (port.isEnabled() && !port.number().equals(PortNumber.LOCAL)) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001554 log.info("eapol will be sent for port added {}", port);
yasin saplib4b8ee12021-06-13 18:25:20 +00001555 oltFlowService.processEapolFilteringObjectives(port, defaultBpId, Optional.empty(),
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001556 null,
Andrea Campanella3f34c992020-07-15 10:54:10 +02001557 VlanId.vlanId(EAPOL_DEFAULT_VLAN),
1558 true);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001559 }
1560 } else {
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001561 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
1562 if (deviceInfo != null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001563 oltFlowService.processNniFilteringObjectives(port, true);
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001564 }
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001565 }
1566 break;
1567 case PORT_REMOVED:
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001568 if (port.type().equals(AccessDevicePort.Type.UNI)) {
Andrea Campanellacf0e3052020-08-27 11:05:39 +02001569 // if no subscriber is provisioned we need to remove the default EAPOL
1570 // if a subscriber was provisioned the default EAPOL will not be there and we can skip.
1571 // The EAPOL with subscriber tag will be removed by removeSubscriber call.
1572 Collection<? extends UniTagInformation> uniTagInformationSet =
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001573 programmedSubs.get(new ConnectPoint(port.deviceId(), port.number())).value();
Andrea Campanellacf0e3052020-08-27 11:05:39 +02001574 if (uniTagInformationSet == null || uniTagInformationSet.isEmpty()) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001575 log.info("No subscriber provisioned on port {} in PORT_REMOVED event, " +
1576 "removing default EAPOL flow", port);
yasin saplib4b8ee12021-06-13 18:25:20 +00001577 oltFlowService.processEapolFilteringObjectives(port, defaultBpId, Optional.empty(),
1578 null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), false);
Andrea Campanellacf0e3052020-08-27 11:05:39 +02001579 } else {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001580 removeSubscriber(port);
Andrea Campanellacf0e3052020-08-27 11:05:39 +02001581 }
Andy Bavier160e8682019-05-07 18:32:22 -07001582
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001583 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, port.port()));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001584 }
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001585 break;
1586 case PORT_UPDATED:
Andrea Campanella3f34c992020-07-15 10:54:10 +02001587 if (!deviceService.isAvailable(devId)) {
1588 log.warn("Received {} for disconnected device {}, ignoring", event, devId);
1589 return;
1590 }
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001591 if (port.type().equals(AccessDevicePort.Type.NNI)) {
Saurav Das9da7d522020-03-23 19:14:35 -07001592 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
1593 if (deviceInfo != null && port.isEnabled()) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001594 log.debug("NNI {} enabled", port);
1595 oltFlowService.processNniFilteringObjectives(port, true);
Saurav Das9da7d522020-03-23 19:14:35 -07001596 }
1597 return;
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001598 }
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001599 ConnectPoint cp = new ConnectPoint(devId, port.number());
1600 Collection<? extends UniTagInformation> uniTagInformationSet = programmedSubs.get(cp).value();
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001601 if (uniTagInformationSet == null || uniTagInformationSet.isEmpty()) {
Saurav Dasb776aef2020-03-09 14:29:46 -07001602 if (!port.number().equals(PortNumber.LOCAL)) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001603 log.info("eapol will be {} updated for {} with default vlan {}",
1604 (port.isEnabled()) ? "added" : "removed", port, EAPOL_DEFAULT_VLAN);
yasin saplib4b8ee12021-06-13 18:25:20 +00001605 oltFlowService.processEapolFilteringObjectives(port, defaultBpId, Optional.empty(),
1606 null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), port.isEnabled());
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001607 }
1608 } else {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001609 log.info("eapol will be {} updated for {}", (port.isEnabled()) ? "added" : "removed",
1610 port);
1611 for (UniTagInformation uniTag : uniTagInformationSet) {
1612 oltFlowService.processEapolFilteringObjectives(port,
yasin saplib4b8ee12021-06-13 18:25:20 +00001613 uniTag.getUpstreamBandwidthProfile(),
1614 Optional.of(uniTag.getUpstreamOltBandwidthProfile()),
1615 null, uniTag.getPonCTag(), port.isEnabled());
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001616 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001617 }
Gamze Abaka838d8142019-02-21 07:06:55 +00001618 if (port.isEnabled()) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001619 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, port.port()));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001620 } else {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001621 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, port.port()));
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001622 }
alshabibbb83aa22016-02-10 15:08:23 -08001623 break;
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001624 case DEVICE_ADDED:
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001625 handleDeviceConnection(dev, true);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001626 break;
1627 case DEVICE_REMOVED:
Andrea Campanella3f34c992020-07-15 10:54:10 +02001628 handleDeviceDisconnection(dev, true, true);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001629 break;
1630 case DEVICE_AVAILABILITY_CHANGED:
1631 if (deviceService.isAvailable(devId)) {
Saurav Dasbd3b6712020-03-31 23:28:35 -07001632 log.info("Handling available device: {}", dev.id());
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001633 handleDeviceConnection(dev, false);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001634 } else {
Hardik Windlassa58fbee2020-03-12 18:33:55 +05301635 if (deviceService.getPorts(devId).isEmpty()) {
Saurav Dasbd3b6712020-03-31 23:28:35 -07001636 log.info("Handling controlled device disconnection .. "
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001637 + "flushing all state for dev:{}", devId);
Andrea Campanella3f34c992020-07-15 10:54:10 +02001638 handleDeviceDisconnection(dev, true, false);
Saurav Dasbd3b6712020-03-31 23:28:35 -07001639 } else {
1640 log.info("Disconnected device has available ports .. "
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001641 + "assuming temporary disconnection, "
1642 + "retaining state for device {}", devId);
Hardik Windlassa58fbee2020-03-12 18:33:55 +05301643 }
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001644 }
1645 break;
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001646 default:
Andrea Campanella3f34c992020-07-15 10:54:10 +02001647 log.debug("Not handling event {}", event);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001648 return;
1649 }
1650 });
alshabibf0e7e702015-05-30 18:22:36 -07001651 }
Gamze Abaka838d8142019-02-21 07:06:55 +00001652
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001653 private void sendUniEvent(Device device, AccessDeviceEvent.Type eventType) {
1654 deviceService.getPorts(device.id()).stream()
1655 .filter(p -> !PortNumber.LOCAL.equals(p.number()))
1656 .filter(p -> isUniPort(device, p))
1657 .forEach(p -> post(new AccessDeviceEvent(eventType, device.id(), p)));
1658 }
1659
Andrea Campanella3f34c992020-07-15 10:54:10 +02001660 private void handleDeviceDisconnection(Device device, boolean sendDisconnectedEvent, boolean sendUniEvent) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001661 programmedDevices.remove(device.id());
1662 removeAllSubscribers(device.id());
Tunahan Sezena07fe962021-02-24 08:24:24 +00001663 removeWaitingMacSubs(device.id());
Andrea Campanella600d2e22020-06-22 11:00:31 +02001664 //Handle case where OLT disconnects during subscriber provisioning
Andrea Campanella7a1d7e72020-11-05 10:40:10 +01001665 pendingSubscribersForDevice.remove(device.id());
Andrea Campanella600d2e22020-06-22 11:00:31 +02001666 oltFlowService.clearDeviceState(device.id());
1667
1668 //Complete meter and flow purge
Hardik Windlassa58fbee2020-03-12 18:33:55 +05301669 flowRuleService.purgeFlowRules(device.id());
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001670 oltMeterService.clearMeters(device.id());
Andrea Campanella3f34c992020-07-15 10:54:10 +02001671 if (sendDisconnectedEvent) {
1672 post(new AccessDeviceEvent(
1673 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, device.id(),
1674 null, null, null));
1675 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001676 if (sendUniEvent) {
1677 sendUniEvent(device, AccessDeviceEvent.Type.UNI_REMOVED);
Gamze Abaka838d8142019-02-21 07:06:55 +00001678 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001679 }
1680
1681 private void handleDeviceConnection(Device dev, boolean sendUniEvent) {
1682 post(new AccessDeviceEvent(
1683 AccessDeviceEvent.Type.DEVICE_CONNECTED, dev.id(),
1684 null, null, null));
1685 programmedDevices.add(dev.id());
1686 checkAndCreateDeviceFlows(dev);
1687 if (sendUniEvent) {
1688 sendUniEvent(dev, AccessDeviceEvent.Type.UNI_ADDED);
1689 }
Gamze Abaka838d8142019-02-21 07:06:55 +00001690 }
Gamze Abakada282b42019-03-11 13:16:48 +00001691
1692 private void removeAllSubscribers(DeviceId deviceId) {
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001693 List<Map.Entry<ConnectPoint, UniTagInformation>> subs = programmedSubs.stream()
1694 .filter(e -> e.getKey().deviceId().equals(deviceId))
1695 .collect(toList());
Gamze Abakada282b42019-03-11 13:16:48 +00001696
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001697 subs.forEach(e -> programmedSubs.remove(e.getKey(), e.getValue()));
Gamze Abakada282b42019-03-11 13:16:48 +00001698 }
Gamze Abaka641fc072018-09-04 09:16:27 +00001699
Tunahan Sezena07fe962021-02-24 08:24:24 +00001700 private void removeWaitingMacSubs(DeviceId deviceId) {
1701 List<ConnectPoint> waitingMacKeys = waitingMacSubscribers.stream()
1702 .filter(cp -> cp.getKey().deviceId().equals(deviceId))
1703 .map(Map.Entry::getKey)
1704 .collect(toList());
1705 waitingMacKeys.forEach(cp -> waitingMacSubscribers.removeAll(cp));
1706 }
1707
Gamze Abaka641fc072018-09-04 09:16:27 +00001708 }
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001709
1710 private class InternalClusterListener implements ClusterEventListener {
1711
1712 @Override
1713 public void event(ClusterEvent event) {
1714 if (event.type() == ClusterEvent.Type.INSTANCE_READY) {
1715 hasher.addServer(event.subject().id());
1716 }
1717 if (event.type() == ClusterEvent.Type.INSTANCE_DEACTIVATED) {
1718 hasher.removeServer(event.subject().id());
1719 }
1720 }
1721 }
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001722
Hardik Windlass395ff372019-06-13 05:16:00 +00001723}