blob: 8a89477e4da36c294b882d822416c00d3726d2d2 [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;
alshabibf0e7e702015-05-30 18:22:36 -0700111
112/**
Jonathan Harte533a422015-10-20 17:31:24 -0700113 * Provisions rules on access devices.
alshabibf0e7e702015-05-30 18:22:36 -0700114 */
Jonathan Harte533a422015-10-20 17:31:24 -0700115@Service
alshabibf0e7e702015-05-30 18:22:36 -0700116@Component(immediate = true)
alshabib8e4fd2f2016-01-12 15:55:53 -0800117public class Olt
118 extends AbstractListenerManager<AccessDeviceEvent, AccessDeviceListener>
119 implements AccessDeviceService {
Charles Chan54f110f2017-01-20 11:22:42 -0800120 private static final String APP_NAME = "org.opencord.olt";
alshabibe0559672016-02-21 14:49:51 -0800121
122 private static final short DEFAULT_VLAN = 0;
Gamze Abaka1efc80c2019-02-15 12:10:54 +0000123 private static final int DEFAULT_TP_ID = 64;
Gamze Abakaad329652018-12-20 10:12:21 +0000124 private static final String DEFAULT_BP_ID = "Default";
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100125 private static final String ADDITIONAL_VLANS = "additional-vlans";
Gamze Abaka838d8142019-02-21 07:06:55 +0000126 private static final String NO_UPLINK_PORT = "No uplink port found for OLT device {}";
127 private static final String INSTALLED = "installed";
128 private static final String REMOVED = "removed";
129 private static final String INSTALLATION = "installation";
130 private static final String REMOVAL = "removal";
alshabibe0559672016-02-21 14:49:51 -0800131
alshabibf0e7e702015-05-30 18:22:36 -0700132 private final Logger log = getLogger(getClass());
133
134 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
135 protected FlowObjectiveService flowObjectiveService;
136
137 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabib09753b52016-03-04 14:55:19 -0800138 protected MastershipService mastershipService;
139
140 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibf0e7e702015-05-30 18:22:36 -0700141 protected DeviceService deviceService;
142
143 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
144 protected CoreService coreService;
145
Jonathan Harte533a422015-10-20 17:31:24 -0700146 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibe0559672016-02-21 14:49:51 -0800147 protected ComponentConfigService componentConfigService;
148
alshabib4ceaed32016-03-03 18:00:58 -0800149 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Gamze Abaka641fc072018-09-04 09:16:27 +0000150 protected SadisService sadisService;
151
152 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
153 protected MeterService meterService;
alshabibe0559672016-02-21 14:49:51 -0800154
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100155 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
156 protected StorageService storageService;
157
alshabibe0559672016-02-21 14:49:51 -0800158 @Property(name = "defaultVlan", intValue = DEFAULT_VLAN,
159 label = "Default VLAN RG<->ONU traffic")
160 private int defaultVlan = DEFAULT_VLAN;
161
Matt Jeanneret3f579262018-06-14 17:16:23 -0400162 @Property(name = "enableDhcpOnProvisioning", boolValue = true,
163 label = "Create the DHCP Flow rules when a subscriber is provisioned")
164 protected boolean enableDhcpOnProvisioning = false;
165
Matteo Scandolo63460d12018-11-02 16:19:04 -0700166 @Property(name = "enableDhcpV4", boolValue = true,
167 label = "Enable flows for DHCP v4")
168 protected boolean enableDhcpV4 = true;
169
170 @Property(name = "enableDhcpV6", boolValue = true,
171 label = "Enable flows for DHCP v6")
172 protected boolean enableDhcpV6 = false;
173
Matt Jeanneret3f579262018-06-14 17:16:23 -0400174 @Property(name = "enableIgmpOnProvisioning", boolValue = false,
175 label = "Create IGMP Flow rules when a subscriber is provisioned")
176 protected boolean enableIgmpOnProvisioning = false;
Amit Ghosh95e2f652017-08-23 12:49:46 +0100177
Gamze Abaka1efc80c2019-02-15 12:10:54 +0000178 @Property(name = "deleteMeters", boolValue = true,
Gamze Abaka641fc072018-09-04 09:16:27 +0000179 label = "Deleting Meters based on flow count statistics")
Gamze Abaka1efc80c2019-02-15 12:10:54 +0000180 protected boolean deleteMeters = true;
Gamze Abaka641fc072018-09-04 09:16:27 +0000181
Gamze Abakaad329652018-12-20 10:12:21 +0000182 @Property(name = "defaultTechProfileId", intValue = DEFAULT_TP_ID,
183 label = "Default technology profile id that is used for authentication trap flows")
184 protected int defaultTechProfileId = DEFAULT_TP_ID;
185
186 @Property(name = "defaultBpId", value = DEFAULT_BP_ID,
187 label = "Default bandwidth profile id that is used for authentication trap flows")
188 protected String defaultBpId = DEFAULT_BP_ID;
189
Gamze Abaka33feef52019-02-27 08:16:47 +0000190 @Property(name = "enableEapol", boolValue = true,
191 label = "Send EAPOL authentication trap flows before subscriber provisioning")
192 protected boolean enableEapol = true;
193
alshabibf0e7e702015-05-30 18:22:36 -0700194 private final DeviceListener deviceListener = new InternalDeviceListener();
Gamze Abaka641fc072018-09-04 09:16:27 +0000195 private final MeterListener meterListener = new InternalMeterListener();
alshabibf0e7e702015-05-30 18:22:36 -0700196
197 private ApplicationId appId;
Gamze Abaka641fc072018-09-04 09:16:27 +0000198 protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
199 private BaseInformationService<BandwidthProfileInformation> bpService;
alshabibf0e7e702015-05-30 18:22:36 -0700200
Gamze Abaka33feef52019-02-27 08:16:47 +0000201 private Map<String, List<MeterKey>> bpInfoToMeter = new ConcurrentHashMap<>();
Gamze Abaka641fc072018-09-04 09:16:27 +0000202
203 private ExecutorService oltInstallers = Executors.newFixedThreadPool(4,
204 groupedThreads("onos/olt-service",
205 "olt-installer-%d"));
alshabibf0e7e702015-05-30 18:22:36 -0700206
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100207 private ConsistentMultimap<ConnectPoint, Map.Entry<VlanId, VlanId>> additionalVlans;
208
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700209 protected ExecutorService eventExecutor;
210
Saurav Das82b8e6d2018-10-04 15:25:12 -0700211 private Map<ConnectPoint, SubscriberAndDeviceInformation> programmedSubs;
Gamze Abaka33feef52019-02-27 08:16:47 +0000212 private Set<MeterKey> programmedMeters;
Saurav Das82b8e6d2018-10-04 15:25:12 -0700213
alshabibf0e7e702015-05-30 18:22:36 -0700214 @Activate
alshabibe0559672016-02-21 14:49:51 -0800215 public void activate(ComponentContext context) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700216 eventExecutor = newSingleThreadScheduledExecutor(groupedThreads("onos/olt", "events-%d", log));
alshabibe0559672016-02-21 14:49:51 -0800217 modified(context);
Charles Chan54f110f2017-01-20 11:22:42 -0800218 appId = coreService.registerApplication(APP_NAME);
Saurav Das62ad75e2019-03-05 12:22:22 -0800219
220 // ensure that flow rules are purged from flow-store upon olt-disconnection
221 // when olt reconnects, the port-numbers may change for the ONUs
222 // making flows pushed earlier invalid
223 componentConfigService
224 .preSetProperty("org.onosproject.net.flow.impl.FlowRuleManager",
Gamze Abaka33feef52019-02-27 08:16:47 +0000225 "purgeOnDisconnection", "true");
alshabibe0559672016-02-21 14:49:51 -0800226 componentConfigService.registerProperties(getClass());
Saurav Das82b8e6d2018-10-04 15:25:12 -0700227 programmedSubs = Maps.newConcurrentMap();
Gamze Abaka33feef52019-02-27 08:16:47 +0000228 programmedMeters = ConcurrentHashMap.newKeySet();
alshabibc4dfe852015-06-05 13:35:13 -0700229
alshabib8e4fd2f2016-01-12 15:55:53 -0800230 eventDispatcher.addSink(AccessDeviceEvent.class, listenerRegistry);
231
Gamze Abaka641fc072018-09-04 09:16:27 +0000232 subsService = sadisService.getSubscriberInfoService();
233 bpService = sadisService.getBandwidthProfileService();
234
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100235 // look for all provisioned devices in Sadis and create EAPOL flows for the
236 // UNI ports
237 Iterable<Device> devices = deviceService.getDevices();
238 for (Device d : devices) {
Jonathan Hart403372d2018-08-22 11:44:13 -0700239 checkAndCreateDeviceFlows(d);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100240 }
alshabib4ceaed32016-03-03 18:00:58 -0800241
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100242 additionalVlans = storageService.<ConnectPoint, Map.Entry<VlanId, VlanId>>consistentMultimapBuilder()
243 .withName(ADDITIONAL_VLANS)
244 .withSerializer(Serializer.using(Arrays.asList(KryoNamespaces.API),
245 AbstractMap.SimpleEntry.class))
246 .build();
247
alshabibba357492016-01-27 13:49:46 -0800248 deviceService.addListener(deviceListener);
Gamze Abaka641fc072018-09-04 09:16:27 +0000249 meterService.addListener(meterListener);
alshabibba357492016-01-27 13:49:46 -0800250
alshabibf0e7e702015-05-30 18:22:36 -0700251 log.info("Started with Application ID {}", appId.id());
252 }
253
254 @Deactivate
255 public void deactivate() {
alshabibe0559672016-02-21 14:49:51 -0800256 componentConfigService.unregisterProperties(getClass(), false);
alshabib62e9ce72016-02-11 17:31:36 -0800257 deviceService.removeListener(deviceListener);
Gamze Abaka641fc072018-09-04 09:16:27 +0000258 meterService.removeListener(meterListener);
Jonathan Hart5f1c8142018-07-24 17:31:59 -0700259 eventDispatcher.removeSink(AccessDeviceEvent.class);
alshabibf0e7e702015-05-30 18:22:36 -0700260 log.info("Stopped");
261 }
262
alshabibe0559672016-02-21 14:49:51 -0800263 @Modified
264 public void modified(ComponentContext context) {
265 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
266
267 try {
268 String s = get(properties, "defaultVlan");
269 defaultVlan = isNullOrEmpty(s) ? DEFAULT_VLAN : Integer.parseInt(s.trim());
Amit Ghosh95e2f652017-08-23 12:49:46 +0100270
Matt Jeanneret3f579262018-06-14 17:16:23 -0400271 Boolean o = Tools.isPropertyEnabled(properties, "enableDhcpOnProvisioning");
Amit Ghosh95e2f652017-08-23 12:49:46 +0100272 if (o != null) {
Matt Jeanneret3f579262018-06-14 17:16:23 -0400273 enableDhcpOnProvisioning = o;
Amit Ghosh95e2f652017-08-23 12:49:46 +0100274 }
Matt Jeanneret3f579262018-06-14 17:16:23 -0400275
Matteo Scandolo63460d12018-11-02 16:19:04 -0700276 Boolean v4 = Tools.isPropertyEnabled(properties, "enableDhcpV4");
277 if (v4 != null) {
278 enableDhcpV4 = v4;
279 }
280
281 Boolean v6 = Tools.isPropertyEnabled(properties, "enableDhcpV6");
282 if (v6 != null) {
283 enableDhcpV6 = v6;
284 }
285
Matt Jeanneret3f579262018-06-14 17:16:23 -0400286 Boolean p = Tools.isPropertyEnabled(properties, "enableIgmpOnProvisioning");
287 if (p != null) {
288 enableIgmpOnProvisioning = p;
289 }
290
Matteo Scandolo63460d12018-11-02 16:19:04 -0700291 log.info("DHCP Settings [enableDhcpOnProvisioning: {}, enableDhcpV4: {}, enableDhcpV6: {}]",
Gamze Abakaad329652018-12-20 10:12:21 +0000292 enableDhcpOnProvisioning, enableDhcpV4, enableDhcpV6);
Matteo Scandolo63460d12018-11-02 16:19:04 -0700293
Gamze Abaka641fc072018-09-04 09:16:27 +0000294 Boolean d = Tools.isPropertyEnabled(properties, "deleteMeters");
295 if (d != null) {
296 deleteMeters = d;
297 }
298
Gamze Abakaad329652018-12-20 10:12:21 +0000299 String tpId = get(properties, "defaultTechProfileId");
300 defaultTechProfileId = isNullOrEmpty(s) ? DEFAULT_TP_ID : Integer.parseInt(tpId.trim());
301
302 String bpId = get(properties, "defaultBpId");
303 defaultBpId = bpId;
304
Gamze Abaka33feef52019-02-27 08:16:47 +0000305 Boolean eap = Tools.isPropertyEnabled(properties, "enableEapol");
306 if (eap != null) {
307 enableEapol = eap;
308 }
309
alshabibe0559672016-02-21 14:49:51 -0800310 } catch (Exception e) {
311 defaultVlan = DEFAULT_VLAN;
312 }
313 }
314
alshabib32232c82016-02-25 17:57:24 -0500315 @Override
Gamze Abaka838d8142019-02-21 07:06:55 +0000316 public boolean provisionSubscriber(ConnectPoint connectPoint) {
317
318 DeviceId deviceId = connectPoint.deviceId();
319 PortNumber subscriberPortNo = connectPoint.port();
320
321 checkNotNull(deviceService.getPort(deviceId, subscriberPortNo),
Jonathan Hart94b90492018-04-24 14:02:25 -0700322 "Invalid connect point");
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100323 // Find the subscriber on this connect point
Gamze Abaka838d8142019-02-21 07:06:55 +0000324 SubscriberAndDeviceInformation sub = getSubscriber(connectPoint);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100325 if (sub == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000326 log.warn("No subscriber found for {}", connectPoint);
Amit Ghosh31939522018-08-16 13:28:21 +0100327 return false;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100328 }
Jonathan Harte533a422015-10-20 17:31:24 -0700329
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100330 // Get the uplink port
Gamze Abaka838d8142019-02-21 07:06:55 +0000331 Port uplinkPort = getUplinkPort(deviceService.getDevice(deviceId));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100332 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000333 log.warn(NO_UPLINK_PORT, deviceId);
Amit Ghosh31939522018-08-16 13:28:21 +0100334 return false;
Jonathan Harte533a422015-10-20 17:31:24 -0700335 }
336
Gamze Abaka33feef52019-02-27 08:16:47 +0000337 CompletableFuture<ObjectiveError> filterFuture = new CompletableFuture();
338
Gamze Abaka838d8142019-02-21 07:06:55 +0000339 //delete Eapol authentication flow with default bandwidth
Gamze Abaka33feef52019-02-27 08:16:47 +0000340 //wait until Eapol rule with defaultBpId is removed to install subscriber-based rules
341 processEapolFilteringObjectives(deviceId, subscriberPortNo, defaultBpId, filterFuture, false);
342 removeMeterIdFromBpMapping(deviceId, defaultBpId);
Gamze Abaka838d8142019-02-21 07:06:55 +0000343
Gamze Abaka33feef52019-02-27 08:16:47 +0000344 //install subscriber flows
345 filterFuture.thenAcceptAsync(filterStatus -> {
346 if (filterStatus == null) {
347 provisionSubscriberBasedFlows(connectPoint, uplinkPort.number(), Optional.empty(), sub);
348 }
349 });
Gamze Abaka838d8142019-02-21 07:06:55 +0000350
Saurav Das82b8e6d2018-10-04 15:25:12 -0700351 // cache subscriber info
Gamze Abaka838d8142019-02-21 07:06:55 +0000352 programmedSubs.put(connectPoint, sub);
Amit Ghosh31939522018-08-16 13:28:21 +0100353 return true;
alshabibb7a9e172016-01-13 11:23:53 -0800354 }
355
356 @Override
Gamze Abaka838d8142019-02-21 07:06:55 +0000357 public boolean removeSubscriber(ConnectPoint connectPoint) {
Matteo Scandolo962a6ad2018-12-11 15:39:42 -0800358 // Get the subscriber connected to this port from the local cache
359 // as if we don't know about the subscriber there's no need to remove it
Gamze Abaka838d8142019-02-21 07:06:55 +0000360
361 DeviceId deviceId = connectPoint.deviceId();
362 PortNumber subscriberPortNo = connectPoint.port();
363
364 SubscriberAndDeviceInformation subscriber = programmedSubs.get(connectPoint);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100365 if (subscriber == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000366 log.warn("Subscriber on connectionPoint {} was not previously programmed, " +
367 "no need to remove it", connectPoint);
Matteo Scandolo962a6ad2018-12-11 15:39:42 -0800368 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800369 }
370
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100371 // Get the uplink port
Gamze Abaka838d8142019-02-21 07:06:55 +0000372 Port uplinkPort = getUplinkPort(deviceService.getDevice(deviceId));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100373 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000374 log.warn(NO_UPLINK_PORT, deviceId);
Amit Ghosh31939522018-08-16 13:28:21 +0100375 return false;
alshabib4ceaed32016-03-03 18:00:58 -0800376 }
377
Gamze Abaka33feef52019-02-27 08:16:47 +0000378 //delete dhcp & igmp trap flows
379 MeterId upstreamMeterId = getMeterIdFromBpMapping(deviceId, subscriber.upstreamBandwidthProfile());
Amit Ghosh95e2f652017-08-23 12:49:46 +0100380
Gamze Abaka33feef52019-02-27 08:16:47 +0000381 //process dhcp filtering
382 processDhcpFilteringObjectives(deviceId, subscriberPortNo,
383 upstreamMeterId, subscriber.technologyProfileId(), false, true);
Gamze Abaka838d8142019-02-21 07:06:55 +0000384
Gamze Abaka33feef52019-02-27 08:16:47 +0000385 //process igmp filtering
386 processIgmpFilteringObjectives(deviceId, subscriberPortNo,
387 upstreamMeterId, subscriber.technologyProfileId(), false);
alshabibbf23a1f2016-01-14 17:27:11 -0800388
Gamze Abaka33feef52019-02-27 08:16:47 +0000389 //unprovision vlans
390 unprovisionVlans(deviceId, uplinkPort.number(), subscriberPortNo, subscriber, Optional.empty());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100391
392 // Remove if there are any flows for the additional Vlans
Gamze Abaka838d8142019-02-21 07:06:55 +0000393 Collection<? extends Map.Entry<VlanId, VlanId>> vlansList = additionalVlans.get(connectPoint).value();
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100394
395 // Remove the flows for the additional vlans for this subscriber
396 for (Map.Entry<VlanId, VlanId> vlans : vlansList) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000397 unprovisionTransparentFlows(deviceId, uplinkPort.number(), subscriberPortNo,
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100398 vlans.getValue(), vlans.getKey());
399
400 // Remove it from the map also
Gamze Abaka838d8142019-02-21 07:06:55 +0000401 additionalVlans.remove(connectPoint, vlans);
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100402 }
403
Gamze Abaka33feef52019-02-27 08:16:47 +0000404 //re-install eapol
405 processEapolFilteringObjectives(deviceId, subscriberPortNo,
406 subscriber.upstreamBandwidthProfile(), null, false);
407 processEapolFilteringObjectives(deviceId, subscriberPortNo, defaultBpId, null, true);
408
Gamze Abaka838d8142019-02-21 07:06:55 +0000409 programmedSubs.remove(connectPoint);
Amit Ghosh31939522018-08-16 13:28:21 +0100410 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800411 }
412
Amit Ghosh31939522018-08-16 13:28:21 +0100413 @Override
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100414 public boolean provisionSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag, Optional<VlanId> cTag) {
Amit Ghosh31939522018-08-16 13:28:21 +0100415 // Check if we can find the connect point to which this subscriber is connected
416 ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
417 if (subsPort == null) {
418 log.warn("ConnectPoint for {} not found", subscriberId);
419 return false;
420 }
421
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100422 if (!sTag.isPresent() && !cTag.isPresent()) {
423 return provisionSubscriber(subsPort);
424 } else if (sTag.isPresent() && cTag.isPresent()) {
425 Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
426 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000427 log.warn(NO_UPLINK_PORT, subsPort.deviceId());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100428 return false;
429 }
430
431 provisionTransparentFlows(subsPort.deviceId(), uplinkPort.number(), subsPort.port(),
432 cTag.get(), sTag.get());
433 return true;
434 } else {
435 log.warn("Provisioning failed for subscriber: {}", subscriberId);
436 return false;
437 }
Amit Ghosh31939522018-08-16 13:28:21 +0100438 }
Amit Ghosh95e2f652017-08-23 12:49:46 +0100439
alshabibe0559672016-02-21 14:49:51 -0800440 @Override
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100441 public boolean removeSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag, Optional<VlanId> cTag) {
Amit Ghosh31939522018-08-16 13:28:21 +0100442 // Check if we can find the connect point to which this subscriber is connected
443 ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
444 if (subsPort == null) {
445 log.warn("ConnectPoint for {} not found", subscriberId);
446 return false;
447 }
448
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100449 if (!sTag.isPresent() && !cTag.isPresent()) {
450 return removeSubscriber(subsPort);
451 } else if (sTag.isPresent() && cTag.isPresent()) {
452 // Get the uplink port
453 Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
454 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000455 log.warn(NO_UPLINK_PORT, subsPort.deviceId());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100456 return false;
457 }
458
459 unprovisionTransparentFlows(subsPort.deviceId(), uplinkPort.number(), subsPort.port(),
460 cTag.get(), sTag.get());
461 return true;
462 } else {
463 log.warn("Removing subscriber failed for: {}", subscriberId);
464 return false;
465 }
Amit Ghosh31939522018-08-16 13:28:21 +0100466 }
467
468 @Override
469 public Collection<Map.Entry<ConnectPoint, Map.Entry<VlanId, VlanId>>> getSubscribers() {
470 ArrayList<Map.Entry<ConnectPoint, Map.Entry<VlanId, VlanId>>> subs = new ArrayList<>();
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100471
Saurav Das82b8e6d2018-10-04 15:25:12 -0700472 // Get the subscribers for all the devices configured in sadis
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100473 // If the port is UNI, is enabled and exists in Sadis then copy it
474 for (Device d : deviceService.getDevices()) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700475 if (getOltInfo(d) == null) {
476 continue; // not an olt, or not configured in sadis
477 }
Gamze Abakaad329652018-12-20 10:12:21 +0000478 for (Port p : deviceService.getPorts(d.id())) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100479 if (isUniPort(d, p) && p.isEnabled()) {
480 ConnectPoint cp = new ConnectPoint(d.id(), p.number());
481
482 SubscriberAndDeviceInformation sub = getSubscriber(cp);
483 if (sub != null) {
Amit Ghosh31939522018-08-16 13:28:21 +0100484 Map.Entry<VlanId, VlanId> vlans = new AbstractMap.SimpleEntry(sub.sTag(), sub.cTag());
485 subs.add(new AbstractMap.SimpleEntry(cp, vlans));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100486 }
487 }
488 }
489 }
490
491 return subs;
Jonathan Hartfd6c1b32016-03-08 14:09:09 -0800492 }
493
494 @Override
Saurav Das82b8e6d2018-10-04 15:25:12 -0700495 public ImmutableMap<ConnectPoint, SubscriberAndDeviceInformation> getProgSubs() {
496 return ImmutableMap.copyOf(programmedSubs);
497 }
498
499 @Override
Gamze Abaka33feef52019-02-27 08:16:47 +0000500 public ImmutableSet<MeterKey> getProgMeters() {
501 return ImmutableSet.copyOf(programmedMeters);
502 }
503
504 @Override
505 public ImmutableMap<String, List<MeterKey>> getBpMeterMappings() {
506 return ImmutableMap.copyOf(bpInfoToMeter);
507 }
508
509 @Override
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100510 public List<DeviceId> fetchOlts() {
511 // look through all the devices and find the ones that are OLTs as per Sadis
512 List<DeviceId> olts = new ArrayList<>();
513 Iterable<Device> devices = deviceService.getDevices();
514 for (Device d : devices) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700515 if (getOltInfo(d) != null) {
516 // So this is indeed an OLT device
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100517 olts.add(d.id());
518 }
519 }
520 return olts;
alshabibe0559672016-02-21 14:49:51 -0800521 }
522
Amit Ghosh31939522018-08-16 13:28:21 +0100523 /**
524 * Finds the connect point to which a subscriber is connected.
525 *
526 * @param id The id of the subscriber, this is the same ID as in Sadis
527 * @return Subscribers ConnectPoint if found else null
528 */
529 private ConnectPoint findSubscriberConnectPoint(String id) {
530
531 Iterable<Device> devices = deviceService.getDevices();
532 for (Device d : devices) {
533 for (Port p : deviceService.getPorts(d.id())) {
534 log.trace("Comparing {} with {}", p.annotations().value(AnnotationKeys.PORT_NAME), id);
535 if (p.annotations().value(AnnotationKeys.PORT_NAME).equals(id)) {
536 log.debug("Found on device {} port {}", d.id(), p.number());
537 return new ConnectPoint(d.id(), p.number());
538 }
539 }
540 }
541 return null;
542 }
543
Gamze Abaka641fc072018-09-04 09:16:27 +0000544 private BandwidthProfileInformation getBandwidthProfileInformation(String bandwidthProfile) {
545 if (bandwidthProfile == null) {
546 return null;
547 }
548 return bpService.get(bandwidthProfile);
549 }
550
Gamze Abaka838d8142019-02-21 07:06:55 +0000551 /**
Gamze Abaka33feef52019-02-27 08:16:47 +0000552 * Removes subscriber vlan flows.
Gamze Abaka838d8142019-02-21 07:06:55 +0000553 *
554 * @param deviceId the device identifier
555 * @param uplink uplink port of the OLT
556 * @param subscriberPort uni port
557 * @param subscriber subscriber info that includes s, c tags, tech profile and bandwidth profile references
558 * @param defaultVlan default vlan of the subscriber
Gamze Abaka838d8142019-02-21 07:06:55 +0000559 */
Gamze Abaka33feef52019-02-27 08:16:47 +0000560 private void unprovisionVlans(DeviceId deviceId, PortNumber uplink,
561 PortNumber subscriberPort, SubscriberAndDeviceInformation subscriber,
562 Optional<VlanId> defaultVlan) {
563
564 log.info("Unprovisioning vlans...");
alshabibbf23a1f2016-01-14 17:27:11 -0800565
566 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
567 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
568
Gamze Abaka641fc072018-09-04 09:16:27 +0000569 VlanId deviceVlan = subscriber.sTag();
570 VlanId subscriberVlan = subscriber.cTag();
571
Gamze Abaka33feef52019-02-27 08:16:47 +0000572 MeterId upstreamMeterId = getMeterIdFromBpMapping(deviceId, subscriber.upstreamBandwidthProfile());
573 MeterId downstreamMeterId = getMeterIdFromBpMapping(deviceId, subscriber.downstreamBandwidthProfile());
Gamze Abaka641fc072018-09-04 09:16:27 +0000574
alshabib4ceaed32016-03-03 18:00:58 -0800575 ForwardingObjective.Builder upFwd = upBuilder(uplink, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000576 subscriberVlan, deviceVlan,
577 defaultVlan, upstreamMeterId, subscriber.technologyProfileId());
alshabib4ceaed32016-03-03 18:00:58 -0800578 ForwardingObjective.Builder downFwd = downBuilder(uplink, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000579 subscriberVlan, deviceVlan,
580 defaultVlan, downstreamMeterId, subscriber.technologyProfileId());
alshabibbf23a1f2016-01-14 17:27:11 -0800581
alshabib4ceaed32016-03-03 18:00:58 -0800582 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
583 @Override
584 public void onSuccess(Objective objective) {
585 upFuture.complete(null);
586 }
alshabibbf23a1f2016-01-14 17:27:11 -0800587
alshabib4ceaed32016-03-03 18:00:58 -0800588 @Override
589 public void onError(Objective objective, ObjectiveError error) {
590 upFuture.complete(error);
591 }
592 }));
593
594 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
595 @Override
596 public void onSuccess(Objective objective) {
597 downFuture.complete(null);
598 }
599
600 @Override
601 public void onError(Objective objective, ObjectiveError error) {
602 downFuture.complete(error);
603 }
604 }));
alshabibbf23a1f2016-01-14 17:27:11 -0800605
606 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
607 if (upStatus == null && downStatus == null) {
608 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_UNREGISTERED,
Gamze Abaka641fc072018-09-04 09:16:27 +0000609 deviceId,
610 deviceVlan,
611 subscriberVlan));
alshabibbf23a1f2016-01-14 17:27:11 -0800612 } else if (downStatus != null) {
613 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000614 "on port {} failed downstream uninstallation: {}",
615 subscriberVlan, deviceId, subscriberPort, downStatus);
alshabibbf23a1f2016-01-14 17:27:11 -0800616 } else if (upStatus != null) {
617 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000618 "on port {} failed upstream uninstallation: {}",
619 subscriberVlan, deviceId, subscriberPort, upStatus);
alshabibbf23a1f2016-01-14 17:27:11 -0800620 }
621 }, oltInstallers);
alshabibb7a9e172016-01-13 11:23:53 -0800622
Gamze Abaka33feef52019-02-27 08:16:47 +0000623 programmedMeters.remove(MeterKey.key(deviceId, upstreamMeterId));
624 programmedMeters.remove(MeterKey.key(deviceId, downstreamMeterId));
Gamze Abaka838d8142019-02-21 07:06:55 +0000625 log.debug("programmed Meters size {}", programmedMeters.size());
Jonathan Harte533a422015-10-20 17:31:24 -0700626 }
627
Gamze Abaka838d8142019-02-21 07:06:55 +0000628 /**
Gamze Abaka33feef52019-02-27 08:16:47 +0000629 * Adds subscriber vlan flows, dhcp, eapol and igmp trap flows for the related uni port.
Gamze Abaka838d8142019-02-21 07:06:55 +0000630 *
631 * @param port the connection point of the subscriber
632 * @param uplinkPort uplink port of the OLT
633 * @param defaultVlan default vlan of the subscriber
634 * @param sub subscriber information that includes s, c tags, tech profile and bandwidth profile references
Gamze Abaka838d8142019-02-21 07:06:55 +0000635 */
Gamze Abaka33feef52019-02-27 08:16:47 +0000636 private void provisionSubscriberBasedFlows(ConnectPoint port, PortNumber uplinkPort, Optional<VlanId> defaultVlan,
637 SubscriberAndDeviceInformation sub) {
Gamze Abaka641fc072018-09-04 09:16:27 +0000638
639 log.info("Provisioning vlans...");
640
641 DeviceId deviceId = port.deviceId();
642 PortNumber subscriberPort = port.port();
643 VlanId deviceVlan = sub.sTag();
644 VlanId subscriberVlan = sub.cTag();
645 int techProfId = sub.technologyProfileId();
646
647 BandwidthProfileInformation upstreamBpInfo = getBandwidthProfileInformation(sub.upstreamBandwidthProfile());
648 BandwidthProfileInformation downstreamBpInfo = getBandwidthProfileInformation(sub.downstreamBandwidthProfile());
649
alshabib3ea82642016-01-12 18:06:53 -0800650 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
651 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
Gamze Abaka33feef52019-02-27 08:16:47 +0000652 CompletableFuture<Object> upstreamMeterFuture = new CompletableFuture<>();
653 CompletableFuture<Object> downsteamMeterFuture = new CompletableFuture<>();
alshabib3ea82642016-01-12 18:06:53 -0800654
Gamze Abaka33feef52019-02-27 08:16:47 +0000655 MeterId upstreamMeterId = createMeter(deviceId, upstreamBpInfo, upstreamMeterFuture);
656 MeterId downstreamMeterId = createMeter(deviceId, downstreamBpInfo, downsteamMeterFuture);
Jonathan Harte533a422015-10-20 17:31:24 -0700657
Gamze Abaka33feef52019-02-27 08:16:47 +0000658 //install upstream flows
659 upstreamMeterFuture.thenAcceptAsync(result -> {
660 if (result == null) {
661 log.info("Upstream Meter {} is sent to the device {}. " +
662 "Sending subscriber flows.", upstreamMeterId, deviceId);
663 ForwardingObjective.Builder upFwd = upBuilder(uplinkPort, subscriberPort,
664 subscriberVlan, deviceVlan,
665 defaultVlan, upstreamMeterId, techProfId);
alshabib3ea82642016-01-12 18:06:53 -0800666
Gamze Abaka33feef52019-02-27 08:16:47 +0000667
668 flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
669 @Override
670 public void onSuccess(Objective objective) {
671 upFuture.complete(null);
672 }
673
674 @Override
675 public void onError(Objective objective, ObjectiveError error) {
676 upFuture.complete(error);
677 }
678 }));
679 } else {
680 log.warn("Meter installation error while sending upstream flows. " +
681 "Result {} and MeterId {}", result, upstreamMeterId);
alshabibbf23a1f2016-01-14 17:27:11 -0800682 }
Gamze Abaka33feef52019-02-27 08:16:47 +0000683 });
alshabibbf23a1f2016-01-14 17:27:11 -0800684
Gamze Abaka33feef52019-02-27 08:16:47 +0000685 //install downstream flows
686 downsteamMeterFuture.thenAcceptAsync(result -> {
687 if (result == null) {
688 log.info("Downstream Meter {} is sent to the device {}. " +
689 "Sending subscriber flows.", downstreamMeterId, deviceId);
690 ForwardingObjective.Builder downFwd = downBuilder(uplinkPort, subscriberPort,
691 subscriberVlan, deviceVlan,
692 defaultVlan, downstreamMeterId, techProfId);
693
694 flowObjectiveService.forward(deviceId, downFwd.add(new ObjectiveContext() {
695 @Override
696 public void onSuccess(Objective objective) {
697 downFuture.complete(null);
698 }
699
700 @Override
701 public void onError(Objective objective, ObjectiveError error) {
702 downFuture.complete(error);
703 }
704 }));
705 } else {
706 log.warn("Meter installation error while sending downstream flows. " +
707 "Result {} and MeterId {}", result, downstreamMeterId);
alshabibbf23a1f2016-01-14 17:27:11 -0800708 }
Gamze Abaka33feef52019-02-27 08:16:47 +0000709 });
alshabibbf23a1f2016-01-14 17:27:11 -0800710
Gamze Abaka33feef52019-02-27 08:16:47 +0000711 //send eapol & dhcp & igmp flows
712 //send Subscriber Registered event
alshabib3ea82642016-01-12 18:06:53 -0800713 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
714 if (upStatus == null && downStatus == null) {
Gamze Abaka33feef52019-02-27 08:16:47 +0000715
716 if (upstreamMeterId != null) {
717 //re-install Eapol authentication flow with the subscribers' upstream bandwidth profile
718 processEapolFilteringObjectives(deviceId, subscriberPort, sub.upstreamBandwidthProfile(),
719 null, true);
720
721 processDhcpFilteringObjectives(deviceId, subscriberPort,
722 upstreamMeterId, sub.technologyProfileId(), true, true);
723
724 processIgmpFilteringObjectives(deviceId, subscriberPort,
725 upstreamMeterId, sub.technologyProfileId(), true);
726 }
727
alshabib3ea82642016-01-12 18:06:53 -0800728 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_REGISTERED,
Gamze Abaka641fc072018-09-04 09:16:27 +0000729 deviceId,
730 deviceVlan,
731 subscriberVlan));
alshabib50d9fc52016-02-12 15:47:20 -0800732
alshabib3ea82642016-01-12 18:06:53 -0800733 } else if (downStatus != null) {
734 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000735 "on port {} failed downstream installation: {}",
736 subscriberVlan, deviceId, subscriberPort, downStatus);
alshabib3ea82642016-01-12 18:06:53 -0800737 } else if (upStatus != null) {
738 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000739 "on port {} failed upstream installation: {}",
740 subscriberVlan, deviceId, subscriberPort, upStatus);
alshabib3ea82642016-01-12 18:06:53 -0800741 }
742 }, oltInstallers);
Jonathan Harte533a422015-10-20 17:31:24 -0700743 }
744
Gamze Abaka33feef52019-02-27 08:16:47 +0000745 private MeterId createMeter(DeviceId deviceId, BandwidthProfileInformation bpInfo,
746 CompletableFuture<Object> meterFuture) {
Gamze Abaka641fc072018-09-04 09:16:27 +0000747 if (bpInfo == null) {
748 log.warn("Bandwidth profile information is not found");
749 return null;
750 }
751
Gamze Abaka33feef52019-02-27 08:16:47 +0000752 MeterId meterId = getMeterIdFromBpMapping(deviceId, bpInfo.id());
Gamze Abaka641fc072018-09-04 09:16:27 +0000753 if (meterId != null) {
754 log.info("Meter is already added. MeterId {}", meterId);
Gamze Abaka33feef52019-02-27 08:16:47 +0000755 meterFuture.complete(null);
Gamze Abaka641fc072018-09-04 09:16:27 +0000756 return meterId;
757 }
758
759 List<Band> meterBands = createMeterBands(bpInfo);
760
761 MeterRequest meterRequest = DefaultMeterRequest.builder()
762 .withBands(meterBands)
763 .withUnit(Meter.Unit.KB_PER_SEC)
Gamze Abaka33feef52019-02-27 08:16:47 +0000764 .withContext(new MeterContext() {
765 @Override
766 public void onSuccess(MeterRequest op) {
767 log.debug("meter addition completed");
768 meterFuture.complete(null);
769 }
770
771 @Override
772 public void onError(MeterRequest op, MeterFailReason reason) {
773 meterFuture.complete(reason);
774 }
775 })
Gamze Abaka641fc072018-09-04 09:16:27 +0000776 .forDevice(deviceId)
777 .fromApp(appId)
778 .burst()
779 .add();
780
781 Meter meter = meterService.submit(meterRequest);
Gamze Abaka33feef52019-02-27 08:16:47 +0000782 addMeterIdToBpMapping(deviceId, meter.id(), bpInfo.id());
Gamze Abaka641fc072018-09-04 09:16:27 +0000783 log.info("Meter is created. Meter Id {}", meter.id());
Gamze Abaka33feef52019-02-27 08:16:47 +0000784 programmedMeters.add(MeterKey.key(deviceId, meter.id()));
Gamze Abaka838d8142019-02-21 07:06:55 +0000785 log.debug("programmed Meters size {}", programmedMeters.size());
Gamze Abaka641fc072018-09-04 09:16:27 +0000786 return meter.id();
787 }
788
789 private List<Band> createMeterBands(BandwidthProfileInformation bpInfo) {
790 List<Band> meterBands = new ArrayList<>();
791
792 meterBands.add(createMeterBand(bpInfo.committedInformationRate(), bpInfo.committedBurstSize()));
793 meterBands.add(createMeterBand(bpInfo.exceededInformationRate(), bpInfo.exceededBurstSize()));
Gamze Abakaad329652018-12-20 10:12:21 +0000794 meterBands.add(createMeterBand(bpInfo.assuredInformationRate(), 0L));
Gamze Abaka641fc072018-09-04 09:16:27 +0000795
Gamze Abaka641fc072018-09-04 09:16:27 +0000796 return meterBands;
797 }
798
799 private Band createMeterBand(long rate, Long burst) {
800 return DefaultBand.builder()
801 .withRate(rate) //already Kbps
802 .burstSize(burst) // already Kbits
803 .ofType(Band.Type.DROP) // no matter
804 .build();
805 }
806
alshabib4ceaed32016-03-03 18:00:58 -0800807 private ForwardingObjective.Builder downBuilder(PortNumber uplinkPort,
808 PortNumber subscriberPort,
809 VlanId subscriberVlan,
810 VlanId deviceVlan,
Gamze Abaka641fc072018-09-04 09:16:27 +0000811 Optional<VlanId> defaultVlan,
812 MeterId meterId,
813 int techProfId) {
alshabib4ceaed32016-03-03 18:00:58 -0800814 TrafficSelector downstream = DefaultTrafficSelector.builder()
815 .matchVlanId(deviceVlan)
816 .matchInPort(uplinkPort)
817 .matchInnerVlanId(subscriberVlan)
818 .build();
819
Gamze Abaka641fc072018-09-04 09:16:27 +0000820 TrafficTreatment.Builder downstreamTreatmentBuilder = DefaultTrafficTreatment.builder()
alshabib4ceaed32016-03-03 18:00:58 -0800821 .popVlan()
822 .setVlanId(defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan)))
Gamze Abaka641fc072018-09-04 09:16:27 +0000823 .setOutput(subscriberPort);
824
825 if (meterId != null) {
826 downstreamTreatmentBuilder.meter(meterId);
827 }
828
Gamze Abakaad329652018-12-20 10:12:21 +0000829 downstreamTreatmentBuilder.writeMetadata(createMetadata(subscriberVlan, techProfId, subscriberPort), 0);
alshabib4ceaed32016-03-03 18:00:58 -0800830
831 return DefaultForwardingObjective.builder()
832 .withFlag(ForwardingObjective.Flag.VERSATILE)
833 .withPriority(1000)
834 .makePermanent()
835 .withSelector(downstream)
836 .fromApp(appId)
Gamze Abaka641fc072018-09-04 09:16:27 +0000837 .withTreatment(downstreamTreatmentBuilder.build());
alshabib4ceaed32016-03-03 18:00:58 -0800838 }
839
840 private ForwardingObjective.Builder upBuilder(PortNumber uplinkPort,
841 PortNumber subscriberPort,
842 VlanId subscriberVlan,
843 VlanId deviceVlan,
Gamze Abaka641fc072018-09-04 09:16:27 +0000844 Optional<VlanId> defaultVlan,
845 MeterId meterId,
846 int technologyProfileId) {
847
848
849 VlanId dVlan = defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan));
850
851 if (subscriberVlan.toShort() == 4096) {
852 dVlan = subscriberVlan;
853 }
854
alshabib4ceaed32016-03-03 18:00:58 -0800855 TrafficSelector upstream = DefaultTrafficSelector.builder()
Gamze Abaka641fc072018-09-04 09:16:27 +0000856 .matchVlanId(dVlan)
alshabib4ceaed32016-03-03 18:00:58 -0800857 .matchInPort(subscriberPort)
858 .build();
859
860
Gamze Abaka641fc072018-09-04 09:16:27 +0000861 TrafficTreatment.Builder upstreamTreatmentBuilder = DefaultTrafficTreatment.builder()
alshabib4ceaed32016-03-03 18:00:58 -0800862 .pushVlan()
863 .setVlanId(subscriberVlan)
864 .pushVlan()
865 .setVlanId(deviceVlan)
Gamze Abaka641fc072018-09-04 09:16:27 +0000866 .setOutput(uplinkPort);
867
868 if (meterId != null) {
869 upstreamTreatmentBuilder.meter(meterId);
870 }
871
Gamze Abakaad329652018-12-20 10:12:21 +0000872 upstreamTreatmentBuilder.writeMetadata(createMetadata(deviceVlan, technologyProfileId, uplinkPort), 0L);
alshabib4ceaed32016-03-03 18:00:58 -0800873
874 return DefaultForwardingObjective.builder()
875 .withFlag(ForwardingObjective.Flag.VERSATILE)
876 .withPriority(1000)
877 .makePermanent()
878 .withSelector(upstream)
879 .fromApp(appId)
Gamze Abaka641fc072018-09-04 09:16:27 +0000880 .withTreatment(upstreamTreatmentBuilder.build());
alshabib4ceaed32016-03-03 18:00:58 -0800881 }
Gamze Abakaad329652018-12-20 10:12:21 +0000882
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100883 private void provisionTransparentFlows(DeviceId deviceId, PortNumber uplinkPort,
884 PortNumber subscriberPort,
885 VlanId innerVlan,
886 VlanId outerVlan) {
887
888 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
889 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
890
891 ForwardingObjective.Builder upFwd = transparentUpBuilder(uplinkPort, subscriberPort,
892 innerVlan, outerVlan);
893
894
895 ForwardingObjective.Builder downFwd = transparentDownBuilder(uplinkPort, subscriberPort,
896 innerVlan, outerVlan);
897
898 ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
899
900 additionalVlans.put(cp, new AbstractMap.SimpleEntry(outerVlan, innerVlan));
901
902 flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
903 @Override
904 public void onSuccess(Objective objective) {
905 upFuture.complete(null);
906 }
907
908 @Override
909 public void onError(Objective objective, ObjectiveError error) {
910 upFuture.complete(error);
911 }
912 }));
913
914 flowObjectiveService.forward(deviceId, downFwd.add(new ObjectiveContext() {
915 @Override
916 public void onSuccess(Objective objective) {
917 downFuture.complete(null);
918 }
919
920 @Override
921 public void onError(Objective objective, ObjectiveError error) {
922 downFuture.complete(error);
923 }
924 }));
925
926 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
927 if (downStatus != null) {
928 log.error("Flow with innervlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000929 "on port {} failed downstream installation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100930 innerVlan, outerVlan, deviceId, subscriberPort, downStatus);
931 } else if (upStatus != null) {
932 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000933 "on port {} failed upstream installation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100934 innerVlan, outerVlan, deviceId, subscriberPort, upStatus);
935 }
936 }, oltInstallers);
937
938 }
939
940 private ForwardingObjective.Builder transparentDownBuilder(PortNumber uplinkPort,
941 PortNumber subscriberPort,
942 VlanId innerVlan,
943 VlanId outerVlan) {
944 TrafficSelector downstream = DefaultTrafficSelector.builder()
945 .matchVlanId(outerVlan)
946 .matchInPort(uplinkPort)
947 .matchInnerVlanId(innerVlan)
948 .build();
949
950 TrafficTreatment downstreamTreatment = DefaultTrafficTreatment.builder()
951 .setOutput(subscriberPort)
952 .build();
953
954 return DefaultForwardingObjective.builder()
955 .withFlag(ForwardingObjective.Flag.VERSATILE)
956 .withPriority(1000)
957 .makePermanent()
958 .withSelector(downstream)
959 .fromApp(appId)
960 .withTreatment(downstreamTreatment);
961 }
962
963 private ForwardingObjective.Builder transparentUpBuilder(PortNumber uplinkPort,
964 PortNumber subscriberPort,
965 VlanId innerVlan,
966 VlanId outerVlan) {
967 TrafficSelector upstream = DefaultTrafficSelector.builder()
968 .matchVlanId(outerVlan)
969 .matchInPort(subscriberPort)
970 .matchInnerVlanId(innerVlan)
971 .build();
972
973 TrafficTreatment upstreamTreatment = DefaultTrafficTreatment.builder()
974 .setOutput(uplinkPort)
975 .build();
976
977 return DefaultForwardingObjective.builder()
978 .withFlag(ForwardingObjective.Flag.VERSATILE)
979 .withPriority(1000)
980 .makePermanent()
981 .withSelector(upstream)
982 .fromApp(appId)
983 .withTreatment(upstreamTreatment);
984 }
985
986 private void unprovisionTransparentFlows(DeviceId deviceId, PortNumber uplink,
987 PortNumber subscriberPort, VlanId innerVlan,
988 VlanId outerVlan) {
989
990 ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
991
992 additionalVlans.remove(cp, new AbstractMap.SimpleEntry(outerVlan, innerVlan));
993
994 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
995 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
996
997 ForwardingObjective.Builder upFwd = transparentUpBuilder(uplink, subscriberPort,
998 innerVlan, outerVlan);
999 ForwardingObjective.Builder downFwd = transparentDownBuilder(uplink, subscriberPort,
1000 innerVlan, outerVlan);
1001
1002
1003 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
1004 @Override
1005 public void onSuccess(Objective objective) {
1006 upFuture.complete(null);
1007 }
1008
1009 @Override
1010 public void onError(Objective objective, ObjectiveError error) {
1011 upFuture.complete(error);
1012 }
1013 }));
1014
1015 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
1016 @Override
1017 public void onSuccess(Objective objective) {
1018 downFuture.complete(null);
1019 }
1020
1021 @Override
1022 public void onError(Objective objective, ObjectiveError error) {
1023 downFuture.complete(error);
1024 }
1025 }));
1026
1027 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
1028 if (downStatus != null) {
1029 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +00001030 "on port {} failed downstream uninstallation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001031 innerVlan, outerVlan, deviceId, subscriberPort, downStatus);
1032 } else if (upStatus != null) {
1033 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +00001034 "on port {} failed upstream uninstallation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001035 innerVlan, outerVlan, deviceId, subscriberPort, upStatus);
1036 }
1037 }, oltInstallers);
1038
1039 }
1040
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001041 private int getDefaultTechProfileId(DeviceId devId, PortNumber portNumber) {
1042 Port port = deviceService.getPort(devId, portNumber);
1043 SubscriberAndDeviceInformation info = subsService.get(port.annotations().value(AnnotationKeys.PORT_NAME));
1044 if (info != null && info.technologyProfileId() != -1) {
1045 return info.technologyProfileId();
1046 }
1047 return defaultTechProfileId;
1048 }
1049
Gamze Abaka838d8142019-02-21 07:06:55 +00001050 /**
1051 * Returns the write metadata value including only tech profile reference.
1052 *
1053 * @param techProfileId tech profile id of one subscriber
1054 * @return the write metadata value including only tech profile reference
1055 */
1056 private Long createTechProfValueForWm(int techProfileId) {
1057 return (long) techProfileId << 32;
1058 }
1059
1060 /**
1061 * Trap eapol authentication packets to the controller.
1062 *
Gamze Abaka33feef52019-02-27 08:16:47 +00001063 * @param devId the device identifier
1064 * @param portNumber the port for which this trap flow is designated
1065 * @param bpId bandwidth profile id to add the related meter to the flow
1066 * @param filterFuture completable future for this filtering objective operation
1067 * @param install true to install the flow, false to remove the flow
Gamze Abaka838d8142019-02-21 07:06:55 +00001068 */
Gamze Abaka33feef52019-02-27 08:16:47 +00001069 private void processEapolFilteringObjectives(DeviceId devId, PortNumber portNumber, String bpId,
1070 CompletableFuture<ObjectiveError> filterFuture,
1071 boolean install) {
1072
1073 if (!enableEapol) {
1074 log.debug("Eapol filtering is disabled.");
1075 if (filterFuture != null) {
1076 filterFuture.complete(null);
1077 }
1078 return;
1079 }
1080
alshabib09753b52016-03-04 14:55:19 -08001081 if (!mastershipService.isLocalMaster(devId)) {
1082 return;
1083 }
alshabibbb83aa22016-02-10 15:08:23 -08001084 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Gamze Abakaad329652018-12-20 10:12:21 +00001085 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
Gamze Abaka33feef52019-02-27 08:16:47 +00001086 CompletableFuture<Object> meterFuture = new CompletableFuture<>();
Gamze Abaka838d8142019-02-21 07:06:55 +00001087 MeterId meterId;
alshabibbb83aa22016-02-10 15:08:23 -08001088
Gamze Abaka838d8142019-02-21 07:06:55 +00001089 BandwidthProfileInformation bpInfo = getBandwidthProfileInformation(bpId);
1090 if (bpInfo != null) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001091 meterId = createMeter(devId, bpInfo, meterFuture);
Gamze Abakaad329652018-12-20 10:12:21 +00001092 treatmentBuilder.meter(meterId);
1093 } else {
Gamze Abaka838d8142019-02-21 07:06:55 +00001094 log.warn("Bandwidth profile {} is not found. Authentication flow will not be installed", bpId);
1095 return;
Gamze Abakaad329652018-12-20 10:12:21 +00001096 }
1097
Gamze Abaka33feef52019-02-27 08:16:47 +00001098 meterFuture.thenAcceptAsync(result -> {
1099 if (result == null) {
1100 log.info("Meter {} for the device {} is installed. " +
1101 "{} EAPOL trap flow", meterId, devId, install ? "Installing " : "Removing ");
1102 int techProfileId = getDefaultTechProfileId(devId, portNumber);
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001103
Gamze Abaka33feef52019-02-27 08:16:47 +00001104 //Authentication trap flow uses only tech profile id as write metadata value
1105 FilteringObjective eapol = (install ? builder.permit() : builder.deny())
1106 .withKey(Criteria.matchInPort(portNumber))
1107 .addCondition(Criteria.matchEthType(EthType.EtherType.EAPOL.ethType()))
1108 .withMeta(treatmentBuilder
1109 .writeMetadata(createTechProfValueForWm(techProfileId), 0)
1110 .setOutput(PortNumber.CONTROLLER).build())
1111 .fromApp(appId)
1112 .withPriority(10000)
1113 .add(new ObjectiveContext() {
1114 @Override
1115 public void onSuccess(Objective objective) {
1116 log.info("Eapol filter for {} on {} {} with meter {}.",
1117 devId, portNumber, (install) ? INSTALLED : REMOVED, meterId);
1118 if (filterFuture != null) {
1119 filterFuture.complete(null);
1120 }
1121 }
alshabibdec2e252016-01-15 12:20:25 -08001122
Gamze Abaka33feef52019-02-27 08:16:47 +00001123 @Override
1124 public void onError(Objective objective, ObjectiveError error) {
1125 log.info("Eapol filter for {} on {} with meter {} failed {} because {}",
1126 devId, portNumber, meterId, (install) ? INSTALLATION : REMOVAL,
1127 error);
1128 if (filterFuture != null) {
1129 filterFuture.complete(error);
1130 }
1131 }
1132 });
alshabibdec2e252016-01-15 12:20:25 -08001133
Gamze Abaka33feef52019-02-27 08:16:47 +00001134 flowObjectiveService.filter(devId, eapol);
1135 } else {
1136 log.warn("Meter installation error while sending eapol trap flow. " +
1137 "Result {} and MeterId {}", result, meterId);
1138 }
1139 });
alshabibdec2e252016-01-15 12:20:25 -08001140 }
1141
Jonathan Hart403372d2018-08-22 11:44:13 -07001142 /**
1143 * Installs trap filtering objectives for particular traffic types on an
1144 * NNI port.
1145 *
Gamze Abakaad329652018-12-20 10:12:21 +00001146 * @param devId device ID
1147 * @param port port number
Jonathan Hart403372d2018-08-22 11:44:13 -07001148 * @param install true to install, false to remove
1149 */
1150 private void processNniFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
1151 processLldpFilteringObjective(devId, port, install);
Gamze Abaka33feef52019-02-27 08:16:47 +00001152 processDhcpFilteringObjectives(devId, port, null, -1, install, false);
Jonathan Hart403372d2018-08-22 11:44:13 -07001153 }
1154
1155 private void processLldpFilteringObjective(DeviceId devId, PortNumber port, boolean install) {
1156 if (!mastershipService.isLocalMaster(devId)) {
1157 return;
1158 }
1159 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
1160
1161 FilteringObjective lldp = (install ? builder.permit() : builder.deny())
1162 .withKey(Criteria.matchInPort(port))
1163 .addCondition(Criteria.matchEthType(EthType.EtherType.LLDP.ethType()))
1164 .withMeta(DefaultTrafficTreatment.builder()
1165 .setOutput(PortNumber.CONTROLLER).build())
1166 .fromApp(appId)
1167 .withPriority(10000)
1168 .add(new ObjectiveContext() {
1169 @Override
1170 public void onSuccess(Objective objective) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001171 log.info("LLDP filter for device {} on port {} {}.",
Gamze Abaka838d8142019-02-21 07:06:55 +00001172 devId, port, (install) ? INSTALLED : REMOVED);
Jonathan Hart403372d2018-08-22 11:44:13 -07001173 }
1174
1175 @Override
1176 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001177 log.info("LLDP filter for device {} on port {} failed {} because {}",
Gamze Abaka838d8142019-02-21 07:06:55 +00001178 devId, port, (install) ? INSTALLATION : REMOVAL,
Saurav Das82b8e6d2018-10-04 15:25:12 -07001179 error);
Jonathan Hart403372d2018-08-22 11:44:13 -07001180 }
1181 });
1182
1183 flowObjectiveService.filter(devId, lldp);
1184
1185 }
1186
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001187 /**
1188 * Trap dhcp packets to the controller.
1189 *
Gamze Abaka838d8142019-02-21 07:06:55 +00001190 * @param devId the device identifier
1191 * @param port the port for which this trap flow is designated
1192 * @param upstreamMeterId the upstream meter id that includes the upstream
1193 * bandwidth profile values such as PIR,CIR. If no meter id needs to be referenced,
1194 * null can be sent
1195 * @param techProfileId the technology profile id that is used to create write
1196 * metadata instruction value. If no tech profile id needs to be referenced,
1197 * -1 can be sent
1198 * @param install true to install the flow, false to remove the flow
1199 * @param upstream true if trapped packets are flowing upstream towards
1200 * server, false if packets are flowing downstream towards client
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001201 */
1202 private void processDhcpFilteringObjectives(DeviceId devId, PortNumber port,
Gamze Abaka838d8142019-02-21 07:06:55 +00001203 MeterId upstreamMeterId,
1204 int techProfileId,
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001205 boolean install,
1206 boolean upstream) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001207
1208 if (!enableDhcpOnProvisioning) {
1209 log.debug("Dhcp provisioning is disabled.");
1210 return;
1211 }
1212
Amit Ghosh95e2f652017-08-23 12:49:46 +01001213 if (!mastershipService.isLocalMaster(devId)) {
1214 return;
1215 }
Amit Ghosh95e2f652017-08-23 12:49:46 +01001216
Matteo Scandolo63460d12018-11-02 16:19:04 -07001217 if (enableDhcpV4) {
1218 int udpSrc = (upstream) ? 68 : 67;
1219 int udpDst = (upstream) ? 67 : 68;
1220
1221 EthType ethType = EthType.EtherType.IPV4.ethType();
1222 byte protocol = IPv4.PROTOCOL_UDP;
1223
Gamze Abaka838d8142019-02-21 07:06:55 +00001224 this.addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType,
1225 upstreamMeterId, techProfileId, protocol, install);
Matteo Scandolo63460d12018-11-02 16:19:04 -07001226 }
1227
1228 if (enableDhcpV6) {
1229 int udpSrc = (upstream) ? 547 : 546;
1230 int udpDst = (upstream) ? 546 : 547;
1231
1232 EthType ethType = EthType.EtherType.IPV6.ethType();
1233 byte protocol = IPv6.PROTOCOL_UDP;
1234
Gamze Abaka838d8142019-02-21 07:06:55 +00001235 this.addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType,
1236 upstreamMeterId, techProfileId, protocol, install);
Matteo Scandolo63460d12018-11-02 16:19:04 -07001237 }
1238
1239 }
1240
1241 private void addDhcpFilteringObjectives(DeviceId devId,
1242 PortNumber port,
1243 int udpSrc,
1244 int udpDst,
1245 EthType ethType,
Gamze Abaka838d8142019-02-21 07:06:55 +00001246 MeterId upstreamMeterId,
1247 int techProfileId,
Matteo Scandolo63460d12018-11-02 16:19:04 -07001248 byte protocol,
1249 boolean install) {
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001250
1251 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Gamze Abaka838d8142019-02-21 07:06:55 +00001252 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
1253
1254 if (upstreamMeterId != null) {
1255 treatmentBuilder.meter(upstreamMeterId);
1256 }
1257
1258 if (techProfileId != -1) {
1259 treatmentBuilder.writeMetadata(createTechProfValueForWm(techProfileId), 0);
1260 }
1261
Amit Ghosh95e2f652017-08-23 12:49:46 +01001262 FilteringObjective dhcpUpstream = (install ? builder.permit() : builder.deny())
1263 .withKey(Criteria.matchInPort(port))
Matteo Scandolo63460d12018-11-02 16:19:04 -07001264 .addCondition(Criteria.matchEthType(ethType))
1265 .addCondition(Criteria.matchIPProtocol(protocol))
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001266 .addCondition(Criteria.matchUdpSrc(TpPort.tpPort(udpSrc)))
1267 .addCondition(Criteria.matchUdpDst(TpPort.tpPort(udpDst)))
Gamze Abaka838d8142019-02-21 07:06:55 +00001268 .withMeta(treatmentBuilder
Gamze Abaka641fc072018-09-04 09:16:27 +00001269 .setOutput(PortNumber.CONTROLLER).build())
Amit Ghosh95e2f652017-08-23 12:49:46 +01001270 .fromApp(appId)
Matt Jeanneret3f579262018-06-14 17:16:23 -04001271 .withPriority(10000)
Amit Ghosh95e2f652017-08-23 12:49:46 +01001272 .add(new ObjectiveContext() {
1273 @Override
1274 public void onSuccess(Objective objective) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001275 log.info("DHCP {} filter for device {} on port {} {}.",
Gamze Abakaad329652018-12-20 10:12:21 +00001276 (ethType.equals(EthType.EtherType.IPV4.ethType())) ? "v4" : "v6",
Gamze Abaka838d8142019-02-21 07:06:55 +00001277 devId, port, (install) ? INSTALLED : REMOVED);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001278 }
1279
1280 @Override
1281 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001282 log.info("DHCP {} filter for device {} on port {} failed {} because {}",
Gamze Abakaad329652018-12-20 10:12:21 +00001283 (ethType.equals(EthType.EtherType.IPV4.ethType())) ? "v4" : "v6",
Gamze Abaka838d8142019-02-21 07:06:55 +00001284 devId, port, (install) ? INSTALLATION : REMOVAL,
Gamze Abakaad329652018-12-20 10:12:21 +00001285 error);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001286 }
1287 });
1288
1289 flowObjectiveService.filter(devId, dhcpUpstream);
1290 }
1291
Gamze Abaka838d8142019-02-21 07:06:55 +00001292 private void processIgmpFilteringObjectives(DeviceId devId, PortNumber port,
1293 MeterId upstreamMeterId,
1294 int techProfileId,
1295 boolean install) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001296
1297 if (enableIgmpOnProvisioning) {
1298 log.debug("Igmp provisioning is disabled.");
1299 return;
1300 }
1301
Amit Ghosh95e2f652017-08-23 12:49:46 +01001302 if (!mastershipService.isLocalMaster(devId)) {
1303 return;
1304 }
1305
Gamze Abaka641fc072018-09-04 09:16:27 +00001306 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Gamze Abaka838d8142019-02-21 07:06:55 +00001307 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
1308
1309 if (upstreamMeterId != null) {
1310 treatmentBuilder.meter(upstreamMeterId);
1311 }
1312
1313 if (techProfileId != -1) {
1314 treatmentBuilder.writeMetadata(createTechProfValueForWm(techProfileId), 0);
1315 }
Amit Ghosh95e2f652017-08-23 12:49:46 +01001316
1317 builder = install ? builder.permit() : builder.deny();
1318
1319 FilteringObjective igmp = builder
1320 .withKey(Criteria.matchInPort(port))
1321 .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
1322 .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_IGMP))
Gamze Abaka838d8142019-02-21 07:06:55 +00001323 .withMeta(treatmentBuilder
Gamze Abaka641fc072018-09-04 09:16:27 +00001324 .setOutput(PortNumber.CONTROLLER).build())
Amit Ghosh95e2f652017-08-23 12:49:46 +01001325 .fromApp(appId)
1326 .withPriority(10000)
1327 .add(new ObjectiveContext() {
1328 @Override
1329 public void onSuccess(Objective objective) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001330 log.info("Igmp filter for {} on {} {}.",
Gamze Abaka838d8142019-02-21 07:06:55 +00001331 devId, port, (install) ? INSTALLED : REMOVED);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001332 }
1333
1334 @Override
1335 public void onError(Objective objective, ObjectiveError error) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001336 log.info("Igmp filter for {} on {} failed {} because {}.",
Gamze Abaka838d8142019-02-21 07:06:55 +00001337 devId, port, (install) ? INSTALLATION : REMOVAL,
Gamze Abaka641fc072018-09-04 09:16:27 +00001338 error);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001339 }
1340 });
1341
1342 flowObjectiveService.filter(devId, igmp);
1343 }
1344
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001345 /**
Jonathan Hart403372d2018-08-22 11:44:13 -07001346 * Creates trap flows for device, including DHCP and LLDP trap on NNI and
1347 * EAPOL trap on the UNIs, if device is present in Sadis config.
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001348 *
1349 * @param dev Device to look for
1350 */
Jonathan Hart403372d2018-08-22 11:44:13 -07001351 private void checkAndCreateDeviceFlows(Device dev) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001352 // we create only for the ones we are master of
1353 if (!mastershipService.isLocalMaster(dev.id())) {
Gamze Abaka641fc072018-09-04 09:16:27 +00001354 return;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001355 }
1356 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +00001357 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Jonathan Hart403372d2018-08-22 11:44:13 -07001358 log.debug("checkAndCreateDeviceFlows: deviceInfo {}", deviceInfo);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001359
1360 if (deviceInfo != null) {
Jonathan Hart403372d2018-08-22 11:44:13 -07001361 // This is an OLT device as per Sadis, we create flows for UNI and NNI ports
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001362 for (Port p : deviceService.getPorts(dev.id())) {
1363 if (isUniPort(dev, p)) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001364 processEapolFilteringObjectives(dev.id(), p.number(), defaultBpId, null, true);
Jonathan Hart403372d2018-08-22 11:44:13 -07001365 } else {
1366 processNniFilteringObjectives(dev.id(), p.number(), true);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001367 }
1368 }
1369 }
1370 }
1371
Jonathan Hart403372d2018-08-22 11:44:13 -07001372
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001373 /**
1374 * Get the uplink for of the OLT device.
Gamze Abakaad329652018-12-20 10:12:21 +00001375 * <p>
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001376 * This assumes that the OLT has a single uplink port. When more uplink ports need to be supported
1377 * this logic needs to be changed
1378 *
1379 * @param dev Device to look for
1380 * @return The uplink Port of the OLT
1381 */
1382 private Port getUplinkPort(Device dev) {
1383 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +00001384 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001385 log.debug("getUplinkPort: deviceInfo {}", deviceInfo);
Saurav Das82b8e6d2018-10-04 15:25:12 -07001386 if (deviceInfo == null) {
1387 log.warn("Device {} is not configured in SADIS .. cannot fetch device"
1388 + " info", dev.id());
1389 return null;
1390 }
1391 // Return the port that has been configured as the uplink port of this OLT in Sadis
Gamze Abakaad329652018-12-20 10:12:21 +00001392 for (Port p : deviceService.getPorts(dev.id())) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001393 if (p.number().toLong() == deviceInfo.uplinkPort()) {
1394 log.debug("getUplinkPort: Found port {}", p);
1395 return p;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001396 }
1397 }
1398
Gamze Abaka838d8142019-02-21 07:06:55 +00001399 log.debug("getUplinkPort: " + NO_UPLINK_PORT, dev.id());
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001400 return null;
1401 }
1402
1403 /**
1404 * Return the subscriber on a port.
1405 *
Matteo Scandolo962a6ad2018-12-11 15:39:42 -08001406 * @param cp ConnectPoint on which to find the subscriber
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001407 * @return subscriber if found else null
1408 */
Matteo Scandolo962a6ad2018-12-11 15:39:42 -08001409 SubscriberAndDeviceInformation getSubscriber(ConnectPoint cp) {
1410 Port port = deviceService.getPort(cp);
1411 checkNotNull(port, "Invalid connect point");
1412 String portName = port.annotations().value(AnnotationKeys.PORT_NAME);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001413 return subsService.get(portName);
1414 }
1415
Gamze Abakaad329652018-12-20 10:12:21 +00001416 /**
1417 * Write metadata instruction value (metadata) is 8 bytes.
Gamze Abaka838d8142019-02-21 07:06:55 +00001418 * <p>
Gamze Abakaad329652018-12-20 10:12:21 +00001419 * MS 2 bytes: C Tag
1420 * Next 2 bytes: Technology Profile Id
1421 * Next 4 bytes: Port number (uni or nni)
1422 */
1423
1424 private Long createMetadata(VlanId innerVlan, int techProfileId, PortNumber egressPort) {
1425
1426 if (techProfileId == -1) {
1427 techProfileId = DEFAULT_TP_ID;
1428 }
1429
1430 return ((long) (innerVlan.id()) << 48 | (long) techProfileId << 32) | egressPort.toLong();
1431 }
1432
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001433 private boolean isUniPort(Device d, Port p) {
1434 Port ulPort = getUplinkPort(d);
1435 if (ulPort != null) {
1436 return (ulPort.number().toLong() != p.number().toLong());
1437 }
1438 return false;
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001439 }
1440
Jonathan Hart4c538002018-08-23 10:11:54 -07001441 private SubscriberAndDeviceInformation getOltInfo(Device dev) {
1442 String devSerialNo = dev.serialNumber();
Gamze Abaka641fc072018-09-04 09:16:27 +00001443 return subsService.get(devSerialNo);
Jonathan Hart4c538002018-08-23 10:11:54 -07001444 }
1445
Gamze Abaka33feef52019-02-27 08:16:47 +00001446 private MeterId getMeterIdFromBpMapping(DeviceId deviceId, String bandwidthProfile) {
1447
1448 if (bpInfoToMeter.get(bandwidthProfile) == null) {
1449 log.warn("Bandwidth Profile '{}' is not found in bandwidth profile map.", bandwidthProfile);
1450 return null;
1451 }
1452
1453 Optional<MeterKey> meterKeyForDevice = bpInfoToMeter.get(bandwidthProfile)
1454 .stream()
1455 .filter(meterKey -> meterKey.deviceId().equals(deviceId))
1456 .findFirst();
1457 return meterKeyForDevice.isPresent() ? meterKeyForDevice.get().meterId() : null;
1458 }
1459
1460 private void addMeterIdToBpMapping(DeviceId deviceId, MeterId meterId, String bandwidthProfile) {
1461
1462 if (bpInfoToMeter.get(bandwidthProfile) == null) {
1463 bpInfoToMeter.put(bandwidthProfile,
1464 new ArrayList<>(Arrays.asList(MeterKey.key(deviceId, meterId))));
1465 } else {
1466
1467 List<MeterKey> meterKeyListForBp = bpInfoToMeter.get(bandwidthProfile);
1468 meterKeyListForBp.add(MeterKey.key(deviceId, meterId));
1469 }
1470 }
1471
1472 private void removeMeterIdFromBpMapping(DeviceId deviceId, String bandwidthProfileId) {
1473 List<MeterKey> meterKeysForBp = bpInfoToMeter.get(bandwidthProfileId);
1474 if (meterKeysForBp != null) {
1475 meterKeysForBp.stream()
1476 .filter(meterKey -> meterKey.deviceId().equals(deviceId))
1477 .findFirst().ifPresent(mk -> {
1478 meterKeysForBp.remove(mk);
1479 programmedMeters.remove(mk);
1480 });
1481 }
1482 }
1483
alshabibf0e7e702015-05-30 18:22:36 -07001484 private class InternalDeviceListener implements DeviceListener {
1485 @Override
1486 public void event(DeviceEvent event) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001487 eventExecutor.execute(() -> {
1488 DeviceId devId = event.subject().id();
1489 Device dev = event.subject();
Gamze Abaka838d8142019-02-21 07:06:55 +00001490 Port port = event.port();
Jonathan Hart4c538002018-08-23 10:11:54 -07001491
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001492 if (event.type() == DeviceEvent.Type.PORT_STATS_UPDATED) {
1493 return;
1494 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001495
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001496 if (getOltInfo(dev) == null) {
1497 log.debug("No device info found, this is not an OLT");
1498 return;
1499 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001500
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001501 log.debug("OLT got {} event for {}", event.type(), event.subject());
Jonathan Hart4c538002018-08-23 10:11:54 -07001502
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001503 switch (event.type()) {
1504 //TODO: Port handling and bookkeeping should be improved once
1505 // olt firmware handles correct behaviour.
1506 case PORT_ADDED:
Gamze Abaka838d8142019-02-21 07:06:55 +00001507 if (isUniPort(dev, port)) {
1508 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, port));
Jonathan Hart4c538002018-08-23 10:11:54 -07001509
Gamze Abaka838d8142019-02-21 07:06:55 +00001510 if (port.isEnabled()) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001511 processEapolFilteringObjectives(devId, port.number(), defaultBpId,
1512 null, true);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001513 }
1514 } else {
1515 checkAndCreateDeviceFlows(dev);
1516 }
1517 break;
1518 case PORT_REMOVED:
Gamze Abaka838d8142019-02-21 07:06:55 +00001519 if (isUniPort(dev, port)) {
1520 if (port.isEnabled()) {
1521 processEapolFilteringObjectives(devId, port.number(),
1522 getCurrentBandwidthProfile(new ConnectPoint(devId, port.number())),
Gamze Abaka33feef52019-02-27 08:16:47 +00001523 null, false);
1524
Gamze Abaka838d8142019-02-21 07:06:55 +00001525 removeSubscriber(new ConnectPoint(devId, port.number()));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001526 }
1527
Gamze Abaka838d8142019-02-21 07:06:55 +00001528 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, port));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001529 }
1530
1531 break;
1532 case PORT_UPDATED:
Gamze Abaka838d8142019-02-21 07:06:55 +00001533 if (!isUniPort(dev, port)) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001534 break;
1535 }
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001536
Gamze Abaka838d8142019-02-21 07:06:55 +00001537 if (port.isEnabled()) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001538 processEapolFilteringObjectives(devId, port.number(), defaultBpId,
1539 null, true);
1540
Gamze Abaka838d8142019-02-21 07:06:55 +00001541 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, port));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001542 } else {
Gamze Abaka838d8142019-02-21 07:06:55 +00001543 processEapolFilteringObjectives(devId, port.number(),
1544 getCurrentBandwidthProfile(new ConnectPoint(devId, port.number())),
Gamze Abaka33feef52019-02-27 08:16:47 +00001545 null, false);
Gamze Abaka838d8142019-02-21 07:06:55 +00001546 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, port));
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001547 }
alshabibbb83aa22016-02-10 15:08:23 -08001548 break;
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001549 case DEVICE_ADDED:
alshabib7c190012016-02-09 18:22:33 -08001550 post(new AccessDeviceEvent(
1551 AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
1552 null, null));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001553
1554 // Send UNI_ADDED events for all existing ports
1555 deviceService.getPorts(devId).stream()
1556 .filter(p -> isUniPort(dev, p))
1557 .filter(Port::isEnabled)
1558 .forEach(p -> post(new AccessDeviceEvent(
1559 AccessDeviceEvent.Type.UNI_ADDED, devId, p)));
1560
Jonathan Hart403372d2018-08-22 11:44:13 -07001561 checkAndCreateDeviceFlows(dev);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001562 break;
1563 case DEVICE_REMOVED:
1564 deviceService.getPorts(devId).stream()
1565 .filter(p -> isUniPort(dev, p))
1566 .forEach(p -> post(new AccessDeviceEvent(
1567 AccessDeviceEvent.Type.UNI_REMOVED, devId, p)));
1568
alshabib7c190012016-02-09 18:22:33 -08001569 post(new AccessDeviceEvent(
1570 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
1571 null, null));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001572 break;
1573 case DEVICE_AVAILABILITY_CHANGED:
1574 if (deviceService.isAvailable(devId)) {
1575 post(new AccessDeviceEvent(
1576 AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
1577 null, null));
1578 checkAndCreateDeviceFlows(dev);
1579 } else {
1580 post(new AccessDeviceEvent(
1581 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
1582 null, null));
1583 }
1584 break;
1585 case DEVICE_UPDATED:
1586 case DEVICE_SUSPENDED:
1587 case PORT_STATS_UPDATED:
1588 default:
1589 return;
1590 }
1591 });
alshabibf0e7e702015-05-30 18:22:36 -07001592 }
Gamze Abaka838d8142019-02-21 07:06:55 +00001593
1594 private String getCurrentBandwidthProfile(ConnectPoint connectPoint) {
1595 SubscriberAndDeviceInformation sub = programmedSubs.get(connectPoint);
1596 if (sub != null) {
1597 return sub.upstreamBandwidthProfile();
1598 }
1599 return defaultBpId;
1600 }
alshabibf0e7e702015-05-30 18:22:36 -07001601 }
Gamze Abaka641fc072018-09-04 09:16:27 +00001602
1603 private class InternalMeterListener implements MeterListener {
1604
1605 @Override
1606 public void event(MeterEvent meterEvent) {
1607 if (deleteMeters && MeterEvent.Type.METER_REFERENCE_COUNT_ZERO.equals(meterEvent.type())) {
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001608 log.info("Zero Count Meter Event is received. Meter is {}", meterEvent.subject());
Gamze Abaka641fc072018-09-04 09:16:27 +00001609 Meter meter = meterEvent.subject();
Gamze Abaka33feef52019-02-27 08:16:47 +00001610 if (meter != null && appId.equals(meter.appId()) &&
1611 !programmedMeters.contains(MeterKey.key(meter.deviceId(), meter.id()))) {
Gamze Abaka641fc072018-09-04 09:16:27 +00001612 deleteMeter(meter.deviceId(), meter.id());
1613 }
1614 } else if (MeterEvent.Type.METER_REMOVED.equals(meterEvent.type())) {
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001615 log.info("Meter removed event is received. Meter is {}", meterEvent.subject());
Gamze Abaka641fc072018-09-04 09:16:27 +00001616 removeMeterFromBpMap(meterEvent.subject());
1617 }
1618 }
1619
1620 private void deleteMeter(DeviceId deviceId, MeterId meterId) {
1621 Meter meter = meterService.getMeter(deviceId, meterId);
Gamze Abaka838d8142019-02-21 07:06:55 +00001622 if (meter != null) {
1623 MeterRequest meterRequest = DefaultMeterRequest.builder()
1624 .withBands(meter.bands())
1625 .withUnit(meter.unit())
1626 .forDevice(deviceId)
1627 .fromApp(appId)
1628 .burst()
1629 .remove();
Gamze Abaka641fc072018-09-04 09:16:27 +00001630
Gamze Abaka838d8142019-02-21 07:06:55 +00001631 meterService.withdraw(meterRequest, meterId);
1632 }
Gamze Abaka641fc072018-09-04 09:16:27 +00001633 }
1634
1635 private void removeMeterFromBpMap(Meter meter) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001636 bpInfoToMeter.values().forEach(meterKeys -> meterKeys.stream()
1637 .filter(meterKey -> (meterKey.deviceId().equals(meter.deviceId()))
1638 && meterKey.meterId().equals(meter.id())).findFirst().
1639 ifPresent(mk -> {
1640 meterKeys.remove(mk);
1641 log.info("Deleted from the internal map. MeterKey {}", mk);
1642 log.info("Programmed meters {}", programmedMeters);
1643 }));
Gamze Abaka641fc072018-09-04 09:16:27 +00001644 }
1645 }
1646}