blob: 13bb9bb51e196975329567ddf9f9825591cc957b [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;
32import java.util.Optional;
33import java.util.Properties;
Gamze Abaka33feef52019-02-27 08:16:47 +000034import java.util.Set;
Saurav Das82b8e6d2018-10-04 15:25:12 -070035import java.util.concurrent.CompletableFuture;
Gamze Abaka33feef52019-02-27 08:16:47 +000036import java.util.concurrent.ConcurrentHashMap;
Saurav Das82b8e6d2018-10-04 15:25:12 -070037import java.util.concurrent.ExecutorService;
38import java.util.concurrent.Executors;
39
Gamze Abaka33feef52019-02-27 08:16:47 +000040import com.google.common.collect.ImmutableSet;
alshabibf0e7e702015-05-30 18:22:36 -070041import org.apache.felix.scr.annotations.Activate;
42import org.apache.felix.scr.annotations.Component;
43import org.apache.felix.scr.annotations.Deactivate;
alshabibe0559672016-02-21 14:49:51 -080044import org.apache.felix.scr.annotations.Modified;
45import org.apache.felix.scr.annotations.Property;
alshabibf0e7e702015-05-30 18:22:36 -070046import org.apache.felix.scr.annotations.Reference;
47import org.apache.felix.scr.annotations.ReferenceCardinality;
Jonathan Harte533a422015-10-20 17:31:24 -070048import org.apache.felix.scr.annotations.Service;
alshabibdec2e252016-01-15 12:20:25 -080049import org.onlab.packet.EthType;
Amit Ghosh95e2f652017-08-23 12:49:46 +010050import org.onlab.packet.IPv4;
Matteo Scandolo63460d12018-11-02 16:19:04 -070051import org.onlab.packet.IPv6;
Amit Ghosh95e2f652017-08-23 12:49:46 +010052import org.onlab.packet.TpPort;
alshabibf0e7e702015-05-30 18:22:36 -070053import org.onlab.packet.VlanId;
Amit Ghosh95e2f652017-08-23 12:49:46 +010054import org.onlab.util.Tools;
alshabibe0559672016-02-21 14:49:51 -080055import org.onosproject.cfg.ComponentConfigService;
alshabibf0e7e702015-05-30 18:22:36 -070056import org.onosproject.core.ApplicationId;
57import org.onosproject.core.CoreService;
alshabib8e4fd2f2016-01-12 15:55:53 -080058import org.onosproject.event.AbstractListenerManager;
alshabib09753b52016-03-04 14:55:19 -080059import org.onosproject.mastership.MastershipService;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010060import org.onosproject.net.AnnotationKeys;
Jonathan Harte533a422015-10-20 17:31:24 -070061import org.onosproject.net.ConnectPoint;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010062import org.onosproject.net.Device;
alshabibf0e7e702015-05-30 18:22:36 -070063import org.onosproject.net.DeviceId;
alshabibdec2e252016-01-15 12:20:25 -080064import org.onosproject.net.Port;
alshabibf0e7e702015-05-30 18:22:36 -070065import org.onosproject.net.PortNumber;
66import org.onosproject.net.device.DeviceEvent;
67import org.onosproject.net.device.DeviceListener;
68import org.onosproject.net.device.DeviceService;
69import org.onosproject.net.flow.DefaultTrafficSelector;
70import org.onosproject.net.flow.DefaultTrafficTreatment;
71import org.onosproject.net.flow.TrafficSelector;
72import org.onosproject.net.flow.TrafficTreatment;
alshabibdec2e252016-01-15 12:20:25 -080073import org.onosproject.net.flow.criteria.Criteria;
74import org.onosproject.net.flowobjective.DefaultFilteringObjective;
alshabibf0e7e702015-05-30 18:22:36 -070075import org.onosproject.net.flowobjective.DefaultForwardingObjective;
alshabibdec2e252016-01-15 12:20:25 -080076import org.onosproject.net.flowobjective.FilteringObjective;
alshabibf0e7e702015-05-30 18:22:36 -070077import org.onosproject.net.flowobjective.FlowObjectiveService;
78import org.onosproject.net.flowobjective.ForwardingObjective;
alshabib3ea82642016-01-12 18:06:53 -080079import org.onosproject.net.flowobjective.Objective;
80import org.onosproject.net.flowobjective.ObjectiveContext;
81import org.onosproject.net.flowobjective.ObjectiveError;
Saurav Das62ad75e2019-03-05 12:22:22 -080082import org.onosproject.store.serializers.KryoNamespaces;
83import org.onosproject.store.service.ConsistentMultimap;
84import org.onosproject.store.service.Serializer;
85import org.onosproject.store.service.StorageService;
Gamze Abaka33feef52019-02-27 08:16:47 +000086import org.onosproject.net.meter.Band;
87import org.onosproject.net.meter.DefaultBand;
88import org.onosproject.net.meter.DefaultMeterRequest;
89import org.onosproject.net.meter.Meter;
90import org.onosproject.net.meter.MeterContext;
91import org.onosproject.net.meter.MeterFailReason;
92import org.onosproject.net.meter.MeterKey;
93import org.onosproject.net.meter.MeterService;
94import org.onosproject.net.meter.MeterListener;
95import org.onosproject.net.meter.MeterRequest;
96import org.onosproject.net.meter.MeterId;
97import org.onosproject.net.meter.MeterEvent;
alshabib36a4d732016-06-01 16:03:59 -070098import org.opencord.olt.AccessDeviceEvent;
99import org.opencord.olt.AccessDeviceListener;
100import org.opencord.olt.AccessDeviceService;
Amit Ghosh31939522018-08-16 13:28:21 +0100101import org.opencord.olt.AccessSubscriberId;
Gamze Abaka641fc072018-09-04 09:16:27 +0000102import org.opencord.sadis.BandwidthProfileInformation;
103import org.opencord.sadis.BaseInformationService;
104import org.opencord.sadis.SadisService;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100105import org.opencord.sadis.SubscriberAndDeviceInformation;
alshabibe0559672016-02-21 14:49:51 -0800106import org.osgi.service.component.ComponentContext;
alshabibf0e7e702015-05-30 18:22:36 -0700107import org.slf4j.Logger;
108
Saurav Das82b8e6d2018-10-04 15:25:12 -0700109import com.google.common.collect.ImmutableMap;
110import com.google.common.collect.Maps;
Saurav Dasa9d5f442019-03-06 19:32:48 -0800111import com.google.common.collect.Sets;
alshabibf0e7e702015-05-30 18:22:36 -0700112
113/**
Jonathan Harte533a422015-10-20 17:31:24 -0700114 * Provisions rules on access devices.
alshabibf0e7e702015-05-30 18:22:36 -0700115 */
Jonathan Harte533a422015-10-20 17:31:24 -0700116@Service
alshabibf0e7e702015-05-30 18:22:36 -0700117@Component(immediate = true)
alshabib8e4fd2f2016-01-12 15:55:53 -0800118public class Olt
119 extends AbstractListenerManager<AccessDeviceEvent, AccessDeviceListener>
120 implements AccessDeviceService {
Charles Chan54f110f2017-01-20 11:22:42 -0800121 private static final String APP_NAME = "org.opencord.olt";
alshabibe0559672016-02-21 14:49:51 -0800122
123 private static final short DEFAULT_VLAN = 0;
Gamze Abaka1efc80c2019-02-15 12:10:54 +0000124 private static final int DEFAULT_TP_ID = 64;
Gamze Abakaad329652018-12-20 10:12:21 +0000125 private static final String DEFAULT_BP_ID = "Default";
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100126 private static final String ADDITIONAL_VLANS = "additional-vlans";
Gamze Abaka838d8142019-02-21 07:06:55 +0000127 private static final String NO_UPLINK_PORT = "No uplink port found for OLT device {}";
128 private static final String INSTALLED = "installed";
129 private static final String REMOVED = "removed";
130 private static final String INSTALLATION = "installation";
131 private static final String REMOVAL = "removal";
alshabibe0559672016-02-21 14:49:51 -0800132
alshabibf0e7e702015-05-30 18:22:36 -0700133 private final Logger log = getLogger(getClass());
134
135 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
136 protected FlowObjectiveService flowObjectiveService;
137
138 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabib09753b52016-03-04 14:55:19 -0800139 protected MastershipService mastershipService;
140
141 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibf0e7e702015-05-30 18:22:36 -0700142 protected DeviceService deviceService;
143
144 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
145 protected CoreService coreService;
146
Jonathan Harte533a422015-10-20 17:31:24 -0700147 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibe0559672016-02-21 14:49:51 -0800148 protected ComponentConfigService componentConfigService;
149
alshabib4ceaed32016-03-03 18:00:58 -0800150 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Gamze Abaka641fc072018-09-04 09:16:27 +0000151 protected SadisService sadisService;
152
153 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
154 protected MeterService meterService;
alshabibe0559672016-02-21 14:49:51 -0800155
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100156 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
157 protected StorageService storageService;
158
alshabibe0559672016-02-21 14:49:51 -0800159 @Property(name = "defaultVlan", intValue = DEFAULT_VLAN,
160 label = "Default VLAN RG<->ONU traffic")
161 private int defaultVlan = DEFAULT_VLAN;
162
Matt Jeanneret3f579262018-06-14 17:16:23 -0400163 @Property(name = "enableDhcpOnProvisioning", boolValue = true,
164 label = "Create the DHCP Flow rules when a subscriber is provisioned")
165 protected boolean enableDhcpOnProvisioning = false;
166
Matteo Scandolo63460d12018-11-02 16:19:04 -0700167 @Property(name = "enableDhcpV4", boolValue = true,
168 label = "Enable flows for DHCP v4")
169 protected boolean enableDhcpV4 = true;
170
171 @Property(name = "enableDhcpV6", boolValue = true,
172 label = "Enable flows for DHCP v6")
173 protected boolean enableDhcpV6 = false;
174
Matt Jeanneret3f579262018-06-14 17:16:23 -0400175 @Property(name = "enableIgmpOnProvisioning", boolValue = false,
176 label = "Create IGMP Flow rules when a subscriber is provisioned")
177 protected boolean enableIgmpOnProvisioning = false;
Amit Ghosh95e2f652017-08-23 12:49:46 +0100178
Gamze Abaka1efc80c2019-02-15 12:10:54 +0000179 @Property(name = "deleteMeters", boolValue = true,
Gamze Abaka641fc072018-09-04 09:16:27 +0000180 label = "Deleting Meters based on flow count statistics")
Gamze Abaka1efc80c2019-02-15 12:10:54 +0000181 protected boolean deleteMeters = true;
Gamze Abaka641fc072018-09-04 09:16:27 +0000182
Gamze Abakaad329652018-12-20 10:12:21 +0000183 @Property(name = "defaultTechProfileId", intValue = DEFAULT_TP_ID,
184 label = "Default technology profile id that is used for authentication trap flows")
185 protected int defaultTechProfileId = DEFAULT_TP_ID;
186
187 @Property(name = "defaultBpId", value = DEFAULT_BP_ID,
188 label = "Default bandwidth profile id that is used for authentication trap flows")
189 protected String defaultBpId = DEFAULT_BP_ID;
190
Gamze Abaka33feef52019-02-27 08:16:47 +0000191 @Property(name = "enableEapol", boolValue = true,
192 label = "Send EAPOL authentication trap flows before subscriber provisioning")
193 protected boolean enableEapol = true;
194
alshabibf0e7e702015-05-30 18:22:36 -0700195 private final DeviceListener deviceListener = new InternalDeviceListener();
Gamze Abaka641fc072018-09-04 09:16:27 +0000196 private final MeterListener meterListener = new InternalMeterListener();
alshabibf0e7e702015-05-30 18:22:36 -0700197
198 private ApplicationId appId;
Gamze Abaka641fc072018-09-04 09:16:27 +0000199 protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
200 private BaseInformationService<BandwidthProfileInformation> bpService;
alshabibf0e7e702015-05-30 18:22:36 -0700201
Gamze Abaka33feef52019-02-27 08:16:47 +0000202 private Map<String, List<MeterKey>> bpInfoToMeter = new ConcurrentHashMap<>();
Gamze Abaka641fc072018-09-04 09:16:27 +0000203
204 private ExecutorService oltInstallers = Executors.newFixedThreadPool(4,
205 groupedThreads("onos/olt-service",
206 "olt-installer-%d"));
alshabibf0e7e702015-05-30 18:22:36 -0700207
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100208 private ConsistentMultimap<ConnectPoint, Map.Entry<VlanId, VlanId>> additionalVlans;
209
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700210 protected ExecutorService eventExecutor;
211
Saurav Das82b8e6d2018-10-04 15:25:12 -0700212 private Map<ConnectPoint, SubscriberAndDeviceInformation> programmedSubs;
Gamze Abaka33feef52019-02-27 08:16:47 +0000213 private Set<MeterKey> programmedMeters;
Saurav Das82b8e6d2018-10-04 15:25:12 -0700214
Saurav Dasa9d5f442019-03-06 19:32:48 -0800215
alshabibf0e7e702015-05-30 18:22:36 -0700216 @Activate
alshabibe0559672016-02-21 14:49:51 -0800217 public void activate(ComponentContext context) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700218 eventExecutor = newSingleThreadScheduledExecutor(groupedThreads("onos/olt", "events-%d", log));
alshabibe0559672016-02-21 14:49:51 -0800219 modified(context);
Charles Chan54f110f2017-01-20 11:22:42 -0800220 appId = coreService.registerApplication(APP_NAME);
Saurav Das62ad75e2019-03-05 12:22:22 -0800221
222 // ensure that flow rules are purged from flow-store upon olt-disconnection
223 // when olt reconnects, the port-numbers may change for the ONUs
224 // making flows pushed earlier invalid
225 componentConfigService
226 .preSetProperty("org.onosproject.net.flow.impl.FlowRuleManager",
Gamze Abaka33feef52019-02-27 08:16:47 +0000227 "purgeOnDisconnection", "true");
alshabibe0559672016-02-21 14:49:51 -0800228 componentConfigService.registerProperties(getClass());
Saurav Das82b8e6d2018-10-04 15:25:12 -0700229 programmedSubs = Maps.newConcurrentMap();
Gamze Abaka33feef52019-02-27 08:16:47 +0000230 programmedMeters = ConcurrentHashMap.newKeySet();
alshabibc4dfe852015-06-05 13:35:13 -0700231
alshabib8e4fd2f2016-01-12 15:55:53 -0800232 eventDispatcher.addSink(AccessDeviceEvent.class, listenerRegistry);
233
Gamze Abaka641fc072018-09-04 09:16:27 +0000234 subsService = sadisService.getSubscriberInfoService();
235 bpService = sadisService.getBandwidthProfileService();
236
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100237 // look for all provisioned devices in Sadis and create EAPOL flows for the
238 // UNI ports
239 Iterable<Device> devices = deviceService.getDevices();
240 for (Device d : devices) {
Jonathan Hart403372d2018-08-22 11:44:13 -0700241 checkAndCreateDeviceFlows(d);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100242 }
alshabib4ceaed32016-03-03 18:00:58 -0800243
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100244 additionalVlans = storageService.<ConnectPoint, Map.Entry<VlanId, VlanId>>consistentMultimapBuilder()
245 .withName(ADDITIONAL_VLANS)
246 .withSerializer(Serializer.using(Arrays.asList(KryoNamespaces.API),
247 AbstractMap.SimpleEntry.class))
248 .build();
249
alshabibba357492016-01-27 13:49:46 -0800250 deviceService.addListener(deviceListener);
Gamze Abaka641fc072018-09-04 09:16:27 +0000251 meterService.addListener(meterListener);
alshabibba357492016-01-27 13:49:46 -0800252
alshabibf0e7e702015-05-30 18:22:36 -0700253 log.info("Started with Application ID {}", appId.id());
254 }
255
256 @Deactivate
257 public void deactivate() {
alshabibe0559672016-02-21 14:49:51 -0800258 componentConfigService.unregisterProperties(getClass(), false);
alshabib62e9ce72016-02-11 17:31:36 -0800259 deviceService.removeListener(deviceListener);
Gamze Abaka641fc072018-09-04 09:16:27 +0000260 meterService.removeListener(meterListener);
Jonathan Hart5f1c8142018-07-24 17:31:59 -0700261 eventDispatcher.removeSink(AccessDeviceEvent.class);
alshabibf0e7e702015-05-30 18:22:36 -0700262 log.info("Stopped");
263 }
264
alshabibe0559672016-02-21 14:49:51 -0800265 @Modified
266 public void modified(ComponentContext context) {
267 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
268
269 try {
270 String s = get(properties, "defaultVlan");
271 defaultVlan = isNullOrEmpty(s) ? DEFAULT_VLAN : Integer.parseInt(s.trim());
Amit Ghosh95e2f652017-08-23 12:49:46 +0100272
Matt Jeanneret3f579262018-06-14 17:16:23 -0400273 Boolean o = Tools.isPropertyEnabled(properties, "enableDhcpOnProvisioning");
Amit Ghosh95e2f652017-08-23 12:49:46 +0100274 if (o != null) {
Matt Jeanneret3f579262018-06-14 17:16:23 -0400275 enableDhcpOnProvisioning = o;
Amit Ghosh95e2f652017-08-23 12:49:46 +0100276 }
Matt Jeanneret3f579262018-06-14 17:16:23 -0400277
Matteo Scandolo63460d12018-11-02 16:19:04 -0700278 Boolean v4 = Tools.isPropertyEnabled(properties, "enableDhcpV4");
279 if (v4 != null) {
280 enableDhcpV4 = v4;
281 }
282
283 Boolean v6 = Tools.isPropertyEnabled(properties, "enableDhcpV6");
284 if (v6 != null) {
285 enableDhcpV6 = v6;
286 }
287
Matt Jeanneret3f579262018-06-14 17:16:23 -0400288 Boolean p = Tools.isPropertyEnabled(properties, "enableIgmpOnProvisioning");
289 if (p != null) {
290 enableIgmpOnProvisioning = p;
291 }
292
Matteo Scandolo63460d12018-11-02 16:19:04 -0700293 log.info("DHCP Settings [enableDhcpOnProvisioning: {}, enableDhcpV4: {}, enableDhcpV6: {}]",
Gamze Abakaad329652018-12-20 10:12:21 +0000294 enableDhcpOnProvisioning, enableDhcpV4, enableDhcpV6);
Matteo Scandolo63460d12018-11-02 16:19:04 -0700295
Gamze Abaka641fc072018-09-04 09:16:27 +0000296 Boolean d = Tools.isPropertyEnabled(properties, "deleteMeters");
297 if (d != null) {
298 deleteMeters = d;
299 }
300
Gamze Abakaad329652018-12-20 10:12:21 +0000301 String tpId = get(properties, "defaultTechProfileId");
302 defaultTechProfileId = isNullOrEmpty(s) ? DEFAULT_TP_ID : Integer.parseInt(tpId.trim());
303
304 String bpId = get(properties, "defaultBpId");
305 defaultBpId = bpId;
306
Gamze Abaka33feef52019-02-27 08:16:47 +0000307 Boolean eap = Tools.isPropertyEnabled(properties, "enableEapol");
308 if (eap != null) {
309 enableEapol = eap;
310 }
311
alshabibe0559672016-02-21 14:49:51 -0800312 } catch (Exception e) {
313 defaultVlan = DEFAULT_VLAN;
314 }
315 }
316
alshabib32232c82016-02-25 17:57:24 -0500317 @Override
Gamze Abaka838d8142019-02-21 07:06:55 +0000318 public boolean provisionSubscriber(ConnectPoint connectPoint) {
319
320 DeviceId deviceId = connectPoint.deviceId();
321 PortNumber subscriberPortNo = connectPoint.port();
322
323 checkNotNull(deviceService.getPort(deviceId, subscriberPortNo),
Jonathan Hart94b90492018-04-24 14:02:25 -0700324 "Invalid connect point");
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100325 // Find the subscriber on this connect point
Gamze Abaka838d8142019-02-21 07:06:55 +0000326 SubscriberAndDeviceInformation sub = getSubscriber(connectPoint);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100327 if (sub == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000328 log.warn("No subscriber found for {}", connectPoint);
Amit Ghosh31939522018-08-16 13:28:21 +0100329 return false;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100330 }
Jonathan Harte533a422015-10-20 17:31:24 -0700331
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100332 // Get the uplink port
Gamze Abaka838d8142019-02-21 07:06:55 +0000333 Port uplinkPort = getUplinkPort(deviceService.getDevice(deviceId));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100334 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000335 log.warn(NO_UPLINK_PORT, deviceId);
Amit Ghosh31939522018-08-16 13:28:21 +0100336 return false;
Jonathan Harte533a422015-10-20 17:31:24 -0700337 }
338
Gamze Abaka33feef52019-02-27 08:16:47 +0000339 CompletableFuture<ObjectiveError> filterFuture = new CompletableFuture();
340
Gamze Abaka838d8142019-02-21 07:06:55 +0000341 //delete Eapol authentication flow with default bandwidth
Gamze Abaka33feef52019-02-27 08:16:47 +0000342 //wait until Eapol rule with defaultBpId is removed to install subscriber-based rules
343 processEapolFilteringObjectives(deviceId, subscriberPortNo, defaultBpId, filterFuture, false);
344 removeMeterIdFromBpMapping(deviceId, defaultBpId);
Gamze Abaka838d8142019-02-21 07:06:55 +0000345
Gamze Abaka33feef52019-02-27 08:16:47 +0000346 //install subscriber flows
347 filterFuture.thenAcceptAsync(filterStatus -> {
348 if (filterStatus == null) {
349 provisionSubscriberBasedFlows(connectPoint, uplinkPort.number(), Optional.empty(), sub);
350 }
351 });
Gamze Abaka838d8142019-02-21 07:06:55 +0000352
Saurav Das82b8e6d2018-10-04 15:25:12 -0700353 // cache subscriber info
Gamze Abaka838d8142019-02-21 07:06:55 +0000354 programmedSubs.put(connectPoint, sub);
Amit Ghosh31939522018-08-16 13:28:21 +0100355 return true;
alshabibb7a9e172016-01-13 11:23:53 -0800356 }
357
358 @Override
Gamze Abaka838d8142019-02-21 07:06:55 +0000359 public boolean removeSubscriber(ConnectPoint connectPoint) {
Matteo Scandolo962a6ad2018-12-11 15:39:42 -0800360 // Get the subscriber connected to this port from the local cache
361 // as if we don't know about the subscriber there's no need to remove it
Gamze Abaka838d8142019-02-21 07:06:55 +0000362
363 DeviceId deviceId = connectPoint.deviceId();
364 PortNumber subscriberPortNo = connectPoint.port();
365
366 SubscriberAndDeviceInformation subscriber = programmedSubs.get(connectPoint);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100367 if (subscriber == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000368 log.warn("Subscriber on connectionPoint {} was not previously programmed, " +
369 "no need to remove it", connectPoint);
Matteo Scandolo962a6ad2018-12-11 15:39:42 -0800370 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800371 }
372
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100373 // Get the uplink port
Gamze Abaka838d8142019-02-21 07:06:55 +0000374 Port uplinkPort = getUplinkPort(deviceService.getDevice(deviceId));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100375 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000376 log.warn(NO_UPLINK_PORT, deviceId);
Amit Ghosh31939522018-08-16 13:28:21 +0100377 return false;
alshabib4ceaed32016-03-03 18:00:58 -0800378 }
379
Gamze Abaka33feef52019-02-27 08:16:47 +0000380 //delete dhcp & igmp trap flows
381 MeterId upstreamMeterId = getMeterIdFromBpMapping(deviceId, subscriber.upstreamBandwidthProfile());
Amit Ghosh95e2f652017-08-23 12:49:46 +0100382
Gamze Abaka33feef52019-02-27 08:16:47 +0000383 //process dhcp filtering
384 processDhcpFilteringObjectives(deviceId, subscriberPortNo,
385 upstreamMeterId, subscriber.technologyProfileId(), false, true);
Gamze Abaka838d8142019-02-21 07:06:55 +0000386
Gamze Abaka33feef52019-02-27 08:16:47 +0000387 //process igmp filtering
388 processIgmpFilteringObjectives(deviceId, subscriberPortNo,
389 upstreamMeterId, subscriber.technologyProfileId(), false);
alshabibbf23a1f2016-01-14 17:27:11 -0800390
Gamze Abaka33feef52019-02-27 08:16:47 +0000391 //unprovision vlans
392 unprovisionVlans(deviceId, uplinkPort.number(), subscriberPortNo, subscriber, Optional.empty());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100393
394 // Remove if there are any flows for the additional Vlans
Gamze Abaka838d8142019-02-21 07:06:55 +0000395 Collection<? extends Map.Entry<VlanId, VlanId>> vlansList = additionalVlans.get(connectPoint).value();
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100396
397 // Remove the flows for the additional vlans for this subscriber
398 for (Map.Entry<VlanId, VlanId> vlans : vlansList) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000399 unprovisionTransparentFlows(deviceId, uplinkPort.number(), subscriberPortNo,
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100400 vlans.getValue(), vlans.getKey());
401
402 // Remove it from the map also
Gamze Abaka838d8142019-02-21 07:06:55 +0000403 additionalVlans.remove(connectPoint, vlans);
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100404 }
405
Gamze Abaka33feef52019-02-27 08:16:47 +0000406 //re-install eapol
407 processEapolFilteringObjectives(deviceId, subscriberPortNo,
408 subscriber.upstreamBandwidthProfile(), null, false);
409 processEapolFilteringObjectives(deviceId, subscriberPortNo, defaultBpId, null, true);
410
Gamze Abaka838d8142019-02-21 07:06:55 +0000411 programmedSubs.remove(connectPoint);
Amit Ghosh31939522018-08-16 13:28:21 +0100412 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800413 }
414
Amit Ghosh31939522018-08-16 13:28:21 +0100415 @Override
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100416 public boolean provisionSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag, Optional<VlanId> cTag) {
Amit Ghosh31939522018-08-16 13:28:21 +0100417 // Check if we can find the connect point to which this subscriber is connected
418 ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
419 if (subsPort == null) {
420 log.warn("ConnectPoint for {} not found", subscriberId);
421 return false;
422 }
423
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100424 if (!sTag.isPresent() && !cTag.isPresent()) {
425 return provisionSubscriber(subsPort);
426 } else if (sTag.isPresent() && cTag.isPresent()) {
427 Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
428 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000429 log.warn(NO_UPLINK_PORT, subsPort.deviceId());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100430 return false;
431 }
432
433 provisionTransparentFlows(subsPort.deviceId(), uplinkPort.number(), subsPort.port(),
434 cTag.get(), sTag.get());
435 return true;
436 } else {
437 log.warn("Provisioning failed for subscriber: {}", subscriberId);
438 return false;
439 }
Amit Ghosh31939522018-08-16 13:28:21 +0100440 }
Amit Ghosh95e2f652017-08-23 12:49:46 +0100441
alshabibe0559672016-02-21 14:49:51 -0800442 @Override
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100443 public boolean removeSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag, Optional<VlanId> cTag) {
Amit Ghosh31939522018-08-16 13:28:21 +0100444 // Check if we can find the connect point to which this subscriber is connected
445 ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
446 if (subsPort == null) {
447 log.warn("ConnectPoint for {} not found", subscriberId);
448 return false;
449 }
450
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100451 if (!sTag.isPresent() && !cTag.isPresent()) {
452 return removeSubscriber(subsPort);
453 } else if (sTag.isPresent() && cTag.isPresent()) {
454 // Get the uplink port
455 Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
456 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000457 log.warn(NO_UPLINK_PORT, subsPort.deviceId());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100458 return false;
459 }
460
461 unprovisionTransparentFlows(subsPort.deviceId(), uplinkPort.number(), subsPort.port(),
462 cTag.get(), sTag.get());
463 return true;
464 } else {
465 log.warn("Removing subscriber failed for: {}", subscriberId);
466 return false;
467 }
Amit Ghosh31939522018-08-16 13:28:21 +0100468 }
469
470 @Override
471 public Collection<Map.Entry<ConnectPoint, Map.Entry<VlanId, VlanId>>> getSubscribers() {
472 ArrayList<Map.Entry<ConnectPoint, Map.Entry<VlanId, VlanId>>> subs = new ArrayList<>();
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100473
Saurav Das82b8e6d2018-10-04 15:25:12 -0700474 // Get the subscribers for all the devices configured in sadis
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100475 // If the port is UNI, is enabled and exists in Sadis then copy it
476 for (Device d : deviceService.getDevices()) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700477 if (getOltInfo(d) == null) {
478 continue; // not an olt, or not configured in sadis
479 }
Gamze Abakaad329652018-12-20 10:12:21 +0000480 for (Port p : deviceService.getPorts(d.id())) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100481 if (isUniPort(d, p) && p.isEnabled()) {
482 ConnectPoint cp = new ConnectPoint(d.id(), p.number());
483
484 SubscriberAndDeviceInformation sub = getSubscriber(cp);
485 if (sub != null) {
Amit Ghosh31939522018-08-16 13:28:21 +0100486 Map.Entry<VlanId, VlanId> vlans = new AbstractMap.SimpleEntry(sub.sTag(), sub.cTag());
487 subs.add(new AbstractMap.SimpleEntry(cp, vlans));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100488 }
489 }
490 }
491 }
492
493 return subs;
Jonathan Hartfd6c1b32016-03-08 14:09:09 -0800494 }
495
496 @Override
Saurav Das82b8e6d2018-10-04 15:25:12 -0700497 public ImmutableMap<ConnectPoint, SubscriberAndDeviceInformation> getProgSubs() {
498 return ImmutableMap.copyOf(programmedSubs);
499 }
500
501 @Override
Gamze Abaka33feef52019-02-27 08:16:47 +0000502 public ImmutableSet<MeterKey> getProgMeters() {
503 return ImmutableSet.copyOf(programmedMeters);
504 }
505
506 @Override
507 public ImmutableMap<String, List<MeterKey>> getBpMeterMappings() {
508 return ImmutableMap.copyOf(bpInfoToMeter);
509 }
510
511 @Override
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100512 public List<DeviceId> fetchOlts() {
513 // look through all the devices and find the ones that are OLTs as per Sadis
514 List<DeviceId> olts = new ArrayList<>();
515 Iterable<Device> devices = deviceService.getDevices();
516 for (Device d : devices) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700517 if (getOltInfo(d) != null) {
518 // So this is indeed an OLT device
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100519 olts.add(d.id());
520 }
521 }
522 return olts;
alshabibe0559672016-02-21 14:49:51 -0800523 }
524
Amit Ghosh31939522018-08-16 13:28:21 +0100525 /**
526 * Finds the connect point to which a subscriber is connected.
527 *
528 * @param id The id of the subscriber, this is the same ID as in Sadis
529 * @return Subscribers ConnectPoint if found else null
530 */
531 private ConnectPoint findSubscriberConnectPoint(String id) {
532
533 Iterable<Device> devices = deviceService.getDevices();
534 for (Device d : devices) {
535 for (Port p : deviceService.getPorts(d.id())) {
536 log.trace("Comparing {} with {}", p.annotations().value(AnnotationKeys.PORT_NAME), id);
537 if (p.annotations().value(AnnotationKeys.PORT_NAME).equals(id)) {
538 log.debug("Found on device {} port {}", d.id(), p.number());
539 return new ConnectPoint(d.id(), p.number());
540 }
541 }
542 }
543 return null;
544 }
545
Gamze Abaka641fc072018-09-04 09:16:27 +0000546 private BandwidthProfileInformation getBandwidthProfileInformation(String bandwidthProfile) {
547 if (bandwidthProfile == null) {
548 return null;
549 }
550 return bpService.get(bandwidthProfile);
551 }
552
Gamze Abaka838d8142019-02-21 07:06:55 +0000553 /**
Gamze Abaka33feef52019-02-27 08:16:47 +0000554 * Removes subscriber vlan flows.
Gamze Abaka838d8142019-02-21 07:06:55 +0000555 *
556 * @param deviceId the device identifier
557 * @param uplink uplink port of the OLT
558 * @param subscriberPort uni port
559 * @param subscriber subscriber info that includes s, c tags, tech profile and bandwidth profile references
560 * @param defaultVlan default vlan of the subscriber
Gamze Abaka838d8142019-02-21 07:06:55 +0000561 */
Gamze Abaka33feef52019-02-27 08:16:47 +0000562 private void unprovisionVlans(DeviceId deviceId, PortNumber uplink,
563 PortNumber subscriberPort, SubscriberAndDeviceInformation subscriber,
564 Optional<VlanId> defaultVlan) {
565
566 log.info("Unprovisioning vlans...");
alshabibbf23a1f2016-01-14 17:27:11 -0800567
568 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
569 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
570
Gamze Abaka641fc072018-09-04 09:16:27 +0000571 VlanId deviceVlan = subscriber.sTag();
572 VlanId subscriberVlan = subscriber.cTag();
573
Gamze Abaka33feef52019-02-27 08:16:47 +0000574 MeterId upstreamMeterId = getMeterIdFromBpMapping(deviceId, subscriber.upstreamBandwidthProfile());
575 MeterId downstreamMeterId = getMeterIdFromBpMapping(deviceId, subscriber.downstreamBandwidthProfile());
Gamze Abaka641fc072018-09-04 09:16:27 +0000576
alshabib4ceaed32016-03-03 18:00:58 -0800577 ForwardingObjective.Builder upFwd = upBuilder(uplink, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000578 subscriberVlan, deviceVlan,
579 defaultVlan, upstreamMeterId, subscriber.technologyProfileId());
alshabib4ceaed32016-03-03 18:00:58 -0800580 ForwardingObjective.Builder downFwd = downBuilder(uplink, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000581 subscriberVlan, deviceVlan,
582 defaultVlan, downstreamMeterId, subscriber.technologyProfileId());
alshabibbf23a1f2016-01-14 17:27:11 -0800583
alshabib4ceaed32016-03-03 18:00:58 -0800584 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
585 @Override
586 public void onSuccess(Objective objective) {
587 upFuture.complete(null);
588 }
alshabibbf23a1f2016-01-14 17:27:11 -0800589
alshabib4ceaed32016-03-03 18:00:58 -0800590 @Override
591 public void onError(Objective objective, ObjectiveError error) {
592 upFuture.complete(error);
593 }
594 }));
595
596 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
597 @Override
598 public void onSuccess(Objective objective) {
599 downFuture.complete(null);
600 }
601
602 @Override
603 public void onError(Objective objective, ObjectiveError error) {
604 downFuture.complete(error);
605 }
606 }));
alshabibbf23a1f2016-01-14 17:27:11 -0800607
608 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
609 if (upStatus == null && downStatus == null) {
610 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_UNREGISTERED,
Gamze Abaka641fc072018-09-04 09:16:27 +0000611 deviceId,
612 deviceVlan,
613 subscriberVlan));
alshabibbf23a1f2016-01-14 17:27:11 -0800614 } else if (downStatus != null) {
615 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000616 "on port {} failed downstream uninstallation: {}",
617 subscriberVlan, deviceId, subscriberPort, downStatus);
alshabibbf23a1f2016-01-14 17:27:11 -0800618 } else if (upStatus != null) {
619 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000620 "on port {} failed upstream uninstallation: {}",
621 subscriberVlan, deviceId, subscriberPort, upStatus);
alshabibbf23a1f2016-01-14 17:27:11 -0800622 }
623 }, oltInstallers);
alshabibb7a9e172016-01-13 11:23:53 -0800624
Gamze Abaka33feef52019-02-27 08:16:47 +0000625 programmedMeters.remove(MeterKey.key(deviceId, upstreamMeterId));
626 programmedMeters.remove(MeterKey.key(deviceId, downstreamMeterId));
Gamze Abaka838d8142019-02-21 07:06:55 +0000627 log.debug("programmed Meters size {}", programmedMeters.size());
Jonathan Harte533a422015-10-20 17:31:24 -0700628 }
629
Gamze Abaka838d8142019-02-21 07:06:55 +0000630 /**
Gamze Abaka33feef52019-02-27 08:16:47 +0000631 * Adds subscriber vlan flows, dhcp, eapol and igmp trap flows for the related uni port.
Gamze Abaka838d8142019-02-21 07:06:55 +0000632 *
633 * @param port the connection point of the subscriber
634 * @param uplinkPort uplink port of the OLT
635 * @param defaultVlan default vlan of the subscriber
636 * @param sub subscriber information that includes s, c tags, tech profile and bandwidth profile references
Gamze Abaka838d8142019-02-21 07:06:55 +0000637 */
Gamze Abaka33feef52019-02-27 08:16:47 +0000638 private void provisionSubscriberBasedFlows(ConnectPoint port, PortNumber uplinkPort, Optional<VlanId> defaultVlan,
639 SubscriberAndDeviceInformation sub) {
Gamze Abaka641fc072018-09-04 09:16:27 +0000640
641 log.info("Provisioning vlans...");
642
643 DeviceId deviceId = port.deviceId();
644 PortNumber subscriberPort = port.port();
645 VlanId deviceVlan = sub.sTag();
646 VlanId subscriberVlan = sub.cTag();
647 int techProfId = sub.technologyProfileId();
648
649 BandwidthProfileInformation upstreamBpInfo = getBandwidthProfileInformation(sub.upstreamBandwidthProfile());
650 BandwidthProfileInformation downstreamBpInfo = getBandwidthProfileInformation(sub.downstreamBandwidthProfile());
651
alshabib3ea82642016-01-12 18:06:53 -0800652 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
653 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
Gamze Abaka33feef52019-02-27 08:16:47 +0000654 CompletableFuture<Object> upstreamMeterFuture = new CompletableFuture<>();
655 CompletableFuture<Object> downsteamMeterFuture = new CompletableFuture<>();
alshabib3ea82642016-01-12 18:06:53 -0800656
Gamze Abaka33feef52019-02-27 08:16:47 +0000657 MeterId upstreamMeterId = createMeter(deviceId, upstreamBpInfo, upstreamMeterFuture);
658 MeterId downstreamMeterId = createMeter(deviceId, downstreamBpInfo, downsteamMeterFuture);
Jonathan Harte533a422015-10-20 17:31:24 -0700659
Gamze Abaka33feef52019-02-27 08:16:47 +0000660 //install upstream flows
661 upstreamMeterFuture.thenAcceptAsync(result -> {
662 if (result == null) {
663 log.info("Upstream Meter {} is sent to the device {}. " +
664 "Sending subscriber flows.", upstreamMeterId, deviceId);
665 ForwardingObjective.Builder upFwd = upBuilder(uplinkPort, subscriberPort,
666 subscriberVlan, deviceVlan,
667 defaultVlan, upstreamMeterId, techProfId);
alshabib3ea82642016-01-12 18:06:53 -0800668
Gamze Abaka33feef52019-02-27 08:16:47 +0000669
670 flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
671 @Override
672 public void onSuccess(Objective objective) {
673 upFuture.complete(null);
674 }
675
676 @Override
677 public void onError(Objective objective, ObjectiveError error) {
678 upFuture.complete(error);
679 }
680 }));
681 } else {
682 log.warn("Meter installation error while sending upstream flows. " +
683 "Result {} and MeterId {}", result, upstreamMeterId);
alshabibbf23a1f2016-01-14 17:27:11 -0800684 }
Gamze Abaka33feef52019-02-27 08:16:47 +0000685 });
alshabibbf23a1f2016-01-14 17:27:11 -0800686
Gamze Abaka33feef52019-02-27 08:16:47 +0000687 //install downstream flows
688 downsteamMeterFuture.thenAcceptAsync(result -> {
689 if (result == null) {
690 log.info("Downstream Meter {} is sent to the device {}. " +
691 "Sending subscriber flows.", downstreamMeterId, deviceId);
692 ForwardingObjective.Builder downFwd = downBuilder(uplinkPort, subscriberPort,
693 subscriberVlan, deviceVlan,
694 defaultVlan, downstreamMeterId, techProfId);
695
696 flowObjectiveService.forward(deviceId, downFwd.add(new ObjectiveContext() {
697 @Override
698 public void onSuccess(Objective objective) {
699 downFuture.complete(null);
700 }
701
702 @Override
703 public void onError(Objective objective, ObjectiveError error) {
704 downFuture.complete(error);
705 }
706 }));
707 } else {
708 log.warn("Meter installation error while sending downstream flows. " +
709 "Result {} and MeterId {}", result, downstreamMeterId);
alshabibbf23a1f2016-01-14 17:27:11 -0800710 }
Gamze Abaka33feef52019-02-27 08:16:47 +0000711 });
alshabibbf23a1f2016-01-14 17:27:11 -0800712
Gamze Abaka33feef52019-02-27 08:16:47 +0000713 //send eapol & dhcp & igmp flows
714 //send Subscriber Registered event
alshabib3ea82642016-01-12 18:06:53 -0800715 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
716 if (upStatus == null && downStatus == null) {
Gamze Abaka33feef52019-02-27 08:16:47 +0000717
718 if (upstreamMeterId != null) {
719 //re-install Eapol authentication flow with the subscribers' upstream bandwidth profile
720 processEapolFilteringObjectives(deviceId, subscriberPort, sub.upstreamBandwidthProfile(),
721 null, true);
722
723 processDhcpFilteringObjectives(deviceId, subscriberPort,
724 upstreamMeterId, sub.technologyProfileId(), true, true);
725
726 processIgmpFilteringObjectives(deviceId, subscriberPort,
727 upstreamMeterId, sub.technologyProfileId(), true);
728 }
729
alshabib3ea82642016-01-12 18:06:53 -0800730 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_REGISTERED,
Gamze Abaka641fc072018-09-04 09:16:27 +0000731 deviceId,
732 deviceVlan,
733 subscriberVlan));
alshabib50d9fc52016-02-12 15:47:20 -0800734
alshabib3ea82642016-01-12 18:06:53 -0800735 } else if (downStatus != null) {
736 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000737 "on port {} failed downstream installation: {}",
738 subscriberVlan, deviceId, subscriberPort, downStatus);
alshabib3ea82642016-01-12 18:06:53 -0800739 } else if (upStatus != null) {
740 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000741 "on port {} failed upstream installation: {}",
742 subscriberVlan, deviceId, subscriberPort, upStatus);
alshabib3ea82642016-01-12 18:06:53 -0800743 }
744 }, oltInstallers);
Jonathan Harte533a422015-10-20 17:31:24 -0700745 }
746
Gamze Abaka33feef52019-02-27 08:16:47 +0000747 private MeterId createMeter(DeviceId deviceId, BandwidthProfileInformation bpInfo,
748 CompletableFuture<Object> meterFuture) {
Gamze Abaka641fc072018-09-04 09:16:27 +0000749 if (bpInfo == null) {
750 log.warn("Bandwidth profile information is not found");
751 return null;
752 }
753
Gamze Abaka33feef52019-02-27 08:16:47 +0000754 MeterId meterId = getMeterIdFromBpMapping(deviceId, bpInfo.id());
Gamze Abaka641fc072018-09-04 09:16:27 +0000755 if (meterId != null) {
756 log.info("Meter is already added. MeterId {}", meterId);
Gamze Abaka33feef52019-02-27 08:16:47 +0000757 meterFuture.complete(null);
Gamze Abaka641fc072018-09-04 09:16:27 +0000758 return meterId;
759 }
760
761 List<Band> meterBands = createMeterBands(bpInfo);
762
763 MeterRequest meterRequest = DefaultMeterRequest.builder()
764 .withBands(meterBands)
765 .withUnit(Meter.Unit.KB_PER_SEC)
Gamze Abaka33feef52019-02-27 08:16:47 +0000766 .withContext(new MeterContext() {
767 @Override
768 public void onSuccess(MeterRequest op) {
769 log.debug("meter addition completed");
770 meterFuture.complete(null);
771 }
772
773 @Override
774 public void onError(MeterRequest op, MeterFailReason reason) {
775 meterFuture.complete(reason);
776 }
777 })
Gamze Abaka641fc072018-09-04 09:16:27 +0000778 .forDevice(deviceId)
779 .fromApp(appId)
780 .burst()
781 .add();
782
783 Meter meter = meterService.submit(meterRequest);
Gamze Abaka33feef52019-02-27 08:16:47 +0000784 addMeterIdToBpMapping(deviceId, meter.id(), bpInfo.id());
Gamze Abaka641fc072018-09-04 09:16:27 +0000785 log.info("Meter is created. Meter Id {}", meter.id());
Gamze Abaka33feef52019-02-27 08:16:47 +0000786 programmedMeters.add(MeterKey.key(deviceId, meter.id()));
Gamze Abaka838d8142019-02-21 07:06:55 +0000787 log.debug("programmed Meters size {}", programmedMeters.size());
Gamze Abaka641fc072018-09-04 09:16:27 +0000788 return meter.id();
789 }
790
791 private List<Band> createMeterBands(BandwidthProfileInformation bpInfo) {
792 List<Band> meterBands = new ArrayList<>();
793
794 meterBands.add(createMeterBand(bpInfo.committedInformationRate(), bpInfo.committedBurstSize()));
795 meterBands.add(createMeterBand(bpInfo.exceededInformationRate(), bpInfo.exceededBurstSize()));
Gamze Abakaad329652018-12-20 10:12:21 +0000796 meterBands.add(createMeterBand(bpInfo.assuredInformationRate(), 0L));
Gamze Abaka641fc072018-09-04 09:16:27 +0000797
Gamze Abaka641fc072018-09-04 09:16:27 +0000798 return meterBands;
799 }
800
801 private Band createMeterBand(long rate, Long burst) {
802 return DefaultBand.builder()
803 .withRate(rate) //already Kbps
804 .burstSize(burst) // already Kbits
805 .ofType(Band.Type.DROP) // no matter
806 .build();
807 }
808
alshabib4ceaed32016-03-03 18:00:58 -0800809 private ForwardingObjective.Builder downBuilder(PortNumber uplinkPort,
810 PortNumber subscriberPort,
811 VlanId subscriberVlan,
812 VlanId deviceVlan,
Gamze Abaka641fc072018-09-04 09:16:27 +0000813 Optional<VlanId> defaultVlan,
814 MeterId meterId,
815 int techProfId) {
alshabib4ceaed32016-03-03 18:00:58 -0800816 TrafficSelector downstream = DefaultTrafficSelector.builder()
817 .matchVlanId(deviceVlan)
818 .matchInPort(uplinkPort)
819 .matchInnerVlanId(subscriberVlan)
820 .build();
821
Gamze Abaka641fc072018-09-04 09:16:27 +0000822 TrafficTreatment.Builder downstreamTreatmentBuilder = DefaultTrafficTreatment.builder()
alshabib4ceaed32016-03-03 18:00:58 -0800823 .popVlan()
824 .setVlanId(defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan)))
Gamze Abaka641fc072018-09-04 09:16:27 +0000825 .setOutput(subscriberPort);
826
827 if (meterId != null) {
828 downstreamTreatmentBuilder.meter(meterId);
829 }
830
Gamze Abakaad329652018-12-20 10:12:21 +0000831 downstreamTreatmentBuilder.writeMetadata(createMetadata(subscriberVlan, techProfId, subscriberPort), 0);
alshabib4ceaed32016-03-03 18:00:58 -0800832
833 return DefaultForwardingObjective.builder()
834 .withFlag(ForwardingObjective.Flag.VERSATILE)
835 .withPriority(1000)
836 .makePermanent()
837 .withSelector(downstream)
838 .fromApp(appId)
Gamze Abaka641fc072018-09-04 09:16:27 +0000839 .withTreatment(downstreamTreatmentBuilder.build());
alshabib4ceaed32016-03-03 18:00:58 -0800840 }
841
842 private ForwardingObjective.Builder upBuilder(PortNumber uplinkPort,
843 PortNumber subscriberPort,
844 VlanId subscriberVlan,
845 VlanId deviceVlan,
Gamze Abaka641fc072018-09-04 09:16:27 +0000846 Optional<VlanId> defaultVlan,
847 MeterId meterId,
848 int technologyProfileId) {
849
850
851 VlanId dVlan = defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan));
852
853 if (subscriberVlan.toShort() == 4096) {
854 dVlan = subscriberVlan;
855 }
856
alshabib4ceaed32016-03-03 18:00:58 -0800857 TrafficSelector upstream = DefaultTrafficSelector.builder()
Gamze Abaka641fc072018-09-04 09:16:27 +0000858 .matchVlanId(dVlan)
alshabib4ceaed32016-03-03 18:00:58 -0800859 .matchInPort(subscriberPort)
860 .build();
861
862
Gamze Abaka641fc072018-09-04 09:16:27 +0000863 TrafficTreatment.Builder upstreamTreatmentBuilder = DefaultTrafficTreatment.builder()
alshabib4ceaed32016-03-03 18:00:58 -0800864 .pushVlan()
865 .setVlanId(subscriberVlan)
866 .pushVlan()
867 .setVlanId(deviceVlan)
Gamze Abaka641fc072018-09-04 09:16:27 +0000868 .setOutput(uplinkPort);
869
870 if (meterId != null) {
871 upstreamTreatmentBuilder.meter(meterId);
872 }
873
Gamze Abakaad329652018-12-20 10:12:21 +0000874 upstreamTreatmentBuilder.writeMetadata(createMetadata(deviceVlan, technologyProfileId, uplinkPort), 0L);
alshabib4ceaed32016-03-03 18:00:58 -0800875
876 return DefaultForwardingObjective.builder()
877 .withFlag(ForwardingObjective.Flag.VERSATILE)
878 .withPriority(1000)
879 .makePermanent()
880 .withSelector(upstream)
881 .fromApp(appId)
Gamze Abaka641fc072018-09-04 09:16:27 +0000882 .withTreatment(upstreamTreatmentBuilder.build());
alshabib4ceaed32016-03-03 18:00:58 -0800883 }
Gamze Abakaad329652018-12-20 10:12:21 +0000884
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100885 private void provisionTransparentFlows(DeviceId deviceId, PortNumber uplinkPort,
886 PortNumber subscriberPort,
887 VlanId innerVlan,
888 VlanId outerVlan) {
889
890 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
891 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
892
893 ForwardingObjective.Builder upFwd = transparentUpBuilder(uplinkPort, subscriberPort,
894 innerVlan, outerVlan);
895
896
897 ForwardingObjective.Builder downFwd = transparentDownBuilder(uplinkPort, subscriberPort,
898 innerVlan, outerVlan);
899
900 ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
901
902 additionalVlans.put(cp, new AbstractMap.SimpleEntry(outerVlan, innerVlan));
903
904 flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
905 @Override
906 public void onSuccess(Objective objective) {
907 upFuture.complete(null);
908 }
909
910 @Override
911 public void onError(Objective objective, ObjectiveError error) {
912 upFuture.complete(error);
913 }
914 }));
915
916 flowObjectiveService.forward(deviceId, downFwd.add(new ObjectiveContext() {
917 @Override
918 public void onSuccess(Objective objective) {
919 downFuture.complete(null);
920 }
921
922 @Override
923 public void onError(Objective objective, ObjectiveError error) {
924 downFuture.complete(error);
925 }
926 }));
927
928 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
929 if (downStatus != null) {
930 log.error("Flow with innervlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000931 "on port {} failed downstream installation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100932 innerVlan, outerVlan, deviceId, subscriberPort, downStatus);
933 } else if (upStatus != null) {
934 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000935 "on port {} failed upstream installation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100936 innerVlan, outerVlan, deviceId, subscriberPort, upStatus);
937 }
938 }, oltInstallers);
939
940 }
941
942 private ForwardingObjective.Builder transparentDownBuilder(PortNumber uplinkPort,
943 PortNumber subscriberPort,
944 VlanId innerVlan,
945 VlanId outerVlan) {
946 TrafficSelector downstream = DefaultTrafficSelector.builder()
947 .matchVlanId(outerVlan)
948 .matchInPort(uplinkPort)
949 .matchInnerVlanId(innerVlan)
950 .build();
951
952 TrafficTreatment downstreamTreatment = DefaultTrafficTreatment.builder()
953 .setOutput(subscriberPort)
954 .build();
955
956 return DefaultForwardingObjective.builder()
957 .withFlag(ForwardingObjective.Flag.VERSATILE)
958 .withPriority(1000)
959 .makePermanent()
960 .withSelector(downstream)
961 .fromApp(appId)
962 .withTreatment(downstreamTreatment);
963 }
964
965 private ForwardingObjective.Builder transparentUpBuilder(PortNumber uplinkPort,
966 PortNumber subscriberPort,
967 VlanId innerVlan,
968 VlanId outerVlan) {
969 TrafficSelector upstream = DefaultTrafficSelector.builder()
970 .matchVlanId(outerVlan)
971 .matchInPort(subscriberPort)
972 .matchInnerVlanId(innerVlan)
973 .build();
974
975 TrafficTreatment upstreamTreatment = DefaultTrafficTreatment.builder()
976 .setOutput(uplinkPort)
977 .build();
978
979 return DefaultForwardingObjective.builder()
980 .withFlag(ForwardingObjective.Flag.VERSATILE)
981 .withPriority(1000)
982 .makePermanent()
983 .withSelector(upstream)
984 .fromApp(appId)
985 .withTreatment(upstreamTreatment);
986 }
987
988 private void unprovisionTransparentFlows(DeviceId deviceId, PortNumber uplink,
989 PortNumber subscriberPort, VlanId innerVlan,
990 VlanId outerVlan) {
991
992 ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
993
994 additionalVlans.remove(cp, new AbstractMap.SimpleEntry(outerVlan, innerVlan));
995
996 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
997 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
998
999 ForwardingObjective.Builder upFwd = transparentUpBuilder(uplink, subscriberPort,
1000 innerVlan, outerVlan);
1001 ForwardingObjective.Builder downFwd = transparentDownBuilder(uplink, subscriberPort,
1002 innerVlan, outerVlan);
1003
1004
1005 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
1006 @Override
1007 public void onSuccess(Objective objective) {
1008 upFuture.complete(null);
1009 }
1010
1011 @Override
1012 public void onError(Objective objective, ObjectiveError error) {
1013 upFuture.complete(error);
1014 }
1015 }));
1016
1017 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
1018 @Override
1019 public void onSuccess(Objective objective) {
1020 downFuture.complete(null);
1021 }
1022
1023 @Override
1024 public void onError(Objective objective, ObjectiveError error) {
1025 downFuture.complete(error);
1026 }
1027 }));
1028
1029 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
1030 if (downStatus != null) {
1031 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +00001032 "on port {} failed downstream uninstallation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001033 innerVlan, outerVlan, deviceId, subscriberPort, downStatus);
1034 } else if (upStatus != null) {
1035 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +00001036 "on port {} failed upstream uninstallation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001037 innerVlan, outerVlan, deviceId, subscriberPort, upStatus);
1038 }
1039 }, oltInstallers);
1040
1041 }
1042
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001043 private int getDefaultTechProfileId(DeviceId devId, PortNumber portNumber) {
1044 Port port = deviceService.getPort(devId, portNumber);
1045 SubscriberAndDeviceInformation info = subsService.get(port.annotations().value(AnnotationKeys.PORT_NAME));
1046 if (info != null && info.technologyProfileId() != -1) {
1047 return info.technologyProfileId();
1048 }
1049 return defaultTechProfileId;
1050 }
1051
Gamze Abaka838d8142019-02-21 07:06:55 +00001052 /**
1053 * Returns the write metadata value including only tech profile reference.
1054 *
1055 * @param techProfileId tech profile id of one subscriber
1056 * @return the write metadata value including only tech profile reference
1057 */
1058 private Long createTechProfValueForWm(int techProfileId) {
1059 return (long) techProfileId << 32;
1060 }
1061
1062 /**
1063 * Trap eapol authentication packets to the controller.
1064 *
Gamze Abaka33feef52019-02-27 08:16:47 +00001065 * @param devId the device identifier
1066 * @param portNumber the port for which this trap flow is designated
1067 * @param bpId bandwidth profile id to add the related meter to the flow
1068 * @param filterFuture completable future for this filtering objective operation
1069 * @param install true to install the flow, false to remove the flow
Gamze Abaka838d8142019-02-21 07:06:55 +00001070 */
Gamze Abaka33feef52019-02-27 08:16:47 +00001071 private void processEapolFilteringObjectives(DeviceId devId, PortNumber portNumber, String bpId,
1072 CompletableFuture<ObjectiveError> filterFuture,
1073 boolean install) {
1074
1075 if (!enableEapol) {
1076 log.debug("Eapol filtering is disabled.");
1077 if (filterFuture != null) {
1078 filterFuture.complete(null);
1079 }
1080 return;
1081 }
1082
alshabib09753b52016-03-04 14:55:19 -08001083 if (!mastershipService.isLocalMaster(devId)) {
1084 return;
1085 }
alshabibbb83aa22016-02-10 15:08:23 -08001086 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Gamze Abakaad329652018-12-20 10:12:21 +00001087 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
Gamze Abaka33feef52019-02-27 08:16:47 +00001088 CompletableFuture<Object> meterFuture = new CompletableFuture<>();
Gamze Abaka838d8142019-02-21 07:06:55 +00001089 MeterId meterId;
alshabibbb83aa22016-02-10 15:08:23 -08001090
Gamze Abaka838d8142019-02-21 07:06:55 +00001091 BandwidthProfileInformation bpInfo = getBandwidthProfileInformation(bpId);
1092 if (bpInfo != null) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001093 meterId = createMeter(devId, bpInfo, meterFuture);
Gamze Abakaad329652018-12-20 10:12:21 +00001094 treatmentBuilder.meter(meterId);
1095 } else {
Gamze Abaka838d8142019-02-21 07:06:55 +00001096 log.warn("Bandwidth profile {} is not found. Authentication flow will not be installed", bpId);
1097 return;
Gamze Abakaad329652018-12-20 10:12:21 +00001098 }
1099
Gamze Abaka33feef52019-02-27 08:16:47 +00001100 meterFuture.thenAcceptAsync(result -> {
1101 if (result == null) {
1102 log.info("Meter {} for the device {} is installed. " +
1103 "{} EAPOL trap flow", meterId, devId, install ? "Installing " : "Removing ");
1104 int techProfileId = getDefaultTechProfileId(devId, portNumber);
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001105
Gamze Abaka33feef52019-02-27 08:16:47 +00001106 //Authentication trap flow uses only tech profile id as write metadata value
1107 FilteringObjective eapol = (install ? builder.permit() : builder.deny())
1108 .withKey(Criteria.matchInPort(portNumber))
1109 .addCondition(Criteria.matchEthType(EthType.EtherType.EAPOL.ethType()))
1110 .withMeta(treatmentBuilder
1111 .writeMetadata(createTechProfValueForWm(techProfileId), 0)
1112 .setOutput(PortNumber.CONTROLLER).build())
1113 .fromApp(appId)
1114 .withPriority(10000)
1115 .add(new ObjectiveContext() {
1116 @Override
1117 public void onSuccess(Objective objective) {
1118 log.info("Eapol filter for {} on {} {} with meter {}.",
1119 devId, portNumber, (install) ? INSTALLED : REMOVED, meterId);
1120 if (filterFuture != null) {
1121 filterFuture.complete(null);
1122 }
1123 }
alshabibdec2e252016-01-15 12:20:25 -08001124
Gamze Abaka33feef52019-02-27 08:16:47 +00001125 @Override
1126 public void onError(Objective objective, ObjectiveError error) {
1127 log.info("Eapol filter for {} on {} with meter {} failed {} because {}",
1128 devId, portNumber, meterId, (install) ? INSTALLATION : REMOVAL,
1129 error);
1130 if (filterFuture != null) {
1131 filterFuture.complete(error);
1132 }
1133 }
1134 });
alshabibdec2e252016-01-15 12:20:25 -08001135
Gamze Abaka33feef52019-02-27 08:16:47 +00001136 flowObjectiveService.filter(devId, eapol);
1137 } else {
1138 log.warn("Meter installation error while sending eapol trap flow. " +
1139 "Result {} and MeterId {}", result, meterId);
1140 }
1141 });
alshabibdec2e252016-01-15 12:20:25 -08001142 }
1143
Jonathan Hart403372d2018-08-22 11:44:13 -07001144 /**
1145 * Installs trap filtering objectives for particular traffic types on an
1146 * NNI port.
1147 *
Gamze Abakaad329652018-12-20 10:12:21 +00001148 * @param devId device ID
1149 * @param port port number
Jonathan Hart403372d2018-08-22 11:44:13 -07001150 * @param install true to install, false to remove
1151 */
1152 private void processNniFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
1153 processLldpFilteringObjective(devId, port, install);
Gamze Abaka33feef52019-02-27 08:16:47 +00001154 processDhcpFilteringObjectives(devId, port, null, -1, install, false);
Jonathan Hart403372d2018-08-22 11:44:13 -07001155 }
1156
1157 private void processLldpFilteringObjective(DeviceId devId, PortNumber port, boolean install) {
1158 if (!mastershipService.isLocalMaster(devId)) {
1159 return;
1160 }
1161 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
1162
1163 FilteringObjective lldp = (install ? builder.permit() : builder.deny())
1164 .withKey(Criteria.matchInPort(port))
1165 .addCondition(Criteria.matchEthType(EthType.EtherType.LLDP.ethType()))
1166 .withMeta(DefaultTrafficTreatment.builder()
1167 .setOutput(PortNumber.CONTROLLER).build())
1168 .fromApp(appId)
1169 .withPriority(10000)
1170 .add(new ObjectiveContext() {
1171 @Override
1172 public void onSuccess(Objective objective) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001173 log.info("LLDP filter for device {} on port {} {}.",
Gamze Abaka838d8142019-02-21 07:06:55 +00001174 devId, port, (install) ? INSTALLED : REMOVED);
Jonathan Hart403372d2018-08-22 11:44:13 -07001175 }
1176
1177 @Override
1178 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001179 log.info("LLDP filter for device {} on port {} failed {} because {}",
Gamze Abaka838d8142019-02-21 07:06:55 +00001180 devId, port, (install) ? INSTALLATION : REMOVAL,
Saurav Das82b8e6d2018-10-04 15:25:12 -07001181 error);
Jonathan Hart403372d2018-08-22 11:44:13 -07001182 }
1183 });
1184
1185 flowObjectiveService.filter(devId, lldp);
1186
1187 }
1188
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001189 /**
1190 * Trap dhcp packets to the controller.
1191 *
Gamze Abaka838d8142019-02-21 07:06:55 +00001192 * @param devId the device identifier
1193 * @param port the port for which this trap flow is designated
1194 * @param upstreamMeterId the upstream meter id that includes the upstream
1195 * bandwidth profile values such as PIR,CIR. If no meter id needs to be referenced,
1196 * null can be sent
1197 * @param techProfileId the technology profile id that is used to create write
1198 * metadata instruction value. If no tech profile id needs to be referenced,
1199 * -1 can be sent
1200 * @param install true to install the flow, false to remove the flow
1201 * @param upstream true if trapped packets are flowing upstream towards
1202 * server, false if packets are flowing downstream towards client
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001203 */
1204 private void processDhcpFilteringObjectives(DeviceId devId, PortNumber port,
Gamze Abaka838d8142019-02-21 07:06:55 +00001205 MeterId upstreamMeterId,
1206 int techProfileId,
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001207 boolean install,
1208 boolean upstream) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001209
1210 if (!enableDhcpOnProvisioning) {
1211 log.debug("Dhcp provisioning is disabled.");
1212 return;
1213 }
1214
Amit Ghosh95e2f652017-08-23 12:49:46 +01001215 if (!mastershipService.isLocalMaster(devId)) {
1216 return;
1217 }
Amit Ghosh95e2f652017-08-23 12:49:46 +01001218
Matteo Scandolo63460d12018-11-02 16:19:04 -07001219 if (enableDhcpV4) {
1220 int udpSrc = (upstream) ? 68 : 67;
1221 int udpDst = (upstream) ? 67 : 68;
1222
1223 EthType ethType = EthType.EtherType.IPV4.ethType();
1224 byte protocol = IPv4.PROTOCOL_UDP;
1225
Gamze Abaka838d8142019-02-21 07:06:55 +00001226 this.addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType,
1227 upstreamMeterId, techProfileId, protocol, install);
Matteo Scandolo63460d12018-11-02 16:19:04 -07001228 }
1229
1230 if (enableDhcpV6) {
1231 int udpSrc = (upstream) ? 547 : 546;
1232 int udpDst = (upstream) ? 546 : 547;
1233
1234 EthType ethType = EthType.EtherType.IPV6.ethType();
1235 byte protocol = IPv6.PROTOCOL_UDP;
1236
Gamze Abaka838d8142019-02-21 07:06:55 +00001237 this.addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType,
1238 upstreamMeterId, techProfileId, protocol, install);
Matteo Scandolo63460d12018-11-02 16:19:04 -07001239 }
1240
1241 }
1242
1243 private void addDhcpFilteringObjectives(DeviceId devId,
1244 PortNumber port,
1245 int udpSrc,
1246 int udpDst,
1247 EthType ethType,
Gamze Abaka838d8142019-02-21 07:06:55 +00001248 MeterId upstreamMeterId,
1249 int techProfileId,
Matteo Scandolo63460d12018-11-02 16:19:04 -07001250 byte protocol,
1251 boolean install) {
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001252
1253 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Gamze Abaka838d8142019-02-21 07:06:55 +00001254 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
1255
1256 if (upstreamMeterId != null) {
1257 treatmentBuilder.meter(upstreamMeterId);
1258 }
1259
1260 if (techProfileId != -1) {
1261 treatmentBuilder.writeMetadata(createTechProfValueForWm(techProfileId), 0);
1262 }
1263
Amit Ghosh95e2f652017-08-23 12:49:46 +01001264 FilteringObjective dhcpUpstream = (install ? builder.permit() : builder.deny())
1265 .withKey(Criteria.matchInPort(port))
Matteo Scandolo63460d12018-11-02 16:19:04 -07001266 .addCondition(Criteria.matchEthType(ethType))
1267 .addCondition(Criteria.matchIPProtocol(protocol))
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001268 .addCondition(Criteria.matchUdpSrc(TpPort.tpPort(udpSrc)))
1269 .addCondition(Criteria.matchUdpDst(TpPort.tpPort(udpDst)))
Gamze Abaka838d8142019-02-21 07:06:55 +00001270 .withMeta(treatmentBuilder
Gamze Abaka641fc072018-09-04 09:16:27 +00001271 .setOutput(PortNumber.CONTROLLER).build())
Amit Ghosh95e2f652017-08-23 12:49:46 +01001272 .fromApp(appId)
Matt Jeanneret3f579262018-06-14 17:16:23 -04001273 .withPriority(10000)
Amit Ghosh95e2f652017-08-23 12:49:46 +01001274 .add(new ObjectiveContext() {
1275 @Override
1276 public void onSuccess(Objective objective) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001277 log.info("DHCP {} filter for device {} on port {} {}.",
Gamze Abakaad329652018-12-20 10:12:21 +00001278 (ethType.equals(EthType.EtherType.IPV4.ethType())) ? "v4" : "v6",
Gamze Abaka838d8142019-02-21 07:06:55 +00001279 devId, port, (install) ? INSTALLED : REMOVED);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001280 }
1281
1282 @Override
1283 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001284 log.info("DHCP {} filter for device {} on port {} failed {} because {}",
Gamze Abakaad329652018-12-20 10:12:21 +00001285 (ethType.equals(EthType.EtherType.IPV4.ethType())) ? "v4" : "v6",
Gamze Abaka838d8142019-02-21 07:06:55 +00001286 devId, port, (install) ? INSTALLATION : REMOVAL,
Gamze Abakaad329652018-12-20 10:12:21 +00001287 error);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001288 }
1289 });
1290
1291 flowObjectiveService.filter(devId, dhcpUpstream);
1292 }
1293
Gamze Abaka838d8142019-02-21 07:06:55 +00001294 private void processIgmpFilteringObjectives(DeviceId devId, PortNumber port,
1295 MeterId upstreamMeterId,
1296 int techProfileId,
1297 boolean install) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001298
1299 if (enableIgmpOnProvisioning) {
1300 log.debug("Igmp provisioning is disabled.");
1301 return;
1302 }
1303
Amit Ghosh95e2f652017-08-23 12:49:46 +01001304 if (!mastershipService.isLocalMaster(devId)) {
1305 return;
1306 }
1307
Gamze Abaka641fc072018-09-04 09:16:27 +00001308 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Gamze Abaka838d8142019-02-21 07:06:55 +00001309 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
1310
1311 if (upstreamMeterId != null) {
1312 treatmentBuilder.meter(upstreamMeterId);
1313 }
1314
1315 if (techProfileId != -1) {
1316 treatmentBuilder.writeMetadata(createTechProfValueForWm(techProfileId), 0);
1317 }
Amit Ghosh95e2f652017-08-23 12:49:46 +01001318
1319 builder = install ? builder.permit() : builder.deny();
1320
1321 FilteringObjective igmp = builder
1322 .withKey(Criteria.matchInPort(port))
1323 .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
1324 .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_IGMP))
Gamze Abaka838d8142019-02-21 07:06:55 +00001325 .withMeta(treatmentBuilder
Gamze Abaka641fc072018-09-04 09:16:27 +00001326 .setOutput(PortNumber.CONTROLLER).build())
Amit Ghosh95e2f652017-08-23 12:49:46 +01001327 .fromApp(appId)
1328 .withPriority(10000)
1329 .add(new ObjectiveContext() {
1330 @Override
1331 public void onSuccess(Objective objective) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001332 log.info("Igmp filter for {} on {} {}.",
Gamze Abaka838d8142019-02-21 07:06:55 +00001333 devId, port, (install) ? INSTALLED : REMOVED);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001334 }
1335
1336 @Override
1337 public void onError(Objective objective, ObjectiveError error) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001338 log.info("Igmp filter for {} on {} failed {} because {}.",
Gamze Abaka838d8142019-02-21 07:06:55 +00001339 devId, port, (install) ? INSTALLATION : REMOVAL,
Gamze Abaka641fc072018-09-04 09:16:27 +00001340 error);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001341 }
1342 });
1343
1344 flowObjectiveService.filter(devId, igmp);
1345 }
1346
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001347 /**
Jonathan Hart403372d2018-08-22 11:44:13 -07001348 * Creates trap flows for device, including DHCP and LLDP trap on NNI and
1349 * EAPOL trap on the UNIs, if device is present in Sadis config.
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001350 *
1351 * @param dev Device to look for
1352 */
Jonathan Hart403372d2018-08-22 11:44:13 -07001353 private void checkAndCreateDeviceFlows(Device dev) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001354 // we create only for the ones we are master of
1355 if (!mastershipService.isLocalMaster(dev.id())) {
Gamze Abaka641fc072018-09-04 09:16:27 +00001356 return;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001357 }
1358 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +00001359 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Jonathan Hart403372d2018-08-22 11:44:13 -07001360 log.debug("checkAndCreateDeviceFlows: deviceInfo {}", deviceInfo);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001361
1362 if (deviceInfo != null) {
Jonathan Hart403372d2018-08-22 11:44:13 -07001363 // This is an OLT device as per Sadis, we create flows for UNI and NNI ports
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001364 for (Port p : deviceService.getPorts(dev.id())) {
1365 if (isUniPort(dev, p)) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001366 processEapolFilteringObjectives(dev.id(), p.number(), defaultBpId, null, true);
Jonathan Hart403372d2018-08-22 11:44:13 -07001367 } else {
1368 processNniFilteringObjectives(dev.id(), p.number(), true);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001369 }
1370 }
1371 }
1372 }
1373
Jonathan Hart403372d2018-08-22 11:44:13 -07001374
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001375 /**
1376 * Get the uplink for of the OLT device.
Gamze Abakaad329652018-12-20 10:12:21 +00001377 * <p>
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001378 * This assumes that the OLT has a single uplink port. When more uplink ports need to be supported
1379 * this logic needs to be changed
1380 *
1381 * @param dev Device to look for
1382 * @return The uplink Port of the OLT
1383 */
1384 private Port getUplinkPort(Device dev) {
1385 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +00001386 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001387 log.debug("getUplinkPort: deviceInfo {}", deviceInfo);
Saurav Das82b8e6d2018-10-04 15:25:12 -07001388 if (deviceInfo == null) {
1389 log.warn("Device {} is not configured in SADIS .. cannot fetch device"
1390 + " info", dev.id());
1391 return null;
1392 }
1393 // Return the port that has been configured as the uplink port of this OLT in Sadis
Gamze Abakaad329652018-12-20 10:12:21 +00001394 for (Port p : deviceService.getPorts(dev.id())) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001395 if (p.number().toLong() == deviceInfo.uplinkPort()) {
1396 log.debug("getUplinkPort: Found port {}", p);
1397 return p;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001398 }
1399 }
1400
Gamze Abaka838d8142019-02-21 07:06:55 +00001401 log.debug("getUplinkPort: " + NO_UPLINK_PORT, dev.id());
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001402 return null;
1403 }
1404
1405 /**
1406 * Return the subscriber on a port.
1407 *
Matteo Scandolo962a6ad2018-12-11 15:39:42 -08001408 * @param cp ConnectPoint on which to find the subscriber
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001409 * @return subscriber if found else null
1410 */
Matteo Scandolo962a6ad2018-12-11 15:39:42 -08001411 SubscriberAndDeviceInformation getSubscriber(ConnectPoint cp) {
1412 Port port = deviceService.getPort(cp);
1413 checkNotNull(port, "Invalid connect point");
1414 String portName = port.annotations().value(AnnotationKeys.PORT_NAME);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001415 return subsService.get(portName);
1416 }
1417
Gamze Abakaad329652018-12-20 10:12:21 +00001418 /**
1419 * Write metadata instruction value (metadata) is 8 bytes.
Gamze Abaka838d8142019-02-21 07:06:55 +00001420 * <p>
Gamze Abakaad329652018-12-20 10:12:21 +00001421 * MS 2 bytes: C Tag
1422 * Next 2 bytes: Technology Profile Id
1423 * Next 4 bytes: Port number (uni or nni)
1424 */
1425
1426 private Long createMetadata(VlanId innerVlan, int techProfileId, PortNumber egressPort) {
1427
1428 if (techProfileId == -1) {
1429 techProfileId = DEFAULT_TP_ID;
1430 }
1431
1432 return ((long) (innerVlan.id()) << 48 | (long) techProfileId << 32) | egressPort.toLong();
1433 }
1434
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001435 private boolean isUniPort(Device d, Port p) {
1436 Port ulPort = getUplinkPort(d);
1437 if (ulPort != null) {
1438 return (ulPort.number().toLong() != p.number().toLong());
1439 }
1440 return false;
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001441 }
1442
Jonathan Hart4c538002018-08-23 10:11:54 -07001443 private SubscriberAndDeviceInformation getOltInfo(Device dev) {
1444 String devSerialNo = dev.serialNumber();
Gamze Abaka641fc072018-09-04 09:16:27 +00001445 return subsService.get(devSerialNo);
Jonathan Hart4c538002018-08-23 10:11:54 -07001446 }
1447
Gamze Abaka33feef52019-02-27 08:16:47 +00001448 private MeterId getMeterIdFromBpMapping(DeviceId deviceId, String bandwidthProfile) {
1449
1450 if (bpInfoToMeter.get(bandwidthProfile) == null) {
1451 log.warn("Bandwidth Profile '{}' is not found in bandwidth profile map.", bandwidthProfile);
1452 return null;
1453 }
1454
1455 Optional<MeterKey> meterKeyForDevice = bpInfoToMeter.get(bandwidthProfile)
1456 .stream()
1457 .filter(meterKey -> meterKey.deviceId().equals(deviceId))
1458 .findFirst();
1459 return meterKeyForDevice.isPresent() ? meterKeyForDevice.get().meterId() : null;
1460 }
1461
1462 private void addMeterIdToBpMapping(DeviceId deviceId, MeterId meterId, String bandwidthProfile) {
1463
1464 if (bpInfoToMeter.get(bandwidthProfile) == null) {
1465 bpInfoToMeter.put(bandwidthProfile,
1466 new ArrayList<>(Arrays.asList(MeterKey.key(deviceId, meterId))));
1467 } else {
1468
1469 List<MeterKey> meterKeyListForBp = bpInfoToMeter.get(bandwidthProfile);
1470 meterKeyListForBp.add(MeterKey.key(deviceId, meterId));
1471 }
1472 }
1473
1474 private void removeMeterIdFromBpMapping(DeviceId deviceId, String bandwidthProfileId) {
1475 List<MeterKey> meterKeysForBp = bpInfoToMeter.get(bandwidthProfileId);
1476 if (meterKeysForBp != null) {
1477 meterKeysForBp.stream()
1478 .filter(meterKey -> meterKey.deviceId().equals(deviceId))
1479 .findFirst().ifPresent(mk -> {
1480 meterKeysForBp.remove(mk);
1481 programmedMeters.remove(mk);
1482 });
1483 }
1484 }
1485
alshabibf0e7e702015-05-30 18:22:36 -07001486 private class InternalDeviceListener implements DeviceListener {
Saurav Dasa9d5f442019-03-06 19:32:48 -08001487 private Set<DeviceId> programmedDevices = Sets.newConcurrentHashSet();
1488
alshabibf0e7e702015-05-30 18:22:36 -07001489 @Override
1490 public void event(DeviceEvent event) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001491 eventExecutor.execute(() -> {
1492 DeviceId devId = event.subject().id();
1493 Device dev = event.subject();
Gamze Abaka838d8142019-02-21 07:06:55 +00001494 Port port = event.port();
Jonathan Hart4c538002018-08-23 10:11:54 -07001495
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001496 if (event.type() == DeviceEvent.Type.PORT_STATS_UPDATED) {
1497 return;
1498 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001499
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001500 if (getOltInfo(dev) == null) {
Saurav Dasa9d5f442019-03-06 19:32:48 -08001501 // it's possible that we got an event for a previously
1502 // programmed OLT that is no longer available in SADIS
1503 // we let such events go through
1504 if (!programmedDevices.contains(devId)) {
1505 log.warn("No device info found for {}, this is either "
1506 + "not an OLT or not known to sadis", dev);
1507 return;
1508 }
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001509 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001510
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001511 log.debug("OLT got {} event for {}", event.type(), event.subject());
Jonathan Hart4c538002018-08-23 10:11:54 -07001512
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001513 switch (event.type()) {
1514 //TODO: Port handling and bookkeeping should be improved once
1515 // olt firmware handles correct behaviour.
1516 case PORT_ADDED:
Gamze Abaka838d8142019-02-21 07:06:55 +00001517 if (isUniPort(dev, port)) {
1518 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, port));
Jonathan Hart4c538002018-08-23 10:11:54 -07001519
Gamze Abaka838d8142019-02-21 07:06:55 +00001520 if (port.isEnabled()) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001521 processEapolFilteringObjectives(devId, port.number(), defaultBpId,
1522 null, true);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001523 }
1524 } else {
1525 checkAndCreateDeviceFlows(dev);
1526 }
1527 break;
1528 case PORT_REMOVED:
Gamze Abaka838d8142019-02-21 07:06:55 +00001529 if (isUniPort(dev, port)) {
1530 if (port.isEnabled()) {
1531 processEapolFilteringObjectives(devId, port.number(),
1532 getCurrentBandwidthProfile(new ConnectPoint(devId, port.number())),
Gamze Abaka33feef52019-02-27 08:16:47 +00001533 null, false);
1534
Gamze Abaka838d8142019-02-21 07:06:55 +00001535 removeSubscriber(new ConnectPoint(devId, port.number()));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001536 }
1537
Gamze Abaka838d8142019-02-21 07:06:55 +00001538 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, port));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001539 }
1540
1541 break;
1542 case PORT_UPDATED:
Gamze Abaka838d8142019-02-21 07:06:55 +00001543 if (!isUniPort(dev, port)) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001544 break;
1545 }
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001546
Gamze Abaka838d8142019-02-21 07:06:55 +00001547 if (port.isEnabled()) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001548 processEapolFilteringObjectives(devId, port.number(), defaultBpId,
1549 null, true);
1550
Gamze Abaka838d8142019-02-21 07:06:55 +00001551 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, port));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001552 } else {
Gamze Abaka838d8142019-02-21 07:06:55 +00001553 processEapolFilteringObjectives(devId, port.number(),
1554 getCurrentBandwidthProfile(new ConnectPoint(devId, port.number())),
Gamze Abaka33feef52019-02-27 08:16:47 +00001555 null, false);
Gamze Abaka838d8142019-02-21 07:06:55 +00001556 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, port));
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001557 }
alshabibbb83aa22016-02-10 15:08:23 -08001558 break;
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001559 case DEVICE_ADDED:
alshabib7c190012016-02-09 18:22:33 -08001560 post(new AccessDeviceEvent(
1561 AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
1562 null, null));
Saurav Dasa9d5f442019-03-06 19:32:48 -08001563 programmedDevices.add(devId);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001564 // Send UNI_ADDED events for all existing ports
1565 deviceService.getPorts(devId).stream()
1566 .filter(p -> isUniPort(dev, p))
1567 .filter(Port::isEnabled)
1568 .forEach(p -> post(new AccessDeviceEvent(
1569 AccessDeviceEvent.Type.UNI_ADDED, devId, p)));
1570
Jonathan Hart403372d2018-08-22 11:44:13 -07001571 checkAndCreateDeviceFlows(dev);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001572 break;
1573 case DEVICE_REMOVED:
1574 deviceService.getPorts(devId).stream()
1575 .filter(p -> isUniPort(dev, p))
1576 .forEach(p -> post(new AccessDeviceEvent(
1577 AccessDeviceEvent.Type.UNI_REMOVED, devId, p)));
Saurav Dasa9d5f442019-03-06 19:32:48 -08001578 programmedDevices.remove(devId);
alshabib7c190012016-02-09 18:22:33 -08001579 post(new AccessDeviceEvent(
1580 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
1581 null, null));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001582 break;
1583 case DEVICE_AVAILABILITY_CHANGED:
1584 if (deviceService.isAvailable(devId)) {
1585 post(new AccessDeviceEvent(
1586 AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
1587 null, null));
Saurav Dasa9d5f442019-03-06 19:32:48 -08001588 programmedDevices.add(devId);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001589 checkAndCreateDeviceFlows(dev);
1590 } else {
Saurav Dasa9d5f442019-03-06 19:32:48 -08001591 programmedDevices.remove(devId);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001592 post(new AccessDeviceEvent(
1593 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
1594 null, null));
1595 }
1596 break;
1597 case DEVICE_UPDATED:
1598 case DEVICE_SUSPENDED:
1599 case PORT_STATS_UPDATED:
1600 default:
1601 return;
1602 }
1603 });
alshabibf0e7e702015-05-30 18:22:36 -07001604 }
Gamze Abaka838d8142019-02-21 07:06:55 +00001605
1606 private String getCurrentBandwidthProfile(ConnectPoint connectPoint) {
1607 SubscriberAndDeviceInformation sub = programmedSubs.get(connectPoint);
1608 if (sub != null) {
1609 return sub.upstreamBandwidthProfile();
1610 }
1611 return defaultBpId;
1612 }
alshabibf0e7e702015-05-30 18:22:36 -07001613 }
Gamze Abaka641fc072018-09-04 09:16:27 +00001614
1615 private class InternalMeterListener implements MeterListener {
1616
1617 @Override
1618 public void event(MeterEvent meterEvent) {
1619 if (deleteMeters && MeterEvent.Type.METER_REFERENCE_COUNT_ZERO.equals(meterEvent.type())) {
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001620 log.info("Zero Count Meter Event is received. Meter is {}", meterEvent.subject());
Gamze Abaka641fc072018-09-04 09:16:27 +00001621 Meter meter = meterEvent.subject();
Gamze Abaka33feef52019-02-27 08:16:47 +00001622 if (meter != null && appId.equals(meter.appId()) &&
1623 !programmedMeters.contains(MeterKey.key(meter.deviceId(), meter.id()))) {
Gamze Abaka641fc072018-09-04 09:16:27 +00001624 deleteMeter(meter.deviceId(), meter.id());
1625 }
1626 } else if (MeterEvent.Type.METER_REMOVED.equals(meterEvent.type())) {
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001627 log.info("Meter removed event is received. Meter is {}", meterEvent.subject());
Gamze Abaka641fc072018-09-04 09:16:27 +00001628 removeMeterFromBpMap(meterEvent.subject());
1629 }
1630 }
1631
1632 private void deleteMeter(DeviceId deviceId, MeterId meterId) {
1633 Meter meter = meterService.getMeter(deviceId, meterId);
Gamze Abaka838d8142019-02-21 07:06:55 +00001634 if (meter != null) {
1635 MeterRequest meterRequest = DefaultMeterRequest.builder()
1636 .withBands(meter.bands())
1637 .withUnit(meter.unit())
1638 .forDevice(deviceId)
1639 .fromApp(appId)
1640 .burst()
1641 .remove();
Gamze Abaka641fc072018-09-04 09:16:27 +00001642
Gamze Abaka838d8142019-02-21 07:06:55 +00001643 meterService.withdraw(meterRequest, meterId);
1644 }
Gamze Abaka641fc072018-09-04 09:16:27 +00001645 }
1646
1647 private void removeMeterFromBpMap(Meter meter) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001648 bpInfoToMeter.values().forEach(meterKeys -> meterKeys.stream()
1649 .filter(meterKey -> (meterKey.deviceId().equals(meter.deviceId()))
1650 && meterKey.meterId().equals(meter.id())).findFirst().
1651 ifPresent(mk -> {
1652 meterKeys.remove(mk);
1653 log.info("Deleted from the internal map. MeterKey {}", mk);
1654 log.info("Programmed meters {}", programmedMeters);
1655 }));
Gamze Abaka641fc072018-09-04 09:16:27 +00001656 }
1657 }
1658}