blob: a611723d1730f6be6da790bf73447083937e8b0a [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;
Amit Ghoshe1d3f092018-10-09 19:44:33 +010026import java.util.Arrays;
Saurav Das82b8e6d2018-10-04 15:25:12 -070027import java.util.ArrayList;
28import java.util.Collection;
29import java.util.Dictionary;
30import java.util.List;
31import java.util.Map;
32import java.util.Optional;
33import java.util.Properties;
34import java.util.concurrent.CompletableFuture;
35import java.util.concurrent.ExecutorService;
36import java.util.concurrent.Executors;
37
alshabibf0e7e702015-05-30 18:22:36 -070038import org.apache.felix.scr.annotations.Activate;
39import org.apache.felix.scr.annotations.Component;
40import org.apache.felix.scr.annotations.Deactivate;
alshabibe0559672016-02-21 14:49:51 -080041import org.apache.felix.scr.annotations.Modified;
42import org.apache.felix.scr.annotations.Property;
alshabibf0e7e702015-05-30 18:22:36 -070043import org.apache.felix.scr.annotations.Reference;
44import org.apache.felix.scr.annotations.ReferenceCardinality;
Jonathan Harte533a422015-10-20 17:31:24 -070045import org.apache.felix.scr.annotations.Service;
alshabibdec2e252016-01-15 12:20:25 -080046import org.onlab.packet.EthType;
Amit Ghosh95e2f652017-08-23 12:49:46 +010047import org.onlab.packet.IPv4;
Matteo Scandolo63460d12018-11-02 16:19:04 -070048import org.onlab.packet.IPv6;
Amit Ghosh95e2f652017-08-23 12:49:46 +010049import org.onlab.packet.TpPort;
alshabibf0e7e702015-05-30 18:22:36 -070050import org.onlab.packet.VlanId;
Amit Ghosh95e2f652017-08-23 12:49:46 +010051import org.onlab.util.Tools;
alshabibe0559672016-02-21 14:49:51 -080052import org.onosproject.cfg.ComponentConfigService;
alshabibf0e7e702015-05-30 18:22:36 -070053import org.onosproject.core.ApplicationId;
54import org.onosproject.core.CoreService;
alshabib8e4fd2f2016-01-12 15:55:53 -080055import org.onosproject.event.AbstractListenerManager;
alshabib09753b52016-03-04 14:55:19 -080056import org.onosproject.mastership.MastershipService;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010057import org.onosproject.net.AnnotationKeys;
Jonathan Harte533a422015-10-20 17:31:24 -070058import org.onosproject.net.ConnectPoint;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010059import org.onosproject.net.Device;
alshabibf0e7e702015-05-30 18:22:36 -070060import org.onosproject.net.DeviceId;
alshabibdec2e252016-01-15 12:20:25 -080061import org.onosproject.net.Port;
alshabibf0e7e702015-05-30 18:22:36 -070062import org.onosproject.net.PortNumber;
63import org.onosproject.net.device.DeviceEvent;
64import org.onosproject.net.device.DeviceListener;
65import org.onosproject.net.device.DeviceService;
66import org.onosproject.net.flow.DefaultTrafficSelector;
67import org.onosproject.net.flow.DefaultTrafficTreatment;
68import org.onosproject.net.flow.TrafficSelector;
69import org.onosproject.net.flow.TrafficTreatment;
alshabibdec2e252016-01-15 12:20:25 -080070import org.onosproject.net.flow.criteria.Criteria;
71import org.onosproject.net.flowobjective.DefaultFilteringObjective;
alshabibf0e7e702015-05-30 18:22:36 -070072import org.onosproject.net.flowobjective.DefaultForwardingObjective;
alshabibdec2e252016-01-15 12:20:25 -080073import org.onosproject.net.flowobjective.FilteringObjective;
alshabibf0e7e702015-05-30 18:22:36 -070074import org.onosproject.net.flowobjective.FlowObjectiveService;
75import org.onosproject.net.flowobjective.ForwardingObjective;
alshabib3ea82642016-01-12 18:06:53 -080076import org.onosproject.net.flowobjective.Objective;
77import org.onosproject.net.flowobjective.ObjectiveContext;
78import org.onosproject.net.flowobjective.ObjectiveError;
Amit Ghoshe1d3f092018-10-09 19:44:33 +010079import org.onosproject.store.serializers.KryoNamespaces;
80import org.onosproject.store.service.ConsistentMultimap;
81import org.onosproject.store.service.Serializer;
82import org.onosproject.store.service.StorageService;
Gamze Abaka641fc072018-09-04 09:16:27 +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.MeterService;
88import org.onosproject.net.meter.MeterListener;
89import org.onosproject.net.meter.MeterRequest;
90import org.onosproject.net.meter.MeterId;
91import org.onosproject.net.meter.MeterEvent;
alshabib36a4d732016-06-01 16:03:59 -070092import org.opencord.olt.AccessDeviceEvent;
93import org.opencord.olt.AccessDeviceListener;
94import org.opencord.olt.AccessDeviceService;
Amit Ghosh31939522018-08-16 13:28:21 +010095import org.opencord.olt.AccessSubscriberId;
Gamze Abaka641fc072018-09-04 09:16:27 +000096import org.opencord.sadis.BandwidthProfileInformation;
97import org.opencord.sadis.BaseInformationService;
98import org.opencord.sadis.SadisService;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010099import org.opencord.sadis.SubscriberAndDeviceInformation;
alshabibe0559672016-02-21 14:49:51 -0800100import org.osgi.service.component.ComponentContext;
alshabibf0e7e702015-05-30 18:22:36 -0700101import org.slf4j.Logger;
102
Gamze Abaka641fc072018-09-04 09:16:27 +0000103import java.util.HashMap;
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100104
Saurav Das82b8e6d2018-10-04 15:25:12 -0700105import com.google.common.collect.ImmutableMap;
106import com.google.common.collect.Maps;
alshabibf0e7e702015-05-30 18:22:36 -0700107
108/**
Jonathan Harte533a422015-10-20 17:31:24 -0700109 * Provisions rules on access devices.
alshabibf0e7e702015-05-30 18:22:36 -0700110 */
Jonathan Harte533a422015-10-20 17:31:24 -0700111@Service
alshabibf0e7e702015-05-30 18:22:36 -0700112@Component(immediate = true)
alshabib8e4fd2f2016-01-12 15:55:53 -0800113public class Olt
114 extends AbstractListenerManager<AccessDeviceEvent, AccessDeviceListener>
115 implements AccessDeviceService {
Charles Chan54f110f2017-01-20 11:22:42 -0800116 private static final String APP_NAME = "org.opencord.olt";
alshabibe0559672016-02-21 14:49:51 -0800117
118 private static final short DEFAULT_VLAN = 0;
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100119 private static final String ADDITIONAL_VLANS = "additional-vlans";
alshabibe0559672016-02-21 14:49:51 -0800120
alshabibf0e7e702015-05-30 18:22:36 -0700121 private final Logger log = getLogger(getClass());
122
123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
124 protected FlowObjectiveService flowObjectiveService;
125
126 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabib09753b52016-03-04 14:55:19 -0800127 protected MastershipService mastershipService;
128
129 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibf0e7e702015-05-30 18:22:36 -0700130 protected DeviceService deviceService;
131
132 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
133 protected CoreService coreService;
134
Jonathan Harte533a422015-10-20 17:31:24 -0700135 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibe0559672016-02-21 14:49:51 -0800136 protected ComponentConfigService componentConfigService;
137
alshabib4ceaed32016-03-03 18:00:58 -0800138 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Gamze Abaka641fc072018-09-04 09:16:27 +0000139 protected SadisService sadisService;
140
141 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
142 protected MeterService meterService;
alshabibe0559672016-02-21 14:49:51 -0800143
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100144 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
145 protected StorageService storageService;
146
alshabibe0559672016-02-21 14:49:51 -0800147 @Property(name = "defaultVlan", intValue = DEFAULT_VLAN,
148 label = "Default VLAN RG<->ONU traffic")
149 private int defaultVlan = DEFAULT_VLAN;
150
Matt Jeanneret3f579262018-06-14 17:16:23 -0400151 @Property(name = "enableDhcpOnProvisioning", boolValue = true,
152 label = "Create the DHCP Flow rules when a subscriber is provisioned")
153 protected boolean enableDhcpOnProvisioning = false;
154
Matteo Scandolo63460d12018-11-02 16:19:04 -0700155 @Property(name = "enableDhcpV4", boolValue = true,
156 label = "Enable flows for DHCP v4")
157 protected boolean enableDhcpV4 = true;
158
159 @Property(name = "enableDhcpV6", boolValue = true,
160 label = "Enable flows for DHCP v6")
161 protected boolean enableDhcpV6 = false;
162
Matt Jeanneret3f579262018-06-14 17:16:23 -0400163 @Property(name = "enableIgmpOnProvisioning", boolValue = false,
164 label = "Create IGMP Flow rules when a subscriber is provisioned")
165 protected boolean enableIgmpOnProvisioning = false;
Amit Ghosh95e2f652017-08-23 12:49:46 +0100166
Gamze Abaka641fc072018-09-04 09:16:27 +0000167 // needed because no implementation for meter statistics in Voltha yet
168 @Property(name = "deleteMeters", boolValue = false,
169 label = "Deleting Meters based on flow count statistics")
170 protected boolean deleteMeters = false;
171
alshabibf0e7e702015-05-30 18:22:36 -0700172 private final DeviceListener deviceListener = new InternalDeviceListener();
Gamze Abaka641fc072018-09-04 09:16:27 +0000173 private final MeterListener meterListener = new InternalMeterListener();
alshabibf0e7e702015-05-30 18:22:36 -0700174
175 private ApplicationId appId;
Gamze Abaka641fc072018-09-04 09:16:27 +0000176 protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
177 private BaseInformationService<BandwidthProfileInformation> bpService;
alshabibf0e7e702015-05-30 18:22:36 -0700178
Gamze Abaka641fc072018-09-04 09:16:27 +0000179 private Map<String, MeterId> bpInfoToMeter = new HashMap<>();
180
181 private ExecutorService oltInstallers = Executors.newFixedThreadPool(4,
182 groupedThreads("onos/olt-service",
183 "olt-installer-%d"));
alshabibf0e7e702015-05-30 18:22:36 -0700184
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100185 private ConsistentMultimap<ConnectPoint, Map.Entry<VlanId, VlanId>> additionalVlans;
186
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700187 protected ExecutorService eventExecutor;
188
Saurav Das82b8e6d2018-10-04 15:25:12 -0700189 private Map<ConnectPoint, SubscriberAndDeviceInformation> programmedSubs;
190
alshabibf0e7e702015-05-30 18:22:36 -0700191 @Activate
alshabibe0559672016-02-21 14:49:51 -0800192 public void activate(ComponentContext context) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700193 eventExecutor = newSingleThreadScheduledExecutor(groupedThreads("onos/olt", "events-%d", log));
alshabibe0559672016-02-21 14:49:51 -0800194 modified(context);
Charles Chan54f110f2017-01-20 11:22:42 -0800195 appId = coreService.registerApplication(APP_NAME);
alshabibe0559672016-02-21 14:49:51 -0800196 componentConfigService.registerProperties(getClass());
Saurav Das82b8e6d2018-10-04 15:25:12 -0700197 programmedSubs = Maps.newConcurrentMap();
alshabibc4dfe852015-06-05 13:35:13 -0700198
alshabib8e4fd2f2016-01-12 15:55:53 -0800199 eventDispatcher.addSink(AccessDeviceEvent.class, listenerRegistry);
200
Gamze Abaka641fc072018-09-04 09:16:27 +0000201 subsService = sadisService.getSubscriberInfoService();
202 bpService = sadisService.getBandwidthProfileService();
203
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100204 // look for all provisioned devices in Sadis and create EAPOL flows for the
205 // UNI ports
206 Iterable<Device> devices = deviceService.getDevices();
207 for (Device d : devices) {
Jonathan Hart403372d2018-08-22 11:44:13 -0700208 checkAndCreateDeviceFlows(d);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100209 }
alshabib4ceaed32016-03-03 18:00:58 -0800210
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100211 additionalVlans = storageService.<ConnectPoint, Map.Entry<VlanId, VlanId>>consistentMultimapBuilder()
212 .withName(ADDITIONAL_VLANS)
213 .withSerializer(Serializer.using(Arrays.asList(KryoNamespaces.API),
214 AbstractMap.SimpleEntry.class))
215 .build();
216
alshabibba357492016-01-27 13:49:46 -0800217 deviceService.addListener(deviceListener);
Gamze Abaka641fc072018-09-04 09:16:27 +0000218 meterService.addListener(meterListener);
alshabibba357492016-01-27 13:49:46 -0800219
alshabibf0e7e702015-05-30 18:22:36 -0700220 log.info("Started with Application ID {}", appId.id());
221 }
222
223 @Deactivate
224 public void deactivate() {
alshabibe0559672016-02-21 14:49:51 -0800225 componentConfigService.unregisterProperties(getClass(), false);
alshabib62e9ce72016-02-11 17:31:36 -0800226 deviceService.removeListener(deviceListener);
Gamze Abaka641fc072018-09-04 09:16:27 +0000227 meterService.removeListener(meterListener);
Jonathan Hart5f1c8142018-07-24 17:31:59 -0700228 eventDispatcher.removeSink(AccessDeviceEvent.class);
alshabibf0e7e702015-05-30 18:22:36 -0700229 log.info("Stopped");
230 }
231
alshabibe0559672016-02-21 14:49:51 -0800232 @Modified
233 public void modified(ComponentContext context) {
234 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
235
236 try {
237 String s = get(properties, "defaultVlan");
238 defaultVlan = isNullOrEmpty(s) ? DEFAULT_VLAN : Integer.parseInt(s.trim());
Amit Ghosh95e2f652017-08-23 12:49:46 +0100239
Matt Jeanneret3f579262018-06-14 17:16:23 -0400240 Boolean o = Tools.isPropertyEnabled(properties, "enableDhcpOnProvisioning");
Amit Ghosh95e2f652017-08-23 12:49:46 +0100241 if (o != null) {
Matt Jeanneret3f579262018-06-14 17:16:23 -0400242 enableDhcpOnProvisioning = o;
Amit Ghosh95e2f652017-08-23 12:49:46 +0100243 }
Matt Jeanneret3f579262018-06-14 17:16:23 -0400244
Matteo Scandolo63460d12018-11-02 16:19:04 -0700245 Boolean v4 = Tools.isPropertyEnabled(properties, "enableDhcpV4");
246 if (v4 != null) {
247 enableDhcpV4 = v4;
248 }
249
250 Boolean v6 = Tools.isPropertyEnabled(properties, "enableDhcpV6");
251 if (v6 != null) {
252 enableDhcpV6 = v6;
253 }
254
Matt Jeanneret3f579262018-06-14 17:16:23 -0400255 Boolean p = Tools.isPropertyEnabled(properties, "enableIgmpOnProvisioning");
256 if (p != null) {
257 enableIgmpOnProvisioning = p;
258 }
259
Matteo Scandolo63460d12018-11-02 16:19:04 -0700260 log.info("DHCP Settings [enableDhcpOnProvisioning: {}, enableDhcpV4: {}, enableDhcpV6: {}]",
261 enableDhcpOnProvisioning, enableDhcpV4, enableDhcpV6);
262
Gamze Abaka641fc072018-09-04 09:16:27 +0000263 Boolean d = Tools.isPropertyEnabled(properties, "deleteMeters");
264 if (d != null) {
265 deleteMeters = d;
266 }
267
alshabibe0559672016-02-21 14:49:51 -0800268 } catch (Exception e) {
269 defaultVlan = DEFAULT_VLAN;
270 }
271 }
272
alshabib32232c82016-02-25 17:57:24 -0500273 @Override
Amit Ghosh31939522018-08-16 13:28:21 +0100274 public boolean provisionSubscriber(ConnectPoint port) {
Jonathan Hart94b90492018-04-24 14:02:25 -0700275 checkNotNull(deviceService.getPort(port.deviceId(), port.port()),
276 "Invalid connect point");
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100277 // Find the subscriber on this connect point
278 SubscriberAndDeviceInformation sub = getSubscriber(port);
279 if (sub == null) {
280 log.warn("No subscriber found for {}", port);
Amit Ghosh31939522018-08-16 13:28:21 +0100281 return false;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100282 }
Jonathan Harte533a422015-10-20 17:31:24 -0700283
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100284 // Get the uplink port
285 Port uplinkPort = getUplinkPort(deviceService.getDevice(port.deviceId()));
286 if (uplinkPort == null) {
287 log.warn("No uplink port found for OLT device {}", port.deviceId());
Amit Ghosh31939522018-08-16 13:28:21 +0100288 return false;
Jonathan Harte533a422015-10-20 17:31:24 -0700289 }
290
Matt Jeanneret3f579262018-06-14 17:16:23 -0400291 if (enableDhcpOnProvisioning) {
Saurav Dasacc5eeb2018-10-11 10:58:01 -0700292 processDhcpFilteringObjectives(port.deviceId(), port.port(), true,
Gamze Abaka641fc072018-09-04 09:16:27 +0000293 true);
Amit Ghosh95e2f652017-08-23 12:49:46 +0100294 }
Saurav Das82b8e6d2018-10-04 15:25:12 -0700295 log.info("Programming vlans for subscriber: {}", sub);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100296 Optional<VlanId> defaultVlan = Optional.empty();
Gamze Abaka641fc072018-09-04 09:16:27 +0000297 provisionVlans(port, uplinkPort.number(), defaultVlan, sub);
Amit Ghosh95e2f652017-08-23 12:49:46 +0100298
Matt Jeanneret3f579262018-06-14 17:16:23 -0400299 if (enableIgmpOnProvisioning) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100300 processIgmpFilteringObjectives(port.deviceId(), port.port(), true);
Amit Ghosh95e2f652017-08-23 12:49:46 +0100301 }
Saurav Das82b8e6d2018-10-04 15:25:12 -0700302 // cache subscriber info
303 programmedSubs.put(port, sub);
Amit Ghosh31939522018-08-16 13:28:21 +0100304 return true;
alshabibb7a9e172016-01-13 11:23:53 -0800305 }
306
307 @Override
Amit Ghosh31939522018-08-16 13:28:21 +0100308 public boolean removeSubscriber(ConnectPoint port) {
Matteo Scandolo962a6ad2018-12-11 15:39:42 -0800309 // Get the subscriber connected to this port from the local cache
310 // as if we don't know about the subscriber there's no need to remove it
311 SubscriberAndDeviceInformation subscriber = programmedSubs.get(port);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100312 if (subscriber == null) {
Matteo Scandolo962a6ad2018-12-11 15:39:42 -0800313 log.warn("Subscriber on port {} was not previously programmed, no need to remove it", port);
314 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800315 }
316
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100317 // Get the uplink port
318 Port uplinkPort = getUplinkPort(deviceService.getDevice(port.deviceId()));
319 if (uplinkPort == null) {
320 log.warn("No uplink port found for OLT device {}", port.deviceId());
Amit Ghosh31939522018-08-16 13:28:21 +0100321 return false;
alshabib4ceaed32016-03-03 18:00:58 -0800322 }
323
Matt Jeanneret3f579262018-06-14 17:16:23 -0400324 if (enableDhcpOnProvisioning) {
Saurav Dasacc5eeb2018-10-11 10:58:01 -0700325 processDhcpFilteringObjectives(port.deviceId(), port.port(), false,
Gamze Abaka641fc072018-09-04 09:16:27 +0000326 true);
Amit Ghosh95e2f652017-08-23 12:49:46 +0100327 }
328
Saurav Das82b8e6d2018-10-04 15:25:12 -0700329 log.info("Removing programmed vlans for subscriber: {}", subscriber);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100330 Optional<VlanId> defaultVlan = Optional.empty();
Gamze Abaka641fc072018-09-04 09:16:27 +0000331 unprovisionSubscriber(port.deviceId(), uplinkPort.number(), port.port(), subscriber, defaultVlan);
alshabibbf23a1f2016-01-14 17:27:11 -0800332
Matt Jeanneret3f579262018-06-14 17:16:23 -0400333 if (enableIgmpOnProvisioning) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100334 processIgmpFilteringObjectives(port.deviceId(), port.port(), false);
Amit Ghosh95e2f652017-08-23 12:49:46 +0100335 }
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100336
337 // Remove if there are any flows for the additional Vlans
338 Collection<? extends Map.Entry<VlanId, VlanId>> vlansList = additionalVlans.get(port).value();
339
340 // Remove the flows for the additional vlans for this subscriber
341 for (Map.Entry<VlanId, VlanId> vlans : vlansList) {
342 unprovisionTransparentFlows(port.deviceId(), uplinkPort.number(), port.port(),
343 vlans.getValue(), vlans.getKey());
344
345 // Remove it from the map also
346 additionalVlans.remove(port, vlans);
347 }
348
Saurav Das82b8e6d2018-10-04 15:25:12 -0700349 programmedSubs.remove(port);
Amit Ghosh31939522018-08-16 13:28:21 +0100350 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800351 }
352
Amit Ghosh31939522018-08-16 13:28:21 +0100353 @Override
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100354 public boolean provisionSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag, Optional<VlanId> cTag) {
Amit Ghosh31939522018-08-16 13:28:21 +0100355 // Check if we can find the connect point to which this subscriber is connected
356 ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
357 if (subsPort == null) {
358 log.warn("ConnectPoint for {} not found", subscriberId);
359 return false;
360 }
361
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100362 if (!sTag.isPresent() && !cTag.isPresent()) {
363 return provisionSubscriber(subsPort);
364 } else if (sTag.isPresent() && cTag.isPresent()) {
365 Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
366 if (uplinkPort == null) {
367 log.warn("No uplink port found for OLT device {}", subsPort.deviceId());
368 return false;
369 }
370
371 provisionTransparentFlows(subsPort.deviceId(), uplinkPort.number(), subsPort.port(),
372 cTag.get(), sTag.get());
373 return true;
374 } else {
375 log.warn("Provisioning failed for subscriber: {}", subscriberId);
376 return false;
377 }
Amit Ghosh31939522018-08-16 13:28:21 +0100378 }
Amit Ghosh95e2f652017-08-23 12:49:46 +0100379
alshabibe0559672016-02-21 14:49:51 -0800380 @Override
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100381 public boolean removeSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag, Optional<VlanId> cTag) {
Amit Ghosh31939522018-08-16 13:28:21 +0100382 // Check if we can find the connect point to which this subscriber is connected
383 ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
384 if (subsPort == null) {
385 log.warn("ConnectPoint for {} not found", subscriberId);
386 return false;
387 }
388
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100389 if (!sTag.isPresent() && !cTag.isPresent()) {
390 return removeSubscriber(subsPort);
391 } else if (sTag.isPresent() && cTag.isPresent()) {
392 // Get the uplink port
393 Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
394 if (uplinkPort == null) {
395 log.warn("No uplink port found for OLT device {}", subsPort.deviceId());
396 return false;
397 }
398
399 unprovisionTransparentFlows(subsPort.deviceId(), uplinkPort.number(), subsPort.port(),
400 cTag.get(), sTag.get());
401 return true;
402 } else {
403 log.warn("Removing subscriber failed for: {}", subscriberId);
404 return false;
405 }
Amit Ghosh31939522018-08-16 13:28:21 +0100406 }
407
408 @Override
409 public Collection<Map.Entry<ConnectPoint, Map.Entry<VlanId, VlanId>>> getSubscribers() {
410 ArrayList<Map.Entry<ConnectPoint, Map.Entry<VlanId, VlanId>>> subs = new ArrayList<>();
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100411
Saurav Das82b8e6d2018-10-04 15:25:12 -0700412 // Get the subscribers for all the devices configured in sadis
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100413 // If the port is UNI, is enabled and exists in Sadis then copy it
414 for (Device d : deviceService.getDevices()) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700415 if (getOltInfo(d) == null) {
416 continue; // not an olt, or not configured in sadis
417 }
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100418 for (Port p: deviceService.getPorts(d.id())) {
419 if (isUniPort(d, p) && p.isEnabled()) {
420 ConnectPoint cp = new ConnectPoint(d.id(), p.number());
421
422 SubscriberAndDeviceInformation sub = getSubscriber(cp);
423 if (sub != null) {
Amit Ghosh31939522018-08-16 13:28:21 +0100424 Map.Entry<VlanId, VlanId> vlans = new AbstractMap.SimpleEntry(sub.sTag(), sub.cTag());
425 subs.add(new AbstractMap.SimpleEntry(cp, vlans));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100426 }
427 }
428 }
429 }
430
431 return subs;
Jonathan Hartfd6c1b32016-03-08 14:09:09 -0800432 }
433
434 @Override
Saurav Das82b8e6d2018-10-04 15:25:12 -0700435 public ImmutableMap<ConnectPoint, SubscriberAndDeviceInformation> getProgSubs() {
436 return ImmutableMap.copyOf(programmedSubs);
437 }
438
439 @Override
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100440 public List<DeviceId> fetchOlts() {
441 // look through all the devices and find the ones that are OLTs as per Sadis
442 List<DeviceId> olts = new ArrayList<>();
443 Iterable<Device> devices = deviceService.getDevices();
444 for (Device d : devices) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700445 if (getOltInfo(d) != null) {
446 // So this is indeed an OLT device
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100447 olts.add(d.id());
448 }
449 }
450 return olts;
alshabibe0559672016-02-21 14:49:51 -0800451 }
452
Amit Ghosh31939522018-08-16 13:28:21 +0100453 /**
454 * Finds the connect point to which a subscriber is connected.
455 *
456 * @param id The id of the subscriber, this is the same ID as in Sadis
457 * @return Subscribers ConnectPoint if found else null
458 */
459 private ConnectPoint findSubscriberConnectPoint(String id) {
460
461 Iterable<Device> devices = deviceService.getDevices();
462 for (Device d : devices) {
463 for (Port p : deviceService.getPorts(d.id())) {
464 log.trace("Comparing {} with {}", p.annotations().value(AnnotationKeys.PORT_NAME), id);
465 if (p.annotations().value(AnnotationKeys.PORT_NAME).equals(id)) {
466 log.debug("Found on device {} port {}", d.id(), p.number());
467 return new ConnectPoint(d.id(), p.number());
468 }
469 }
470 }
471 return null;
472 }
473
Gamze Abaka641fc072018-09-04 09:16:27 +0000474 private BandwidthProfileInformation getBandwidthProfileInformation(String bandwidthProfile) {
475 if (bandwidthProfile == null) {
476 return null;
477 }
478 return bpService.get(bandwidthProfile);
479 }
480
alshabibbf23a1f2016-01-14 17:27:11 -0800481 private void unprovisionSubscriber(DeviceId deviceId, PortNumber uplink,
Gamze Abaka641fc072018-09-04 09:16:27 +0000482 PortNumber subscriberPort, SubscriberAndDeviceInformation subscriber,
483 Optional<VlanId> defaultVlan) {
alshabibbf23a1f2016-01-14 17:27:11 -0800484
485 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
486 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
487
Gamze Abaka641fc072018-09-04 09:16:27 +0000488 VlanId deviceVlan = subscriber.sTag();
489 VlanId subscriberVlan = subscriber.cTag();
490
491 MeterId upstreamMeterId = bpInfoToMeter.get(subscriber.upstreamBandwidthProfile());
492 MeterId downstreamMeterId = bpInfoToMeter.get(subscriber.downstreamBandwidthProfile());
493
alshabib4ceaed32016-03-03 18:00:58 -0800494 ForwardingObjective.Builder upFwd = upBuilder(uplink, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000495 subscriberVlan, deviceVlan,
496 defaultVlan, upstreamMeterId, subscriber.technologyProfileId());
alshabib4ceaed32016-03-03 18:00:58 -0800497 ForwardingObjective.Builder downFwd = downBuilder(uplink, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000498 subscriberVlan, deviceVlan,
499 defaultVlan, downstreamMeterId, subscriber.technologyProfileId());
alshabibbf23a1f2016-01-14 17:27:11 -0800500
alshabib4ceaed32016-03-03 18:00:58 -0800501 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
502 @Override
503 public void onSuccess(Objective objective) {
504 upFuture.complete(null);
505 }
alshabibbf23a1f2016-01-14 17:27:11 -0800506
alshabib4ceaed32016-03-03 18:00:58 -0800507 @Override
508 public void onError(Objective objective, ObjectiveError error) {
509 upFuture.complete(error);
510 }
511 }));
512
513 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
514 @Override
515 public void onSuccess(Objective objective) {
516 downFuture.complete(null);
517 }
518
519 @Override
520 public void onError(Objective objective, ObjectiveError error) {
521 downFuture.complete(error);
522 }
523 }));
alshabibbf23a1f2016-01-14 17:27:11 -0800524
525 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
526 if (upStatus == null && downStatus == null) {
527 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_UNREGISTERED,
Gamze Abaka641fc072018-09-04 09:16:27 +0000528 deviceId,
529 deviceVlan,
530 subscriberVlan));
alshabibbf23a1f2016-01-14 17:27:11 -0800531 } else if (downStatus != null) {
532 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000533 "on port {} failed downstream uninstallation: {}",
534 subscriberVlan, deviceId, subscriberPort, downStatus);
alshabibbf23a1f2016-01-14 17:27:11 -0800535 } else if (upStatus != null) {
536 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000537 "on port {} failed upstream uninstallation: {}",
538 subscriberVlan, deviceId, subscriberPort, upStatus);
alshabibbf23a1f2016-01-14 17:27:11 -0800539 }
540 }, oltInstallers);
alshabibb7a9e172016-01-13 11:23:53 -0800541
Jonathan Harte533a422015-10-20 17:31:24 -0700542 }
543
Gamze Abaka641fc072018-09-04 09:16:27 +0000544 private void provisionVlans(ConnectPoint port, PortNumber uplinkPort, Optional<VlanId> defaultVlan,
545 SubscriberAndDeviceInformation sub) {
546
547 log.info("Provisioning vlans...");
548
549 DeviceId deviceId = port.deviceId();
550 PortNumber subscriberPort = port.port();
551 VlanId deviceVlan = sub.sTag();
552 VlanId subscriberVlan = sub.cTag();
553 int techProfId = sub.technologyProfileId();
554
555 BandwidthProfileInformation upstreamBpInfo = getBandwidthProfileInformation(sub.upstreamBandwidthProfile());
556 BandwidthProfileInformation downstreamBpInfo = getBandwidthProfileInformation(sub.downstreamBandwidthProfile());
557
558 MeterId usptreamMeterId = createMeter(deviceId, upstreamBpInfo);
559 MeterId downstreamMeterId = createMeter(deviceId, downstreamBpInfo);
Jonathan Harte533a422015-10-20 17:31:24 -0700560
alshabib3ea82642016-01-12 18:06:53 -0800561 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
562 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
563
alshabib4ceaed32016-03-03 18:00:58 -0800564 ForwardingObjective.Builder upFwd = upBuilder(uplinkPort, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000565 subscriberVlan, deviceVlan,
566 defaultVlan, usptreamMeterId, techProfId);
Jonathan Harte533a422015-10-20 17:31:24 -0700567
alshabib4ceaed32016-03-03 18:00:58 -0800568 ForwardingObjective.Builder downFwd = downBuilder(uplinkPort, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000569 subscriberVlan, deviceVlan,
570 defaultVlan, downstreamMeterId, techProfId);
alshabib3ea82642016-01-12 18:06:53 -0800571
alshabibbf23a1f2016-01-14 17:27:11 -0800572 flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
573 @Override
574 public void onSuccess(Objective objective) {
575 upFuture.complete(null);
576 }
577
578 @Override
579 public void onError(Objective objective, ObjectiveError error) {
580 upFuture.complete(error);
581 }
582 }));
583
alshabibbf23a1f2016-01-14 17:27:11 -0800584 flowObjectiveService.forward(deviceId, downFwd.add(new ObjectiveContext() {
585 @Override
586 public void onSuccess(Objective objective) {
587 downFuture.complete(null);
588 }
589
590 @Override
591 public void onError(Objective objective, ObjectiveError error) {
592 downFuture.complete(error);
593 }
594 }));
alshabib3ea82642016-01-12 18:06:53 -0800595
596 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
597 if (upStatus == null && downStatus == null) {
598 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_REGISTERED,
Gamze Abaka641fc072018-09-04 09:16:27 +0000599 deviceId,
600 deviceVlan,
601 subscriberVlan));
alshabib50d9fc52016-02-12 15:47:20 -0800602
alshabib3ea82642016-01-12 18:06:53 -0800603 } else if (downStatus != null) {
604 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000605 "on port {} failed downstream installation: {}",
606 subscriberVlan, deviceId, subscriberPort, downStatus);
alshabib3ea82642016-01-12 18:06:53 -0800607 } else if (upStatus != null) {
608 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000609 "on port {} failed upstream installation: {}",
610 subscriberVlan, deviceId, subscriberPort, upStatus);
alshabib3ea82642016-01-12 18:06:53 -0800611 }
612 }, oltInstallers);
613
Jonathan Harte533a422015-10-20 17:31:24 -0700614 }
615
Gamze Abaka641fc072018-09-04 09:16:27 +0000616 private MeterId createMeter(DeviceId deviceId, BandwidthProfileInformation bpInfo) {
617
618 if (bpInfo == null) {
619 log.warn("Bandwidth profile information is not found");
620 return null;
621 }
622
623 MeterId meterId = bpInfoToMeter.get(bpInfo.id());
624 if (meterId != null) {
625 log.info("Meter is already added. MeterId {}", meterId);
626 return meterId;
627 }
628
629 List<Band> meterBands = createMeterBands(bpInfo);
630
631 MeterRequest meterRequest = DefaultMeterRequest.builder()
632 .withBands(meterBands)
633 .withUnit(Meter.Unit.KB_PER_SEC)
634 .forDevice(deviceId)
635 .fromApp(appId)
636 .burst()
637 .add();
638
639 Meter meter = meterService.submit(meterRequest);
640 bpInfoToMeter.put(bpInfo.id(), meter.id());
641 log.info("Meter is created. Meter Id {}", meter.id());
642 return meter.id();
643 }
644
645 private List<Band> createMeterBands(BandwidthProfileInformation bpInfo) {
646 List<Band> meterBands = new ArrayList<>();
647
648 meterBands.add(createMeterBand(bpInfo.committedInformationRate(), bpInfo.committedBurstSize()));
649 meterBands.add(createMeterBand(bpInfo.exceededInformationRate(), bpInfo.exceededBurstSize()));
650
651 if (bpInfo.assuredInformationRate() != 0) {
652 meterBands.add(createMeterBand(bpInfo.assuredInformationRate(), 0L));
653 }
654 return meterBands;
655 }
656
657 private Band createMeterBand(long rate, Long burst) {
658 return DefaultBand.builder()
659 .withRate(rate) //already Kbps
660 .burstSize(burst) // already Kbits
661 .ofType(Band.Type.DROP) // no matter
662 .build();
663 }
664
alshabib4ceaed32016-03-03 18:00:58 -0800665 private ForwardingObjective.Builder downBuilder(PortNumber uplinkPort,
666 PortNumber subscriberPort,
667 VlanId subscriberVlan,
668 VlanId deviceVlan,
Gamze Abaka641fc072018-09-04 09:16:27 +0000669 Optional<VlanId> defaultVlan,
670 MeterId meterId,
671 int techProfId) {
alshabib4ceaed32016-03-03 18:00:58 -0800672 TrafficSelector downstream = DefaultTrafficSelector.builder()
673 .matchVlanId(deviceVlan)
674 .matchInPort(uplinkPort)
675 .matchInnerVlanId(subscriberVlan)
676 .build();
677
Gamze Abaka641fc072018-09-04 09:16:27 +0000678 TrafficTreatment.Builder downstreamTreatmentBuilder = DefaultTrafficTreatment.builder()
alshabib4ceaed32016-03-03 18:00:58 -0800679 .popVlan()
680 .setVlanId(defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan)))
Gamze Abaka641fc072018-09-04 09:16:27 +0000681 .setOutput(subscriberPort);
682
683 if (meterId != null) {
684 downstreamTreatmentBuilder.meter(meterId);
685 }
686
687 if (techProfId != -1) {
688 downstreamTreatmentBuilder.transition(techProfId);
689 }
alshabib4ceaed32016-03-03 18:00:58 -0800690
691 return DefaultForwardingObjective.builder()
692 .withFlag(ForwardingObjective.Flag.VERSATILE)
693 .withPriority(1000)
694 .makePermanent()
695 .withSelector(downstream)
696 .fromApp(appId)
Gamze Abaka641fc072018-09-04 09:16:27 +0000697 .withTreatment(downstreamTreatmentBuilder.build());
alshabib4ceaed32016-03-03 18:00:58 -0800698 }
699
700 private ForwardingObjective.Builder upBuilder(PortNumber uplinkPort,
701 PortNumber subscriberPort,
702 VlanId subscriberVlan,
703 VlanId deviceVlan,
Gamze Abaka641fc072018-09-04 09:16:27 +0000704 Optional<VlanId> defaultVlan,
705 MeterId meterId,
706 int technologyProfileId) {
707
708
709 VlanId dVlan = defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan));
710
711 if (subscriberVlan.toShort() == 4096) {
712 dVlan = subscriberVlan;
713 }
714
alshabib4ceaed32016-03-03 18:00:58 -0800715 TrafficSelector upstream = DefaultTrafficSelector.builder()
Gamze Abaka641fc072018-09-04 09:16:27 +0000716 .matchVlanId(dVlan)
alshabib4ceaed32016-03-03 18:00:58 -0800717 .matchInPort(subscriberPort)
718 .build();
719
720
Gamze Abaka641fc072018-09-04 09:16:27 +0000721 TrafficTreatment.Builder upstreamTreatmentBuilder = DefaultTrafficTreatment.builder()
alshabib4ceaed32016-03-03 18:00:58 -0800722 .pushVlan()
723 .setVlanId(subscriberVlan)
724 .pushVlan()
725 .setVlanId(deviceVlan)
Gamze Abaka641fc072018-09-04 09:16:27 +0000726 .setOutput(uplinkPort);
727
728 if (meterId != null) {
729 upstreamTreatmentBuilder.meter(meterId);
730 }
731
732 if (technologyProfileId != -1) {
733 upstreamTreatmentBuilder.transition(technologyProfileId);
734
735 }
alshabib4ceaed32016-03-03 18:00:58 -0800736
737 return DefaultForwardingObjective.builder()
738 .withFlag(ForwardingObjective.Flag.VERSATILE)
739 .withPriority(1000)
740 .makePermanent()
741 .withSelector(upstream)
742 .fromApp(appId)
Gamze Abaka641fc072018-09-04 09:16:27 +0000743 .withTreatment(upstreamTreatmentBuilder.build());
alshabib4ceaed32016-03-03 18:00:58 -0800744 }
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100745 private void provisionTransparentFlows(DeviceId deviceId, PortNumber uplinkPort,
746 PortNumber subscriberPort,
747 VlanId innerVlan,
748 VlanId outerVlan) {
749
750 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
751 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
752
753 ForwardingObjective.Builder upFwd = transparentUpBuilder(uplinkPort, subscriberPort,
754 innerVlan, outerVlan);
755
756
757 ForwardingObjective.Builder downFwd = transparentDownBuilder(uplinkPort, subscriberPort,
758 innerVlan, outerVlan);
759
760 ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
761
762 additionalVlans.put(cp, new AbstractMap.SimpleEntry(outerVlan, innerVlan));
763
764 flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
765 @Override
766 public void onSuccess(Objective objective) {
767 upFuture.complete(null);
768 }
769
770 @Override
771 public void onError(Objective objective, ObjectiveError error) {
772 upFuture.complete(error);
773 }
774 }));
775
776 flowObjectiveService.forward(deviceId, downFwd.add(new ObjectiveContext() {
777 @Override
778 public void onSuccess(Objective objective) {
779 downFuture.complete(null);
780 }
781
782 @Override
783 public void onError(Objective objective, ObjectiveError error) {
784 downFuture.complete(error);
785 }
786 }));
787
788 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
789 if (downStatus != null) {
790 log.error("Flow with innervlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000791 "on port {} failed downstream installation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100792 innerVlan, outerVlan, deviceId, subscriberPort, downStatus);
793 } else if (upStatus != null) {
794 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000795 "on port {} failed upstream installation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100796 innerVlan, outerVlan, deviceId, subscriberPort, upStatus);
797 }
798 }, oltInstallers);
799
800 }
801
802 private ForwardingObjective.Builder transparentDownBuilder(PortNumber uplinkPort,
803 PortNumber subscriberPort,
804 VlanId innerVlan,
805 VlanId outerVlan) {
806 TrafficSelector downstream = DefaultTrafficSelector.builder()
807 .matchVlanId(outerVlan)
808 .matchInPort(uplinkPort)
809 .matchInnerVlanId(innerVlan)
810 .build();
811
812 TrafficTreatment downstreamTreatment = DefaultTrafficTreatment.builder()
813 .setOutput(subscriberPort)
814 .build();
815
816 return DefaultForwardingObjective.builder()
817 .withFlag(ForwardingObjective.Flag.VERSATILE)
818 .withPriority(1000)
819 .makePermanent()
820 .withSelector(downstream)
821 .fromApp(appId)
822 .withTreatment(downstreamTreatment);
823 }
824
825 private ForwardingObjective.Builder transparentUpBuilder(PortNumber uplinkPort,
826 PortNumber subscriberPort,
827 VlanId innerVlan,
828 VlanId outerVlan) {
829 TrafficSelector upstream = DefaultTrafficSelector.builder()
830 .matchVlanId(outerVlan)
831 .matchInPort(subscriberPort)
832 .matchInnerVlanId(innerVlan)
833 .build();
834
835 TrafficTreatment upstreamTreatment = DefaultTrafficTreatment.builder()
836 .setOutput(uplinkPort)
837 .build();
838
839 return DefaultForwardingObjective.builder()
840 .withFlag(ForwardingObjective.Flag.VERSATILE)
841 .withPriority(1000)
842 .makePermanent()
843 .withSelector(upstream)
844 .fromApp(appId)
845 .withTreatment(upstreamTreatment);
846 }
847
848 private void unprovisionTransparentFlows(DeviceId deviceId, PortNumber uplink,
849 PortNumber subscriberPort, VlanId innerVlan,
850 VlanId outerVlan) {
851
852 ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
853
854 additionalVlans.remove(cp, new AbstractMap.SimpleEntry(outerVlan, innerVlan));
855
856 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
857 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
858
859 ForwardingObjective.Builder upFwd = transparentUpBuilder(uplink, subscriberPort,
860 innerVlan, outerVlan);
861 ForwardingObjective.Builder downFwd = transparentDownBuilder(uplink, subscriberPort,
862 innerVlan, outerVlan);
863
864
865 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
866 @Override
867 public void onSuccess(Objective objective) {
868 upFuture.complete(null);
869 }
870
871 @Override
872 public void onError(Objective objective, ObjectiveError error) {
873 upFuture.complete(error);
874 }
875 }));
876
877 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
878 @Override
879 public void onSuccess(Objective objective) {
880 downFuture.complete(null);
881 }
882
883 @Override
884 public void onError(Objective objective, ObjectiveError error) {
885 downFuture.complete(error);
886 }
887 }));
888
889 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
890 if (downStatus != null) {
891 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000892 "on port {} failed downstream uninstallation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100893 innerVlan, outerVlan, deviceId, subscriberPort, downStatus);
894 } else if (upStatus != null) {
895 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000896 "on port {} failed upstream uninstallation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100897 innerVlan, outerVlan, deviceId, subscriberPort, upStatus);
898 }
899 }, oltInstallers);
900
901 }
902
Saurav Das82b8e6d2018-10-04 15:25:12 -0700903 private void processEapolFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
alshabib09753b52016-03-04 14:55:19 -0800904 if (!mastershipService.isLocalMaster(devId)) {
905 return;
906 }
alshabibbb83aa22016-02-10 15:08:23 -0800907 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
908
909 FilteringObjective eapol = (install ? builder.permit() : builder.deny())
alshabib50d9fc52016-02-12 15:47:20 -0800910 .withKey(Criteria.matchInPort(port))
alshabibdec2e252016-01-15 12:20:25 -0800911 .addCondition(Criteria.matchEthType(EthType.EtherType.EAPOL.ethType()))
912 .withMeta(DefaultTrafficTreatment.builder()
Gamze Abaka641fc072018-09-04 09:16:27 +0000913 .setOutput(PortNumber.CONTROLLER).build())
alshabibdec2e252016-01-15 12:20:25 -0800914 .fromApp(appId)
Matt Jeanneret3f579262018-06-14 17:16:23 -0400915 .withPriority(10000)
alshabibdec2e252016-01-15 12:20:25 -0800916 .add(new ObjectiveContext() {
917 @Override
918 public void onSuccess(Objective objective) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700919 log.info("Eapol filter for {} on {} {}.",
Gamze Abaka641fc072018-09-04 09:16:27 +0000920 devId, port, (install) ? "installed" : "removed");
alshabibdec2e252016-01-15 12:20:25 -0800921 }
922
923 @Override
924 public void onError(Objective objective, ObjectiveError error) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700925 log.info("Eapol filter for {} on {} failed {} because {}",
Gamze Abaka641fc072018-09-04 09:16:27 +0000926 devId, port, (install) ? "installation" : "removal",
927 error);
alshabibdec2e252016-01-15 12:20:25 -0800928 }
929 });
930
alshabibdec2e252016-01-15 12:20:25 -0800931 flowObjectiveService.filter(devId, eapol);
alshabib000b6fc2016-02-01 17:25:00 -0800932
alshabibdec2e252016-01-15 12:20:25 -0800933 }
934
Jonathan Hart403372d2018-08-22 11:44:13 -0700935 /**
936 * Installs trap filtering objectives for particular traffic types on an
937 * NNI port.
938 *
939 * @param devId device ID
940 * @param port port number
941 * @param install true to install, false to remove
942 */
943 private void processNniFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
944 processLldpFilteringObjective(devId, port, install);
Matteo Scandolo63460d12018-11-02 16:19:04 -0700945 if (enableDhcpOnProvisioning) {
946 processDhcpFilteringObjectives(devId, port, install, false);
947 }
Jonathan Hart403372d2018-08-22 11:44:13 -0700948 }
949
950 private void processLldpFilteringObjective(DeviceId devId, PortNumber port, boolean install) {
951 if (!mastershipService.isLocalMaster(devId)) {
952 return;
953 }
954 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
955
956 FilteringObjective lldp = (install ? builder.permit() : builder.deny())
957 .withKey(Criteria.matchInPort(port))
958 .addCondition(Criteria.matchEthType(EthType.EtherType.LLDP.ethType()))
959 .withMeta(DefaultTrafficTreatment.builder()
960 .setOutput(PortNumber.CONTROLLER).build())
961 .fromApp(appId)
962 .withPriority(10000)
963 .add(new ObjectiveContext() {
964 @Override
965 public void onSuccess(Objective objective) {
Matteo Scandolo63460d12018-11-02 16:19:04 -0700966 log.info("LLDP filter for device {} on port {} {}.",
Saurav Das82b8e6d2018-10-04 15:25:12 -0700967 devId, port, (install) ? "installed" : "removed");
Jonathan Hart403372d2018-08-22 11:44:13 -0700968 }
969
970 @Override
971 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo63460d12018-11-02 16:19:04 -0700972 log.info("LLDP filter for device {} on port {} failed {} because {}",
Saurav Das82b8e6d2018-10-04 15:25:12 -0700973 devId, port, (install) ? "installation" : "removal",
974 error);
Jonathan Hart403372d2018-08-22 11:44:13 -0700975 }
976 });
977
978 flowObjectiveService.filter(devId, lldp);
979
980 }
981
Saurav Dasacc5eeb2018-10-11 10:58:01 -0700982 /**
983 * Trap dhcp packets to the controller.
984 *
985 * @param devId the device identifier
986 * @param port the port for which this trap flow is designated
987 * @param install true to install the flow, false to remove the flow
988 * @param upstream true if trapped packets are flowing upstream towards
989 * server, false if packets are flowing dowstream towards client
990 */
991 private void processDhcpFilteringObjectives(DeviceId devId, PortNumber port,
992 boolean install,
993 boolean upstream) {
Amit Ghosh95e2f652017-08-23 12:49:46 +0100994 if (!mastershipService.isLocalMaster(devId)) {
995 return;
996 }
Amit Ghosh95e2f652017-08-23 12:49:46 +0100997
Matteo Scandolo63460d12018-11-02 16:19:04 -0700998 if (enableDhcpV4) {
999 int udpSrc = (upstream) ? 68 : 67;
1000 int udpDst = (upstream) ? 67 : 68;
1001
1002 EthType ethType = EthType.EtherType.IPV4.ethType();
1003 byte protocol = IPv4.PROTOCOL_UDP;
1004
1005 this.addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType, protocol, install);
1006 }
1007
1008 if (enableDhcpV6) {
1009 int udpSrc = (upstream) ? 547 : 546;
1010 int udpDst = (upstream) ? 546 : 547;
1011
1012 EthType ethType = EthType.EtherType.IPV6.ethType();
1013 byte protocol = IPv6.PROTOCOL_UDP;
1014
1015 this.addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType, protocol, install);
1016 }
1017
1018 }
1019
1020 private void addDhcpFilteringObjectives(DeviceId devId,
1021 PortNumber port,
1022 int udpSrc,
1023 int udpDst,
1024 EthType ethType,
1025 byte protocol,
1026 boolean install) {
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001027
1028 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Amit Ghosh95e2f652017-08-23 12:49:46 +01001029 FilteringObjective dhcpUpstream = (install ? builder.permit() : builder.deny())
1030 .withKey(Criteria.matchInPort(port))
Matteo Scandolo63460d12018-11-02 16:19:04 -07001031 .addCondition(Criteria.matchEthType(ethType))
1032 .addCondition(Criteria.matchIPProtocol(protocol))
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001033 .addCondition(Criteria.matchUdpSrc(TpPort.tpPort(udpSrc)))
1034 .addCondition(Criteria.matchUdpDst(TpPort.tpPort(udpDst)))
Amit Ghosh95e2f652017-08-23 12:49:46 +01001035 .withMeta(DefaultTrafficTreatment.builder()
Gamze Abaka641fc072018-09-04 09:16:27 +00001036 .setOutput(PortNumber.CONTROLLER).build())
Amit Ghosh95e2f652017-08-23 12:49:46 +01001037 .fromApp(appId)
Matt Jeanneret3f579262018-06-14 17:16:23 -04001038 .withPriority(10000)
Amit Ghosh95e2f652017-08-23 12:49:46 +01001039 .add(new ObjectiveContext() {
1040 @Override
1041 public void onSuccess(Objective objective) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001042 log.info("DHCP {} filter for device {} on port {} {}.",
1043 (ethType.equals(EthType.EtherType.IPV4.ethType())) ? "v4" : "v6",
1044 devId, port, (install) ? "installed" : "removed");
Amit Ghosh95e2f652017-08-23 12:49:46 +01001045 }
1046
1047 @Override
1048 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001049 log.info("DHCP {} filter for device {} on port {} failed {} because {}",
1050 (ethType.equals(EthType.EtherType.IPV4.ethType())) ? "v4" : "v6",
1051 devId, port, (install) ? "installation" : "removal",
1052 error);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001053 }
1054 });
1055
1056 flowObjectiveService.filter(devId, dhcpUpstream);
1057 }
1058
1059 private void processIgmpFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
1060 if (!mastershipService.isLocalMaster(devId)) {
1061 return;
1062 }
1063
Gamze Abaka641fc072018-09-04 09:16:27 +00001064 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Amit Ghosh95e2f652017-08-23 12:49:46 +01001065
1066 builder = install ? builder.permit() : builder.deny();
1067
1068 FilteringObjective igmp = builder
1069 .withKey(Criteria.matchInPort(port))
1070 .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
1071 .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_IGMP))
1072 .withMeta(DefaultTrafficTreatment.builder()
Gamze Abaka641fc072018-09-04 09:16:27 +00001073 .setOutput(PortNumber.CONTROLLER).build())
Amit Ghosh95e2f652017-08-23 12:49:46 +01001074 .fromApp(appId)
1075 .withPriority(10000)
1076 .add(new ObjectiveContext() {
1077 @Override
1078 public void onSuccess(Objective objective) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001079 log.info("Igmp filter for {} on {} {}.",
Gamze Abaka641fc072018-09-04 09:16:27 +00001080 devId, port, (install) ? "installed" : "removed");
Amit Ghosh95e2f652017-08-23 12:49:46 +01001081 }
1082
1083 @Override
1084 public void onError(Objective objective, ObjectiveError error) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001085 log.info("Igmp filter for {} on {} failed {} because {}.",
Gamze Abaka641fc072018-09-04 09:16:27 +00001086 devId, port, (install) ? "installation" : "removal",
1087 error);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001088 }
1089 });
1090
1091 flowObjectiveService.filter(devId, igmp);
1092 }
1093
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001094 /**
Jonathan Hart403372d2018-08-22 11:44:13 -07001095 * Creates trap flows for device, including DHCP and LLDP trap on NNI and
1096 * EAPOL trap on the UNIs, if device is present in Sadis config.
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001097 *
1098 * @param dev Device to look for
1099 */
Jonathan Hart403372d2018-08-22 11:44:13 -07001100 private void checkAndCreateDeviceFlows(Device dev) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001101 // we create only for the ones we are master of
1102 if (!mastershipService.isLocalMaster(dev.id())) {
Gamze Abaka641fc072018-09-04 09:16:27 +00001103 return;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001104 }
1105 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +00001106 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Jonathan Hart403372d2018-08-22 11:44:13 -07001107 log.debug("checkAndCreateDeviceFlows: deviceInfo {}", deviceInfo);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001108
1109 if (deviceInfo != null) {
Jonathan Hart403372d2018-08-22 11:44:13 -07001110 // This is an OLT device as per Sadis, we create flows for UNI and NNI ports
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001111 for (Port p : deviceService.getPorts(dev.id())) {
1112 if (isUniPort(dev, p)) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001113 processEapolFilteringObjectives(dev.id(), p.number(), true);
Jonathan Hart403372d2018-08-22 11:44:13 -07001114 } else {
1115 processNniFilteringObjectives(dev.id(), p.number(), true);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001116 }
1117 }
1118 }
1119 }
1120
Jonathan Hart403372d2018-08-22 11:44:13 -07001121
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001122 /**
1123 * Get the uplink for of the OLT device.
1124 *
1125 * This assumes that the OLT has a single uplink port. When more uplink ports need to be supported
1126 * this logic needs to be changed
1127 *
1128 * @param dev Device to look for
1129 * @return The uplink Port of the OLT
1130 */
1131 private Port getUplinkPort(Device dev) {
1132 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +00001133 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001134 log.debug("getUplinkPort: deviceInfo {}", deviceInfo);
Saurav Das82b8e6d2018-10-04 15:25:12 -07001135 if (deviceInfo == null) {
1136 log.warn("Device {} is not configured in SADIS .. cannot fetch device"
1137 + " info", dev.id());
1138 return null;
1139 }
1140 // Return the port that has been configured as the uplink port of this OLT in Sadis
1141 for (Port p: deviceService.getPorts(dev.id())) {
1142 if (p.number().toLong() == deviceInfo.uplinkPort()) {
1143 log.debug("getUplinkPort: Found port {}", p);
1144 return p;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001145 }
1146 }
1147
Saurav Das82b8e6d2018-10-04 15:25:12 -07001148 log.debug("getUplinkPort: No uplink port found for OLT {}", dev.id());
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001149 return null;
1150 }
1151
1152 /**
1153 * Return the subscriber on a port.
1154 *
Matteo Scandolo962a6ad2018-12-11 15:39:42 -08001155 * @param cp ConnectPoint on which to find the subscriber
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001156 * @return subscriber if found else null
1157 */
Matteo Scandolo962a6ad2018-12-11 15:39:42 -08001158 SubscriberAndDeviceInformation getSubscriber(ConnectPoint cp) {
1159 Port port = deviceService.getPort(cp);
1160 checkNotNull(port, "Invalid connect point");
1161 String portName = port.annotations().value(AnnotationKeys.PORT_NAME);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001162 return subsService.get(portName);
1163 }
1164
1165 private boolean isUniPort(Device d, Port p) {
1166 Port ulPort = getUplinkPort(d);
1167 if (ulPort != null) {
1168 return (ulPort.number().toLong() != p.number().toLong());
1169 }
1170 return false;
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001171 }
1172
Jonathan Hart4c538002018-08-23 10:11:54 -07001173 private SubscriberAndDeviceInformation getOltInfo(Device dev) {
1174 String devSerialNo = dev.serialNumber();
Gamze Abaka641fc072018-09-04 09:16:27 +00001175 return subsService.get(devSerialNo);
Jonathan Hart4c538002018-08-23 10:11:54 -07001176 }
1177
alshabibf0e7e702015-05-30 18:22:36 -07001178 private class InternalDeviceListener implements DeviceListener {
1179 @Override
1180 public void event(DeviceEvent event) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001181 eventExecutor.execute(() -> {
1182 DeviceId devId = event.subject().id();
1183 Device dev = event.subject();
Jonathan Hart4c538002018-08-23 10:11:54 -07001184
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001185 if (event.type() == DeviceEvent.Type.PORT_STATS_UPDATED) {
1186 return;
1187 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001188
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001189 if (getOltInfo(dev) == null) {
1190 log.debug("No device info found, this is not an OLT");
1191 return;
1192 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001193
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001194 log.debug("OLT got {} event for {}", event.type(), event.subject());
Jonathan Hart4c538002018-08-23 10:11:54 -07001195
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001196 switch (event.type()) {
1197 //TODO: Port handling and bookkeeping should be improved once
1198 // olt firmware handles correct behaviour.
1199 case PORT_ADDED:
1200 if (isUniPort(dev, event.port())) {
1201 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, event.port()));
Jonathan Hart4c538002018-08-23 10:11:54 -07001202
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001203 if (event.port().isEnabled()) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001204 processEapolFilteringObjectives(devId, event.port().number(), true);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001205 }
1206 } else {
1207 checkAndCreateDeviceFlows(dev);
1208 }
1209 break;
1210 case PORT_REMOVED:
1211 if (isUniPort(dev, event.port())) {
1212 if (event.port().isEnabled()) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001213 processEapolFilteringObjectives(devId, event.port().number(), false);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001214 removeSubscriber(new ConnectPoint(devId, event.port().number()));
1215 }
1216
1217 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, event.port()));
1218 }
1219
1220 break;
1221 case PORT_UPDATED:
1222 if (!isUniPort(dev, event.port())) {
1223 break;
1224 }
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001225
1226 if (event.port().isEnabled()) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001227 processEapolFilteringObjectives(devId, event.port().number(), true);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001228 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, event.port()));
1229 } else {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001230 processEapolFilteringObjectives(devId, event.port().number(), false);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001231 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, event.port()));
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001232 }
alshabibbb83aa22016-02-10 15:08:23 -08001233 break;
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001234 case DEVICE_ADDED:
alshabib7c190012016-02-09 18:22:33 -08001235 post(new AccessDeviceEvent(
1236 AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
1237 null, null));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001238
1239 // Send UNI_ADDED events for all existing ports
1240 deviceService.getPorts(devId).stream()
1241 .filter(p -> isUniPort(dev, p))
1242 .filter(Port::isEnabled)
1243 .forEach(p -> post(new AccessDeviceEvent(
1244 AccessDeviceEvent.Type.UNI_ADDED, devId, p)));
1245
Jonathan Hart403372d2018-08-22 11:44:13 -07001246 checkAndCreateDeviceFlows(dev);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001247 break;
1248 case DEVICE_REMOVED:
1249 deviceService.getPorts(devId).stream()
1250 .filter(p -> isUniPort(dev, p))
1251 .forEach(p -> post(new AccessDeviceEvent(
1252 AccessDeviceEvent.Type.UNI_REMOVED, devId, p)));
1253
alshabib7c190012016-02-09 18:22:33 -08001254 post(new AccessDeviceEvent(
1255 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
1256 null, null));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001257 break;
1258 case DEVICE_AVAILABILITY_CHANGED:
1259 if (deviceService.isAvailable(devId)) {
1260 post(new AccessDeviceEvent(
1261 AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
1262 null, null));
1263 checkAndCreateDeviceFlows(dev);
1264 } else {
1265 post(new AccessDeviceEvent(
1266 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
1267 null, null));
1268 }
1269 break;
1270 case DEVICE_UPDATED:
1271 case DEVICE_SUSPENDED:
1272 case PORT_STATS_UPDATED:
1273 default:
1274 return;
1275 }
1276 });
alshabibf0e7e702015-05-30 18:22:36 -07001277 }
1278 }
Gamze Abaka641fc072018-09-04 09:16:27 +00001279
1280 private class InternalMeterListener implements MeterListener {
1281
1282 @Override
1283 public void event(MeterEvent meterEvent) {
1284 if (deleteMeters && MeterEvent.Type.METER_REFERENCE_COUNT_ZERO.equals(meterEvent.type())) {
1285 log.debug("Zero Count Meter Event is received. Meter is {}", meterEvent.subject());
1286 Meter meter = meterEvent.subject();
1287 if (meter != null && appId.equals(meter.appId())) {
1288 deleteMeter(meter.deviceId(), meter.id());
1289 }
1290 } else if (MeterEvent.Type.METER_REMOVED.equals(meterEvent.type())) {
1291 log.debug("Meter removed event is received. Meter is {}", meterEvent.subject());
1292 removeMeterFromBpMap(meterEvent.subject());
1293 }
1294 }
1295
1296 private void deleteMeter(DeviceId deviceId, MeterId meterId) {
1297 Meter meter = meterService.getMeter(deviceId, meterId);
1298 MeterRequest meterRequest = DefaultMeterRequest.builder()
1299 .withBands(meter.bands())
1300 .withUnit(meter.unit())
1301 .forDevice(deviceId)
1302 .fromApp(appId)
1303 .burst()
1304 .remove();
1305
1306 meterService.withdraw(meterRequest, meterId);
1307
1308 }
1309
1310 private void removeMeterFromBpMap(Meter meter) {
1311 for (Map.Entry<String, MeterId> entry : bpInfoToMeter.entrySet()) {
1312 if (entry.getValue().equals(meter.id())) {
1313 bpInfoToMeter.remove(entry.getKey());
1314 log.info("Deleted from the internal map. Profile {} and Meter {}", entry.getKey(), meter.id());
1315 break;
1316 }
1317 }
1318 }
1319 }
1320}