blob: f11ac217717920e78efce42e1ec9b17988907043 [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;
Jonathan Hart4f178fa2020-02-03 10:46:01 -080055import org.onosproject.store.serializers.KryoNamespaces;
56import org.onosproject.store.service.ConsistentMultimap;
57import org.onosproject.store.service.Serializer;
58import org.onosproject.store.service.StorageService;
alshabib36a4d732016-06-01 16:03:59 -070059import org.opencord.olt.AccessDeviceEvent;
60import org.opencord.olt.AccessDeviceListener;
Tunahan Sezenf0843b92021-04-30 07:13:16 +000061import org.opencord.olt.AccessDevicePort;
alshabib36a4d732016-06-01 16:03:59 -070062import org.opencord.olt.AccessDeviceService;
Amit Ghosh31939522018-08-16 13:28:21 +010063import org.opencord.olt.AccessSubscriberId;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000064import org.opencord.olt.internalapi.AccessDeviceFlowService;
65import org.opencord.olt.internalapi.AccessDeviceMeterService;
Gamze Abaka641fc072018-09-04 09:16:27 +000066import org.opencord.sadis.BandwidthProfileInformation;
67import org.opencord.sadis.BaseInformationService;
68import org.opencord.sadis.SadisService;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010069import org.opencord.sadis.SubscriberAndDeviceInformation;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000070import org.opencord.sadis.UniTagInformation;
alshabibe0559672016-02-21 14:49:51 -080071import org.osgi.service.component.ComponentContext;
Carmelo Casconeca931162019-07-15 18:22:24 -070072import org.osgi.service.component.annotations.Activate;
73import org.osgi.service.component.annotations.Component;
74import org.osgi.service.component.annotations.Deactivate;
75import org.osgi.service.component.annotations.Modified;
76import org.osgi.service.component.annotations.Reference;
77import org.osgi.service.component.annotations.ReferenceCardinality;
Ilayda Ozdemir90a93622021-02-25 09:40:58 +000078import org.osgi.service.component.annotations.ReferencePolicy;
alshabibf0e7e702015-05-30 18:22:36 -070079import org.slf4j.Logger;
80
Andrea Campanella7a1d7e72020-11-05 10:40:10 +010081import java.util.ArrayList;
82import java.util.Collection;
83import java.util.Dictionary;
84import java.util.List;
85import java.util.Map;
86import java.util.Optional;
87import java.util.Properties;
88import java.util.Set;
89import java.util.concurrent.BlockingQueue;
90import java.util.concurrent.CompletableFuture;
Andrea Campanella7a1d7e72020-11-05 10:40:10 +010091import java.util.concurrent.ExecutorService;
92import java.util.concurrent.Executors;
93import java.util.concurrent.LinkedBlockingQueue;
94import java.util.concurrent.ScheduledExecutorService;
95import java.util.concurrent.TimeUnit;
96import java.util.concurrent.atomic.AtomicBoolean;
97
98import static com.google.common.base.Preconditions.checkNotNull;
99import static com.google.common.base.Strings.isNullOrEmpty;
100import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
101import static java.util.stream.Collectors.*;
102import static org.onlab.util.Tools.get;
103import static org.onlab.util.Tools.groupedThreads;
104import static org.opencord.olt.impl.OsgiPropertyConstants.*;
105import static org.slf4j.LoggerFactory.getLogger;
alshabibf0e7e702015-05-30 18:22:36 -0700106
107/**
Jonathan Harte533a422015-10-20 17:31:24 -0700108 * Provisions rules on access devices.
alshabibf0e7e702015-05-30 18:22:36 -0700109 */
Carmelo Casconeca931162019-07-15 18:22:24 -0700110@Component(immediate = true,
111 property = {
Carmelo Casconeca931162019-07-15 18:22:24 -0700112 DEFAULT_BP_ID + ":String=" + DEFAULT_BP_ID_DEFAULT,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000113 DEFAULT_MCAST_SERVICE_NAME + ":String=" + DEFAULT_MCAST_SERVICE_NAME_DEFAULT,
Saurav Das2d3777a2020-08-07 18:48:51 -0700114 EAPOL_DELETE_RETRY_MAX_ATTEMPS + ":Integer=" +
115 EAPOL_DELETE_RETRY_MAX_ATTEMPS_DEFAULT,
Matteo Scandoloa4aaa972020-10-23 15:24:38 -0700116 PROVISION_DELAY + ":Integer=" + PROVISION_DELAY_DEFAULT,
Carmelo Casconeca931162019-07-15 18:22:24 -0700117 })
alshabib8e4fd2f2016-01-12 15:55:53 -0800118public class Olt
119 extends AbstractListenerManager<AccessDeviceEvent, AccessDeviceListener>
120 implements AccessDeviceService {
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000121 private static final String SADIS_NOT_RUNNING = "Sadis is not running.";
Charles Chan54f110f2017-01-20 11:22:42 -0800122 private static final String APP_NAME = "org.opencord.olt";
alshabibe0559672016-02-21 14:49:51 -0800123
Gamze Abakada282b42019-03-11 13:16:48 +0000124 private static final short EAPOL_DEFAULT_VLAN = 4091;
Gamze Abaka838d8142019-02-21 07:06:55 +0000125 private static final String NO_UPLINK_PORT = "No uplink port found for OLT device {}";
alshabibe0559672016-02-21 14:49:51 -0800126
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800127 public static final int HASH_WEIGHT = 10;
128
alshabibf0e7e702015-05-30 18:22:36 -0700129 private final Logger log = getLogger(getClass());
130
Thomas Lee Sd7735f92020-02-20 19:21:47 +0530131 private static final String NNI = "nni-";
132
Carmelo Casconeca931162019-07-15 18:22:24 -0700133 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabibf0e7e702015-05-30 18:22:36 -0700134 protected FlowObjectiveService flowObjectiveService;
135
Carmelo Casconeca931162019-07-15 18:22:24 -0700136 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabibf0e7e702015-05-30 18:22:36 -0700137 protected DeviceService deviceService;
138
Andrea Campanella438e1ad2021-03-26 11:41:16 +0100139
Carmelo Casconeca931162019-07-15 18:22:24 -0700140 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabibf0e7e702015-05-30 18:22:36 -0700141 protected CoreService coreService;
142
Andrea Campanella438e1ad2021-03-26 11:41:16 +0100143 //Dependency on driver service is to ensure correct startup order
144 @Reference(cardinality = ReferenceCardinality.MANDATORY)
145 protected DriverService driverService;
146
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000147 @Reference(cardinality = ReferenceCardinality.OPTIONAL,
148 bind = "bindSadisService",
149 unbind = "unbindSadisService",
150 policy = ReferencePolicy.DYNAMIC)
151 protected volatile SadisService sadisService;
Gamze Abaka641fc072018-09-04 09:16:27 +0000152
Carmelo Casconeca931162019-07-15 18:22:24 -0700153 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000154 protected AccessDeviceFlowService oltFlowService;
alshabibe0559672016-02-21 14:49:51 -0800155
Carmelo Casconeca931162019-07-15 18:22:24 -0700156 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000157 protected AccessDeviceMeterService oltMeterService;
Gamze Abakaad329652018-12-20 10:12:21 +0000158
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800159 @Reference(cardinality = ReferenceCardinality.MANDATORY)
160 protected StorageService storageService;
161
162 @Reference(cardinality = ReferenceCardinality.MANDATORY)
163 protected ClusterService clusterService;
164
Hardik Windlassa58fbee2020-03-12 18:33:55 +0530165 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andrea Campanellaaf39b4c2020-05-13 14:07:44 +0200166 protected MastershipService mastershipService;
167
168 @Reference(cardinality = ReferenceCardinality.MANDATORY)
169 protected LeadershipService leadershipService;
170
171 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hardik Windlassa58fbee2020-03-12 18:33:55 +0530172 protected FlowRuleService flowRuleService;
173
Gamze Abaka1f62dd92020-05-07 08:58:13 +0000174 @Reference(cardinality = ReferenceCardinality.MANDATORY)
175 protected ComponentConfigService componentConfigService;
176
Tunahan Sezena07fe962021-02-24 08:24:24 +0000177 @Reference(cardinality = ReferenceCardinality.MANDATORY)
178 protected HostService hostService;
179
Carmelo Casconeca931162019-07-15 18:22:24 -0700180 /**
Carmelo Cascone95ff5122019-11-14 14:19:13 -0800181 * Default bandwidth profile id that is used for authentication trap flows.
Carmelo Casconeca931162019-07-15 18:22:24 -0700182 **/
183 protected String defaultBpId = DEFAULT_BP_ID_DEFAULT;
Gamze Abakaad329652018-12-20 10:12:21 +0000184
Carmelo Casconeca931162019-07-15 18:22:24 -0700185 /**
Gamze Abaka51a34e82020-05-08 13:03:14 +0000186 * Default multicast service name.
Carmelo Casconeca931162019-07-15 18:22:24 -0700187 **/
Gamze Abaka51a34e82020-05-08 13:03:14 +0000188 protected String multicastServiceName = DEFAULT_MCAST_SERVICE_NAME_DEFAULT;
Gamze Abaka33feef52019-02-27 08:16:47 +0000189
Saurav Das2d3777a2020-08-07 18:48:51 -0700190 /**
191 * Default amounts of eapol retry.
192 **/
193 protected int eapolDeleteRetryMaxAttempts = EAPOL_DELETE_RETRY_MAX_ATTEMPS_DEFAULT;
194
Matteo Scandoloa4aaa972020-10-23 15:24:38 -0700195 /**
196 * Delay between EAPOL removal and data plane flows provisioning.
197 */
198 protected int provisionDelay = PROVISION_DELAY_DEFAULT;
199
alshabibf0e7e702015-05-30 18:22:36 -0700200 private final DeviceListener deviceListener = new InternalDeviceListener();
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800201 private final ClusterEventListener clusterListener = new InternalClusterListener();
Tunahan Sezena07fe962021-02-24 08:24:24 +0000202 private final HostListener hostListener = new InternalHostListener();
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800203
204 private ConsistentHasher hasher;
alshabibf0e7e702015-05-30 18:22:36 -0700205
Gamze Abaka641fc072018-09-04 09:16:27 +0000206 protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
207 private BaseInformationService<BandwidthProfileInformation> bpService;
alshabibf0e7e702015-05-30 18:22:36 -0700208
Gamze Abaka641fc072018-09-04 09:16:27 +0000209 private ExecutorService oltInstallers = Executors.newFixedThreadPool(4,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000210 groupedThreads("onos/olt-service",
211 "olt-installer-%d"));
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100212
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700213 protected ExecutorService eventExecutor;
Tunahan Sezena07fe962021-02-24 08:24:24 +0000214 protected ExecutorService hostEventExecutor;
Saurav Das2d3777a2020-08-07 18:48:51 -0700215 protected ExecutorService retryExecutor;
Matteo Scandoloa4aaa972020-10-23 15:24:38 -0700216 protected ScheduledExecutorService provisionExecutor;
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700217
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800218 private ConsistentMultimap<ConnectPoint, UniTagInformation> programmedSubs;
Saurav Das2d3777a2020-08-07 18:48:51 -0700219 private ConsistentMultimap<ConnectPoint, UniTagInformation> failedSubs;
Saurav Dasa9d5f442019-03-06 19:32:48 -0800220
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000221 protected Map<DeviceId, BlockingQueue<SubscriberFlowInfo>> pendingSubscribersForDevice;
Tunahan Sezena07fe962021-02-24 08:24:24 +0000222 private ConsistentMultimap<ConnectPoint, SubscriberFlowInfo> waitingMacSubscribers;
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700223
alshabibf0e7e702015-05-30 18:22:36 -0700224 @Activate
alshabibe0559672016-02-21 14:49:51 -0800225 public void activate(ComponentContext context) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000226 eventExecutor = newSingleThreadScheduledExecutor(groupedThreads("onos/olt",
227 "events-%d", log));
Tunahan Sezena07fe962021-02-24 08:24:24 +0000228 hostEventExecutor = Executors.newFixedThreadPool(8, groupedThreads("onos/olt", "mac-events-%d", log));
Saurav Das2d3777a2020-08-07 18:48:51 -0700229 retryExecutor = Executors.newCachedThreadPool();
Matteo Scandoloa4aaa972020-10-23 15:24:38 -0700230 provisionExecutor = Executors.newSingleThreadScheduledExecutor(groupedThreads("onos/olt",
231 "provision-%d", log));
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700232
alshabibe0559672016-02-21 14:49:51 -0800233 modified(context);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000234 ApplicationId appId = coreService.registerApplication(APP_NAME);
Gamze Abaka1f62dd92020-05-07 08:58:13 +0000235 componentConfigService.registerProperties(getClass());
Saurav Das62ad75e2019-03-05 12:22:22 -0800236
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800237 KryoNamespace serializer = KryoNamespace.newBuilder()
238 .register(KryoNamespaces.API)
239 .register(UniTagInformation.class)
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000240 .register(SubscriberFlowInfo.class)
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000241 .register(AccessDevicePort.class)
242 .register(AccessDevicePort.Type.class)
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000243 .register(LinkedBlockingQueue.class)
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800244 .build();
245
246 programmedSubs = storageService.<ConnectPoint, UniTagInformation>consistentMultimapBuilder()
247 .withName("volt-programmed-subs")
248 .withSerializer(Serializer.using(serializer))
249 .withApplicationId(appId)
250 .build();
alshabibc4dfe852015-06-05 13:35:13 -0700251
Saurav Das2d3777a2020-08-07 18:48:51 -0700252 failedSubs = storageService.<ConnectPoint, UniTagInformation>consistentMultimapBuilder()
253 .withName("volt-failed-subs")
254 .withSerializer(Serializer.using(serializer))
255 .withApplicationId(appId)
256 .build();
257
Tunahan Sezena07fe962021-02-24 08:24:24 +0000258 KryoNamespace macSerializer = KryoNamespace.newBuilder()
259 .register(KryoNamespaces.API)
260 .register(SubscriberFlowInfo.class)
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000261 .register(AccessDevicePort.class)
262 .register(AccessDevicePort.Type.class)
Tunahan Sezena07fe962021-02-24 08:24:24 +0000263 .register(UniTagInformation.class)
264 .build();
265
266 waitingMacSubscribers = storageService.<ConnectPoint, SubscriberFlowInfo>consistentMultimapBuilder()
267 .withName("volt-waiting-mac-subs")
268 .withSerializer(Serializer.using(macSerializer))
269 .withApplicationId(appId)
270 .build();
271
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000272 pendingSubscribersForDevice = storageService.<DeviceId, BlockingQueue<SubscriberFlowInfo>>consistentMapBuilder()
273 .withName("volt-pending-subs")
274 .withSerializer(Serializer.using(serializer))
275 .withApplicationId(appId)
276 .build().asJavaMap();
alshabib8e4fd2f2016-01-12 15:55:53 -0800277 eventDispatcher.addSink(AccessDeviceEvent.class, listenerRegistry);
278
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000279 if (sadisService != null) {
280 subsService = sadisService.getSubscriberInfoService();
281 bpService = sadisService.getBandwidthProfileService();
282 } else {
283 log.warn(SADIS_NOT_RUNNING);
284 }
Gamze Abaka641fc072018-09-04 09:16:27 +0000285
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800286 List<NodeId> readyNodes = clusterService.getNodes().stream()
287 .filter(c -> clusterService.getState(c.id()) == ControllerNode.State.READY)
288 .map(ControllerNode::id)
289 .collect(toList());
290 hasher = new ConsistentHasher(readyNodes, HASH_WEIGHT);
291 clusterService.addListener(clusterListener);
292
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100293 // look for all provisioned devices in Sadis and create EAPOL flows for the
294 // UNI ports
295 Iterable<Device> devices = deviceService.getDevices();
296 for (Device d : devices) {
Andrea Campanellaaf39b4c2020-05-13 14:07:44 +0200297 if (isLocalLeader(d.id())) {
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800298 checkAndCreateDeviceFlows(d);
299 }
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100300 }
alshabib4ceaed32016-03-03 18:00:58 -0800301
alshabibba357492016-01-27 13:49:46 -0800302 deviceService.addListener(deviceListener);
Tunahan Sezena07fe962021-02-24 08:24:24 +0000303 hostService.addListener(hostListener);
alshabibf0e7e702015-05-30 18:22:36 -0700304 log.info("Started with Application ID {}", appId.id());
305 }
306
307 @Deactivate
308 public void deactivate() {
Gamze Abaka1f62dd92020-05-07 08:58:13 +0000309 componentConfigService.unregisterProperties(getClass(), false);
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800310 clusterService.removeListener(clusterListener);
alshabib62e9ce72016-02-11 17:31:36 -0800311 deviceService.removeListener(deviceListener);
Tunahan Sezena07fe962021-02-24 08:24:24 +0000312 hostService.removeListener(hostListener);
Jonathan Hart5f1c8142018-07-24 17:31:59 -0700313 eventDispatcher.removeSink(AccessDeviceEvent.class);
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700314 eventExecutor.shutdown();
Tunahan Sezena07fe962021-02-24 08:24:24 +0000315 hostEventExecutor.shutdown();
Saurav Das2d3777a2020-08-07 18:48:51 -0700316 retryExecutor.shutdown();
Matteo Scandoloa4aaa972020-10-23 15:24:38 -0700317 provisionExecutor.shutdown();
alshabibf0e7e702015-05-30 18:22:36 -0700318 log.info("Stopped");
319 }
320
alshabibe0559672016-02-21 14:49:51 -0800321 @Modified
322 public void modified(ComponentContext context) {
323 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
324
325 try {
Andrea Campanella971d5b92020-05-07 11:20:43 +0200326 String bpId = get(properties, DEFAULT_BP_ID);
327 defaultBpId = isNullOrEmpty(bpId) ? defaultBpId : bpId;
Gamze Abakaad329652018-12-20 10:12:21 +0000328
Andrea Campanella971d5b92020-05-07 11:20:43 +0200329 String mcastSN = get(properties, DEFAULT_MCAST_SERVICE_NAME);
330 multicastServiceName = isNullOrEmpty(mcastSN) ? multicastServiceName : mcastSN;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000331
Saurav Das2d3777a2020-08-07 18:48:51 -0700332 String eapolDeleteRetryNew = get(properties, EAPOL_DELETE_RETRY_MAX_ATTEMPS);
333 eapolDeleteRetryMaxAttempts = isNullOrEmpty(eapolDeleteRetryNew) ? EAPOL_DELETE_RETRY_MAX_ATTEMPS_DEFAULT :
334 Integer.parseInt(eapolDeleteRetryNew.trim());
335
336 log.debug("OLT properties: DefaultBpId: {}, MulticastServiceName: {}, EapolDeleteRetryMaxAttempts: {}",
337 defaultBpId, multicastServiceName, eapolDeleteRetryMaxAttempts);
Gamze Abaka33feef52019-02-27 08:16:47 +0000338
alshabibe0559672016-02-21 14:49:51 -0800339 } catch (Exception e) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000340 log.error("Error while modifying the properties", e);
Andrea Campanella971d5b92020-05-07 11:20:43 +0200341 defaultBpId = DEFAULT_BP_ID_DEFAULT;
342 multicastServiceName = DEFAULT_MCAST_SERVICE_NAME_DEFAULT;
alshabibe0559672016-02-21 14:49:51 -0800343 }
344 }
345
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000346 protected void bindSadisService(SadisService service) {
347 sadisService = service;
348 bpService = sadisService.getBandwidthProfileService();
349 subsService = sadisService.getSubscriberInfoService();
350 log.info("Sadis-service binds to onos.");
351 }
352
353 protected void unbindSadisService(SadisService service) {
354 sadisService = null;
355 bpService = null;
356 subsService = null;
357 log.info("Sadis-service unbinds from onos.");
358 }
359
alshabib32232c82016-02-25 17:57:24 -0500360 @Override
Gamze Abaka838d8142019-02-21 07:06:55 +0000361 public boolean provisionSubscriber(ConnectPoint connectPoint) {
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200362 log.info("Call to provision subscriber at {}", connectPoint);
Gamze Abaka838d8142019-02-21 07:06:55 +0000363 DeviceId deviceId = connectPoint.deviceId();
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000364 Port subscriberPortOnos = deviceService.getPort(deviceId, connectPoint.port());
365 checkNotNull(subscriberPortOnos, "Invalid connect point:" + connectPoint);
366 AccessDevicePort subscriberPort = new AccessDevicePort(subscriberPortOnos, AccessDevicePort.Type.UNI);
Hardik Windlass395ff372019-06-13 05:16:00 +0000367
Saurav Das026650f2020-09-21 18:56:35 -0700368 if (isSubscriberInstalled(connectPoint)) {
369 log.warn("Subscriber at {} already provisioned or in the process .."
370 + " not taking any more action", connectPoint);
371 return true;
372 }
373
374 // Find the subscriber config at this connect point
Gamze Abaka838d8142019-02-21 07:06:55 +0000375 SubscriberAndDeviceInformation sub = getSubscriber(connectPoint);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100376 if (sub == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000377 log.warn("No subscriber found for {}", connectPoint);
Amit Ghosh31939522018-08-16 13:28:21 +0100378 return false;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100379 }
Jonathan Harte533a422015-10-20 17:31:24 -0700380
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100381 // Get the uplink port
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000382 AccessDevicePort uplinkPort = getUplinkPort(deviceService.getDevice(deviceId));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100383 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000384 log.warn(NO_UPLINK_PORT, deviceId);
Amit Ghosh31939522018-08-16 13:28:21 +0100385 return false;
Jonathan Harte533a422015-10-20 17:31:24 -0700386 }
387
Saurav Das2d3777a2020-08-07 18:48:51 -0700388 // delete Eapol authentication flow with default bandwidth
389 // wait until Eapol rule with defaultBpId is removed to install subscriber-based rules
390 // retry deletion if it fails/times-out
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000391 retryExecutor.execute(new DeleteEapolInstallSub(subscriberPort, uplinkPort, sub, 1));
Amit Ghosh31939522018-08-16 13:28:21 +0100392 return true;
alshabibb7a9e172016-01-13 11:23:53 -0800393 }
394
Saurav Das026650f2020-09-21 18:56:35 -0700395 // returns true if subscriber is programmed or in the process of being programmed
396 private boolean isSubscriberInstalled(ConnectPoint connectPoint) {
397 Collection<? extends UniTagInformation> uniTagInformationSet =
398 programmedSubs.get(connectPoint).value();
399 if (!uniTagInformationSet.isEmpty()) {
400 return true;
401 }
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100402 //Check if the subscriber is already getting provisioned
403 // so we do not provision twice
404 AtomicBoolean isPending = new AtomicBoolean(false);
405 pendingSubscribersForDevice.computeIfPresent(connectPoint.deviceId(), (id, infos) -> {
406 for (SubscriberFlowInfo fi : infos) {
407 if (fi.getUniPort().equals(connectPoint.port())) {
yasin saplib4b8ee12021-06-13 18:25:20 +0000408 log.debug("Subscriber is already pending, {}", fi);
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100409 isPending.set(true);
410 break;
411 }
Saurav Das026650f2020-09-21 18:56:35 -0700412 }
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100413 return infos;
414 });
Saurav Das026650f2020-09-21 18:56:35 -0700415
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100416 return isPending.get();
Saurav Das026650f2020-09-21 18:56:35 -0700417 }
418
Saurav Das2d3777a2020-08-07 18:48:51 -0700419 private class DeleteEapolInstallSub implements Runnable {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000420 AccessDevicePort subscriberPort;
421 AccessDevicePort uplinkPort;
Saurav Das2d3777a2020-08-07 18:48:51 -0700422 SubscriberAndDeviceInformation sub;
423 private int attemptNumber;
424
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000425 DeleteEapolInstallSub(AccessDevicePort subscriberPort, AccessDevicePort uplinkPort,
Saurav Das2d3777a2020-08-07 18:48:51 -0700426 SubscriberAndDeviceInformation sub,
427 int attemptNumber) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000428 this.subscriberPort = subscriberPort;
Saurav Das2d3777a2020-08-07 18:48:51 -0700429 this.uplinkPort = uplinkPort;
430 this.sub = sub;
431 this.attemptNumber = attemptNumber;
432 }
433
434 @Override
435 public void run() {
Tunahan Sezena07fe962021-02-24 08:24:24 +0000436 CompletableFuture<ObjectiveError> filterFuture = new CompletableFuture<>();
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000437 oltFlowService.processEapolFilteringObjectives(subscriberPort,
yasin saplib4b8ee12021-06-13 18:25:20 +0000438 defaultBpId, Optional.empty(), filterFuture,
Saurav Das2d3777a2020-08-07 18:48:51 -0700439 VlanId.vlanId(EAPOL_DEFAULT_VLAN),
440 false);
441 filterFuture.thenAcceptAsync(filterStatus -> {
442 if (filterStatus == null) {
443 log.info("Default eapol flow deleted in attempt {} of {}"
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000444 + "... provisioning subscriber flows on {}",
445 attemptNumber, eapolDeleteRetryMaxAttempts, subscriberPort);
Matteo Scandoloa4aaa972020-10-23 15:24:38 -0700446
447 // FIXME this is needed to prevent that default EAPOL flow removal and
448 // data plane flows install are received by the device at the same time
449 provisionExecutor.schedule(
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000450 () -> provisionUniTagList(subscriberPort, uplinkPort, sub),
Matteo Scandoloa4aaa972020-10-23 15:24:38 -0700451 provisionDelay, TimeUnit.MILLISECONDS);
Saurav Das2d3777a2020-08-07 18:48:51 -0700452 } else {
453 if (attemptNumber <= eapolDeleteRetryMaxAttempts) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000454 log.warn("The filtering future failed {} for subscriber on {}"
Saurav Das2d3777a2020-08-07 18:48:51 -0700455 + "... retrying {} of {} attempts",
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000456 filterStatus, subscriberPort, attemptNumber, eapolDeleteRetryMaxAttempts);
Saurav Das2d3777a2020-08-07 18:48:51 -0700457 retryExecutor.execute(
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000458 new DeleteEapolInstallSub(subscriberPort, uplinkPort, sub,
Saurav Das2d3777a2020-08-07 18:48:51 -0700459 attemptNumber + 1));
460 } else {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000461 log.error("The filtering future failed {} for subscriber on {}"
Saurav Das2d3777a2020-08-07 18:48:51 -0700462 + "after {} attempts. Subscriber provisioning failed",
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000463 filterStatus, subscriberPort, eapolDeleteRetryMaxAttempts);
464 sub.uniTagList().forEach(ut ->
465 failedSubs.put(
466 new ConnectPoint(subscriberPort.deviceId(), subscriberPort.number()), ut));
Saurav Das2d3777a2020-08-07 18:48:51 -0700467 }
468 }
469 });
470 }
471
472 }
473
alshabibb7a9e172016-01-13 11:23:53 -0800474 @Override
Gamze Abaka838d8142019-02-21 07:06:55 +0000475 public boolean removeSubscriber(ConnectPoint connectPoint) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000476 Port subscriberPort = deviceService.getPort(connectPoint);
477 if (subscriberPort == null) {
478 log.error("Subscriber port not found at: {}", connectPoint);
479 return false;
480 }
481 return removeSubscriber(new AccessDevicePort(subscriberPort, AccessDevicePort.Type.UNI));
482 }
483
484 private boolean removeSubscriber(AccessDevicePort subscriberPort) {
485 log.info("Call to un-provision subscriber at {}", subscriberPort);
Gamze Abaka838d8142019-02-21 07:06:55 +0000486
Saurav Daseae48de2019-06-19 13:26:15 -0700487 // Get the subscriber connected to this port from the local cache
488 // If we don't know about the subscriber there's no need to remove it
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000489 DeviceId deviceId = subscriberPort.deviceId();
Gamze Abaka838d8142019-02-21 07:06:55 +0000490
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000491 ConnectPoint connectPoint = new ConnectPoint(deviceId, subscriberPort.number());
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800492 Collection<? extends UniTagInformation> uniTagInformationSet = programmedSubs.get(connectPoint).value();
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000493 if (uniTagInformationSet == null || uniTagInformationSet.isEmpty()) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000494 log.warn("Subscriber on connectionPoint {} was not previously programmed, " +
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000495 "no need to remove it", connectPoint);
Matteo Scandolo962a6ad2018-12-11 15:39:42 -0800496 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800497 }
498
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100499 // Get the uplink port
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000500 AccessDevicePort uplinkPort = getUplinkPort(deviceService.getDevice(deviceId));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100501 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000502 log.warn(NO_UPLINK_PORT, deviceId);
Amit Ghosh31939522018-08-16 13:28:21 +0100503 return false;
alshabib4ceaed32016-03-03 18:00:58 -0800504 }
505
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000506 for (UniTagInformation uniTag : uniTagInformationSet) {
Amit Ghosh95e2f652017-08-23 12:49:46 +0100507
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000508 if (multicastServiceName.equals(uniTag.getServiceName())) {
509 continue;
510 }
Gamze Abaka838d8142019-02-21 07:06:55 +0000511
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000512 unprovisionVlans(uplinkPort, subscriberPort, uniTag);
alshabibbf23a1f2016-01-14 17:27:11 -0800513
Saurav Das9da7d522020-03-23 19:14:35 -0700514 // remove eapol with subscriber bandwidth profile
yasin saplib4b8ee12021-06-13 18:25:20 +0000515 Optional<String> upstreamOltBw = uniTag.getUpstreamOltBandwidthProfile() == null ?
516 Optional.empty() : Optional.of(uniTag.getUpstreamOltBandwidthProfile());
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000517 oltFlowService.processEapolFilteringObjectives(subscriberPort,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000518 uniTag.getUpstreamBandwidthProfile(),
yasin saplib4b8ee12021-06-13 18:25:20 +0000519 upstreamOltBw,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000520 null, uniTag.getPonCTag(), false);
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100521
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000522 if (subscriberPort.port() != null && subscriberPort.isEnabled()) {
Saurav Das9da7d522020-03-23 19:14:35 -0700523 // reinstall eapol with default bandwidth profile
yasin saplib4b8ee12021-06-13 18:25:20 +0000524 oltFlowService.processEapolFilteringObjectives(subscriberPort, defaultBpId, Optional.empty(),
525 null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000526 } else {
527 log.debug("Port {} is no longer enabled or it's unavailable. Not "
528 + "reprogramming default eapol flow", connectPoint);
529 }
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100530 }
Amit Ghosh31939522018-08-16 13:28:21 +0100531 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800532 }
533
Gamze Abakaf59c0912019-04-19 08:24:28 +0000534
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000535 @Override
536 public boolean provisionSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag,
537 Optional<VlanId> cTag, Optional<Integer> tpId) {
538
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000539 log.info("Provisioning subscriber using subscriberId {}, sTag {}, cTag {}, tpId {}",
540 subscriberId, sTag, cTag, tpId);
Gamze Abakaf59c0912019-04-19 08:24:28 +0000541
Amit Ghosh31939522018-08-16 13:28:21 +0100542 // Check if we can find the connect point to which this subscriber is connected
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000543 ConnectPoint cp = findSubscriberConnectPoint(subscriberId.toString());
544 if (cp == null) {
Amit Ghosh31939522018-08-16 13:28:21 +0100545 log.warn("ConnectPoint for {} not found", subscriberId);
546 return false;
547 }
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000548 AccessDevicePort subscriberPort = new AccessDevicePort(deviceService.getPort(cp), AccessDevicePort.Type.UNI);
Amit Ghosh31939522018-08-16 13:28:21 +0100549
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100550 if (!sTag.isPresent() && !cTag.isPresent()) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000551 return provisionSubscriber(cp);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000552 } else if (sTag.isPresent() && cTag.isPresent() && tpId.isPresent()) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000553 AccessDevicePort uplinkPort = getUplinkPort(deviceService.getDevice(cp.deviceId()));
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100554 if (uplinkPort == null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000555 log.warn(NO_UPLINK_PORT, cp.deviceId());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100556 return false;
557 }
558
Gamze Abakaf59c0912019-04-19 08:24:28 +0000559 //delete Eapol authentication flow with default bandwidth
560 //wait until Eapol rule with defaultBpId is removed to install subscriber-based rules
Gamze Abakaf59c0912019-04-19 08:24:28 +0000561 //install subscriber flows
Tunahan Sezena07fe962021-02-24 08:24:24 +0000562 CompletableFuture<ObjectiveError> filterFuture = new CompletableFuture<>();
yasin saplib4b8ee12021-06-13 18:25:20 +0000563 oltFlowService.processEapolFilteringObjectives(subscriberPort, defaultBpId, Optional.empty(),
564 filterFuture, VlanId.vlanId(EAPOL_DEFAULT_VLAN), false);
Gamze Abakaf59c0912019-04-19 08:24:28 +0000565 filterFuture.thenAcceptAsync(filterStatus -> {
566 if (filterStatus == null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000567 provisionUniTagInformation(uplinkPort, subscriberPort, cTag.get(), sTag.get(), tpId.get());
Gamze Abakaf59c0912019-04-19 08:24:28 +0000568 }
569 });
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100570 return true;
571 } else {
572 log.warn("Provisioning failed for subscriber: {}", subscriberId);
573 return false;
574 }
Amit Ghosh31939522018-08-16 13:28:21 +0100575 }
Amit Ghosh95e2f652017-08-23 12:49:46 +0100576
alshabibe0559672016-02-21 14:49:51 -0800577 @Override
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000578 public boolean removeSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag,
579 Optional<VlanId> cTag, Optional<Integer> tpId) {
Amit Ghosh31939522018-08-16 13:28:21 +0100580 // Check if we can find the connect point to which this subscriber is connected
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000581 ConnectPoint cp = findSubscriberConnectPoint(subscriberId.toString());
582 if (cp == null) {
Amit Ghosh31939522018-08-16 13:28:21 +0100583 log.warn("ConnectPoint for {} not found", subscriberId);
584 return false;
585 }
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000586 AccessDevicePort subscriberPort = new AccessDevicePort(deviceService.getPort(cp), AccessDevicePort.Type.UNI);
Amit Ghosh31939522018-08-16 13:28:21 +0100587
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100588 if (!sTag.isPresent() && !cTag.isPresent()) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000589 return removeSubscriber(cp);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000590 } else if (sTag.isPresent() && cTag.isPresent() && tpId.isPresent()) {
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100591 // Get the uplink port
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000592 AccessDevicePort uplinkPort = getUplinkPort(deviceService.getDevice(cp.deviceId()));
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100593 if (uplinkPort == null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000594 log.warn(NO_UPLINK_PORT, cp.deviceId());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100595 return false;
596 }
597
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000598 Optional<UniTagInformation> tagInfo = getUniTagInformation(subscriberPort, cTag.get(),
599 sTag.get(), tpId.get());
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000600 if (!tagInfo.isPresent()) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000601 log.warn("UniTagInformation does not exist for {}, cTag {}, sTag {}, tpId {}",
602 subscriberPort, cTag, sTag, tpId);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000603 return false;
604 }
Gamze Abakaf59c0912019-04-19 08:24:28 +0000605
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000606 unprovisionVlans(uplinkPort, subscriberPort, tagInfo.get());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100607 return true;
608 } else {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000609 log.warn("Removing subscriber is not possible - please check the provided information" +
610 "for the subscriber: {}", subscriberId);
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100611 return false;
612 }
Amit Ghosh31939522018-08-16 13:28:21 +0100613 }
614
615 @Override
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000616 public ImmutableMap<ConnectPoint, Set<UniTagInformation>> getProgSubs() {
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800617 return programmedSubs.stream()
618 .collect(collectingAndThen(
619 groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, toSet())),
620 ImmutableMap::copyOf));
Saurav Das82b8e6d2018-10-04 15:25:12 -0700621 }
622
623 @Override
Saurav Das2d3777a2020-08-07 18:48:51 -0700624 public ImmutableMap<ConnectPoint, Set<UniTagInformation>> getFailedSubs() {
625 return failedSubs.stream()
626 .collect(collectingAndThen(
627 groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, toSet())),
628 ImmutableMap::copyOf));
629 }
630
631 @Override
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100632 public List<DeviceId> fetchOlts() {
633 // look through all the devices and find the ones that are OLTs as per Sadis
634 List<DeviceId> olts = new ArrayList<>();
635 Iterable<Device> devices = deviceService.getDevices();
636 for (Device d : devices) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700637 if (getOltInfo(d) != null) {
638 // So this is indeed an OLT device
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100639 olts.add(d.id());
640 }
641 }
642 return olts;
alshabibe0559672016-02-21 14:49:51 -0800643 }
644
Amit Ghosh31939522018-08-16 13:28:21 +0100645 /**
646 * Finds the connect point to which a subscriber is connected.
647 *
648 * @param id The id of the subscriber, this is the same ID as in Sadis
649 * @return Subscribers ConnectPoint if found else null
650 */
651 private ConnectPoint findSubscriberConnectPoint(String id) {
652
653 Iterable<Device> devices = deviceService.getDevices();
654 for (Device d : devices) {
655 for (Port p : deviceService.getPorts(d.id())) {
656 log.trace("Comparing {} with {}", p.annotations().value(AnnotationKeys.PORT_NAME), id);
657 if (p.annotations().value(AnnotationKeys.PORT_NAME).equals(id)) {
658 log.debug("Found on device {} port {}", d.id(), p.number());
659 return new ConnectPoint(d.id(), p.number());
660 }
661 }
662 }
663 return null;
664 }
665
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000666 /**
667 * Gets the context of the bandwidth profile information for the given parameter.
668 *
669 * @param bandwidthProfile the bandwidth profile id
670 * @return the context of the bandwidth profile information
671 */
Gamze Abaka641fc072018-09-04 09:16:27 +0000672 private BandwidthProfileInformation getBandwidthProfileInformation(String bandwidthProfile) {
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000673 if (bpService == null) {
674 log.warn(SADIS_NOT_RUNNING);
675 return null;
676 }
Gamze Abaka641fc072018-09-04 09:16:27 +0000677 if (bandwidthProfile == null) {
678 return null;
679 }
680 return bpService.get(bandwidthProfile);
681 }
682
Gamze Abaka838d8142019-02-21 07:06:55 +0000683 /**
Gamze Abaka33feef52019-02-27 08:16:47 +0000684 * Removes subscriber vlan flows.
Gamze Abaka838d8142019-02-21 07:06:55 +0000685 *
Gamze Abaka838d8142019-02-21 07:06:55 +0000686 * @param uplink uplink port of the OLT
687 * @param subscriberPort uni port
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000688 * @param uniTag uni tag information
Gamze Abaka838d8142019-02-21 07:06:55 +0000689 */
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000690 private void unprovisionVlans(AccessDevicePort uplink, AccessDevicePort subscriberPort, UniTagInformation uniTag) {
691 log.info("Unprovisioning vlans for {} at {}", uniTag, subscriberPort);
692 DeviceId deviceId = subscriberPort.deviceId();
alshabibbf23a1f2016-01-14 17:27:11 -0800693
Tunahan Sezena07fe962021-02-24 08:24:24 +0000694 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture<>();
695 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture<>();
alshabibbf23a1f2016-01-14 17:27:11 -0800696
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000697 VlanId deviceVlan = uniTag.getPonSTag();
698 VlanId subscriberVlan = uniTag.getPonCTag();
Gamze Abaka641fc072018-09-04 09:16:27 +0000699
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000700 MeterId upstreamMeterId = oltMeterService
701 .getMeterIdFromBpMapping(deviceId, uniTag.getUpstreamBandwidthProfile());
702 MeterId downstreamMeterId = oltMeterService
703 .getMeterIdFromBpMapping(deviceId, uniTag.getDownstreamBandwidthProfile());
yasin saplib4b8ee12021-06-13 18:25:20 +0000704 MeterId upstreamOltMeterId = oltMeterService
705 .getMeterIdFromBpMapping(deviceId, uniTag.getUpstreamOltBandwidthProfile());
706 MeterId downstreamOltMeterId = oltMeterService
707 .getMeterIdFromBpMapping(deviceId, uniTag.getDownstreamOltBandwidthProfile());
Gamze Abaka641fc072018-09-04 09:16:27 +0000708
Tunahan Sezena07fe962021-02-24 08:24:24 +0000709 Optional<SubscriberFlowInfo> waitingMacSubFlowInfo =
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000710 getAndRemoveWaitingMacSubFlowInfoForCTag(new ConnectPoint(deviceId, subscriberPort.number()),
711 subscriberVlan);
Tunahan Sezena07fe962021-02-24 08:24:24 +0000712 if (waitingMacSubFlowInfo.isPresent()) {
713 // only dhcp objectives applied previously, so only dhcp uninstallation objective will be processed
714 log.debug("Waiting MAC service removed and dhcp uninstallation objective will be processed. " +
715 "waitingMacSubFlowInfo:{}", waitingMacSubFlowInfo.get());
716 CompletableFuture<ObjectiveError> dhcpFuture = new CompletableFuture<>();
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000717 oltFlowService.processDhcpFilteringObjectives(subscriberPort,
yasin saplib4b8ee12021-06-13 18:25:20 +0000718 upstreamMeterId, upstreamOltMeterId, uniTag, false, true, Optional.of(dhcpFuture));
Tunahan Sezena07fe962021-02-24 08:24:24 +0000719 dhcpFuture.thenAcceptAsync(dhcpStatus -> {
720 AccessDeviceEvent.Type type;
721 if (dhcpStatus == null) {
722 type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_UNREGISTERED;
723 log.debug("Dhcp uninstallation objective was processed successfully for cTag {}, sTag {}, " +
724 "tpId {} and Device/Port:{}", uniTag.getPonCTag(), uniTag.getPonSTag(),
725 uniTag.getTechnologyProfileId(), subscriberPort);
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000726 updateProgrammedSubscriber(subscriberPort, uniTag, false);
Tunahan Sezena07fe962021-02-24 08:24:24 +0000727 } else {
728 type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_UNREGISTRATION_FAILED;
729 log.error("Dhcp uninstallation objective was failed for cTag {}, sTag {}, " +
730 "tpId {} and Device/Port:{} :{}", uniTag.getPonCTag(), uniTag.getPonSTag(),
731 uniTag.getTechnologyProfileId(), subscriberPort, dhcpStatus);
732 }
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000733 post(new AccessDeviceEvent(type, deviceId, subscriberPort.port(),
Tunahan Sezena07fe962021-02-24 08:24:24 +0000734 deviceVlan, subscriberVlan, uniTag.getTechnologyProfileId()));
735 });
736 return;
737 } else {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000738 log.debug("There is no waiting MAC service for {} and subscriberVlan: {}", subscriberPort, subscriberVlan);
Tunahan Sezena07fe962021-02-24 08:24:24 +0000739 }
740
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000741 ForwardingObjective.Builder upFwd =
yasin saplib4b8ee12021-06-13 18:25:20 +0000742 oltFlowService.createUpBuilder(uplink, subscriberPort, upstreamMeterId, upstreamOltMeterId, uniTag);
Tunahan Sezena07fe962021-02-24 08:24:24 +0000743
744 Optional<MacAddress> macAddress = getMacAddress(deviceId, subscriberPort, uniTag);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000745 ForwardingObjective.Builder downFwd =
yasin saplib4b8ee12021-06-13 18:25:20 +0000746 oltFlowService.createDownBuilder(uplink, subscriberPort, downstreamMeterId, downstreamOltMeterId,
747 uniTag, macAddress);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000748
yasin saplib4b8ee12021-06-13 18:25:20 +0000749 oltFlowService.processIgmpFilteringObjectives(subscriberPort, upstreamMeterId, upstreamOltMeterId, uniTag,
750 false, true);
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000751 oltFlowService.processDhcpFilteringObjectives(subscriberPort,
yasin saplib4b8ee12021-06-13 18:25:20 +0000752 upstreamMeterId, upstreamOltMeterId, uniTag, false, true, Optional.empty());
753 oltFlowService.processPPPoEDFilteringObjectives(subscriberPort, upstreamMeterId, upstreamOltMeterId, uniTag,
754 false, true);
alshabibbf23a1f2016-01-14 17:27:11 -0800755
alshabib4ceaed32016-03-03 18:00:58 -0800756 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
757 @Override
758 public void onSuccess(Objective objective) {
759 upFuture.complete(null);
760 }
alshabibbf23a1f2016-01-14 17:27:11 -0800761
alshabib4ceaed32016-03-03 18:00:58 -0800762 @Override
763 public void onError(Objective objective, ObjectiveError error) {
764 upFuture.complete(error);
765 }
766 }));
767
768 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
769 @Override
770 public void onSuccess(Objective objective) {
771 downFuture.complete(null);
772 }
773
774 @Override
775 public void onError(Objective objective, ObjectiveError error) {
776 downFuture.complete(error);
777 }
778 }));
alshabibbf23a1f2016-01-14 17:27:11 -0800779
780 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000781 AccessDeviceEvent.Type type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_UNREGISTERED;
alshabibbf23a1f2016-01-14 17:27:11 -0800782 if (upStatus == null && downStatus == null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000783 log.debug("Uni tag information is unregistered successfully for cTag {}, sTag {}, tpId {} on {}",
784 uniTag.getPonCTag(), uniTag.getPonSTag(), uniTag.getTechnologyProfileId(), subscriberPort);
785 updateProgrammedSubscriber(subscriberPort, uniTag, false);
alshabibbf23a1f2016-01-14 17:27:11 -0800786 } else if (downStatus != null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000787 log.error("Subscriber with vlan {} on {} failed downstream uninstallation: {}",
788 subscriberVlan, subscriberPort, downStatus);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000789 type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_UNREGISTRATION_FAILED;
alshabibbf23a1f2016-01-14 17:27:11 -0800790 } else if (upStatus != null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000791 log.error("Subscriber with vlan {} on {} failed upstream uninstallation: {}",
792 subscriberVlan, subscriberPort, upStatus);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000793 type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_UNREGISTRATION_FAILED;
alshabibbf23a1f2016-01-14 17:27:11 -0800794 }
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000795 post(new AccessDeviceEvent(type, deviceId, subscriberPort.port(), deviceVlan, subscriberVlan,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000796 uniTag.getTechnologyProfileId()));
alshabibbf23a1f2016-01-14 17:27:11 -0800797 }, oltInstallers);
Jonathan Harte533a422015-10-20 17:31:24 -0700798 }
799
Tunahan Sezena07fe962021-02-24 08:24:24 +0000800 private Optional<SubscriberFlowInfo> getAndRemoveWaitingMacSubFlowInfoForCTag(ConnectPoint cp, VlanId cTag) {
801 SubscriberFlowInfo returnSubFlowInfo = null;
802 Collection<? extends SubscriberFlowInfo> subFlowInfoSet = waitingMacSubscribers.get(cp).value();
803 for (SubscriberFlowInfo subFlowInfo : subFlowInfoSet) {
804 if (subFlowInfo.getTagInfo().getPonCTag().equals(cTag)) {
805 returnSubFlowInfo = subFlowInfo;
806 break;
807 }
808 }
809 if (returnSubFlowInfo != null) {
810 waitingMacSubscribers.remove(cp, returnSubFlowInfo);
811 return Optional.of(returnSubFlowInfo);
812 }
813 return Optional.empty();
814 }
815
Gamze Abaka838d8142019-02-21 07:06:55 +0000816 /**
Gamze Abaka33feef52019-02-27 08:16:47 +0000817 * Adds subscriber vlan flows, dhcp, eapol and igmp trap flows for the related uni port.
Gamze Abaka838d8142019-02-21 07:06:55 +0000818 *
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000819 * @param subPort the connection point of the subscriber
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000820 * @param uplinkPort uplink port of the OLT (the nni port)
821 * @param sub subscriber information that includes s, c tags, tech profile and bandwidth profile references
Gamze Abaka838d8142019-02-21 07:06:55 +0000822 */
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000823 private void provisionUniTagList(AccessDevicePort subPort, AccessDevicePort uplinkPort,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000824 SubscriberAndDeviceInformation sub) {
Gamze Abaka641fc072018-09-04 09:16:27 +0000825
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000826 log.debug("Provisioning vlans for subscriber on {}", subPort);
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700827 if (log.isTraceEnabled()) {
828 log.trace("Subscriber informations {}", sub);
829 }
Gamze Abaka641fc072018-09-04 09:16:27 +0000830
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000831 if (sub.uniTagList() == null || sub.uniTagList().isEmpty()) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000832 log.warn("Unitaglist doesn't exist for the subscriber {} on {}", sub.id(), subPort);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000833 return;
834 }
Gamze Abaka641fc072018-09-04 09:16:27 +0000835
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000836 for (UniTagInformation uniTag : sub.uniTagList()) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000837 handleSubscriberFlows(uplinkPort, subPort, uniTag);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000838 }
839 }
alshabib3ea82642016-01-12 18:06:53 -0800840
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000841 /**
842 * Finds the uni tag information and provisions the found information.
843 * If the uni tag information is not found, returns
844 *
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000845 * @param uplinkPort the nni port
846 * @param subscriberPort the uni port
847 * @param innerVlan the pon c tag
848 * @param outerVlan the pon s tag
849 * @param tpId the technology profile id
850 */
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000851 private void provisionUniTagInformation(AccessDevicePort uplinkPort,
852 AccessDevicePort subscriberPort,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000853 VlanId innerVlan,
854 VlanId outerVlan,
855 Integer tpId) {
Jonathan Harte533a422015-10-20 17:31:24 -0700856
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000857 Optional<UniTagInformation> gotTagInformation = getUniTagInformation(subscriberPort, innerVlan,
858 outerVlan, tpId);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000859 if (!gotTagInformation.isPresent()) {
860 return;
861 }
862 UniTagInformation tagInformation = gotTagInformation.get();
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000863 handleSubscriberFlows(uplinkPort, subscriberPort, tagInformation);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000864 }
alshabib3ea82642016-01-12 18:06:53 -0800865
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000866 private void updateProgrammedSubscriber(AccessDevicePort port, UniTagInformation tagInformation, boolean add) {
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800867 if (add) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000868 programmedSubs.put(new ConnectPoint(port.deviceId(), port.number()), tagInformation);
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800869 } else {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000870 programmedSubs.remove(new ConnectPoint(port.deviceId(), port.number()), tagInformation);
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800871 }
Jonathan Harte533a422015-10-20 17:31:24 -0700872 }
873
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000874 /**
875 * Installs a uni tag information flow.
876 *
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000877 * @param uplinkPort the nni port
878 * @param subscriberPort the uni port
879 * @param tagInfo the uni tag information
880 */
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000881 private void handleSubscriberFlows(AccessDevicePort uplinkPort, AccessDevicePort subscriberPort,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000882 UniTagInformation tagInfo) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000883 log.debug("Provisioning vlan-based flows for the uniTagInformation {} on {}", tagInfo, subscriberPort);
884 DeviceId deviceId = subscriberPort.deviceId();
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000885
886 if (multicastServiceName.equals(tagInfo.getServiceName())) {
887 // IGMP flows are taken care of along with VOD service
888 // Please note that for each service, Subscriber Registered event will be sent
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000889 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_REGISTERED, deviceId,
890 subscriberPort.port(), tagInfo.getPonSTag(), tagInfo.getPonCTag(),
891 tagInfo.getTechnologyProfileId()));
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000892 return;
Gamze Abaka641fc072018-09-04 09:16:27 +0000893 }
894
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000895 BandwidthProfileInformation upstreamBpInfo =
896 getBandwidthProfileInformation(tagInfo.getUpstreamBandwidthProfile());
897 BandwidthProfileInformation downstreamBpInfo =
898 getBandwidthProfileInformation(tagInfo.getDownstreamBandwidthProfile());
yasin saplib4b8ee12021-06-13 18:25:20 +0000899 BandwidthProfileInformation upstreamOltBpInfo =
900 getBandwidthProfileInformation(tagInfo.getUpstreamOltBandwidthProfile());
901 BandwidthProfileInformation downstreamOltBpInfo =
902 getBandwidthProfileInformation(tagInfo.getDownstreamOltBandwidthProfile());
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700903 if (upstreamBpInfo == null) {
904 log.warn("No meter installed since no Upstream BW Profile definition found for "
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000905 + "ctag {} stag {} tpId {} on {}",
906 tagInfo.getPonCTag(), tagInfo.getPonSTag(), tagInfo.getTechnologyProfileId(), subscriberPort);
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700907 return;
908 }
909 if (downstreamBpInfo == null) {
910 log.warn("No meter installed since no Downstream BW Profile definition found for "
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000911 + "ctag {} stag {} tpId {} on {}",
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700912 tagInfo.getPonCTag(), tagInfo.getPonSTag(),
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000913 tagInfo.getTechnologyProfileId(), subscriberPort);
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700914 return;
915 }
yasin saplib4b8ee12021-06-13 18:25:20 +0000916 if ((upstreamOltBpInfo != null && downstreamOltBpInfo == null) ||
917 (upstreamOltBpInfo == null && downstreamOltBpInfo != null)) {
918 log.warn("No meter installed since only one olt BW Profile definition found for "
919 + "ctag {} stag {} tpId {} and Device/port: {}:{}",
920 tagInfo.getPonCTag(), tagInfo.getPonSTag(),
921 tagInfo.getTechnologyProfileId(), deviceId,
922 subscriberPort);
923 return;
924 }
925
926 MeterId upOltMeterId = null;
927 MeterId downOltMeterId = null;
Gamze Abakaf59c0912019-04-19 08:24:28 +0000928
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700929 // check for meterIds for the upstream and downstream bandwidth profiles
930 MeterId upMeterId = oltMeterService
931 .getMeterIdFromBpMapping(deviceId, upstreamBpInfo.id());
932 MeterId downMeterId = oltMeterService
933 .getMeterIdFromBpMapping(deviceId, downstreamBpInfo.id());
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700934
yasin saplib4b8ee12021-06-13 18:25:20 +0000935 if (upstreamOltBpInfo != null) {
936 // Multi UNI service
937 upOltMeterId = oltMeterService
938 .getMeterIdFromBpMapping(deviceId, upstreamOltBpInfo.id());
939 downOltMeterId = oltMeterService
940 .getMeterIdFromBpMapping(deviceId, downstreamOltBpInfo.id());
941 } else {
942 // NOT Multi UNI service
943 log.debug("OLT bandwidth profiles fields are set to ONU bandwidth profiles");
944 upstreamOltBpInfo = upstreamBpInfo;
945 downstreamOltBpInfo = downstreamBpInfo;
946 upOltMeterId = upMeterId;
947 downOltMeterId = downMeterId;
948 }
949 SubscriberFlowInfo fi = new SubscriberFlowInfo(uplinkPort, subscriberPort,
950 tagInfo, downMeterId, upMeterId, downOltMeterId, upOltMeterId,
951 downstreamBpInfo.id(), upstreamBpInfo.id(),
952 downstreamOltBpInfo.id(), upstreamOltBpInfo.id());
953
954 if (upMeterId != null && downMeterId != null && upOltMeterId != null && downOltMeterId != null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000955 log.debug("Meters are existing for upstream {} and downstream {} on {}",
956 upstreamBpInfo.id(), downstreamBpInfo.id(), subscriberPort);
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700957 handleSubFlowsWithMeters(fi);
958 } else {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000959 log.debug("Adding {} on {} to pending subs", fi, subscriberPort);
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700960 // one or both meters are not ready. It's possible they are in the process of being
961 // created for other subscribers that share the same bandwidth profile.
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100962 pendingSubscribersForDevice.compute(deviceId, (id, queue) -> {
963 if (queue == null) {
964 queue = new LinkedBlockingQueue<>();
965 }
966 queue.add(fi);
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000967 log.info("Added {} to pending subscribers on {}", fi, subscriberPort);
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100968 return queue;
969 });
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700970
yasin saplib4b8ee12021-06-13 18:25:20 +0000971 List<BandwidthProfileInformation> bws = new ArrayList<>();
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700972 // queue up the meters to be created
973 if (upMeterId == null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000974 log.debug("Missing meter for upstream {} on {}", upstreamBpInfo.id(), subscriberPort);
yasin saplib4b8ee12021-06-13 18:25:20 +0000975 bws.add(upstreamBpInfo);
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700976 }
977 if (downMeterId == null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +0000978 log.debug("Missing meter for downstream {} on {}", downstreamBpInfo.id(), subscriberPort);
yasin saplib4b8ee12021-06-13 18:25:20 +0000979 bws.add(downstreamBpInfo);
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700980 }
yasin saplib4b8ee12021-06-13 18:25:20 +0000981 if (upOltMeterId == null) {
982 log.debug("Missing meter for upstreamOlt {} on {}", upstreamOltBpInfo.id(), subscriberPort);
983 bws.add(upstreamOltBpInfo);
984 }
985 if (downOltMeterId == null) {
986 log.debug("Missing meter for downstreamOlt {} on {}", downstreamOltBpInfo.id(), subscriberPort);
987 bws.add(downstreamOltBpInfo);
988 }
989 bws.stream().distinct().forEach(bw -> checkAndCreateDevMeter(deviceId, bw));
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700990 }
991 }
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000992
Andrea Campanella600d2e22020-06-22 11:00:31 +0200993 private void checkAndCreateDevMeter(DeviceId deviceId, BandwidthProfileInformation bwpInfo) {
yasin saplib4b8ee12021-06-13 18:25:20 +0000994 log.debug("Checking and Creating Meter with {} on {}", bwpInfo, deviceId);
995 if (bwpInfo == null) {
996 log.error("Can't create meter. Bandwidth profile is null for device : {}", deviceId);
997 return;
998 }
Andrea Campanellad1e26642020-10-23 12:08:32 +0200999 //If false the meter is already being installed, skipping installation
1000 if (!oltMeterService.checkAndAddPendingMeter(deviceId, bwpInfo)) {
yasin saplib4b8ee12021-06-13 18:25:20 +00001001 log.debug("Meter is already being installed on {} for {}", deviceId, bwpInfo);
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001002 return;
1003 }
Andrea Campanella600d2e22020-06-22 11:00:31 +02001004 createMeter(deviceId, bwpInfo);
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001005 }
1006
Andrea Campanella600d2e22020-06-22 11:00:31 +02001007 private void createMeter(DeviceId deviceId, BandwidthProfileInformation bwpInfo) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -07001008 log.debug("Creating Meter with {} on {}", bwpInfo, deviceId);
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001009 CompletableFuture<Object> meterFuture = new CompletableFuture<>();
Andrea Campanella3ce4d282020-06-09 13:46:58 +02001010
Andrea Campanella600d2e22020-06-22 11:00:31 +02001011 MeterId meterId = oltMeterService.createMeter(deviceId, bwpInfo,
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001012 meterFuture);
1013
1014 meterFuture.thenAcceptAsync(result -> {
yasin saplib4b8ee12021-06-13 18:25:20 +00001015 log.debug("Meter Future for {} has completed", meterId);
1016 pendingSubscribersForDevice.compute(deviceId, (id, queue) -> {
1017 // iterate through the subscribers on hold
1018 if (queue != null && !queue.isEmpty()) {
1019 while (true) {
1020 //TODO this might return the reference and not the actual object so
1021 // it can be actually swapped underneath us.
1022 SubscriberFlowInfo fi = queue.peek();
1023 if (fi == null) {
1024 log.debug("No more subscribers pending on {}", deviceId);
1025 queue = new LinkedBlockingQueue<>();
1026 break;
1027 }
1028 if (result == null) {
1029 // meter install sent to device
1030 log.debug("Meter {} installed for bw {} on {}", meterId, bwpInfo, deviceId);
Andrea Campanella7a1d7e72020-11-05 10:40:10 +01001031
yasin saplib4b8ee12021-06-13 18:25:20 +00001032 MeterId upMeterId = oltMeterService
1033 .getMeterIdFromBpMapping(deviceId, fi.getUpBpInfo());
1034 MeterId downMeterId = oltMeterService
1035 .getMeterIdFromBpMapping(deviceId, fi.getDownBpInfo());
1036 MeterId upOltMeterId = oltMeterService
1037 .getMeterIdFromBpMapping(deviceId, fi.getUpOltBpInfo());
1038 MeterId downOltMeterId = oltMeterService
1039 .getMeterIdFromBpMapping(deviceId, fi.getDownOltBpInfo());
1040 if (upMeterId != null && downMeterId != null &&
1041 upOltMeterId != null && downOltMeterId != null) {
1042 log.debug("Provisioning subscriber after meter {} " +
1043 "installation and all meters are present " +
1044 "upstream {} , downstream {} , oltUpstream {} " +
1045 "and oltDownstream {} on {}",
1046 meterId, upMeterId, downMeterId, upOltMeterId,
1047 downOltMeterId, fi.getUniPort());
1048 // put in the meterIds because when fi was first
1049 // created there may or may not have been a meterId
1050 // depending on whether the meter was created or
1051 // not at that time.
1052 fi.setUpMeterId(upMeterId);
1053 fi.setDownMeterId(downMeterId);
1054 fi.setUpOltMeterId(upOltMeterId);
1055 fi.setDownOltMeterId(downOltMeterId);
1056 handleSubFlowsWithMeters(fi);
1057 queue.remove(fi);
1058 } else {
1059 log.debug("Not all meters for {} are yet installed up {}, " +
1060 "down {}, oltUp {}, oltDown {}", fi, upMeterId,
1061 downMeterId, upOltMeterId, downOltMeterId);
1062 }
1063 oltMeterService.removeFromPendingMeters(deviceId, bwpInfo);
1064 } else {
1065 // meter install failed
1066 log.error("Addition of subscriber {} on {} failed due to meter " +
1067 "{} with result {}", fi, fi.getUniPort(), meterId, result);
1068 oltMeterService.removeFromPendingMeters(deviceId, bwpInfo);
Andrea Campanella7a1d7e72020-11-05 10:40:10 +01001069 queue.remove(fi);
1070 }
Andrea Campanella7a1d7e72020-11-05 10:40:10 +01001071 }
yasin saplib4b8ee12021-06-13 18:25:20 +00001072 } else {
1073 log.info("No pending subscribers on {}", deviceId);
1074 queue = new LinkedBlockingQueue<>();
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001075 }
yasin saplib4b8ee12021-06-13 18:25:20 +00001076 return queue;
1077 });
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001078 });
Andrea Campanella7a1d7e72020-11-05 10:40:10 +01001079
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001080 }
Ilayda Ozdemir90a93622021-02-25 09:40:58 +00001081
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001082 /**
1083 * Add subscriber flows given meter information for both upstream and
1084 * downstream directions.
1085 *
1086 * @param subscriberFlowInfo relevant information for subscriber
1087 */
1088 private void handleSubFlowsWithMeters(SubscriberFlowInfo subscriberFlowInfo) {
Tunahan Sezena07fe962021-02-24 08:24:24 +00001089 log.debug("Provisioning subscriber flows based on {}", subscriberFlowInfo);
1090 UniTagInformation tagInfo = subscriberFlowInfo.getTagInfo();
1091 if (tagInfo.getIsDhcpRequired()) {
1092 Optional<MacAddress> macAddress =
1093 getMacAddress(subscriberFlowInfo.getDevId(), subscriberFlowInfo.getUniPort(), tagInfo);
1094 if (subscriberFlowInfo.getTagInfo().getEnableMacLearning()) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001095 ConnectPoint cp = new ConnectPoint(subscriberFlowInfo.getDevId(),
1096 subscriberFlowInfo.getUniPort().number());
Tunahan Sezena07fe962021-02-24 08:24:24 +00001097 if (macAddress.isPresent()) {
1098 log.debug("MAC Address {} obtained for {}", macAddress.get(), subscriberFlowInfo);
1099 } else {
1100 waitingMacSubscribers.put(cp, subscriberFlowInfo);
1101 log.debug("Adding sub to waiting mac map: {}", subscriberFlowInfo);
1102 }
1103
1104 CompletableFuture<ObjectiveError> dhcpFuture = new CompletableFuture<>();
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001105 oltFlowService.processDhcpFilteringObjectives(subscriberFlowInfo.getUniPort(),
yasin saplib4b8ee12021-06-13 18:25:20 +00001106 subscriberFlowInfo.getUpId(), subscriberFlowInfo.getUpOltId(),
1107 tagInfo, true, true, Optional.of(dhcpFuture));
Tunahan Sezena07fe962021-02-24 08:24:24 +00001108 dhcpFuture.thenAcceptAsync(dhcpStatus -> {
1109 if (dhcpStatus != null) {
1110 log.error("Dhcp Objective failed for {}: {}", subscriberFlowInfo, dhcpStatus);
1111 if (macAddress.isEmpty()) {
1112 waitingMacSubscribers.remove(cp, subscriberFlowInfo);
1113 }
1114 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_REGISTRATION_FAILED,
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001115 subscriberFlowInfo.getDevId(), subscriberFlowInfo.getUniPort().port(),
Tunahan Sezena07fe962021-02-24 08:24:24 +00001116 tagInfo.getPonSTag(), tagInfo.getPonCTag(), tagInfo.getTechnologyProfileId()));
1117 } else {
1118 log.debug("Dhcp Objective success for: {}", subscriberFlowInfo);
1119 if (macAddress.isPresent()) {
1120 continueProvisioningSubs(subscriberFlowInfo, macAddress);
1121 }
1122 }
1123 });
1124 } else {
1125 log.debug("Dynamic MAC Learning disabled, so will not learn for: {}", subscriberFlowInfo);
1126 // dhcp flows will handle after data plane flows
1127 continueProvisioningSubs(subscriberFlowInfo, macAddress);
1128 }
1129 } else {
1130 // dhcp not required for this service
1131 continueProvisioningSubs(subscriberFlowInfo, Optional.empty());
1132 }
1133 }
1134
1135 private void continueProvisioningSubs(SubscriberFlowInfo subscriberFlowInfo, Optional<MacAddress> macAddress) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001136 AccessDevicePort uniPort = subscriberFlowInfo.getUniPort();
1137 log.debug("Provisioning subscriber flows on {} based on {}", uniPort, subscriberFlowInfo);
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001138 UniTagInformation tagInfo = subscriberFlowInfo.getTagInfo();
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001139 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture<>();
1140 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture<>();
Gamze Abakaf59c0912019-04-19 08:24:28 +00001141
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001142 ForwardingObjective.Builder upFwd =
yasin saplib4b8ee12021-06-13 18:25:20 +00001143 oltFlowService.createUpBuilder(subscriberFlowInfo.getNniPort(), uniPort, subscriberFlowInfo.getUpId(),
1144 subscriberFlowInfo.getUpOltId(), subscriberFlowInfo.getTagInfo());
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001145 flowObjectiveService.forward(subscriberFlowInfo.getDevId(), upFwd.add(new ObjectiveContext() {
1146 @Override
1147 public void onSuccess(Objective objective) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001148 log.debug("Upstream HSIA flow {} installed successfully on {}", subscriberFlowInfo, uniPort);
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001149 upFuture.complete(null);
Gamze Abakaf59c0912019-04-19 08:24:28 +00001150 }
Gamze Abakaf59c0912019-04-19 08:24:28 +00001151
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001152 @Override
1153 public void onError(Objective objective, ObjectiveError error) {
1154 upFuture.complete(error);
Gamze Abakaf59c0912019-04-19 08:24:28 +00001155 }
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001156 }));
1157
1158 ForwardingObjective.Builder downFwd =
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001159 oltFlowService.createDownBuilder(subscriberFlowInfo.getNniPort(), uniPort,
yasin saplib4b8ee12021-06-13 18:25:20 +00001160 subscriberFlowInfo.getDownId(), subscriberFlowInfo.getDownOltId(),
1161 subscriberFlowInfo.getTagInfo(), macAddress);
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001162 flowObjectiveService.forward(subscriberFlowInfo.getDevId(), downFwd.add(new ObjectiveContext() {
1163 @Override
1164 public void onSuccess(Objective objective) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001165 log.debug("Downstream HSIA flow {} installed successfully on {}", subscriberFlowInfo, uniPort);
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001166 downFuture.complete(null);
1167 }
1168
1169 @Override
1170 public void onError(Objective objective, ObjectiveError error) {
1171 downFuture.complete(error);
1172 }
1173 }));
Gamze Abakaf59c0912019-04-19 08:24:28 +00001174
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001175 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001176 AccessDeviceEvent.Type type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_REGISTERED;
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001177 if (downStatus != null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001178 log.error("Flow with innervlan {} and outerVlan {} on {} failed downstream installation: {}",
1179 tagInfo.getPonCTag(), tagInfo.getPonSTag(), uniPort, downStatus);
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001180 type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_REGISTRATION_FAILED;
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001181 } else if (upStatus != null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001182 log.error("Flow with innervlan {} and outerVlan {} on {} failed upstream installation: {}",
1183 tagInfo.getPonCTag(), tagInfo.getPonSTag(), uniPort, upStatus);
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001184 type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_REGISTRATION_FAILED;
Gamze Abakaf59c0912019-04-19 08:24:28 +00001185 } else {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001186 log.debug("Upstream and downstream data plane flows are installed successfully on {}", uniPort);
yasin saplib4b8ee12021-06-13 18:25:20 +00001187 Optional<String> upstreamOltBw = tagInfo.getUpstreamOltBandwidthProfile() == null ?
1188 Optional.empty() : Optional.of(tagInfo.getUpstreamOltBandwidthProfile());
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001189 oltFlowService.processEapolFilteringObjectives(uniPort, tagInfo.getUpstreamBandwidthProfile(),
yasin saplib4b8ee12021-06-13 18:25:20 +00001190 upstreamOltBw, null,
1191 tagInfo.getPonCTag(), true);
Tunahan Sezena07fe962021-02-24 08:24:24 +00001192
1193 if (!tagInfo.getEnableMacLearning()) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001194 oltFlowService.processDhcpFilteringObjectives(uniPort, subscriberFlowInfo.getUpId(),
yasin saplib4b8ee12021-06-13 18:25:20 +00001195 subscriberFlowInfo.getUpOltId(), tagInfo, true, true, Optional.empty());
Tunahan Sezena07fe962021-02-24 08:24:24 +00001196 }
Gamze Abakaf59c0912019-04-19 08:24:28 +00001197
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001198 oltFlowService.processIgmpFilteringObjectives(uniPort, subscriberFlowInfo.getUpId(),
yasin saplib4b8ee12021-06-13 18:25:20 +00001199 subscriberFlowInfo.getUpOltId(), tagInfo, true, true);
Gustavo Silva5c492dd2021-02-12 10:21:11 -03001200
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001201 oltFlowService.processPPPoEDFilteringObjectives(uniPort, subscriberFlowInfo.getUpId(),
yasin saplib4b8ee12021-06-13 18:25:20 +00001202 subscriberFlowInfo.getUpOltId(), tagInfo, true, true);
1203
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001204 updateProgrammedSubscriber(uniPort, tagInfo, true);
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001205 }
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001206 post(new AccessDeviceEvent(type, subscriberFlowInfo.getDevId(), uniPort.port(),
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001207 tagInfo.getPonSTag(), tagInfo.getPonCTag(),
1208 tagInfo.getTechnologyProfileId()));
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001209 }, oltInstallers);
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001210 }
1211
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001212 /**
Tunahan Sezena07fe962021-02-24 08:24:24 +00001213 * Gets mac address from tag info if present, else checks the host service.
1214 *
1215 * @param deviceId device ID
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001216 * @param port uni port
Tunahan Sezena07fe962021-02-24 08:24:24 +00001217 * @param tagInformation tag info
1218 * @return MAC Address of subscriber
1219 */
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001220 private Optional<MacAddress> getMacAddress(DeviceId deviceId, AccessDevicePort port,
Tunahan Sezena07fe962021-02-24 08:24:24 +00001221 UniTagInformation tagInformation) {
1222 if (isMacAddressValid(tagInformation)) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001223 log.debug("Got MAC Address {} from the uniTagInformation for {} and cTag {}",
1224 tagInformation.getConfiguredMacAddress(), port, tagInformation.getPonCTag());
Tunahan Sezena07fe962021-02-24 08:24:24 +00001225 return Optional.of(MacAddress.valueOf(tagInformation.getConfiguredMacAddress()));
1226 } else if (tagInformation.getEnableMacLearning()) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001227 Optional<Host> optHost = hostService.getConnectedHosts(new ConnectPoint(deviceId, port.number()))
Tunahan Sezena07fe962021-02-24 08:24:24 +00001228 .stream().filter(host -> host.vlan().equals(tagInformation.getPonCTag())).findFirst();
1229 if (optHost.isPresent()) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001230 log.debug("Got MAC Address {} from the hostService for {} and cTag {}",
1231 optHost.get().mac(), port, tagInformation.getPonCTag());
Tunahan Sezena07fe962021-02-24 08:24:24 +00001232 return Optional.of(optHost.get().mac());
1233 }
1234 }
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001235 log.debug("Could not obtain MAC Address for {} and cTag {}", port, tagInformation.getPonCTag());
Tunahan Sezena07fe962021-02-24 08:24:24 +00001236 return Optional.empty();
1237 }
1238
1239 private boolean isMacAddressValid(UniTagInformation tagInformation) {
1240 return tagInformation.getConfiguredMacAddress() != null &&
1241 !tagInformation.getConfiguredMacAddress().trim().equals("") &&
1242 !MacAddress.NONE.equals(MacAddress.valueOf(tagInformation.getConfiguredMacAddress()));
1243 }
1244
1245 /**
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001246 * Checks the subscriber uni tag list and find the uni tag information.
1247 * using the pon c tag, pon s tag and the technology profile id
1248 * May return Optional<null>
1249 *
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001250 * @param port port of the subscriber
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001251 * @param innerVlan pon c tag
1252 * @param outerVlan pon s tag
1253 * @param tpId the technology profile id
1254 * @return the found uni tag information
1255 */
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001256 private Optional<UniTagInformation> getUniTagInformation(AccessDevicePort port, VlanId innerVlan,
1257 VlanId outerVlan, int tpId) {
1258 log.debug("Getting uni tag information for {}, innerVlan: {}, outerVlan: {}, tpId: {}",
1259 port, innerVlan, outerVlan, tpId);
1260 SubscriberAndDeviceInformation subInfo = getSubscriber(new ConnectPoint(port.deviceId(), port.number()));
Gamze Abakaf59c0912019-04-19 08:24:28 +00001261 if (subInfo == null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001262 log.warn("Subscriber information doesn't exist for {}", port);
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001263 return Optional.empty();
Gamze Abakaf59c0912019-04-19 08:24:28 +00001264 }
1265
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001266 List<UniTagInformation> uniTagList = subInfo.uniTagList();
1267 if (uniTagList == null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001268 log.warn("Uni tag list is not found for the subscriber {} on {}", subInfo.id(), port);
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001269 return Optional.empty();
1270 }
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001271
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001272 UniTagInformation service = null;
1273 for (UniTagInformation tagInfo : subInfo.uniTagList()) {
1274 if (innerVlan.equals(tagInfo.getPonCTag()) && outerVlan.equals(tagInfo.getPonSTag())
1275 && tpId == tagInfo.getTechnologyProfileId()) {
1276 service = tagInfo;
1277 break;
Andy Bavier160e8682019-05-07 18:32:22 -07001278 }
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001279 }
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001280
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001281 if (service == null) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -07001282 log.warn("SADIS doesn't include the service with ponCtag {} ponStag {} and tpId {} on {}",
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001283 innerVlan, outerVlan, tpId, port);
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001284 return Optional.empty();
Gamze Abaka33feef52019-02-27 08:16:47 +00001285 }
1286
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001287 return Optional.of(service);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001288 }
1289
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001290 /**
Jonathan Hart403372d2018-08-22 11:44:13 -07001291 * Creates trap flows for device, including DHCP and LLDP trap on NNI and
1292 * EAPOL trap on the UNIs, if device is present in Sadis config.
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001293 *
1294 * @param dev Device to look for
1295 */
Jonathan Hart403372d2018-08-22 11:44:13 -07001296 private void checkAndCreateDeviceFlows(Device dev) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001297 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +00001298 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001299 log.info("checkAndCreateDeviceFlows: deviceInfo {}", deviceInfo);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001300
1301 if (deviceInfo != null) {
Andrea Campanella438e1ad2021-03-26 11:41:16 +01001302 log.debug("Driver for device {} is {}", dev.id(),
1303 driverService.getDriver(dev.id()));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001304 for (Port p : deviceService.getPorts(dev.id())) {
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001305 if (PortNumber.LOCAL.equals(p.number()) || !p.isEnabled()) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001306 continue;
1307 }
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001308 if (isUniPort(dev, p)) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001309 AccessDevicePort port = new AccessDevicePort(p, AccessDevicePort.Type.UNI);
Andrea Campanellaa2491782020-03-13 18:09:31 +01001310 if (!programmedSubs.containsKey(new ConnectPoint(dev.id(), p.number()))) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001311 log.info("Creating Eapol on {}", port);
yasin saplib4b8ee12021-06-13 18:25:20 +00001312 oltFlowService.processEapolFilteringObjectives(port, defaultBpId, Optional.empty(),
1313 null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
Andrea Campanellaa2491782020-03-13 18:09:31 +01001314 } else {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001315 log.debug("Subscriber Eapol on {} is already provisioned, not installing default", port);
Andrea Campanellaa2491782020-03-13 18:09:31 +01001316 }
Jonathan Hart403372d2018-08-22 11:44:13 -07001317 } else {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001318 AccessDevicePort port = new AccessDevicePort(p, AccessDevicePort.Type.NNI);
1319 oltFlowService.processNniFilteringObjectives(port, true);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001320 }
1321 }
1322 }
1323 }
1324
Jonathan Hart403372d2018-08-22 11:44:13 -07001325
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001326 /**
1327 * Get the uplink for of the OLT device.
Gamze Abakaad329652018-12-20 10:12:21 +00001328 * <p>
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001329 * This assumes that the OLT has a single uplink port. When more uplink ports need to be supported
1330 * this logic needs to be changed
1331 *
1332 * @param dev Device to look for
1333 * @return The uplink Port of the OLT
1334 */
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001335 private AccessDevicePort getUplinkPort(Device dev) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001336 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +00001337 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Saurav Daseae48de2019-06-19 13:26:15 -07001338 log.trace("getUplinkPort: deviceInfo {}", deviceInfo);
Saurav Das82b8e6d2018-10-04 15:25:12 -07001339 if (deviceInfo == null) {
1340 log.warn("Device {} is not configured in SADIS .. cannot fetch device"
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001341 + " info", dev.id());
Saurav Das82b8e6d2018-10-04 15:25:12 -07001342 return null;
1343 }
1344 // Return the port that has been configured as the uplink port of this OLT in Sadis
kdarapuaa5da252020-04-10 15:58:05 +05301345 Optional<Port> optionalPort = deviceService.getPorts(dev.id()).stream()
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001346 .filter(port -> isNniPort(port) ||
1347 (port.number().toLong() == deviceInfo.uplinkPort()))
1348 .findFirst();
kdarapuaa5da252020-04-10 15:58:05 +05301349 if (optionalPort.isPresent()) {
1350 log.trace("getUplinkPort: Found port {}", optionalPort.get());
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001351 return new AccessDevicePort(optionalPort.get(), AccessDevicePort.Type.NNI);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001352 }
1353
Saurav Daseae48de2019-06-19 13:26:15 -07001354 log.warn("getUplinkPort: " + NO_UPLINK_PORT, dev.id());
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001355 return null;
1356 }
1357
1358 /**
1359 * Return the subscriber on a port.
1360 *
Matteo Scandolo962a6ad2018-12-11 15:39:42 -08001361 * @param cp ConnectPoint on which to find the subscriber
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001362 * @return subscriber if found else null
1363 */
Ilayda Ozdemir90a93622021-02-25 09:40:58 +00001364 protected SubscriberAndDeviceInformation getSubscriber(ConnectPoint cp) {
1365 if (subsService == null) {
1366 log.warn(SADIS_NOT_RUNNING);
1367 return null;
1368 }
Matteo Scandolo962a6ad2018-12-11 15:39:42 -08001369 Port port = deviceService.getPort(cp);
1370 checkNotNull(port, "Invalid connect point");
1371 String portName = port.annotations().value(AnnotationKeys.PORT_NAME);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001372 return subsService.get(portName);
1373 }
1374
Gamze Abakaad329652018-12-20 10:12:21 +00001375 /**
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001376 * Checks whether the given port of the device is a uni port or not.
1377 *
1378 * @param d the access device
1379 * @param p the port of the device
1380 * @return true if the given port is a uni port
Gamze Abakaad329652018-12-20 10:12:21 +00001381 */
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001382 private boolean isUniPort(Device d, Port p) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001383 AccessDevicePort ulPort = getUplinkPort(d);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001384 if (ulPort != null) {
1385 return (ulPort.number().toLong() != p.number().toLong());
1386 }
Thomas Lee Sd7735f92020-02-20 19:21:47 +05301387 //handles a special case where NNI port is misconfigured in SADIS and getUplinkPort(d) returns null
1388 //checks whether the port name starts with nni- which is the signature of an NNI Port
1389 if (p.annotations().value(AnnotationKeys.PORT_NAME) != null &&
1390 p.annotations().value(AnnotationKeys.PORT_NAME).startsWith(NNI)) {
1391 log.error("NNI port number {} is not matching with configured value", p.number().toLong());
1392 return false;
1393 }
1394 return true;
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001395 }
1396
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001397 /**
1398 * Gets the given device details from SADIS.
1399 * If the device is not found, returns null
1400 *
1401 * @param dev the access device
1402 * @return the olt information
1403 */
Jonathan Hart4c538002018-08-23 10:11:54 -07001404 private SubscriberAndDeviceInformation getOltInfo(Device dev) {
Ilayda Ozdemir90a93622021-02-25 09:40:58 +00001405 if (subsService == null) {
1406 log.warn(SADIS_NOT_RUNNING);
1407 return null;
1408 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001409 String devSerialNo = dev.serialNumber();
Gamze Abaka641fc072018-09-04 09:16:27 +00001410 return subsService.get(devSerialNo);
Jonathan Hart4c538002018-08-23 10:11:54 -07001411 }
1412
Andrea Campanella1edf8832021-05-06 12:51:33 +02001413 /**
1414 * Checks for mastership or falls back to leadership on deviceId.
1415 * If the device is available use mastership,
1416 * otherwise fallback on leadership.
1417 * Leadership on the device topic is needed because the master can be NONE
1418 * in case the device went away, we still need to handle events
1419 * consistently
1420 */
Andrea Campanellaaf39b4c2020-05-13 14:07:44 +02001421 private boolean isLocalLeader(DeviceId deviceId) {
Andrea Campanella1edf8832021-05-06 12:51:33 +02001422 if (deviceService.isAvailable(deviceId)) {
1423 return mastershipService.isLocalMaster(deviceId);
1424 } else {
Andrea Campanellaaf39b4c2020-05-13 14:07:44 +02001425 // Fallback with Leadership service - device id is used as topic
1426 NodeId leader = leadershipService.runForLeadership(
1427 deviceId.toString()).leaderNodeId();
1428 // Verify if this node is the leader
1429 return clusterService.getLocalNode().id().equals(leader);
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001430 }
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001431 }
1432
kdarapuaa5da252020-04-10 15:58:05 +05301433 private boolean isNniPort(Port port) {
1434 if (port.annotations().keys().contains(AnnotationKeys.PORT_NAME)) {
1435 return port.annotations().value(AnnotationKeys.PORT_NAME).contains(NNI);
1436 }
1437 return false;
1438 }
1439
Tunahan Sezena07fe962021-02-24 08:24:24 +00001440 private class InternalHostListener implements HostListener {
1441 @Override
1442 public void event(HostEvent event) {
1443 hostEventExecutor.execute(() -> {
1444 Host host = event.subject();
1445 switch (event.type()) {
1446 case HOST_ADDED:
1447 ConnectPoint cp = new ConnectPoint(host.location().deviceId(), host.location().port());
1448 Optional<SubscriberFlowInfo> optSubFlowInfo =
1449 getAndRemoveWaitingMacSubFlowInfoForCTag(cp, host.vlan());
1450 if (optSubFlowInfo.isPresent()) {
1451 log.debug("Continuing provisioning for waiting mac service. event: {}", event);
1452 continueProvisioningSubs(optSubFlowInfo.get(), Optional.of(host.mac()));
1453 } else {
1454 log.debug("There is no waiting mac sub. event: {}", event);
1455 }
1456 break;
1457 case HOST_UPDATED:
1458 if (event.prevSubject() != null && !event.prevSubject().mac().equals(event.subject().mac())) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001459 log.debug("Subscriber's MAC address changed from {} to {}. " +
1460 "devId/portNumber: {}/{} vlan: {}", event.prevSubject().mac(),
1461 event.subject().mac(), host.location().deviceId(), host.location().port(),
1462 host.vlan());
Tunahan Sezena07fe962021-02-24 08:24:24 +00001463 // TODO handle subscriber MAC Address changed
1464 } else {
1465 log.debug("Unhandled HOST_UPDATED event: {}", event);
1466 }
1467 break;
1468 default:
1469 log.debug("Unhandled host event received. event: {}", event);
1470 }
1471 });
1472 }
1473
1474 @Override
1475 public boolean isRelevant(HostEvent event) {
1476 return isLocalLeader(event.subject().location().deviceId());
1477 }
1478 }
1479
alshabibf0e7e702015-05-30 18:22:36 -07001480 private class InternalDeviceListener implements DeviceListener {
Saurav Dasa9d5f442019-03-06 19:32:48 -08001481 private Set<DeviceId> programmedDevices = Sets.newConcurrentHashSet();
1482
alshabibf0e7e702015-05-30 18:22:36 -07001483 @Override
1484 public void event(DeviceEvent event) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001485 eventExecutor.execute(() -> {
1486 DeviceId devId = event.subject().id();
1487 Device dev = event.subject();
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001488 Port p = event.port();
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001489 DeviceEvent.Type eventType = event.type();
Jonathan Hart4c538002018-08-23 10:11:54 -07001490
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001491 if (DeviceEvent.Type.PORT_STATS_UPDATED.equals(eventType) ||
1492 DeviceEvent.Type.DEVICE_SUSPENDED.equals(eventType) ||
1493 DeviceEvent.Type.DEVICE_UPDATED.equals(eventType)) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001494 return;
1495 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001496
Andrea Campanellaaf39b4c2020-05-13 14:07:44 +02001497 boolean isLocalLeader = isLocalLeader(devId);
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001498 // Only handle the event if the device belongs to us
Andrea Campanellaaf39b4c2020-05-13 14:07:44 +02001499 if (!isLocalLeader && event.type().equals(DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED)
1500 && !deviceService.isAvailable(devId) && deviceService.getPorts(devId).isEmpty()) {
1501 log.info("Cleaning local state for non master instance upon " +
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001502 "device disconnection {}", devId);
Andrea Campanellaaf39b4c2020-05-13 14:07:44 +02001503 // Since no mastership of the device is present upon disconnection
1504 // the method in the FlowRuleManager only empties the local copy
1505 // of the DeviceFlowTable thus this method needs to get called
1506 // on every instance, see how it's done in the InternalDeviceListener
1507 // in FlowRuleManager: no mastership check for purgeOnDisconnection
Andrea Campanella3f34c992020-07-15 10:54:10 +02001508 handleDeviceDisconnection(dev, false, false);
Andrea Campanellaaf39b4c2020-05-13 14:07:44 +02001509 return;
1510 } else if (!isLocalLeader) {
Andrea Campanella506df202020-05-21 10:26:12 +02001511 log.debug("Not handling event because instance is not leader for {}", devId);
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001512 return;
1513 }
1514
Matteo Scandolo19b56f62020-10-29 13:29:21 -07001515 log.debug("OLT got {} event for {}/{}", eventType, event.subject(), event.port());
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001516
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001517 if (getOltInfo(dev) == null) {
Saurav Dasa9d5f442019-03-06 19:32:48 -08001518 // it's possible that we got an event for a previously
1519 // programmed OLT that is no longer available in SADIS
1520 // we let such events go through
1521 if (!programmedDevices.contains(devId)) {
1522 log.warn("No device info found for {}, this is either "
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001523 + "not an OLT or not known to sadis", dev);
Saurav Dasa9d5f442019-03-06 19:32:48 -08001524 return;
1525 }
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001526 }
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001527 AccessDevicePort port = null;
1528 if (p != null) {
1529 if (isUniPort(dev, p)) {
1530 port = new AccessDevicePort(p, AccessDevicePort.Type.UNI);
1531 } else {
1532 port = new AccessDevicePort(p, AccessDevicePort.Type.NNI);
1533 }
1534 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001535
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001536 switch (event.type()) {
1537 //TODO: Port handling and bookkeeping should be improved once
1538 // olt firmware handles correct behaviour.
1539 case PORT_ADDED:
Andrea Campanella3f34c992020-07-15 10:54:10 +02001540 if (!deviceService.isAvailable(devId)) {
1541 log.warn("Received {} for disconnected device {}, ignoring", event, devId);
1542 return;
1543 }
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001544 if (port.type().equals(AccessDevicePort.Type.UNI)) {
1545 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, port.port()));
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001546
1547 if (port.isEnabled() && !port.number().equals(PortNumber.LOCAL)) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001548 log.info("eapol will be sent for port added {}", port);
yasin saplib4b8ee12021-06-13 18:25:20 +00001549 oltFlowService.processEapolFilteringObjectives(port, defaultBpId, Optional.empty(),
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001550 null,
Andrea Campanella3f34c992020-07-15 10:54:10 +02001551 VlanId.vlanId(EAPOL_DEFAULT_VLAN),
1552 true);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001553 }
1554 } else {
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001555 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
1556 if (deviceInfo != null) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001557 oltFlowService.processNniFilteringObjectives(port, true);
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001558 }
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001559 }
1560 break;
1561 case PORT_REMOVED:
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001562 if (port.type().equals(AccessDevicePort.Type.UNI)) {
Andrea Campanellacf0e3052020-08-27 11:05:39 +02001563 // if no subscriber is provisioned we need to remove the default EAPOL
1564 // if a subscriber was provisioned the default EAPOL will not be there and we can skip.
1565 // The EAPOL with subscriber tag will be removed by removeSubscriber call.
1566 Collection<? extends UniTagInformation> uniTagInformationSet =
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001567 programmedSubs.get(new ConnectPoint(port.deviceId(), port.number())).value();
Andrea Campanellacf0e3052020-08-27 11:05:39 +02001568 if (uniTagInformationSet == null || uniTagInformationSet.isEmpty()) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001569 log.info("No subscriber provisioned on port {} in PORT_REMOVED event, " +
1570 "removing default EAPOL flow", port);
yasin saplib4b8ee12021-06-13 18:25:20 +00001571 oltFlowService.processEapolFilteringObjectives(port, defaultBpId, Optional.empty(),
1572 null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), false);
Andrea Campanellacf0e3052020-08-27 11:05:39 +02001573 } else {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001574 removeSubscriber(port);
Andrea Campanellacf0e3052020-08-27 11:05:39 +02001575 }
Andy Bavier160e8682019-05-07 18:32:22 -07001576
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001577 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, port.port()));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001578 }
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001579 break;
1580 case PORT_UPDATED:
Andrea Campanella3f34c992020-07-15 10:54:10 +02001581 if (!deviceService.isAvailable(devId)) {
1582 log.warn("Received {} for disconnected device {}, ignoring", event, devId);
1583 return;
1584 }
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001585 if (port.type().equals(AccessDevicePort.Type.NNI)) {
Saurav Das9da7d522020-03-23 19:14:35 -07001586 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
1587 if (deviceInfo != null && port.isEnabled()) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001588 log.debug("NNI {} enabled", port);
1589 oltFlowService.processNniFilteringObjectives(port, true);
Saurav Das9da7d522020-03-23 19:14:35 -07001590 }
1591 return;
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001592 }
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001593 ConnectPoint cp = new ConnectPoint(devId, port.number());
1594 Collection<? extends UniTagInformation> uniTagInformationSet = programmedSubs.get(cp).value();
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001595 if (uniTagInformationSet == null || uniTagInformationSet.isEmpty()) {
Saurav Dasb776aef2020-03-09 14:29:46 -07001596 if (!port.number().equals(PortNumber.LOCAL)) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001597 log.info("eapol will be {} updated for {} with default vlan {}",
1598 (port.isEnabled()) ? "added" : "removed", port, EAPOL_DEFAULT_VLAN);
yasin saplib4b8ee12021-06-13 18:25:20 +00001599 oltFlowService.processEapolFilteringObjectives(port, defaultBpId, Optional.empty(),
1600 null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), port.isEnabled());
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001601 }
1602 } else {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001603 log.info("eapol will be {} updated for {}", (port.isEnabled()) ? "added" : "removed",
1604 port);
1605 for (UniTagInformation uniTag : uniTagInformationSet) {
1606 oltFlowService.processEapolFilteringObjectives(port,
yasin saplib4b8ee12021-06-13 18:25:20 +00001607 uniTag.getUpstreamBandwidthProfile(),
1608 Optional.of(uniTag.getUpstreamOltBandwidthProfile()),
1609 null, uniTag.getPonCTag(), port.isEnabled());
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001610 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001611 }
Gamze Abaka838d8142019-02-21 07:06:55 +00001612 if (port.isEnabled()) {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001613 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, port.port()));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001614 } else {
Tunahan Sezenf0843b92021-04-30 07:13:16 +00001615 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, port.port()));
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001616 }
alshabibbb83aa22016-02-10 15:08:23 -08001617 break;
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001618 case DEVICE_ADDED:
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001619 handleDeviceConnection(dev, true);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001620 break;
1621 case DEVICE_REMOVED:
Andrea Campanella3f34c992020-07-15 10:54:10 +02001622 handleDeviceDisconnection(dev, true, true);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001623 break;
1624 case DEVICE_AVAILABILITY_CHANGED:
1625 if (deviceService.isAvailable(devId)) {
Saurav Dasbd3b6712020-03-31 23:28:35 -07001626 log.info("Handling available device: {}", dev.id());
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001627 handleDeviceConnection(dev, false);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001628 } else {
Hardik Windlassa58fbee2020-03-12 18:33:55 +05301629 if (deviceService.getPorts(devId).isEmpty()) {
Saurav Dasbd3b6712020-03-31 23:28:35 -07001630 log.info("Handling controlled device disconnection .. "
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001631 + "flushing all state for dev:{}", devId);
Andrea Campanella3f34c992020-07-15 10:54:10 +02001632 handleDeviceDisconnection(dev, true, false);
Saurav Dasbd3b6712020-03-31 23:28:35 -07001633 } else {
1634 log.info("Disconnected device has available ports .. "
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001635 + "assuming temporary disconnection, "
1636 + "retaining state for device {}", devId);
Hardik Windlassa58fbee2020-03-12 18:33:55 +05301637 }
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001638 }
1639 break;
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001640 default:
Andrea Campanella3f34c992020-07-15 10:54:10 +02001641 log.debug("Not handling event {}", event);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001642 return;
1643 }
1644 });
alshabibf0e7e702015-05-30 18:22:36 -07001645 }
Gamze Abaka838d8142019-02-21 07:06:55 +00001646
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001647 private void sendUniEvent(Device device, AccessDeviceEvent.Type eventType) {
1648 deviceService.getPorts(device.id()).stream()
1649 .filter(p -> !PortNumber.LOCAL.equals(p.number()))
1650 .filter(p -> isUniPort(device, p))
1651 .forEach(p -> post(new AccessDeviceEvent(eventType, device.id(), p)));
1652 }
1653
Andrea Campanella3f34c992020-07-15 10:54:10 +02001654 private void handleDeviceDisconnection(Device device, boolean sendDisconnectedEvent, boolean sendUniEvent) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001655 programmedDevices.remove(device.id());
1656 removeAllSubscribers(device.id());
Tunahan Sezena07fe962021-02-24 08:24:24 +00001657 removeWaitingMacSubs(device.id());
Andrea Campanella600d2e22020-06-22 11:00:31 +02001658 //Handle case where OLT disconnects during subscriber provisioning
Andrea Campanella7a1d7e72020-11-05 10:40:10 +01001659 pendingSubscribersForDevice.remove(device.id());
Andrea Campanella600d2e22020-06-22 11:00:31 +02001660 oltFlowService.clearDeviceState(device.id());
1661
1662 //Complete meter and flow purge
Hardik Windlassa58fbee2020-03-12 18:33:55 +05301663 flowRuleService.purgeFlowRules(device.id());
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001664 oltMeterService.clearMeters(device.id());
Andrea Campanella3f34c992020-07-15 10:54:10 +02001665 if (sendDisconnectedEvent) {
1666 post(new AccessDeviceEvent(
1667 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, device.id(),
1668 null, null, null));
1669 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001670 if (sendUniEvent) {
1671 sendUniEvent(device, AccessDeviceEvent.Type.UNI_REMOVED);
Gamze Abaka838d8142019-02-21 07:06:55 +00001672 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001673 }
1674
1675 private void handleDeviceConnection(Device dev, boolean sendUniEvent) {
1676 post(new AccessDeviceEvent(
1677 AccessDeviceEvent.Type.DEVICE_CONNECTED, dev.id(),
1678 null, null, null));
1679 programmedDevices.add(dev.id());
1680 checkAndCreateDeviceFlows(dev);
1681 if (sendUniEvent) {
1682 sendUniEvent(dev, AccessDeviceEvent.Type.UNI_ADDED);
1683 }
Gamze Abaka838d8142019-02-21 07:06:55 +00001684 }
Gamze Abakada282b42019-03-11 13:16:48 +00001685
1686 private void removeAllSubscribers(DeviceId deviceId) {
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001687 List<Map.Entry<ConnectPoint, UniTagInformation>> subs = programmedSubs.stream()
1688 .filter(e -> e.getKey().deviceId().equals(deviceId))
1689 .collect(toList());
Gamze Abakada282b42019-03-11 13:16:48 +00001690
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001691 subs.forEach(e -> programmedSubs.remove(e.getKey(), e.getValue()));
Gamze Abakada282b42019-03-11 13:16:48 +00001692 }
Gamze Abaka641fc072018-09-04 09:16:27 +00001693
Tunahan Sezena07fe962021-02-24 08:24:24 +00001694 private void removeWaitingMacSubs(DeviceId deviceId) {
1695 List<ConnectPoint> waitingMacKeys = waitingMacSubscribers.stream()
1696 .filter(cp -> cp.getKey().deviceId().equals(deviceId))
1697 .map(Map.Entry::getKey)
1698 .collect(toList());
1699 waitingMacKeys.forEach(cp -> waitingMacSubscribers.removeAll(cp));
1700 }
1701
Gamze Abaka641fc072018-09-04 09:16:27 +00001702 }
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001703
1704 private class InternalClusterListener implements ClusterEventListener {
1705
1706 @Override
1707 public void event(ClusterEvent event) {
1708 if (event.type() == ClusterEvent.Type.INSTANCE_READY) {
1709 hasher.addServer(event.subject().id());
1710 }
1711 if (event.type() == ClusterEvent.Type.INSTANCE_DEACTIVATED) {
1712 hasher.removeServer(event.subject().id());
1713 }
1714 }
1715 }
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001716
Hardik Windlass395ff372019-06-13 05:16:00 +00001717}