blob: 326767fc7f93a97f4029fff3c9fc1f59172a7b3d [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
Saurav Das82b8e6d2018-10-04 15:25:12 -070018import static com.google.common.base.Preconditions.checkNotNull;
19import static com.google.common.base.Strings.isNullOrEmpty;
20import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
21import static org.onlab.util.Tools.get;
22import static org.onlab.util.Tools.groupedThreads;
23import static org.slf4j.LoggerFactory.getLogger;
24
25import java.util.AbstractMap;
Gamze Abaka33feef52019-02-27 08:16:47 +000026import java.util.ArrayList;
Saurav Daseae48de2019-06-19 13:26:15 -070027import java.util.Arrays;
Saurav Das82b8e6d2018-10-04 15:25:12 -070028import java.util.Collection;
29import java.util.Dictionary;
30import java.util.List;
31import java.util.Map;
Gamze Abakada282b42019-03-11 13:16:48 +000032import java.util.Objects;
Saurav Das82b8e6d2018-10-04 15:25:12 -070033import java.util.Optional;
34import java.util.Properties;
Gamze Abaka33feef52019-02-27 08:16:47 +000035import java.util.Set;
Saurav Das82b8e6d2018-10-04 15:25:12 -070036import java.util.concurrent.CompletableFuture;
Gamze Abaka33feef52019-02-27 08:16:47 +000037import java.util.concurrent.ConcurrentHashMap;
Saurav Das82b8e6d2018-10-04 15:25:12 -070038import java.util.concurrent.ExecutorService;
39import java.util.concurrent.Executors;
Gamze Abakada282b42019-03-11 13:16:48 +000040import java.util.stream.Collectors;
Saurav Das82b8e6d2018-10-04 15:25:12 -070041
alshabibf0e7e702015-05-30 18:22:36 -070042import org.apache.felix.scr.annotations.Activate;
43import org.apache.felix.scr.annotations.Component;
44import org.apache.felix.scr.annotations.Deactivate;
alshabibe0559672016-02-21 14:49:51 -080045import org.apache.felix.scr.annotations.Modified;
46import org.apache.felix.scr.annotations.Property;
alshabibf0e7e702015-05-30 18:22:36 -070047import org.apache.felix.scr.annotations.Reference;
48import org.apache.felix.scr.annotations.ReferenceCardinality;
Jonathan Harte533a422015-10-20 17:31:24 -070049import org.apache.felix.scr.annotations.Service;
alshabibdec2e252016-01-15 12:20:25 -080050import org.onlab.packet.EthType;
Amit Ghosh95e2f652017-08-23 12:49:46 +010051import org.onlab.packet.IPv4;
Matteo Scandolo63460d12018-11-02 16:19:04 -070052import org.onlab.packet.IPv6;
Amit Ghosh95e2f652017-08-23 12:49:46 +010053import org.onlab.packet.TpPort;
alshabibf0e7e702015-05-30 18:22:36 -070054import org.onlab.packet.VlanId;
Amit Ghosh95e2f652017-08-23 12:49:46 +010055import org.onlab.util.Tools;
alshabibe0559672016-02-21 14:49:51 -080056import org.onosproject.cfg.ComponentConfigService;
alshabibf0e7e702015-05-30 18:22:36 -070057import org.onosproject.core.ApplicationId;
58import org.onosproject.core.CoreService;
alshabib8e4fd2f2016-01-12 15:55:53 -080059import org.onosproject.event.AbstractListenerManager;
alshabib09753b52016-03-04 14:55:19 -080060import org.onosproject.mastership.MastershipService;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010061import org.onosproject.net.AnnotationKeys;
Jonathan Harte533a422015-10-20 17:31:24 -070062import org.onosproject.net.ConnectPoint;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010063import org.onosproject.net.Device;
alshabibf0e7e702015-05-30 18:22:36 -070064import org.onosproject.net.DeviceId;
alshabibdec2e252016-01-15 12:20:25 -080065import org.onosproject.net.Port;
alshabibf0e7e702015-05-30 18:22:36 -070066import org.onosproject.net.PortNumber;
67import org.onosproject.net.device.DeviceEvent;
68import org.onosproject.net.device.DeviceListener;
69import org.onosproject.net.device.DeviceService;
70import org.onosproject.net.flow.DefaultTrafficSelector;
71import org.onosproject.net.flow.DefaultTrafficTreatment;
72import org.onosproject.net.flow.TrafficSelector;
73import org.onosproject.net.flow.TrafficTreatment;
alshabibdec2e252016-01-15 12:20:25 -080074import org.onosproject.net.flow.criteria.Criteria;
75import org.onosproject.net.flowobjective.DefaultFilteringObjective;
alshabibf0e7e702015-05-30 18:22:36 -070076import org.onosproject.net.flowobjective.DefaultForwardingObjective;
alshabibdec2e252016-01-15 12:20:25 -080077import org.onosproject.net.flowobjective.FilteringObjective;
alshabibf0e7e702015-05-30 18:22:36 -070078import org.onosproject.net.flowobjective.FlowObjectiveService;
79import org.onosproject.net.flowobjective.ForwardingObjective;
alshabib3ea82642016-01-12 18:06:53 -080080import org.onosproject.net.flowobjective.Objective;
81import org.onosproject.net.flowobjective.ObjectiveContext;
82import org.onosproject.net.flowobjective.ObjectiveError;
Gamze Abaka33feef52019-02-27 08:16:47 +000083import org.onosproject.net.meter.Band;
84import org.onosproject.net.meter.DefaultBand;
85import org.onosproject.net.meter.DefaultMeterRequest;
86import org.onosproject.net.meter.Meter;
87import org.onosproject.net.meter.MeterContext;
Saurav Daseae48de2019-06-19 13:26:15 -070088import org.onosproject.net.meter.MeterEvent;
Gamze Abaka33feef52019-02-27 08:16:47 +000089import org.onosproject.net.meter.MeterFailReason;
Saurav Daseae48de2019-06-19 13:26:15 -070090import org.onosproject.net.meter.MeterId;
Gamze Abaka33feef52019-02-27 08:16:47 +000091import org.onosproject.net.meter.MeterKey;
Gamze Abaka33feef52019-02-27 08:16:47 +000092import org.onosproject.net.meter.MeterListener;
93import org.onosproject.net.meter.MeterRequest;
Saurav Daseae48de2019-06-19 13:26:15 -070094import org.onosproject.net.meter.MeterService;
95import org.onosproject.store.serializers.KryoNamespaces;
96import org.onosproject.store.service.ConsistentMultimap;
97import org.onosproject.store.service.Serializer;
98import org.onosproject.store.service.StorageService;
alshabib36a4d732016-06-01 16:03:59 -070099import org.opencord.olt.AccessDeviceEvent;
100import org.opencord.olt.AccessDeviceListener;
101import org.opencord.olt.AccessDeviceService;
Amit Ghosh31939522018-08-16 13:28:21 +0100102import org.opencord.olt.AccessSubscriberId;
Gamze Abaka641fc072018-09-04 09:16:27 +0000103import org.opencord.sadis.BandwidthProfileInformation;
104import org.opencord.sadis.BaseInformationService;
105import org.opencord.sadis.SadisService;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100106import org.opencord.sadis.SubscriberAndDeviceInformation;
alshabibe0559672016-02-21 14:49:51 -0800107import org.osgi.service.component.ComponentContext;
alshabibf0e7e702015-05-30 18:22:36 -0700108import org.slf4j.Logger;
109
Saurav Das82b8e6d2018-10-04 15:25:12 -0700110import com.google.common.collect.ImmutableMap;
Saurav Daseae48de2019-06-19 13:26:15 -0700111import com.google.common.collect.ImmutableSet;
Saurav Das82b8e6d2018-10-04 15:25:12 -0700112import com.google.common.collect.Maps;
Saurav Dasa9d5f442019-03-06 19:32:48 -0800113import com.google.common.collect.Sets;
alshabibf0e7e702015-05-30 18:22:36 -0700114
115/**
Jonathan Harte533a422015-10-20 17:31:24 -0700116 * Provisions rules on access devices.
alshabibf0e7e702015-05-30 18:22:36 -0700117 */
Jonathan Harte533a422015-10-20 17:31:24 -0700118@Service
alshabibf0e7e702015-05-30 18:22:36 -0700119@Component(immediate = true)
alshabib8e4fd2f2016-01-12 15:55:53 -0800120public class Olt
121 extends AbstractListenerManager<AccessDeviceEvent, AccessDeviceListener>
122 implements AccessDeviceService {
Charles Chan54f110f2017-01-20 11:22:42 -0800123 private static final String APP_NAME = "org.opencord.olt";
alshabibe0559672016-02-21 14:49:51 -0800124
125 private static final short DEFAULT_VLAN = 0;
Gamze Abakada282b42019-03-11 13:16:48 +0000126 private static final short EAPOL_DEFAULT_VLAN = 4091;
Gamze Abaka1efc80c2019-02-15 12:10:54 +0000127 private static final int DEFAULT_TP_ID = 64;
Gamze Abakaad329652018-12-20 10:12:21 +0000128 private static final String DEFAULT_BP_ID = "Default";
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100129 private static final String ADDITIONAL_VLANS = "additional-vlans";
Gamze Abaka838d8142019-02-21 07:06:55 +0000130 private static final String NO_UPLINK_PORT = "No uplink port found for OLT device {}";
131 private static final String INSTALLED = "installed";
132 private static final String REMOVED = "removed";
133 private static final String INSTALLATION = "installation";
134 private static final String REMOVAL = "removal";
alshabibe0559672016-02-21 14:49:51 -0800135
alshabibf0e7e702015-05-30 18:22:36 -0700136 private final Logger log = getLogger(getClass());
137
138 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
139 protected FlowObjectiveService flowObjectiveService;
140
141 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabib09753b52016-03-04 14:55:19 -0800142 protected MastershipService mastershipService;
143
144 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibf0e7e702015-05-30 18:22:36 -0700145 protected DeviceService deviceService;
146
147 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
148 protected CoreService coreService;
149
Jonathan Harte533a422015-10-20 17:31:24 -0700150 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibe0559672016-02-21 14:49:51 -0800151 protected ComponentConfigService componentConfigService;
152
alshabib4ceaed32016-03-03 18:00:58 -0800153 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Gamze Abaka641fc072018-09-04 09:16:27 +0000154 protected SadisService sadisService;
155
156 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
157 protected MeterService meterService;
alshabibe0559672016-02-21 14:49:51 -0800158
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100159 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
160 protected StorageService storageService;
161
alshabibe0559672016-02-21 14:49:51 -0800162 @Property(name = "defaultVlan", intValue = DEFAULT_VLAN,
163 label = "Default VLAN RG<->ONU traffic")
164 private int defaultVlan = DEFAULT_VLAN;
165
Matt Jeanneret3f579262018-06-14 17:16:23 -0400166 @Property(name = "enableDhcpOnProvisioning", boolValue = true,
167 label = "Create the DHCP Flow rules when a subscriber is provisioned")
168 protected boolean enableDhcpOnProvisioning = false;
169
Matteo Scandolo63460d12018-11-02 16:19:04 -0700170 @Property(name = "enableDhcpV4", boolValue = true,
171 label = "Enable flows for DHCP v4")
172 protected boolean enableDhcpV4 = true;
173
174 @Property(name = "enableDhcpV6", boolValue = true,
175 label = "Enable flows for DHCP v6")
176 protected boolean enableDhcpV6 = false;
177
Matt Jeanneret3f579262018-06-14 17:16:23 -0400178 @Property(name = "enableIgmpOnProvisioning", boolValue = false,
179 label = "Create IGMP Flow rules when a subscriber is provisioned")
180 protected boolean enableIgmpOnProvisioning = false;
Amit Ghosh95e2f652017-08-23 12:49:46 +0100181
Gamze Abaka1efc80c2019-02-15 12:10:54 +0000182 @Property(name = "deleteMeters", boolValue = true,
Gamze Abaka641fc072018-09-04 09:16:27 +0000183 label = "Deleting Meters based on flow count statistics")
Gamze Abaka1efc80c2019-02-15 12:10:54 +0000184 protected boolean deleteMeters = true;
Gamze Abaka641fc072018-09-04 09:16:27 +0000185
Gamze Abakaad329652018-12-20 10:12:21 +0000186 @Property(name = "defaultTechProfileId", intValue = DEFAULT_TP_ID,
187 label = "Default technology profile id that is used for authentication trap flows")
188 protected int defaultTechProfileId = DEFAULT_TP_ID;
189
190 @Property(name = "defaultBpId", value = DEFAULT_BP_ID,
191 label = "Default bandwidth profile id that is used for authentication trap flows")
192 protected String defaultBpId = DEFAULT_BP_ID;
193
Gamze Abaka33feef52019-02-27 08:16:47 +0000194 @Property(name = "enableEapol", boolValue = true,
195 label = "Send EAPOL authentication trap flows before subscriber provisioning")
196 protected boolean enableEapol = true;
197
alshabibf0e7e702015-05-30 18:22:36 -0700198 private final DeviceListener deviceListener = new InternalDeviceListener();
Gamze Abaka641fc072018-09-04 09:16:27 +0000199 private final MeterListener meterListener = new InternalMeterListener();
alshabibf0e7e702015-05-30 18:22:36 -0700200
201 private ApplicationId appId;
Gamze Abaka641fc072018-09-04 09:16:27 +0000202 protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
203 private BaseInformationService<BandwidthProfileInformation> bpService;
alshabibf0e7e702015-05-30 18:22:36 -0700204
Gamze Abaka33feef52019-02-27 08:16:47 +0000205 private Map<String, List<MeterKey>> bpInfoToMeter = new ConcurrentHashMap<>();
Gamze Abaka641fc072018-09-04 09:16:27 +0000206
207 private ExecutorService oltInstallers = Executors.newFixedThreadPool(4,
208 groupedThreads("onos/olt-service",
209 "olt-installer-%d"));
alshabibf0e7e702015-05-30 18:22:36 -0700210
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100211 private ConsistentMultimap<ConnectPoint, Map.Entry<VlanId, VlanId>> additionalVlans;
212
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700213 protected ExecutorService eventExecutor;
214
Saurav Das82b8e6d2018-10-04 15:25:12 -0700215 private Map<ConnectPoint, SubscriberAndDeviceInformation> programmedSubs;
Gamze Abaka33feef52019-02-27 08:16:47 +0000216 private Set<MeterKey> programmedMeters;
Saurav Das82b8e6d2018-10-04 15:25:12 -0700217
Saurav Dasa9d5f442019-03-06 19:32:48 -0800218
alshabibf0e7e702015-05-30 18:22:36 -0700219 @Activate
alshabibe0559672016-02-21 14:49:51 -0800220 public void activate(ComponentContext context) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700221 eventExecutor = newSingleThreadScheduledExecutor(groupedThreads("onos/olt", "events-%d", log));
alshabibe0559672016-02-21 14:49:51 -0800222 modified(context);
Charles Chan54f110f2017-01-20 11:22:42 -0800223 appId = coreService.registerApplication(APP_NAME);
Saurav Das62ad75e2019-03-05 12:22:22 -0800224
225 // ensure that flow rules are purged from flow-store upon olt-disconnection
226 // when olt reconnects, the port-numbers may change for the ONUs
227 // making flows pushed earlier invalid
228 componentConfigService
229 .preSetProperty("org.onosproject.net.flow.impl.FlowRuleManager",
Gamze Abaka33feef52019-02-27 08:16:47 +0000230 "purgeOnDisconnection", "true");
Gamze Abakada282b42019-03-11 13:16:48 +0000231 componentConfigService
232 .preSetProperty("org.onosproject.net.meter.impl.MeterManager",
233 "purgeOnDisconnection", "true");
alshabibe0559672016-02-21 14:49:51 -0800234 componentConfigService.registerProperties(getClass());
Saurav Das82b8e6d2018-10-04 15:25:12 -0700235 programmedSubs = Maps.newConcurrentMap();
Gamze Abaka33feef52019-02-27 08:16:47 +0000236 programmedMeters = ConcurrentHashMap.newKeySet();
alshabibc4dfe852015-06-05 13:35:13 -0700237
alshabib8e4fd2f2016-01-12 15:55:53 -0800238 eventDispatcher.addSink(AccessDeviceEvent.class, listenerRegistry);
239
Gamze Abaka641fc072018-09-04 09:16:27 +0000240 subsService = sadisService.getSubscriberInfoService();
241 bpService = sadisService.getBandwidthProfileService();
242
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100243 // look for all provisioned devices in Sadis and create EAPOL flows for the
244 // UNI ports
245 Iterable<Device> devices = deviceService.getDevices();
246 for (Device d : devices) {
Jonathan Hart403372d2018-08-22 11:44:13 -0700247 checkAndCreateDeviceFlows(d);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100248 }
alshabib4ceaed32016-03-03 18:00:58 -0800249
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100250 additionalVlans = storageService.<ConnectPoint, Map.Entry<VlanId, VlanId>>consistentMultimapBuilder()
251 .withName(ADDITIONAL_VLANS)
252 .withSerializer(Serializer.using(Arrays.asList(KryoNamespaces.API),
253 AbstractMap.SimpleEntry.class))
254 .build();
255
alshabibba357492016-01-27 13:49:46 -0800256 deviceService.addListener(deviceListener);
Gamze Abaka641fc072018-09-04 09:16:27 +0000257 meterService.addListener(meterListener);
alshabibba357492016-01-27 13:49:46 -0800258
alshabibf0e7e702015-05-30 18:22:36 -0700259 log.info("Started with Application ID {}", appId.id());
260 }
261
262 @Deactivate
263 public void deactivate() {
alshabibe0559672016-02-21 14:49:51 -0800264 componentConfigService.unregisterProperties(getClass(), false);
alshabib62e9ce72016-02-11 17:31:36 -0800265 deviceService.removeListener(deviceListener);
Gamze Abaka641fc072018-09-04 09:16:27 +0000266 meterService.removeListener(meterListener);
Jonathan Hart5f1c8142018-07-24 17:31:59 -0700267 eventDispatcher.removeSink(AccessDeviceEvent.class);
alshabibf0e7e702015-05-30 18:22:36 -0700268 log.info("Stopped");
269 }
270
alshabibe0559672016-02-21 14:49:51 -0800271 @Modified
272 public void modified(ComponentContext context) {
273 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
274
275 try {
276 String s = get(properties, "defaultVlan");
277 defaultVlan = isNullOrEmpty(s) ? DEFAULT_VLAN : Integer.parseInt(s.trim());
Amit Ghosh95e2f652017-08-23 12:49:46 +0100278
Matt Jeanneret3f579262018-06-14 17:16:23 -0400279 Boolean o = Tools.isPropertyEnabled(properties, "enableDhcpOnProvisioning");
Amit Ghosh95e2f652017-08-23 12:49:46 +0100280 if (o != null) {
Matt Jeanneret3f579262018-06-14 17:16:23 -0400281 enableDhcpOnProvisioning = o;
Amit Ghosh95e2f652017-08-23 12:49:46 +0100282 }
Matt Jeanneret3f579262018-06-14 17:16:23 -0400283
Matteo Scandolo63460d12018-11-02 16:19:04 -0700284 Boolean v4 = Tools.isPropertyEnabled(properties, "enableDhcpV4");
285 if (v4 != null) {
286 enableDhcpV4 = v4;
287 }
288
289 Boolean v6 = Tools.isPropertyEnabled(properties, "enableDhcpV6");
290 if (v6 != null) {
291 enableDhcpV6 = v6;
292 }
293
Matt Jeanneret3f579262018-06-14 17:16:23 -0400294 Boolean p = Tools.isPropertyEnabled(properties, "enableIgmpOnProvisioning");
295 if (p != null) {
296 enableIgmpOnProvisioning = p;
297 }
298
Matteo Scandolo63460d12018-11-02 16:19:04 -0700299 log.info("DHCP Settings [enableDhcpOnProvisioning: {}, enableDhcpV4: {}, enableDhcpV6: {}]",
Gamze Abakaad329652018-12-20 10:12:21 +0000300 enableDhcpOnProvisioning, enableDhcpV4, enableDhcpV6);
Matteo Scandolo63460d12018-11-02 16:19:04 -0700301
Gamze Abaka641fc072018-09-04 09:16:27 +0000302 Boolean d = Tools.isPropertyEnabled(properties, "deleteMeters");
303 if (d != null) {
304 deleteMeters = d;
305 }
306
Gamze Abakaad329652018-12-20 10:12:21 +0000307 String tpId = get(properties, "defaultTechProfileId");
308 defaultTechProfileId = isNullOrEmpty(s) ? DEFAULT_TP_ID : Integer.parseInt(tpId.trim());
309
310 String bpId = get(properties, "defaultBpId");
311 defaultBpId = bpId;
312
Gamze Abaka33feef52019-02-27 08:16:47 +0000313 Boolean eap = Tools.isPropertyEnabled(properties, "enableEapol");
314 if (eap != null) {
315 enableEapol = eap;
316 }
317
alshabibe0559672016-02-21 14:49:51 -0800318 } catch (Exception e) {
319 defaultVlan = DEFAULT_VLAN;
320 }
321 }
322
alshabib32232c82016-02-25 17:57:24 -0500323 @Override
Gamze Abaka838d8142019-02-21 07:06:55 +0000324 public boolean provisionSubscriber(ConnectPoint connectPoint) {
Saurav Daseae48de2019-06-19 13:26:15 -0700325 log.info("Call to provision subscriber at {}", connectPoint);
Gamze Abaka838d8142019-02-21 07:06:55 +0000326 DeviceId deviceId = connectPoint.deviceId();
327 PortNumber subscriberPortNo = connectPoint.port();
328
329 checkNotNull(deviceService.getPort(deviceId, subscriberPortNo),
Jonathan Hart94b90492018-04-24 14:02:25 -0700330 "Invalid connect point");
Hardik Windlass395ff372019-06-13 05:16:00 +0000331
332 // If the subscriber is modified then first remove the previous and proceed
333 SubscriberAndDeviceInformation subscriber = programmedSubs.get(connectPoint);
334 if (subscriber != null) {
335 log.info("Subscriber on connectionPoint {} was previously programmed, " +
336 "remove it before adding again", connectPoint);
337 removeSubscriber(connectPoint);
338 }
339
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100340 // Find the subscriber on this connect point
Gamze Abaka838d8142019-02-21 07:06:55 +0000341 SubscriberAndDeviceInformation sub = getSubscriber(connectPoint);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100342 if (sub == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000343 log.warn("No subscriber found for {}", connectPoint);
Amit Ghosh31939522018-08-16 13:28:21 +0100344 return false;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100345 }
Jonathan Harte533a422015-10-20 17:31:24 -0700346
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100347 // Get the uplink port
Gamze Abaka838d8142019-02-21 07:06:55 +0000348 Port uplinkPort = getUplinkPort(deviceService.getDevice(deviceId));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100349 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000350 log.warn(NO_UPLINK_PORT, deviceId);
Amit Ghosh31939522018-08-16 13:28:21 +0100351 return false;
Jonathan Harte533a422015-10-20 17:31:24 -0700352 }
353
Saurav Daseae48de2019-06-19 13:26:15 -0700354 SubscriberAndDeviceInformation prgSub = programmedSubs.get(connectPoint);
355 if (prgSub != null) {
356 log.warn("Subscriber {} on connectionPoint {} was previously programmed .. "
357 + "taking no action. Note that updating a subscribers params "
358 + "(vlans, bw, tpid etc) requires removing the subscriber"
359 + "before re-provisioning the subscriber", prgSub.id(),
360 connectPoint);
361 return true;
362 }
Gamze Abaka33feef52019-02-27 08:16:47 +0000363
Gamze Abaka838d8142019-02-21 07:06:55 +0000364 //delete Eapol authentication flow with default bandwidth
Gamze Abaka33feef52019-02-27 08:16:47 +0000365 //wait until Eapol rule with defaultBpId is removed to install subscriber-based rules
Saurav Daseae48de2019-06-19 13:26:15 -0700366 CompletableFuture<ObjectiveError> filterFuture = new CompletableFuture();
Gamze Abakada282b42019-03-11 13:16:48 +0000367 processEapolFilteringObjectives(deviceId, subscriberPortNo, defaultBpId, filterFuture,
368 VlanId.vlanId(EAPOL_DEFAULT_VLAN), false);
Gamze Abaka33feef52019-02-27 08:16:47 +0000369 removeMeterIdFromBpMapping(deviceId, defaultBpId);
Gamze Abaka838d8142019-02-21 07:06:55 +0000370
Gamze Abaka33feef52019-02-27 08:16:47 +0000371 //install subscriber flows
372 filterFuture.thenAcceptAsync(filterStatus -> {
373 if (filterStatus == null) {
374 provisionSubscriberBasedFlows(connectPoint, uplinkPort.number(), Optional.empty(), sub);
375 }
376 });
Gamze Abaka838d8142019-02-21 07:06:55 +0000377
Saurav Das82b8e6d2018-10-04 15:25:12 -0700378 // cache subscriber info
Gamze Abaka838d8142019-02-21 07:06:55 +0000379 programmedSubs.put(connectPoint, sub);
Amit Ghosh31939522018-08-16 13:28:21 +0100380 return true;
alshabibb7a9e172016-01-13 11:23:53 -0800381 }
382
383 @Override
Gamze Abaka838d8142019-02-21 07:06:55 +0000384 public boolean removeSubscriber(ConnectPoint connectPoint) {
Saurav Daseae48de2019-06-19 13:26:15 -0700385 log.info("Call to un-provision subscriber at {}", connectPoint);
Gamze Abaka838d8142019-02-21 07:06:55 +0000386
Saurav Daseae48de2019-06-19 13:26:15 -0700387 // Get the subscriber connected to this port from the local cache
388 // If we don't know about the subscriber there's no need to remove it
Gamze Abaka838d8142019-02-21 07:06:55 +0000389 DeviceId deviceId = connectPoint.deviceId();
390 PortNumber subscriberPortNo = connectPoint.port();
391
392 SubscriberAndDeviceInformation subscriber = programmedSubs.get(connectPoint);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100393 if (subscriber == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000394 log.warn("Subscriber on connectionPoint {} was not previously programmed, " +
395 "no need to remove it", connectPoint);
Matteo Scandolo962a6ad2018-12-11 15:39:42 -0800396 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800397 }
398
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100399 // Get the uplink port
Gamze Abaka838d8142019-02-21 07:06:55 +0000400 Port uplinkPort = getUplinkPort(deviceService.getDevice(deviceId));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100401 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000402 log.warn(NO_UPLINK_PORT, deviceId);
Amit Ghosh31939522018-08-16 13:28:21 +0100403 return false;
alshabib4ceaed32016-03-03 18:00:58 -0800404 }
405
Gamze Abaka33feef52019-02-27 08:16:47 +0000406 //delete dhcp & igmp trap flows
407 MeterId upstreamMeterId = getMeterIdFromBpMapping(deviceId, subscriber.upstreamBandwidthProfile());
Amit Ghosh95e2f652017-08-23 12:49:46 +0100408
Saurav Daseae48de2019-06-19 13:26:15 -0700409 // remove dhcp filters
Gamze Abaka33feef52019-02-27 08:16:47 +0000410 processDhcpFilteringObjectives(deviceId, subscriberPortNo,
411 upstreamMeterId, subscriber.technologyProfileId(), false, true);
Gamze Abaka838d8142019-02-21 07:06:55 +0000412
Saurav Daseae48de2019-06-19 13:26:15 -0700413 // remove igmp filters
Gamze Abaka33feef52019-02-27 08:16:47 +0000414 processIgmpFilteringObjectives(deviceId, subscriberPortNo,
415 upstreamMeterId, subscriber.technologyProfileId(), false);
alshabibbf23a1f2016-01-14 17:27:11 -0800416
Gamze Abaka33feef52019-02-27 08:16:47 +0000417 //unprovision vlans
418 unprovisionVlans(deviceId, uplinkPort.number(), subscriberPortNo, subscriber, Optional.empty());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100419
420 // Remove if there are any flows for the additional Vlans
Gamze Abaka838d8142019-02-21 07:06:55 +0000421 Collection<? extends Map.Entry<VlanId, VlanId>> vlansList = additionalVlans.get(connectPoint).value();
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100422
423 // Remove the flows for the additional vlans for this subscriber
424 for (Map.Entry<VlanId, VlanId> vlans : vlansList) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000425 unprovisionTransparentFlows(deviceId, uplinkPort.number(), subscriberPortNo,
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100426 vlans.getValue(), vlans.getKey());
427
428 // Remove it from the map also
Gamze Abaka838d8142019-02-21 07:06:55 +0000429 additionalVlans.remove(connectPoint, vlans);
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100430 }
431
Saurav Daseae48de2019-06-19 13:26:15 -0700432 // re-install eapol with default bandwidth profile
Gamze Abaka33feef52019-02-27 08:16:47 +0000433 processEapolFilteringObjectives(deviceId, subscriberPortNo,
Gamze Abakada282b42019-03-11 13:16:48 +0000434 subscriber.upstreamBandwidthProfile(), null, subscriber.cTag(), false);
Andy Bavier160e8682019-05-07 18:32:22 -0700435
436 Port port = deviceService.getPort(deviceId, subscriberPortNo);
437 if (port != null && port.isEnabled()) {
438 processEapolFilteringObjectives(deviceId, subscriberPortNo, defaultBpId,
439 null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
Saurav Daseae48de2019-06-19 13:26:15 -0700440 } else {
441 log.debug("Port {} is no longer enabled or it's unavailable. Not "
442 + "reprogramming default eapol flow", connectPoint);
Andy Bavier160e8682019-05-07 18:32:22 -0700443 }
Gamze Abaka33feef52019-02-27 08:16:47 +0000444
Gamze Abaka838d8142019-02-21 07:06:55 +0000445 programmedSubs.remove(connectPoint);
Amit Ghosh31939522018-08-16 13:28:21 +0100446 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800447 }
448
Amit Ghosh31939522018-08-16 13:28:21 +0100449 @Override
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100450 public boolean provisionSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag, Optional<VlanId> cTag) {
Gamze Abakaf59c0912019-04-19 08:24:28 +0000451
452 log.info("Provisioning subscriber using subscriberId {}, sTag {}, cTag {}", subscriberId, sTag, cTag);
453
Amit Ghosh31939522018-08-16 13:28:21 +0100454 // Check if we can find the connect point to which this subscriber is connected
455 ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
456 if (subsPort == null) {
457 log.warn("ConnectPoint for {} not found", subscriberId);
458 return false;
459 }
460
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100461 if (!sTag.isPresent() && !cTag.isPresent()) {
462 return provisionSubscriber(subsPort);
463 } else if (sTag.isPresent() && cTag.isPresent()) {
464 Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
465 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000466 log.warn(NO_UPLINK_PORT, subsPort.deviceId());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100467 return false;
468 }
469
Gamze Abakaf59c0912019-04-19 08:24:28 +0000470 CompletableFuture<ObjectiveError> filterFuture = new CompletableFuture();
471
472 //delete Eapol authentication flow with default bandwidth
473 //wait until Eapol rule with defaultBpId is removed to install subscriber-based rules
474 processEapolFilteringObjectives(subsPort.deviceId(), subsPort.port(), defaultBpId, filterFuture,
475 VlanId.vlanId(EAPOL_DEFAULT_VLAN), false);
476 removeMeterIdFromBpMapping(subsPort.deviceId(), defaultBpId);
477
478 //install subscriber flows
479 filterFuture.thenAcceptAsync(filterStatus -> {
480 if (filterStatus == null) {
481 provisionTransparentFlows(subsPort.deviceId(), uplinkPort.number(), subsPort.port(),
482 cTag.get(), sTag.get());
483 }
484 });
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100485 return true;
486 } else {
487 log.warn("Provisioning failed for subscriber: {}", subscriberId);
488 return false;
489 }
Amit Ghosh31939522018-08-16 13:28:21 +0100490 }
Amit Ghosh95e2f652017-08-23 12:49:46 +0100491
alshabibe0559672016-02-21 14:49:51 -0800492 @Override
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100493 public boolean removeSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag, Optional<VlanId> cTag) {
Amit Ghosh31939522018-08-16 13:28:21 +0100494 // Check if we can find the connect point to which this subscriber is connected
495 ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
496 if (subsPort == null) {
497 log.warn("ConnectPoint for {} not found", subscriberId);
498 return false;
499 }
500
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100501 if (!sTag.isPresent() && !cTag.isPresent()) {
502 return removeSubscriber(subsPort);
503 } else if (sTag.isPresent() && cTag.isPresent()) {
504 // Get the uplink port
505 Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
506 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000507 log.warn(NO_UPLINK_PORT, subsPort.deviceId());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100508 return false;
509 }
510
511 unprovisionTransparentFlows(subsPort.deviceId(), uplinkPort.number(), subsPort.port(),
512 cTag.get(), sTag.get());
Gamze Abakaf59c0912019-04-19 08:24:28 +0000513
514 programmedSubs.remove(subsPort);
515
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100516 return true;
517 } else {
518 log.warn("Removing subscriber failed for: {}", subscriberId);
519 return false;
520 }
Amit Ghosh31939522018-08-16 13:28:21 +0100521 }
522
523 @Override
524 public Collection<Map.Entry<ConnectPoint, Map.Entry<VlanId, VlanId>>> getSubscribers() {
525 ArrayList<Map.Entry<ConnectPoint, Map.Entry<VlanId, VlanId>>> subs = new ArrayList<>();
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100526
Saurav Das82b8e6d2018-10-04 15:25:12 -0700527 // Get the subscribers for all the devices configured in sadis
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100528 // If the port is UNI, is enabled and exists in Sadis then copy it
529 for (Device d : deviceService.getDevices()) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700530 if (getOltInfo(d) == null) {
531 continue; // not an olt, or not configured in sadis
532 }
Gamze Abakaad329652018-12-20 10:12:21 +0000533 for (Port p : deviceService.getPorts(d.id())) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100534 if (isUniPort(d, p) && p.isEnabled()) {
535 ConnectPoint cp = new ConnectPoint(d.id(), p.number());
536
537 SubscriberAndDeviceInformation sub = getSubscriber(cp);
538 if (sub != null) {
Amit Ghosh31939522018-08-16 13:28:21 +0100539 Map.Entry<VlanId, VlanId> vlans = new AbstractMap.SimpleEntry(sub.sTag(), sub.cTag());
540 subs.add(new AbstractMap.SimpleEntry(cp, vlans));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100541 }
542 }
543 }
544 }
545
546 return subs;
Jonathan Hartfd6c1b32016-03-08 14:09:09 -0800547 }
548
549 @Override
Saurav Das82b8e6d2018-10-04 15:25:12 -0700550 public ImmutableMap<ConnectPoint, SubscriberAndDeviceInformation> getProgSubs() {
551 return ImmutableMap.copyOf(programmedSubs);
552 }
553
554 @Override
Gamze Abaka33feef52019-02-27 08:16:47 +0000555 public ImmutableSet<MeterKey> getProgMeters() {
556 return ImmutableSet.copyOf(programmedMeters);
557 }
558
559 @Override
560 public ImmutableMap<String, List<MeterKey>> getBpMeterMappings() {
561 return ImmutableMap.copyOf(bpInfoToMeter);
562 }
563
564 @Override
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100565 public List<DeviceId> fetchOlts() {
566 // look through all the devices and find the ones that are OLTs as per Sadis
567 List<DeviceId> olts = new ArrayList<>();
568 Iterable<Device> devices = deviceService.getDevices();
569 for (Device d : devices) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700570 if (getOltInfo(d) != null) {
571 // So this is indeed an OLT device
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100572 olts.add(d.id());
573 }
574 }
575 return olts;
alshabibe0559672016-02-21 14:49:51 -0800576 }
577
Amit Ghosh31939522018-08-16 13:28:21 +0100578 /**
579 * Finds the connect point to which a subscriber is connected.
580 *
581 * @param id The id of the subscriber, this is the same ID as in Sadis
582 * @return Subscribers ConnectPoint if found else null
583 */
584 private ConnectPoint findSubscriberConnectPoint(String id) {
585
586 Iterable<Device> devices = deviceService.getDevices();
587 for (Device d : devices) {
588 for (Port p : deviceService.getPorts(d.id())) {
589 log.trace("Comparing {} with {}", p.annotations().value(AnnotationKeys.PORT_NAME), id);
590 if (p.annotations().value(AnnotationKeys.PORT_NAME).equals(id)) {
591 log.debug("Found on device {} port {}", d.id(), p.number());
592 return new ConnectPoint(d.id(), p.number());
593 }
594 }
595 }
596 return null;
597 }
598
Gamze Abaka641fc072018-09-04 09:16:27 +0000599 private BandwidthProfileInformation getBandwidthProfileInformation(String bandwidthProfile) {
600 if (bandwidthProfile == null) {
601 return null;
602 }
603 return bpService.get(bandwidthProfile);
604 }
605
Gamze Abaka838d8142019-02-21 07:06:55 +0000606 /**
Gamze Abaka33feef52019-02-27 08:16:47 +0000607 * Removes subscriber vlan flows.
Gamze Abaka838d8142019-02-21 07:06:55 +0000608 *
609 * @param deviceId the device identifier
610 * @param uplink uplink port of the OLT
611 * @param subscriberPort uni port
612 * @param subscriber subscriber info that includes s, c tags, tech profile and bandwidth profile references
613 * @param defaultVlan default vlan of the subscriber
Gamze Abaka838d8142019-02-21 07:06:55 +0000614 */
Gamze Abaka33feef52019-02-27 08:16:47 +0000615 private void unprovisionVlans(DeviceId deviceId, PortNumber uplink,
616 PortNumber subscriberPort, SubscriberAndDeviceInformation subscriber,
617 Optional<VlanId> defaultVlan) {
Saurav Daseae48de2019-06-19 13:26:15 -0700618 log.info("Unprovisioning vlans for subscriber {} on dev/port: {}/{}",
619 subscriber, deviceId, subscriberPort);
alshabibbf23a1f2016-01-14 17:27:11 -0800620
621 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
622 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
623
Gamze Abaka641fc072018-09-04 09:16:27 +0000624 VlanId deviceVlan = subscriber.sTag();
625 VlanId subscriberVlan = subscriber.cTag();
626
Gamze Abaka33feef52019-02-27 08:16:47 +0000627 MeterId upstreamMeterId = getMeterIdFromBpMapping(deviceId, subscriber.upstreamBandwidthProfile());
628 MeterId downstreamMeterId = getMeterIdFromBpMapping(deviceId, subscriber.downstreamBandwidthProfile());
Gamze Abaka641fc072018-09-04 09:16:27 +0000629
alshabib4ceaed32016-03-03 18:00:58 -0800630 ForwardingObjective.Builder upFwd = upBuilder(uplink, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000631 subscriberVlan, deviceVlan,
632 defaultVlan, upstreamMeterId, subscriber.technologyProfileId());
alshabib4ceaed32016-03-03 18:00:58 -0800633 ForwardingObjective.Builder downFwd = downBuilder(uplink, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000634 subscriberVlan, deviceVlan,
635 defaultVlan, downstreamMeterId, subscriber.technologyProfileId());
alshabibbf23a1f2016-01-14 17:27:11 -0800636
alshabib4ceaed32016-03-03 18:00:58 -0800637 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
638 @Override
639 public void onSuccess(Objective objective) {
640 upFuture.complete(null);
641 }
alshabibbf23a1f2016-01-14 17:27:11 -0800642
alshabib4ceaed32016-03-03 18:00:58 -0800643 @Override
644 public void onError(Objective objective, ObjectiveError error) {
645 upFuture.complete(error);
646 }
647 }));
648
649 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
650 @Override
651 public void onSuccess(Objective objective) {
652 downFuture.complete(null);
653 }
654
655 @Override
656 public void onError(Objective objective, ObjectiveError error) {
657 downFuture.complete(error);
658 }
659 }));
alshabibbf23a1f2016-01-14 17:27:11 -0800660
661 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
662 if (upStatus == null && downStatus == null) {
663 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_UNREGISTERED,
Gamze Abaka641fc072018-09-04 09:16:27 +0000664 deviceId,
665 deviceVlan,
666 subscriberVlan));
alshabibbf23a1f2016-01-14 17:27:11 -0800667 } else if (downStatus != null) {
668 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000669 "on port {} failed downstream uninstallation: {}",
670 subscriberVlan, deviceId, subscriberPort, downStatus);
alshabibbf23a1f2016-01-14 17:27:11 -0800671 } else if (upStatus != null) {
672 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000673 "on port {} failed upstream uninstallation: {}",
674 subscriberVlan, deviceId, subscriberPort, upStatus);
alshabibbf23a1f2016-01-14 17:27:11 -0800675 }
676 }, oltInstallers);
alshabibb7a9e172016-01-13 11:23:53 -0800677
Gamze Abaka33feef52019-02-27 08:16:47 +0000678 programmedMeters.remove(MeterKey.key(deviceId, upstreamMeterId));
679 programmedMeters.remove(MeterKey.key(deviceId, downstreamMeterId));
Gamze Abaka838d8142019-02-21 07:06:55 +0000680 log.debug("programmed Meters size {}", programmedMeters.size());
Jonathan Harte533a422015-10-20 17:31:24 -0700681 }
682
Gamze Abaka838d8142019-02-21 07:06:55 +0000683 /**
Gamze Abaka33feef52019-02-27 08:16:47 +0000684 * Adds subscriber vlan flows, dhcp, eapol and igmp trap flows for the related uni port.
Gamze Abaka838d8142019-02-21 07:06:55 +0000685 *
686 * @param port the connection point of the subscriber
687 * @param uplinkPort uplink port of the OLT
688 * @param defaultVlan default vlan of the subscriber
689 * @param sub subscriber information that includes s, c tags, tech profile and bandwidth profile references
Gamze Abaka838d8142019-02-21 07:06:55 +0000690 */
Saurav Daseae48de2019-06-19 13:26:15 -0700691 private void provisionSubscriberBasedFlows(ConnectPoint port, PortNumber uplinkPort,
692 Optional<VlanId> defaultVlan,
Gamze Abaka33feef52019-02-27 08:16:47 +0000693 SubscriberAndDeviceInformation sub) {
Gamze Abaka641fc072018-09-04 09:16:27 +0000694
Saurav Daseae48de2019-06-19 13:26:15 -0700695 log.info("Provisioning vlans for subscriber {} on dev/port: {}",
696 sub, port);
Gamze Abaka641fc072018-09-04 09:16:27 +0000697
698 DeviceId deviceId = port.deviceId();
699 PortNumber subscriberPort = port.port();
700 VlanId deviceVlan = sub.sTag();
701 VlanId subscriberVlan = sub.cTag();
702 int techProfId = sub.technologyProfileId();
703
704 BandwidthProfileInformation upstreamBpInfo = getBandwidthProfileInformation(sub.upstreamBandwidthProfile());
705 BandwidthProfileInformation downstreamBpInfo = getBandwidthProfileInformation(sub.downstreamBandwidthProfile());
706
alshabib3ea82642016-01-12 18:06:53 -0800707 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
708 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
Gamze Abaka33feef52019-02-27 08:16:47 +0000709 CompletableFuture<Object> upstreamMeterFuture = new CompletableFuture<>();
710 CompletableFuture<Object> downsteamMeterFuture = new CompletableFuture<>();
alshabib3ea82642016-01-12 18:06:53 -0800711
Gamze Abaka33feef52019-02-27 08:16:47 +0000712 MeterId upstreamMeterId = createMeter(deviceId, upstreamBpInfo, upstreamMeterFuture);
713 MeterId downstreamMeterId = createMeter(deviceId, downstreamBpInfo, downsteamMeterFuture);
Jonathan Harte533a422015-10-20 17:31:24 -0700714
Gamze Abaka33feef52019-02-27 08:16:47 +0000715 //install upstream flows
716 upstreamMeterFuture.thenAcceptAsync(result -> {
717 if (result == null) {
Saurav Daseae48de2019-06-19 13:26:15 -0700718 log.info("Upstream Meter {} is in the device {}. " +
Gamze Abaka33feef52019-02-27 08:16:47 +0000719 "Sending subscriber flows.", upstreamMeterId, deviceId);
720 ForwardingObjective.Builder upFwd = upBuilder(uplinkPort, subscriberPort,
721 subscriberVlan, deviceVlan,
722 defaultVlan, upstreamMeterId, techProfId);
alshabib3ea82642016-01-12 18:06:53 -0800723
Gamze Abaka33feef52019-02-27 08:16:47 +0000724
725 flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
726 @Override
727 public void onSuccess(Objective objective) {
728 upFuture.complete(null);
729 }
730
731 @Override
732 public void onError(Objective objective, ObjectiveError error) {
733 upFuture.complete(error);
734 }
735 }));
736 } else {
737 log.warn("Meter installation error while sending upstream flows. " +
738 "Result {} and MeterId {}", result, upstreamMeterId);
alshabibbf23a1f2016-01-14 17:27:11 -0800739 }
Gamze Abaka33feef52019-02-27 08:16:47 +0000740 });
alshabibbf23a1f2016-01-14 17:27:11 -0800741
Gamze Abaka33feef52019-02-27 08:16:47 +0000742 //install downstream flows
743 downsteamMeterFuture.thenAcceptAsync(result -> {
744 if (result == null) {
Saurav Daseae48de2019-06-19 13:26:15 -0700745 log.info("Downstream Meter {} is in the device {}. " +
Gamze Abaka33feef52019-02-27 08:16:47 +0000746 "Sending subscriber flows.", downstreamMeterId, deviceId);
747 ForwardingObjective.Builder downFwd = downBuilder(uplinkPort, subscriberPort,
748 subscriberVlan, deviceVlan,
749 defaultVlan, downstreamMeterId, techProfId);
750
751 flowObjectiveService.forward(deviceId, downFwd.add(new ObjectiveContext() {
752 @Override
753 public void onSuccess(Objective objective) {
754 downFuture.complete(null);
755 }
756
757 @Override
758 public void onError(Objective objective, ObjectiveError error) {
759 downFuture.complete(error);
760 }
761 }));
762 } else {
763 log.warn("Meter installation error while sending downstream flows. " +
764 "Result {} and MeterId {}", result, downstreamMeterId);
alshabibbf23a1f2016-01-14 17:27:11 -0800765 }
Gamze Abaka33feef52019-02-27 08:16:47 +0000766 });
alshabibbf23a1f2016-01-14 17:27:11 -0800767
Gamze Abaka33feef52019-02-27 08:16:47 +0000768 //send eapol & dhcp & igmp flows
769 //send Subscriber Registered event
alshabib3ea82642016-01-12 18:06:53 -0800770 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
771 if (upStatus == null && downStatus == null) {
Gamze Abaka33feef52019-02-27 08:16:47 +0000772
773 if (upstreamMeterId != null) {
774 //re-install Eapol authentication flow with the subscribers' upstream bandwidth profile
775 processEapolFilteringObjectives(deviceId, subscriberPort, sub.upstreamBandwidthProfile(),
Gamze Abakada282b42019-03-11 13:16:48 +0000776 null, sub.cTag(), true);
Gamze Abaka33feef52019-02-27 08:16:47 +0000777
778 processDhcpFilteringObjectives(deviceId, subscriberPort,
779 upstreamMeterId, sub.technologyProfileId(), true, true);
780
781 processIgmpFilteringObjectives(deviceId, subscriberPort,
782 upstreamMeterId, sub.technologyProfileId(), true);
783 }
784
alshabib3ea82642016-01-12 18:06:53 -0800785 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_REGISTERED,
Gamze Abaka641fc072018-09-04 09:16:27 +0000786 deviceId,
787 deviceVlan,
788 subscriberVlan));
alshabib50d9fc52016-02-12 15:47:20 -0800789
alshabib3ea82642016-01-12 18:06:53 -0800790 } else if (downStatus != null) {
791 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000792 "on port {} failed downstream installation: {}",
793 subscriberVlan, deviceId, subscriberPort, downStatus);
alshabib3ea82642016-01-12 18:06:53 -0800794 } else if (upStatus != null) {
795 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000796 "on port {} failed upstream installation: {}",
797 subscriberVlan, deviceId, subscriberPort, upStatus);
alshabib3ea82642016-01-12 18:06:53 -0800798 }
799 }, oltInstallers);
Jonathan Harte533a422015-10-20 17:31:24 -0700800 }
801
Gamze Abaka33feef52019-02-27 08:16:47 +0000802 private MeterId createMeter(DeviceId deviceId, BandwidthProfileInformation bpInfo,
803 CompletableFuture<Object> meterFuture) {
Gamze Abaka641fc072018-09-04 09:16:27 +0000804 if (bpInfo == null) {
Saurav Daseae48de2019-06-19 13:26:15 -0700805 log.warn("Bandwidth profile information cannot be null when creating meter");
Gamze Abaka641fc072018-09-04 09:16:27 +0000806 return null;
807 }
808
Gamze Abaka33feef52019-02-27 08:16:47 +0000809 MeterId meterId = getMeterIdFromBpMapping(deviceId, bpInfo.id());
Gamze Abaka641fc072018-09-04 09:16:27 +0000810 if (meterId != null) {
Saurav Daseae48de2019-06-19 13:26:15 -0700811 log.debug("Meter {} was previously created for bp {}", meterId,
812 bpInfo.id());
Gamze Abaka33feef52019-02-27 08:16:47 +0000813 meterFuture.complete(null);
Gamze Abaka641fc072018-09-04 09:16:27 +0000814 return meterId;
815 }
816
817 List<Band> meterBands = createMeterBands(bpInfo);
818
819 MeterRequest meterRequest = DefaultMeterRequest.builder()
820 .withBands(meterBands)
821 .withUnit(Meter.Unit.KB_PER_SEC)
Gamze Abaka33feef52019-02-27 08:16:47 +0000822 .withContext(new MeterContext() {
823 @Override
824 public void onSuccess(MeterRequest op) {
Saurav Daseae48de2019-06-19 13:26:15 -0700825 log.debug("meter addition confirmed for bpInfo:{}", bpInfo);
Gamze Abaka33feef52019-02-27 08:16:47 +0000826 meterFuture.complete(null);
827 }
828
829 @Override
830 public void onError(MeterRequest op, MeterFailReason reason) {
831 meterFuture.complete(reason);
832 }
833 })
Gamze Abaka641fc072018-09-04 09:16:27 +0000834 .forDevice(deviceId)
835 .fromApp(appId)
836 .burst()
837 .add();
838
839 Meter meter = meterService.submit(meterRequest);
Gamze Abaka33feef52019-02-27 08:16:47 +0000840 addMeterIdToBpMapping(deviceId, meter.id(), bpInfo.id());
Saurav Daseae48de2019-06-19 13:26:15 -0700841 log.info("Meter creation message sent for Meter Id {}", meter.id());
Gamze Abaka33feef52019-02-27 08:16:47 +0000842 programmedMeters.add(MeterKey.key(deviceId, meter.id()));
Gamze Abaka641fc072018-09-04 09:16:27 +0000843 return meter.id();
844 }
845
846 private List<Band> createMeterBands(BandwidthProfileInformation bpInfo) {
847 List<Band> meterBands = new ArrayList<>();
848
849 meterBands.add(createMeterBand(bpInfo.committedInformationRate(), bpInfo.committedBurstSize()));
850 meterBands.add(createMeterBand(bpInfo.exceededInformationRate(), bpInfo.exceededBurstSize()));
Gamze Abakaad329652018-12-20 10:12:21 +0000851 meterBands.add(createMeterBand(bpInfo.assuredInformationRate(), 0L));
Gamze Abaka641fc072018-09-04 09:16:27 +0000852
Gamze Abaka641fc072018-09-04 09:16:27 +0000853 return meterBands;
854 }
855
856 private Band createMeterBand(long rate, Long burst) {
857 return DefaultBand.builder()
858 .withRate(rate) //already Kbps
859 .burstSize(burst) // already Kbits
860 .ofType(Band.Type.DROP) // no matter
861 .build();
862 }
863
alshabib4ceaed32016-03-03 18:00:58 -0800864 private ForwardingObjective.Builder downBuilder(PortNumber uplinkPort,
865 PortNumber subscriberPort,
866 VlanId subscriberVlan,
867 VlanId deviceVlan,
Gamze Abaka641fc072018-09-04 09:16:27 +0000868 Optional<VlanId> defaultVlan,
869 MeterId meterId,
870 int techProfId) {
alshabib4ceaed32016-03-03 18:00:58 -0800871 TrafficSelector downstream = DefaultTrafficSelector.builder()
872 .matchVlanId(deviceVlan)
873 .matchInPort(uplinkPort)
874 .matchInnerVlanId(subscriberVlan)
875 .build();
876
Gamze Abaka641fc072018-09-04 09:16:27 +0000877 TrafficTreatment.Builder downstreamTreatmentBuilder = DefaultTrafficTreatment.builder()
alshabib4ceaed32016-03-03 18:00:58 -0800878 .popVlan()
879 .setVlanId(defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan)))
Gamze Abaka641fc072018-09-04 09:16:27 +0000880 .setOutput(subscriberPort);
881
882 if (meterId != null) {
883 downstreamTreatmentBuilder.meter(meterId);
884 }
885
Gamze Abakaad329652018-12-20 10:12:21 +0000886 downstreamTreatmentBuilder.writeMetadata(createMetadata(subscriberVlan, techProfId, subscriberPort), 0);
alshabib4ceaed32016-03-03 18:00:58 -0800887
888 return DefaultForwardingObjective.builder()
889 .withFlag(ForwardingObjective.Flag.VERSATILE)
890 .withPriority(1000)
891 .makePermanent()
892 .withSelector(downstream)
893 .fromApp(appId)
Gamze Abaka641fc072018-09-04 09:16:27 +0000894 .withTreatment(downstreamTreatmentBuilder.build());
alshabib4ceaed32016-03-03 18:00:58 -0800895 }
896
897 private ForwardingObjective.Builder upBuilder(PortNumber uplinkPort,
898 PortNumber subscriberPort,
899 VlanId subscriberVlan,
900 VlanId deviceVlan,
Gamze Abaka641fc072018-09-04 09:16:27 +0000901 Optional<VlanId> defaultVlan,
902 MeterId meterId,
903 int technologyProfileId) {
904
905
906 VlanId dVlan = defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan));
907
908 if (subscriberVlan.toShort() == 4096) {
909 dVlan = subscriberVlan;
910 }
911
alshabib4ceaed32016-03-03 18:00:58 -0800912 TrafficSelector upstream = DefaultTrafficSelector.builder()
Gamze Abaka641fc072018-09-04 09:16:27 +0000913 .matchVlanId(dVlan)
alshabib4ceaed32016-03-03 18:00:58 -0800914 .matchInPort(subscriberPort)
915 .build();
916
917
Gamze Abaka641fc072018-09-04 09:16:27 +0000918 TrafficTreatment.Builder upstreamTreatmentBuilder = DefaultTrafficTreatment.builder()
alshabib4ceaed32016-03-03 18:00:58 -0800919 .pushVlan()
920 .setVlanId(subscriberVlan)
921 .pushVlan()
922 .setVlanId(deviceVlan)
Gamze Abaka641fc072018-09-04 09:16:27 +0000923 .setOutput(uplinkPort);
924
925 if (meterId != null) {
926 upstreamTreatmentBuilder.meter(meterId);
927 }
928
Gamze Abakaad329652018-12-20 10:12:21 +0000929 upstreamTreatmentBuilder.writeMetadata(createMetadata(deviceVlan, technologyProfileId, uplinkPort), 0L);
alshabib4ceaed32016-03-03 18:00:58 -0800930
931 return DefaultForwardingObjective.builder()
932 .withFlag(ForwardingObjective.Flag.VERSATILE)
933 .withPriority(1000)
934 .makePermanent()
935 .withSelector(upstream)
936 .fromApp(appId)
Gamze Abaka641fc072018-09-04 09:16:27 +0000937 .withTreatment(upstreamTreatmentBuilder.build());
alshabib4ceaed32016-03-03 18:00:58 -0800938 }
Gamze Abakaad329652018-12-20 10:12:21 +0000939
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100940 private void provisionTransparentFlows(DeviceId deviceId, PortNumber uplinkPort,
941 PortNumber subscriberPort,
942 VlanId innerVlan,
943 VlanId outerVlan) {
944
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100945 ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
946
Gamze Abakaf59c0912019-04-19 08:24:28 +0000947 SubscriberAndDeviceInformation subInfo = getSubscriber(cp);
948
949 BandwidthProfileInformation upstreamBpInfo = getBandwidthProfileInformation(
950 subInfo.upstreamBandwidthProfile());
951 BandwidthProfileInformation downstreamBpInfo = getBandwidthProfileInformation(
952 subInfo.downstreamBandwidthProfile());
953
954 CompletableFuture<Object> upstreamMeterFuture = new CompletableFuture<>();
955 CompletableFuture<Object> downsteamMeterFuture = new CompletableFuture<>();
956 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
957 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
958
959 MeterId upstreamMeterId = createMeter(deviceId, upstreamBpInfo, upstreamMeterFuture);
960 MeterId downstreamMeterId = createMeter(deviceId, downstreamBpInfo, downsteamMeterFuture);
961
962 upstreamMeterFuture.thenAcceptAsync(result -> {
963 if (result == null) {
964 log.info("Upstream Meter {} is sent to the device {}. " +
965 "Sending subscriber flows.", upstreamMeterId, deviceId);
966
967 ForwardingObjective.Builder upFwd = transparentUpBuilder(uplinkPort, subscriberPort,
968 innerVlan, outerVlan, upstreamMeterId, subInfo);
969
970 flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
971 @Override
972 public void onSuccess(Objective objective) {
973 upFuture.complete(null);
974 }
975
976 @Override
977 public void onError(Objective objective, ObjectiveError error) {
978 upFuture.complete(error);
979 }
980 }));
981
982 } else {
983 log.warn("Meter installation error while sending upstream flows. " +
984 "Result {} and MeterId {}", result, upstreamMeterId);
985 }
986 });
987
988 downsteamMeterFuture.thenAcceptAsync(result -> {
989 if (result == null) {
990 log.info("Downstream Meter {} is sent to the device {}. " +
991 "Sending subscriber flows.", downstreamMeterId, deviceId);
992
993 ForwardingObjective.Builder downFwd = transparentDownBuilder(uplinkPort, subscriberPort,
994 innerVlan, outerVlan, downstreamMeterId, subInfo);
995
996 flowObjectiveService.forward(deviceId, downFwd.add(new ObjectiveContext() {
997 @Override
998 public void onSuccess(Objective objective) {
999 downFuture.complete(null);
1000 }
1001
1002 @Override
1003 public void onError(Objective objective, ObjectiveError error) {
1004 downFuture.complete(error);
1005 }
1006 }));
1007 } else {
1008 log.warn("Meter installation error while sending upstream flows. " +
1009 "Result {} and MeterId {}", result, downstreamMeterId);
1010 }
1011 });
1012
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001013 additionalVlans.put(cp, new AbstractMap.SimpleEntry(outerVlan, innerVlan));
1014
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001015 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
1016 if (downStatus != null) {
1017 log.error("Flow with innervlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +00001018 "on port {} failed downstream installation: {}",
Gamze Abakaf59c0912019-04-19 08:24:28 +00001019 innerVlan, outerVlan, deviceId, cp, downStatus);
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001020 } else if (upStatus != null) {
1021 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +00001022 "on port {} failed upstream installation: {}",
Gamze Abakaf59c0912019-04-19 08:24:28 +00001023 innerVlan, outerVlan, deviceId, cp, upStatus);
1024 } else {
1025 processEapolFilteringObjectives(deviceId, subscriberPort, subInfo.upstreamBandwidthProfile(),
1026 null, subInfo.cTag(), true);
1027
1028 // cache subscriber info
1029 programmedSubs.put(cp, subInfo);
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001030 }
1031 }, oltInstallers);
1032
1033 }
1034
1035 private ForwardingObjective.Builder transparentDownBuilder(PortNumber uplinkPort,
1036 PortNumber subscriberPort,
1037 VlanId innerVlan,
Gamze Abakaf59c0912019-04-19 08:24:28 +00001038 VlanId outerVlan,
1039 MeterId downstreamMeterId,
1040 SubscriberAndDeviceInformation subInfo) {
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001041 TrafficSelector downstream = DefaultTrafficSelector.builder()
1042 .matchVlanId(outerVlan)
1043 .matchInPort(uplinkPort)
1044 .matchInnerVlanId(innerVlan)
1045 .build();
1046
Gamze Abakaf59c0912019-04-19 08:24:28 +00001047 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1048 if (downstreamMeterId != null) {
1049 tBuilder.meter(downstreamMeterId);
1050 }
1051
1052 TrafficTreatment downstreamTreatment = tBuilder
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001053 .setOutput(subscriberPort)
Gamze Abakaf59c0912019-04-19 08:24:28 +00001054 .writeMetadata(createMetadata(subInfo.cTag(), subInfo.technologyProfileId(), subscriberPort), 0)
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001055 .build();
1056
1057 return DefaultForwardingObjective.builder()
1058 .withFlag(ForwardingObjective.Flag.VERSATILE)
1059 .withPriority(1000)
1060 .makePermanent()
1061 .withSelector(downstream)
1062 .fromApp(appId)
1063 .withTreatment(downstreamTreatment);
1064 }
1065
1066 private ForwardingObjective.Builder transparentUpBuilder(PortNumber uplinkPort,
1067 PortNumber subscriberPort,
1068 VlanId innerVlan,
Gamze Abakaf59c0912019-04-19 08:24:28 +00001069 VlanId outerVlan,
1070 MeterId upstreamMeterId,
1071 SubscriberAndDeviceInformation subInfo) {
1072
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001073 TrafficSelector upstream = DefaultTrafficSelector.builder()
1074 .matchVlanId(outerVlan)
1075 .matchInPort(subscriberPort)
1076 .matchInnerVlanId(innerVlan)
1077 .build();
1078
Gamze Abakaf59c0912019-04-19 08:24:28 +00001079 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1080 if (upstreamMeterId != null) {
1081 tBuilder.meter(upstreamMeterId);
1082 }
1083
1084 TrafficTreatment upstreamTreatment = tBuilder
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001085 .setOutput(uplinkPort)
Gamze Abakaf59c0912019-04-19 08:24:28 +00001086 .writeMetadata(createMetadata(subInfo.sTag(), subInfo.technologyProfileId(), uplinkPort), 0)
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001087 .build();
1088
1089 return DefaultForwardingObjective.builder()
1090 .withFlag(ForwardingObjective.Flag.VERSATILE)
1091 .withPriority(1000)
1092 .makePermanent()
1093 .withSelector(upstream)
1094 .fromApp(appId)
1095 .withTreatment(upstreamTreatment);
1096 }
1097
1098 private void unprovisionTransparentFlows(DeviceId deviceId, PortNumber uplink,
1099 PortNumber subscriberPort, VlanId innerVlan,
1100 VlanId outerVlan) {
1101
1102 ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
1103
Gamze Abakaf59c0912019-04-19 08:24:28 +00001104 SubscriberAndDeviceInformation subInfo = programmedSubs.get(cp);
1105 if (subInfo == null) {
1106 log.warn("Subscriber is not programmed before for the connectPoint {}", cp);
1107 return;
1108 }
1109
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001110 additionalVlans.remove(cp, new AbstractMap.SimpleEntry(outerVlan, innerVlan));
1111
1112 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
1113 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
1114
Gamze Abakaf59c0912019-04-19 08:24:28 +00001115 MeterId upstreamMeterId = getMeterIdFromBpMapping(deviceId, subInfo.upstreamBandwidthProfile());
1116 MeterId downstreamMeterId = getMeterIdFromBpMapping(deviceId, subInfo.downstreamBandwidthProfile());
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001117
Gamze Abakaf59c0912019-04-19 08:24:28 +00001118 ForwardingObjective.Builder upFwd = transparentUpBuilder(uplink, subscriberPort,
1119 innerVlan, outerVlan, upstreamMeterId, subInfo);
1120 ForwardingObjective.Builder downFwd = transparentDownBuilder(uplink, subscriberPort,
1121 innerVlan, outerVlan, downstreamMeterId, subInfo);
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001122
1123 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
1124 @Override
1125 public void onSuccess(Objective objective) {
1126 upFuture.complete(null);
1127 }
1128
1129 @Override
1130 public void onError(Objective objective, ObjectiveError error) {
1131 upFuture.complete(error);
1132 }
1133 }));
1134
1135 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
1136 @Override
1137 public void onSuccess(Objective objective) {
1138 downFuture.complete(null);
1139 }
1140
1141 @Override
1142 public void onError(Objective objective, ObjectiveError error) {
1143 downFuture.complete(error);
1144 }
1145 }));
1146
1147 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
1148 if (downStatus != null) {
1149 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +00001150 "on port {} failed downstream uninstallation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001151 innerVlan, outerVlan, deviceId, subscriberPort, downStatus);
1152 } else if (upStatus != null) {
1153 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +00001154 "on port {} failed upstream uninstallation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001155 innerVlan, outerVlan, deviceId, subscriberPort, upStatus);
1156 }
1157 }, oltInstallers);
1158
Gamze Abakaf59c0912019-04-19 08:24:28 +00001159 //re-install eapol
1160 processEapolFilteringObjectives(deviceId, subscriberPort,
1161 subInfo.upstreamBandwidthProfile(), null, subInfo.cTag(), false);
1162 processEapolFilteringObjectives(deviceId, subscriberPort, defaultBpId,
1163 null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
1164
1165 programmedMeters.remove(MeterKey.key(deviceId, upstreamMeterId));
1166 programmedMeters.remove(MeterKey.key(deviceId, downstreamMeterId));
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001167 }
1168
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001169 private int getDefaultTechProfileId(DeviceId devId, PortNumber portNumber) {
1170 Port port = deviceService.getPort(devId, portNumber);
Andy Bavier160e8682019-05-07 18:32:22 -07001171 if (port != null) {
1172 SubscriberAndDeviceInformation info = subsService.get(port.annotations().value(AnnotationKeys.PORT_NAME));
1173 if (info != null && info.technologyProfileId() != -1) {
1174 return info.technologyProfileId();
1175 }
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001176 }
1177 return defaultTechProfileId;
1178 }
1179
Gamze Abaka838d8142019-02-21 07:06:55 +00001180 /**
Gamze Abakada282b42019-03-11 13:16:48 +00001181 * Returns the write metadata value including tech profile reference and innerVlan.
1182 * For param cVlan, null can be sent
Gamze Abaka838d8142019-02-21 07:06:55 +00001183 *
Gamze Abakada282b42019-03-11 13:16:48 +00001184 * @param cVlan c (customer) tag of one subscriber
Gamze Abaka838d8142019-02-21 07:06:55 +00001185 * @param techProfileId tech profile id of one subscriber
Gamze Abakada282b42019-03-11 13:16:48 +00001186 * @return the write metadata value including tech profile reference and innerVlan
Gamze Abaka838d8142019-02-21 07:06:55 +00001187 */
Gamze Abakada282b42019-03-11 13:16:48 +00001188 private Long createTechProfValueForWm(VlanId cVlan, int techProfileId) {
1189 if (cVlan == null) {
1190 return (long) techProfileId << 32;
1191 }
1192 return ((long) (cVlan.id()) << 48 | (long) techProfileId << 32);
Gamze Abaka838d8142019-02-21 07:06:55 +00001193 }
1194
1195 /**
1196 * Trap eapol authentication packets to the controller.
1197 *
Gamze Abaka33feef52019-02-27 08:16:47 +00001198 * @param devId the device identifier
1199 * @param portNumber the port for which this trap flow is designated
1200 * @param bpId bandwidth profile id to add the related meter to the flow
1201 * @param filterFuture completable future for this filtering objective operation
Gamze Abakada282b42019-03-11 13:16:48 +00001202 * @param vlanId the default or customer tag for a subscriber
Gamze Abaka33feef52019-02-27 08:16:47 +00001203 * @param install true to install the flow, false to remove the flow
Gamze Abaka838d8142019-02-21 07:06:55 +00001204 */
Gamze Abaka33feef52019-02-27 08:16:47 +00001205 private void processEapolFilteringObjectives(DeviceId devId, PortNumber portNumber, String bpId,
1206 CompletableFuture<ObjectiveError> filterFuture,
Gamze Abakada282b42019-03-11 13:16:48 +00001207 VlanId vlanId, boolean install) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001208
1209 if (!enableEapol) {
1210 log.debug("Eapol filtering is disabled.");
1211 if (filterFuture != null) {
1212 filterFuture.complete(null);
1213 }
1214 return;
1215 }
1216
alshabib09753b52016-03-04 14:55:19 -08001217 if (!mastershipService.isLocalMaster(devId)) {
1218 return;
1219 }
alshabibbb83aa22016-02-10 15:08:23 -08001220 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Gamze Abakaad329652018-12-20 10:12:21 +00001221 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
Gamze Abaka33feef52019-02-27 08:16:47 +00001222 CompletableFuture<Object> meterFuture = new CompletableFuture<>();
Gamze Abaka838d8142019-02-21 07:06:55 +00001223 MeterId meterId;
alshabibbb83aa22016-02-10 15:08:23 -08001224
Gamze Abaka838d8142019-02-21 07:06:55 +00001225 BandwidthProfileInformation bpInfo = getBandwidthProfileInformation(bpId);
1226 if (bpInfo != null) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001227 meterId = createMeter(devId, bpInfo, meterFuture);
Gamze Abakaad329652018-12-20 10:12:21 +00001228 treatmentBuilder.meter(meterId);
1229 } else {
Gamze Abaka838d8142019-02-21 07:06:55 +00001230 log.warn("Bandwidth profile {} is not found. Authentication flow will not be installed", bpId);
1231 return;
Gamze Abakaad329652018-12-20 10:12:21 +00001232 }
1233
Gamze Abaka33feef52019-02-27 08:16:47 +00001234 meterFuture.thenAcceptAsync(result -> {
1235 if (result == null) {
1236 log.info("Meter {} for the device {} is installed. " +
1237 "{} EAPOL trap flow", meterId, devId, install ? "Installing " : "Removing ");
1238 int techProfileId = getDefaultTechProfileId(devId, portNumber);
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001239
Gamze Abaka33feef52019-02-27 08:16:47 +00001240 //Authentication trap flow uses only tech profile id as write metadata value
1241 FilteringObjective eapol = (install ? builder.permit() : builder.deny())
1242 .withKey(Criteria.matchInPort(portNumber))
1243 .addCondition(Criteria.matchEthType(EthType.EtherType.EAPOL.ethType()))
Gamze Abakada282b42019-03-11 13:16:48 +00001244 .addCondition(Criteria.matchVlanId(vlanId))
Gamze Abaka33feef52019-02-27 08:16:47 +00001245 .withMeta(treatmentBuilder
Gamze Abakada282b42019-03-11 13:16:48 +00001246 .writeMetadata(createTechProfValueForWm(vlanId, techProfileId), 0)
Gamze Abaka33feef52019-02-27 08:16:47 +00001247 .setOutput(PortNumber.CONTROLLER).build())
1248 .fromApp(appId)
1249 .withPriority(10000)
1250 .add(new ObjectiveContext() {
1251 @Override
1252 public void onSuccess(Objective objective) {
1253 log.info("Eapol filter for {} on {} {} with meter {}.",
1254 devId, portNumber, (install) ? INSTALLED : REMOVED, meterId);
1255 if (filterFuture != null) {
1256 filterFuture.complete(null);
1257 }
1258 }
alshabibdec2e252016-01-15 12:20:25 -08001259
Gamze Abaka33feef52019-02-27 08:16:47 +00001260 @Override
1261 public void onError(Objective objective, ObjectiveError error) {
1262 log.info("Eapol filter for {} on {} with meter {} failed {} because {}",
1263 devId, portNumber, meterId, (install) ? INSTALLATION : REMOVAL,
1264 error);
1265 if (filterFuture != null) {
1266 filterFuture.complete(error);
1267 }
1268 }
1269 });
alshabibdec2e252016-01-15 12:20:25 -08001270
Gamze Abaka33feef52019-02-27 08:16:47 +00001271 flowObjectiveService.filter(devId, eapol);
1272 } else {
1273 log.warn("Meter installation error while sending eapol trap flow. " +
1274 "Result {} and MeterId {}", result, meterId);
1275 }
1276 });
alshabibdec2e252016-01-15 12:20:25 -08001277 }
1278
Jonathan Hart403372d2018-08-22 11:44:13 -07001279 /**
1280 * Installs trap filtering objectives for particular traffic types on an
1281 * NNI port.
1282 *
Gamze Abakaad329652018-12-20 10:12:21 +00001283 * @param devId device ID
1284 * @param port port number
Jonathan Hart403372d2018-08-22 11:44:13 -07001285 * @param install true to install, false to remove
1286 */
1287 private void processNniFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
1288 processLldpFilteringObjective(devId, port, install);
Gamze Abaka33feef52019-02-27 08:16:47 +00001289 processDhcpFilteringObjectives(devId, port, null, -1, install, false);
Jonathan Hart403372d2018-08-22 11:44:13 -07001290 }
1291
1292 private void processLldpFilteringObjective(DeviceId devId, PortNumber port, boolean install) {
1293 if (!mastershipService.isLocalMaster(devId)) {
1294 return;
1295 }
1296 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
1297
1298 FilteringObjective lldp = (install ? builder.permit() : builder.deny())
1299 .withKey(Criteria.matchInPort(port))
1300 .addCondition(Criteria.matchEthType(EthType.EtherType.LLDP.ethType()))
1301 .withMeta(DefaultTrafficTreatment.builder()
1302 .setOutput(PortNumber.CONTROLLER).build())
1303 .fromApp(appId)
1304 .withPriority(10000)
1305 .add(new ObjectiveContext() {
1306 @Override
1307 public void onSuccess(Objective objective) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001308 log.info("LLDP filter for device {} on port {} {}.",
Gamze Abaka838d8142019-02-21 07:06:55 +00001309 devId, port, (install) ? INSTALLED : REMOVED);
Jonathan Hart403372d2018-08-22 11:44:13 -07001310 }
1311
1312 @Override
1313 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001314 log.info("LLDP filter for device {} on port {} failed {} because {}",
Gamze Abaka838d8142019-02-21 07:06:55 +00001315 devId, port, (install) ? INSTALLATION : REMOVAL,
Saurav Das82b8e6d2018-10-04 15:25:12 -07001316 error);
Jonathan Hart403372d2018-08-22 11:44:13 -07001317 }
1318 });
1319
1320 flowObjectiveService.filter(devId, lldp);
1321
1322 }
1323
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001324 /**
1325 * Trap dhcp packets to the controller.
1326 *
Gamze Abaka838d8142019-02-21 07:06:55 +00001327 * @param devId the device identifier
1328 * @param port the port for which this trap flow is designated
1329 * @param upstreamMeterId the upstream meter id that includes the upstream
1330 * bandwidth profile values such as PIR,CIR. If no meter id needs to be referenced,
1331 * null can be sent
1332 * @param techProfileId the technology profile id that is used to create write
1333 * metadata instruction value. If no tech profile id needs to be referenced,
1334 * -1 can be sent
1335 * @param install true to install the flow, false to remove the flow
1336 * @param upstream true if trapped packets are flowing upstream towards
1337 * server, false if packets are flowing downstream towards client
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001338 */
1339 private void processDhcpFilteringObjectives(DeviceId devId, PortNumber port,
Gamze Abaka838d8142019-02-21 07:06:55 +00001340 MeterId upstreamMeterId,
1341 int techProfileId,
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001342 boolean install,
1343 boolean upstream) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001344
1345 if (!enableDhcpOnProvisioning) {
1346 log.debug("Dhcp provisioning is disabled.");
1347 return;
1348 }
1349
Amit Ghosh95e2f652017-08-23 12:49:46 +01001350 if (!mastershipService.isLocalMaster(devId)) {
1351 return;
1352 }
Amit Ghosh95e2f652017-08-23 12:49:46 +01001353
Matteo Scandolo63460d12018-11-02 16:19:04 -07001354 if (enableDhcpV4) {
1355 int udpSrc = (upstream) ? 68 : 67;
1356 int udpDst = (upstream) ? 67 : 68;
1357
1358 EthType ethType = EthType.EtherType.IPV4.ethType();
1359 byte protocol = IPv4.PROTOCOL_UDP;
1360
Gamze Abaka838d8142019-02-21 07:06:55 +00001361 this.addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType,
1362 upstreamMeterId, techProfileId, protocol, install);
Matteo Scandolo63460d12018-11-02 16:19:04 -07001363 }
1364
1365 if (enableDhcpV6) {
1366 int udpSrc = (upstream) ? 547 : 546;
1367 int udpDst = (upstream) ? 546 : 547;
1368
1369 EthType ethType = EthType.EtherType.IPV6.ethType();
1370 byte protocol = IPv6.PROTOCOL_UDP;
1371
Gamze Abaka838d8142019-02-21 07:06:55 +00001372 this.addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType,
1373 upstreamMeterId, techProfileId, protocol, install);
Matteo Scandolo63460d12018-11-02 16:19:04 -07001374 }
1375
1376 }
1377
1378 private void addDhcpFilteringObjectives(DeviceId devId,
1379 PortNumber port,
1380 int udpSrc,
1381 int udpDst,
1382 EthType ethType,
Gamze Abaka838d8142019-02-21 07:06:55 +00001383 MeterId upstreamMeterId,
1384 int techProfileId,
Matteo Scandolo63460d12018-11-02 16:19:04 -07001385 byte protocol,
1386 boolean install) {
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001387
1388 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Gamze Abaka838d8142019-02-21 07:06:55 +00001389 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
1390
1391 if (upstreamMeterId != null) {
1392 treatmentBuilder.meter(upstreamMeterId);
1393 }
1394
1395 if (techProfileId != -1) {
Gamze Abakada282b42019-03-11 13:16:48 +00001396 treatmentBuilder.writeMetadata(createTechProfValueForWm(null, techProfileId), 0);
Gamze Abaka838d8142019-02-21 07:06:55 +00001397 }
1398
Amit Ghosh95e2f652017-08-23 12:49:46 +01001399 FilteringObjective dhcpUpstream = (install ? builder.permit() : builder.deny())
1400 .withKey(Criteria.matchInPort(port))
Matteo Scandolo63460d12018-11-02 16:19:04 -07001401 .addCondition(Criteria.matchEthType(ethType))
1402 .addCondition(Criteria.matchIPProtocol(protocol))
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001403 .addCondition(Criteria.matchUdpSrc(TpPort.tpPort(udpSrc)))
1404 .addCondition(Criteria.matchUdpDst(TpPort.tpPort(udpDst)))
Gamze Abaka838d8142019-02-21 07:06:55 +00001405 .withMeta(treatmentBuilder
Gamze Abaka641fc072018-09-04 09:16:27 +00001406 .setOutput(PortNumber.CONTROLLER).build())
Amit Ghosh95e2f652017-08-23 12:49:46 +01001407 .fromApp(appId)
Matt Jeanneret3f579262018-06-14 17:16:23 -04001408 .withPriority(10000)
Amit Ghosh95e2f652017-08-23 12:49:46 +01001409 .add(new ObjectiveContext() {
1410 @Override
1411 public void onSuccess(Objective objective) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001412 log.info("DHCP {} filter for device {} on port {} {}.",
Gamze Abakaad329652018-12-20 10:12:21 +00001413 (ethType.equals(EthType.EtherType.IPV4.ethType())) ? "v4" : "v6",
Gamze Abaka838d8142019-02-21 07:06:55 +00001414 devId, port, (install) ? INSTALLED : REMOVED);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001415 }
1416
1417 @Override
1418 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001419 log.info("DHCP {} filter for device {} on port {} failed {} because {}",
Gamze Abakaad329652018-12-20 10:12:21 +00001420 (ethType.equals(EthType.EtherType.IPV4.ethType())) ? "v4" : "v6",
Gamze Abaka838d8142019-02-21 07:06:55 +00001421 devId, port, (install) ? INSTALLATION : REMOVAL,
Gamze Abakaad329652018-12-20 10:12:21 +00001422 error);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001423 }
1424 });
1425
1426 flowObjectiveService.filter(devId, dhcpUpstream);
1427 }
1428
Gamze Abaka838d8142019-02-21 07:06:55 +00001429 private void processIgmpFilteringObjectives(DeviceId devId, PortNumber port,
1430 MeterId upstreamMeterId,
1431 int techProfileId,
1432 boolean install) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001433
Gamze Abakaf59c0912019-04-19 08:24:28 +00001434 if (!enableIgmpOnProvisioning) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001435 log.debug("Igmp provisioning is disabled.");
1436 return;
1437 }
1438
Amit Ghosh95e2f652017-08-23 12:49:46 +01001439 if (!mastershipService.isLocalMaster(devId)) {
1440 return;
1441 }
1442
Gamze Abaka641fc072018-09-04 09:16:27 +00001443 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Gamze Abaka838d8142019-02-21 07:06:55 +00001444 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
1445
1446 if (upstreamMeterId != null) {
1447 treatmentBuilder.meter(upstreamMeterId);
1448 }
1449
1450 if (techProfileId != -1) {
Gamze Abakada282b42019-03-11 13:16:48 +00001451 treatmentBuilder.writeMetadata(createTechProfValueForWm(null, techProfileId), 0);
Gamze Abaka838d8142019-02-21 07:06:55 +00001452 }
Amit Ghosh95e2f652017-08-23 12:49:46 +01001453
1454 builder = install ? builder.permit() : builder.deny();
1455
1456 FilteringObjective igmp = builder
1457 .withKey(Criteria.matchInPort(port))
1458 .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
1459 .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_IGMP))
Gamze Abaka838d8142019-02-21 07:06:55 +00001460 .withMeta(treatmentBuilder
Gamze Abaka641fc072018-09-04 09:16:27 +00001461 .setOutput(PortNumber.CONTROLLER).build())
Amit Ghosh95e2f652017-08-23 12:49:46 +01001462 .fromApp(appId)
1463 .withPriority(10000)
1464 .add(new ObjectiveContext() {
1465 @Override
1466 public void onSuccess(Objective objective) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001467 log.info("Igmp filter for {} on {} {}.",
Gamze Abaka838d8142019-02-21 07:06:55 +00001468 devId, port, (install) ? INSTALLED : REMOVED);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001469 }
1470
1471 @Override
1472 public void onError(Objective objective, ObjectiveError error) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001473 log.info("Igmp filter for {} on {} failed {} because {}.",
Gamze Abaka838d8142019-02-21 07:06:55 +00001474 devId, port, (install) ? INSTALLATION : REMOVAL,
Gamze Abaka641fc072018-09-04 09:16:27 +00001475 error);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001476 }
1477 });
1478
1479 flowObjectiveService.filter(devId, igmp);
1480 }
1481
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001482 /**
Jonathan Hart403372d2018-08-22 11:44:13 -07001483 * Creates trap flows for device, including DHCP and LLDP trap on NNI and
1484 * EAPOL trap on the UNIs, if device is present in Sadis config.
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001485 *
1486 * @param dev Device to look for
1487 */
Jonathan Hart403372d2018-08-22 11:44:13 -07001488 private void checkAndCreateDeviceFlows(Device dev) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001489 // we create only for the ones we are master of
1490 if (!mastershipService.isLocalMaster(dev.id())) {
Gamze Abaka641fc072018-09-04 09:16:27 +00001491 return;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001492 }
1493 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +00001494 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Jonathan Hart403372d2018-08-22 11:44:13 -07001495 log.debug("checkAndCreateDeviceFlows: deviceInfo {}", deviceInfo);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001496
1497 if (deviceInfo != null) {
Jonathan Hart403372d2018-08-22 11:44:13 -07001498 // This is an OLT device as per Sadis, we create flows for UNI and NNI ports
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001499 for (Port p : deviceService.getPorts(dev.id())) {
1500 if (isUniPort(dev, p)) {
Gamze Abakada282b42019-03-11 13:16:48 +00001501 processEapolFilteringObjectives(dev.id(), p.number(), defaultBpId, null,
1502 VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
Jonathan Hart403372d2018-08-22 11:44:13 -07001503 } else {
1504 processNniFilteringObjectives(dev.id(), p.number(), true);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001505 }
1506 }
1507 }
1508 }
1509
Jonathan Hart403372d2018-08-22 11:44:13 -07001510
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001511 /**
1512 * Get the uplink for of the OLT device.
Gamze Abakaad329652018-12-20 10:12:21 +00001513 * <p>
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001514 * This assumes that the OLT has a single uplink port. When more uplink ports need to be supported
1515 * this logic needs to be changed
1516 *
1517 * @param dev Device to look for
1518 * @return The uplink Port of the OLT
1519 */
1520 private Port getUplinkPort(Device dev) {
1521 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +00001522 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Saurav Daseae48de2019-06-19 13:26:15 -07001523 log.trace("getUplinkPort: deviceInfo {}", deviceInfo);
Saurav Das82b8e6d2018-10-04 15:25:12 -07001524 if (deviceInfo == null) {
1525 log.warn("Device {} is not configured in SADIS .. cannot fetch device"
1526 + " info", dev.id());
1527 return null;
1528 }
1529 // Return the port that has been configured as the uplink port of this OLT in Sadis
Gamze Abakaad329652018-12-20 10:12:21 +00001530 for (Port p : deviceService.getPorts(dev.id())) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001531 if (p.number().toLong() == deviceInfo.uplinkPort()) {
Saurav Daseae48de2019-06-19 13:26:15 -07001532 log.trace("getUplinkPort: Found port {}", p);
Saurav Das82b8e6d2018-10-04 15:25:12 -07001533 return p;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001534 }
1535 }
1536
Saurav Daseae48de2019-06-19 13:26:15 -07001537 log.warn("getUplinkPort: " + NO_UPLINK_PORT, dev.id());
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001538 return null;
1539 }
1540
1541 /**
1542 * Return the subscriber on a port.
1543 *
Matteo Scandolo962a6ad2018-12-11 15:39:42 -08001544 * @param cp ConnectPoint on which to find the subscriber
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001545 * @return subscriber if found else null
1546 */
Matteo Scandolo962a6ad2018-12-11 15:39:42 -08001547 SubscriberAndDeviceInformation getSubscriber(ConnectPoint cp) {
1548 Port port = deviceService.getPort(cp);
1549 checkNotNull(port, "Invalid connect point");
1550 String portName = port.annotations().value(AnnotationKeys.PORT_NAME);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001551 return subsService.get(portName);
1552 }
1553
Gamze Abakaad329652018-12-20 10:12:21 +00001554 /**
1555 * Write metadata instruction value (metadata) is 8 bytes.
Gamze Abaka838d8142019-02-21 07:06:55 +00001556 * <p>
Gamze Abakaad329652018-12-20 10:12:21 +00001557 * MS 2 bytes: C Tag
1558 * Next 2 bytes: Technology Profile Id
1559 * Next 4 bytes: Port number (uni or nni)
1560 */
1561
1562 private Long createMetadata(VlanId innerVlan, int techProfileId, PortNumber egressPort) {
1563
1564 if (techProfileId == -1) {
1565 techProfileId = DEFAULT_TP_ID;
1566 }
1567
1568 return ((long) (innerVlan.id()) << 48 | (long) techProfileId << 32) | egressPort.toLong();
1569 }
1570
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001571 private boolean isUniPort(Device d, Port p) {
1572 Port ulPort = getUplinkPort(d);
1573 if (ulPort != null) {
1574 return (ulPort.number().toLong() != p.number().toLong());
1575 }
1576 return false;
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001577 }
1578
Jonathan Hart4c538002018-08-23 10:11:54 -07001579 private SubscriberAndDeviceInformation getOltInfo(Device dev) {
1580 String devSerialNo = dev.serialNumber();
Gamze Abaka641fc072018-09-04 09:16:27 +00001581 return subsService.get(devSerialNo);
Jonathan Hart4c538002018-08-23 10:11:54 -07001582 }
1583
Gamze Abaka33feef52019-02-27 08:16:47 +00001584 private MeterId getMeterIdFromBpMapping(DeviceId deviceId, String bandwidthProfile) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001585 if (bpInfoToMeter.get(bandwidthProfile) == null) {
Saurav Daseae48de2019-06-19 13:26:15 -07001586 log.warn("Bandwidth Profile '{}' is not currently mapped to a meter",
1587 bandwidthProfile);
Gamze Abaka33feef52019-02-27 08:16:47 +00001588 return null;
1589 }
1590
1591 Optional<MeterKey> meterKeyForDevice = bpInfoToMeter.get(bandwidthProfile)
1592 .stream()
1593 .filter(meterKey -> meterKey.deviceId().equals(deviceId))
1594 .findFirst();
Saurav Daseae48de2019-06-19 13:26:15 -07001595 if (meterKeyForDevice.isPresent()) {
1596 log.debug("Found meter {} for bandwidth profile {}",
1597 meterKeyForDevice.get().meterId(), bandwidthProfile);
1598 return meterKeyForDevice.get().meterId();
1599 } else {
1600 log.warn("Bandwidth profile '{}' is not currently mapped to a meter",
1601 bandwidthProfile);
1602 return null;
1603 }
Gamze Abaka33feef52019-02-27 08:16:47 +00001604 }
1605
1606 private void addMeterIdToBpMapping(DeviceId deviceId, MeterId meterId, String bandwidthProfile) {
1607
1608 if (bpInfoToMeter.get(bandwidthProfile) == null) {
1609 bpInfoToMeter.put(bandwidthProfile,
1610 new ArrayList<>(Arrays.asList(MeterKey.key(deviceId, meterId))));
1611 } else {
Gamze Abaka33feef52019-02-27 08:16:47 +00001612 List<MeterKey> meterKeyListForBp = bpInfoToMeter.get(bandwidthProfile);
1613 meterKeyListForBp.add(MeterKey.key(deviceId, meterId));
1614 }
1615 }
1616
1617 private void removeMeterIdFromBpMapping(DeviceId deviceId, String bandwidthProfileId) {
1618 List<MeterKey> meterKeysForBp = bpInfoToMeter.get(bandwidthProfileId);
1619 if (meterKeysForBp != null) {
1620 meterKeysForBp.stream()
1621 .filter(meterKey -> meterKey.deviceId().equals(deviceId))
1622 .findFirst().ifPresent(mk -> {
1623 meterKeysForBp.remove(mk);
1624 programmedMeters.remove(mk);
1625 });
1626 }
1627 }
1628
alshabibf0e7e702015-05-30 18:22:36 -07001629 private class InternalDeviceListener implements DeviceListener {
Saurav Dasa9d5f442019-03-06 19:32:48 -08001630 private Set<DeviceId> programmedDevices = Sets.newConcurrentHashSet();
1631
alshabibf0e7e702015-05-30 18:22:36 -07001632 @Override
1633 public void event(DeviceEvent event) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001634 eventExecutor.execute(() -> {
1635 DeviceId devId = event.subject().id();
1636 Device dev = event.subject();
Gamze Abaka838d8142019-02-21 07:06:55 +00001637 Port port = event.port();
Jonathan Hart4c538002018-08-23 10:11:54 -07001638
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001639 if (event.type() == DeviceEvent.Type.PORT_STATS_UPDATED) {
1640 return;
1641 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001642
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001643 if (getOltInfo(dev) == null) {
Saurav Dasa9d5f442019-03-06 19:32:48 -08001644 // it's possible that we got an event for a previously
1645 // programmed OLT that is no longer available in SADIS
1646 // we let such events go through
1647 if (!programmedDevices.contains(devId)) {
1648 log.warn("No device info found for {}, this is either "
1649 + "not an OLT or not known to sadis", dev);
1650 return;
1651 }
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001652 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001653
Saurav Daseae48de2019-06-19 13:26:15 -07001654 log.debug("OLT got {} event for {}: {}", event.type(),
1655 event.subject().id(), event);
Jonathan Hart4c538002018-08-23 10:11:54 -07001656
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001657 switch (event.type()) {
1658 //TODO: Port handling and bookkeeping should be improved once
1659 // olt firmware handles correct behaviour.
1660 case PORT_ADDED:
Gamze Abaka838d8142019-02-21 07:06:55 +00001661 if (isUniPort(dev, port)) {
1662 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, port));
Gamze Abaka838d8142019-02-21 07:06:55 +00001663 if (port.isEnabled()) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001664 processEapolFilteringObjectives(devId, port.number(), defaultBpId,
Gamze Abakada282b42019-03-11 13:16:48 +00001665 null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001666 }
1667 } else {
1668 checkAndCreateDeviceFlows(dev);
1669 }
1670 break;
1671 case PORT_REMOVED:
Gamze Abaka838d8142019-02-21 07:06:55 +00001672 if (isUniPort(dev, port)) {
Gamze Abaka853bf252019-03-25 10:27:06 +00001673 removeSubscriber(new ConnectPoint(devId, port.number()));
Andy Bavier160e8682019-05-07 18:32:22 -07001674 processEapolFilteringObjectives(devId, port.number(), defaultBpId,
1675 null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), false);
1676
Gamze Abaka838d8142019-02-21 07:06:55 +00001677 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, port));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001678 }
1679
1680 break;
1681 case PORT_UPDATED:
Gamze Abaka838d8142019-02-21 07:06:55 +00001682 if (!isUniPort(dev, port)) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001683 break;
1684 }
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001685
Gamze Abakada282b42019-03-11 13:16:48 +00001686 SubscriberAndDeviceInformation sub = programmedSubs
1687 .get(new ConnectPoint(devId, port.number()));
1688 VlanId vlanId = sub == null ? VlanId.vlanId(EAPOL_DEFAULT_VLAN) : sub.cTag();
1689
1690 String bpId = getCurrentBandwidthProfile(new ConnectPoint(devId, port.number()));
1691
Gamze Abaka838d8142019-02-21 07:06:55 +00001692 if (port.isEnabled()) {
Gamze Abakada282b42019-03-11 13:16:48 +00001693 processEapolFilteringObjectives(devId, port.number(), bpId,
1694 null, vlanId, true);
Gamze Abaka33feef52019-02-27 08:16:47 +00001695
Gamze Abaka838d8142019-02-21 07:06:55 +00001696 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, port));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001697 } else {
Gamze Abakada282b42019-03-11 13:16:48 +00001698 processEapolFilteringObjectives(devId, port.number(), bpId,
1699 null, vlanId, false);
Gamze Abaka838d8142019-02-21 07:06:55 +00001700 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, port));
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001701 }
alshabibbb83aa22016-02-10 15:08:23 -08001702 break;
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001703 case DEVICE_ADDED:
alshabib7c190012016-02-09 18:22:33 -08001704 post(new AccessDeviceEvent(
1705 AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
1706 null, null));
Saurav Dasa9d5f442019-03-06 19:32:48 -08001707 programmedDevices.add(devId);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001708 // Send UNI_ADDED events for all existing ports
1709 deviceService.getPorts(devId).stream()
1710 .filter(p -> isUniPort(dev, p))
1711 .filter(Port::isEnabled)
1712 .forEach(p -> post(new AccessDeviceEvent(
1713 AccessDeviceEvent.Type.UNI_ADDED, devId, p)));
1714
Jonathan Hart403372d2018-08-22 11:44:13 -07001715 checkAndCreateDeviceFlows(dev);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001716 break;
1717 case DEVICE_REMOVED:
1718 deviceService.getPorts(devId).stream()
1719 .filter(p -> isUniPort(dev, p))
1720 .forEach(p -> post(new AccessDeviceEvent(
1721 AccessDeviceEvent.Type.UNI_REMOVED, devId, p)));
Saurav Dasa9d5f442019-03-06 19:32:48 -08001722 programmedDevices.remove(devId);
Gamze Abakada282b42019-03-11 13:16:48 +00001723 removeAllSubscribers(devId);
alshabib7c190012016-02-09 18:22:33 -08001724 post(new AccessDeviceEvent(
1725 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
1726 null, null));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001727 break;
1728 case DEVICE_AVAILABILITY_CHANGED:
1729 if (deviceService.isAvailable(devId)) {
1730 post(new AccessDeviceEvent(
1731 AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
1732 null, null));
Gamze Abakada282b42019-03-11 13:16:48 +00001733 programmedDevices.add(devId);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001734 checkAndCreateDeviceFlows(dev);
1735 } else {
Gamze Abakada282b42019-03-11 13:16:48 +00001736 programmedDevices.remove(devId);
1737 removeAllSubscribers(devId);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001738 post(new AccessDeviceEvent(
1739 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
1740 null, null));
1741 }
1742 break;
1743 case DEVICE_UPDATED:
1744 case DEVICE_SUSPENDED:
1745 case PORT_STATS_UPDATED:
1746 default:
1747 return;
1748 }
1749 });
alshabibf0e7e702015-05-30 18:22:36 -07001750 }
Gamze Abaka838d8142019-02-21 07:06:55 +00001751
1752 private String getCurrentBandwidthProfile(ConnectPoint connectPoint) {
1753 SubscriberAndDeviceInformation sub = programmedSubs.get(connectPoint);
1754 if (sub != null) {
1755 return sub.upstreamBandwidthProfile();
1756 }
1757 return defaultBpId;
1758 }
Gamze Abakada282b42019-03-11 13:16:48 +00001759
1760 private void removeAllSubscribers(DeviceId deviceId) {
1761 List<ConnectPoint> connectPoints = programmedSubs.keySet().stream()
1762 .filter(ks -> Objects.equals(ks.deviceId(), deviceId))
1763 .collect(Collectors.toList());
1764
1765 connectPoints.forEach(cp -> programmedSubs.remove(cp));
1766 }
alshabibf0e7e702015-05-30 18:22:36 -07001767 }
Gamze Abaka641fc072018-09-04 09:16:27 +00001768
1769 private class InternalMeterListener implements MeterListener {
1770
1771 @Override
1772 public void event(MeterEvent meterEvent) {
1773 if (deleteMeters && MeterEvent.Type.METER_REFERENCE_COUNT_ZERO.equals(meterEvent.type())) {
Saurav Daseae48de2019-06-19 13:26:15 -07001774 log.debug("Zero Count Meter {} received", meterEvent.subject());
Gamze Abaka641fc072018-09-04 09:16:27 +00001775 Meter meter = meterEvent.subject();
Gamze Abaka33feef52019-02-27 08:16:47 +00001776 if (meter != null && appId.equals(meter.appId()) &&
1777 !programmedMeters.contains(MeterKey.key(meter.deviceId(), meter.id()))) {
Saurav Daseae48de2019-06-19 13:26:15 -07001778 log.info("Deleting unreferenced, no longer programmed Meter {}",
1779 meter.id());
Gamze Abaka641fc072018-09-04 09:16:27 +00001780 deleteMeter(meter.deviceId(), meter.id());
1781 }
1782 } else if (MeterEvent.Type.METER_REMOVED.equals(meterEvent.type())) {
Saurav Daseae48de2019-06-19 13:26:15 -07001783 log.debug("Meter removed event is received. Meter is {}",
1784 meterEvent.subject());
Gamze Abaka641fc072018-09-04 09:16:27 +00001785 removeMeterFromBpMap(meterEvent.subject());
1786 }
1787 }
1788
1789 private void deleteMeter(DeviceId deviceId, MeterId meterId) {
1790 Meter meter = meterService.getMeter(deviceId, meterId);
Gamze Abaka838d8142019-02-21 07:06:55 +00001791 if (meter != null) {
1792 MeterRequest meterRequest = DefaultMeterRequest.builder()
1793 .withBands(meter.bands())
1794 .withUnit(meter.unit())
1795 .forDevice(deviceId)
1796 .fromApp(appId)
1797 .burst()
1798 .remove();
Gamze Abaka641fc072018-09-04 09:16:27 +00001799
Gamze Abaka838d8142019-02-21 07:06:55 +00001800 meterService.withdraw(meterRequest, meterId);
1801 }
Gamze Abaka641fc072018-09-04 09:16:27 +00001802 }
1803
1804 private void removeMeterFromBpMap(Meter meter) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001805 bpInfoToMeter.values().forEach(meterKeys -> meterKeys.stream()
1806 .filter(meterKey -> (meterKey.deviceId().equals(meter.deviceId()))
1807 && meterKey.meterId().equals(meter.id())).findFirst().
1808 ifPresent(mk -> {
1809 meterKeys.remove(mk);
Gamze Abakada282b42019-03-11 13:16:48 +00001810 programmedMeters.remove(mk);
Gamze Abaka33feef52019-02-27 08:16:47 +00001811 log.info("Deleted from the internal map. MeterKey {}", mk);
1812 log.info("Programmed meters {}", programmedMeters);
1813 }));
Gamze Abaka641fc072018-09-04 09:16:27 +00001814 }
1815 }
Hardik Windlass395ff372019-06-13 05:16:00 +00001816}