blob: f822ae36773bea194585fd71015d0b270eb37349 [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;
Hardik Windlassa58fbee2020-03-12 18:33:55 +053044import org.onosproject.net.flow.FlowRuleService;
alshabibf0e7e702015-05-30 18:22:36 -070045import org.onosproject.net.flowobjective.FlowObjectiveService;
46import org.onosproject.net.flowobjective.ForwardingObjective;
alshabib3ea82642016-01-12 18:06:53 -080047import org.onosproject.net.flowobjective.Objective;
48import org.onosproject.net.flowobjective.ObjectiveContext;
49import org.onosproject.net.flowobjective.ObjectiveError;
Tunahan Sezena07fe962021-02-24 08:24:24 +000050import org.onosproject.net.host.HostEvent;
51import org.onosproject.net.host.HostListener;
52import org.onosproject.net.host.HostService;
Saurav Daseae48de2019-06-19 13:26:15 -070053import org.onosproject.net.meter.MeterId;
Jonathan Hart4f178fa2020-02-03 10:46:01 -080054import org.onosproject.store.serializers.KryoNamespaces;
55import org.onosproject.store.service.ConsistentMultimap;
56import org.onosproject.store.service.Serializer;
57import org.onosproject.store.service.StorageService;
alshabib36a4d732016-06-01 16:03:59 -070058import org.opencord.olt.AccessDeviceEvent;
59import org.opencord.olt.AccessDeviceListener;
60import org.opencord.olt.AccessDeviceService;
Amit Ghosh31939522018-08-16 13:28:21 +010061import org.opencord.olt.AccessSubscriberId;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000062import org.opencord.olt.internalapi.AccessDeviceFlowService;
63import org.opencord.olt.internalapi.AccessDeviceMeterService;
Gamze Abaka641fc072018-09-04 09:16:27 +000064import org.opencord.sadis.BandwidthProfileInformation;
65import org.opencord.sadis.BaseInformationService;
66import org.opencord.sadis.SadisService;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010067import org.opencord.sadis.SubscriberAndDeviceInformation;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000068import org.opencord.sadis.UniTagInformation;
alshabibe0559672016-02-21 14:49:51 -080069import org.osgi.service.component.ComponentContext;
Carmelo Casconeca931162019-07-15 18:22:24 -070070import org.osgi.service.component.annotations.Activate;
71import org.osgi.service.component.annotations.Component;
72import org.osgi.service.component.annotations.Deactivate;
73import org.osgi.service.component.annotations.Modified;
74import org.osgi.service.component.annotations.Reference;
75import org.osgi.service.component.annotations.ReferenceCardinality;
Ilayda Ozdemir90a93622021-02-25 09:40:58 +000076import org.osgi.service.component.annotations.ReferencePolicy;
alshabibf0e7e702015-05-30 18:22:36 -070077import org.slf4j.Logger;
78
Andrea Campanella7a1d7e72020-11-05 10:40:10 +010079import java.util.ArrayList;
80import java.util.Collection;
81import java.util.Dictionary;
82import java.util.List;
83import java.util.Map;
84import java.util.Optional;
85import java.util.Properties;
86import java.util.Set;
87import java.util.concurrent.BlockingQueue;
88import java.util.concurrent.CompletableFuture;
Andrea Campanella7a1d7e72020-11-05 10:40:10 +010089import java.util.concurrent.ExecutorService;
90import java.util.concurrent.Executors;
91import java.util.concurrent.LinkedBlockingQueue;
92import java.util.concurrent.ScheduledExecutorService;
93import java.util.concurrent.TimeUnit;
94import java.util.concurrent.atomic.AtomicBoolean;
95
96import static com.google.common.base.Preconditions.checkNotNull;
97import static com.google.common.base.Strings.isNullOrEmpty;
98import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
99import static java.util.stream.Collectors.*;
100import static org.onlab.util.Tools.get;
101import static org.onlab.util.Tools.groupedThreads;
102import static org.opencord.olt.impl.OsgiPropertyConstants.*;
103import static org.slf4j.LoggerFactory.getLogger;
alshabibf0e7e702015-05-30 18:22:36 -0700104
105/**
Jonathan Harte533a422015-10-20 17:31:24 -0700106 * Provisions rules on access devices.
alshabibf0e7e702015-05-30 18:22:36 -0700107 */
Carmelo Casconeca931162019-07-15 18:22:24 -0700108@Component(immediate = true,
109 property = {
Carmelo Casconeca931162019-07-15 18:22:24 -0700110 DEFAULT_BP_ID + ":String=" + DEFAULT_BP_ID_DEFAULT,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000111 DEFAULT_MCAST_SERVICE_NAME + ":String=" + DEFAULT_MCAST_SERVICE_NAME_DEFAULT,
Saurav Das2d3777a2020-08-07 18:48:51 -0700112 EAPOL_DELETE_RETRY_MAX_ATTEMPS + ":Integer=" +
113 EAPOL_DELETE_RETRY_MAX_ATTEMPS_DEFAULT,
Matteo Scandoloa4aaa972020-10-23 15:24:38 -0700114 PROVISION_DELAY + ":Integer=" + PROVISION_DELAY_DEFAULT,
Carmelo Casconeca931162019-07-15 18:22:24 -0700115 })
alshabib8e4fd2f2016-01-12 15:55:53 -0800116public class Olt
117 extends AbstractListenerManager<AccessDeviceEvent, AccessDeviceListener>
118 implements AccessDeviceService {
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000119 private static final String SADIS_NOT_RUNNING = "Sadis is not running.";
Charles Chan54f110f2017-01-20 11:22:42 -0800120 private static final String APP_NAME = "org.opencord.olt";
alshabibe0559672016-02-21 14:49:51 -0800121
Gamze Abakada282b42019-03-11 13:16:48 +0000122 private static final short EAPOL_DEFAULT_VLAN = 4091;
Gamze Abaka838d8142019-02-21 07:06:55 +0000123 private static final String NO_UPLINK_PORT = "No uplink port found for OLT device {}";
alshabibe0559672016-02-21 14:49:51 -0800124
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800125 public static final int HASH_WEIGHT = 10;
126
alshabibf0e7e702015-05-30 18:22:36 -0700127 private final Logger log = getLogger(getClass());
128
Thomas Lee Sd7735f92020-02-20 19:21:47 +0530129 private static final String NNI = "nni-";
130
Carmelo Casconeca931162019-07-15 18:22:24 -0700131 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabibf0e7e702015-05-30 18:22:36 -0700132 protected FlowObjectiveService flowObjectiveService;
133
Carmelo Casconeca931162019-07-15 18:22:24 -0700134 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabibf0e7e702015-05-30 18:22:36 -0700135 protected DeviceService deviceService;
136
Carmelo Casconeca931162019-07-15 18:22:24 -0700137 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabibf0e7e702015-05-30 18:22:36 -0700138 protected CoreService coreService;
139
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000140 @Reference(cardinality = ReferenceCardinality.OPTIONAL,
141 bind = "bindSadisService",
142 unbind = "unbindSadisService",
143 policy = ReferencePolicy.DYNAMIC)
144 protected volatile SadisService sadisService;
Gamze Abaka641fc072018-09-04 09:16:27 +0000145
Carmelo Casconeca931162019-07-15 18:22:24 -0700146 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000147 protected AccessDeviceFlowService oltFlowService;
alshabibe0559672016-02-21 14:49:51 -0800148
Carmelo Casconeca931162019-07-15 18:22:24 -0700149 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000150 protected AccessDeviceMeterService oltMeterService;
Gamze Abakaad329652018-12-20 10:12:21 +0000151
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800152 @Reference(cardinality = ReferenceCardinality.MANDATORY)
153 protected StorageService storageService;
154
155 @Reference(cardinality = ReferenceCardinality.MANDATORY)
156 protected ClusterService clusterService;
157
Hardik Windlassa58fbee2020-03-12 18:33:55 +0530158 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andrea Campanellaaf39b4c2020-05-13 14:07:44 +0200159 protected MastershipService mastershipService;
160
161 @Reference(cardinality = ReferenceCardinality.MANDATORY)
162 protected LeadershipService leadershipService;
163
164 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hardik Windlassa58fbee2020-03-12 18:33:55 +0530165 protected FlowRuleService flowRuleService;
166
Gamze Abaka1f62dd92020-05-07 08:58:13 +0000167 @Reference(cardinality = ReferenceCardinality.MANDATORY)
168 protected ComponentConfigService componentConfigService;
169
Tunahan Sezena07fe962021-02-24 08:24:24 +0000170 @Reference(cardinality = ReferenceCardinality.MANDATORY)
171 protected HostService hostService;
172
Carmelo Casconeca931162019-07-15 18:22:24 -0700173 /**
Carmelo Cascone95ff5122019-11-14 14:19:13 -0800174 * Default bandwidth profile id that is used for authentication trap flows.
Carmelo Casconeca931162019-07-15 18:22:24 -0700175 **/
176 protected String defaultBpId = DEFAULT_BP_ID_DEFAULT;
Gamze Abakaad329652018-12-20 10:12:21 +0000177
Carmelo Casconeca931162019-07-15 18:22:24 -0700178 /**
Gamze Abaka51a34e82020-05-08 13:03:14 +0000179 * Default multicast service name.
Carmelo Casconeca931162019-07-15 18:22:24 -0700180 **/
Gamze Abaka51a34e82020-05-08 13:03:14 +0000181 protected String multicastServiceName = DEFAULT_MCAST_SERVICE_NAME_DEFAULT;
Gamze Abaka33feef52019-02-27 08:16:47 +0000182
Saurav Das2d3777a2020-08-07 18:48:51 -0700183 /**
184 * Default amounts of eapol retry.
185 **/
186 protected int eapolDeleteRetryMaxAttempts = EAPOL_DELETE_RETRY_MAX_ATTEMPS_DEFAULT;
187
Matteo Scandoloa4aaa972020-10-23 15:24:38 -0700188 /**
189 * Delay between EAPOL removal and data plane flows provisioning.
190 */
191 protected int provisionDelay = PROVISION_DELAY_DEFAULT;
192
alshabibf0e7e702015-05-30 18:22:36 -0700193 private final DeviceListener deviceListener = new InternalDeviceListener();
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800194 private final ClusterEventListener clusterListener = new InternalClusterListener();
Tunahan Sezena07fe962021-02-24 08:24:24 +0000195 private final HostListener hostListener = new InternalHostListener();
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800196
197 private ConsistentHasher hasher;
alshabibf0e7e702015-05-30 18:22:36 -0700198
Gamze Abaka641fc072018-09-04 09:16:27 +0000199 protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
200 private BaseInformationService<BandwidthProfileInformation> bpService;
alshabibf0e7e702015-05-30 18:22:36 -0700201
Gamze Abaka641fc072018-09-04 09:16:27 +0000202 private ExecutorService oltInstallers = Executors.newFixedThreadPool(4,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000203 groupedThreads("onos/olt-service",
204 "olt-installer-%d"));
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100205
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700206 protected ExecutorService eventExecutor;
Tunahan Sezena07fe962021-02-24 08:24:24 +0000207 protected ExecutorService hostEventExecutor;
Saurav Das2d3777a2020-08-07 18:48:51 -0700208 protected ExecutorService retryExecutor;
Matteo Scandoloa4aaa972020-10-23 15:24:38 -0700209 protected ScheduledExecutorService provisionExecutor;
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700210
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800211 private ConsistentMultimap<ConnectPoint, UniTagInformation> programmedSubs;
Saurav Das2d3777a2020-08-07 18:48:51 -0700212 private ConsistentMultimap<ConnectPoint, UniTagInformation> failedSubs;
Saurav Dasa9d5f442019-03-06 19:32:48 -0800213
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000214 protected Map<DeviceId, BlockingQueue<SubscriberFlowInfo>> pendingSubscribersForDevice;
Tunahan Sezena07fe962021-02-24 08:24:24 +0000215 private ConsistentMultimap<ConnectPoint, SubscriberFlowInfo> waitingMacSubscribers;
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700216
alshabibf0e7e702015-05-30 18:22:36 -0700217 @Activate
alshabibe0559672016-02-21 14:49:51 -0800218 public void activate(ComponentContext context) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000219 eventExecutor = newSingleThreadScheduledExecutor(groupedThreads("onos/olt",
220 "events-%d", log));
Tunahan Sezena07fe962021-02-24 08:24:24 +0000221 hostEventExecutor = Executors.newFixedThreadPool(8, groupedThreads("onos/olt", "mac-events-%d", log));
Saurav Das2d3777a2020-08-07 18:48:51 -0700222 retryExecutor = Executors.newCachedThreadPool();
Matteo Scandoloa4aaa972020-10-23 15:24:38 -0700223 provisionExecutor = Executors.newSingleThreadScheduledExecutor(groupedThreads("onos/olt",
224 "provision-%d", log));
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700225
alshabibe0559672016-02-21 14:49:51 -0800226 modified(context);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000227 ApplicationId appId = coreService.registerApplication(APP_NAME);
Gamze Abaka1f62dd92020-05-07 08:58:13 +0000228 componentConfigService.registerProperties(getClass());
Saurav Das62ad75e2019-03-05 12:22:22 -0800229
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800230 KryoNamespace serializer = KryoNamespace.newBuilder()
231 .register(KryoNamespaces.API)
232 .register(UniTagInformation.class)
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000233 .register(SubscriberFlowInfo.class)
234 .register(LinkedBlockingQueue.class)
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800235 .build();
236
237 programmedSubs = storageService.<ConnectPoint, UniTagInformation>consistentMultimapBuilder()
238 .withName("volt-programmed-subs")
239 .withSerializer(Serializer.using(serializer))
240 .withApplicationId(appId)
241 .build();
alshabibc4dfe852015-06-05 13:35:13 -0700242
Saurav Das2d3777a2020-08-07 18:48:51 -0700243 failedSubs = storageService.<ConnectPoint, UniTagInformation>consistentMultimapBuilder()
244 .withName("volt-failed-subs")
245 .withSerializer(Serializer.using(serializer))
246 .withApplicationId(appId)
247 .build();
248
Tunahan Sezena07fe962021-02-24 08:24:24 +0000249 KryoNamespace macSerializer = KryoNamespace.newBuilder()
250 .register(KryoNamespaces.API)
251 .register(SubscriberFlowInfo.class)
252 .register(UniTagInformation.class)
253 .build();
254
255 waitingMacSubscribers = storageService.<ConnectPoint, SubscriberFlowInfo>consistentMultimapBuilder()
256 .withName("volt-waiting-mac-subs")
257 .withSerializer(Serializer.using(macSerializer))
258 .withApplicationId(appId)
259 .build();
260
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000261 pendingSubscribersForDevice = storageService.<DeviceId, BlockingQueue<SubscriberFlowInfo>>consistentMapBuilder()
262 .withName("volt-pending-subs")
263 .withSerializer(Serializer.using(serializer))
264 .withApplicationId(appId)
265 .build().asJavaMap();
alshabib8e4fd2f2016-01-12 15:55:53 -0800266 eventDispatcher.addSink(AccessDeviceEvent.class, listenerRegistry);
267
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000268 if (sadisService != null) {
269 subsService = sadisService.getSubscriberInfoService();
270 bpService = sadisService.getBandwidthProfileService();
271 } else {
272 log.warn(SADIS_NOT_RUNNING);
273 }
Gamze Abaka641fc072018-09-04 09:16:27 +0000274
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800275 List<NodeId> readyNodes = clusterService.getNodes().stream()
276 .filter(c -> clusterService.getState(c.id()) == ControllerNode.State.READY)
277 .map(ControllerNode::id)
278 .collect(toList());
279 hasher = new ConsistentHasher(readyNodes, HASH_WEIGHT);
280 clusterService.addListener(clusterListener);
281
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100282 // look for all provisioned devices in Sadis and create EAPOL flows for the
283 // UNI ports
284 Iterable<Device> devices = deviceService.getDevices();
285 for (Device d : devices) {
Andrea Campanellaaf39b4c2020-05-13 14:07:44 +0200286 if (isLocalLeader(d.id())) {
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800287 checkAndCreateDeviceFlows(d);
288 }
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100289 }
alshabib4ceaed32016-03-03 18:00:58 -0800290
alshabibba357492016-01-27 13:49:46 -0800291 deviceService.addListener(deviceListener);
Tunahan Sezena07fe962021-02-24 08:24:24 +0000292 hostService.addListener(hostListener);
alshabibf0e7e702015-05-30 18:22:36 -0700293 log.info("Started with Application ID {}", appId.id());
294 }
295
296 @Deactivate
297 public void deactivate() {
Gamze Abaka1f62dd92020-05-07 08:58:13 +0000298 componentConfigService.unregisterProperties(getClass(), false);
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800299 clusterService.removeListener(clusterListener);
alshabib62e9ce72016-02-11 17:31:36 -0800300 deviceService.removeListener(deviceListener);
Tunahan Sezena07fe962021-02-24 08:24:24 +0000301 hostService.removeListener(hostListener);
Jonathan Hart5f1c8142018-07-24 17:31:59 -0700302 eventDispatcher.removeSink(AccessDeviceEvent.class);
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700303 eventExecutor.shutdown();
Tunahan Sezena07fe962021-02-24 08:24:24 +0000304 hostEventExecutor.shutdown();
Saurav Das2d3777a2020-08-07 18:48:51 -0700305 retryExecutor.shutdown();
Matteo Scandoloa4aaa972020-10-23 15:24:38 -0700306 provisionExecutor.shutdown();
alshabibf0e7e702015-05-30 18:22:36 -0700307 log.info("Stopped");
308 }
309
alshabibe0559672016-02-21 14:49:51 -0800310 @Modified
311 public void modified(ComponentContext context) {
312 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
313
314 try {
Andrea Campanella971d5b92020-05-07 11:20:43 +0200315 String bpId = get(properties, DEFAULT_BP_ID);
316 defaultBpId = isNullOrEmpty(bpId) ? defaultBpId : bpId;
Gamze Abakaad329652018-12-20 10:12:21 +0000317
Andrea Campanella971d5b92020-05-07 11:20:43 +0200318 String mcastSN = get(properties, DEFAULT_MCAST_SERVICE_NAME);
319 multicastServiceName = isNullOrEmpty(mcastSN) ? multicastServiceName : mcastSN;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000320
Saurav Das2d3777a2020-08-07 18:48:51 -0700321 String eapolDeleteRetryNew = get(properties, EAPOL_DELETE_RETRY_MAX_ATTEMPS);
322 eapolDeleteRetryMaxAttempts = isNullOrEmpty(eapolDeleteRetryNew) ? EAPOL_DELETE_RETRY_MAX_ATTEMPS_DEFAULT :
323 Integer.parseInt(eapolDeleteRetryNew.trim());
324
325 log.debug("OLT properties: DefaultBpId: {}, MulticastServiceName: {}, EapolDeleteRetryMaxAttempts: {}",
326 defaultBpId, multicastServiceName, eapolDeleteRetryMaxAttempts);
Gamze Abaka33feef52019-02-27 08:16:47 +0000327
alshabibe0559672016-02-21 14:49:51 -0800328 } catch (Exception e) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000329 log.error("Error while modifying the properties", e);
Andrea Campanella971d5b92020-05-07 11:20:43 +0200330 defaultBpId = DEFAULT_BP_ID_DEFAULT;
331 multicastServiceName = DEFAULT_MCAST_SERVICE_NAME_DEFAULT;
alshabibe0559672016-02-21 14:49:51 -0800332 }
333 }
334
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000335 protected void bindSadisService(SadisService service) {
336 sadisService = service;
337 bpService = sadisService.getBandwidthProfileService();
338 subsService = sadisService.getSubscriberInfoService();
339 log.info("Sadis-service binds to onos.");
340 }
341
342 protected void unbindSadisService(SadisService service) {
343 sadisService = null;
344 bpService = null;
345 subsService = null;
346 log.info("Sadis-service unbinds from onos.");
347 }
348
alshabib32232c82016-02-25 17:57:24 -0500349 @Override
Gamze Abaka838d8142019-02-21 07:06:55 +0000350 public boolean provisionSubscriber(ConnectPoint connectPoint) {
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200351 log.info("Call to provision subscriber at {}", connectPoint);
Gamze Abaka838d8142019-02-21 07:06:55 +0000352 DeviceId deviceId = connectPoint.deviceId();
353 PortNumber subscriberPortNo = connectPoint.port();
Gamze Abaka838d8142019-02-21 07:06:55 +0000354 checkNotNull(deviceService.getPort(deviceId, subscriberPortNo),
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000355 "Invalid connect point:" + connectPoint);
Hardik Windlass395ff372019-06-13 05:16:00 +0000356
Saurav Das026650f2020-09-21 18:56:35 -0700357 if (isSubscriberInstalled(connectPoint)) {
358 log.warn("Subscriber at {} already provisioned or in the process .."
359 + " not taking any more action", connectPoint);
360 return true;
361 }
362
363 // Find the subscriber config at this connect point
Gamze Abaka838d8142019-02-21 07:06:55 +0000364 SubscriberAndDeviceInformation sub = getSubscriber(connectPoint);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100365 if (sub == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000366 log.warn("No subscriber found for {}", connectPoint);
Amit Ghosh31939522018-08-16 13:28:21 +0100367 return false;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100368 }
Jonathan Harte533a422015-10-20 17:31:24 -0700369
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100370 // Get the uplink port
Gamze Abaka838d8142019-02-21 07:06:55 +0000371 Port uplinkPort = getUplinkPort(deviceService.getDevice(deviceId));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100372 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000373 log.warn(NO_UPLINK_PORT, deviceId);
Amit Ghosh31939522018-08-16 13:28:21 +0100374 return false;
Jonathan Harte533a422015-10-20 17:31:24 -0700375 }
376
Saurav Das2d3777a2020-08-07 18:48:51 -0700377 // delete Eapol authentication flow with default bandwidth
378 // wait until Eapol rule with defaultBpId is removed to install subscriber-based rules
379 // retry deletion if it fails/times-out
380 retryExecutor.execute(new DeleteEapolInstallSub(connectPoint,
381 uplinkPort, sub, 1));
Amit Ghosh31939522018-08-16 13:28:21 +0100382 return true;
alshabibb7a9e172016-01-13 11:23:53 -0800383 }
384
Saurav Das026650f2020-09-21 18:56:35 -0700385 // returns true if subscriber is programmed or in the process of being programmed
386 private boolean isSubscriberInstalled(ConnectPoint connectPoint) {
387 Collection<? extends UniTagInformation> uniTagInformationSet =
388 programmedSubs.get(connectPoint).value();
389 if (!uniTagInformationSet.isEmpty()) {
390 return true;
391 }
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100392 //Check if the subscriber is already getting provisioned
393 // so we do not provision twice
394 AtomicBoolean isPending = new AtomicBoolean(false);
395 pendingSubscribersForDevice.computeIfPresent(connectPoint.deviceId(), (id, infos) -> {
396 for (SubscriberFlowInfo fi : infos) {
397 if (fi.getUniPort().equals(connectPoint.port())) {
398 isPending.set(true);
399 break;
400 }
Saurav Das026650f2020-09-21 18:56:35 -0700401 }
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100402 return infos;
403 });
Saurav Das026650f2020-09-21 18:56:35 -0700404
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100405 return isPending.get();
Saurav Das026650f2020-09-21 18:56:35 -0700406 }
407
Saurav Das2d3777a2020-08-07 18:48:51 -0700408 private class DeleteEapolInstallSub implements Runnable {
409 ConnectPoint cp;
410 Port uplinkPort;
411 SubscriberAndDeviceInformation sub;
412 private int attemptNumber;
413
414 DeleteEapolInstallSub(ConnectPoint cp, Port uplinkPort,
415 SubscriberAndDeviceInformation sub,
416 int attemptNumber) {
417 this.cp = cp;
418 this.uplinkPort = uplinkPort;
419 this.sub = sub;
420 this.attemptNumber = attemptNumber;
421 }
422
423 @Override
424 public void run() {
Tunahan Sezena07fe962021-02-24 08:24:24 +0000425 CompletableFuture<ObjectiveError> filterFuture = new CompletableFuture<>();
Saurav Das2d3777a2020-08-07 18:48:51 -0700426 oltFlowService.processEapolFilteringObjectives(cp.deviceId(), cp.port(),
427 defaultBpId, filterFuture,
428 VlanId.vlanId(EAPOL_DEFAULT_VLAN),
429 false);
430 filterFuture.thenAcceptAsync(filterStatus -> {
431 if (filterStatus == null) {
432 log.info("Default eapol flow deleted in attempt {} of {}"
433 + "... provisioning subscriber flows {}",
434 attemptNumber, eapolDeleteRetryMaxAttempts, cp);
Matteo Scandoloa4aaa972020-10-23 15:24:38 -0700435
436 // FIXME this is needed to prevent that default EAPOL flow removal and
437 // data plane flows install are received by the device at the same time
438 provisionExecutor.schedule(
439 () -> provisionUniTagList(cp, uplinkPort.number(), sub),
440 provisionDelay, TimeUnit.MILLISECONDS);
Saurav Das2d3777a2020-08-07 18:48:51 -0700441 } else {
442 if (attemptNumber <= eapolDeleteRetryMaxAttempts) {
443 log.warn("The filtering future failed {} for subscriber {}"
444 + "... retrying {} of {} attempts",
445 filterStatus, cp, attemptNumber, eapolDeleteRetryMaxAttempts);
446 retryExecutor.execute(
447 new DeleteEapolInstallSub(cp, uplinkPort, sub,
448 attemptNumber + 1));
449 } else {
450 log.error("The filtering future failed {} for subscriber {}"
451 + "after {} attempts. Subscriber provisioning failed",
452 filterStatus, cp, eapolDeleteRetryMaxAttempts);
453 sub.uniTagList().forEach(ut -> failedSubs.put(cp, ut));
454 }
455 }
456 });
457 }
458
459 }
460
alshabibb7a9e172016-01-13 11:23:53 -0800461 @Override
Gamze Abaka838d8142019-02-21 07:06:55 +0000462 public boolean removeSubscriber(ConnectPoint connectPoint) {
Saurav Daseae48de2019-06-19 13:26:15 -0700463 log.info("Call to un-provision subscriber at {}", connectPoint);
Gamze Abaka838d8142019-02-21 07:06:55 +0000464
Saurav Daseae48de2019-06-19 13:26:15 -0700465 // Get the subscriber connected to this port from the local cache
466 // If we don't know about the subscriber there's no need to remove it
Gamze Abaka838d8142019-02-21 07:06:55 +0000467 DeviceId deviceId = connectPoint.deviceId();
468 PortNumber subscriberPortNo = connectPoint.port();
469
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800470 Collection<? extends UniTagInformation> uniTagInformationSet = programmedSubs.get(connectPoint).value();
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000471 if (uniTagInformationSet == null || uniTagInformationSet.isEmpty()) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000472 log.warn("Subscriber on connectionPoint {} was not previously programmed, " +
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000473 "no need to remove it", connectPoint);
Matteo Scandolo962a6ad2018-12-11 15:39:42 -0800474 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800475 }
476
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100477 // Get the uplink port
Gamze Abaka838d8142019-02-21 07:06:55 +0000478 Port uplinkPort = getUplinkPort(deviceService.getDevice(deviceId));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100479 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000480 log.warn(NO_UPLINK_PORT, deviceId);
Amit Ghosh31939522018-08-16 13:28:21 +0100481 return false;
alshabib4ceaed32016-03-03 18:00:58 -0800482 }
483
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000484 for (UniTagInformation uniTag : uniTagInformationSet) {
Amit Ghosh95e2f652017-08-23 12:49:46 +0100485
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000486 if (multicastServiceName.equals(uniTag.getServiceName())) {
487 continue;
488 }
Gamze Abaka838d8142019-02-21 07:06:55 +0000489
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000490 unprovisionVlans(deviceId, uplinkPort.number(), subscriberPortNo, uniTag);
alshabibbf23a1f2016-01-14 17:27:11 -0800491
Saurav Das9da7d522020-03-23 19:14:35 -0700492 // remove eapol with subscriber bandwidth profile
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000493 oltFlowService.processEapolFilteringObjectives(deviceId, subscriberPortNo,
494 uniTag.getUpstreamBandwidthProfile(),
495 null, uniTag.getPonCTag(), false);
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100496
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000497 Port port = deviceService.getPort(deviceId, subscriberPortNo);
498 if (port != null && port.isEnabled()) {
Saurav Das9da7d522020-03-23 19:14:35 -0700499 // reinstall eapol with default bandwidth profile
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000500 oltFlowService.processEapolFilteringObjectives(deviceId, subscriberPortNo, defaultBpId,
501 null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
502 } else {
503 log.debug("Port {} is no longer enabled or it's unavailable. Not "
504 + "reprogramming default eapol flow", connectPoint);
505 }
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100506 }
Amit Ghosh31939522018-08-16 13:28:21 +0100507 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800508 }
509
Gamze Abakaf59c0912019-04-19 08:24:28 +0000510
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000511 @Override
512 public boolean provisionSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag,
513 Optional<VlanId> cTag, Optional<Integer> tpId) {
514
515 log.info("Provisioning subscriber using subscriberId {}, sTag {}, cTag {}, tpId {}" +
516 "", subscriberId, sTag, cTag, tpId);
Gamze Abakaf59c0912019-04-19 08:24:28 +0000517
Amit Ghosh31939522018-08-16 13:28:21 +0100518 // Check if we can find the connect point to which this subscriber is connected
519 ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
520 if (subsPort == null) {
521 log.warn("ConnectPoint for {} not found", subscriberId);
522 return false;
523 }
524
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100525 if (!sTag.isPresent() && !cTag.isPresent()) {
526 return provisionSubscriber(subsPort);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000527 } else if (sTag.isPresent() && cTag.isPresent() && tpId.isPresent()) {
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100528 Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
529 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000530 log.warn(NO_UPLINK_PORT, subsPort.deviceId());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100531 return false;
532 }
533
Gamze Abakaf59c0912019-04-19 08:24:28 +0000534 //delete Eapol authentication flow with default bandwidth
535 //wait until Eapol rule with defaultBpId is removed to install subscriber-based rules
Gamze Abakaf59c0912019-04-19 08:24:28 +0000536 //install subscriber flows
Tunahan Sezena07fe962021-02-24 08:24:24 +0000537 CompletableFuture<ObjectiveError> filterFuture = new CompletableFuture<>();
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000538 oltFlowService.processEapolFilteringObjectives(subsPort.deviceId(), subsPort.port(), defaultBpId,
539 filterFuture, VlanId.vlanId(EAPOL_DEFAULT_VLAN), false);
Gamze Abakaf59c0912019-04-19 08:24:28 +0000540 filterFuture.thenAcceptAsync(filterStatus -> {
541 if (filterStatus == null) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000542 provisionUniTagInformation(subsPort.deviceId(), uplinkPort.number(), subsPort.port(),
543 cTag.get(), sTag.get(), tpId.get());
Gamze Abakaf59c0912019-04-19 08:24:28 +0000544 }
545 });
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100546 return true;
547 } else {
548 log.warn("Provisioning failed for subscriber: {}", subscriberId);
549 return false;
550 }
Amit Ghosh31939522018-08-16 13:28:21 +0100551 }
Amit Ghosh95e2f652017-08-23 12:49:46 +0100552
alshabibe0559672016-02-21 14:49:51 -0800553 @Override
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000554 public boolean removeSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag,
555 Optional<VlanId> cTag, Optional<Integer> tpId) {
Amit Ghosh31939522018-08-16 13:28:21 +0100556 // Check if we can find the connect point to which this subscriber is connected
557 ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
558 if (subsPort == null) {
559 log.warn("ConnectPoint for {} not found", subscriberId);
560 return false;
561 }
562
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100563 if (!sTag.isPresent() && !cTag.isPresent()) {
564 return removeSubscriber(subsPort);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000565 } else if (sTag.isPresent() && cTag.isPresent() && tpId.isPresent()) {
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100566 // Get the uplink port
567 Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
568 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000569 log.warn(NO_UPLINK_PORT, subsPort.deviceId());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100570 return false;
571 }
572
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000573 Optional<UniTagInformation> tagInfo = getUniTagInformation(subsPort, cTag.get(), sTag.get(), tpId.get());
574 if (!tagInfo.isPresent()) {
575 log.warn("UniTagInformation does not exist for Device/Port {}, cTag {}, sTag {}, tpId {}",
576 subsPort, cTag, sTag, tpId);
577 return false;
578 }
Gamze Abakaf59c0912019-04-19 08:24:28 +0000579
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000580 unprovisionVlans(subsPort.deviceId(), uplinkPort.number(), subsPort.port(), tagInfo.get());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100581 return true;
582 } else {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000583 log.warn("Removing subscriber is not possible - please check the provided information" +
584 "for the subscriber: {}", subscriberId);
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100585 return false;
586 }
Amit Ghosh31939522018-08-16 13:28:21 +0100587 }
588
589 @Override
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000590 public ImmutableMap<ConnectPoint, Set<UniTagInformation>> getProgSubs() {
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800591 return programmedSubs.stream()
592 .collect(collectingAndThen(
593 groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, toSet())),
594 ImmutableMap::copyOf));
Saurav Das82b8e6d2018-10-04 15:25:12 -0700595 }
596
597 @Override
Saurav Das2d3777a2020-08-07 18:48:51 -0700598 public ImmutableMap<ConnectPoint, Set<UniTagInformation>> getFailedSubs() {
599 return failedSubs.stream()
600 .collect(collectingAndThen(
601 groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, toSet())),
602 ImmutableMap::copyOf));
603 }
604
605 @Override
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100606 public List<DeviceId> fetchOlts() {
607 // look through all the devices and find the ones that are OLTs as per Sadis
608 List<DeviceId> olts = new ArrayList<>();
609 Iterable<Device> devices = deviceService.getDevices();
610 for (Device d : devices) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700611 if (getOltInfo(d) != null) {
612 // So this is indeed an OLT device
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100613 olts.add(d.id());
614 }
615 }
616 return olts;
alshabibe0559672016-02-21 14:49:51 -0800617 }
618
Amit Ghosh31939522018-08-16 13:28:21 +0100619 /**
620 * Finds the connect point to which a subscriber is connected.
621 *
622 * @param id The id of the subscriber, this is the same ID as in Sadis
623 * @return Subscribers ConnectPoint if found else null
624 */
625 private ConnectPoint findSubscriberConnectPoint(String id) {
626
627 Iterable<Device> devices = deviceService.getDevices();
628 for (Device d : devices) {
629 for (Port p : deviceService.getPorts(d.id())) {
630 log.trace("Comparing {} with {}", p.annotations().value(AnnotationKeys.PORT_NAME), id);
631 if (p.annotations().value(AnnotationKeys.PORT_NAME).equals(id)) {
632 log.debug("Found on device {} port {}", d.id(), p.number());
633 return new ConnectPoint(d.id(), p.number());
634 }
635 }
636 }
637 return null;
638 }
639
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000640 /**
641 * Gets the context of the bandwidth profile information for the given parameter.
642 *
643 * @param bandwidthProfile the bandwidth profile id
644 * @return the context of the bandwidth profile information
645 */
Gamze Abaka641fc072018-09-04 09:16:27 +0000646 private BandwidthProfileInformation getBandwidthProfileInformation(String bandwidthProfile) {
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000647 if (bpService == null) {
648 log.warn(SADIS_NOT_RUNNING);
649 return null;
650 }
Gamze Abaka641fc072018-09-04 09:16:27 +0000651 if (bandwidthProfile == null) {
652 return null;
653 }
654 return bpService.get(bandwidthProfile);
655 }
656
Gamze Abaka838d8142019-02-21 07:06:55 +0000657 /**
Gamze Abaka33feef52019-02-27 08:16:47 +0000658 * Removes subscriber vlan flows.
Gamze Abaka838d8142019-02-21 07:06:55 +0000659 *
660 * @param deviceId the device identifier
661 * @param uplink uplink port of the OLT
662 * @param subscriberPort uni port
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000663 * @param uniTag uni tag information
Gamze Abaka838d8142019-02-21 07:06:55 +0000664 */
Gamze Abaka33feef52019-02-27 08:16:47 +0000665 private void unprovisionVlans(DeviceId deviceId, PortNumber uplink,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000666 PortNumber subscriberPort, UniTagInformation uniTag) {
667
668 log.info("Unprovisioning vlans for {} at {}/{}", uniTag, deviceId, subscriberPort);
alshabibbf23a1f2016-01-14 17:27:11 -0800669
Tunahan Sezena07fe962021-02-24 08:24:24 +0000670 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture<>();
671 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture<>();
alshabibbf23a1f2016-01-14 17:27:11 -0800672
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000673 VlanId deviceVlan = uniTag.getPonSTag();
674 VlanId subscriberVlan = uniTag.getPonCTag();
Gamze Abaka641fc072018-09-04 09:16:27 +0000675
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000676 MeterId upstreamMeterId = oltMeterService
677 .getMeterIdFromBpMapping(deviceId, uniTag.getUpstreamBandwidthProfile());
678 MeterId downstreamMeterId = oltMeterService
679 .getMeterIdFromBpMapping(deviceId, uniTag.getDownstreamBandwidthProfile());
Gamze Abaka641fc072018-09-04 09:16:27 +0000680
Tunahan Sezena07fe962021-02-24 08:24:24 +0000681 Optional<SubscriberFlowInfo> waitingMacSubFlowInfo =
682 getAndRemoveWaitingMacSubFlowInfoForCTag(new ConnectPoint(deviceId, subscriberPort), subscriberVlan);
683 if (waitingMacSubFlowInfo.isPresent()) {
684 // only dhcp objectives applied previously, so only dhcp uninstallation objective will be processed
685 log.debug("Waiting MAC service removed and dhcp uninstallation objective will be processed. " +
686 "waitingMacSubFlowInfo:{}", waitingMacSubFlowInfo.get());
687 CompletableFuture<ObjectiveError> dhcpFuture = new CompletableFuture<>();
688 oltFlowService.processDhcpFilteringObjectives(deviceId, subscriberPort,
689 upstreamMeterId, uniTag, false, true, Optional.of(dhcpFuture));
690 dhcpFuture.thenAcceptAsync(dhcpStatus -> {
691 AccessDeviceEvent.Type type;
692 if (dhcpStatus == null) {
693 type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_UNREGISTERED;
694 log.debug("Dhcp uninstallation objective was processed successfully for cTag {}, sTag {}, " +
695 "tpId {} and Device/Port:{}", uniTag.getPonCTag(), uniTag.getPonSTag(),
696 uniTag.getTechnologyProfileId(), subscriberPort);
697 updateProgrammedSubscriber(new ConnectPoint(deviceId, subscriberPort), uniTag, false);
698 } else {
699 type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_UNREGISTRATION_FAILED;
700 log.error("Dhcp uninstallation objective was failed for cTag {}, sTag {}, " +
701 "tpId {} and Device/Port:{} :{}", uniTag.getPonCTag(), uniTag.getPonSTag(),
702 uniTag.getTechnologyProfileId(), subscriberPort, dhcpStatus);
703 }
704 post(new AccessDeviceEvent(type, deviceId, deviceService.getPort(deviceId, subscriberPort),
705 deviceVlan, subscriberVlan, uniTag.getTechnologyProfileId()));
706 });
707 return;
708 } else {
709 log.debug("There is no waiting MAC service for dev/port: {}/{} and subscriberVlan: {}",
710 deviceId, subscriberPort, subscriberVlan);
711 }
712
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000713 ForwardingObjective.Builder upFwd =
714 oltFlowService.createUpBuilder(uplink, subscriberPort, upstreamMeterId, uniTag);
Tunahan Sezena07fe962021-02-24 08:24:24 +0000715
716 Optional<MacAddress> macAddress = getMacAddress(deviceId, subscriberPort, uniTag);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000717 ForwardingObjective.Builder downFwd =
Tunahan Sezena07fe962021-02-24 08:24:24 +0000718 oltFlowService.createDownBuilder(uplink, subscriberPort, downstreamMeterId, uniTag, macAddress);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000719
Andrea Campanella7c49b792020-05-11 11:36:53 +0200720 oltFlowService.processIgmpFilteringObjectives(deviceId, subscriberPort,
721 upstreamMeterId, uniTag, false, true);
722 oltFlowService.processDhcpFilteringObjectives(deviceId, subscriberPort,
Tunahan Sezena07fe962021-02-24 08:24:24 +0000723 upstreamMeterId, uniTag, false, true, Optional.empty());
Gustavo Silva5c492dd2021-02-12 10:21:11 -0300724 oltFlowService.processPPPoEDFilteringObjectives(deviceId, subscriberPort,
725 upstreamMeterId, uniTag, false, true);
alshabibbf23a1f2016-01-14 17:27:11 -0800726
alshabib4ceaed32016-03-03 18:00:58 -0800727 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
728 @Override
729 public void onSuccess(Objective objective) {
730 upFuture.complete(null);
731 }
alshabibbf23a1f2016-01-14 17:27:11 -0800732
alshabib4ceaed32016-03-03 18:00:58 -0800733 @Override
734 public void onError(Objective objective, ObjectiveError error) {
735 upFuture.complete(error);
736 }
737 }));
738
739 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
740 @Override
741 public void onSuccess(Objective objective) {
742 downFuture.complete(null);
743 }
744
745 @Override
746 public void onError(Objective objective, ObjectiveError error) {
747 downFuture.complete(error);
748 }
749 }));
alshabibbf23a1f2016-01-14 17:27:11 -0800750
751 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000752 AccessDeviceEvent.Type type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_UNREGISTERED;
alshabibbf23a1f2016-01-14 17:27:11 -0800753 if (upStatus == null && downStatus == null) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000754 log.debug("Uni tag information is unregistered successfully for cTag {}, sTag {}, tpId {}, and" +
755 "Device/Port{}", uniTag.getPonCTag(), uniTag.getPonSTag(),
756 uniTag.getTechnologyProfileId(), subscriberPort);
757 updateProgrammedSubscriber(new ConnectPoint(deviceId, subscriberPort), uniTag, false);
alshabibbf23a1f2016-01-14 17:27:11 -0800758 } else if (downStatus != null) {
759 log.error("Subscriber with vlan {} on device {} " +
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000760 "on port {} failed downstream uninstallation: {}",
761 subscriberVlan, deviceId, subscriberPort, downStatus);
762 type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_UNREGISTRATION_FAILED;
alshabibbf23a1f2016-01-14 17:27:11 -0800763 } else if (upStatus != null) {
764 log.error("Subscriber with vlan {} on device {} " +
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000765 "on port {} failed upstream uninstallation: {}",
766 subscriberVlan, deviceId, subscriberPort, upStatus);
767 type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_UNREGISTRATION_FAILED;
alshabibbf23a1f2016-01-14 17:27:11 -0800768 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000769 Port port = deviceService.getPort(deviceId, subscriberPort);
770 post(new AccessDeviceEvent(type, deviceId, port, deviceVlan, subscriberVlan,
771 uniTag.getTechnologyProfileId()));
alshabibbf23a1f2016-01-14 17:27:11 -0800772 }, oltInstallers);
Jonathan Harte533a422015-10-20 17:31:24 -0700773 }
774
Tunahan Sezena07fe962021-02-24 08:24:24 +0000775 private Optional<SubscriberFlowInfo> getAndRemoveWaitingMacSubFlowInfoForCTag(ConnectPoint cp, VlanId cTag) {
776 SubscriberFlowInfo returnSubFlowInfo = null;
777 Collection<? extends SubscriberFlowInfo> subFlowInfoSet = waitingMacSubscribers.get(cp).value();
778 for (SubscriberFlowInfo subFlowInfo : subFlowInfoSet) {
779 if (subFlowInfo.getTagInfo().getPonCTag().equals(cTag)) {
780 returnSubFlowInfo = subFlowInfo;
781 break;
782 }
783 }
784 if (returnSubFlowInfo != null) {
785 waitingMacSubscribers.remove(cp, returnSubFlowInfo);
786 return Optional.of(returnSubFlowInfo);
787 }
788 return Optional.empty();
789 }
790
Gamze Abaka838d8142019-02-21 07:06:55 +0000791 /**
Gamze Abaka33feef52019-02-27 08:16:47 +0000792 * Adds subscriber vlan flows, dhcp, eapol and igmp trap flows for the related uni port.
Gamze Abaka838d8142019-02-21 07:06:55 +0000793 *
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000794 * @param connectPoint the connection point of the subscriber
795 * @param uplinkPort uplink port of the OLT (the nni port)
796 * @param sub subscriber information that includes s, c tags, tech profile and bandwidth profile references
Gamze Abaka838d8142019-02-21 07:06:55 +0000797 */
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000798 private void provisionUniTagList(ConnectPoint connectPoint, PortNumber uplinkPort,
799 SubscriberAndDeviceInformation sub) {
Gamze Abaka641fc072018-09-04 09:16:27 +0000800
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700801 log.debug("Provisioning vlans for subscriber on dev/port: {}", connectPoint.toString());
802 if (log.isTraceEnabled()) {
803 log.trace("Subscriber informations {}", sub);
804 }
Gamze Abaka641fc072018-09-04 09:16:27 +0000805
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000806 if (sub.uniTagList() == null || sub.uniTagList().isEmpty()) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700807 log.warn("Unitaglist doesn't exist for the subscriber {} on dev/port {}",
808 sub.id(), connectPoint.toString());
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000809 return;
810 }
Gamze Abaka641fc072018-09-04 09:16:27 +0000811
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000812 DeviceId deviceId = connectPoint.deviceId();
813 PortNumber subscriberPort = connectPoint.port();
Gamze Abaka641fc072018-09-04 09:16:27 +0000814
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000815 for (UniTagInformation uniTag : sub.uniTagList()) {
816 handleSubscriberFlows(deviceId, uplinkPort, subscriberPort, uniTag);
817 }
818 }
alshabib3ea82642016-01-12 18:06:53 -0800819
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000820 /**
821 * Finds the uni tag information and provisions the found information.
822 * If the uni tag information is not found, returns
823 *
824 * @param deviceId the access device id
825 * @param uplinkPort the nni port
826 * @param subscriberPort the uni port
827 * @param innerVlan the pon c tag
828 * @param outerVlan the pon s tag
829 * @param tpId the technology profile id
830 */
831 private void provisionUniTagInformation(DeviceId deviceId, PortNumber uplinkPort,
832 PortNumber subscriberPort,
833 VlanId innerVlan,
834 VlanId outerVlan,
835 Integer tpId) {
Jonathan Harte533a422015-10-20 17:31:24 -0700836
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000837 ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
838 Optional<UniTagInformation> gotTagInformation = getUniTagInformation(cp, innerVlan, outerVlan, tpId);
839 if (!gotTagInformation.isPresent()) {
840 return;
841 }
842 UniTagInformation tagInformation = gotTagInformation.get();
843 handleSubscriberFlows(deviceId, uplinkPort, subscriberPort, tagInformation);
844 }
alshabib3ea82642016-01-12 18:06:53 -0800845
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000846 private void updateProgrammedSubscriber(ConnectPoint connectPoint, UniTagInformation tagInformation, Boolean add) {
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800847 if (add) {
848 programmedSubs.put(connectPoint, tagInformation);
849 } else {
850 programmedSubs.remove(connectPoint, tagInformation);
851 }
Jonathan Harte533a422015-10-20 17:31:24 -0700852 }
853
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000854 /**
855 * Installs a uni tag information flow.
856 *
857 * @param deviceId the access device id
858 * @param uplinkPort the nni port
859 * @param subscriberPort the uni port
860 * @param tagInfo the uni tag information
861 */
862 private void handleSubscriberFlows(DeviceId deviceId, PortNumber uplinkPort, PortNumber subscriberPort,
863 UniTagInformation tagInfo) {
864
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700865 log.debug("Provisioning vlan-based flows for the uniTagInformation {} on dev/port {}/{}",
866 tagInfo, deviceId, subscriberPort);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000867
868 Port port = deviceService.getPort(deviceId, subscriberPort);
869
870 if (multicastServiceName.equals(tagInfo.getServiceName())) {
871 // IGMP flows are taken care of along with VOD service
872 // Please note that for each service, Subscriber Registered event will be sent
873 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_REGISTERED,
874 deviceId, port, tagInfo.getPonSTag(), tagInfo.getPonCTag(),
875 tagInfo.getTechnologyProfileId()));
876 return;
Gamze Abaka641fc072018-09-04 09:16:27 +0000877 }
878
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000879 BandwidthProfileInformation upstreamBpInfo =
880 getBandwidthProfileInformation(tagInfo.getUpstreamBandwidthProfile());
881 BandwidthProfileInformation downstreamBpInfo =
882 getBandwidthProfileInformation(tagInfo.getDownstreamBandwidthProfile());
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700883 if (upstreamBpInfo == null) {
884 log.warn("No meter installed since no Upstream BW Profile definition found for "
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700885 + "ctag {} stag {} tpId {} and dev/port: {}/{}",
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700886 tagInfo.getPonCTag(), tagInfo.getPonSTag(),
887 tagInfo.getTechnologyProfileId(), deviceId,
888 subscriberPort);
889 return;
890 }
891 if (downstreamBpInfo == null) {
892 log.warn("No meter installed since no Downstream BW Profile definition found for "
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700893 + "ctag {} stag {} tpId {} and dev/port: {}/{}",
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700894 tagInfo.getPonCTag(), tagInfo.getPonSTag(),
895 tagInfo.getTechnologyProfileId(), deviceId,
896 subscriberPort);
897 return;
898 }
Gamze Abakaf59c0912019-04-19 08:24:28 +0000899
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700900 // check for meterIds for the upstream and downstream bandwidth profiles
901 MeterId upMeterId = oltMeterService
902 .getMeterIdFromBpMapping(deviceId, upstreamBpInfo.id());
903 MeterId downMeterId = oltMeterService
904 .getMeterIdFromBpMapping(deviceId, downstreamBpInfo.id());
905 SubscriberFlowInfo fi = new SubscriberFlowInfo(deviceId, uplinkPort, subscriberPort,
906 tagInfo, downMeterId, upMeterId,
907 downstreamBpInfo.id(), upstreamBpInfo.id());
908
909 if (upMeterId != null && downMeterId != null) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700910 log.debug("Meters are existing for upstream {} and downstream {} on dev/port {}/{}",
911 upstreamBpInfo.id(), downstreamBpInfo.id(), deviceId, subscriberPort);
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700912 handleSubFlowsWithMeters(fi);
913 } else {
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700914 log.debug("Adding {} on {}/{} to pending subs", fi, deviceId, subscriberPort);
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700915 // one or both meters are not ready. It's possible they are in the process of being
916 // created for other subscribers that share the same bandwidth profile.
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100917 pendingSubscribersForDevice.compute(deviceId, (id, queue) -> {
918 if (queue == null) {
919 queue = new LinkedBlockingQueue<>();
920 }
921 queue.add(fi);
922 log.info("Added {} to pending subscribers on {}/{}", fi, deviceId, subscriberPort);
923 return queue;
924 });
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700925
926 // queue up the meters to be created
927 if (upMeterId == null) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700928 log.debug("Missing meter for upstream {} on {}/{}", upstreamBpInfo.id(), deviceId, subscriberPort);
Andrea Campanella600d2e22020-06-22 11:00:31 +0200929 checkAndCreateDevMeter(deviceId, upstreamBpInfo);
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700930 }
931 if (downMeterId == null) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700932 log.debug("Missing meter for downstream {} on {}/{}", downstreamBpInfo.id(), deviceId, subscriberPort);
Andrea Campanella600d2e22020-06-22 11:00:31 +0200933 checkAndCreateDevMeter(deviceId, downstreamBpInfo);
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700934 }
935 }
936 }
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000937
Andrea Campanella600d2e22020-06-22 11:00:31 +0200938 private void checkAndCreateDevMeter(DeviceId deviceId, BandwidthProfileInformation bwpInfo) {
Andrea Campanellad1e26642020-10-23 12:08:32 +0200939 //If false the meter is already being installed, skipping installation
940 if (!oltMeterService.checkAndAddPendingMeter(deviceId, bwpInfo)) {
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700941 return;
942 }
Andrea Campanella600d2e22020-06-22 11:00:31 +0200943 createMeter(deviceId, bwpInfo);
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700944 }
945
Andrea Campanella600d2e22020-06-22 11:00:31 +0200946 private void createMeter(DeviceId deviceId, BandwidthProfileInformation bwpInfo) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -0700947 log.debug("Creating Meter with {} on {}", bwpInfo, deviceId);
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700948 CompletableFuture<Object> meterFuture = new CompletableFuture<>();
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200949
Andrea Campanella600d2e22020-06-22 11:00:31 +0200950 MeterId meterId = oltMeterService.createMeter(deviceId, bwpInfo,
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700951 meterFuture);
952
953 meterFuture.thenAcceptAsync(result -> {
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100954 BlockingQueue<SubscriberFlowInfo> queue = pendingSubscribersForDevice.get(deviceId);
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700955 // iterate through the subscribers on hold
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100956 if (queue != null) {
957 while (true) {
958 //TODO this might return the reference and not the actual object so
959 // it can be actually swapped underneath us.
960 SubscriberFlowInfo fi = queue.peek();
961 if (fi == null) {
962 log.debug("No more subscribers pending on {}", deviceId);
Ilayda Ozdemir90a93622021-02-25 09:40:58 +0000963 pendingSubscribersForDevice.replace(deviceId, queue);
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100964 break;
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700965 }
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100966 if (result == null) {
967 // meter install sent to device
968 log.debug("Meter {} installed for bw {} on {}", meterId, bwpInfo, deviceId);
969
970 MeterId upMeterId = oltMeterService
971 .getMeterIdFromBpMapping(deviceId, fi.getUpBpInfo());
972 MeterId downMeterId = oltMeterService
973 .getMeterIdFromBpMapping(deviceId, fi.getDownBpInfo());
974 if (upMeterId != null && downMeterId != null) {
975 log.debug("Provisioning subscriber after meter {} " +
976 "installation and both meters are present " +
977 "upstream {} and downstream {} on {}/{}",
978 meterId, upMeterId, downMeterId, deviceId, fi.getUniPort());
979 // put in the meterIds because when fi was first
980 // created there may or may not have been a meterId
981 // depending on whether the meter was created or
982 // not at that time.
983 fi.setUpMeterId(upMeterId);
984 fi.setDownMeterId(downMeterId);
985 handleSubFlowsWithMeters(fi);
986 queue.remove(fi);
987 }
988 oltMeterService.removeFromPendingMeters(deviceId, bwpInfo);
989 } else {
990 // meter install failed
991 log.error("Addition of subscriber {} on {}/{} failed due to meter " +
992 "{} with result {}", fi, deviceId, fi.getUniPort(),
993 meterId, result);
994 queue.remove(fi);
995 oltMeterService.removeFromPendingMeters(deviceId, bwpInfo);
996 }
Andrea Campanella0c3309d2020-05-29 01:51:18 -0700997 }
Andrea Campanella7a1d7e72020-11-05 10:40:10 +0100998 } else {
999 log.info("No pending subscribers on {}", deviceId);
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001000 }
1001 });
Andrea Campanella7a1d7e72020-11-05 10:40:10 +01001002
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001003 }
Ilayda Ozdemir90a93622021-02-25 09:40:58 +00001004
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001005 /**
1006 * Add subscriber flows given meter information for both upstream and
1007 * downstream directions.
1008 *
1009 * @param subscriberFlowInfo relevant information for subscriber
1010 */
1011 private void handleSubFlowsWithMeters(SubscriberFlowInfo subscriberFlowInfo) {
Tunahan Sezena07fe962021-02-24 08:24:24 +00001012 log.debug("Provisioning subscriber flows based on {}", subscriberFlowInfo);
1013 UniTagInformation tagInfo = subscriberFlowInfo.getTagInfo();
1014 if (tagInfo.getIsDhcpRequired()) {
1015 Optional<MacAddress> macAddress =
1016 getMacAddress(subscriberFlowInfo.getDevId(), subscriberFlowInfo.getUniPort(), tagInfo);
1017 if (subscriberFlowInfo.getTagInfo().getEnableMacLearning()) {
1018 ConnectPoint cp = new ConnectPoint(subscriberFlowInfo.getDevId(), subscriberFlowInfo.getUniPort());
1019 if (macAddress.isPresent()) {
1020 log.debug("MAC Address {} obtained for {}", macAddress.get(), subscriberFlowInfo);
1021 } else {
1022 waitingMacSubscribers.put(cp, subscriberFlowInfo);
1023 log.debug("Adding sub to waiting mac map: {}", subscriberFlowInfo);
1024 }
1025
1026 CompletableFuture<ObjectiveError> dhcpFuture = new CompletableFuture<>();
1027 oltFlowService.processDhcpFilteringObjectives(subscriberFlowInfo.getDevId(),
1028 subscriberFlowInfo.getUniPort(), subscriberFlowInfo.getUpId(),
1029 tagInfo, true, true, Optional.of(dhcpFuture));
1030 dhcpFuture.thenAcceptAsync(dhcpStatus -> {
1031 if (dhcpStatus != null) {
1032 log.error("Dhcp Objective failed for {}: {}", subscriberFlowInfo, dhcpStatus);
1033 if (macAddress.isEmpty()) {
1034 waitingMacSubscribers.remove(cp, subscriberFlowInfo);
1035 }
1036 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_REGISTRATION_FAILED,
1037 subscriberFlowInfo.getDevId(),
1038 deviceService.getPort(subscriberFlowInfo.getDevId(), subscriberFlowInfo.getUniPort()),
1039 tagInfo.getPonSTag(), tagInfo.getPonCTag(), tagInfo.getTechnologyProfileId()));
1040 } else {
1041 log.debug("Dhcp Objective success for: {}", subscriberFlowInfo);
1042 if (macAddress.isPresent()) {
1043 continueProvisioningSubs(subscriberFlowInfo, macAddress);
1044 }
1045 }
1046 });
1047 } else {
1048 log.debug("Dynamic MAC Learning disabled, so will not learn for: {}", subscriberFlowInfo);
1049 // dhcp flows will handle after data plane flows
1050 continueProvisioningSubs(subscriberFlowInfo, macAddress);
1051 }
1052 } else {
1053 // dhcp not required for this service
1054 continueProvisioningSubs(subscriberFlowInfo, Optional.empty());
1055 }
1056 }
1057
1058 private void continueProvisioningSubs(SubscriberFlowInfo subscriberFlowInfo, Optional<MacAddress> macAddress) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -07001059 log.debug("Provisioning subscriber flows on {}/{} based on {}",
1060 subscriberFlowInfo.getDevId(), subscriberFlowInfo.getUniPort(), subscriberFlowInfo);
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001061 UniTagInformation tagInfo = subscriberFlowInfo.getTagInfo();
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001062 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture<>();
1063 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture<>();
Gamze Abakaf59c0912019-04-19 08:24:28 +00001064
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001065 ForwardingObjective.Builder upFwd =
1066 oltFlowService.createUpBuilder(subscriberFlowInfo.getNniPort(), subscriberFlowInfo.getUniPort(),
1067 subscriberFlowInfo.getUpId(), subscriberFlowInfo.getTagInfo());
1068 flowObjectiveService.forward(subscriberFlowInfo.getDevId(), upFwd.add(new ObjectiveContext() {
1069 @Override
1070 public void onSuccess(Objective objective) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -07001071 log.debug("Upstream HSIA flow {} installed successfully on {}/{}",
1072 subscriberFlowInfo, subscriberFlowInfo.getDevId(), subscriberFlowInfo.getUniPort());
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001073 upFuture.complete(null);
Gamze Abakaf59c0912019-04-19 08:24:28 +00001074 }
Gamze Abakaf59c0912019-04-19 08:24:28 +00001075
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001076 @Override
1077 public void onError(Objective objective, ObjectiveError error) {
1078 upFuture.complete(error);
Gamze Abakaf59c0912019-04-19 08:24:28 +00001079 }
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001080 }));
1081
1082 ForwardingObjective.Builder downFwd =
1083 oltFlowService.createDownBuilder(subscriberFlowInfo.getNniPort(), subscriberFlowInfo.getUniPort(),
Tunahan Sezena07fe962021-02-24 08:24:24 +00001084 subscriberFlowInfo.getDownId(), subscriberFlowInfo.getTagInfo(), macAddress);
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001085 flowObjectiveService.forward(subscriberFlowInfo.getDevId(), downFwd.add(new ObjectiveContext() {
1086 @Override
1087 public void onSuccess(Objective objective) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -07001088 log.debug("Downstream HSIA flow {} installed successfully on {}/{}",
1089 subscriberFlowInfo, subscriberFlowInfo.getDevId(), subscriberFlowInfo.getUniPort());
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001090 downFuture.complete(null);
1091 }
1092
1093 @Override
1094 public void onError(Objective objective, ObjectiveError error) {
1095 downFuture.complete(error);
1096 }
1097 }));
Gamze Abakaf59c0912019-04-19 08:24:28 +00001098
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001099 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001100 AccessDeviceEvent.Type type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_REGISTERED;
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001101 if (downStatus != null) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -07001102 log.error("Flow with innervlan {} and outerVlan {} on {}/{} failed downstream installation: {}",
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001103 tagInfo.getPonCTag(), tagInfo.getPonSTag(), subscriberFlowInfo.getDevId(),
1104 subscriberFlowInfo.getUniPort(), downStatus);
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001105 type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_REGISTRATION_FAILED;
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001106 } else if (upStatus != null) {
Tunahan Sezena07fe962021-02-24 08:24:24 +00001107 log.error("Flow with innervlan {} and outerVlan {} on {}/{} failed upstream installation: {}",
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001108 tagInfo.getPonCTag(), tagInfo.getPonSTag(), subscriberFlowInfo.getDevId(),
1109 subscriberFlowInfo.getUniPort(), upStatus);
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001110 type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_REGISTRATION_FAILED;
Gamze Abakaf59c0912019-04-19 08:24:28 +00001111 } else {
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001112 log.debug("Upstream and downstream data plane flows are installed successfully " +
Matteo Scandolo19b56f62020-10-29 13:29:21 -07001113 "for {}/{}", subscriberFlowInfo.getDevId(), subscriberFlowInfo.getUniPort());
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001114 oltFlowService.processEapolFilteringObjectives(subscriberFlowInfo.getDevId(),
1115 subscriberFlowInfo.getUniPort(),
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001116 tagInfo.getUpstreamBandwidthProfile(),
1117 null, tagInfo.getPonCTag(), true);
Tunahan Sezena07fe962021-02-24 08:24:24 +00001118
1119
1120 if (!tagInfo.getEnableMacLearning()) {
1121 oltFlowService.processDhcpFilteringObjectives(subscriberFlowInfo.getDevId(),
1122 subscriberFlowInfo.getUniPort(),
1123 subscriberFlowInfo.getUpId(),
1124 tagInfo, true, true, Optional.empty());
1125 }
Gamze Abakaf59c0912019-04-19 08:24:28 +00001126
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001127 oltFlowService.processIgmpFilteringObjectives(subscriberFlowInfo.getDevId(),
1128 subscriberFlowInfo.getUniPort(),
1129 subscriberFlowInfo.getUpId(),
1130 tagInfo, true, true);
Gustavo Silva5c492dd2021-02-12 10:21:11 -03001131
1132 oltFlowService.processPPPoEDFilteringObjectives(subscriberFlowInfo.getDevId(),
1133 subscriberFlowInfo.getUniPort(),
1134 subscriberFlowInfo.getUpId(),
1135 tagInfo, true, true);
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001136 updateProgrammedSubscriber(new ConnectPoint(subscriberFlowInfo.getDevId(),
1137 subscriberFlowInfo.getUniPort()),
1138 tagInfo, true);
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001139 }
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001140 post(new AccessDeviceEvent(type, subscriberFlowInfo.getDevId(),
1141 deviceService.getPort(subscriberFlowInfo.getDevId(),
1142 subscriberFlowInfo.getUniPort()),
1143 tagInfo.getPonSTag(), tagInfo.getPonCTag(),
1144 tagInfo.getTechnologyProfileId()));
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001145 }, oltInstallers);
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001146 }
1147
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001148 /**
Tunahan Sezena07fe962021-02-24 08:24:24 +00001149 * Gets mac address from tag info if present, else checks the host service.
1150 *
1151 * @param deviceId device ID
1152 * @param portNumber uni port
1153 * @param tagInformation tag info
1154 * @return MAC Address of subscriber
1155 */
1156 private Optional<MacAddress> getMacAddress(DeviceId deviceId, PortNumber portNumber,
1157 UniTagInformation tagInformation) {
1158 if (isMacAddressValid(tagInformation)) {
1159 log.debug("Got MAC Address {} from the uniTagInformation for dev/port {}/{} and cTag {}",
1160 tagInformation.getConfiguredMacAddress(), deviceId, portNumber, tagInformation.getPonCTag());
1161 return Optional.of(MacAddress.valueOf(tagInformation.getConfiguredMacAddress()));
1162 } else if (tagInformation.getEnableMacLearning()) {
1163 Optional<Host> optHost = hostService.getConnectedHosts(new ConnectPoint(deviceId, portNumber))
1164 .stream().filter(host -> host.vlan().equals(tagInformation.getPonCTag())).findFirst();
1165 if (optHost.isPresent()) {
1166 log.debug("Got MAC Address {} from the hostService for dev/port {}/{} and cTag {}",
1167 optHost.get().mac(), deviceId, portNumber, tagInformation.getPonCTag());
1168 return Optional.of(optHost.get().mac());
1169 }
1170 }
1171 log.debug("Could not obtain MAC Address for dev/port {}/{} and cTag {}", deviceId, portNumber,
1172 tagInformation.getPonCTag());
1173 return Optional.empty();
1174 }
1175
1176 private boolean isMacAddressValid(UniTagInformation tagInformation) {
1177 return tagInformation.getConfiguredMacAddress() != null &&
1178 !tagInformation.getConfiguredMacAddress().trim().equals("") &&
1179 !MacAddress.NONE.equals(MacAddress.valueOf(tagInformation.getConfiguredMacAddress()));
1180 }
1181
1182 /**
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001183 * Checks the subscriber uni tag list and find the uni tag information.
1184 * using the pon c tag, pon s tag and the technology profile id
1185 * May return Optional<null>
1186 *
1187 * @param cp the connection point of the subscriber
1188 * @param innerVlan pon c tag
1189 * @param outerVlan pon s tag
1190 * @param tpId the technology profile id
1191 * @return the found uni tag information
1192 */
1193 private Optional<UniTagInformation> getUniTagInformation(ConnectPoint cp, VlanId innerVlan, VlanId outerVlan,
1194 int tpId) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -07001195 log.debug("Getting uni tag information for cp: {}, innerVlan: {}, outerVlan: {}, tpId: {}",
1196 cp.toString(), innerVlan, outerVlan, tpId);
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001197 SubscriberAndDeviceInformation subInfo = getSubscriber(cp);
Gamze Abakaf59c0912019-04-19 08:24:28 +00001198 if (subInfo == null) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -07001199 log.warn("Subscriber information doesn't exist for the connect point {}", cp.toString());
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001200 return Optional.empty();
Gamze Abakaf59c0912019-04-19 08:24:28 +00001201 }
1202
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001203 List<UniTagInformation> uniTagList = subInfo.uniTagList();
1204 if (uniTagList == null) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -07001205 log.warn("Uni tag list is not found for the subscriber {} on {}", subInfo.id(), cp.toString());
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001206 return Optional.empty();
1207 }
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001208
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001209 UniTagInformation service = null;
1210 for (UniTagInformation tagInfo : subInfo.uniTagList()) {
1211 if (innerVlan.equals(tagInfo.getPonCTag()) && outerVlan.equals(tagInfo.getPonSTag())
1212 && tpId == tagInfo.getTechnologyProfileId()) {
1213 service = tagInfo;
1214 break;
Andy Bavier160e8682019-05-07 18:32:22 -07001215 }
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001216 }
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001217
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001218 if (service == null) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -07001219 log.warn("SADIS doesn't include the service with ponCtag {} ponStag {} and tpId {} on {}",
1220 innerVlan, outerVlan, tpId, cp.toString());
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001221 return Optional.empty();
Gamze Abaka33feef52019-02-27 08:16:47 +00001222 }
1223
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001224 return Optional.of(service);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001225 }
1226
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001227 /**
Jonathan Hart403372d2018-08-22 11:44:13 -07001228 * Creates trap flows for device, including DHCP and LLDP trap on NNI and
1229 * EAPOL trap on the UNIs, if device is present in Sadis config.
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001230 *
1231 * @param dev Device to look for
1232 */
Jonathan Hart403372d2018-08-22 11:44:13 -07001233 private void checkAndCreateDeviceFlows(Device dev) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001234 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +00001235 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001236 log.info("checkAndCreateDeviceFlows: deviceInfo {}", deviceInfo);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001237
1238 if (deviceInfo != null) {
Jonathan Hart403372d2018-08-22 11:44:13 -07001239 // This is an OLT device as per Sadis, we create flows for UNI and NNI ports
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001240 for (Port p : deviceService.getPorts(dev.id())) {
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001241 if (PortNumber.LOCAL.equals(p.number()) || !p.isEnabled()) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001242 continue;
1243 }
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001244 if (isUniPort(dev, p)) {
Andrea Campanellaa2491782020-03-13 18:09:31 +01001245 if (!programmedSubs.containsKey(new ConnectPoint(dev.id(), p.number()))) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -07001246 log.info("Creating Eapol on {}/{}", dev.id(), p.number());
Andrea Campanellaa2491782020-03-13 18:09:31 +01001247 oltFlowService.processEapolFilteringObjectives(dev.id(), p.number(), defaultBpId, null,
1248 VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
1249 } else {
Matteo Scandolo19b56f62020-10-29 13:29:21 -07001250 log.debug("Subscriber Eapol on {}/{} is already provisioned, not installing default",
1251 dev.id(), p.number());
Andrea Campanellaa2491782020-03-13 18:09:31 +01001252 }
Jonathan Hart403372d2018-08-22 11:44:13 -07001253 } else {
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001254 oltFlowService.processNniFilteringObjectives(dev.id(), p.number(), true);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001255 }
1256 }
1257 }
1258 }
1259
Jonathan Hart403372d2018-08-22 11:44:13 -07001260
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001261 /**
1262 * Get the uplink for of the OLT device.
Gamze Abakaad329652018-12-20 10:12:21 +00001263 * <p>
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001264 * This assumes that the OLT has a single uplink port. When more uplink ports need to be supported
1265 * this logic needs to be changed
1266 *
1267 * @param dev Device to look for
1268 * @return The uplink Port of the OLT
1269 */
1270 private Port getUplinkPort(Device dev) {
1271 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +00001272 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Saurav Daseae48de2019-06-19 13:26:15 -07001273 log.trace("getUplinkPort: deviceInfo {}", deviceInfo);
Saurav Das82b8e6d2018-10-04 15:25:12 -07001274 if (deviceInfo == null) {
1275 log.warn("Device {} is not configured in SADIS .. cannot fetch device"
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001276 + " info", dev.id());
Saurav Das82b8e6d2018-10-04 15:25:12 -07001277 return null;
1278 }
1279 // Return the port that has been configured as the uplink port of this OLT in Sadis
kdarapuaa5da252020-04-10 15:58:05 +05301280 Optional<Port> optionalPort = deviceService.getPorts(dev.id()).stream()
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001281 .filter(port -> isNniPort(port) ||
1282 (port.number().toLong() == deviceInfo.uplinkPort()))
1283 .findFirst();
kdarapuaa5da252020-04-10 15:58:05 +05301284 if (optionalPort.isPresent()) {
1285 log.trace("getUplinkPort: Found port {}", optionalPort.get());
1286 return optionalPort.get();
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001287 }
1288
Saurav Daseae48de2019-06-19 13:26:15 -07001289 log.warn("getUplinkPort: " + NO_UPLINK_PORT, dev.id());
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001290 return null;
1291 }
1292
1293 /**
1294 * Return the subscriber on a port.
1295 *
Matteo Scandolo962a6ad2018-12-11 15:39:42 -08001296 * @param cp ConnectPoint on which to find the subscriber
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001297 * @return subscriber if found else null
1298 */
Ilayda Ozdemir90a93622021-02-25 09:40:58 +00001299 protected SubscriberAndDeviceInformation getSubscriber(ConnectPoint cp) {
1300 if (subsService == null) {
1301 log.warn(SADIS_NOT_RUNNING);
1302 return null;
1303 }
Matteo Scandolo962a6ad2018-12-11 15:39:42 -08001304 Port port = deviceService.getPort(cp);
1305 checkNotNull(port, "Invalid connect point");
1306 String portName = port.annotations().value(AnnotationKeys.PORT_NAME);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001307 return subsService.get(portName);
1308 }
1309
Gamze Abakaad329652018-12-20 10:12:21 +00001310 /**
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001311 * Checks whether the given port of the device is a uni port or not.
1312 *
1313 * @param d the access device
1314 * @param p the port of the device
1315 * @return true if the given port is a uni port
Gamze Abakaad329652018-12-20 10:12:21 +00001316 */
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001317 private boolean isUniPort(Device d, Port p) {
1318 Port ulPort = getUplinkPort(d);
1319 if (ulPort != null) {
1320 return (ulPort.number().toLong() != p.number().toLong());
1321 }
Thomas Lee Sd7735f92020-02-20 19:21:47 +05301322 //handles a special case where NNI port is misconfigured in SADIS and getUplinkPort(d) returns null
1323 //checks whether the port name starts with nni- which is the signature of an NNI Port
1324 if (p.annotations().value(AnnotationKeys.PORT_NAME) != null &&
1325 p.annotations().value(AnnotationKeys.PORT_NAME).startsWith(NNI)) {
1326 log.error("NNI port number {} is not matching with configured value", p.number().toLong());
1327 return false;
1328 }
1329 return true;
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001330 }
1331
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001332 /**
1333 * Gets the given device details from SADIS.
1334 * If the device is not found, returns null
1335 *
1336 * @param dev the access device
1337 * @return the olt information
1338 */
Jonathan Hart4c538002018-08-23 10:11:54 -07001339 private SubscriberAndDeviceInformation getOltInfo(Device dev) {
Ilayda Ozdemir90a93622021-02-25 09:40:58 +00001340 if (subsService == null) {
1341 log.warn(SADIS_NOT_RUNNING);
1342 return null;
1343 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001344 String devSerialNo = dev.serialNumber();
Gamze Abaka641fc072018-09-04 09:16:27 +00001345 return subsService.get(devSerialNo);
Jonathan Hart4c538002018-08-23 10:11:54 -07001346 }
1347
Andrea Campanellaaf39b4c2020-05-13 14:07:44 +02001348 // Custom-built function, when the device is not available we need a fallback mechanism
1349 private boolean isLocalLeader(DeviceId deviceId) {
1350 if (!mastershipService.isLocalMaster(deviceId)) {
1351 // When the device is available we just check the mastership
1352 if (deviceService.isAvailable(deviceId)) {
1353 return false;
1354 }
1355 // Fallback with Leadership service - device id is used as topic
1356 NodeId leader = leadershipService.runForLeadership(
1357 deviceId.toString()).leaderNodeId();
1358 // Verify if this node is the leader
1359 return clusterService.getLocalNode().id().equals(leader);
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001360 }
Andrea Campanellaaf39b4c2020-05-13 14:07:44 +02001361 return true;
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001362 }
1363
kdarapuaa5da252020-04-10 15:58:05 +05301364 private boolean isNniPort(Port port) {
1365 if (port.annotations().keys().contains(AnnotationKeys.PORT_NAME)) {
1366 return port.annotations().value(AnnotationKeys.PORT_NAME).contains(NNI);
1367 }
1368 return false;
1369 }
1370
Tunahan Sezena07fe962021-02-24 08:24:24 +00001371 private class InternalHostListener implements HostListener {
1372 @Override
1373 public void event(HostEvent event) {
1374 hostEventExecutor.execute(() -> {
1375 Host host = event.subject();
1376 switch (event.type()) {
1377 case HOST_ADDED:
1378 ConnectPoint cp = new ConnectPoint(host.location().deviceId(), host.location().port());
1379 Optional<SubscriberFlowInfo> optSubFlowInfo =
1380 getAndRemoveWaitingMacSubFlowInfoForCTag(cp, host.vlan());
1381 if (optSubFlowInfo.isPresent()) {
1382 log.debug("Continuing provisioning for waiting mac service. event: {}", event);
1383 continueProvisioningSubs(optSubFlowInfo.get(), Optional.of(host.mac()));
1384 } else {
1385 log.debug("There is no waiting mac sub. event: {}", event);
1386 }
1387 break;
1388 case HOST_UPDATED:
1389 if (event.prevSubject() != null && !event.prevSubject().mac().equals(event.subject().mac())) {
1390 log.debug("Subscriber's MAC address changed. devId/port: {}/{} vlan: {}",
1391 host.location().deviceId(), host.location().port(), host.vlan());
1392 // TODO handle subscriber MAC Address changed
1393 } else {
1394 log.debug("Unhandled HOST_UPDATED event: {}", event);
1395 }
1396 break;
1397 default:
1398 log.debug("Unhandled host event received. event: {}", event);
1399 }
1400 });
1401 }
1402
1403 @Override
1404 public boolean isRelevant(HostEvent event) {
1405 return isLocalLeader(event.subject().location().deviceId());
1406 }
1407 }
1408
alshabibf0e7e702015-05-30 18:22:36 -07001409 private class InternalDeviceListener implements DeviceListener {
Saurav Dasa9d5f442019-03-06 19:32:48 -08001410 private Set<DeviceId> programmedDevices = Sets.newConcurrentHashSet();
1411
alshabibf0e7e702015-05-30 18:22:36 -07001412 @Override
1413 public void event(DeviceEvent event) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001414 eventExecutor.execute(() -> {
1415 DeviceId devId = event.subject().id();
1416 Device dev = event.subject();
Gamze Abaka838d8142019-02-21 07:06:55 +00001417 Port port = event.port();
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001418 DeviceEvent.Type eventType = event.type();
Jonathan Hart4c538002018-08-23 10:11:54 -07001419
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001420 if (DeviceEvent.Type.PORT_STATS_UPDATED.equals(eventType) ||
1421 DeviceEvent.Type.DEVICE_SUSPENDED.equals(eventType) ||
1422 DeviceEvent.Type.DEVICE_UPDATED.equals(eventType)) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001423 return;
1424 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001425
Andrea Campanellaaf39b4c2020-05-13 14:07:44 +02001426 boolean isLocalLeader = isLocalLeader(devId);
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001427 // Only handle the event if the device belongs to us
Andrea Campanellaaf39b4c2020-05-13 14:07:44 +02001428 if (!isLocalLeader && event.type().equals(DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED)
1429 && !deviceService.isAvailable(devId) && deviceService.getPorts(devId).isEmpty()) {
1430 log.info("Cleaning local state for non master instance upon " +
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001431 "device disconnection {}", devId);
Andrea Campanellaaf39b4c2020-05-13 14:07:44 +02001432 // Since no mastership of the device is present upon disconnection
1433 // the method in the FlowRuleManager only empties the local copy
1434 // of the DeviceFlowTable thus this method needs to get called
1435 // on every instance, see how it's done in the InternalDeviceListener
1436 // in FlowRuleManager: no mastership check for purgeOnDisconnection
Andrea Campanella3f34c992020-07-15 10:54:10 +02001437 handleDeviceDisconnection(dev, false, false);
Andrea Campanellaaf39b4c2020-05-13 14:07:44 +02001438 return;
1439 } else if (!isLocalLeader) {
Andrea Campanella506df202020-05-21 10:26:12 +02001440 log.debug("Not handling event because instance is not leader for {}", devId);
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001441 return;
1442 }
1443
Matteo Scandolo19b56f62020-10-29 13:29:21 -07001444 log.debug("OLT got {} event for {}/{}", eventType, event.subject(), event.port());
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001445
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001446 if (getOltInfo(dev) == null) {
Saurav Dasa9d5f442019-03-06 19:32:48 -08001447 // it's possible that we got an event for a previously
1448 // programmed OLT that is no longer available in SADIS
1449 // we let such events go through
1450 if (!programmedDevices.contains(devId)) {
1451 log.warn("No device info found for {}, this is either "
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001452 + "not an OLT or not known to sadis", dev);
Saurav Dasa9d5f442019-03-06 19:32:48 -08001453 return;
1454 }
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001455 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001456
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001457 switch (event.type()) {
1458 //TODO: Port handling and bookkeeping should be improved once
1459 // olt firmware handles correct behaviour.
1460 case PORT_ADDED:
Andrea Campanella3f34c992020-07-15 10:54:10 +02001461 if (!deviceService.isAvailable(devId)) {
1462 log.warn("Received {} for disconnected device {}, ignoring", event, devId);
1463 return;
1464 }
Gamze Abaka838d8142019-02-21 07:06:55 +00001465 if (isUniPort(dev, port)) {
1466 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, port));
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001467
1468 if (port.isEnabled() && !port.number().equals(PortNumber.LOCAL)) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -07001469 log.info("eapol will be sent for port added {}/{}", devId, port);
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001470 oltFlowService.processEapolFilteringObjectives(devId, port.number(), defaultBpId,
1471 null,
Andrea Campanella3f34c992020-07-15 10:54:10 +02001472 VlanId.vlanId(EAPOL_DEFAULT_VLAN),
1473 true);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001474 }
1475 } else {
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001476 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
1477 if (deviceInfo != null) {
1478 oltFlowService.processNniFilteringObjectives(dev.id(), port.number(), true);
1479 }
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001480 }
1481 break;
1482 case PORT_REMOVED:
Gamze Abaka838d8142019-02-21 07:06:55 +00001483 if (isUniPort(dev, port)) {
Andrea Campanellacf0e3052020-08-27 11:05:39 +02001484 // if no subscriber is provisioned we need to remove the default EAPOL
1485 // if a subscriber was provisioned the default EAPOL will not be there and we can skip.
1486 // The EAPOL with subscriber tag will be removed by removeSubscriber call.
1487 Collection<? extends UniTagInformation> uniTagInformationSet =
1488 programmedSubs.get(new ConnectPoint(port.element().id(), port.number())).value();
1489 if (uniTagInformationSet == null || uniTagInformationSet.isEmpty()) {
Matteo Scandolo19b56f62020-10-29 13:29:21 -07001490 log.info("No subscriber provisioned on port {}/{} in PORT_REMOVED event, " +
1491 "removing default EAPOL flow", devId, port);
Andrea Campanellacf0e3052020-08-27 11:05:39 +02001492 oltFlowService.processEapolFilteringObjectives(devId, port.number(), defaultBpId,
1493 null,
1494 VlanId.vlanId(EAPOL_DEFAULT_VLAN),
1495 false);
1496 } else {
1497 removeSubscriber(new ConnectPoint(devId, port.number()));
1498 }
Andy Bavier160e8682019-05-07 18:32:22 -07001499
Gamze Abaka838d8142019-02-21 07:06:55 +00001500 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, port));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001501 }
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001502 break;
1503 case PORT_UPDATED:
Andrea Campanella3f34c992020-07-15 10:54:10 +02001504 if (!deviceService.isAvailable(devId)) {
1505 log.warn("Received {} for disconnected device {}, ignoring", event, devId);
1506 return;
1507 }
Gamze Abaka838d8142019-02-21 07:06:55 +00001508 if (!isUniPort(dev, port)) {
Saurav Das9da7d522020-03-23 19:14:35 -07001509 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
1510 if (deviceInfo != null && port.isEnabled()) {
1511 log.debug("NNI dev/port {}/{} enabled", dev.id(),
1512 port.number());
1513 oltFlowService.processNniFilteringObjectives(dev.id(),
1514 port.number(), true);
1515 }
1516 return;
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001517 }
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001518 ConnectPoint cp = new ConnectPoint(devId, port.number());
1519 Collection<? extends UniTagInformation> uniTagInformationSet = programmedSubs.get(cp).value();
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001520 if (uniTagInformationSet == null || uniTagInformationSet.isEmpty()) {
Saurav Dasb776aef2020-03-09 14:29:46 -07001521 if (!port.number().equals(PortNumber.LOCAL)) {
Matteo Scandolo3a037a32020-04-01 12:17:50 -07001522 log.info("eapol will be {} for dev/port updated {}/{} with default vlan {}",
Saurav Dasb776aef2020-03-09 14:29:46 -07001523 (port.isEnabled()) ? "added" : "removed",
Matteo Scandolo3a037a32020-04-01 12:17:50 -07001524 devId, port.number(), EAPOL_DEFAULT_VLAN);
Matteo Scandolo27c471c2020-02-11 16:41:53 -08001525 oltFlowService.processEapolFilteringObjectives(devId, port.number(), defaultBpId,
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001526 null,
1527 VlanId.vlanId(EAPOL_DEFAULT_VLAN),
1528 port.isEnabled());
1529 }
1530 } else {
Saurav Dasb776aef2020-03-09 14:29:46 -07001531 log.info("eapol will be {} for dev/port updated {}/{}",
1532 (port.isEnabled()) ? "added" : "removed",
1533 devId, port.number());
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001534 uniTagInformationSet.forEach(uniTag ->
1535 oltFlowService.processEapolFilteringObjectives(devId, port.number(),
1536 uniTag.getUpstreamBandwidthProfile(), null,
1537 uniTag.getPonCTag(), port.isEnabled()));
1538 }
Gamze Abaka838d8142019-02-21 07:06:55 +00001539 if (port.isEnabled()) {
Gamze Abaka838d8142019-02-21 07:06:55 +00001540 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, port));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001541 } else {
Gamze Abaka838d8142019-02-21 07:06:55 +00001542 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, port));
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001543 }
alshabibbb83aa22016-02-10 15:08:23 -08001544 break;
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001545 case DEVICE_ADDED:
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001546 handleDeviceConnection(dev, true);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001547 break;
1548 case DEVICE_REMOVED:
Andrea Campanella3f34c992020-07-15 10:54:10 +02001549 handleDeviceDisconnection(dev, true, true);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001550 break;
1551 case DEVICE_AVAILABILITY_CHANGED:
1552 if (deviceService.isAvailable(devId)) {
Saurav Dasbd3b6712020-03-31 23:28:35 -07001553 log.info("Handling available device: {}", dev.id());
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001554 handleDeviceConnection(dev, false);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001555 } else {
Hardik Windlassa58fbee2020-03-12 18:33:55 +05301556 if (deviceService.getPorts(devId).isEmpty()) {
Saurav Dasbd3b6712020-03-31 23:28:35 -07001557 log.info("Handling controlled device disconnection .. "
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001558 + "flushing all state for dev:{}", devId);
Andrea Campanella3f34c992020-07-15 10:54:10 +02001559 handleDeviceDisconnection(dev, true, false);
Saurav Dasbd3b6712020-03-31 23:28:35 -07001560 } else {
1561 log.info("Disconnected device has available ports .. "
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001562 + "assuming temporary disconnection, "
1563 + "retaining state for device {}", devId);
Hardik Windlassa58fbee2020-03-12 18:33:55 +05301564 }
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001565 }
1566 break;
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001567 default:
Andrea Campanella3f34c992020-07-15 10:54:10 +02001568 log.debug("Not handling event {}", event);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001569 return;
1570 }
1571 });
alshabibf0e7e702015-05-30 18:22:36 -07001572 }
Gamze Abaka838d8142019-02-21 07:06:55 +00001573
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001574 private void sendUniEvent(Device device, AccessDeviceEvent.Type eventType) {
1575 deviceService.getPorts(device.id()).stream()
1576 .filter(p -> !PortNumber.LOCAL.equals(p.number()))
1577 .filter(p -> isUniPort(device, p))
1578 .forEach(p -> post(new AccessDeviceEvent(eventType, device.id(), p)));
1579 }
1580
Andrea Campanella3f34c992020-07-15 10:54:10 +02001581 private void handleDeviceDisconnection(Device device, boolean sendDisconnectedEvent, boolean sendUniEvent) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001582 programmedDevices.remove(device.id());
1583 removeAllSubscribers(device.id());
Tunahan Sezena07fe962021-02-24 08:24:24 +00001584 removeWaitingMacSubs(device.id());
Andrea Campanella600d2e22020-06-22 11:00:31 +02001585 //Handle case where OLT disconnects during subscriber provisioning
Andrea Campanella7a1d7e72020-11-05 10:40:10 +01001586 pendingSubscribersForDevice.remove(device.id());
Andrea Campanella600d2e22020-06-22 11:00:31 +02001587 oltFlowService.clearDeviceState(device.id());
1588
1589 //Complete meter and flow purge
Hardik Windlassa58fbee2020-03-12 18:33:55 +05301590 flowRuleService.purgeFlowRules(device.id());
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001591 oltMeterService.clearMeters(device.id());
Andrea Campanella3f34c992020-07-15 10:54:10 +02001592 if (sendDisconnectedEvent) {
1593 post(new AccessDeviceEvent(
1594 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, device.id(),
1595 null, null, null));
1596 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001597 if (sendUniEvent) {
1598 sendUniEvent(device, AccessDeviceEvent.Type.UNI_REMOVED);
Gamze Abaka838d8142019-02-21 07:06:55 +00001599 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001600 }
1601
1602 private void handleDeviceConnection(Device dev, boolean sendUniEvent) {
1603 post(new AccessDeviceEvent(
1604 AccessDeviceEvent.Type.DEVICE_CONNECTED, dev.id(),
1605 null, null, null));
1606 programmedDevices.add(dev.id());
1607 checkAndCreateDeviceFlows(dev);
1608 if (sendUniEvent) {
1609 sendUniEvent(dev, AccessDeviceEvent.Type.UNI_ADDED);
1610 }
Gamze Abaka838d8142019-02-21 07:06:55 +00001611 }
Gamze Abakada282b42019-03-11 13:16:48 +00001612
1613 private void removeAllSubscribers(DeviceId deviceId) {
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001614 List<Map.Entry<ConnectPoint, UniTagInformation>> subs = programmedSubs.stream()
1615 .filter(e -> e.getKey().deviceId().equals(deviceId))
1616 .collect(toList());
Gamze Abakada282b42019-03-11 13:16:48 +00001617
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001618 subs.forEach(e -> programmedSubs.remove(e.getKey(), e.getValue()));
Gamze Abakada282b42019-03-11 13:16:48 +00001619 }
Gamze Abaka641fc072018-09-04 09:16:27 +00001620
Tunahan Sezena07fe962021-02-24 08:24:24 +00001621 private void removeWaitingMacSubs(DeviceId deviceId) {
1622 List<ConnectPoint> waitingMacKeys = waitingMacSubscribers.stream()
1623 .filter(cp -> cp.getKey().deviceId().equals(deviceId))
1624 .map(Map.Entry::getKey)
1625 .collect(toList());
1626 waitingMacKeys.forEach(cp -> waitingMacSubscribers.removeAll(cp));
1627 }
1628
Gamze Abaka641fc072018-09-04 09:16:27 +00001629 }
Jonathan Hart4f178fa2020-02-03 10:46:01 -08001630
1631 private class InternalClusterListener implements ClusterEventListener {
1632
1633 @Override
1634 public void event(ClusterEvent event) {
1635 if (event.type() == ClusterEvent.Type.INSTANCE_READY) {
1636 hasher.addServer(event.subject().id());
1637 }
1638 if (event.type() == ClusterEvent.Type.INSTANCE_DEACTIVATED) {
1639 hasher.removeServer(event.subject().id());
1640 }
1641 }
1642 }
Andrea Campanella0c3309d2020-05-29 01:51:18 -07001643
Hardik Windlass395ff372019-06-13 05:16:00 +00001644}