blob: 9a3534fcddfac81ef5a0398f0df4f8f655bc5d58 [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;
Saurav Das62ad75e2019-03-05 12:22:22 -080026import java.util.Arrays;
Gamze Abaka33feef52019-02-27 08:16:47 +000027import java.util.ArrayList;
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
Gamze Abaka33feef52019-02-27 08:16:47 +000042import com.google.common.collect.ImmutableSet;
alshabibf0e7e702015-05-30 18:22:36 -070043import org.apache.felix.scr.annotations.Activate;
44import org.apache.felix.scr.annotations.Component;
45import org.apache.felix.scr.annotations.Deactivate;
alshabibe0559672016-02-21 14:49:51 -080046import org.apache.felix.scr.annotations.Modified;
47import org.apache.felix.scr.annotations.Property;
alshabibf0e7e702015-05-30 18:22:36 -070048import org.apache.felix.scr.annotations.Reference;
49import org.apache.felix.scr.annotations.ReferenceCardinality;
Jonathan Harte533a422015-10-20 17:31:24 -070050import org.apache.felix.scr.annotations.Service;
alshabibdec2e252016-01-15 12:20:25 -080051import org.onlab.packet.EthType;
Amit Ghosh95e2f652017-08-23 12:49:46 +010052import org.onlab.packet.IPv4;
Matteo Scandolo63460d12018-11-02 16:19:04 -070053import org.onlab.packet.IPv6;
Amit Ghosh95e2f652017-08-23 12:49:46 +010054import org.onlab.packet.TpPort;
alshabibf0e7e702015-05-30 18:22:36 -070055import org.onlab.packet.VlanId;
Amit Ghosh95e2f652017-08-23 12:49:46 +010056import org.onlab.util.Tools;
alshabibe0559672016-02-21 14:49:51 -080057import org.onosproject.cfg.ComponentConfigService;
alshabibf0e7e702015-05-30 18:22:36 -070058import org.onosproject.core.ApplicationId;
59import org.onosproject.core.CoreService;
alshabib8e4fd2f2016-01-12 15:55:53 -080060import org.onosproject.event.AbstractListenerManager;
alshabib09753b52016-03-04 14:55:19 -080061import org.onosproject.mastership.MastershipService;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010062import org.onosproject.net.AnnotationKeys;
Jonathan Harte533a422015-10-20 17:31:24 -070063import org.onosproject.net.ConnectPoint;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010064import org.onosproject.net.Device;
alshabibf0e7e702015-05-30 18:22:36 -070065import org.onosproject.net.DeviceId;
alshabibdec2e252016-01-15 12:20:25 -080066import org.onosproject.net.Port;
alshabibf0e7e702015-05-30 18:22:36 -070067import org.onosproject.net.PortNumber;
68import org.onosproject.net.device.DeviceEvent;
69import org.onosproject.net.device.DeviceListener;
70import org.onosproject.net.device.DeviceService;
71import org.onosproject.net.flow.DefaultTrafficSelector;
72import org.onosproject.net.flow.DefaultTrafficTreatment;
73import org.onosproject.net.flow.TrafficSelector;
74import org.onosproject.net.flow.TrafficTreatment;
alshabibdec2e252016-01-15 12:20:25 -080075import org.onosproject.net.flow.criteria.Criteria;
76import org.onosproject.net.flowobjective.DefaultFilteringObjective;
alshabibf0e7e702015-05-30 18:22:36 -070077import org.onosproject.net.flowobjective.DefaultForwardingObjective;
alshabibdec2e252016-01-15 12:20:25 -080078import org.onosproject.net.flowobjective.FilteringObjective;
alshabibf0e7e702015-05-30 18:22:36 -070079import org.onosproject.net.flowobjective.FlowObjectiveService;
80import org.onosproject.net.flowobjective.ForwardingObjective;
alshabib3ea82642016-01-12 18:06:53 -080081import org.onosproject.net.flowobjective.Objective;
82import org.onosproject.net.flowobjective.ObjectiveContext;
83import org.onosproject.net.flowobjective.ObjectiveError;
Saurav Das62ad75e2019-03-05 12:22:22 -080084import org.onosproject.store.serializers.KryoNamespaces;
85import org.onosproject.store.service.ConsistentMultimap;
86import org.onosproject.store.service.Serializer;
87import org.onosproject.store.service.StorageService;
Gamze Abaka33feef52019-02-27 08:16:47 +000088import org.onosproject.net.meter.Band;
89import org.onosproject.net.meter.DefaultBand;
90import org.onosproject.net.meter.DefaultMeterRequest;
91import org.onosproject.net.meter.Meter;
92import org.onosproject.net.meter.MeterContext;
93import org.onosproject.net.meter.MeterFailReason;
94import org.onosproject.net.meter.MeterKey;
95import org.onosproject.net.meter.MeterService;
96import org.onosproject.net.meter.MeterListener;
97import org.onosproject.net.meter.MeterRequest;
98import org.onosproject.net.meter.MeterId;
99import org.onosproject.net.meter.MeterEvent;
alshabib36a4d732016-06-01 16:03:59 -0700100import org.opencord.olt.AccessDeviceEvent;
101import org.opencord.olt.AccessDeviceListener;
102import org.opencord.olt.AccessDeviceService;
Amit Ghosh31939522018-08-16 13:28:21 +0100103import org.opencord.olt.AccessSubscriberId;
Gamze Abaka641fc072018-09-04 09:16:27 +0000104import org.opencord.sadis.BandwidthProfileInformation;
105import org.opencord.sadis.BaseInformationService;
106import org.opencord.sadis.SadisService;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100107import org.opencord.sadis.SubscriberAndDeviceInformation;
alshabibe0559672016-02-21 14:49:51 -0800108import org.osgi.service.component.ComponentContext;
alshabibf0e7e702015-05-30 18:22:36 -0700109import org.slf4j.Logger;
110
Saurav Das82b8e6d2018-10-04 15:25:12 -0700111import com.google.common.collect.ImmutableMap;
112import 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) {
325
326 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
Gamze Abaka33feef52019-02-27 08:16:47 +0000345 CompletableFuture<ObjectiveError> filterFuture = new CompletableFuture();
346
Gamze Abaka838d8142019-02-21 07:06:55 +0000347 //delete Eapol authentication flow with default bandwidth
Gamze Abaka33feef52019-02-27 08:16:47 +0000348 //wait until Eapol rule with defaultBpId is removed to install subscriber-based rules
Gamze Abakada282b42019-03-11 13:16:48 +0000349 processEapolFilteringObjectives(deviceId, subscriberPortNo, defaultBpId, filterFuture,
350 VlanId.vlanId(EAPOL_DEFAULT_VLAN), false);
Gamze Abaka33feef52019-02-27 08:16:47 +0000351 removeMeterIdFromBpMapping(deviceId, defaultBpId);
Gamze Abaka838d8142019-02-21 07:06:55 +0000352
Gamze Abaka33feef52019-02-27 08:16:47 +0000353 //install subscriber flows
354 filterFuture.thenAcceptAsync(filterStatus -> {
355 if (filterStatus == null) {
356 provisionSubscriberBasedFlows(connectPoint, uplinkPort.number(), Optional.empty(), sub);
357 }
358 });
Gamze Abaka838d8142019-02-21 07:06:55 +0000359
Saurav Das82b8e6d2018-10-04 15:25:12 -0700360 // cache subscriber info
Gamze Abaka838d8142019-02-21 07:06:55 +0000361 programmedSubs.put(connectPoint, sub);
Amit Ghosh31939522018-08-16 13:28:21 +0100362 return true;
alshabibb7a9e172016-01-13 11:23:53 -0800363 }
364
365 @Override
Gamze Abaka838d8142019-02-21 07:06:55 +0000366 public boolean removeSubscriber(ConnectPoint connectPoint) {
Matteo Scandolo962a6ad2018-12-11 15:39:42 -0800367 // Get the subscriber connected to this port from the local cache
368 // as if we don't know about the subscriber there's no need to remove it
Gamze Abaka838d8142019-02-21 07:06:55 +0000369
370 DeviceId deviceId = connectPoint.deviceId();
371 PortNumber subscriberPortNo = connectPoint.port();
372
373 SubscriberAndDeviceInformation subscriber = programmedSubs.get(connectPoint);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100374 if (subscriber == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000375 log.warn("Subscriber on connectionPoint {} was not previously programmed, " +
376 "no need to remove it", connectPoint);
Matteo Scandolo962a6ad2018-12-11 15:39:42 -0800377 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800378 }
379
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100380 // Get the uplink port
Gamze Abaka838d8142019-02-21 07:06:55 +0000381 Port uplinkPort = getUplinkPort(deviceService.getDevice(deviceId));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100382 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000383 log.warn(NO_UPLINK_PORT, deviceId);
Amit Ghosh31939522018-08-16 13:28:21 +0100384 return false;
alshabib4ceaed32016-03-03 18:00:58 -0800385 }
386
Gamze Abaka33feef52019-02-27 08:16:47 +0000387 //delete dhcp & igmp trap flows
388 MeterId upstreamMeterId = getMeterIdFromBpMapping(deviceId, subscriber.upstreamBandwidthProfile());
Amit Ghosh95e2f652017-08-23 12:49:46 +0100389
Gamze Abaka33feef52019-02-27 08:16:47 +0000390 //process dhcp filtering
391 processDhcpFilteringObjectives(deviceId, subscriberPortNo,
392 upstreamMeterId, subscriber.technologyProfileId(), false, true);
Gamze Abaka838d8142019-02-21 07:06:55 +0000393
Gamze Abaka33feef52019-02-27 08:16:47 +0000394 //process igmp filtering
395 processIgmpFilteringObjectives(deviceId, subscriberPortNo,
396 upstreamMeterId, subscriber.technologyProfileId(), false);
alshabibbf23a1f2016-01-14 17:27:11 -0800397
Gamze Abaka33feef52019-02-27 08:16:47 +0000398 //unprovision vlans
399 unprovisionVlans(deviceId, uplinkPort.number(), subscriberPortNo, subscriber, Optional.empty());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100400
401 // Remove if there are any flows for the additional Vlans
Gamze Abaka838d8142019-02-21 07:06:55 +0000402 Collection<? extends Map.Entry<VlanId, VlanId>> vlansList = additionalVlans.get(connectPoint).value();
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100403
404 // Remove the flows for the additional vlans for this subscriber
405 for (Map.Entry<VlanId, VlanId> vlans : vlansList) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000406 unprovisionTransparentFlows(deviceId, uplinkPort.number(), subscriberPortNo,
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100407 vlans.getValue(), vlans.getKey());
408
409 // Remove it from the map also
Gamze Abaka838d8142019-02-21 07:06:55 +0000410 additionalVlans.remove(connectPoint, vlans);
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100411 }
412
Gamze Abaka33feef52019-02-27 08:16:47 +0000413 //re-install eapol
414 processEapolFilteringObjectives(deviceId, subscriberPortNo,
Gamze Abakada282b42019-03-11 13:16:48 +0000415 subscriber.upstreamBandwidthProfile(), null, subscriber.cTag(), false);
Andy Bavier160e8682019-05-07 18:32:22 -0700416
417 Port port = deviceService.getPort(deviceId, subscriberPortNo);
418 if (port != null && port.isEnabled()) {
419 processEapolFilteringObjectives(deviceId, subscriberPortNo, defaultBpId,
420 null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
421 }
Gamze Abaka33feef52019-02-27 08:16:47 +0000422
Gamze Abaka838d8142019-02-21 07:06:55 +0000423 programmedSubs.remove(connectPoint);
Amit Ghosh31939522018-08-16 13:28:21 +0100424 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800425 }
426
Amit Ghosh31939522018-08-16 13:28:21 +0100427 @Override
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100428 public boolean provisionSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag, Optional<VlanId> cTag) {
Gamze Abakaf59c0912019-04-19 08:24:28 +0000429
430 log.info("Provisioning subscriber using subscriberId {}, sTag {}, cTag {}", subscriberId, sTag, cTag);
431
Amit Ghosh31939522018-08-16 13:28:21 +0100432 // Check if we can find the connect point to which this subscriber is connected
433 ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
434 if (subsPort == null) {
435 log.warn("ConnectPoint for {} not found", subscriberId);
436 return false;
437 }
438
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100439 if (!sTag.isPresent() && !cTag.isPresent()) {
440 return provisionSubscriber(subsPort);
441 } else if (sTag.isPresent() && cTag.isPresent()) {
442 Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
443 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000444 log.warn(NO_UPLINK_PORT, subsPort.deviceId());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100445 return false;
446 }
447
Gamze Abakaf59c0912019-04-19 08:24:28 +0000448 CompletableFuture<ObjectiveError> filterFuture = new CompletableFuture();
449
450 //delete Eapol authentication flow with default bandwidth
451 //wait until Eapol rule with defaultBpId is removed to install subscriber-based rules
452 processEapolFilteringObjectives(subsPort.deviceId(), subsPort.port(), defaultBpId, filterFuture,
453 VlanId.vlanId(EAPOL_DEFAULT_VLAN), false);
454 removeMeterIdFromBpMapping(subsPort.deviceId(), defaultBpId);
455
456 //install subscriber flows
457 filterFuture.thenAcceptAsync(filterStatus -> {
458 if (filterStatus == null) {
459 provisionTransparentFlows(subsPort.deviceId(), uplinkPort.number(), subsPort.port(),
460 cTag.get(), sTag.get());
461 }
462 });
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100463 return true;
464 } else {
465 log.warn("Provisioning failed for subscriber: {}", subscriberId);
466 return false;
467 }
Amit Ghosh31939522018-08-16 13:28:21 +0100468 }
Amit Ghosh95e2f652017-08-23 12:49:46 +0100469
alshabibe0559672016-02-21 14:49:51 -0800470 @Override
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100471 public boolean removeSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag, Optional<VlanId> cTag) {
Amit Ghosh31939522018-08-16 13:28:21 +0100472 // Check if we can find the connect point to which this subscriber is connected
473 ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
474 if (subsPort == null) {
475 log.warn("ConnectPoint for {} not found", subscriberId);
476 return false;
477 }
478
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100479 if (!sTag.isPresent() && !cTag.isPresent()) {
480 return removeSubscriber(subsPort);
481 } else if (sTag.isPresent() && cTag.isPresent()) {
482 // Get the uplink port
483 Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
484 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000485 log.warn(NO_UPLINK_PORT, subsPort.deviceId());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100486 return false;
487 }
488
489 unprovisionTransparentFlows(subsPort.deviceId(), uplinkPort.number(), subsPort.port(),
490 cTag.get(), sTag.get());
Gamze Abakaf59c0912019-04-19 08:24:28 +0000491
492 programmedSubs.remove(subsPort);
493
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100494 return true;
495 } else {
496 log.warn("Removing subscriber failed for: {}", subscriberId);
497 return false;
498 }
Amit Ghosh31939522018-08-16 13:28:21 +0100499 }
500
501 @Override
502 public Collection<Map.Entry<ConnectPoint, Map.Entry<VlanId, VlanId>>> getSubscribers() {
503 ArrayList<Map.Entry<ConnectPoint, Map.Entry<VlanId, VlanId>>> subs = new ArrayList<>();
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100504
Saurav Das82b8e6d2018-10-04 15:25:12 -0700505 // Get the subscribers for all the devices configured in sadis
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100506 // If the port is UNI, is enabled and exists in Sadis then copy it
507 for (Device d : deviceService.getDevices()) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700508 if (getOltInfo(d) == null) {
509 continue; // not an olt, or not configured in sadis
510 }
Gamze Abakaad329652018-12-20 10:12:21 +0000511 for (Port p : deviceService.getPorts(d.id())) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100512 if (isUniPort(d, p) && p.isEnabled()) {
513 ConnectPoint cp = new ConnectPoint(d.id(), p.number());
514
515 SubscriberAndDeviceInformation sub = getSubscriber(cp);
516 if (sub != null) {
Amit Ghosh31939522018-08-16 13:28:21 +0100517 Map.Entry<VlanId, VlanId> vlans = new AbstractMap.SimpleEntry(sub.sTag(), sub.cTag());
518 subs.add(new AbstractMap.SimpleEntry(cp, vlans));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100519 }
520 }
521 }
522 }
523
524 return subs;
Jonathan Hartfd6c1b32016-03-08 14:09:09 -0800525 }
526
527 @Override
Saurav Das82b8e6d2018-10-04 15:25:12 -0700528 public ImmutableMap<ConnectPoint, SubscriberAndDeviceInformation> getProgSubs() {
529 return ImmutableMap.copyOf(programmedSubs);
530 }
531
532 @Override
Gamze Abaka33feef52019-02-27 08:16:47 +0000533 public ImmutableSet<MeterKey> getProgMeters() {
534 return ImmutableSet.copyOf(programmedMeters);
535 }
536
537 @Override
538 public ImmutableMap<String, List<MeterKey>> getBpMeterMappings() {
539 return ImmutableMap.copyOf(bpInfoToMeter);
540 }
541
542 @Override
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100543 public List<DeviceId> fetchOlts() {
544 // look through all the devices and find the ones that are OLTs as per Sadis
545 List<DeviceId> olts = new ArrayList<>();
546 Iterable<Device> devices = deviceService.getDevices();
547 for (Device d : devices) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700548 if (getOltInfo(d) != null) {
549 // So this is indeed an OLT device
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100550 olts.add(d.id());
551 }
552 }
553 return olts;
alshabibe0559672016-02-21 14:49:51 -0800554 }
555
Amit Ghosh31939522018-08-16 13:28:21 +0100556 /**
557 * Finds the connect point to which a subscriber is connected.
558 *
559 * @param id The id of the subscriber, this is the same ID as in Sadis
560 * @return Subscribers ConnectPoint if found else null
561 */
562 private ConnectPoint findSubscriberConnectPoint(String id) {
563
564 Iterable<Device> devices = deviceService.getDevices();
565 for (Device d : devices) {
566 for (Port p : deviceService.getPorts(d.id())) {
567 log.trace("Comparing {} with {}", p.annotations().value(AnnotationKeys.PORT_NAME), id);
568 if (p.annotations().value(AnnotationKeys.PORT_NAME).equals(id)) {
569 log.debug("Found on device {} port {}", d.id(), p.number());
570 return new ConnectPoint(d.id(), p.number());
571 }
572 }
573 }
574 return null;
575 }
576
Gamze Abaka641fc072018-09-04 09:16:27 +0000577 private BandwidthProfileInformation getBandwidthProfileInformation(String bandwidthProfile) {
578 if (bandwidthProfile == null) {
579 return null;
580 }
581 return bpService.get(bandwidthProfile);
582 }
583
Gamze Abaka838d8142019-02-21 07:06:55 +0000584 /**
Gamze Abaka33feef52019-02-27 08:16:47 +0000585 * Removes subscriber vlan flows.
Gamze Abaka838d8142019-02-21 07:06:55 +0000586 *
587 * @param deviceId the device identifier
588 * @param uplink uplink port of the OLT
589 * @param subscriberPort uni port
590 * @param subscriber subscriber info that includes s, c tags, tech profile and bandwidth profile references
591 * @param defaultVlan default vlan of the subscriber
Gamze Abaka838d8142019-02-21 07:06:55 +0000592 */
Gamze Abaka33feef52019-02-27 08:16:47 +0000593 private void unprovisionVlans(DeviceId deviceId, PortNumber uplink,
594 PortNumber subscriberPort, SubscriberAndDeviceInformation subscriber,
595 Optional<VlanId> defaultVlan) {
596
597 log.info("Unprovisioning vlans...");
alshabibbf23a1f2016-01-14 17:27:11 -0800598
599 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
600 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
601
Gamze Abaka641fc072018-09-04 09:16:27 +0000602 VlanId deviceVlan = subscriber.sTag();
603 VlanId subscriberVlan = subscriber.cTag();
604
Gamze Abaka33feef52019-02-27 08:16:47 +0000605 MeterId upstreamMeterId = getMeterIdFromBpMapping(deviceId, subscriber.upstreamBandwidthProfile());
606 MeterId downstreamMeterId = getMeterIdFromBpMapping(deviceId, subscriber.downstreamBandwidthProfile());
Gamze Abaka641fc072018-09-04 09:16:27 +0000607
alshabib4ceaed32016-03-03 18:00:58 -0800608 ForwardingObjective.Builder upFwd = upBuilder(uplink, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000609 subscriberVlan, deviceVlan,
610 defaultVlan, upstreamMeterId, subscriber.technologyProfileId());
alshabib4ceaed32016-03-03 18:00:58 -0800611 ForwardingObjective.Builder downFwd = downBuilder(uplink, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000612 subscriberVlan, deviceVlan,
613 defaultVlan, downstreamMeterId, subscriber.technologyProfileId());
alshabibbf23a1f2016-01-14 17:27:11 -0800614
alshabib4ceaed32016-03-03 18:00:58 -0800615 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
616 @Override
617 public void onSuccess(Objective objective) {
618 upFuture.complete(null);
619 }
alshabibbf23a1f2016-01-14 17:27:11 -0800620
alshabib4ceaed32016-03-03 18:00:58 -0800621 @Override
622 public void onError(Objective objective, ObjectiveError error) {
623 upFuture.complete(error);
624 }
625 }));
626
627 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
628 @Override
629 public void onSuccess(Objective objective) {
630 downFuture.complete(null);
631 }
632
633 @Override
634 public void onError(Objective objective, ObjectiveError error) {
635 downFuture.complete(error);
636 }
637 }));
alshabibbf23a1f2016-01-14 17:27:11 -0800638
639 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
640 if (upStatus == null && downStatus == null) {
641 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_UNREGISTERED,
Gamze Abaka641fc072018-09-04 09:16:27 +0000642 deviceId,
643 deviceVlan,
644 subscriberVlan));
alshabibbf23a1f2016-01-14 17:27:11 -0800645 } else if (downStatus != null) {
646 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000647 "on port {} failed downstream uninstallation: {}",
648 subscriberVlan, deviceId, subscriberPort, downStatus);
alshabibbf23a1f2016-01-14 17:27:11 -0800649 } else if (upStatus != null) {
650 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000651 "on port {} failed upstream uninstallation: {}",
652 subscriberVlan, deviceId, subscriberPort, upStatus);
alshabibbf23a1f2016-01-14 17:27:11 -0800653 }
654 }, oltInstallers);
alshabibb7a9e172016-01-13 11:23:53 -0800655
Gamze Abaka33feef52019-02-27 08:16:47 +0000656 programmedMeters.remove(MeterKey.key(deviceId, upstreamMeterId));
657 programmedMeters.remove(MeterKey.key(deviceId, downstreamMeterId));
Gamze Abaka838d8142019-02-21 07:06:55 +0000658 log.debug("programmed Meters size {}", programmedMeters.size());
Jonathan Harte533a422015-10-20 17:31:24 -0700659 }
660
Gamze Abaka838d8142019-02-21 07:06:55 +0000661 /**
Gamze Abaka33feef52019-02-27 08:16:47 +0000662 * Adds subscriber vlan flows, dhcp, eapol and igmp trap flows for the related uni port.
Gamze Abaka838d8142019-02-21 07:06:55 +0000663 *
664 * @param port the connection point of the subscriber
665 * @param uplinkPort uplink port of the OLT
666 * @param defaultVlan default vlan of the subscriber
667 * @param sub subscriber information that includes s, c tags, tech profile and bandwidth profile references
Gamze Abaka838d8142019-02-21 07:06:55 +0000668 */
Gamze Abaka33feef52019-02-27 08:16:47 +0000669 private void provisionSubscriberBasedFlows(ConnectPoint port, PortNumber uplinkPort, Optional<VlanId> defaultVlan,
670 SubscriberAndDeviceInformation sub) {
Gamze Abaka641fc072018-09-04 09:16:27 +0000671
672 log.info("Provisioning vlans...");
673
674 DeviceId deviceId = port.deviceId();
675 PortNumber subscriberPort = port.port();
676 VlanId deviceVlan = sub.sTag();
677 VlanId subscriberVlan = sub.cTag();
678 int techProfId = sub.technologyProfileId();
679
680 BandwidthProfileInformation upstreamBpInfo = getBandwidthProfileInformation(sub.upstreamBandwidthProfile());
681 BandwidthProfileInformation downstreamBpInfo = getBandwidthProfileInformation(sub.downstreamBandwidthProfile());
682
alshabib3ea82642016-01-12 18:06:53 -0800683 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
684 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
Gamze Abaka33feef52019-02-27 08:16:47 +0000685 CompletableFuture<Object> upstreamMeterFuture = new CompletableFuture<>();
686 CompletableFuture<Object> downsteamMeterFuture = new CompletableFuture<>();
alshabib3ea82642016-01-12 18:06:53 -0800687
Gamze Abaka33feef52019-02-27 08:16:47 +0000688 MeterId upstreamMeterId = createMeter(deviceId, upstreamBpInfo, upstreamMeterFuture);
689 MeterId downstreamMeterId = createMeter(deviceId, downstreamBpInfo, downsteamMeterFuture);
Jonathan Harte533a422015-10-20 17:31:24 -0700690
Gamze Abaka33feef52019-02-27 08:16:47 +0000691 //install upstream flows
692 upstreamMeterFuture.thenAcceptAsync(result -> {
693 if (result == null) {
694 log.info("Upstream Meter {} is sent to the device {}. " +
695 "Sending subscriber flows.", upstreamMeterId, deviceId);
696 ForwardingObjective.Builder upFwd = upBuilder(uplinkPort, subscriberPort,
697 subscriberVlan, deviceVlan,
698 defaultVlan, upstreamMeterId, techProfId);
alshabib3ea82642016-01-12 18:06:53 -0800699
Gamze Abaka33feef52019-02-27 08:16:47 +0000700
701 flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
702 @Override
703 public void onSuccess(Objective objective) {
704 upFuture.complete(null);
705 }
706
707 @Override
708 public void onError(Objective objective, ObjectiveError error) {
709 upFuture.complete(error);
710 }
711 }));
712 } else {
713 log.warn("Meter installation error while sending upstream flows. " +
714 "Result {} and MeterId {}", result, upstreamMeterId);
alshabibbf23a1f2016-01-14 17:27:11 -0800715 }
Gamze Abaka33feef52019-02-27 08:16:47 +0000716 });
alshabibbf23a1f2016-01-14 17:27:11 -0800717
Gamze Abaka33feef52019-02-27 08:16:47 +0000718 //install downstream flows
719 downsteamMeterFuture.thenAcceptAsync(result -> {
720 if (result == null) {
721 log.info("Downstream Meter {} is sent to the device {}. " +
722 "Sending subscriber flows.", downstreamMeterId, deviceId);
723 ForwardingObjective.Builder downFwd = downBuilder(uplinkPort, subscriberPort,
724 subscriberVlan, deviceVlan,
725 defaultVlan, downstreamMeterId, techProfId);
726
727 flowObjectiveService.forward(deviceId, downFwd.add(new ObjectiveContext() {
728 @Override
729 public void onSuccess(Objective objective) {
730 downFuture.complete(null);
731 }
732
733 @Override
734 public void onError(Objective objective, ObjectiveError error) {
735 downFuture.complete(error);
736 }
737 }));
738 } else {
739 log.warn("Meter installation error while sending downstream flows. " +
740 "Result {} and MeterId {}", result, downstreamMeterId);
alshabibbf23a1f2016-01-14 17:27:11 -0800741 }
Gamze Abaka33feef52019-02-27 08:16:47 +0000742 });
alshabibbf23a1f2016-01-14 17:27:11 -0800743
Gamze Abaka33feef52019-02-27 08:16:47 +0000744 //send eapol & dhcp & igmp flows
745 //send Subscriber Registered event
alshabib3ea82642016-01-12 18:06:53 -0800746 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
747 if (upStatus == null && downStatus == null) {
Gamze Abaka33feef52019-02-27 08:16:47 +0000748
749 if (upstreamMeterId != null) {
750 //re-install Eapol authentication flow with the subscribers' upstream bandwidth profile
751 processEapolFilteringObjectives(deviceId, subscriberPort, sub.upstreamBandwidthProfile(),
Gamze Abakada282b42019-03-11 13:16:48 +0000752 null, sub.cTag(), true);
Gamze Abaka33feef52019-02-27 08:16:47 +0000753
754 processDhcpFilteringObjectives(deviceId, subscriberPort,
755 upstreamMeterId, sub.technologyProfileId(), true, true);
756
757 processIgmpFilteringObjectives(deviceId, subscriberPort,
758 upstreamMeterId, sub.technologyProfileId(), true);
759 }
760
alshabib3ea82642016-01-12 18:06:53 -0800761 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_REGISTERED,
Gamze Abaka641fc072018-09-04 09:16:27 +0000762 deviceId,
763 deviceVlan,
764 subscriberVlan));
alshabib50d9fc52016-02-12 15:47:20 -0800765
alshabib3ea82642016-01-12 18:06:53 -0800766 } else if (downStatus != null) {
767 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000768 "on port {} failed downstream installation: {}",
769 subscriberVlan, deviceId, subscriberPort, downStatus);
alshabib3ea82642016-01-12 18:06:53 -0800770 } else if (upStatus != null) {
771 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000772 "on port {} failed upstream installation: {}",
773 subscriberVlan, deviceId, subscriberPort, upStatus);
alshabib3ea82642016-01-12 18:06:53 -0800774 }
775 }, oltInstallers);
Jonathan Harte533a422015-10-20 17:31:24 -0700776 }
777
Gamze Abaka33feef52019-02-27 08:16:47 +0000778 private MeterId createMeter(DeviceId deviceId, BandwidthProfileInformation bpInfo,
779 CompletableFuture<Object> meterFuture) {
Gamze Abaka641fc072018-09-04 09:16:27 +0000780 if (bpInfo == null) {
781 log.warn("Bandwidth profile information is not found");
782 return null;
783 }
784
Gamze Abaka33feef52019-02-27 08:16:47 +0000785 MeterId meterId = getMeterIdFromBpMapping(deviceId, bpInfo.id());
Gamze Abaka641fc072018-09-04 09:16:27 +0000786 if (meterId != null) {
787 log.info("Meter is already added. MeterId {}", meterId);
Gamze Abaka33feef52019-02-27 08:16:47 +0000788 meterFuture.complete(null);
Gamze Abaka641fc072018-09-04 09:16:27 +0000789 return meterId;
790 }
791
792 List<Band> meterBands = createMeterBands(bpInfo);
793
794 MeterRequest meterRequest = DefaultMeterRequest.builder()
795 .withBands(meterBands)
796 .withUnit(Meter.Unit.KB_PER_SEC)
Gamze Abaka33feef52019-02-27 08:16:47 +0000797 .withContext(new MeterContext() {
798 @Override
799 public void onSuccess(MeterRequest op) {
800 log.debug("meter addition completed");
801 meterFuture.complete(null);
802 }
803
804 @Override
805 public void onError(MeterRequest op, MeterFailReason reason) {
806 meterFuture.complete(reason);
807 }
808 })
Gamze Abaka641fc072018-09-04 09:16:27 +0000809 .forDevice(deviceId)
810 .fromApp(appId)
811 .burst()
812 .add();
813
814 Meter meter = meterService.submit(meterRequest);
Gamze Abaka33feef52019-02-27 08:16:47 +0000815 addMeterIdToBpMapping(deviceId, meter.id(), bpInfo.id());
Gamze Abaka641fc072018-09-04 09:16:27 +0000816 log.info("Meter is created. Meter Id {}", meter.id());
Gamze Abaka33feef52019-02-27 08:16:47 +0000817 programmedMeters.add(MeterKey.key(deviceId, meter.id()));
Gamze Abaka838d8142019-02-21 07:06:55 +0000818 log.debug("programmed Meters size {}", programmedMeters.size());
Gamze Abaka641fc072018-09-04 09:16:27 +0000819 return meter.id();
820 }
821
822 private List<Band> createMeterBands(BandwidthProfileInformation bpInfo) {
823 List<Band> meterBands = new ArrayList<>();
824
825 meterBands.add(createMeterBand(bpInfo.committedInformationRate(), bpInfo.committedBurstSize()));
826 meterBands.add(createMeterBand(bpInfo.exceededInformationRate(), bpInfo.exceededBurstSize()));
Gamze Abakaad329652018-12-20 10:12:21 +0000827 meterBands.add(createMeterBand(bpInfo.assuredInformationRate(), 0L));
Gamze Abaka641fc072018-09-04 09:16:27 +0000828
Gamze Abaka641fc072018-09-04 09:16:27 +0000829 return meterBands;
830 }
831
832 private Band createMeterBand(long rate, Long burst) {
833 return DefaultBand.builder()
834 .withRate(rate) //already Kbps
835 .burstSize(burst) // already Kbits
836 .ofType(Band.Type.DROP) // no matter
837 .build();
838 }
839
alshabib4ceaed32016-03-03 18:00:58 -0800840 private ForwardingObjective.Builder downBuilder(PortNumber uplinkPort,
841 PortNumber subscriberPort,
842 VlanId subscriberVlan,
843 VlanId deviceVlan,
Gamze Abaka641fc072018-09-04 09:16:27 +0000844 Optional<VlanId> defaultVlan,
845 MeterId meterId,
846 int techProfId) {
alshabib4ceaed32016-03-03 18:00:58 -0800847 TrafficSelector downstream = DefaultTrafficSelector.builder()
848 .matchVlanId(deviceVlan)
849 .matchInPort(uplinkPort)
850 .matchInnerVlanId(subscriberVlan)
851 .build();
852
Gamze Abaka641fc072018-09-04 09:16:27 +0000853 TrafficTreatment.Builder downstreamTreatmentBuilder = DefaultTrafficTreatment.builder()
alshabib4ceaed32016-03-03 18:00:58 -0800854 .popVlan()
855 .setVlanId(defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan)))
Gamze Abaka641fc072018-09-04 09:16:27 +0000856 .setOutput(subscriberPort);
857
858 if (meterId != null) {
859 downstreamTreatmentBuilder.meter(meterId);
860 }
861
Gamze Abakaad329652018-12-20 10:12:21 +0000862 downstreamTreatmentBuilder.writeMetadata(createMetadata(subscriberVlan, techProfId, subscriberPort), 0);
alshabib4ceaed32016-03-03 18:00:58 -0800863
864 return DefaultForwardingObjective.builder()
865 .withFlag(ForwardingObjective.Flag.VERSATILE)
866 .withPriority(1000)
867 .makePermanent()
868 .withSelector(downstream)
869 .fromApp(appId)
Gamze Abaka641fc072018-09-04 09:16:27 +0000870 .withTreatment(downstreamTreatmentBuilder.build());
alshabib4ceaed32016-03-03 18:00:58 -0800871 }
872
873 private ForwardingObjective.Builder upBuilder(PortNumber uplinkPort,
874 PortNumber subscriberPort,
875 VlanId subscriberVlan,
876 VlanId deviceVlan,
Gamze Abaka641fc072018-09-04 09:16:27 +0000877 Optional<VlanId> defaultVlan,
878 MeterId meterId,
879 int technologyProfileId) {
880
881
882 VlanId dVlan = defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan));
883
884 if (subscriberVlan.toShort() == 4096) {
885 dVlan = subscriberVlan;
886 }
887
alshabib4ceaed32016-03-03 18:00:58 -0800888 TrafficSelector upstream = DefaultTrafficSelector.builder()
Gamze Abaka641fc072018-09-04 09:16:27 +0000889 .matchVlanId(dVlan)
alshabib4ceaed32016-03-03 18:00:58 -0800890 .matchInPort(subscriberPort)
891 .build();
892
893
Gamze Abaka641fc072018-09-04 09:16:27 +0000894 TrafficTreatment.Builder upstreamTreatmentBuilder = DefaultTrafficTreatment.builder()
alshabib4ceaed32016-03-03 18:00:58 -0800895 .pushVlan()
896 .setVlanId(subscriberVlan)
897 .pushVlan()
898 .setVlanId(deviceVlan)
Gamze Abaka641fc072018-09-04 09:16:27 +0000899 .setOutput(uplinkPort);
900
901 if (meterId != null) {
902 upstreamTreatmentBuilder.meter(meterId);
903 }
904
Gamze Abakaad329652018-12-20 10:12:21 +0000905 upstreamTreatmentBuilder.writeMetadata(createMetadata(deviceVlan, technologyProfileId, uplinkPort), 0L);
alshabib4ceaed32016-03-03 18:00:58 -0800906
907 return DefaultForwardingObjective.builder()
908 .withFlag(ForwardingObjective.Flag.VERSATILE)
909 .withPriority(1000)
910 .makePermanent()
911 .withSelector(upstream)
912 .fromApp(appId)
Gamze Abaka641fc072018-09-04 09:16:27 +0000913 .withTreatment(upstreamTreatmentBuilder.build());
alshabib4ceaed32016-03-03 18:00:58 -0800914 }
Gamze Abakaad329652018-12-20 10:12:21 +0000915
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100916 private void provisionTransparentFlows(DeviceId deviceId, PortNumber uplinkPort,
917 PortNumber subscriberPort,
918 VlanId innerVlan,
919 VlanId outerVlan) {
920
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100921 ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
922
Gamze Abakaf59c0912019-04-19 08:24:28 +0000923 SubscriberAndDeviceInformation subInfo = getSubscriber(cp);
924
925 BandwidthProfileInformation upstreamBpInfo = getBandwidthProfileInformation(
926 subInfo.upstreamBandwidthProfile());
927 BandwidthProfileInformation downstreamBpInfo = getBandwidthProfileInformation(
928 subInfo.downstreamBandwidthProfile());
929
930 CompletableFuture<Object> upstreamMeterFuture = new CompletableFuture<>();
931 CompletableFuture<Object> downsteamMeterFuture = new CompletableFuture<>();
932 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
933 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
934
935 MeterId upstreamMeterId = createMeter(deviceId, upstreamBpInfo, upstreamMeterFuture);
936 MeterId downstreamMeterId = createMeter(deviceId, downstreamBpInfo, downsteamMeterFuture);
937
938 upstreamMeterFuture.thenAcceptAsync(result -> {
939 if (result == null) {
940 log.info("Upstream Meter {} is sent to the device {}. " +
941 "Sending subscriber flows.", upstreamMeterId, deviceId);
942
943 ForwardingObjective.Builder upFwd = transparentUpBuilder(uplinkPort, subscriberPort,
944 innerVlan, outerVlan, upstreamMeterId, subInfo);
945
946 flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
947 @Override
948 public void onSuccess(Objective objective) {
949 upFuture.complete(null);
950 }
951
952 @Override
953 public void onError(Objective objective, ObjectiveError error) {
954 upFuture.complete(error);
955 }
956 }));
957
958 } else {
959 log.warn("Meter installation error while sending upstream flows. " +
960 "Result {} and MeterId {}", result, upstreamMeterId);
961 }
962 });
963
964 downsteamMeterFuture.thenAcceptAsync(result -> {
965 if (result == null) {
966 log.info("Downstream Meter {} is sent to the device {}. " +
967 "Sending subscriber flows.", downstreamMeterId, deviceId);
968
969 ForwardingObjective.Builder downFwd = transparentDownBuilder(uplinkPort, subscriberPort,
970 innerVlan, outerVlan, downstreamMeterId, subInfo);
971
972 flowObjectiveService.forward(deviceId, downFwd.add(new ObjectiveContext() {
973 @Override
974 public void onSuccess(Objective objective) {
975 downFuture.complete(null);
976 }
977
978 @Override
979 public void onError(Objective objective, ObjectiveError error) {
980 downFuture.complete(error);
981 }
982 }));
983 } else {
984 log.warn("Meter installation error while sending upstream flows. " +
985 "Result {} and MeterId {}", result, downstreamMeterId);
986 }
987 });
988
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100989 additionalVlans.put(cp, new AbstractMap.SimpleEntry(outerVlan, innerVlan));
990
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100991 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
992 if (downStatus != null) {
993 log.error("Flow with innervlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000994 "on port {} failed downstream installation: {}",
Gamze Abakaf59c0912019-04-19 08:24:28 +0000995 innerVlan, outerVlan, deviceId, cp, downStatus);
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100996 } else if (upStatus != null) {
997 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000998 "on port {} failed upstream installation: {}",
Gamze Abakaf59c0912019-04-19 08:24:28 +0000999 innerVlan, outerVlan, deviceId, cp, upStatus);
1000 } else {
1001 processEapolFilteringObjectives(deviceId, subscriberPort, subInfo.upstreamBandwidthProfile(),
1002 null, subInfo.cTag(), true);
1003
1004 // cache subscriber info
1005 programmedSubs.put(cp, subInfo);
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001006 }
1007 }, oltInstallers);
1008
1009 }
1010
1011 private ForwardingObjective.Builder transparentDownBuilder(PortNumber uplinkPort,
1012 PortNumber subscriberPort,
1013 VlanId innerVlan,
Gamze Abakaf59c0912019-04-19 08:24:28 +00001014 VlanId outerVlan,
1015 MeterId downstreamMeterId,
1016 SubscriberAndDeviceInformation subInfo) {
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001017 TrafficSelector downstream = DefaultTrafficSelector.builder()
1018 .matchVlanId(outerVlan)
1019 .matchInPort(uplinkPort)
1020 .matchInnerVlanId(innerVlan)
1021 .build();
1022
Gamze Abakaf59c0912019-04-19 08:24:28 +00001023 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1024 if (downstreamMeterId != null) {
1025 tBuilder.meter(downstreamMeterId);
1026 }
1027
1028 TrafficTreatment downstreamTreatment = tBuilder
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001029 .setOutput(subscriberPort)
Gamze Abakaf59c0912019-04-19 08:24:28 +00001030 .writeMetadata(createMetadata(subInfo.cTag(), subInfo.technologyProfileId(), subscriberPort), 0)
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001031 .build();
1032
1033 return DefaultForwardingObjective.builder()
1034 .withFlag(ForwardingObjective.Flag.VERSATILE)
1035 .withPriority(1000)
1036 .makePermanent()
1037 .withSelector(downstream)
1038 .fromApp(appId)
1039 .withTreatment(downstreamTreatment);
1040 }
1041
1042 private ForwardingObjective.Builder transparentUpBuilder(PortNumber uplinkPort,
1043 PortNumber subscriberPort,
1044 VlanId innerVlan,
Gamze Abakaf59c0912019-04-19 08:24:28 +00001045 VlanId outerVlan,
1046 MeterId upstreamMeterId,
1047 SubscriberAndDeviceInformation subInfo) {
1048
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001049 TrafficSelector upstream = DefaultTrafficSelector.builder()
1050 .matchVlanId(outerVlan)
1051 .matchInPort(subscriberPort)
1052 .matchInnerVlanId(innerVlan)
1053 .build();
1054
Gamze Abakaf59c0912019-04-19 08:24:28 +00001055 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1056 if (upstreamMeterId != null) {
1057 tBuilder.meter(upstreamMeterId);
1058 }
1059
1060 TrafficTreatment upstreamTreatment = tBuilder
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001061 .setOutput(uplinkPort)
Gamze Abakaf59c0912019-04-19 08:24:28 +00001062 .writeMetadata(createMetadata(subInfo.sTag(), subInfo.technologyProfileId(), uplinkPort), 0)
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001063 .build();
1064
1065 return DefaultForwardingObjective.builder()
1066 .withFlag(ForwardingObjective.Flag.VERSATILE)
1067 .withPriority(1000)
1068 .makePermanent()
1069 .withSelector(upstream)
1070 .fromApp(appId)
1071 .withTreatment(upstreamTreatment);
1072 }
1073
1074 private void unprovisionTransparentFlows(DeviceId deviceId, PortNumber uplink,
1075 PortNumber subscriberPort, VlanId innerVlan,
1076 VlanId outerVlan) {
1077
1078 ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
1079
Gamze Abakaf59c0912019-04-19 08:24:28 +00001080 SubscriberAndDeviceInformation subInfo = programmedSubs.get(cp);
1081 if (subInfo == null) {
1082 log.warn("Subscriber is not programmed before for the connectPoint {}", cp);
1083 return;
1084 }
1085
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001086 additionalVlans.remove(cp, new AbstractMap.SimpleEntry(outerVlan, innerVlan));
1087
1088 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
1089 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
1090
Gamze Abakaf59c0912019-04-19 08:24:28 +00001091 MeterId upstreamMeterId = getMeterIdFromBpMapping(deviceId, subInfo.upstreamBandwidthProfile());
1092 MeterId downstreamMeterId = getMeterIdFromBpMapping(deviceId, subInfo.downstreamBandwidthProfile());
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001093
Gamze Abakaf59c0912019-04-19 08:24:28 +00001094 ForwardingObjective.Builder upFwd = transparentUpBuilder(uplink, subscriberPort,
1095 innerVlan, outerVlan, upstreamMeterId, subInfo);
1096 ForwardingObjective.Builder downFwd = transparentDownBuilder(uplink, subscriberPort,
1097 innerVlan, outerVlan, downstreamMeterId, subInfo);
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001098
1099 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
1100 @Override
1101 public void onSuccess(Objective objective) {
1102 upFuture.complete(null);
1103 }
1104
1105 @Override
1106 public void onError(Objective objective, ObjectiveError error) {
1107 upFuture.complete(error);
1108 }
1109 }));
1110
1111 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
1112 @Override
1113 public void onSuccess(Objective objective) {
1114 downFuture.complete(null);
1115 }
1116
1117 @Override
1118 public void onError(Objective objective, ObjectiveError error) {
1119 downFuture.complete(error);
1120 }
1121 }));
1122
1123 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
1124 if (downStatus != null) {
1125 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +00001126 "on port {} failed downstream uninstallation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001127 innerVlan, outerVlan, deviceId, subscriberPort, downStatus);
1128 } else if (upStatus != null) {
1129 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +00001130 "on port {} failed upstream uninstallation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001131 innerVlan, outerVlan, deviceId, subscriberPort, upStatus);
1132 }
1133 }, oltInstallers);
1134
Gamze Abakaf59c0912019-04-19 08:24:28 +00001135 //re-install eapol
1136 processEapolFilteringObjectives(deviceId, subscriberPort,
1137 subInfo.upstreamBandwidthProfile(), null, subInfo.cTag(), false);
1138 processEapolFilteringObjectives(deviceId, subscriberPort, defaultBpId,
1139 null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
1140
1141 programmedMeters.remove(MeterKey.key(deviceId, upstreamMeterId));
1142 programmedMeters.remove(MeterKey.key(deviceId, downstreamMeterId));
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001143 }
1144
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001145 private int getDefaultTechProfileId(DeviceId devId, PortNumber portNumber) {
1146 Port port = deviceService.getPort(devId, portNumber);
Andy Bavier160e8682019-05-07 18:32:22 -07001147 if (port != null) {
1148 SubscriberAndDeviceInformation info = subsService.get(port.annotations().value(AnnotationKeys.PORT_NAME));
1149 if (info != null && info.technologyProfileId() != -1) {
1150 return info.technologyProfileId();
1151 }
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001152 }
1153 return defaultTechProfileId;
1154 }
1155
Gamze Abaka838d8142019-02-21 07:06:55 +00001156 /**
Gamze Abakada282b42019-03-11 13:16:48 +00001157 * Returns the write metadata value including tech profile reference and innerVlan.
1158 * For param cVlan, null can be sent
Gamze Abaka838d8142019-02-21 07:06:55 +00001159 *
Gamze Abakada282b42019-03-11 13:16:48 +00001160 * @param cVlan c (customer) tag of one subscriber
Gamze Abaka838d8142019-02-21 07:06:55 +00001161 * @param techProfileId tech profile id of one subscriber
Gamze Abakada282b42019-03-11 13:16:48 +00001162 * @return the write metadata value including tech profile reference and innerVlan
Gamze Abaka838d8142019-02-21 07:06:55 +00001163 */
Gamze Abakada282b42019-03-11 13:16:48 +00001164 private Long createTechProfValueForWm(VlanId cVlan, int techProfileId) {
1165 if (cVlan == null) {
1166 return (long) techProfileId << 32;
1167 }
1168 return ((long) (cVlan.id()) << 48 | (long) techProfileId << 32);
Gamze Abaka838d8142019-02-21 07:06:55 +00001169 }
1170
1171 /**
1172 * Trap eapol authentication packets to the controller.
1173 *
Gamze Abaka33feef52019-02-27 08:16:47 +00001174 * @param devId the device identifier
1175 * @param portNumber the port for which this trap flow is designated
1176 * @param bpId bandwidth profile id to add the related meter to the flow
1177 * @param filterFuture completable future for this filtering objective operation
Gamze Abakada282b42019-03-11 13:16:48 +00001178 * @param vlanId the default or customer tag for a subscriber
Gamze Abaka33feef52019-02-27 08:16:47 +00001179 * @param install true to install the flow, false to remove the flow
Gamze Abaka838d8142019-02-21 07:06:55 +00001180 */
Gamze Abaka33feef52019-02-27 08:16:47 +00001181 private void processEapolFilteringObjectives(DeviceId devId, PortNumber portNumber, String bpId,
1182 CompletableFuture<ObjectiveError> filterFuture,
Gamze Abakada282b42019-03-11 13:16:48 +00001183 VlanId vlanId, boolean install) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001184
1185 if (!enableEapol) {
1186 log.debug("Eapol filtering is disabled.");
1187 if (filterFuture != null) {
1188 filterFuture.complete(null);
1189 }
1190 return;
1191 }
1192
alshabib09753b52016-03-04 14:55:19 -08001193 if (!mastershipService.isLocalMaster(devId)) {
1194 return;
1195 }
alshabibbb83aa22016-02-10 15:08:23 -08001196 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Gamze Abakaad329652018-12-20 10:12:21 +00001197 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
Gamze Abaka33feef52019-02-27 08:16:47 +00001198 CompletableFuture<Object> meterFuture = new CompletableFuture<>();
Gamze Abaka838d8142019-02-21 07:06:55 +00001199 MeterId meterId;
alshabibbb83aa22016-02-10 15:08:23 -08001200
Gamze Abaka838d8142019-02-21 07:06:55 +00001201 BandwidthProfileInformation bpInfo = getBandwidthProfileInformation(bpId);
1202 if (bpInfo != null) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001203 meterId = createMeter(devId, bpInfo, meterFuture);
Gamze Abakaad329652018-12-20 10:12:21 +00001204 treatmentBuilder.meter(meterId);
1205 } else {
Gamze Abaka838d8142019-02-21 07:06:55 +00001206 log.warn("Bandwidth profile {} is not found. Authentication flow will not be installed", bpId);
1207 return;
Gamze Abakaad329652018-12-20 10:12:21 +00001208 }
1209
Gamze Abaka33feef52019-02-27 08:16:47 +00001210 meterFuture.thenAcceptAsync(result -> {
1211 if (result == null) {
1212 log.info("Meter {} for the device {} is installed. " +
1213 "{} EAPOL trap flow", meterId, devId, install ? "Installing " : "Removing ");
1214 int techProfileId = getDefaultTechProfileId(devId, portNumber);
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001215
Gamze Abaka33feef52019-02-27 08:16:47 +00001216 //Authentication trap flow uses only tech profile id as write metadata value
1217 FilteringObjective eapol = (install ? builder.permit() : builder.deny())
1218 .withKey(Criteria.matchInPort(portNumber))
1219 .addCondition(Criteria.matchEthType(EthType.EtherType.EAPOL.ethType()))
Gamze Abakada282b42019-03-11 13:16:48 +00001220 .addCondition(Criteria.matchVlanId(vlanId))
Gamze Abaka33feef52019-02-27 08:16:47 +00001221 .withMeta(treatmentBuilder
Gamze Abakada282b42019-03-11 13:16:48 +00001222 .writeMetadata(createTechProfValueForWm(vlanId, techProfileId), 0)
Gamze Abaka33feef52019-02-27 08:16:47 +00001223 .setOutput(PortNumber.CONTROLLER).build())
1224 .fromApp(appId)
1225 .withPriority(10000)
1226 .add(new ObjectiveContext() {
1227 @Override
1228 public void onSuccess(Objective objective) {
1229 log.info("Eapol filter for {} on {} {} with meter {}.",
1230 devId, portNumber, (install) ? INSTALLED : REMOVED, meterId);
1231 if (filterFuture != null) {
1232 filterFuture.complete(null);
1233 }
1234 }
alshabibdec2e252016-01-15 12:20:25 -08001235
Gamze Abaka33feef52019-02-27 08:16:47 +00001236 @Override
1237 public void onError(Objective objective, ObjectiveError error) {
1238 log.info("Eapol filter for {} on {} with meter {} failed {} because {}",
1239 devId, portNumber, meterId, (install) ? INSTALLATION : REMOVAL,
1240 error);
1241 if (filterFuture != null) {
1242 filterFuture.complete(error);
1243 }
1244 }
1245 });
alshabibdec2e252016-01-15 12:20:25 -08001246
Gamze Abaka33feef52019-02-27 08:16:47 +00001247 flowObjectiveService.filter(devId, eapol);
1248 } else {
1249 log.warn("Meter installation error while sending eapol trap flow. " +
1250 "Result {} and MeterId {}", result, meterId);
1251 }
1252 });
alshabibdec2e252016-01-15 12:20:25 -08001253 }
1254
Jonathan Hart403372d2018-08-22 11:44:13 -07001255 /**
1256 * Installs trap filtering objectives for particular traffic types on an
1257 * NNI port.
1258 *
Gamze Abakaad329652018-12-20 10:12:21 +00001259 * @param devId device ID
1260 * @param port port number
Jonathan Hart403372d2018-08-22 11:44:13 -07001261 * @param install true to install, false to remove
1262 */
1263 private void processNniFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
1264 processLldpFilteringObjective(devId, port, install);
Gamze Abaka33feef52019-02-27 08:16:47 +00001265 processDhcpFilteringObjectives(devId, port, null, -1, install, false);
Jonathan Hart403372d2018-08-22 11:44:13 -07001266 }
1267
1268 private void processLldpFilteringObjective(DeviceId devId, PortNumber port, boolean install) {
1269 if (!mastershipService.isLocalMaster(devId)) {
1270 return;
1271 }
1272 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
1273
1274 FilteringObjective lldp = (install ? builder.permit() : builder.deny())
1275 .withKey(Criteria.matchInPort(port))
1276 .addCondition(Criteria.matchEthType(EthType.EtherType.LLDP.ethType()))
1277 .withMeta(DefaultTrafficTreatment.builder()
1278 .setOutput(PortNumber.CONTROLLER).build())
1279 .fromApp(appId)
1280 .withPriority(10000)
1281 .add(new ObjectiveContext() {
1282 @Override
1283 public void onSuccess(Objective objective) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001284 log.info("LLDP filter for device {} on port {} {}.",
Gamze Abaka838d8142019-02-21 07:06:55 +00001285 devId, port, (install) ? INSTALLED : REMOVED);
Jonathan Hart403372d2018-08-22 11:44:13 -07001286 }
1287
1288 @Override
1289 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001290 log.info("LLDP filter for device {} on port {} failed {} because {}",
Gamze Abaka838d8142019-02-21 07:06:55 +00001291 devId, port, (install) ? INSTALLATION : REMOVAL,
Saurav Das82b8e6d2018-10-04 15:25:12 -07001292 error);
Jonathan Hart403372d2018-08-22 11:44:13 -07001293 }
1294 });
1295
1296 flowObjectiveService.filter(devId, lldp);
1297
1298 }
1299
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001300 /**
1301 * Trap dhcp packets to the controller.
1302 *
Gamze Abaka838d8142019-02-21 07:06:55 +00001303 * @param devId the device identifier
1304 * @param port the port for which this trap flow is designated
1305 * @param upstreamMeterId the upstream meter id that includes the upstream
1306 * bandwidth profile values such as PIR,CIR. If no meter id needs to be referenced,
1307 * null can be sent
1308 * @param techProfileId the technology profile id that is used to create write
1309 * metadata instruction value. If no tech profile id needs to be referenced,
1310 * -1 can be sent
1311 * @param install true to install the flow, false to remove the flow
1312 * @param upstream true if trapped packets are flowing upstream towards
1313 * server, false if packets are flowing downstream towards client
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001314 */
1315 private void processDhcpFilteringObjectives(DeviceId devId, PortNumber port,
Gamze Abaka838d8142019-02-21 07:06:55 +00001316 MeterId upstreamMeterId,
1317 int techProfileId,
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001318 boolean install,
1319 boolean upstream) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001320
1321 if (!enableDhcpOnProvisioning) {
1322 log.debug("Dhcp provisioning is disabled.");
1323 return;
1324 }
1325
Amit Ghosh95e2f652017-08-23 12:49:46 +01001326 if (!mastershipService.isLocalMaster(devId)) {
1327 return;
1328 }
Amit Ghosh95e2f652017-08-23 12:49:46 +01001329
Matteo Scandolo63460d12018-11-02 16:19:04 -07001330 if (enableDhcpV4) {
1331 int udpSrc = (upstream) ? 68 : 67;
1332 int udpDst = (upstream) ? 67 : 68;
1333
1334 EthType ethType = EthType.EtherType.IPV4.ethType();
1335 byte protocol = IPv4.PROTOCOL_UDP;
1336
Gamze Abaka838d8142019-02-21 07:06:55 +00001337 this.addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType,
1338 upstreamMeterId, techProfileId, protocol, install);
Matteo Scandolo63460d12018-11-02 16:19:04 -07001339 }
1340
1341 if (enableDhcpV6) {
1342 int udpSrc = (upstream) ? 547 : 546;
1343 int udpDst = (upstream) ? 546 : 547;
1344
1345 EthType ethType = EthType.EtherType.IPV6.ethType();
1346 byte protocol = IPv6.PROTOCOL_UDP;
1347
Gamze Abaka838d8142019-02-21 07:06:55 +00001348 this.addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType,
1349 upstreamMeterId, techProfileId, protocol, install);
Matteo Scandolo63460d12018-11-02 16:19:04 -07001350 }
1351
1352 }
1353
1354 private void addDhcpFilteringObjectives(DeviceId devId,
1355 PortNumber port,
1356 int udpSrc,
1357 int udpDst,
1358 EthType ethType,
Gamze Abaka838d8142019-02-21 07:06:55 +00001359 MeterId upstreamMeterId,
1360 int techProfileId,
Matteo Scandolo63460d12018-11-02 16:19:04 -07001361 byte protocol,
1362 boolean install) {
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001363
1364 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Gamze Abaka838d8142019-02-21 07:06:55 +00001365 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
1366
1367 if (upstreamMeterId != null) {
1368 treatmentBuilder.meter(upstreamMeterId);
1369 }
1370
1371 if (techProfileId != -1) {
Gamze Abakada282b42019-03-11 13:16:48 +00001372 treatmentBuilder.writeMetadata(createTechProfValueForWm(null, techProfileId), 0);
Gamze Abaka838d8142019-02-21 07:06:55 +00001373 }
1374
Amit Ghosh95e2f652017-08-23 12:49:46 +01001375 FilteringObjective dhcpUpstream = (install ? builder.permit() : builder.deny())
1376 .withKey(Criteria.matchInPort(port))
Matteo Scandolo63460d12018-11-02 16:19:04 -07001377 .addCondition(Criteria.matchEthType(ethType))
1378 .addCondition(Criteria.matchIPProtocol(protocol))
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001379 .addCondition(Criteria.matchUdpSrc(TpPort.tpPort(udpSrc)))
1380 .addCondition(Criteria.matchUdpDst(TpPort.tpPort(udpDst)))
Gamze Abaka838d8142019-02-21 07:06:55 +00001381 .withMeta(treatmentBuilder
Gamze Abaka641fc072018-09-04 09:16:27 +00001382 .setOutput(PortNumber.CONTROLLER).build())
Amit Ghosh95e2f652017-08-23 12:49:46 +01001383 .fromApp(appId)
Matt Jeanneret3f579262018-06-14 17:16:23 -04001384 .withPriority(10000)
Amit Ghosh95e2f652017-08-23 12:49:46 +01001385 .add(new ObjectiveContext() {
1386 @Override
1387 public void onSuccess(Objective objective) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001388 log.info("DHCP {} filter for device {} on port {} {}.",
Gamze Abakaad329652018-12-20 10:12:21 +00001389 (ethType.equals(EthType.EtherType.IPV4.ethType())) ? "v4" : "v6",
Gamze Abaka838d8142019-02-21 07:06:55 +00001390 devId, port, (install) ? INSTALLED : REMOVED);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001391 }
1392
1393 @Override
1394 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001395 log.info("DHCP {} filter for device {} on port {} failed {} because {}",
Gamze Abakaad329652018-12-20 10:12:21 +00001396 (ethType.equals(EthType.EtherType.IPV4.ethType())) ? "v4" : "v6",
Gamze Abaka838d8142019-02-21 07:06:55 +00001397 devId, port, (install) ? INSTALLATION : REMOVAL,
Gamze Abakaad329652018-12-20 10:12:21 +00001398 error);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001399 }
1400 });
1401
1402 flowObjectiveService.filter(devId, dhcpUpstream);
1403 }
1404
Gamze Abaka838d8142019-02-21 07:06:55 +00001405 private void processIgmpFilteringObjectives(DeviceId devId, PortNumber port,
1406 MeterId upstreamMeterId,
1407 int techProfileId,
1408 boolean install) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001409
Gamze Abakaf59c0912019-04-19 08:24:28 +00001410 if (!enableIgmpOnProvisioning) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001411 log.debug("Igmp provisioning is disabled.");
1412 return;
1413 }
1414
Amit Ghosh95e2f652017-08-23 12:49:46 +01001415 if (!mastershipService.isLocalMaster(devId)) {
1416 return;
1417 }
1418
Gamze Abaka641fc072018-09-04 09:16:27 +00001419 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Gamze Abaka838d8142019-02-21 07:06:55 +00001420 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
1421
1422 if (upstreamMeterId != null) {
1423 treatmentBuilder.meter(upstreamMeterId);
1424 }
1425
1426 if (techProfileId != -1) {
Gamze Abakada282b42019-03-11 13:16:48 +00001427 treatmentBuilder.writeMetadata(createTechProfValueForWm(null, techProfileId), 0);
Gamze Abaka838d8142019-02-21 07:06:55 +00001428 }
Amit Ghosh95e2f652017-08-23 12:49:46 +01001429
1430 builder = install ? builder.permit() : builder.deny();
1431
1432 FilteringObjective igmp = builder
1433 .withKey(Criteria.matchInPort(port))
1434 .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
1435 .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_IGMP))
Gamze Abaka838d8142019-02-21 07:06:55 +00001436 .withMeta(treatmentBuilder
Gamze Abaka641fc072018-09-04 09:16:27 +00001437 .setOutput(PortNumber.CONTROLLER).build())
Amit Ghosh95e2f652017-08-23 12:49:46 +01001438 .fromApp(appId)
1439 .withPriority(10000)
1440 .add(new ObjectiveContext() {
1441 @Override
1442 public void onSuccess(Objective objective) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001443 log.info("Igmp filter for {} on {} {}.",
Gamze Abaka838d8142019-02-21 07:06:55 +00001444 devId, port, (install) ? INSTALLED : REMOVED);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001445 }
1446
1447 @Override
1448 public void onError(Objective objective, ObjectiveError error) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001449 log.info("Igmp filter for {} on {} failed {} because {}.",
Gamze Abaka838d8142019-02-21 07:06:55 +00001450 devId, port, (install) ? INSTALLATION : REMOVAL,
Gamze Abaka641fc072018-09-04 09:16:27 +00001451 error);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001452 }
1453 });
1454
1455 flowObjectiveService.filter(devId, igmp);
1456 }
1457
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001458 /**
Jonathan Hart403372d2018-08-22 11:44:13 -07001459 * Creates trap flows for device, including DHCP and LLDP trap on NNI and
1460 * EAPOL trap on the UNIs, if device is present in Sadis config.
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001461 *
1462 * @param dev Device to look for
1463 */
Jonathan Hart403372d2018-08-22 11:44:13 -07001464 private void checkAndCreateDeviceFlows(Device dev) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001465 // we create only for the ones we are master of
1466 if (!mastershipService.isLocalMaster(dev.id())) {
Gamze Abaka641fc072018-09-04 09:16:27 +00001467 return;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001468 }
1469 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +00001470 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Jonathan Hart403372d2018-08-22 11:44:13 -07001471 log.debug("checkAndCreateDeviceFlows: deviceInfo {}", deviceInfo);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001472
1473 if (deviceInfo != null) {
Jonathan Hart403372d2018-08-22 11:44:13 -07001474 // This is an OLT device as per Sadis, we create flows for UNI and NNI ports
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001475 for (Port p : deviceService.getPorts(dev.id())) {
1476 if (isUniPort(dev, p)) {
Gamze Abakada282b42019-03-11 13:16:48 +00001477 processEapolFilteringObjectives(dev.id(), p.number(), defaultBpId, null,
1478 VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
Jonathan Hart403372d2018-08-22 11:44:13 -07001479 } else {
1480 processNniFilteringObjectives(dev.id(), p.number(), true);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001481 }
1482 }
1483 }
1484 }
1485
Jonathan Hart403372d2018-08-22 11:44:13 -07001486
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001487 /**
1488 * Get the uplink for of the OLT device.
Gamze Abakaad329652018-12-20 10:12:21 +00001489 * <p>
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001490 * This assumes that the OLT has a single uplink port. When more uplink ports need to be supported
1491 * this logic needs to be changed
1492 *
1493 * @param dev Device to look for
1494 * @return The uplink Port of the OLT
1495 */
1496 private Port getUplinkPort(Device dev) {
1497 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +00001498 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001499 log.debug("getUplinkPort: deviceInfo {}", deviceInfo);
Saurav Das82b8e6d2018-10-04 15:25:12 -07001500 if (deviceInfo == null) {
1501 log.warn("Device {} is not configured in SADIS .. cannot fetch device"
1502 + " info", dev.id());
1503 return null;
1504 }
1505 // Return the port that has been configured as the uplink port of this OLT in Sadis
Gamze Abakaad329652018-12-20 10:12:21 +00001506 for (Port p : deviceService.getPorts(dev.id())) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001507 if (p.number().toLong() == deviceInfo.uplinkPort()) {
1508 log.debug("getUplinkPort: Found port {}", p);
1509 return p;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001510 }
1511 }
1512
Gamze Abaka838d8142019-02-21 07:06:55 +00001513 log.debug("getUplinkPort: " + NO_UPLINK_PORT, dev.id());
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001514 return null;
1515 }
1516
1517 /**
1518 * Return the subscriber on a port.
1519 *
Matteo Scandolo962a6ad2018-12-11 15:39:42 -08001520 * @param cp ConnectPoint on which to find the subscriber
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001521 * @return subscriber if found else null
1522 */
Matteo Scandolo962a6ad2018-12-11 15:39:42 -08001523 SubscriberAndDeviceInformation getSubscriber(ConnectPoint cp) {
1524 Port port = deviceService.getPort(cp);
1525 checkNotNull(port, "Invalid connect point");
1526 String portName = port.annotations().value(AnnotationKeys.PORT_NAME);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001527 return subsService.get(portName);
1528 }
1529
Gamze Abakaad329652018-12-20 10:12:21 +00001530 /**
1531 * Write metadata instruction value (metadata) is 8 bytes.
Gamze Abaka838d8142019-02-21 07:06:55 +00001532 * <p>
Gamze Abakaad329652018-12-20 10:12:21 +00001533 * MS 2 bytes: C Tag
1534 * Next 2 bytes: Technology Profile Id
1535 * Next 4 bytes: Port number (uni or nni)
1536 */
1537
1538 private Long createMetadata(VlanId innerVlan, int techProfileId, PortNumber egressPort) {
1539
1540 if (techProfileId == -1) {
1541 techProfileId = DEFAULT_TP_ID;
1542 }
1543
1544 return ((long) (innerVlan.id()) << 48 | (long) techProfileId << 32) | egressPort.toLong();
1545 }
1546
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001547 private boolean isUniPort(Device d, Port p) {
1548 Port ulPort = getUplinkPort(d);
1549 if (ulPort != null) {
1550 return (ulPort.number().toLong() != p.number().toLong());
1551 }
1552 return false;
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001553 }
1554
Jonathan Hart4c538002018-08-23 10:11:54 -07001555 private SubscriberAndDeviceInformation getOltInfo(Device dev) {
1556 String devSerialNo = dev.serialNumber();
Gamze Abaka641fc072018-09-04 09:16:27 +00001557 return subsService.get(devSerialNo);
Jonathan Hart4c538002018-08-23 10:11:54 -07001558 }
1559
Gamze Abaka33feef52019-02-27 08:16:47 +00001560 private MeterId getMeterIdFromBpMapping(DeviceId deviceId, String bandwidthProfile) {
1561
1562 if (bpInfoToMeter.get(bandwidthProfile) == null) {
1563 log.warn("Bandwidth Profile '{}' is not found in bandwidth profile map.", bandwidthProfile);
1564 return null;
1565 }
1566
1567 Optional<MeterKey> meterKeyForDevice = bpInfoToMeter.get(bandwidthProfile)
1568 .stream()
1569 .filter(meterKey -> meterKey.deviceId().equals(deviceId))
1570 .findFirst();
1571 return meterKeyForDevice.isPresent() ? meterKeyForDevice.get().meterId() : null;
1572 }
1573
1574 private void addMeterIdToBpMapping(DeviceId deviceId, MeterId meterId, String bandwidthProfile) {
1575
1576 if (bpInfoToMeter.get(bandwidthProfile) == null) {
1577 bpInfoToMeter.put(bandwidthProfile,
1578 new ArrayList<>(Arrays.asList(MeterKey.key(deviceId, meterId))));
1579 } else {
Gamze Abaka33feef52019-02-27 08:16:47 +00001580 List<MeterKey> meterKeyListForBp = bpInfoToMeter.get(bandwidthProfile);
1581 meterKeyListForBp.add(MeterKey.key(deviceId, meterId));
1582 }
1583 }
1584
1585 private void removeMeterIdFromBpMapping(DeviceId deviceId, String bandwidthProfileId) {
1586 List<MeterKey> meterKeysForBp = bpInfoToMeter.get(bandwidthProfileId);
1587 if (meterKeysForBp != null) {
1588 meterKeysForBp.stream()
1589 .filter(meterKey -> meterKey.deviceId().equals(deviceId))
1590 .findFirst().ifPresent(mk -> {
1591 meterKeysForBp.remove(mk);
1592 programmedMeters.remove(mk);
1593 });
1594 }
1595 }
1596
alshabibf0e7e702015-05-30 18:22:36 -07001597 private class InternalDeviceListener implements DeviceListener {
Saurav Dasa9d5f442019-03-06 19:32:48 -08001598 private Set<DeviceId> programmedDevices = Sets.newConcurrentHashSet();
1599
alshabibf0e7e702015-05-30 18:22:36 -07001600 @Override
1601 public void event(DeviceEvent event) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001602 eventExecutor.execute(() -> {
1603 DeviceId devId = event.subject().id();
1604 Device dev = event.subject();
Gamze Abaka838d8142019-02-21 07:06:55 +00001605 Port port = event.port();
Jonathan Hart4c538002018-08-23 10:11:54 -07001606
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001607 if (event.type() == DeviceEvent.Type.PORT_STATS_UPDATED) {
1608 return;
1609 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001610
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001611 if (getOltInfo(dev) == null) {
Saurav Dasa9d5f442019-03-06 19:32:48 -08001612 // it's possible that we got an event for a previously
1613 // programmed OLT that is no longer available in SADIS
1614 // we let such events go through
1615 if (!programmedDevices.contains(devId)) {
1616 log.warn("No device info found for {}, this is either "
1617 + "not an OLT or not known to sadis", dev);
1618 return;
1619 }
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001620 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001621
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001622 log.debug("OLT got {} event for {}", event.type(), event.subject());
Jonathan Hart4c538002018-08-23 10:11:54 -07001623
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001624 switch (event.type()) {
1625 //TODO: Port handling and bookkeeping should be improved once
1626 // olt firmware handles correct behaviour.
1627 case PORT_ADDED:
Gamze Abaka838d8142019-02-21 07:06:55 +00001628 if (isUniPort(dev, port)) {
1629 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, port));
Jonathan Hart4c538002018-08-23 10:11:54 -07001630
Gamze Abaka838d8142019-02-21 07:06:55 +00001631 if (port.isEnabled()) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001632 processEapolFilteringObjectives(devId, port.number(), defaultBpId,
Gamze Abakada282b42019-03-11 13:16:48 +00001633 null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001634 }
1635 } else {
1636 checkAndCreateDeviceFlows(dev);
1637 }
1638 break;
1639 case PORT_REMOVED:
Gamze Abaka838d8142019-02-21 07:06:55 +00001640 if (isUniPort(dev, port)) {
Gamze Abaka853bf252019-03-25 10:27:06 +00001641 removeSubscriber(new ConnectPoint(devId, port.number()));
Andy Bavier160e8682019-05-07 18:32:22 -07001642 processEapolFilteringObjectives(devId, port.number(), defaultBpId,
1643 null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), false);
1644
Gamze Abaka838d8142019-02-21 07:06:55 +00001645 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, port));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001646 }
1647
1648 break;
1649 case PORT_UPDATED:
Gamze Abaka838d8142019-02-21 07:06:55 +00001650 if (!isUniPort(dev, port)) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001651 break;
1652 }
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001653
Gamze Abakada282b42019-03-11 13:16:48 +00001654 SubscriberAndDeviceInformation sub = programmedSubs
1655 .get(new ConnectPoint(devId, port.number()));
1656 VlanId vlanId = sub == null ? VlanId.vlanId(EAPOL_DEFAULT_VLAN) : sub.cTag();
1657
1658 String bpId = getCurrentBandwidthProfile(new ConnectPoint(devId, port.number()));
1659
Gamze Abaka838d8142019-02-21 07:06:55 +00001660 if (port.isEnabled()) {
Gamze Abakada282b42019-03-11 13:16:48 +00001661 processEapolFilteringObjectives(devId, port.number(), bpId,
1662 null, vlanId, true);
Gamze Abaka33feef52019-02-27 08:16:47 +00001663
Gamze Abaka838d8142019-02-21 07:06:55 +00001664 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, port));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001665 } else {
Gamze Abakada282b42019-03-11 13:16:48 +00001666 processEapolFilteringObjectives(devId, port.number(), bpId,
1667 null, vlanId, false);
Gamze Abaka838d8142019-02-21 07:06:55 +00001668 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, port));
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001669 }
alshabibbb83aa22016-02-10 15:08:23 -08001670 break;
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001671 case DEVICE_ADDED:
alshabib7c190012016-02-09 18:22:33 -08001672 post(new AccessDeviceEvent(
1673 AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
1674 null, null));
Saurav Dasa9d5f442019-03-06 19:32:48 -08001675 programmedDevices.add(devId);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001676 // Send UNI_ADDED events for all existing ports
1677 deviceService.getPorts(devId).stream()
1678 .filter(p -> isUniPort(dev, p))
1679 .filter(Port::isEnabled)
1680 .forEach(p -> post(new AccessDeviceEvent(
1681 AccessDeviceEvent.Type.UNI_ADDED, devId, p)));
1682
Jonathan Hart403372d2018-08-22 11:44:13 -07001683 checkAndCreateDeviceFlows(dev);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001684 break;
1685 case DEVICE_REMOVED:
1686 deviceService.getPorts(devId).stream()
1687 .filter(p -> isUniPort(dev, p))
1688 .forEach(p -> post(new AccessDeviceEvent(
1689 AccessDeviceEvent.Type.UNI_REMOVED, devId, p)));
Saurav Dasa9d5f442019-03-06 19:32:48 -08001690 programmedDevices.remove(devId);
Gamze Abakada282b42019-03-11 13:16:48 +00001691 removeAllSubscribers(devId);
alshabib7c190012016-02-09 18:22:33 -08001692 post(new AccessDeviceEvent(
1693 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
1694 null, null));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001695 break;
1696 case DEVICE_AVAILABILITY_CHANGED:
1697 if (deviceService.isAvailable(devId)) {
1698 post(new AccessDeviceEvent(
1699 AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
1700 null, null));
Gamze Abakada282b42019-03-11 13:16:48 +00001701 programmedDevices.add(devId);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001702 checkAndCreateDeviceFlows(dev);
1703 } else {
Gamze Abakada282b42019-03-11 13:16:48 +00001704 programmedDevices.remove(devId);
1705 removeAllSubscribers(devId);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001706 post(new AccessDeviceEvent(
1707 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
1708 null, null));
1709 }
1710 break;
1711 case DEVICE_UPDATED:
1712 case DEVICE_SUSPENDED:
1713 case PORT_STATS_UPDATED:
1714 default:
1715 return;
1716 }
1717 });
alshabibf0e7e702015-05-30 18:22:36 -07001718 }
Gamze Abaka838d8142019-02-21 07:06:55 +00001719
1720 private String getCurrentBandwidthProfile(ConnectPoint connectPoint) {
1721 SubscriberAndDeviceInformation sub = programmedSubs.get(connectPoint);
1722 if (sub != null) {
1723 return sub.upstreamBandwidthProfile();
1724 }
1725 return defaultBpId;
1726 }
Gamze Abakada282b42019-03-11 13:16:48 +00001727
1728 private void removeAllSubscribers(DeviceId deviceId) {
1729 List<ConnectPoint> connectPoints = programmedSubs.keySet().stream()
1730 .filter(ks -> Objects.equals(ks.deviceId(), deviceId))
1731 .collect(Collectors.toList());
1732
1733 connectPoints.forEach(cp -> programmedSubs.remove(cp));
1734 }
alshabibf0e7e702015-05-30 18:22:36 -07001735 }
Gamze Abaka641fc072018-09-04 09:16:27 +00001736
1737 private class InternalMeterListener implements MeterListener {
1738
1739 @Override
1740 public void event(MeterEvent meterEvent) {
1741 if (deleteMeters && MeterEvent.Type.METER_REFERENCE_COUNT_ZERO.equals(meterEvent.type())) {
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001742 log.info("Zero Count Meter Event is received. Meter is {}", meterEvent.subject());
Gamze Abaka641fc072018-09-04 09:16:27 +00001743 Meter meter = meterEvent.subject();
Gamze Abaka33feef52019-02-27 08:16:47 +00001744 if (meter != null && appId.equals(meter.appId()) &&
1745 !programmedMeters.contains(MeterKey.key(meter.deviceId(), meter.id()))) {
Gamze Abaka641fc072018-09-04 09:16:27 +00001746 deleteMeter(meter.deviceId(), meter.id());
1747 }
1748 } else if (MeterEvent.Type.METER_REMOVED.equals(meterEvent.type())) {
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001749 log.info("Meter removed event is received. Meter is {}", meterEvent.subject());
Gamze Abaka641fc072018-09-04 09:16:27 +00001750 removeMeterFromBpMap(meterEvent.subject());
1751 }
1752 }
1753
1754 private void deleteMeter(DeviceId deviceId, MeterId meterId) {
1755 Meter meter = meterService.getMeter(deviceId, meterId);
Gamze Abaka838d8142019-02-21 07:06:55 +00001756 if (meter != null) {
1757 MeterRequest meterRequest = DefaultMeterRequest.builder()
1758 .withBands(meter.bands())
1759 .withUnit(meter.unit())
1760 .forDevice(deviceId)
1761 .fromApp(appId)
1762 .burst()
1763 .remove();
Gamze Abaka641fc072018-09-04 09:16:27 +00001764
Gamze Abaka838d8142019-02-21 07:06:55 +00001765 meterService.withdraw(meterRequest, meterId);
1766 }
Gamze Abaka641fc072018-09-04 09:16:27 +00001767 }
1768
1769 private void removeMeterFromBpMap(Meter meter) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001770 bpInfoToMeter.values().forEach(meterKeys -> meterKeys.stream()
1771 .filter(meterKey -> (meterKey.deviceId().equals(meter.deviceId()))
1772 && meterKey.meterId().equals(meter.id())).findFirst().
1773 ifPresent(mk -> {
1774 meterKeys.remove(mk);
Gamze Abakada282b42019-03-11 13:16:48 +00001775 programmedMeters.remove(mk);
Gamze Abaka33feef52019-02-27 08:16:47 +00001776 log.info("Deleted from the internal map. MeterKey {}", mk);
1777 log.info("Programmed meters {}", programmedMeters);
1778 }));
Gamze Abaka641fc072018-09-04 09:16:27 +00001779 }
1780 }
1781}