blob: 50a8fd6ccaef5c37158cc4e833e9c086602fde64 [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
Carmelo Casconeca931162019-07-15 18:22:24 -070018import com.google.common.collect.ImmutableMap;
Carmelo Casconeca931162019-07-15 18:22:24 -070019import com.google.common.collect.Maps;
20import com.google.common.collect.Sets;
alshabibf0e7e702015-05-30 18:22:36 -070021import org.onlab.packet.VlanId;
alshabibe0559672016-02-21 14:49:51 -080022import org.onosproject.cfg.ComponentConfigService;
alshabibf0e7e702015-05-30 18:22:36 -070023import org.onosproject.core.ApplicationId;
24import org.onosproject.core.CoreService;
alshabib8e4fd2f2016-01-12 15:55:53 -080025import org.onosproject.event.AbstractListenerManager;
alshabib09753b52016-03-04 14:55:19 -080026import org.onosproject.mastership.MastershipService;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010027import org.onosproject.net.AnnotationKeys;
Jonathan Harte533a422015-10-20 17:31:24 -070028import org.onosproject.net.ConnectPoint;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010029import org.onosproject.net.Device;
alshabibf0e7e702015-05-30 18:22:36 -070030import org.onosproject.net.DeviceId;
alshabibdec2e252016-01-15 12:20:25 -080031import org.onosproject.net.Port;
alshabibf0e7e702015-05-30 18:22:36 -070032import org.onosproject.net.PortNumber;
33import org.onosproject.net.device.DeviceEvent;
34import org.onosproject.net.device.DeviceListener;
35import org.onosproject.net.device.DeviceService;
alshabibf0e7e702015-05-30 18:22:36 -070036import org.onosproject.net.flowobjective.FlowObjectiveService;
37import org.onosproject.net.flowobjective.ForwardingObjective;
alshabib3ea82642016-01-12 18:06:53 -080038import org.onosproject.net.flowobjective.Objective;
39import org.onosproject.net.flowobjective.ObjectiveContext;
40import org.onosproject.net.flowobjective.ObjectiveError;
Saurav Daseae48de2019-06-19 13:26:15 -070041import org.onosproject.net.meter.MeterId;
alshabib36a4d732016-06-01 16:03:59 -070042import org.opencord.olt.AccessDeviceEvent;
43import org.opencord.olt.AccessDeviceListener;
44import org.opencord.olt.AccessDeviceService;
Amit Ghosh31939522018-08-16 13:28:21 +010045import org.opencord.olt.AccessSubscriberId;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000046import org.opencord.olt.internalapi.AccessDeviceFlowService;
47import org.opencord.olt.internalapi.AccessDeviceMeterService;
Gamze Abaka641fc072018-09-04 09:16:27 +000048import org.opencord.sadis.BandwidthProfileInformation;
49import org.opencord.sadis.BaseInformationService;
50import org.opencord.sadis.SadisService;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010051import org.opencord.sadis.SubscriberAndDeviceInformation;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000052import org.opencord.sadis.UniTagInformation;
alshabibe0559672016-02-21 14:49:51 -080053import org.osgi.service.component.ComponentContext;
Carmelo Casconeca931162019-07-15 18:22:24 -070054import org.osgi.service.component.annotations.Activate;
55import org.osgi.service.component.annotations.Component;
56import org.osgi.service.component.annotations.Deactivate;
57import org.osgi.service.component.annotations.Modified;
58import org.osgi.service.component.annotations.Reference;
59import org.osgi.service.component.annotations.ReferenceCardinality;
alshabibf0e7e702015-05-30 18:22:36 -070060import org.slf4j.Logger;
61
Carmelo Casconeca931162019-07-15 18:22:24 -070062import java.util.ArrayList;
Carmelo Casconeca931162019-07-15 18:22:24 -070063import java.util.Dictionary;
64import java.util.List;
65import java.util.Map;
66import java.util.Objects;
67import java.util.Optional;
68import java.util.Properties;
69import java.util.Set;
70import java.util.concurrent.CompletableFuture;
Carmelo Casconeca931162019-07-15 18:22:24 -070071import java.util.concurrent.ExecutorService;
72import java.util.concurrent.Executors;
73import java.util.stream.Collectors;
74
75import static com.google.common.base.Preconditions.checkNotNull;
Carmelo Casconeca931162019-07-15 18:22:24 -070076import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
77import static org.onlab.util.Tools.get;
78import static org.onlab.util.Tools.groupedThreads;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000079import static org.opencord.olt.impl.OsgiPropertyConstants.*;
Carmelo Casconeca931162019-07-15 18:22:24 -070080import static org.slf4j.LoggerFactory.getLogger;
alshabibf0e7e702015-05-30 18:22:36 -070081
82/**
Jonathan Harte533a422015-10-20 17:31:24 -070083 * Provisions rules on access devices.
alshabibf0e7e702015-05-30 18:22:36 -070084 */
Carmelo Casconeca931162019-07-15 18:22:24 -070085@Component(immediate = true,
86 property = {
Carmelo Casconeca931162019-07-15 18:22:24 -070087 DEFAULT_BP_ID + ":String=" + DEFAULT_BP_ID_DEFAULT,
Andrea Campanellacbbb7952019-11-25 06:38:41 +000088 DEFAULT_MCAST_SERVICE_NAME + ":String=" + DEFAULT_MCAST_SERVICE_NAME_DEFAULT,
Carmelo Casconeca931162019-07-15 18:22:24 -070089 })
alshabib8e4fd2f2016-01-12 15:55:53 -080090public class Olt
91 extends AbstractListenerManager<AccessDeviceEvent, AccessDeviceListener>
92 implements AccessDeviceService {
Charles Chan54f110f2017-01-20 11:22:42 -080093 private static final String APP_NAME = "org.opencord.olt";
alshabibe0559672016-02-21 14:49:51 -080094
Gamze Abakada282b42019-03-11 13:16:48 +000095 private static final short EAPOL_DEFAULT_VLAN = 4091;
Gamze Abaka838d8142019-02-21 07:06:55 +000096 private static final String NO_UPLINK_PORT = "No uplink port found for OLT device {}";
alshabibe0559672016-02-21 14:49:51 -080097
alshabibf0e7e702015-05-30 18:22:36 -070098 private final Logger log = getLogger(getClass());
99
Thomas Lee Sd7735f92020-02-20 19:21:47 +0530100 private static final String NNI = "nni-";
101
Carmelo Casconeca931162019-07-15 18:22:24 -0700102 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabibf0e7e702015-05-30 18:22:36 -0700103 protected FlowObjectiveService flowObjectiveService;
104
Carmelo Casconeca931162019-07-15 18:22:24 -0700105 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabib09753b52016-03-04 14:55:19 -0800106 protected MastershipService mastershipService;
107
Carmelo Casconeca931162019-07-15 18:22:24 -0700108 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabibf0e7e702015-05-30 18:22:36 -0700109 protected DeviceService deviceService;
110
Carmelo Casconeca931162019-07-15 18:22:24 -0700111 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabibf0e7e702015-05-30 18:22:36 -0700112 protected CoreService coreService;
113
Carmelo Casconeca931162019-07-15 18:22:24 -0700114 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabibe0559672016-02-21 14:49:51 -0800115 protected ComponentConfigService componentConfigService;
116
Carmelo Casconeca931162019-07-15 18:22:24 -0700117 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Gamze Abaka641fc072018-09-04 09:16:27 +0000118 protected SadisService sadisService;
119
Carmelo Casconeca931162019-07-15 18:22:24 -0700120 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000121 protected AccessDeviceFlowService oltFlowService;
alshabibe0559672016-02-21 14:49:51 -0800122
Carmelo Casconeca931162019-07-15 18:22:24 -0700123 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000124 protected AccessDeviceMeterService oltMeterService;
Gamze Abakaad329652018-12-20 10:12:21 +0000125
Carmelo Casconeca931162019-07-15 18:22:24 -0700126 /**
Carmelo Cascone95ff5122019-11-14 14:19:13 -0800127 * Default bandwidth profile id that is used for authentication trap flows.
Carmelo Casconeca931162019-07-15 18:22:24 -0700128 **/
129 protected String defaultBpId = DEFAULT_BP_ID_DEFAULT;
Gamze Abakaad329652018-12-20 10:12:21 +0000130
Carmelo Casconeca931162019-07-15 18:22:24 -0700131 /**
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000132 * Deleting Meters based on flow count statistics.
Carmelo Casconeca931162019-07-15 18:22:24 -0700133 **/
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000134 protected String multicastServiceName = DEFAULT_MCAST_SERVICE_NAME;
Gamze Abaka33feef52019-02-27 08:16:47 +0000135
alshabibf0e7e702015-05-30 18:22:36 -0700136 private final DeviceListener deviceListener = new InternalDeviceListener();
137
Gamze Abaka641fc072018-09-04 09:16:27 +0000138 protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
139 private BaseInformationService<BandwidthProfileInformation> bpService;
alshabibf0e7e702015-05-30 18:22:36 -0700140
Gamze Abaka641fc072018-09-04 09:16:27 +0000141 private ExecutorService oltInstallers = Executors.newFixedThreadPool(4,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000142 groupedThreads("onos/olt-service",
143 "olt-installer-%d"));
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100144
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700145 protected ExecutorService eventExecutor;
146
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000147 private Map<ConnectPoint, Set<UniTagInformation>> programmedSubs;
Saurav Dasa9d5f442019-03-06 19:32:48 -0800148
alshabibf0e7e702015-05-30 18:22:36 -0700149 @Activate
alshabibe0559672016-02-21 14:49:51 -0800150 public void activate(ComponentContext context) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000151 eventExecutor = newSingleThreadScheduledExecutor(groupedThreads("onos/olt",
152 "events-%d", log));
alshabibe0559672016-02-21 14:49:51 -0800153 modified(context);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000154 ApplicationId appId = coreService.registerApplication(APP_NAME);
Saurav Das62ad75e2019-03-05 12:22:22 -0800155
156 // ensure that flow rules are purged from flow-store upon olt-disconnection
157 // when olt reconnects, the port-numbers may change for the ONUs
158 // making flows pushed earlier invalid
159 componentConfigService
160 .preSetProperty("org.onosproject.net.flow.impl.FlowRuleManager",
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000161 "purgeOnDisconnection", "true");
Gamze Abakada282b42019-03-11 13:16:48 +0000162 componentConfigService
163 .preSetProperty("org.onosproject.net.meter.impl.MeterManager",
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000164 "purgeOnDisconnection", "true");
alshabibe0559672016-02-21 14:49:51 -0800165 componentConfigService.registerProperties(getClass());
Saurav Das82b8e6d2018-10-04 15:25:12 -0700166 programmedSubs = Maps.newConcurrentMap();
alshabibc4dfe852015-06-05 13:35:13 -0700167
alshabib8e4fd2f2016-01-12 15:55:53 -0800168 eventDispatcher.addSink(AccessDeviceEvent.class, listenerRegistry);
169
Gamze Abaka641fc072018-09-04 09:16:27 +0000170 subsService = sadisService.getSubscriberInfoService();
171 bpService = sadisService.getBandwidthProfileService();
172
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100173 // look for all provisioned devices in Sadis and create EAPOL flows for the
174 // UNI ports
175 Iterable<Device> devices = deviceService.getDevices();
176 for (Device d : devices) {
Jonathan Hart403372d2018-08-22 11:44:13 -0700177 checkAndCreateDeviceFlows(d);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100178 }
alshabib4ceaed32016-03-03 18:00:58 -0800179
alshabibba357492016-01-27 13:49:46 -0800180 deviceService.addListener(deviceListener);
alshabibf0e7e702015-05-30 18:22:36 -0700181 log.info("Started with Application ID {}", appId.id());
182 }
183
184 @Deactivate
185 public void deactivate() {
alshabibe0559672016-02-21 14:49:51 -0800186 componentConfigService.unregisterProperties(getClass(), false);
alshabib62e9ce72016-02-11 17:31:36 -0800187 deviceService.removeListener(deviceListener);
Jonathan Hart5f1c8142018-07-24 17:31:59 -0700188 eventDispatcher.removeSink(AccessDeviceEvent.class);
alshabibf0e7e702015-05-30 18:22:36 -0700189 log.info("Stopped");
190 }
191
alshabibe0559672016-02-21 14:49:51 -0800192 @Modified
193 public void modified(ComponentContext context) {
194 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
195
196 try {
Gamze Abakaad329652018-12-20 10:12:21 +0000197 String bpId = get(properties, "defaultBpId");
198 defaultBpId = bpId;
199
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000200 String mcastSN = get(properties, "multicastServiceName");
201 multicastServiceName = mcastSN;
202
203 log.debug("OLT properties: DefaultBpId: {}, MulticastServiceName: {}", defaultBpId, multicastServiceName);
Gamze Abaka33feef52019-02-27 08:16:47 +0000204
alshabibe0559672016-02-21 14:49:51 -0800205 } catch (Exception e) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000206 log.error("Error while modifying the properties", e);
alshabibe0559672016-02-21 14:49:51 -0800207 }
208 }
209
alshabib32232c82016-02-25 17:57:24 -0500210 @Override
Gamze Abaka838d8142019-02-21 07:06:55 +0000211 public boolean provisionSubscriber(ConnectPoint connectPoint) {
Saurav Daseae48de2019-06-19 13:26:15 -0700212 log.info("Call to provision subscriber at {}", connectPoint);
Gamze Abaka838d8142019-02-21 07:06:55 +0000213 DeviceId deviceId = connectPoint.deviceId();
214 PortNumber subscriberPortNo = connectPoint.port();
215
216 checkNotNull(deviceService.getPort(deviceId, subscriberPortNo),
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000217 "Invalid connect point:" + connectPoint);
Hardik Windlass395ff372019-06-13 05:16:00 +0000218
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100219 // Find the subscriber on this connect point
Gamze Abaka838d8142019-02-21 07:06:55 +0000220 SubscriberAndDeviceInformation sub = getSubscriber(connectPoint);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100221 if (sub == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000222 log.warn("No subscriber found for {}", connectPoint);
Amit Ghosh31939522018-08-16 13:28:21 +0100223 return false;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100224 }
Jonathan Harte533a422015-10-20 17:31:24 -0700225
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100226 // Get the uplink port
Gamze Abaka838d8142019-02-21 07:06:55 +0000227 Port uplinkPort = getUplinkPort(deviceService.getDevice(deviceId));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100228 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000229 log.warn(NO_UPLINK_PORT, deviceId);
Amit Ghosh31939522018-08-16 13:28:21 +0100230 return false;
Jonathan Harte533a422015-10-20 17:31:24 -0700231 }
232
Gamze Abaka838d8142019-02-21 07:06:55 +0000233 //delete Eapol authentication flow with default bandwidth
Gamze Abaka33feef52019-02-27 08:16:47 +0000234 //wait until Eapol rule with defaultBpId is removed to install subscriber-based rules
Gamze Abaka33feef52019-02-27 08:16:47 +0000235 //install subscriber flows
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000236 CompletableFuture<ObjectiveError> filterFuture = new CompletableFuture();
237 oltFlowService.processEapolFilteringObjectives(deviceId, subscriberPortNo, defaultBpId, filterFuture,
238 VlanId.vlanId(EAPOL_DEFAULT_VLAN), false);
Gamze Abaka33feef52019-02-27 08:16:47 +0000239 filterFuture.thenAcceptAsync(filterStatus -> {
240 if (filterStatus == null) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000241 provisionUniTagList(connectPoint, uplinkPort.number(), sub);
Gamze Abaka33feef52019-02-27 08:16:47 +0000242 }
243 });
Amit Ghosh31939522018-08-16 13:28:21 +0100244 return true;
alshabibb7a9e172016-01-13 11:23:53 -0800245 }
246
247 @Override
Gamze Abaka838d8142019-02-21 07:06:55 +0000248 public boolean removeSubscriber(ConnectPoint connectPoint) {
Saurav Daseae48de2019-06-19 13:26:15 -0700249 log.info("Call to un-provision subscriber at {}", connectPoint);
Gamze Abaka838d8142019-02-21 07:06:55 +0000250
Saurav Daseae48de2019-06-19 13:26:15 -0700251 // Get the subscriber connected to this port from the local cache
252 // If we don't know about the subscriber there's no need to remove it
Gamze Abaka838d8142019-02-21 07:06:55 +0000253 DeviceId deviceId = connectPoint.deviceId();
254 PortNumber subscriberPortNo = connectPoint.port();
255
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000256 Set<UniTagInformation> uniTagInformationSet = programmedSubs.get(connectPoint);
257 if (uniTagInformationSet == null || uniTagInformationSet.isEmpty()) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000258 log.warn("Subscriber on connectionPoint {} was not previously programmed, " +
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000259 "no need to remove it", connectPoint);
Matteo Scandolo962a6ad2018-12-11 15:39:42 -0800260 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800261 }
262
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100263 // Get the uplink port
Gamze Abaka838d8142019-02-21 07:06:55 +0000264 Port uplinkPort = getUplinkPort(deviceService.getDevice(deviceId));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100265 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000266 log.warn(NO_UPLINK_PORT, deviceId);
Amit Ghosh31939522018-08-16 13:28:21 +0100267 return false;
alshabib4ceaed32016-03-03 18:00:58 -0800268 }
269
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000270 for (UniTagInformation uniTag : uniTagInformationSet) {
Amit Ghosh95e2f652017-08-23 12:49:46 +0100271
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000272 if (multicastServiceName.equals(uniTag.getServiceName())) {
273 continue;
274 }
Gamze Abaka838d8142019-02-21 07:06:55 +0000275
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000276 unprovisionVlans(deviceId, uplinkPort.number(), subscriberPortNo, uniTag);
alshabibbf23a1f2016-01-14 17:27:11 -0800277
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000278 // re-install eapol with default bandwidth profile
279 oltFlowService.processEapolFilteringObjectives(deviceId, subscriberPortNo,
280 uniTag.getUpstreamBandwidthProfile(),
281 null, uniTag.getPonCTag(), false);
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100282
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000283 Port port = deviceService.getPort(deviceId, subscriberPortNo);
284 if (port != null && port.isEnabled()) {
285 oltFlowService.processEapolFilteringObjectives(deviceId, subscriberPortNo, defaultBpId,
286 null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
287 } else {
288 log.debug("Port {} is no longer enabled or it's unavailable. Not "
289 + "reprogramming default eapol flow", connectPoint);
290 }
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100291 }
Amit Ghosh31939522018-08-16 13:28:21 +0100292 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800293 }
294
Gamze Abakaf59c0912019-04-19 08:24:28 +0000295
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000296 @Override
297 public boolean provisionSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag,
298 Optional<VlanId> cTag, Optional<Integer> tpId) {
299
300 log.info("Provisioning subscriber using subscriberId {}, sTag {}, cTag {}, tpId {}" +
301 "", subscriberId, sTag, cTag, tpId);
Gamze Abakaf59c0912019-04-19 08:24:28 +0000302
Amit Ghosh31939522018-08-16 13:28:21 +0100303 // Check if we can find the connect point to which this subscriber is connected
304 ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
305 if (subsPort == null) {
306 log.warn("ConnectPoint for {} not found", subscriberId);
307 return false;
308 }
309
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100310 if (!sTag.isPresent() && !cTag.isPresent()) {
311 return provisionSubscriber(subsPort);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000312 } else if (sTag.isPresent() && cTag.isPresent() && tpId.isPresent()) {
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100313 Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
314 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000315 log.warn(NO_UPLINK_PORT, subsPort.deviceId());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100316 return false;
317 }
318
Gamze Abakaf59c0912019-04-19 08:24:28 +0000319 //delete Eapol authentication flow with default bandwidth
320 //wait until Eapol rule with defaultBpId is removed to install subscriber-based rules
Gamze Abakaf59c0912019-04-19 08:24:28 +0000321 //install subscriber flows
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000322 CompletableFuture<ObjectiveError> filterFuture = new CompletableFuture();
323 oltFlowService.processEapolFilteringObjectives(subsPort.deviceId(), subsPort.port(), defaultBpId,
324 filterFuture, VlanId.vlanId(EAPOL_DEFAULT_VLAN), false);
Gamze Abakaf59c0912019-04-19 08:24:28 +0000325 filterFuture.thenAcceptAsync(filterStatus -> {
326 if (filterStatus == null) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000327 provisionUniTagInformation(subsPort.deviceId(), uplinkPort.number(), subsPort.port(),
328 cTag.get(), sTag.get(), tpId.get());
Gamze Abakaf59c0912019-04-19 08:24:28 +0000329 }
330 });
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100331 return true;
332 } else {
333 log.warn("Provisioning failed for subscriber: {}", subscriberId);
334 return false;
335 }
Amit Ghosh31939522018-08-16 13:28:21 +0100336 }
Amit Ghosh95e2f652017-08-23 12:49:46 +0100337
alshabibe0559672016-02-21 14:49:51 -0800338 @Override
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000339 public boolean removeSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag,
340 Optional<VlanId> cTag, Optional<Integer> tpId) {
Amit Ghosh31939522018-08-16 13:28:21 +0100341 // Check if we can find the connect point to which this subscriber is connected
342 ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
343 if (subsPort == null) {
344 log.warn("ConnectPoint for {} not found", subscriberId);
345 return false;
346 }
347
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100348 if (!sTag.isPresent() && !cTag.isPresent()) {
349 return removeSubscriber(subsPort);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000350 } else if (sTag.isPresent() && cTag.isPresent() && tpId.isPresent()) {
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100351 // Get the uplink port
352 Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
353 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000354 log.warn(NO_UPLINK_PORT, subsPort.deviceId());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100355 return false;
356 }
357
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000358 Optional<UniTagInformation> tagInfo = getUniTagInformation(subsPort, cTag.get(), sTag.get(), tpId.get());
359 if (!tagInfo.isPresent()) {
360 log.warn("UniTagInformation does not exist for Device/Port {}, cTag {}, sTag {}, tpId {}",
361 subsPort, cTag, sTag, tpId);
362 return false;
363 }
Gamze Abakaf59c0912019-04-19 08:24:28 +0000364
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000365 unprovisionVlans(subsPort.deviceId(), uplinkPort.number(), subsPort.port(), tagInfo.get());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100366 return true;
367 } else {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000368 log.warn("Removing subscriber is not possible - please check the provided information" +
369 "for the subscriber: {}", subscriberId);
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100370 return false;
371 }
Amit Ghosh31939522018-08-16 13:28:21 +0100372 }
373
374 @Override
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000375 public ImmutableMap<ConnectPoint, Set<UniTagInformation>> getProgSubs() {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700376 return ImmutableMap.copyOf(programmedSubs);
377 }
378
379 @Override
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100380 public List<DeviceId> fetchOlts() {
381 // look through all the devices and find the ones that are OLTs as per Sadis
382 List<DeviceId> olts = new ArrayList<>();
383 Iterable<Device> devices = deviceService.getDevices();
384 for (Device d : devices) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700385 if (getOltInfo(d) != null) {
386 // So this is indeed an OLT device
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100387 olts.add(d.id());
388 }
389 }
390 return olts;
alshabibe0559672016-02-21 14:49:51 -0800391 }
392
Amit Ghosh31939522018-08-16 13:28:21 +0100393 /**
394 * Finds the connect point to which a subscriber is connected.
395 *
396 * @param id The id of the subscriber, this is the same ID as in Sadis
397 * @return Subscribers ConnectPoint if found else null
398 */
399 private ConnectPoint findSubscriberConnectPoint(String id) {
400
401 Iterable<Device> devices = deviceService.getDevices();
402 for (Device d : devices) {
403 for (Port p : deviceService.getPorts(d.id())) {
404 log.trace("Comparing {} with {}", p.annotations().value(AnnotationKeys.PORT_NAME), id);
405 if (p.annotations().value(AnnotationKeys.PORT_NAME).equals(id)) {
406 log.debug("Found on device {} port {}", d.id(), p.number());
407 return new ConnectPoint(d.id(), p.number());
408 }
409 }
410 }
411 return null;
412 }
413
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000414 /**
415 * Gets the context of the bandwidth profile information for the given parameter.
416 *
417 * @param bandwidthProfile the bandwidth profile id
418 * @return the context of the bandwidth profile information
419 */
Gamze Abaka641fc072018-09-04 09:16:27 +0000420 private BandwidthProfileInformation getBandwidthProfileInformation(String bandwidthProfile) {
421 if (bandwidthProfile == null) {
422 return null;
423 }
424 return bpService.get(bandwidthProfile);
425 }
426
Gamze Abaka838d8142019-02-21 07:06:55 +0000427 /**
Gamze Abaka33feef52019-02-27 08:16:47 +0000428 * Removes subscriber vlan flows.
Gamze Abaka838d8142019-02-21 07:06:55 +0000429 *
430 * @param deviceId the device identifier
431 * @param uplink uplink port of the OLT
432 * @param subscriberPort uni port
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000433 * @param uniTag uni tag information
Gamze Abaka838d8142019-02-21 07:06:55 +0000434 */
Gamze Abaka33feef52019-02-27 08:16:47 +0000435 private void unprovisionVlans(DeviceId deviceId, PortNumber uplink,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000436 PortNumber subscriberPort, UniTagInformation uniTag) {
437
438 log.info("Unprovisioning vlans for {} at {}/{}", uniTag, deviceId, subscriberPort);
alshabibbf23a1f2016-01-14 17:27:11 -0800439
440 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
441 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
442
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000443 VlanId deviceVlan = uniTag.getPonSTag();
444 VlanId subscriberVlan = uniTag.getPonCTag();
Gamze Abaka641fc072018-09-04 09:16:27 +0000445
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000446 MeterId upstreamMeterId = oltMeterService
447 .getMeterIdFromBpMapping(deviceId, uniTag.getUpstreamBandwidthProfile());
448 MeterId downstreamMeterId = oltMeterService
449 .getMeterIdFromBpMapping(deviceId, uniTag.getDownstreamBandwidthProfile());
Gamze Abaka641fc072018-09-04 09:16:27 +0000450
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000451 ForwardingObjective.Builder upFwd =
452 oltFlowService.createUpBuilder(uplink, subscriberPort, upstreamMeterId, uniTag);
453 ForwardingObjective.Builder downFwd =
454 oltFlowService.createDownBuilder(uplink, subscriberPort, downstreamMeterId, uniTag);
455
456 if (uniTag.getIsIgmpRequired()) {
457 oltFlowService.processIgmpFilteringObjectives(deviceId, subscriberPort,
458 upstreamMeterId, uniTag, false, true);
459 }
460 if (uniTag.getIsDhcpRequired()) {
461 oltFlowService.processDhcpFilteringObjectives(deviceId, subscriberPort,
462 upstreamMeterId, uniTag, false, true);
463 }
alshabibbf23a1f2016-01-14 17:27:11 -0800464
alshabib4ceaed32016-03-03 18:00:58 -0800465 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
466 @Override
467 public void onSuccess(Objective objective) {
468 upFuture.complete(null);
469 }
alshabibbf23a1f2016-01-14 17:27:11 -0800470
alshabib4ceaed32016-03-03 18:00:58 -0800471 @Override
472 public void onError(Objective objective, ObjectiveError error) {
473 upFuture.complete(error);
474 }
475 }));
476
477 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
478 @Override
479 public void onSuccess(Objective objective) {
480 downFuture.complete(null);
481 }
482
483 @Override
484 public void onError(Objective objective, ObjectiveError error) {
485 downFuture.complete(error);
486 }
487 }));
alshabibbf23a1f2016-01-14 17:27:11 -0800488
489 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000490 AccessDeviceEvent.Type type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_UNREGISTERED;
alshabibbf23a1f2016-01-14 17:27:11 -0800491 if (upStatus == null && downStatus == null) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000492 log.debug("Uni tag information is unregistered successfully for cTag {}, sTag {}, tpId {}, and" +
493 "Device/Port{}", uniTag.getPonCTag(), uniTag.getPonSTag(),
494 uniTag.getTechnologyProfileId(), subscriberPort);
495 updateProgrammedSubscriber(new ConnectPoint(deviceId, subscriberPort), uniTag, false);
alshabibbf23a1f2016-01-14 17:27:11 -0800496 } else if (downStatus != null) {
497 log.error("Subscriber with vlan {} on device {} " +
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000498 "on port {} failed downstream uninstallation: {}",
499 subscriberVlan, deviceId, subscriberPort, downStatus);
500 type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_UNREGISTRATION_FAILED;
alshabibbf23a1f2016-01-14 17:27:11 -0800501 } else if (upStatus != null) {
502 log.error("Subscriber with vlan {} on device {} " +
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000503 "on port {} failed upstream uninstallation: {}",
504 subscriberVlan, deviceId, subscriberPort, upStatus);
505 type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_UNREGISTRATION_FAILED;
alshabibbf23a1f2016-01-14 17:27:11 -0800506 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000507 Port port = deviceService.getPort(deviceId, subscriberPort);
508 post(new AccessDeviceEvent(type, deviceId, port, deviceVlan, subscriberVlan,
509 uniTag.getTechnologyProfileId()));
alshabibbf23a1f2016-01-14 17:27:11 -0800510 }, oltInstallers);
Jonathan Harte533a422015-10-20 17:31:24 -0700511 }
512
Gamze Abaka838d8142019-02-21 07:06:55 +0000513 /**
Gamze Abaka33feef52019-02-27 08:16:47 +0000514 * Adds subscriber vlan flows, dhcp, eapol and igmp trap flows for the related uni port.
Gamze Abaka838d8142019-02-21 07:06:55 +0000515 *
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000516 * @param connectPoint the connection point of the subscriber
517 * @param uplinkPort uplink port of the OLT (the nni port)
518 * @param sub subscriber information that includes s, c tags, tech profile and bandwidth profile references
Gamze Abaka838d8142019-02-21 07:06:55 +0000519 */
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000520 private void provisionUniTagList(ConnectPoint connectPoint, PortNumber uplinkPort,
521 SubscriberAndDeviceInformation sub) {
Gamze Abaka641fc072018-09-04 09:16:27 +0000522
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000523 log.info("Provisioning vlans for subscriber {} on dev/port: {}", sub, connectPoint);
Gamze Abaka641fc072018-09-04 09:16:27 +0000524
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000525 if (sub.uniTagList() == null || sub.uniTagList().isEmpty()) {
526 log.warn("Unitaglist doesn't exist for the subscriber {}", sub.id());
527 return;
528 }
Gamze Abaka641fc072018-09-04 09:16:27 +0000529
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000530 DeviceId deviceId = connectPoint.deviceId();
531 PortNumber subscriberPort = connectPoint.port();
Gamze Abaka641fc072018-09-04 09:16:27 +0000532
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000533 for (UniTagInformation uniTag : sub.uniTagList()) {
534 handleSubscriberFlows(deviceId, uplinkPort, subscriberPort, uniTag);
535 }
536 }
alshabib3ea82642016-01-12 18:06:53 -0800537
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000538 /**
539 * Finds the uni tag information and provisions the found information.
540 * If the uni tag information is not found, returns
541 *
542 * @param deviceId the access device id
543 * @param uplinkPort the nni port
544 * @param subscriberPort the uni port
545 * @param innerVlan the pon c tag
546 * @param outerVlan the pon s tag
547 * @param tpId the technology profile id
548 */
549 private void provisionUniTagInformation(DeviceId deviceId, PortNumber uplinkPort,
550 PortNumber subscriberPort,
551 VlanId innerVlan,
552 VlanId outerVlan,
553 Integer tpId) {
Jonathan Harte533a422015-10-20 17:31:24 -0700554
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000555 ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
556 Optional<UniTagInformation> gotTagInformation = getUniTagInformation(cp, innerVlan, outerVlan, tpId);
557 if (!gotTagInformation.isPresent()) {
558 return;
559 }
560 UniTagInformation tagInformation = gotTagInformation.get();
561 handleSubscriberFlows(deviceId, uplinkPort, subscriberPort, tagInformation);
562 }
alshabib3ea82642016-01-12 18:06:53 -0800563
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000564 private void updateProgrammedSubscriber(ConnectPoint connectPoint, UniTagInformation tagInformation, Boolean add) {
565 programmedSubs.compute(connectPoint, (k, v) -> {
566 if (add) {
567 if (v == null) {
568 v = Sets.newHashSet();
Gamze Abaka33feef52019-02-27 08:16:47 +0000569 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000570 v.add(tagInformation);
571 } else {
572 if (v != null) {
573 v.remove(tagInformation);
574 }
alshabib3ea82642016-01-12 18:06:53 -0800575 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000576 return v;
577 });
Jonathan Harte533a422015-10-20 17:31:24 -0700578 }
579
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000580 /**
581 * Installs a uni tag information flow.
582 *
583 * @param deviceId the access device id
584 * @param uplinkPort the nni port
585 * @param subscriberPort the uni port
586 * @param tagInfo the uni tag information
587 */
588 private void handleSubscriberFlows(DeviceId deviceId, PortNumber uplinkPort, PortNumber subscriberPort,
589 UniTagInformation tagInfo) {
590
591 log.info("Provisioning vlan-based flows for the uniTagInformation {}", tagInfo);
592
593 Port port = deviceService.getPort(deviceId, subscriberPort);
594
595 if (multicastServiceName.equals(tagInfo.getServiceName())) {
596 // IGMP flows are taken care of along with VOD service
597 // Please note that for each service, Subscriber Registered event will be sent
598 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_REGISTERED,
599 deviceId, port, tagInfo.getPonSTag(), tagInfo.getPonCTag(),
600 tagInfo.getTechnologyProfileId()));
601 return;
Gamze Abaka641fc072018-09-04 09:16:27 +0000602 }
603
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100604 ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
605
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000606 BandwidthProfileInformation upstreamBpInfo =
607 getBandwidthProfileInformation(tagInfo.getUpstreamBandwidthProfile());
608 BandwidthProfileInformation downstreamBpInfo =
609 getBandwidthProfileInformation(tagInfo.getDownstreamBandwidthProfile());
Gamze Abakaf59c0912019-04-19 08:24:28 +0000610
611 CompletableFuture<Object> upstreamMeterFuture = new CompletableFuture<>();
612 CompletableFuture<Object> downsteamMeterFuture = new CompletableFuture<>();
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000613 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture<>();
614 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture<>();
Gamze Abakaf59c0912019-04-19 08:24:28 +0000615
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000616 MeterId upstreamMeterId = oltMeterService.createMeter(deviceId, upstreamBpInfo, upstreamMeterFuture);
617
618 MeterId downstreamMeterId = oltMeterService.createMeter(deviceId, downstreamBpInfo, downsteamMeterFuture);
Gamze Abakaf59c0912019-04-19 08:24:28 +0000619
620 upstreamMeterFuture.thenAcceptAsync(result -> {
621 if (result == null) {
622 log.info("Upstream Meter {} is sent to the device {}. " +
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000623 "Sending subscriber flows.", upstreamMeterId, deviceId);
Gamze Abakaf59c0912019-04-19 08:24:28 +0000624
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000625 ForwardingObjective.Builder upFwd =
626 oltFlowService.createUpBuilder(uplinkPort, subscriberPort, upstreamMeterId, tagInfo);
Gamze Abakaf59c0912019-04-19 08:24:28 +0000627
628 flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
629 @Override
630 public void onSuccess(Objective objective) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000631 log.info("Upstream flow installed successfully");
Gamze Abakaf59c0912019-04-19 08:24:28 +0000632 upFuture.complete(null);
633 }
634
635 @Override
636 public void onError(Objective objective, ObjectiveError error) {
637 upFuture.complete(error);
638 }
639 }));
640
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000641 } else if (upstreamBpInfo == null) {
642 log.warn("No meter installed since no Upstream BW Profile definition found for " +
643 "ctag {} stag {} tpId {} and Device/port: {}:{}",
644 tagInfo.getPonCTag(), tagInfo.getPonSTag(),
645 tagInfo.getTechnologyProfileId(),
646 deviceId, subscriberPort);
Gamze Abakaf59c0912019-04-19 08:24:28 +0000647 } else {
648 log.warn("Meter installation error while sending upstream flows. " +
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000649 "Result {} and MeterId {}", result, upstreamMeterId);
Gamze Abakaf59c0912019-04-19 08:24:28 +0000650 }
651 });
652
653 downsteamMeterFuture.thenAcceptAsync(result -> {
654 if (result == null) {
655 log.info("Downstream Meter {} is sent to the device {}. " +
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000656 "Sending subscriber flows.", downstreamMeterId, deviceId);
Gamze Abakaf59c0912019-04-19 08:24:28 +0000657
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000658 ForwardingObjective.Builder downFwd =
659 oltFlowService.createDownBuilder(uplinkPort, subscriberPort, downstreamMeterId, tagInfo);
Gamze Abakaf59c0912019-04-19 08:24:28 +0000660
661 flowObjectiveService.forward(deviceId, downFwd.add(new ObjectiveContext() {
662 @Override
663 public void onSuccess(Objective objective) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000664 log.info("Downstream flow installed successfully");
Gamze Abakaf59c0912019-04-19 08:24:28 +0000665 downFuture.complete(null);
666 }
667
668 @Override
669 public void onError(Objective objective, ObjectiveError error) {
670 downFuture.complete(error);
671 }
672 }));
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000673
674 } else if (downstreamBpInfo == null) {
675 log.warn("No meter installed since no Downstream BW Profile definition found for " +
676 "ctag {} stag {} tpId {} and Device/port: {}:{}",
677 tagInfo.getPonCTag(), tagInfo.getPonSTag(),
678 tagInfo.getTechnologyProfileId(),
679 deviceId, subscriberPort);
Gamze Abakaf59c0912019-04-19 08:24:28 +0000680 } else {
681 log.warn("Meter installation error while sending upstream flows. " +
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000682 "Result {} and MeterId {}", result, downstreamMeterId);
Gamze Abakaf59c0912019-04-19 08:24:28 +0000683 }
684 });
685
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100686 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000687 AccessDeviceEvent.Type type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_REGISTERED;
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100688 if (downStatus != null) {
689 log.error("Flow with innervlan {} and outerVlan {} on device {} " +
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000690 "on port {} failed downstream installation: {}",
691 tagInfo.getPonCTag(), tagInfo.getPonSTag(), deviceId, cp, downStatus);
692 type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_REGISTRATION_FAILED;
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100693 } else if (upStatus != null) {
694 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000695 "on port {} failed upstream installation: {}",
696 tagInfo.getPonCTag(), tagInfo.getPonSTag(), deviceId, cp, upStatus);
697 type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_REGISTRATION_FAILED;
Gamze Abakaf59c0912019-04-19 08:24:28 +0000698 } else {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000699 log.info("Upstream and downstream data plane flows are installed successfully.");
700 oltFlowService.processEapolFilteringObjectives(deviceId, subscriberPort,
701 tagInfo.getUpstreamBandwidthProfile(),
702 null, tagInfo.getPonCTag(), true);
703 if (tagInfo.getIsDhcpRequired()) {
704 oltFlowService.processDhcpFilteringObjectives(deviceId, subscriberPort,
705 upstreamMeterId, tagInfo, true, true);
706 }
Gamze Abakaf59c0912019-04-19 08:24:28 +0000707
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000708 if (tagInfo.getIsIgmpRequired()) {
709 oltFlowService.processIgmpFilteringObjectives(deviceId, subscriberPort, upstreamMeterId, tagInfo,
710 true, true);
711 }
712 updateProgrammedSubscriber(cp, tagInfo, true);
713 post(new AccessDeviceEvent(type, deviceId, port, tagInfo.getPonSTag(), tagInfo.getPonCTag(),
714 tagInfo.getTechnologyProfileId()));
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100715 }
716 }, oltInstallers);
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100717 }
718
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000719 /**
720 * Checks the subscriber uni tag list and find the uni tag information.
721 * using the pon c tag, pon s tag and the technology profile id
722 * May return Optional<null>
723 *
724 * @param cp the connection point of the subscriber
725 * @param innerVlan pon c tag
726 * @param outerVlan pon s tag
727 * @param tpId the technology profile id
728 * @return the found uni tag information
729 */
730 private Optional<UniTagInformation> getUniTagInformation(ConnectPoint cp, VlanId innerVlan, VlanId outerVlan,
731 int tpId) {
732 log.info("Getting uni tag information for cp: {}, innerVlan: {}, outerVlan: {}, tpId: {}", cp, innerVlan,
733 outerVlan, tpId);
734 SubscriberAndDeviceInformation subInfo = getSubscriber(cp);
Gamze Abakaf59c0912019-04-19 08:24:28 +0000735 if (subInfo == null) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000736 log.warn("Subscriber information doesn't exist for the connect point {}", cp);
737 return Optional.empty();
Gamze Abakaf59c0912019-04-19 08:24:28 +0000738 }
739
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000740 List<UniTagInformation> uniTagList = subInfo.uniTagList();
741 if (uniTagList == null) {
742 log.warn("Uni tag list is not found for the subscriber {}", subInfo.id());
743 return Optional.empty();
744 }
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100745
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000746 UniTagInformation service = null;
747 for (UniTagInformation tagInfo : subInfo.uniTagList()) {
748 if (innerVlan.equals(tagInfo.getPonCTag()) && outerVlan.equals(tagInfo.getPonSTag())
749 && tpId == tagInfo.getTechnologyProfileId()) {
750 service = tagInfo;
751 break;
Andy Bavier160e8682019-05-07 18:32:22 -0700752 }
Gamze Abaka1efc80c2019-02-15 12:10:54 +0000753 }
Gamze Abaka1efc80c2019-02-15 12:10:54 +0000754
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000755 if (service == null) {
756 log.warn("SADIS doesn't include the service with ponCtag {} ponStag {} and tpId {}",
757 innerVlan, outerVlan, tpId);
758 return Optional.empty();
Gamze Abaka33feef52019-02-27 08:16:47 +0000759 }
760
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000761 return Optional.of(service);
Amit Ghosh95e2f652017-08-23 12:49:46 +0100762 }
763
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100764 /**
Jonathan Hart403372d2018-08-22 11:44:13 -0700765 * Creates trap flows for device, including DHCP and LLDP trap on NNI and
766 * EAPOL trap on the UNIs, if device is present in Sadis config.
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100767 *
768 * @param dev Device to look for
769 */
Jonathan Hart403372d2018-08-22 11:44:13 -0700770 private void checkAndCreateDeviceFlows(Device dev) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100771 // we create only for the ones we are master of
772 if (!mastershipService.isLocalMaster(dev.id())) {
Gamze Abaka641fc072018-09-04 09:16:27 +0000773 return;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100774 }
775 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +0000776 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000777 log.info("checkAndCreateDeviceFlows: deviceInfo {}", deviceInfo);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100778
779 if (deviceInfo != null) {
Jonathan Hart403372d2018-08-22 11:44:13 -0700780 // This is an OLT device as per Sadis, we create flows for UNI and NNI ports
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100781 for (Port p : deviceService.getPorts(dev.id())) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000782 if (PortNumber.LOCAL.equals(p.number())) {
783 continue;
784 }
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100785 if (isUniPort(dev, p)) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000786 log.info("Creating Eapol for the uni {}", p);
787 oltFlowService.processEapolFilteringObjectives(dev.id(), p.number(), defaultBpId, null,
788 VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
Jonathan Hart403372d2018-08-22 11:44:13 -0700789 } else {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000790 oltFlowService.processNniFilteringObjectives(dev.id(), p.number(), true);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100791 }
792 }
793 }
794 }
795
Jonathan Hart403372d2018-08-22 11:44:13 -0700796
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100797 /**
798 * Get the uplink for of the OLT device.
Gamze Abakaad329652018-12-20 10:12:21 +0000799 * <p>
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100800 * This assumes that the OLT has a single uplink port. When more uplink ports need to be supported
801 * this logic needs to be changed
802 *
803 * @param dev Device to look for
804 * @return The uplink Port of the OLT
805 */
806 private Port getUplinkPort(Device dev) {
807 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +0000808 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Saurav Daseae48de2019-06-19 13:26:15 -0700809 log.trace("getUplinkPort: deviceInfo {}", deviceInfo);
Saurav Das82b8e6d2018-10-04 15:25:12 -0700810 if (deviceInfo == null) {
811 log.warn("Device {} is not configured in SADIS .. cannot fetch device"
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000812 + " info", dev.id());
Saurav Das82b8e6d2018-10-04 15:25:12 -0700813 return null;
814 }
815 // Return the port that has been configured as the uplink port of this OLT in Sadis
Gamze Abakaad329652018-12-20 10:12:21 +0000816 for (Port p : deviceService.getPorts(dev.id())) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700817 if (p.number().toLong() == deviceInfo.uplinkPort()) {
Saurav Daseae48de2019-06-19 13:26:15 -0700818 log.trace("getUplinkPort: Found port {}", p);
Saurav Das82b8e6d2018-10-04 15:25:12 -0700819 return p;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100820 }
821 }
822
Saurav Daseae48de2019-06-19 13:26:15 -0700823 log.warn("getUplinkPort: " + NO_UPLINK_PORT, dev.id());
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100824 return null;
825 }
826
827 /**
828 * Return the subscriber on a port.
829 *
Matteo Scandolo962a6ad2018-12-11 15:39:42 -0800830 * @param cp ConnectPoint on which to find the subscriber
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100831 * @return subscriber if found else null
832 */
Matteo Scandolo962a6ad2018-12-11 15:39:42 -0800833 SubscriberAndDeviceInformation getSubscriber(ConnectPoint cp) {
834 Port port = deviceService.getPort(cp);
835 checkNotNull(port, "Invalid connect point");
836 String portName = port.annotations().value(AnnotationKeys.PORT_NAME);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100837 return subsService.get(portName);
838 }
839
Gamze Abakaad329652018-12-20 10:12:21 +0000840 /**
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000841 * Checks whether the given port of the device is a uni port or not.
842 *
843 * @param d the access device
844 * @param p the port of the device
845 * @return true if the given port is a uni port
Gamze Abakaad329652018-12-20 10:12:21 +0000846 */
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100847 private boolean isUniPort(Device d, Port p) {
848 Port ulPort = getUplinkPort(d);
849 if (ulPort != null) {
850 return (ulPort.number().toLong() != p.number().toLong());
851 }
Thomas Lee Sd7735f92020-02-20 19:21:47 +0530852 //handles a special case where NNI port is misconfigured in SADIS and getUplinkPort(d) returns null
853 //checks whether the port name starts with nni- which is the signature of an NNI Port
854 if (p.annotations().value(AnnotationKeys.PORT_NAME) != null &&
855 p.annotations().value(AnnotationKeys.PORT_NAME).startsWith(NNI)) {
856 log.error("NNI port number {} is not matching with configured value", p.number().toLong());
857 return false;
858 }
859 return true;
Jonathan Hart1d34c8b2018-05-05 15:37:28 -0700860 }
861
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000862 /**
863 * Gets the given device details from SADIS.
864 * If the device is not found, returns null
865 *
866 * @param dev the access device
867 * @return the olt information
868 */
Jonathan Hart4c538002018-08-23 10:11:54 -0700869 private SubscriberAndDeviceInformation getOltInfo(Device dev) {
870 String devSerialNo = dev.serialNumber();
Gamze Abaka641fc072018-09-04 09:16:27 +0000871 return subsService.get(devSerialNo);
Jonathan Hart4c538002018-08-23 10:11:54 -0700872 }
873
alshabibf0e7e702015-05-30 18:22:36 -0700874 private class InternalDeviceListener implements DeviceListener {
Saurav Dasa9d5f442019-03-06 19:32:48 -0800875 private Set<DeviceId> programmedDevices = Sets.newConcurrentHashSet();
876
alshabibf0e7e702015-05-30 18:22:36 -0700877 @Override
878 public void event(DeviceEvent event) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700879 eventExecutor.execute(() -> {
880 DeviceId devId = event.subject().id();
881 Device dev = event.subject();
Gamze Abaka838d8142019-02-21 07:06:55 +0000882 Port port = event.port();
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000883 DeviceEvent.Type eventType = event.type();
Jonathan Hart4c538002018-08-23 10:11:54 -0700884
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000885 if (DeviceEvent.Type.PORT_STATS_UPDATED.equals(eventType) ||
886 DeviceEvent.Type.DEVICE_SUSPENDED.equals(eventType) ||
887 DeviceEvent.Type.DEVICE_UPDATED.equals(eventType)) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700888 return;
889 }
Jonathan Hart4c538002018-08-23 10:11:54 -0700890
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000891 log.debug("OLT got {} event for {} {}", eventType, event.subject(), event.port());
892
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700893 if (getOltInfo(dev) == null) {
Saurav Dasa9d5f442019-03-06 19:32:48 -0800894 // it's possible that we got an event for a previously
895 // programmed OLT that is no longer available in SADIS
896 // we let such events go through
897 if (!programmedDevices.contains(devId)) {
898 log.warn("No device info found for {}, this is either "
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000899 + "not an OLT or not known to sadis", dev);
Saurav Dasa9d5f442019-03-06 19:32:48 -0800900 return;
901 }
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700902 }
Jonathan Hart4c538002018-08-23 10:11:54 -0700903
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700904 switch (event.type()) {
905 //TODO: Port handling and bookkeeping should be improved once
906 // olt firmware handles correct behaviour.
907 case PORT_ADDED:
Gamze Abaka838d8142019-02-21 07:06:55 +0000908 if (isUniPort(dev, port)) {
909 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, port));
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000910
911 if (port.isEnabled() && !port.number().equals(PortNumber.LOCAL)) {
912 log.info("eapol will be sent for port added {}", port);
913 oltFlowService.processEapolFilteringObjectives(devId, port.number(), defaultBpId,
914 null,
915 VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700916 }
917 } else {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000918 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
919 if (deviceInfo != null) {
920 oltFlowService.processNniFilteringObjectives(dev.id(), port.number(), true);
921 }
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700922 }
923 break;
924 case PORT_REMOVED:
Gamze Abaka838d8142019-02-21 07:06:55 +0000925 if (isUniPort(dev, port)) {
Gamze Abaka853bf252019-03-25 10:27:06 +0000926 removeSubscriber(new ConnectPoint(devId, port.number()));
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000927 log.info("eapol will be send for port removed", port);
928 oltFlowService.processEapolFilteringObjectives(devId, port.number(), defaultBpId,
929 null,
930 VlanId.vlanId(EAPOL_DEFAULT_VLAN), false);
Andy Bavier160e8682019-05-07 18:32:22 -0700931
Gamze Abaka838d8142019-02-21 07:06:55 +0000932 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, port));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700933 }
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700934 break;
935 case PORT_UPDATED:
Gamze Abaka838d8142019-02-21 07:06:55 +0000936 if (!isUniPort(dev, port)) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700937 break;
938 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000939 Set<UniTagInformation> uniTagInformationSet = programmedSubs
Gamze Abakada282b42019-03-11 13:16:48 +0000940 .get(new ConnectPoint(devId, port.number()));
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000941 if (uniTagInformationSet == null || uniTagInformationSet.isEmpty()) {
942 if (port.isEnabled() && !port.number().equals(PortNumber.LOCAL)) {
943 log.info("eapol will be processed for port updated {}", port);
Matteo Scandolo27c471c2020-02-11 16:41:53 -0800944 oltFlowService.processEapolFilteringObjectives(devId, port.number(), defaultBpId,
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000945 null,
946 VlanId.vlanId(EAPOL_DEFAULT_VLAN),
947 port.isEnabled());
948 }
949 } else {
950 log.info("eapol will be processed for port updated {}", port);
951 uniTagInformationSet.forEach(uniTag ->
952 oltFlowService.processEapolFilteringObjectives(devId, port.number(),
953 uniTag.getUpstreamBandwidthProfile(), null,
954 uniTag.getPonCTag(), port.isEnabled()));
955 }
Gamze Abaka838d8142019-02-21 07:06:55 +0000956 if (port.isEnabled()) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000957 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, port));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700958 } else {
Gamze Abaka838d8142019-02-21 07:06:55 +0000959 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, port));
Jonathan Hart1d34c8b2018-05-05 15:37:28 -0700960 }
alshabibbb83aa22016-02-10 15:08:23 -0800961 break;
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700962 case DEVICE_ADDED:
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000963 handleDeviceConnection(dev, true);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700964 break;
965 case DEVICE_REMOVED:
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000966 handleDeviceDisconnection(dev, true);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700967 break;
968 case DEVICE_AVAILABILITY_CHANGED:
969 if (deviceService.isAvailable(devId)) {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000970 handleDeviceConnection(dev, false);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700971 } else {
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000972 handleDeviceDisconnection(dev, false);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700973 }
974 break;
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700975 default:
976 return;
977 }
978 });
alshabibf0e7e702015-05-30 18:22:36 -0700979 }
Gamze Abaka838d8142019-02-21 07:06:55 +0000980
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000981 private void sendUniEvent(Device device, AccessDeviceEvent.Type eventType) {
982 deviceService.getPorts(device.id()).stream()
983 .filter(p -> !PortNumber.LOCAL.equals(p.number()))
984 .filter(p -> isUniPort(device, p))
985 .forEach(p -> post(new AccessDeviceEvent(eventType, device.id(), p)));
986 }
987
988 private void handleDeviceDisconnection(Device device, boolean sendUniEvent) {
989 programmedDevices.remove(device.id());
990 removeAllSubscribers(device.id());
991 post(new AccessDeviceEvent(
992 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, device.id(),
993 null, null, null));
994 if (sendUniEvent) {
995 sendUniEvent(device, AccessDeviceEvent.Type.UNI_REMOVED);
Gamze Abaka838d8142019-02-21 07:06:55 +0000996 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000997 }
998
999 private void handleDeviceConnection(Device dev, boolean sendUniEvent) {
1000 post(new AccessDeviceEvent(
1001 AccessDeviceEvent.Type.DEVICE_CONNECTED, dev.id(),
1002 null, null, null));
1003 programmedDevices.add(dev.id());
1004 checkAndCreateDeviceFlows(dev);
1005 if (sendUniEvent) {
1006 sendUniEvent(dev, AccessDeviceEvent.Type.UNI_ADDED);
1007 }
Gamze Abaka838d8142019-02-21 07:06:55 +00001008 }
Gamze Abakada282b42019-03-11 13:16:48 +00001009
1010 private void removeAllSubscribers(DeviceId deviceId) {
1011 List<ConnectPoint> connectPoints = programmedSubs.keySet().stream()
1012 .filter(ks -> Objects.equals(ks.deviceId(), deviceId))
1013 .collect(Collectors.toList());
1014
1015 connectPoints.forEach(cp -> programmedSubs.remove(cp));
1016 }
Gamze Abaka641fc072018-09-04 09:16:27 +00001017
Gamze Abaka641fc072018-09-04 09:16:27 +00001018 }
Hardik Windlass395ff372019-06-13 05:16:00 +00001019}