blob: 9d5240f115fbaea995492d3bbc925ba5549343a7 [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 Das4c1a6a92019-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 Das4c1a6a92019-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 Das4c1a6a92019-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 Das4c1a6a92019-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 Das4c1a6a92019-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 Das4c1a6a92019-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");
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100331 // Find the subscriber on this connect point
Gamze Abaka838d8142019-02-21 07:06:55 +0000332 SubscriberAndDeviceInformation sub = getSubscriber(connectPoint);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100333 if (sub == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000334 log.warn("No subscriber found for {}", connectPoint);
Amit Ghosh31939522018-08-16 13:28:21 +0100335 return false;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100336 }
Jonathan Harte533a422015-10-20 17:31:24 -0700337
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100338 // Get the uplink port
Gamze Abaka838d8142019-02-21 07:06:55 +0000339 Port uplinkPort = getUplinkPort(deviceService.getDevice(deviceId));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100340 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000341 log.warn(NO_UPLINK_PORT, deviceId);
Amit Ghosh31939522018-08-16 13:28:21 +0100342 return false;
Jonathan Harte533a422015-10-20 17:31:24 -0700343 }
344
Saurav Das4c1a6a92019-06-19 13:26:15 -0700345 SubscriberAndDeviceInformation prgSub = programmedSubs.get(connectPoint);
346 if (prgSub != null) {
347 log.warn("Subscriber {} on connectionPoint {} was previously programmed .. "
348 + "taking no action. Note that updating a subscribers params "
349 + "(vlans, bw, tpid etc) requires removing the subscriber"
350 + "before re-provisioning the subscriber", prgSub.id(),
351 connectPoint);
352 return true;
353 }
Gamze Abaka33feef52019-02-27 08:16:47 +0000354
Gamze Abaka838d8142019-02-21 07:06:55 +0000355 //delete Eapol authentication flow with default bandwidth
Gamze Abaka33feef52019-02-27 08:16:47 +0000356 //wait until Eapol rule with defaultBpId is removed to install subscriber-based rules
Saurav Das4c1a6a92019-06-19 13:26:15 -0700357 CompletableFuture<ObjectiveError> filterFuture = new CompletableFuture();
Gamze Abakada282b42019-03-11 13:16:48 +0000358 processEapolFilteringObjectives(deviceId, subscriberPortNo, defaultBpId, filterFuture,
359 VlanId.vlanId(EAPOL_DEFAULT_VLAN), false);
Saurav Das80b6b6c2019-06-27 12:28:06 -0700360 // do not remove meter from bpInfoToMeter mapping as flows for other ONUs
361 // could still be using it - this also prevents duplicate meters from being
362 // created for the same bandwidth profile
363 // we still need to remove from programmedMeters so the meter can be
364 // deleted if its reference count drops to zero
365 removeMeterIdFromPrgMeters(deviceId, defaultBpId);
Gamze Abaka838d8142019-02-21 07:06:55 +0000366
Gamze Abaka33feef52019-02-27 08:16:47 +0000367 //install subscriber flows
368 filterFuture.thenAcceptAsync(filterStatus -> {
369 if (filterStatus == null) {
370 provisionSubscriberBasedFlows(connectPoint, uplinkPort.number(), Optional.empty(), sub);
371 }
372 });
Gamze Abaka838d8142019-02-21 07:06:55 +0000373
Saurav Das82b8e6d2018-10-04 15:25:12 -0700374 // cache subscriber info
Gamze Abaka838d8142019-02-21 07:06:55 +0000375 programmedSubs.put(connectPoint, sub);
Amit Ghosh31939522018-08-16 13:28:21 +0100376 return true;
alshabibb7a9e172016-01-13 11:23:53 -0800377 }
378
379 @Override
Gamze Abaka838d8142019-02-21 07:06:55 +0000380 public boolean removeSubscriber(ConnectPoint connectPoint) {
Saurav Das4c1a6a92019-06-19 13:26:15 -0700381 log.info("Call to un-provision subscriber at {}", connectPoint);
Gamze Abaka838d8142019-02-21 07:06:55 +0000382
Saurav Das4c1a6a92019-06-19 13:26:15 -0700383 // Get the subscriber connected to this port from the local cache
384 // If we don't know about the subscriber there's no need to remove it
Gamze Abaka838d8142019-02-21 07:06:55 +0000385 DeviceId deviceId = connectPoint.deviceId();
386 PortNumber subscriberPortNo = connectPoint.port();
387
388 SubscriberAndDeviceInformation subscriber = programmedSubs.get(connectPoint);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100389 if (subscriber == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000390 log.warn("Subscriber on connectionPoint {} was not previously programmed, " +
391 "no need to remove it", connectPoint);
Matteo Scandolo962a6ad2018-12-11 15:39:42 -0800392 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800393 }
394
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100395 // Get the uplink port
Gamze Abaka838d8142019-02-21 07:06:55 +0000396 Port uplinkPort = getUplinkPort(deviceService.getDevice(deviceId));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100397 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000398 log.warn(NO_UPLINK_PORT, deviceId);
Amit Ghosh31939522018-08-16 13:28:21 +0100399 return false;
alshabib4ceaed32016-03-03 18:00:58 -0800400 }
401
Gamze Abaka33feef52019-02-27 08:16:47 +0000402 //delete dhcp & igmp trap flows
403 MeterId upstreamMeterId = getMeterIdFromBpMapping(deviceId, subscriber.upstreamBandwidthProfile());
Amit Ghosh95e2f652017-08-23 12:49:46 +0100404
Saurav Das4c1a6a92019-06-19 13:26:15 -0700405 // remove dhcp filters
Gamze Abaka33feef52019-02-27 08:16:47 +0000406 processDhcpFilteringObjectives(deviceId, subscriberPortNo,
407 upstreamMeterId, subscriber.technologyProfileId(), false, true);
Gamze Abaka838d8142019-02-21 07:06:55 +0000408
Saurav Das4c1a6a92019-06-19 13:26:15 -0700409 // remove igmp filters
Gamze Abaka33feef52019-02-27 08:16:47 +0000410 processIgmpFilteringObjectives(deviceId, subscriberPortNo,
411 upstreamMeterId, subscriber.technologyProfileId(), false);
alshabibbf23a1f2016-01-14 17:27:11 -0800412
Gamze Abaka33feef52019-02-27 08:16:47 +0000413 //unprovision vlans
414 unprovisionVlans(deviceId, uplinkPort.number(), subscriberPortNo, subscriber, Optional.empty());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100415
416 // Remove if there are any flows for the additional Vlans
Gamze Abaka838d8142019-02-21 07:06:55 +0000417 Collection<? extends Map.Entry<VlanId, VlanId>> vlansList = additionalVlans.get(connectPoint).value();
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100418
419 // Remove the flows for the additional vlans for this subscriber
420 for (Map.Entry<VlanId, VlanId> vlans : vlansList) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000421 unprovisionTransparentFlows(deviceId, uplinkPort.number(), subscriberPortNo,
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100422 vlans.getValue(), vlans.getKey());
423
424 // Remove it from the map also
Gamze Abaka838d8142019-02-21 07:06:55 +0000425 additionalVlans.remove(connectPoint, vlans);
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100426 }
427
Saurav Das4c1a6a92019-06-19 13:26:15 -0700428 // re-install eapol with default bandwidth profile
Gamze Abaka33feef52019-02-27 08:16:47 +0000429 processEapolFilteringObjectives(deviceId, subscriberPortNo,
Gamze Abakada282b42019-03-11 13:16:48 +0000430 subscriber.upstreamBandwidthProfile(), null, subscriber.cTag(), false);
Andy Bavier160e8682019-05-07 18:32:22 -0700431
432 Port port = deviceService.getPort(deviceId, subscriberPortNo);
433 if (port != null && port.isEnabled()) {
434 processEapolFilteringObjectives(deviceId, subscriberPortNo, defaultBpId,
435 null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
Saurav Das4c1a6a92019-06-19 13:26:15 -0700436 } else {
437 log.debug("Port {} is no longer enabled or it's unavailable. Not "
438 + "reprogramming default eapol flow", connectPoint);
Andy Bavier160e8682019-05-07 18:32:22 -0700439 }
Gamze Abaka33feef52019-02-27 08:16:47 +0000440
Gamze Abaka838d8142019-02-21 07:06:55 +0000441 programmedSubs.remove(connectPoint);
Amit Ghosh31939522018-08-16 13:28:21 +0100442 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800443 }
444
Amit Ghosh31939522018-08-16 13:28:21 +0100445 @Override
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100446 public boolean provisionSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag, Optional<VlanId> cTag) {
Gamze Abakaf59c0912019-04-19 08:24:28 +0000447
448 log.info("Provisioning subscriber using subscriberId {}, sTag {}, cTag {}", subscriberId, sTag, cTag);
449
Amit Ghosh31939522018-08-16 13:28:21 +0100450 // Check if we can find the connect point to which this subscriber is connected
451 ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
452 if (subsPort == null) {
453 log.warn("ConnectPoint for {} not found", subscriberId);
454 return false;
455 }
456
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100457 if (!sTag.isPresent() && !cTag.isPresent()) {
458 return provisionSubscriber(subsPort);
459 } else if (sTag.isPresent() && cTag.isPresent()) {
460 Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
461 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000462 log.warn(NO_UPLINK_PORT, subsPort.deviceId());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100463 return false;
464 }
465
Gamze Abakaf59c0912019-04-19 08:24:28 +0000466 CompletableFuture<ObjectiveError> filterFuture = new CompletableFuture();
467
468 //delete Eapol authentication flow with default bandwidth
469 //wait until Eapol rule with defaultBpId is removed to install subscriber-based rules
470 processEapolFilteringObjectives(subsPort.deviceId(), subsPort.port(), defaultBpId, filterFuture,
471 VlanId.vlanId(EAPOL_DEFAULT_VLAN), false);
Saurav Das80b6b6c2019-06-27 12:28:06 -0700472 // do not remove meter from bpInfoToMeter mapping as flows for other ONUs
473 // could still be using it - this also prevents duplicate meters from being
474 // created for the same bandwidth profile
475 // we still need to remove from programmedMeters so the meter can be
476 // deleted if its reference count drops to zero
477 removeMeterIdFromPrgMeters(subsPort.deviceId(), defaultBpId);
Gamze Abakaf59c0912019-04-19 08:24:28 +0000478
479 //install subscriber flows
480 filterFuture.thenAcceptAsync(filterStatus -> {
481 if (filterStatus == null) {
482 provisionTransparentFlows(subsPort.deviceId(), uplinkPort.number(), subsPort.port(),
483 cTag.get(), sTag.get());
484 }
485 });
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100486 return true;
487 } else {
488 log.warn("Provisioning failed for subscriber: {}", subscriberId);
489 return false;
490 }
Amit Ghosh31939522018-08-16 13:28:21 +0100491 }
Amit Ghosh95e2f652017-08-23 12:49:46 +0100492
alshabibe0559672016-02-21 14:49:51 -0800493 @Override
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100494 public boolean removeSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag, Optional<VlanId> cTag) {
Amit Ghosh31939522018-08-16 13:28:21 +0100495 // Check if we can find the connect point to which this subscriber is connected
496 ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
497 if (subsPort == null) {
498 log.warn("ConnectPoint for {} not found", subscriberId);
499 return false;
500 }
501
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100502 if (!sTag.isPresent() && !cTag.isPresent()) {
503 return removeSubscriber(subsPort);
504 } else if (sTag.isPresent() && cTag.isPresent()) {
505 // Get the uplink port
506 Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
507 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000508 log.warn(NO_UPLINK_PORT, subsPort.deviceId());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100509 return false;
510 }
511
512 unprovisionTransparentFlows(subsPort.deviceId(), uplinkPort.number(), subsPort.port(),
513 cTag.get(), sTag.get());
Gamze Abakaf59c0912019-04-19 08:24:28 +0000514
515 programmedSubs.remove(subsPort);
516
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100517 return true;
518 } else {
519 log.warn("Removing subscriber failed for: {}", subscriberId);
520 return false;
521 }
Amit Ghosh31939522018-08-16 13:28:21 +0100522 }
523
524 @Override
525 public Collection<Map.Entry<ConnectPoint, Map.Entry<VlanId, VlanId>>> getSubscribers() {
526 ArrayList<Map.Entry<ConnectPoint, Map.Entry<VlanId, VlanId>>> subs = new ArrayList<>();
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100527
Saurav Das82b8e6d2018-10-04 15:25:12 -0700528 // Get the subscribers for all the devices configured in sadis
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100529 // If the port is UNI, is enabled and exists in Sadis then copy it
530 for (Device d : deviceService.getDevices()) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700531 if (getOltInfo(d) == null) {
532 continue; // not an olt, or not configured in sadis
533 }
Gamze Abakaad329652018-12-20 10:12:21 +0000534 for (Port p : deviceService.getPorts(d.id())) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100535 if (isUniPort(d, p) && p.isEnabled()) {
536 ConnectPoint cp = new ConnectPoint(d.id(), p.number());
537
538 SubscriberAndDeviceInformation sub = getSubscriber(cp);
539 if (sub != null) {
Amit Ghosh31939522018-08-16 13:28:21 +0100540 Map.Entry<VlanId, VlanId> vlans = new AbstractMap.SimpleEntry(sub.sTag(), sub.cTag());
541 subs.add(new AbstractMap.SimpleEntry(cp, vlans));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100542 }
543 }
544 }
545 }
546
547 return subs;
Jonathan Hartfd6c1b32016-03-08 14:09:09 -0800548 }
549
550 @Override
Saurav Das82b8e6d2018-10-04 15:25:12 -0700551 public ImmutableMap<ConnectPoint, SubscriberAndDeviceInformation> getProgSubs() {
552 return ImmutableMap.copyOf(programmedSubs);
553 }
554
555 @Override
Gamze Abaka33feef52019-02-27 08:16:47 +0000556 public ImmutableSet<MeterKey> getProgMeters() {
557 return ImmutableSet.copyOf(programmedMeters);
558 }
559
560 @Override
561 public ImmutableMap<String, List<MeterKey>> getBpMeterMappings() {
562 return ImmutableMap.copyOf(bpInfoToMeter);
563 }
564
565 @Override
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100566 public List<DeviceId> fetchOlts() {
567 // look through all the devices and find the ones that are OLTs as per Sadis
568 List<DeviceId> olts = new ArrayList<>();
569 Iterable<Device> devices = deviceService.getDevices();
570 for (Device d : devices) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700571 if (getOltInfo(d) != null) {
572 // So this is indeed an OLT device
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100573 olts.add(d.id());
574 }
575 }
576 return olts;
alshabibe0559672016-02-21 14:49:51 -0800577 }
578
Amit Ghosh31939522018-08-16 13:28:21 +0100579 /**
580 * Finds the connect point to which a subscriber is connected.
581 *
582 * @param id The id of the subscriber, this is the same ID as in Sadis
583 * @return Subscribers ConnectPoint if found else null
584 */
585 private ConnectPoint findSubscriberConnectPoint(String id) {
586
587 Iterable<Device> devices = deviceService.getDevices();
588 for (Device d : devices) {
589 for (Port p : deviceService.getPorts(d.id())) {
590 log.trace("Comparing {} with {}", p.annotations().value(AnnotationKeys.PORT_NAME), id);
591 if (p.annotations().value(AnnotationKeys.PORT_NAME).equals(id)) {
592 log.debug("Found on device {} port {}", d.id(), p.number());
593 return new ConnectPoint(d.id(), p.number());
594 }
595 }
596 }
597 return null;
598 }
599
Gamze Abaka641fc072018-09-04 09:16:27 +0000600 private BandwidthProfileInformation getBandwidthProfileInformation(String bandwidthProfile) {
601 if (bandwidthProfile == null) {
602 return null;
603 }
604 return bpService.get(bandwidthProfile);
605 }
606
Gamze Abaka838d8142019-02-21 07:06:55 +0000607 /**
Gamze Abaka33feef52019-02-27 08:16:47 +0000608 * Removes subscriber vlan flows.
Gamze Abaka838d8142019-02-21 07:06:55 +0000609 *
610 * @param deviceId the device identifier
611 * @param uplink uplink port of the OLT
612 * @param subscriberPort uni port
613 * @param subscriber subscriber info that includes s, c tags, tech profile and bandwidth profile references
614 * @param defaultVlan default vlan of the subscriber
Gamze Abaka838d8142019-02-21 07:06:55 +0000615 */
Gamze Abaka33feef52019-02-27 08:16:47 +0000616 private void unprovisionVlans(DeviceId deviceId, PortNumber uplink,
617 PortNumber subscriberPort, SubscriberAndDeviceInformation subscriber,
618 Optional<VlanId> defaultVlan) {
Saurav Das4c1a6a92019-06-19 13:26:15 -0700619 log.info("Unprovisioning vlans for subscriber {} on dev/port: {}/{}",
620 subscriber, deviceId, subscriberPort);
alshabibbf23a1f2016-01-14 17:27:11 -0800621
622 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
623 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
624
Gamze Abaka641fc072018-09-04 09:16:27 +0000625 VlanId deviceVlan = subscriber.sTag();
626 VlanId subscriberVlan = subscriber.cTag();
627
Gamze Abaka33feef52019-02-27 08:16:47 +0000628 MeterId upstreamMeterId = getMeterIdFromBpMapping(deviceId, subscriber.upstreamBandwidthProfile());
629 MeterId downstreamMeterId = getMeterIdFromBpMapping(deviceId, subscriber.downstreamBandwidthProfile());
Gamze Abaka641fc072018-09-04 09:16:27 +0000630
alshabib4ceaed32016-03-03 18:00:58 -0800631 ForwardingObjective.Builder upFwd = upBuilder(uplink, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000632 subscriberVlan, deviceVlan,
633 defaultVlan, upstreamMeterId, subscriber.technologyProfileId());
alshabib4ceaed32016-03-03 18:00:58 -0800634 ForwardingObjective.Builder downFwd = downBuilder(uplink, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000635 subscriberVlan, deviceVlan,
636 defaultVlan, downstreamMeterId, subscriber.technologyProfileId());
alshabibbf23a1f2016-01-14 17:27:11 -0800637
alshabib4ceaed32016-03-03 18:00:58 -0800638 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
639 @Override
640 public void onSuccess(Objective objective) {
641 upFuture.complete(null);
642 }
alshabibbf23a1f2016-01-14 17:27:11 -0800643
alshabib4ceaed32016-03-03 18:00:58 -0800644 @Override
645 public void onError(Objective objective, ObjectiveError error) {
646 upFuture.complete(error);
647 }
648 }));
649
650 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
651 @Override
652 public void onSuccess(Objective objective) {
653 downFuture.complete(null);
654 }
655
656 @Override
657 public void onError(Objective objective, ObjectiveError error) {
658 downFuture.complete(error);
659 }
660 }));
alshabibbf23a1f2016-01-14 17:27:11 -0800661
662 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
663 if (upStatus == null && downStatus == null) {
664 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_UNREGISTERED,
Gamze Abaka641fc072018-09-04 09:16:27 +0000665 deviceId,
666 deviceVlan,
667 subscriberVlan));
alshabibbf23a1f2016-01-14 17:27:11 -0800668 } else if (downStatus != null) {
669 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000670 "on port {} failed downstream uninstallation: {}",
671 subscriberVlan, deviceId, subscriberPort, downStatus);
alshabibbf23a1f2016-01-14 17:27:11 -0800672 } else if (upStatus != null) {
673 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000674 "on port {} failed upstream uninstallation: {}",
675 subscriberVlan, deviceId, subscriberPort, upStatus);
alshabibbf23a1f2016-01-14 17:27:11 -0800676 }
677 }, oltInstallers);
alshabibb7a9e172016-01-13 11:23:53 -0800678
Gamze Abaka33feef52019-02-27 08:16:47 +0000679 programmedMeters.remove(MeterKey.key(deviceId, upstreamMeterId));
680 programmedMeters.remove(MeterKey.key(deviceId, downstreamMeterId));
Gamze Abaka838d8142019-02-21 07:06:55 +0000681 log.debug("programmed Meters size {}", programmedMeters.size());
Jonathan Harte533a422015-10-20 17:31:24 -0700682 }
683
Gamze Abaka838d8142019-02-21 07:06:55 +0000684 /**
Gamze Abaka33feef52019-02-27 08:16:47 +0000685 * Adds subscriber vlan flows, dhcp, eapol and igmp trap flows for the related uni port.
Gamze Abaka838d8142019-02-21 07:06:55 +0000686 *
687 * @param port the connection point of the subscriber
688 * @param uplinkPort uplink port of the OLT
689 * @param defaultVlan default vlan of the subscriber
690 * @param sub subscriber information that includes s, c tags, tech profile and bandwidth profile references
Gamze Abaka838d8142019-02-21 07:06:55 +0000691 */
Saurav Das4c1a6a92019-06-19 13:26:15 -0700692 private void provisionSubscriberBasedFlows(ConnectPoint port, PortNumber uplinkPort,
693 Optional<VlanId> defaultVlan,
Gamze Abaka33feef52019-02-27 08:16:47 +0000694 SubscriberAndDeviceInformation sub) {
Gamze Abaka641fc072018-09-04 09:16:27 +0000695
Saurav Das4c1a6a92019-06-19 13:26:15 -0700696 log.info("Provisioning vlans for subscriber {} on dev/port: {}",
697 sub, port);
Gamze Abaka641fc072018-09-04 09:16:27 +0000698
699 DeviceId deviceId = port.deviceId();
700 PortNumber subscriberPort = port.port();
701 VlanId deviceVlan = sub.sTag();
702 VlanId subscriberVlan = sub.cTag();
703 int techProfId = sub.technologyProfileId();
704
705 BandwidthProfileInformation upstreamBpInfo = getBandwidthProfileInformation(sub.upstreamBandwidthProfile());
706 BandwidthProfileInformation downstreamBpInfo = getBandwidthProfileInformation(sub.downstreamBandwidthProfile());
707
alshabib3ea82642016-01-12 18:06:53 -0800708 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
709 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
Gamze Abaka33feef52019-02-27 08:16:47 +0000710 CompletableFuture<Object> upstreamMeterFuture = new CompletableFuture<>();
711 CompletableFuture<Object> downsteamMeterFuture = new CompletableFuture<>();
alshabib3ea82642016-01-12 18:06:53 -0800712
Gamze Abaka33feef52019-02-27 08:16:47 +0000713 MeterId upstreamMeterId = createMeter(deviceId, upstreamBpInfo, upstreamMeterFuture);
714 MeterId downstreamMeterId = createMeter(deviceId, downstreamBpInfo, downsteamMeterFuture);
Jonathan Harte533a422015-10-20 17:31:24 -0700715
Gamze Abaka33feef52019-02-27 08:16:47 +0000716 //install upstream flows
717 upstreamMeterFuture.thenAcceptAsync(result -> {
718 if (result == null) {
Saurav Das4c1a6a92019-06-19 13:26:15 -0700719 log.info("Upstream Meter {} is in the device {}. " +
Gamze Abaka33feef52019-02-27 08:16:47 +0000720 "Sending subscriber flows.", upstreamMeterId, deviceId);
721 ForwardingObjective.Builder upFwd = upBuilder(uplinkPort, subscriberPort,
722 subscriberVlan, deviceVlan,
723 defaultVlan, upstreamMeterId, techProfId);
alshabib3ea82642016-01-12 18:06:53 -0800724
Gamze Abaka33feef52019-02-27 08:16:47 +0000725
726 flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
727 @Override
728 public void onSuccess(Objective objective) {
729 upFuture.complete(null);
730 }
731
732 @Override
733 public void onError(Objective objective, ObjectiveError error) {
734 upFuture.complete(error);
735 }
736 }));
737 } else {
738 log.warn("Meter installation error while sending upstream flows. " +
739 "Result {} and MeterId {}", result, upstreamMeterId);
alshabibbf23a1f2016-01-14 17:27:11 -0800740 }
Gamze Abaka33feef52019-02-27 08:16:47 +0000741 });
alshabibbf23a1f2016-01-14 17:27:11 -0800742
Gamze Abaka33feef52019-02-27 08:16:47 +0000743 //install downstream flows
744 downsteamMeterFuture.thenAcceptAsync(result -> {
745 if (result == null) {
Saurav Das4c1a6a92019-06-19 13:26:15 -0700746 log.info("Downstream Meter {} is in the device {}. " +
Gamze Abaka33feef52019-02-27 08:16:47 +0000747 "Sending subscriber flows.", downstreamMeterId, deviceId);
748 ForwardingObjective.Builder downFwd = downBuilder(uplinkPort, subscriberPort,
749 subscriberVlan, deviceVlan,
750 defaultVlan, downstreamMeterId, techProfId);
751
752 flowObjectiveService.forward(deviceId, downFwd.add(new ObjectiveContext() {
753 @Override
754 public void onSuccess(Objective objective) {
755 downFuture.complete(null);
756 }
757
758 @Override
759 public void onError(Objective objective, ObjectiveError error) {
760 downFuture.complete(error);
761 }
762 }));
763 } else {
764 log.warn("Meter installation error while sending downstream flows. " +
765 "Result {} and MeterId {}", result, downstreamMeterId);
alshabibbf23a1f2016-01-14 17:27:11 -0800766 }
Gamze Abaka33feef52019-02-27 08:16:47 +0000767 });
alshabibbf23a1f2016-01-14 17:27:11 -0800768
Gamze Abaka33feef52019-02-27 08:16:47 +0000769 //send eapol & dhcp & igmp flows
770 //send Subscriber Registered event
alshabib3ea82642016-01-12 18:06:53 -0800771 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
772 if (upStatus == null && downStatus == null) {
Gamze Abaka33feef52019-02-27 08:16:47 +0000773
774 if (upstreamMeterId != null) {
775 //re-install Eapol authentication flow with the subscribers' upstream bandwidth profile
776 processEapolFilteringObjectives(deviceId, subscriberPort, sub.upstreamBandwidthProfile(),
Gamze Abakada282b42019-03-11 13:16:48 +0000777 null, sub.cTag(), true);
Gamze Abaka33feef52019-02-27 08:16:47 +0000778
779 processDhcpFilteringObjectives(deviceId, subscriberPort,
780 upstreamMeterId, sub.technologyProfileId(), true, true);
781
782 processIgmpFilteringObjectives(deviceId, subscriberPort,
783 upstreamMeterId, sub.technologyProfileId(), true);
784 }
785
alshabib3ea82642016-01-12 18:06:53 -0800786 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_REGISTERED,
Gamze Abaka641fc072018-09-04 09:16:27 +0000787 deviceId,
788 deviceVlan,
789 subscriberVlan));
alshabib50d9fc52016-02-12 15:47:20 -0800790
alshabib3ea82642016-01-12 18:06:53 -0800791 } else if (downStatus != null) {
792 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000793 "on port {} failed downstream installation: {}",
794 subscriberVlan, deviceId, subscriberPort, downStatus);
alshabib3ea82642016-01-12 18:06:53 -0800795 } else if (upStatus != null) {
796 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000797 "on port {} failed upstream installation: {}",
798 subscriberVlan, deviceId, subscriberPort, upStatus);
alshabib3ea82642016-01-12 18:06:53 -0800799 }
800 }, oltInstallers);
Jonathan Harte533a422015-10-20 17:31:24 -0700801 }
802
Gamze Abaka33feef52019-02-27 08:16:47 +0000803 private MeterId createMeter(DeviceId deviceId, BandwidthProfileInformation bpInfo,
804 CompletableFuture<Object> meterFuture) {
Gamze Abaka641fc072018-09-04 09:16:27 +0000805 if (bpInfo == null) {
Saurav Das4c1a6a92019-06-19 13:26:15 -0700806 log.warn("Bandwidth profile information cannot be null when creating meter");
Gamze Abaka641fc072018-09-04 09:16:27 +0000807 return null;
808 }
809
Gamze Abaka33feef52019-02-27 08:16:47 +0000810 MeterId meterId = getMeterIdFromBpMapping(deviceId, bpInfo.id());
Gamze Abaka641fc072018-09-04 09:16:27 +0000811 if (meterId != null) {
Saurav Das4c1a6a92019-06-19 13:26:15 -0700812 log.debug("Meter {} was previously created for bp {}", meterId,
813 bpInfo.id());
Gamze Abaka33feef52019-02-27 08:16:47 +0000814 meterFuture.complete(null);
Gamze Abaka641fc072018-09-04 09:16:27 +0000815 return meterId;
816 }
817
818 List<Band> meterBands = createMeterBands(bpInfo);
819
820 MeterRequest meterRequest = DefaultMeterRequest.builder()
821 .withBands(meterBands)
822 .withUnit(Meter.Unit.KB_PER_SEC)
Gamze Abaka33feef52019-02-27 08:16:47 +0000823 .withContext(new MeterContext() {
824 @Override
825 public void onSuccess(MeterRequest op) {
Saurav Das4c1a6a92019-06-19 13:26:15 -0700826 log.debug("meter addition confirmed for bpInfo:{}", bpInfo);
Gamze Abaka33feef52019-02-27 08:16:47 +0000827 meterFuture.complete(null);
828 }
829
830 @Override
831 public void onError(MeterRequest op, MeterFailReason reason) {
832 meterFuture.complete(reason);
833 }
834 })
Gamze Abaka641fc072018-09-04 09:16:27 +0000835 .forDevice(deviceId)
836 .fromApp(appId)
837 .burst()
838 .add();
839
840 Meter meter = meterService.submit(meterRequest);
Gamze Abaka33feef52019-02-27 08:16:47 +0000841 addMeterIdToBpMapping(deviceId, meter.id(), bpInfo.id());
Saurav Das4c1a6a92019-06-19 13:26:15 -0700842 log.info("Meter creation message sent for Meter Id {}", meter.id());
Gamze Abaka33feef52019-02-27 08:16:47 +0000843 programmedMeters.add(MeterKey.key(deviceId, meter.id()));
Gamze Abaka641fc072018-09-04 09:16:27 +0000844 return meter.id();
845 }
846
847 private List<Band> createMeterBands(BandwidthProfileInformation bpInfo) {
848 List<Band> meterBands = new ArrayList<>();
849
850 meterBands.add(createMeterBand(bpInfo.committedInformationRate(), bpInfo.committedBurstSize()));
851 meterBands.add(createMeterBand(bpInfo.exceededInformationRate(), bpInfo.exceededBurstSize()));
Gamze Abakaad329652018-12-20 10:12:21 +0000852 meterBands.add(createMeterBand(bpInfo.assuredInformationRate(), 0L));
Gamze Abaka641fc072018-09-04 09:16:27 +0000853
Gamze Abaka641fc072018-09-04 09:16:27 +0000854 return meterBands;
855 }
856
857 private Band createMeterBand(long rate, Long burst) {
858 return DefaultBand.builder()
859 .withRate(rate) //already Kbps
860 .burstSize(burst) // already Kbits
861 .ofType(Band.Type.DROP) // no matter
862 .build();
863 }
864
alshabib4ceaed32016-03-03 18:00:58 -0800865 private ForwardingObjective.Builder downBuilder(PortNumber uplinkPort,
866 PortNumber subscriberPort,
867 VlanId subscriberVlan,
868 VlanId deviceVlan,
Gamze Abaka641fc072018-09-04 09:16:27 +0000869 Optional<VlanId> defaultVlan,
870 MeterId meterId,
871 int techProfId) {
alshabib4ceaed32016-03-03 18:00:58 -0800872 TrafficSelector downstream = DefaultTrafficSelector.builder()
873 .matchVlanId(deviceVlan)
874 .matchInPort(uplinkPort)
875 .matchInnerVlanId(subscriberVlan)
876 .build();
877
Gamze Abaka641fc072018-09-04 09:16:27 +0000878 TrafficTreatment.Builder downstreamTreatmentBuilder = DefaultTrafficTreatment.builder()
alshabib4ceaed32016-03-03 18:00:58 -0800879 .popVlan()
880 .setVlanId(defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan)))
Gamze Abaka641fc072018-09-04 09:16:27 +0000881 .setOutput(subscriberPort);
882
883 if (meterId != null) {
884 downstreamTreatmentBuilder.meter(meterId);
885 }
886
Gamze Abakaad329652018-12-20 10:12:21 +0000887 downstreamTreatmentBuilder.writeMetadata(createMetadata(subscriberVlan, techProfId, subscriberPort), 0);
alshabib4ceaed32016-03-03 18:00:58 -0800888
889 return DefaultForwardingObjective.builder()
890 .withFlag(ForwardingObjective.Flag.VERSATILE)
891 .withPriority(1000)
892 .makePermanent()
893 .withSelector(downstream)
894 .fromApp(appId)
Gamze Abaka641fc072018-09-04 09:16:27 +0000895 .withTreatment(downstreamTreatmentBuilder.build());
alshabib4ceaed32016-03-03 18:00:58 -0800896 }
897
898 private ForwardingObjective.Builder upBuilder(PortNumber uplinkPort,
899 PortNumber subscriberPort,
900 VlanId subscriberVlan,
901 VlanId deviceVlan,
Gamze Abaka641fc072018-09-04 09:16:27 +0000902 Optional<VlanId> defaultVlan,
903 MeterId meterId,
904 int technologyProfileId) {
905
906
907 VlanId dVlan = defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan));
908
909 if (subscriberVlan.toShort() == 4096) {
910 dVlan = subscriberVlan;
911 }
912
alshabib4ceaed32016-03-03 18:00:58 -0800913 TrafficSelector upstream = DefaultTrafficSelector.builder()
Gamze Abaka641fc072018-09-04 09:16:27 +0000914 .matchVlanId(dVlan)
alshabib4ceaed32016-03-03 18:00:58 -0800915 .matchInPort(subscriberPort)
916 .build();
917
918
Gamze Abaka641fc072018-09-04 09:16:27 +0000919 TrafficTreatment.Builder upstreamTreatmentBuilder = DefaultTrafficTreatment.builder()
alshabib4ceaed32016-03-03 18:00:58 -0800920 .pushVlan()
921 .setVlanId(subscriberVlan)
922 .pushVlan()
923 .setVlanId(deviceVlan)
Gamze Abaka641fc072018-09-04 09:16:27 +0000924 .setOutput(uplinkPort);
925
926 if (meterId != null) {
927 upstreamTreatmentBuilder.meter(meterId);
928 }
929
Gamze Abakaad329652018-12-20 10:12:21 +0000930 upstreamTreatmentBuilder.writeMetadata(createMetadata(deviceVlan, technologyProfileId, uplinkPort), 0L);
alshabib4ceaed32016-03-03 18:00:58 -0800931
932 return DefaultForwardingObjective.builder()
933 .withFlag(ForwardingObjective.Flag.VERSATILE)
934 .withPriority(1000)
935 .makePermanent()
936 .withSelector(upstream)
937 .fromApp(appId)
Gamze Abaka641fc072018-09-04 09:16:27 +0000938 .withTreatment(upstreamTreatmentBuilder.build());
alshabib4ceaed32016-03-03 18:00:58 -0800939 }
Gamze Abakaad329652018-12-20 10:12:21 +0000940
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100941 private void provisionTransparentFlows(DeviceId deviceId, PortNumber uplinkPort,
942 PortNumber subscriberPort,
943 VlanId innerVlan,
944 VlanId outerVlan) {
945
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100946 ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
947
Gamze Abakaf59c0912019-04-19 08:24:28 +0000948 SubscriberAndDeviceInformation subInfo = getSubscriber(cp);
949
950 BandwidthProfileInformation upstreamBpInfo = getBandwidthProfileInformation(
951 subInfo.upstreamBandwidthProfile());
952 BandwidthProfileInformation downstreamBpInfo = getBandwidthProfileInformation(
953 subInfo.downstreamBandwidthProfile());
954
955 CompletableFuture<Object> upstreamMeterFuture = new CompletableFuture<>();
956 CompletableFuture<Object> downsteamMeterFuture = new CompletableFuture<>();
957 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
958 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
959
960 MeterId upstreamMeterId = createMeter(deviceId, upstreamBpInfo, upstreamMeterFuture);
961 MeterId downstreamMeterId = createMeter(deviceId, downstreamBpInfo, downsteamMeterFuture);
962
963 upstreamMeterFuture.thenAcceptAsync(result -> {
964 if (result == null) {
965 log.info("Upstream Meter {} is sent to the device {}. " +
966 "Sending subscriber flows.", upstreamMeterId, deviceId);
967
968 ForwardingObjective.Builder upFwd = transparentUpBuilder(uplinkPort, subscriberPort,
969 innerVlan, outerVlan, upstreamMeterId, subInfo);
970
971 flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
972 @Override
973 public void onSuccess(Objective objective) {
974 upFuture.complete(null);
975 }
976
977 @Override
978 public void onError(Objective objective, ObjectiveError error) {
979 upFuture.complete(error);
980 }
981 }));
982
983 } else {
984 log.warn("Meter installation error while sending upstream flows. " +
985 "Result {} and MeterId {}", result, upstreamMeterId);
986 }
987 });
988
989 downsteamMeterFuture.thenAcceptAsync(result -> {
990 if (result == null) {
991 log.info("Downstream Meter {} is sent to the device {}. " +
992 "Sending subscriber flows.", downstreamMeterId, deviceId);
993
994 ForwardingObjective.Builder downFwd = transparentDownBuilder(uplinkPort, subscriberPort,
995 innerVlan, outerVlan, downstreamMeterId, subInfo);
996
997 flowObjectiveService.forward(deviceId, downFwd.add(new ObjectiveContext() {
998 @Override
999 public void onSuccess(Objective objective) {
1000 downFuture.complete(null);
1001 }
1002
1003 @Override
1004 public void onError(Objective objective, ObjectiveError error) {
1005 downFuture.complete(error);
1006 }
1007 }));
1008 } else {
1009 log.warn("Meter installation error while sending upstream flows. " +
1010 "Result {} and MeterId {}", result, downstreamMeterId);
1011 }
1012 });
1013
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001014 additionalVlans.put(cp, new AbstractMap.SimpleEntry(outerVlan, innerVlan));
1015
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001016 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
1017 if (downStatus != null) {
1018 log.error("Flow with innervlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +00001019 "on port {} failed downstream installation: {}",
Gamze Abakaf59c0912019-04-19 08:24:28 +00001020 innerVlan, outerVlan, deviceId, cp, downStatus);
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001021 } else if (upStatus != null) {
1022 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +00001023 "on port {} failed upstream installation: {}",
Gamze Abakaf59c0912019-04-19 08:24:28 +00001024 innerVlan, outerVlan, deviceId, cp, upStatus);
1025 } else {
1026 processEapolFilteringObjectives(deviceId, subscriberPort, subInfo.upstreamBandwidthProfile(),
1027 null, subInfo.cTag(), true);
1028
1029 // cache subscriber info
1030 programmedSubs.put(cp, subInfo);
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001031 }
1032 }, oltInstallers);
1033
1034 }
1035
1036 private ForwardingObjective.Builder transparentDownBuilder(PortNumber uplinkPort,
1037 PortNumber subscriberPort,
1038 VlanId innerVlan,
Gamze Abakaf59c0912019-04-19 08:24:28 +00001039 VlanId outerVlan,
1040 MeterId downstreamMeterId,
1041 SubscriberAndDeviceInformation subInfo) {
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001042 TrafficSelector downstream = DefaultTrafficSelector.builder()
1043 .matchVlanId(outerVlan)
1044 .matchInPort(uplinkPort)
1045 .matchInnerVlanId(innerVlan)
1046 .build();
1047
Gamze Abakaf59c0912019-04-19 08:24:28 +00001048 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1049 if (downstreamMeterId != null) {
1050 tBuilder.meter(downstreamMeterId);
1051 }
1052
1053 TrafficTreatment downstreamTreatment = tBuilder
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001054 .setOutput(subscriberPort)
Gamze Abakaf59c0912019-04-19 08:24:28 +00001055 .writeMetadata(createMetadata(subInfo.cTag(), subInfo.technologyProfileId(), subscriberPort), 0)
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001056 .build();
1057
1058 return DefaultForwardingObjective.builder()
1059 .withFlag(ForwardingObjective.Flag.VERSATILE)
1060 .withPriority(1000)
1061 .makePermanent()
1062 .withSelector(downstream)
1063 .fromApp(appId)
1064 .withTreatment(downstreamTreatment);
1065 }
1066
1067 private ForwardingObjective.Builder transparentUpBuilder(PortNumber uplinkPort,
1068 PortNumber subscriberPort,
1069 VlanId innerVlan,
Gamze Abakaf59c0912019-04-19 08:24:28 +00001070 VlanId outerVlan,
1071 MeterId upstreamMeterId,
1072 SubscriberAndDeviceInformation subInfo) {
1073
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001074 TrafficSelector upstream = DefaultTrafficSelector.builder()
1075 .matchVlanId(outerVlan)
1076 .matchInPort(subscriberPort)
1077 .matchInnerVlanId(innerVlan)
1078 .build();
1079
Gamze Abakaf59c0912019-04-19 08:24:28 +00001080 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1081 if (upstreamMeterId != null) {
1082 tBuilder.meter(upstreamMeterId);
1083 }
1084
1085 TrafficTreatment upstreamTreatment = tBuilder
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001086 .setOutput(uplinkPort)
Gamze Abakaf59c0912019-04-19 08:24:28 +00001087 .writeMetadata(createMetadata(subInfo.sTag(), subInfo.technologyProfileId(), uplinkPort), 0)
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001088 .build();
1089
1090 return DefaultForwardingObjective.builder()
1091 .withFlag(ForwardingObjective.Flag.VERSATILE)
1092 .withPriority(1000)
1093 .makePermanent()
1094 .withSelector(upstream)
1095 .fromApp(appId)
1096 .withTreatment(upstreamTreatment);
1097 }
1098
1099 private void unprovisionTransparentFlows(DeviceId deviceId, PortNumber uplink,
1100 PortNumber subscriberPort, VlanId innerVlan,
1101 VlanId outerVlan) {
1102
1103 ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
1104
Gamze Abakaf59c0912019-04-19 08:24:28 +00001105 SubscriberAndDeviceInformation subInfo = programmedSubs.get(cp);
1106 if (subInfo == null) {
1107 log.warn("Subscriber is not programmed before for the connectPoint {}", cp);
1108 return;
1109 }
1110
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001111 additionalVlans.remove(cp, new AbstractMap.SimpleEntry(outerVlan, innerVlan));
1112
1113 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
1114 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
1115
Gamze Abakaf59c0912019-04-19 08:24:28 +00001116 MeterId upstreamMeterId = getMeterIdFromBpMapping(deviceId, subInfo.upstreamBandwidthProfile());
1117 MeterId downstreamMeterId = getMeterIdFromBpMapping(deviceId, subInfo.downstreamBandwidthProfile());
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001118
Gamze Abakaf59c0912019-04-19 08:24:28 +00001119 ForwardingObjective.Builder upFwd = transparentUpBuilder(uplink, subscriberPort,
1120 innerVlan, outerVlan, upstreamMeterId, subInfo);
1121 ForwardingObjective.Builder downFwd = transparentDownBuilder(uplink, subscriberPort,
1122 innerVlan, outerVlan, downstreamMeterId, subInfo);
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001123
1124 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
1125 @Override
1126 public void onSuccess(Objective objective) {
1127 upFuture.complete(null);
1128 }
1129
1130 @Override
1131 public void onError(Objective objective, ObjectiveError error) {
1132 upFuture.complete(error);
1133 }
1134 }));
1135
1136 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
1137 @Override
1138 public void onSuccess(Objective objective) {
1139 downFuture.complete(null);
1140 }
1141
1142 @Override
1143 public void onError(Objective objective, ObjectiveError error) {
1144 downFuture.complete(error);
1145 }
1146 }));
1147
1148 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
1149 if (downStatus != null) {
1150 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +00001151 "on port {} failed downstream uninstallation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001152 innerVlan, outerVlan, deviceId, subscriberPort, downStatus);
1153 } else if (upStatus != null) {
1154 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +00001155 "on port {} failed upstream uninstallation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001156 innerVlan, outerVlan, deviceId, subscriberPort, upStatus);
1157 }
1158 }, oltInstallers);
1159
Gamze Abakaf59c0912019-04-19 08:24:28 +00001160 //re-install eapol
1161 processEapolFilteringObjectives(deviceId, subscriberPort,
1162 subInfo.upstreamBandwidthProfile(), null, subInfo.cTag(), false);
1163 processEapolFilteringObjectives(deviceId, subscriberPort, defaultBpId,
1164 null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
1165
1166 programmedMeters.remove(MeterKey.key(deviceId, upstreamMeterId));
1167 programmedMeters.remove(MeterKey.key(deviceId, downstreamMeterId));
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001168 }
1169
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001170 private int getDefaultTechProfileId(DeviceId devId, PortNumber portNumber) {
1171 Port port = deviceService.getPort(devId, portNumber);
Andy Bavier160e8682019-05-07 18:32:22 -07001172 if (port != null) {
1173 SubscriberAndDeviceInformation info = subsService.get(port.annotations().value(AnnotationKeys.PORT_NAME));
1174 if (info != null && info.technologyProfileId() != -1) {
1175 return info.technologyProfileId();
1176 }
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001177 }
1178 return defaultTechProfileId;
1179 }
1180
Gamze Abaka838d8142019-02-21 07:06:55 +00001181 /**
Gamze Abakada282b42019-03-11 13:16:48 +00001182 * Returns the write metadata value including tech profile reference and innerVlan.
1183 * For param cVlan, null can be sent
Gamze Abaka838d8142019-02-21 07:06:55 +00001184 *
Gamze Abakada282b42019-03-11 13:16:48 +00001185 * @param cVlan c (customer) tag of one subscriber
Gamze Abaka838d8142019-02-21 07:06:55 +00001186 * @param techProfileId tech profile id of one subscriber
Gamze Abakada282b42019-03-11 13:16:48 +00001187 * @return the write metadata value including tech profile reference and innerVlan
Gamze Abaka838d8142019-02-21 07:06:55 +00001188 */
Gamze Abakada282b42019-03-11 13:16:48 +00001189 private Long createTechProfValueForWm(VlanId cVlan, int techProfileId) {
1190 if (cVlan == null) {
1191 return (long) techProfileId << 32;
1192 }
1193 return ((long) (cVlan.id()) << 48 | (long) techProfileId << 32);
Gamze Abaka838d8142019-02-21 07:06:55 +00001194 }
1195
1196 /**
1197 * Trap eapol authentication packets to the controller.
1198 *
Gamze Abaka33feef52019-02-27 08:16:47 +00001199 * @param devId the device identifier
1200 * @param portNumber the port for which this trap flow is designated
1201 * @param bpId bandwidth profile id to add the related meter to the flow
1202 * @param filterFuture completable future for this filtering objective operation
Gamze Abakada282b42019-03-11 13:16:48 +00001203 * @param vlanId the default or customer tag for a subscriber
Gamze Abaka33feef52019-02-27 08:16:47 +00001204 * @param install true to install the flow, false to remove the flow
Gamze Abaka838d8142019-02-21 07:06:55 +00001205 */
Gamze Abaka33feef52019-02-27 08:16:47 +00001206 private void processEapolFilteringObjectives(DeviceId devId, PortNumber portNumber, String bpId,
1207 CompletableFuture<ObjectiveError> filterFuture,
Gamze Abakada282b42019-03-11 13:16:48 +00001208 VlanId vlanId, boolean install) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001209 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<>();
alshabibbb83aa22016-02-10 15:08:23 -08001223
Gamze Abaka838d8142019-02-21 07:06:55 +00001224 BandwidthProfileInformation bpInfo = getBandwidthProfileInformation(bpId);
Saurav Das80b6b6c2019-06-27 12:28:06 -07001225 if (bpInfo == null) {
1226 log.warn("Bandwidth profile {} is not found. Authentication flow"
1227 + " will not be installed", bpId);
Gamze Abaka838d8142019-02-21 07:06:55 +00001228 return;
Gamze Abakaad329652018-12-20 10:12:21 +00001229 }
1230
Saurav Das80b6b6c2019-06-27 12:28:06 -07001231 // check if meter exists and create it only for an install
1232 MeterId meterId = getMeterIdFromBpMapping(devId, bpInfo.id());
1233 if (meterId == null) {
1234 if (install) {
1235 meterId = createMeter(devId, bpInfo, meterFuture);
1236 treatmentBuilder.meter(meterId);
1237 } else {
1238 // this case should not happen as the request to remove an eapol
1239 // flow should mean that the flow points to a meter that exists.
1240 // Nevertheless we can still delete the flow as we only need the
1241 // correct 'match' to do so.
1242 log.warn("Unknown meter id for bp {}, still proceeding with "
1243 + "delete of eapol flow for {}/{}", bpInfo.id(), devId,
1244 portNumber);
1245 meterFuture.complete(null);
1246 }
1247 } else {
1248 log.debug("Meter {} was previously created for bp {}", meterId,
1249 bpInfo.id());
1250 treatmentBuilder.meter(meterId);
1251 meterFuture.complete(null);
1252 }
1253
1254 final MeterId mId = meterId;
Gamze Abaka33feef52019-02-27 08:16:47 +00001255 meterFuture.thenAcceptAsync(result -> {
1256 if (result == null) {
Saurav Das80b6b6c2019-06-27 12:28:06 -07001257 log.info("Meter {} for {} on {}/{} exists. {} EAPOL trap flow",
1258 mId, bpId, devId, portNumber,
1259 (install) ? "Installing " : "Removing ");
Gamze Abaka33feef52019-02-27 08:16:47 +00001260 int techProfileId = getDefaultTechProfileId(devId, portNumber);
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001261
Gamze Abaka33feef52019-02-27 08:16:47 +00001262 //Authentication trap flow uses only tech profile id as write metadata value
1263 FilteringObjective eapol = (install ? builder.permit() : builder.deny())
1264 .withKey(Criteria.matchInPort(portNumber))
1265 .addCondition(Criteria.matchEthType(EthType.EtherType.EAPOL.ethType()))
Gamze Abakada282b42019-03-11 13:16:48 +00001266 .addCondition(Criteria.matchVlanId(vlanId))
Gamze Abaka33feef52019-02-27 08:16:47 +00001267 .withMeta(treatmentBuilder
Gamze Abakada282b42019-03-11 13:16:48 +00001268 .writeMetadata(createTechProfValueForWm(vlanId, techProfileId), 0)
Gamze Abaka33feef52019-02-27 08:16:47 +00001269 .setOutput(PortNumber.CONTROLLER).build())
1270 .fromApp(appId)
1271 .withPriority(10000)
1272 .add(new ObjectiveContext() {
1273 @Override
1274 public void onSuccess(Objective objective) {
1275 log.info("Eapol filter for {} on {} {} with meter {}.",
Saurav Das80b6b6c2019-06-27 12:28:06 -07001276 devId, portNumber, (install) ? INSTALLED : REMOVED, mId);
Gamze Abaka33feef52019-02-27 08:16:47 +00001277 if (filterFuture != null) {
1278 filterFuture.complete(null);
1279 }
1280 }
alshabibdec2e252016-01-15 12:20:25 -08001281
Gamze Abaka33feef52019-02-27 08:16:47 +00001282 @Override
1283 public void onError(Objective objective, ObjectiveError error) {
1284 log.info("Eapol filter for {} on {} with meter {} failed {} because {}",
Saurav Das80b6b6c2019-06-27 12:28:06 -07001285 devId, portNumber, mId, (install) ? INSTALLATION : REMOVAL,
Gamze Abaka33feef52019-02-27 08:16:47 +00001286 error);
1287 if (filterFuture != null) {
1288 filterFuture.complete(error);
1289 }
1290 }
1291 });
alshabibdec2e252016-01-15 12:20:25 -08001292
Gamze Abaka33feef52019-02-27 08:16:47 +00001293 flowObjectiveService.filter(devId, eapol);
1294 } else {
1295 log.warn("Meter installation error while sending eapol trap flow. " +
Saurav Das80b6b6c2019-06-27 12:28:06 -07001296 "Result {} and MeterId {}", result, mId);
Gamze Abaka33feef52019-02-27 08:16:47 +00001297 }
1298 });
alshabibdec2e252016-01-15 12:20:25 -08001299 }
1300
Jonathan Hart403372d2018-08-22 11:44:13 -07001301 /**
1302 * Installs trap filtering objectives for particular traffic types on an
1303 * NNI port.
1304 *
Gamze Abakaad329652018-12-20 10:12:21 +00001305 * @param devId device ID
1306 * @param port port number
Jonathan Hart403372d2018-08-22 11:44:13 -07001307 * @param install true to install, false to remove
1308 */
1309 private void processNniFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
1310 processLldpFilteringObjective(devId, port, install);
Gamze Abaka33feef52019-02-27 08:16:47 +00001311 processDhcpFilteringObjectives(devId, port, null, -1, install, false);
Jonathan Hart403372d2018-08-22 11:44:13 -07001312 }
1313
1314 private void processLldpFilteringObjective(DeviceId devId, PortNumber port, boolean install) {
1315 if (!mastershipService.isLocalMaster(devId)) {
1316 return;
1317 }
1318 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
1319
1320 FilteringObjective lldp = (install ? builder.permit() : builder.deny())
1321 .withKey(Criteria.matchInPort(port))
1322 .addCondition(Criteria.matchEthType(EthType.EtherType.LLDP.ethType()))
1323 .withMeta(DefaultTrafficTreatment.builder()
1324 .setOutput(PortNumber.CONTROLLER).build())
1325 .fromApp(appId)
1326 .withPriority(10000)
1327 .add(new ObjectiveContext() {
1328 @Override
1329 public void onSuccess(Objective objective) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001330 log.info("LLDP filter for device {} on port {} {}.",
Gamze Abaka838d8142019-02-21 07:06:55 +00001331 devId, port, (install) ? INSTALLED : REMOVED);
Jonathan Hart403372d2018-08-22 11:44:13 -07001332 }
1333
1334 @Override
1335 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001336 log.info("LLDP filter for device {} on port {} failed {} because {}",
Gamze Abaka838d8142019-02-21 07:06:55 +00001337 devId, port, (install) ? INSTALLATION : REMOVAL,
Saurav Das82b8e6d2018-10-04 15:25:12 -07001338 error);
Jonathan Hart403372d2018-08-22 11:44:13 -07001339 }
1340 });
1341
1342 flowObjectiveService.filter(devId, lldp);
1343
1344 }
1345
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001346 /**
1347 * Trap dhcp packets to the controller.
1348 *
Gamze Abaka838d8142019-02-21 07:06:55 +00001349 * @param devId the device identifier
1350 * @param port the port for which this trap flow is designated
1351 * @param upstreamMeterId the upstream meter id that includes the upstream
1352 * bandwidth profile values such as PIR,CIR. If no meter id needs to be referenced,
1353 * null can be sent
1354 * @param techProfileId the technology profile id that is used to create write
1355 * metadata instruction value. If no tech profile id needs to be referenced,
1356 * -1 can be sent
1357 * @param install true to install the flow, false to remove the flow
1358 * @param upstream true if trapped packets are flowing upstream towards
1359 * server, false if packets are flowing downstream towards client
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001360 */
1361 private void processDhcpFilteringObjectives(DeviceId devId, PortNumber port,
Gamze Abaka838d8142019-02-21 07:06:55 +00001362 MeterId upstreamMeterId,
1363 int techProfileId,
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001364 boolean install,
1365 boolean upstream) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001366
1367 if (!enableDhcpOnProvisioning) {
1368 log.debug("Dhcp provisioning is disabled.");
1369 return;
1370 }
1371
Amit Ghosh95e2f652017-08-23 12:49:46 +01001372 if (!mastershipService.isLocalMaster(devId)) {
1373 return;
1374 }
Amit Ghosh95e2f652017-08-23 12:49:46 +01001375
Matteo Scandolo63460d12018-11-02 16:19:04 -07001376 if (enableDhcpV4) {
1377 int udpSrc = (upstream) ? 68 : 67;
1378 int udpDst = (upstream) ? 67 : 68;
1379
1380 EthType ethType = EthType.EtherType.IPV4.ethType();
1381 byte protocol = IPv4.PROTOCOL_UDP;
1382
Gamze Abaka838d8142019-02-21 07:06:55 +00001383 this.addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType,
1384 upstreamMeterId, techProfileId, protocol, install);
Matteo Scandolo63460d12018-11-02 16:19:04 -07001385 }
1386
1387 if (enableDhcpV6) {
1388 int udpSrc = (upstream) ? 547 : 546;
1389 int udpDst = (upstream) ? 546 : 547;
1390
1391 EthType ethType = EthType.EtherType.IPV6.ethType();
1392 byte protocol = IPv6.PROTOCOL_UDP;
1393
Gamze Abaka838d8142019-02-21 07:06:55 +00001394 this.addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType,
1395 upstreamMeterId, techProfileId, protocol, install);
Matteo Scandolo63460d12018-11-02 16:19:04 -07001396 }
1397
1398 }
1399
1400 private void addDhcpFilteringObjectives(DeviceId devId,
1401 PortNumber port,
1402 int udpSrc,
1403 int udpDst,
1404 EthType ethType,
Gamze Abaka838d8142019-02-21 07:06:55 +00001405 MeterId upstreamMeterId,
1406 int techProfileId,
Matteo Scandolo63460d12018-11-02 16:19:04 -07001407 byte protocol,
1408 boolean install) {
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001409
1410 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Gamze Abaka838d8142019-02-21 07:06:55 +00001411 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
1412
1413 if (upstreamMeterId != null) {
1414 treatmentBuilder.meter(upstreamMeterId);
1415 }
1416
1417 if (techProfileId != -1) {
Gamze Abakada282b42019-03-11 13:16:48 +00001418 treatmentBuilder.writeMetadata(createTechProfValueForWm(null, techProfileId), 0);
Gamze Abaka838d8142019-02-21 07:06:55 +00001419 }
1420
Amit Ghosh95e2f652017-08-23 12:49:46 +01001421 FilteringObjective dhcpUpstream = (install ? builder.permit() : builder.deny())
1422 .withKey(Criteria.matchInPort(port))
Matteo Scandolo63460d12018-11-02 16:19:04 -07001423 .addCondition(Criteria.matchEthType(ethType))
1424 .addCondition(Criteria.matchIPProtocol(protocol))
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001425 .addCondition(Criteria.matchUdpSrc(TpPort.tpPort(udpSrc)))
1426 .addCondition(Criteria.matchUdpDst(TpPort.tpPort(udpDst)))
Gamze Abaka838d8142019-02-21 07:06:55 +00001427 .withMeta(treatmentBuilder
Gamze Abaka641fc072018-09-04 09:16:27 +00001428 .setOutput(PortNumber.CONTROLLER).build())
Amit Ghosh95e2f652017-08-23 12:49:46 +01001429 .fromApp(appId)
Matt Jeanneret3f579262018-06-14 17:16:23 -04001430 .withPriority(10000)
Amit Ghosh95e2f652017-08-23 12:49:46 +01001431 .add(new ObjectiveContext() {
1432 @Override
1433 public void onSuccess(Objective objective) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001434 log.info("DHCP {} filter for device {} on port {} {}.",
Gamze Abakaad329652018-12-20 10:12:21 +00001435 (ethType.equals(EthType.EtherType.IPV4.ethType())) ? "v4" : "v6",
Gamze Abaka838d8142019-02-21 07:06:55 +00001436 devId, port, (install) ? INSTALLED : REMOVED);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001437 }
1438
1439 @Override
1440 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001441 log.info("DHCP {} filter for device {} on port {} failed {} because {}",
Gamze Abakaad329652018-12-20 10:12:21 +00001442 (ethType.equals(EthType.EtherType.IPV4.ethType())) ? "v4" : "v6",
Gamze Abaka838d8142019-02-21 07:06:55 +00001443 devId, port, (install) ? INSTALLATION : REMOVAL,
Gamze Abakaad329652018-12-20 10:12:21 +00001444 error);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001445 }
1446 });
1447
1448 flowObjectiveService.filter(devId, dhcpUpstream);
1449 }
1450
Gamze Abaka838d8142019-02-21 07:06:55 +00001451 private void processIgmpFilteringObjectives(DeviceId devId, PortNumber port,
1452 MeterId upstreamMeterId,
1453 int techProfileId,
1454 boolean install) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001455
Gamze Abakaf59c0912019-04-19 08:24:28 +00001456 if (!enableIgmpOnProvisioning) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001457 log.debug("Igmp provisioning is disabled.");
1458 return;
1459 }
1460
Amit Ghosh95e2f652017-08-23 12:49:46 +01001461 if (!mastershipService.isLocalMaster(devId)) {
1462 return;
1463 }
1464
Gamze Abaka641fc072018-09-04 09:16:27 +00001465 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Gamze Abaka838d8142019-02-21 07:06:55 +00001466 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
1467
1468 if (upstreamMeterId != null) {
1469 treatmentBuilder.meter(upstreamMeterId);
1470 }
1471
1472 if (techProfileId != -1) {
Gamze Abakada282b42019-03-11 13:16:48 +00001473 treatmentBuilder.writeMetadata(createTechProfValueForWm(null, techProfileId), 0);
Gamze Abaka838d8142019-02-21 07:06:55 +00001474 }
Amit Ghosh95e2f652017-08-23 12:49:46 +01001475
1476 builder = install ? builder.permit() : builder.deny();
1477
1478 FilteringObjective igmp = builder
1479 .withKey(Criteria.matchInPort(port))
1480 .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
1481 .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_IGMP))
Gamze Abaka838d8142019-02-21 07:06:55 +00001482 .withMeta(treatmentBuilder
Gamze Abaka641fc072018-09-04 09:16:27 +00001483 .setOutput(PortNumber.CONTROLLER).build())
Amit Ghosh95e2f652017-08-23 12:49:46 +01001484 .fromApp(appId)
1485 .withPriority(10000)
1486 .add(new ObjectiveContext() {
1487 @Override
1488 public void onSuccess(Objective objective) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001489 log.info("Igmp filter for {} on {} {}.",
Gamze Abaka838d8142019-02-21 07:06:55 +00001490 devId, port, (install) ? INSTALLED : REMOVED);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001491 }
1492
1493 @Override
1494 public void onError(Objective objective, ObjectiveError error) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001495 log.info("Igmp filter for {} on {} failed {} because {}.",
Gamze Abaka838d8142019-02-21 07:06:55 +00001496 devId, port, (install) ? INSTALLATION : REMOVAL,
Gamze Abaka641fc072018-09-04 09:16:27 +00001497 error);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001498 }
1499 });
1500
1501 flowObjectiveService.filter(devId, igmp);
1502 }
1503
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001504 /**
Jonathan Hart403372d2018-08-22 11:44:13 -07001505 * Creates trap flows for device, including DHCP and LLDP trap on NNI and
1506 * EAPOL trap on the UNIs, if device is present in Sadis config.
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001507 *
1508 * @param dev Device to look for
1509 */
Jonathan Hart403372d2018-08-22 11:44:13 -07001510 private void checkAndCreateDeviceFlows(Device dev) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001511 // we create only for the ones we are master of
1512 if (!mastershipService.isLocalMaster(dev.id())) {
Gamze Abaka641fc072018-09-04 09:16:27 +00001513 return;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001514 }
1515 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +00001516 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Jonathan Hart403372d2018-08-22 11:44:13 -07001517 log.debug("checkAndCreateDeviceFlows: deviceInfo {}", deviceInfo);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001518
1519 if (deviceInfo != null) {
Jonathan Hart403372d2018-08-22 11:44:13 -07001520 // This is an OLT device as per Sadis, we create flows for UNI and NNI ports
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001521 for (Port p : deviceService.getPorts(dev.id())) {
1522 if (isUniPort(dev, p)) {
Gamze Abakada282b42019-03-11 13:16:48 +00001523 processEapolFilteringObjectives(dev.id(), p.number(), defaultBpId, null,
1524 VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
Jonathan Hart403372d2018-08-22 11:44:13 -07001525 } else {
1526 processNniFilteringObjectives(dev.id(), p.number(), true);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001527 }
1528 }
1529 }
1530 }
1531
Jonathan Hart403372d2018-08-22 11:44:13 -07001532
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001533 /**
1534 * Get the uplink for of the OLT device.
Gamze Abakaad329652018-12-20 10:12:21 +00001535 * <p>
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001536 * This assumes that the OLT has a single uplink port. When more uplink ports need to be supported
1537 * this logic needs to be changed
1538 *
1539 * @param dev Device to look for
1540 * @return The uplink Port of the OLT
1541 */
1542 private Port getUplinkPort(Device dev) {
1543 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +00001544 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Saurav Das4c1a6a92019-06-19 13:26:15 -07001545 log.trace("getUplinkPort: deviceInfo {}", deviceInfo);
Saurav Das82b8e6d2018-10-04 15:25:12 -07001546 if (deviceInfo == null) {
1547 log.warn("Device {} is not configured in SADIS .. cannot fetch device"
1548 + " info", dev.id());
1549 return null;
1550 }
1551 // Return the port that has been configured as the uplink port of this OLT in Sadis
Gamze Abakaad329652018-12-20 10:12:21 +00001552 for (Port p : deviceService.getPorts(dev.id())) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001553 if (p.number().toLong() == deviceInfo.uplinkPort()) {
Saurav Das4c1a6a92019-06-19 13:26:15 -07001554 log.trace("getUplinkPort: Found port {}", p);
Saurav Das82b8e6d2018-10-04 15:25:12 -07001555 return p;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001556 }
1557 }
1558
Saurav Das4c1a6a92019-06-19 13:26:15 -07001559 log.warn("getUplinkPort: " + NO_UPLINK_PORT, dev.id());
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001560 return null;
1561 }
1562
1563 /**
1564 * Return the subscriber on a port.
1565 *
Matteo Scandolo962a6ad2018-12-11 15:39:42 -08001566 * @param cp ConnectPoint on which to find the subscriber
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001567 * @return subscriber if found else null
1568 */
Matteo Scandolo962a6ad2018-12-11 15:39:42 -08001569 SubscriberAndDeviceInformation getSubscriber(ConnectPoint cp) {
1570 Port port = deviceService.getPort(cp);
1571 checkNotNull(port, "Invalid connect point");
1572 String portName = port.annotations().value(AnnotationKeys.PORT_NAME);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001573 return subsService.get(portName);
1574 }
1575
Gamze Abakaad329652018-12-20 10:12:21 +00001576 /**
1577 * Write metadata instruction value (metadata) is 8 bytes.
Gamze Abaka838d8142019-02-21 07:06:55 +00001578 * <p>
Gamze Abakaad329652018-12-20 10:12:21 +00001579 * MS 2 bytes: C Tag
1580 * Next 2 bytes: Technology Profile Id
1581 * Next 4 bytes: Port number (uni or nni)
1582 */
1583
1584 private Long createMetadata(VlanId innerVlan, int techProfileId, PortNumber egressPort) {
1585
1586 if (techProfileId == -1) {
1587 techProfileId = DEFAULT_TP_ID;
1588 }
1589
1590 return ((long) (innerVlan.id()) << 48 | (long) techProfileId << 32) | egressPort.toLong();
1591 }
1592
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001593 private boolean isUniPort(Device d, Port p) {
1594 Port ulPort = getUplinkPort(d);
1595 if (ulPort != null) {
1596 return (ulPort.number().toLong() != p.number().toLong());
1597 }
1598 return false;
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001599 }
1600
Jonathan Hart4c538002018-08-23 10:11:54 -07001601 private SubscriberAndDeviceInformation getOltInfo(Device dev) {
1602 String devSerialNo = dev.serialNumber();
Gamze Abaka641fc072018-09-04 09:16:27 +00001603 return subsService.get(devSerialNo);
Jonathan Hart4c538002018-08-23 10:11:54 -07001604 }
1605
Gamze Abaka33feef52019-02-27 08:16:47 +00001606 private MeterId getMeterIdFromBpMapping(DeviceId deviceId, String bandwidthProfile) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001607 if (bpInfoToMeter.get(bandwidthProfile) == null) {
Saurav Das4c1a6a92019-06-19 13:26:15 -07001608 log.warn("Bandwidth Profile '{}' is not currently mapped to a meter",
1609 bandwidthProfile);
Gamze Abaka33feef52019-02-27 08:16:47 +00001610 return null;
1611 }
1612
1613 Optional<MeterKey> meterKeyForDevice = bpInfoToMeter.get(bandwidthProfile)
1614 .stream()
1615 .filter(meterKey -> meterKey.deviceId().equals(deviceId))
1616 .findFirst();
Saurav Das4c1a6a92019-06-19 13:26:15 -07001617 if (meterKeyForDevice.isPresent()) {
1618 log.debug("Found meter {} for bandwidth profile {}",
1619 meterKeyForDevice.get().meterId(), bandwidthProfile);
1620 return meterKeyForDevice.get().meterId();
1621 } else {
1622 log.warn("Bandwidth profile '{}' is not currently mapped to a meter",
1623 bandwidthProfile);
1624 return null;
1625 }
Gamze Abaka33feef52019-02-27 08:16:47 +00001626 }
1627
1628 private void addMeterIdToBpMapping(DeviceId deviceId, MeterId meterId, String bandwidthProfile) {
1629
1630 if (bpInfoToMeter.get(bandwidthProfile) == null) {
1631 bpInfoToMeter.put(bandwidthProfile,
1632 new ArrayList<>(Arrays.asList(MeterKey.key(deviceId, meterId))));
1633 } else {
Gamze Abaka33feef52019-02-27 08:16:47 +00001634 List<MeterKey> meterKeyListForBp = bpInfoToMeter.get(bandwidthProfile);
1635 meterKeyListForBp.add(MeterKey.key(deviceId, meterId));
1636 }
1637 }
1638
Saurav Das80b6b6c2019-06-27 12:28:06 -07001639 /**
1640 * Removes meter key from programmed meters. If the meter has no reference
1641 * count in the data plane and is not present in the programmed-meters store
1642 * it will be removed.
1643 *
1644 * @param deviceId device identifier
1645 * @param bandwidthProfileId name of bandwidth profile
1646 */
1647 private void removeMeterIdFromPrgMeters(DeviceId deviceId,
1648 String bandwidthProfileId) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001649 List<MeterKey> meterKeysForBp = bpInfoToMeter.get(bandwidthProfileId);
1650 if (meterKeysForBp != null) {
1651 meterKeysForBp.stream()
1652 .filter(meterKey -> meterKey.deviceId().equals(deviceId))
1653 .findFirst().ifPresent(mk -> {
Gamze Abaka33feef52019-02-27 08:16:47 +00001654 programmedMeters.remove(mk);
1655 });
1656 }
1657 }
1658
alshabibf0e7e702015-05-30 18:22:36 -07001659 private class InternalDeviceListener implements DeviceListener {
Saurav Dasa9d5f442019-03-06 19:32:48 -08001660 private Set<DeviceId> programmedDevices = Sets.newConcurrentHashSet();
1661
alshabibf0e7e702015-05-30 18:22:36 -07001662 @Override
1663 public void event(DeviceEvent event) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001664 eventExecutor.execute(() -> {
1665 DeviceId devId = event.subject().id();
1666 Device dev = event.subject();
Gamze Abaka838d8142019-02-21 07:06:55 +00001667 Port port = event.port();
Jonathan Hart4c538002018-08-23 10:11:54 -07001668
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001669 if (event.type() == DeviceEvent.Type.PORT_STATS_UPDATED) {
1670 return;
1671 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001672
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001673 if (getOltInfo(dev) == null) {
Saurav Dasa9d5f442019-03-06 19:32:48 -08001674 // it's possible that we got an event for a previously
1675 // programmed OLT that is no longer available in SADIS
1676 // we let such events go through
1677 if (!programmedDevices.contains(devId)) {
1678 log.warn("No device info found for {}, this is either "
1679 + "not an OLT or not known to sadis", dev);
1680 return;
1681 }
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001682 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001683
Saurav Das4c1a6a92019-06-19 13:26:15 -07001684 log.debug("OLT got {} event for {}: {}", event.type(),
1685 event.subject().id(), event);
Jonathan Hart4c538002018-08-23 10:11:54 -07001686
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001687 switch (event.type()) {
1688 //TODO: Port handling and bookkeeping should be improved once
1689 // olt firmware handles correct behaviour.
1690 case PORT_ADDED:
Gamze Abaka838d8142019-02-21 07:06:55 +00001691 if (isUniPort(dev, port)) {
1692 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, port));
Gamze Abaka838d8142019-02-21 07:06:55 +00001693 if (port.isEnabled()) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001694 processEapolFilteringObjectives(devId, port.number(), defaultBpId,
Gamze Abakada282b42019-03-11 13:16:48 +00001695 null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001696 }
1697 } else {
1698 checkAndCreateDeviceFlows(dev);
1699 }
1700 break;
1701 case PORT_REMOVED:
Gamze Abaka838d8142019-02-21 07:06:55 +00001702 if (isUniPort(dev, port)) {
Gamze Abaka853bf252019-03-25 10:27:06 +00001703 removeSubscriber(new ConnectPoint(devId, port.number()));
Andy Bavier160e8682019-05-07 18:32:22 -07001704 processEapolFilteringObjectives(devId, port.number(), defaultBpId,
1705 null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), false);
1706
Gamze Abaka838d8142019-02-21 07:06:55 +00001707 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, port));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001708 }
1709
1710 break;
1711 case PORT_UPDATED:
Gamze Abaka838d8142019-02-21 07:06:55 +00001712 if (!isUniPort(dev, port)) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001713 break;
1714 }
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001715
Gamze Abakada282b42019-03-11 13:16:48 +00001716 SubscriberAndDeviceInformation sub = programmedSubs
1717 .get(new ConnectPoint(devId, port.number()));
1718 VlanId vlanId = sub == null ? VlanId.vlanId(EAPOL_DEFAULT_VLAN) : sub.cTag();
1719
1720 String bpId = getCurrentBandwidthProfile(new ConnectPoint(devId, port.number()));
1721
Gamze Abaka838d8142019-02-21 07:06:55 +00001722 if (port.isEnabled()) {
Gamze Abakada282b42019-03-11 13:16:48 +00001723 processEapolFilteringObjectives(devId, port.number(), bpId,
1724 null, vlanId, true);
Gamze Abaka33feef52019-02-27 08:16:47 +00001725
Gamze Abaka838d8142019-02-21 07:06:55 +00001726 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, port));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001727 } else {
Gamze Abakada282b42019-03-11 13:16:48 +00001728 processEapolFilteringObjectives(devId, port.number(), bpId,
1729 null, vlanId, false);
Gamze Abaka838d8142019-02-21 07:06:55 +00001730 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, port));
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001731 }
alshabibbb83aa22016-02-10 15:08:23 -08001732 break;
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001733 case DEVICE_ADDED:
alshabib7c190012016-02-09 18:22:33 -08001734 post(new AccessDeviceEvent(
1735 AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
1736 null, null));
Saurav Dasa9d5f442019-03-06 19:32:48 -08001737 programmedDevices.add(devId);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001738 // Send UNI_ADDED events for all existing ports
1739 deviceService.getPorts(devId).stream()
1740 .filter(p -> isUniPort(dev, p))
1741 .filter(Port::isEnabled)
1742 .forEach(p -> post(new AccessDeviceEvent(
1743 AccessDeviceEvent.Type.UNI_ADDED, devId, p)));
1744
Jonathan Hart403372d2018-08-22 11:44:13 -07001745 checkAndCreateDeviceFlows(dev);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001746 break;
1747 case DEVICE_REMOVED:
1748 deviceService.getPorts(devId).stream()
1749 .filter(p -> isUniPort(dev, p))
1750 .forEach(p -> post(new AccessDeviceEvent(
1751 AccessDeviceEvent.Type.UNI_REMOVED, devId, p)));
Saurav Dasa9d5f442019-03-06 19:32:48 -08001752 programmedDevices.remove(devId);
Gamze Abakada282b42019-03-11 13:16:48 +00001753 removeAllSubscribers(devId);
A R Karthicke135d692019-10-29 00:15:51 +00001754 removeDeviceMetersFromBpMap(devId);
alshabib7c190012016-02-09 18:22:33 -08001755 post(new AccessDeviceEvent(
1756 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
1757 null, null));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001758 break;
1759 case DEVICE_AVAILABILITY_CHANGED:
1760 if (deviceService.isAvailable(devId)) {
1761 post(new AccessDeviceEvent(
1762 AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
1763 null, null));
Gamze Abakada282b42019-03-11 13:16:48 +00001764 programmedDevices.add(devId);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001765 checkAndCreateDeviceFlows(dev);
1766 } else {
Gamze Abakada282b42019-03-11 13:16:48 +00001767 programmedDevices.remove(devId);
1768 removeAllSubscribers(devId);
A R Karthicke135d692019-10-29 00:15:51 +00001769 removeDeviceMetersFromBpMap(devId);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001770 post(new AccessDeviceEvent(
1771 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
1772 null, null));
1773 }
1774 break;
1775 case DEVICE_UPDATED:
1776 case DEVICE_SUSPENDED:
1777 case PORT_STATS_UPDATED:
1778 default:
1779 return;
1780 }
1781 });
alshabibf0e7e702015-05-30 18:22:36 -07001782 }
Gamze Abaka838d8142019-02-21 07:06:55 +00001783
1784 private String getCurrentBandwidthProfile(ConnectPoint connectPoint) {
1785 SubscriberAndDeviceInformation sub = programmedSubs.get(connectPoint);
1786 if (sub != null) {
1787 return sub.upstreamBandwidthProfile();
1788 }
1789 return defaultBpId;
1790 }
Gamze Abakada282b42019-03-11 13:16:48 +00001791
1792 private void removeAllSubscribers(DeviceId deviceId) {
1793 List<ConnectPoint> connectPoints = programmedSubs.keySet().stream()
1794 .filter(ks -> Objects.equals(ks.deviceId(), deviceId))
1795 .collect(Collectors.toList());
1796
1797 connectPoints.forEach(cp -> programmedSubs.remove(cp));
1798 }
A R Karthicke135d692019-10-29 00:15:51 +00001799
1800 private void removeDeviceMetersFromBpMap(DeviceId deviceId) {
1801 bpInfoToMeter.values().forEach(meterKeys -> meterKeys.stream()
1802 .filter(meterKey -> meterKey.deviceId().equals(deviceId)).findFirst().
1803 ifPresent(mk -> {
1804 meterKeys.remove(mk);
1805 programmedMeters.remove(mk);
1806 log.info("Deleted from the internal map. MeterKey {}", mk);
1807 log.info("Programmed meters {}", programmedMeters);
1808 }));
1809 }
1810
alshabibf0e7e702015-05-30 18:22:36 -07001811 }
Gamze Abaka641fc072018-09-04 09:16:27 +00001812
1813 private class InternalMeterListener implements MeterListener {
1814
1815 @Override
1816 public void event(MeterEvent meterEvent) {
1817 if (deleteMeters && MeterEvent.Type.METER_REFERENCE_COUNT_ZERO.equals(meterEvent.type())) {
Saurav Das4c1a6a92019-06-19 13:26:15 -07001818 log.debug("Zero Count Meter {} received", meterEvent.subject());
Gamze Abaka641fc072018-09-04 09:16:27 +00001819 Meter meter = meterEvent.subject();
Gamze Abaka33feef52019-02-27 08:16:47 +00001820 if (meter != null && appId.equals(meter.appId()) &&
1821 !programmedMeters.contains(MeterKey.key(meter.deviceId(), meter.id()))) {
Saurav Das4c1a6a92019-06-19 13:26:15 -07001822 log.info("Deleting unreferenced, no longer programmed Meter {}",
1823 meter.id());
Gamze Abaka641fc072018-09-04 09:16:27 +00001824 deleteMeter(meter.deviceId(), meter.id());
1825 }
1826 } else if (MeterEvent.Type.METER_REMOVED.equals(meterEvent.type())) {
Saurav Das4c1a6a92019-06-19 13:26:15 -07001827 log.debug("Meter removed event is received. Meter is {}",
1828 meterEvent.subject());
Gamze Abaka641fc072018-09-04 09:16:27 +00001829 removeMeterFromBpMap(meterEvent.subject());
1830 }
1831 }
1832
1833 private void deleteMeter(DeviceId deviceId, MeterId meterId) {
1834 Meter meter = meterService.getMeter(deviceId, meterId);
Gamze Abaka838d8142019-02-21 07:06:55 +00001835 if (meter != null) {
1836 MeterRequest meterRequest = DefaultMeterRequest.builder()
1837 .withBands(meter.bands())
1838 .withUnit(meter.unit())
1839 .forDevice(deviceId)
1840 .fromApp(appId)
1841 .burst()
1842 .remove();
Gamze Abaka641fc072018-09-04 09:16:27 +00001843
Gamze Abaka838d8142019-02-21 07:06:55 +00001844 meterService.withdraw(meterRequest, meterId);
1845 }
Gamze Abaka641fc072018-09-04 09:16:27 +00001846 }
1847
1848 private void removeMeterFromBpMap(Meter meter) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001849 bpInfoToMeter.values().forEach(meterKeys -> meterKeys.stream()
1850 .filter(meterKey -> (meterKey.deviceId().equals(meter.deviceId()))
1851 && meterKey.meterId().equals(meter.id())).findFirst().
1852 ifPresent(mk -> {
1853 meterKeys.remove(mk);
Gamze Abakada282b42019-03-11 13:16:48 +00001854 programmedMeters.remove(mk);
Gamze Abaka33feef52019-02-27 08:16:47 +00001855 log.info("Deleted from the internal map. MeterKey {}", mk);
1856 log.info("Programmed meters {}", programmedMeters);
1857 }));
Gamze Abaka641fc072018-09-04 09:16:27 +00001858 }
1859 }
A R Karthicke135d692019-10-29 00:15:51 +00001860}