blob: 1e002374108ccc43c58a2de0112e238481447632 [file] [log] [blame]
alshabibf0e7e702015-05-30 18:22:36 -07001/*
Brian O'Connord6a135a2017-08-03 22:46:05 -07002 * Copyright 2016-present Open Networking Foundation
alshabibf0e7e702015-05-30 18:22:36 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
alshabib36a4d732016-06-01 16:03:59 -070016package org.opencord.olt.impl;
alshabibf0e7e702015-05-30 18:22:36 -070017
Saurav Das82b8e6d2018-10-04 15:25:12 -070018import static com.google.common.base.Preconditions.checkNotNull;
19import static com.google.common.base.Strings.isNullOrEmpty;
20import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
21import static org.onlab.util.Tools.get;
22import static org.onlab.util.Tools.groupedThreads;
23import static org.slf4j.LoggerFactory.getLogger;
24
25import java.util.AbstractMap;
Amit Ghoshe1d3f092018-10-09 19:44:33 +010026import java.util.Arrays;
Saurav Das82b8e6d2018-10-04 15:25:12 -070027import java.util.ArrayList;
28import java.util.Collection;
29import java.util.Dictionary;
30import java.util.List;
31import java.util.Map;
32import java.util.Optional;
33import java.util.Properties;
34import java.util.concurrent.CompletableFuture;
35import java.util.concurrent.ExecutorService;
36import java.util.concurrent.Executors;
37
alshabibf0e7e702015-05-30 18:22:36 -070038import org.apache.felix.scr.annotations.Activate;
39import org.apache.felix.scr.annotations.Component;
40import org.apache.felix.scr.annotations.Deactivate;
alshabibe0559672016-02-21 14:49:51 -080041import org.apache.felix.scr.annotations.Modified;
42import org.apache.felix.scr.annotations.Property;
alshabibf0e7e702015-05-30 18:22:36 -070043import org.apache.felix.scr.annotations.Reference;
44import org.apache.felix.scr.annotations.ReferenceCardinality;
Jonathan Harte533a422015-10-20 17:31:24 -070045import org.apache.felix.scr.annotations.Service;
alshabibdec2e252016-01-15 12:20:25 -080046import org.onlab.packet.EthType;
Amit Ghosh95e2f652017-08-23 12:49:46 +010047import org.onlab.packet.IPv4;
Matteo Scandolo63460d12018-11-02 16:19:04 -070048import org.onlab.packet.IPv6;
Amit Ghosh95e2f652017-08-23 12:49:46 +010049import org.onlab.packet.TpPort;
alshabibf0e7e702015-05-30 18:22:36 -070050import org.onlab.packet.VlanId;
Amit Ghosh95e2f652017-08-23 12:49:46 +010051import org.onlab.util.Tools;
alshabibe0559672016-02-21 14:49:51 -080052import org.onosproject.cfg.ComponentConfigService;
alshabibf0e7e702015-05-30 18:22:36 -070053import org.onosproject.core.ApplicationId;
54import org.onosproject.core.CoreService;
alshabib8e4fd2f2016-01-12 15:55:53 -080055import org.onosproject.event.AbstractListenerManager;
alshabib09753b52016-03-04 14:55:19 -080056import org.onosproject.mastership.MastershipService;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010057import org.onosproject.net.AnnotationKeys;
Jonathan Harte533a422015-10-20 17:31:24 -070058import org.onosproject.net.ConnectPoint;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010059import org.onosproject.net.Device;
alshabibf0e7e702015-05-30 18:22:36 -070060import org.onosproject.net.DeviceId;
alshabibdec2e252016-01-15 12:20:25 -080061import org.onosproject.net.Port;
alshabibf0e7e702015-05-30 18:22:36 -070062import org.onosproject.net.PortNumber;
63import org.onosproject.net.device.DeviceEvent;
64import org.onosproject.net.device.DeviceListener;
65import org.onosproject.net.device.DeviceService;
66import org.onosproject.net.flow.DefaultTrafficSelector;
67import org.onosproject.net.flow.DefaultTrafficTreatment;
68import org.onosproject.net.flow.TrafficSelector;
69import org.onosproject.net.flow.TrafficTreatment;
alshabibdec2e252016-01-15 12:20:25 -080070import org.onosproject.net.flow.criteria.Criteria;
71import org.onosproject.net.flowobjective.DefaultFilteringObjective;
alshabibf0e7e702015-05-30 18:22:36 -070072import org.onosproject.net.flowobjective.DefaultForwardingObjective;
alshabibdec2e252016-01-15 12:20:25 -080073import org.onosproject.net.flowobjective.FilteringObjective;
alshabibf0e7e702015-05-30 18:22:36 -070074import org.onosproject.net.flowobjective.FlowObjectiveService;
75import org.onosproject.net.flowobjective.ForwardingObjective;
alshabib3ea82642016-01-12 18:06:53 -080076import org.onosproject.net.flowobjective.Objective;
77import org.onosproject.net.flowobjective.ObjectiveContext;
78import org.onosproject.net.flowobjective.ObjectiveError;
Amit Ghoshe1d3f092018-10-09 19:44:33 +010079import org.onosproject.store.serializers.KryoNamespaces;
80import org.onosproject.store.service.ConsistentMultimap;
81import org.onosproject.store.service.Serializer;
82import org.onosproject.store.service.StorageService;
Gamze Abaka641fc072018-09-04 09:16:27 +000083import org.onosproject.net.meter.Band;
84import org.onosproject.net.meter.DefaultBand;
85import org.onosproject.net.meter.DefaultMeterRequest;
86import org.onosproject.net.meter.Meter;
87import org.onosproject.net.meter.MeterService;
88import org.onosproject.net.meter.MeterListener;
89import org.onosproject.net.meter.MeterRequest;
90import org.onosproject.net.meter.MeterId;
91import org.onosproject.net.meter.MeterEvent;
alshabib36a4d732016-06-01 16:03:59 -070092import org.opencord.olt.AccessDeviceEvent;
93import org.opencord.olt.AccessDeviceListener;
94import org.opencord.olt.AccessDeviceService;
Amit Ghosh31939522018-08-16 13:28:21 +010095import org.opencord.olt.AccessSubscriberId;
Gamze Abaka641fc072018-09-04 09:16:27 +000096import org.opencord.sadis.BandwidthProfileInformation;
97import org.opencord.sadis.BaseInformationService;
98import org.opencord.sadis.SadisService;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010099import org.opencord.sadis.SubscriberAndDeviceInformation;
alshabibe0559672016-02-21 14:49:51 -0800100import org.osgi.service.component.ComponentContext;
alshabibf0e7e702015-05-30 18:22:36 -0700101import org.slf4j.Logger;
102
Gamze Abaka641fc072018-09-04 09:16:27 +0000103import java.util.HashMap;
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100104
Saurav Das82b8e6d2018-10-04 15:25:12 -0700105import com.google.common.collect.ImmutableMap;
106import com.google.common.collect.Maps;
alshabibf0e7e702015-05-30 18:22:36 -0700107
108/**
Jonathan Harte533a422015-10-20 17:31:24 -0700109 * Provisions rules on access devices.
alshabibf0e7e702015-05-30 18:22:36 -0700110 */
Jonathan Harte533a422015-10-20 17:31:24 -0700111@Service
alshabibf0e7e702015-05-30 18:22:36 -0700112@Component(immediate = true)
alshabib8e4fd2f2016-01-12 15:55:53 -0800113public class Olt
114 extends AbstractListenerManager<AccessDeviceEvent, AccessDeviceListener>
115 implements AccessDeviceService {
Charles Chan54f110f2017-01-20 11:22:42 -0800116 private static final String APP_NAME = "org.opencord.olt";
alshabibe0559672016-02-21 14:49:51 -0800117
118 private static final short DEFAULT_VLAN = 0;
Gamze Abakaad329652018-12-20 10:12:21 +0000119 private static final int DEFAULT_TP_ID = 10;
120 private static final String DEFAULT_BP_ID = "Default";
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100121 private static final String ADDITIONAL_VLANS = "additional-vlans";
alshabibe0559672016-02-21 14:49:51 -0800122
alshabibf0e7e702015-05-30 18:22:36 -0700123 private final Logger log = getLogger(getClass());
124
125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
126 protected FlowObjectiveService flowObjectiveService;
127
128 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabib09753b52016-03-04 14:55:19 -0800129 protected MastershipService mastershipService;
130
131 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibf0e7e702015-05-30 18:22:36 -0700132 protected DeviceService deviceService;
133
134 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
135 protected CoreService coreService;
136
Jonathan Harte533a422015-10-20 17:31:24 -0700137 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibe0559672016-02-21 14:49:51 -0800138 protected ComponentConfigService componentConfigService;
139
alshabib4ceaed32016-03-03 18:00:58 -0800140 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Gamze Abaka641fc072018-09-04 09:16:27 +0000141 protected SadisService sadisService;
142
143 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
144 protected MeterService meterService;
alshabibe0559672016-02-21 14:49:51 -0800145
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100146 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
147 protected StorageService storageService;
148
alshabibe0559672016-02-21 14:49:51 -0800149 @Property(name = "defaultVlan", intValue = DEFAULT_VLAN,
150 label = "Default VLAN RG<->ONU traffic")
151 private int defaultVlan = DEFAULT_VLAN;
152
Matt Jeanneret3f579262018-06-14 17:16:23 -0400153 @Property(name = "enableDhcpOnProvisioning", boolValue = true,
154 label = "Create the DHCP Flow rules when a subscriber is provisioned")
155 protected boolean enableDhcpOnProvisioning = false;
156
Matteo Scandolo63460d12018-11-02 16:19:04 -0700157 @Property(name = "enableDhcpV4", boolValue = true,
158 label = "Enable flows for DHCP v4")
159 protected boolean enableDhcpV4 = true;
160
161 @Property(name = "enableDhcpV6", boolValue = true,
162 label = "Enable flows for DHCP v6")
163 protected boolean enableDhcpV6 = false;
164
Matt Jeanneret3f579262018-06-14 17:16:23 -0400165 @Property(name = "enableIgmpOnProvisioning", boolValue = false,
166 label = "Create IGMP Flow rules when a subscriber is provisioned")
167 protected boolean enableIgmpOnProvisioning = false;
Amit Ghosh95e2f652017-08-23 12:49:46 +0100168
Gamze Abaka641fc072018-09-04 09:16:27 +0000169 // needed because no implementation for meter statistics in Voltha yet
170 @Property(name = "deleteMeters", boolValue = false,
171 label = "Deleting Meters based on flow count statistics")
172 protected boolean deleteMeters = false;
173
Gamze Abakaad329652018-12-20 10:12:21 +0000174 @Property(name = "defaultTechProfileId", intValue = DEFAULT_TP_ID,
175 label = "Default technology profile id that is used for authentication trap flows")
176 protected int defaultTechProfileId = DEFAULT_TP_ID;
177
178 @Property(name = "defaultBpId", value = DEFAULT_BP_ID,
179 label = "Default bandwidth profile id that is used for authentication trap flows")
180 protected String defaultBpId = DEFAULT_BP_ID;
181
alshabibf0e7e702015-05-30 18:22:36 -0700182 private final DeviceListener deviceListener = new InternalDeviceListener();
Gamze Abaka641fc072018-09-04 09:16:27 +0000183 private final MeterListener meterListener = new InternalMeterListener();
alshabibf0e7e702015-05-30 18:22:36 -0700184
185 private ApplicationId appId;
Gamze Abaka641fc072018-09-04 09:16:27 +0000186 protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
187 private BaseInformationService<BandwidthProfileInformation> bpService;
alshabibf0e7e702015-05-30 18:22:36 -0700188
Gamze Abaka641fc072018-09-04 09:16:27 +0000189 private Map<String, MeterId> bpInfoToMeter = new HashMap<>();
190
191 private ExecutorService oltInstallers = Executors.newFixedThreadPool(4,
192 groupedThreads("onos/olt-service",
193 "olt-installer-%d"));
alshabibf0e7e702015-05-30 18:22:36 -0700194
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100195 private ConsistentMultimap<ConnectPoint, Map.Entry<VlanId, VlanId>> additionalVlans;
196
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700197 protected ExecutorService eventExecutor;
198
Saurav Das82b8e6d2018-10-04 15:25:12 -0700199 private Map<ConnectPoint, SubscriberAndDeviceInformation> programmedSubs;
200
alshabibf0e7e702015-05-30 18:22:36 -0700201 @Activate
alshabibe0559672016-02-21 14:49:51 -0800202 public void activate(ComponentContext context) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700203 eventExecutor = newSingleThreadScheduledExecutor(groupedThreads("onos/olt", "events-%d", log));
alshabibe0559672016-02-21 14:49:51 -0800204 modified(context);
Charles Chan54f110f2017-01-20 11:22:42 -0800205 appId = coreService.registerApplication(APP_NAME);
alshabibe0559672016-02-21 14:49:51 -0800206 componentConfigService.registerProperties(getClass());
Saurav Das82b8e6d2018-10-04 15:25:12 -0700207 programmedSubs = Maps.newConcurrentMap();
alshabibc4dfe852015-06-05 13:35:13 -0700208
alshabib8e4fd2f2016-01-12 15:55:53 -0800209 eventDispatcher.addSink(AccessDeviceEvent.class, listenerRegistry);
210
Gamze Abaka641fc072018-09-04 09:16:27 +0000211 subsService = sadisService.getSubscriberInfoService();
212 bpService = sadisService.getBandwidthProfileService();
213
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100214 // look for all provisioned devices in Sadis and create EAPOL flows for the
215 // UNI ports
216 Iterable<Device> devices = deviceService.getDevices();
217 for (Device d : devices) {
Jonathan Hart403372d2018-08-22 11:44:13 -0700218 checkAndCreateDeviceFlows(d);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100219 }
alshabib4ceaed32016-03-03 18:00:58 -0800220
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100221 additionalVlans = storageService.<ConnectPoint, Map.Entry<VlanId, VlanId>>consistentMultimapBuilder()
222 .withName(ADDITIONAL_VLANS)
223 .withSerializer(Serializer.using(Arrays.asList(KryoNamespaces.API),
224 AbstractMap.SimpleEntry.class))
225 .build();
226
alshabibba357492016-01-27 13:49:46 -0800227 deviceService.addListener(deviceListener);
Gamze Abaka641fc072018-09-04 09:16:27 +0000228 meterService.addListener(meterListener);
alshabibba357492016-01-27 13:49:46 -0800229
alshabibf0e7e702015-05-30 18:22:36 -0700230 log.info("Started with Application ID {}", appId.id());
231 }
232
233 @Deactivate
234 public void deactivate() {
alshabibe0559672016-02-21 14:49:51 -0800235 componentConfigService.unregisterProperties(getClass(), false);
alshabib62e9ce72016-02-11 17:31:36 -0800236 deviceService.removeListener(deviceListener);
Gamze Abaka641fc072018-09-04 09:16:27 +0000237 meterService.removeListener(meterListener);
Jonathan Hart5f1c8142018-07-24 17:31:59 -0700238 eventDispatcher.removeSink(AccessDeviceEvent.class);
alshabibf0e7e702015-05-30 18:22:36 -0700239 log.info("Stopped");
240 }
241
alshabibe0559672016-02-21 14:49:51 -0800242 @Modified
243 public void modified(ComponentContext context) {
244 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
245
246 try {
247 String s = get(properties, "defaultVlan");
248 defaultVlan = isNullOrEmpty(s) ? DEFAULT_VLAN : Integer.parseInt(s.trim());
Amit Ghosh95e2f652017-08-23 12:49:46 +0100249
Matt Jeanneret3f579262018-06-14 17:16:23 -0400250 Boolean o = Tools.isPropertyEnabled(properties, "enableDhcpOnProvisioning");
Amit Ghosh95e2f652017-08-23 12:49:46 +0100251 if (o != null) {
Matt Jeanneret3f579262018-06-14 17:16:23 -0400252 enableDhcpOnProvisioning = o;
Amit Ghosh95e2f652017-08-23 12:49:46 +0100253 }
Matt Jeanneret3f579262018-06-14 17:16:23 -0400254
Matteo Scandolo63460d12018-11-02 16:19:04 -0700255 Boolean v4 = Tools.isPropertyEnabled(properties, "enableDhcpV4");
256 if (v4 != null) {
257 enableDhcpV4 = v4;
258 }
259
260 Boolean v6 = Tools.isPropertyEnabled(properties, "enableDhcpV6");
261 if (v6 != null) {
262 enableDhcpV6 = v6;
263 }
264
Matt Jeanneret3f579262018-06-14 17:16:23 -0400265 Boolean p = Tools.isPropertyEnabled(properties, "enableIgmpOnProvisioning");
266 if (p != null) {
267 enableIgmpOnProvisioning = p;
268 }
269
Matteo Scandolo63460d12018-11-02 16:19:04 -0700270 log.info("DHCP Settings [enableDhcpOnProvisioning: {}, enableDhcpV4: {}, enableDhcpV6: {}]",
Gamze Abakaad329652018-12-20 10:12:21 +0000271 enableDhcpOnProvisioning, enableDhcpV4, enableDhcpV6);
Matteo Scandolo63460d12018-11-02 16:19:04 -0700272
Gamze Abaka641fc072018-09-04 09:16:27 +0000273 Boolean d = Tools.isPropertyEnabled(properties, "deleteMeters");
274 if (d != null) {
275 deleteMeters = d;
276 }
277
Gamze Abakaad329652018-12-20 10:12:21 +0000278 String tpId = get(properties, "defaultTechProfileId");
279 defaultTechProfileId = isNullOrEmpty(s) ? DEFAULT_TP_ID : Integer.parseInt(tpId.trim());
280
281 String bpId = get(properties, "defaultBpId");
282 defaultBpId = bpId;
283
alshabibe0559672016-02-21 14:49:51 -0800284 } catch (Exception e) {
285 defaultVlan = DEFAULT_VLAN;
286 }
287 }
288
alshabib32232c82016-02-25 17:57:24 -0500289 @Override
Amit Ghosh31939522018-08-16 13:28:21 +0100290 public boolean provisionSubscriber(ConnectPoint port) {
Jonathan Hart94b90492018-04-24 14:02:25 -0700291 checkNotNull(deviceService.getPort(port.deviceId(), port.port()),
292 "Invalid connect point");
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100293 // Find the subscriber on this connect point
294 SubscriberAndDeviceInformation sub = getSubscriber(port);
295 if (sub == null) {
296 log.warn("No subscriber found for {}", port);
Amit Ghosh31939522018-08-16 13:28:21 +0100297 return false;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100298 }
Jonathan Harte533a422015-10-20 17:31:24 -0700299
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100300 // Get the uplink port
301 Port uplinkPort = getUplinkPort(deviceService.getDevice(port.deviceId()));
302 if (uplinkPort == null) {
303 log.warn("No uplink port found for OLT device {}", port.deviceId());
Amit Ghosh31939522018-08-16 13:28:21 +0100304 return false;
Jonathan Harte533a422015-10-20 17:31:24 -0700305 }
306
Matt Jeanneret3f579262018-06-14 17:16:23 -0400307 if (enableDhcpOnProvisioning) {
Saurav Dasacc5eeb2018-10-11 10:58:01 -0700308 processDhcpFilteringObjectives(port.deviceId(), port.port(), true,
Gamze Abaka641fc072018-09-04 09:16:27 +0000309 true);
Amit Ghosh95e2f652017-08-23 12:49:46 +0100310 }
Saurav Das82b8e6d2018-10-04 15:25:12 -0700311 log.info("Programming vlans for subscriber: {}", sub);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100312 Optional<VlanId> defaultVlan = Optional.empty();
Gamze Abaka641fc072018-09-04 09:16:27 +0000313 provisionVlans(port, uplinkPort.number(), defaultVlan, sub);
Amit Ghosh95e2f652017-08-23 12:49:46 +0100314
Matt Jeanneret3f579262018-06-14 17:16:23 -0400315 if (enableIgmpOnProvisioning) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100316 processIgmpFilteringObjectives(port.deviceId(), port.port(), true);
Amit Ghosh95e2f652017-08-23 12:49:46 +0100317 }
Saurav Das82b8e6d2018-10-04 15:25:12 -0700318 // cache subscriber info
319 programmedSubs.put(port, sub);
Amit Ghosh31939522018-08-16 13:28:21 +0100320 return true;
alshabibb7a9e172016-01-13 11:23:53 -0800321 }
322
323 @Override
Amit Ghosh31939522018-08-16 13:28:21 +0100324 public boolean removeSubscriber(ConnectPoint port) {
Matteo Scandolo962a6ad2018-12-11 15:39:42 -0800325 // Get the subscriber connected to this port from the local cache
326 // as if we don't know about the subscriber there's no need to remove it
327 SubscriberAndDeviceInformation subscriber = programmedSubs.get(port);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100328 if (subscriber == null) {
Matteo Scandolo962a6ad2018-12-11 15:39:42 -0800329 log.warn("Subscriber on port {} was not previously programmed, no need to remove it", port);
330 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800331 }
332
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100333 // Get the uplink port
334 Port uplinkPort = getUplinkPort(deviceService.getDevice(port.deviceId()));
335 if (uplinkPort == null) {
336 log.warn("No uplink port found for OLT device {}", port.deviceId());
Amit Ghosh31939522018-08-16 13:28:21 +0100337 return false;
alshabib4ceaed32016-03-03 18:00:58 -0800338 }
339
Matt Jeanneret3f579262018-06-14 17:16:23 -0400340 if (enableDhcpOnProvisioning) {
Saurav Dasacc5eeb2018-10-11 10:58:01 -0700341 processDhcpFilteringObjectives(port.deviceId(), port.port(), false,
Gamze Abaka641fc072018-09-04 09:16:27 +0000342 true);
Amit Ghosh95e2f652017-08-23 12:49:46 +0100343 }
344
Saurav Das82b8e6d2018-10-04 15:25:12 -0700345 log.info("Removing programmed vlans for subscriber: {}", subscriber);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100346 Optional<VlanId> defaultVlan = Optional.empty();
Gamze Abaka641fc072018-09-04 09:16:27 +0000347 unprovisionSubscriber(port.deviceId(), uplinkPort.number(), port.port(), subscriber, defaultVlan);
alshabibbf23a1f2016-01-14 17:27:11 -0800348
Matt Jeanneret3f579262018-06-14 17:16:23 -0400349 if (enableIgmpOnProvisioning) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100350 processIgmpFilteringObjectives(port.deviceId(), port.port(), false);
Amit Ghosh95e2f652017-08-23 12:49:46 +0100351 }
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100352
353 // Remove if there are any flows for the additional Vlans
354 Collection<? extends Map.Entry<VlanId, VlanId>> vlansList = additionalVlans.get(port).value();
355
356 // Remove the flows for the additional vlans for this subscriber
357 for (Map.Entry<VlanId, VlanId> vlans : vlansList) {
358 unprovisionTransparentFlows(port.deviceId(), uplinkPort.number(), port.port(),
359 vlans.getValue(), vlans.getKey());
360
361 // Remove it from the map also
362 additionalVlans.remove(port, vlans);
363 }
364
Saurav Das82b8e6d2018-10-04 15:25:12 -0700365 programmedSubs.remove(port);
Amit Ghosh31939522018-08-16 13:28:21 +0100366 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800367 }
368
Amit Ghosh31939522018-08-16 13:28:21 +0100369 @Override
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100370 public boolean provisionSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag, Optional<VlanId> cTag) {
Amit Ghosh31939522018-08-16 13:28:21 +0100371 // Check if we can find the connect point to which this subscriber is connected
372 ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
373 if (subsPort == null) {
374 log.warn("ConnectPoint for {} not found", subscriberId);
375 return false;
376 }
377
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100378 if (!sTag.isPresent() && !cTag.isPresent()) {
379 return provisionSubscriber(subsPort);
380 } else if (sTag.isPresent() && cTag.isPresent()) {
381 Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
382 if (uplinkPort == null) {
383 log.warn("No uplink port found for OLT device {}", subsPort.deviceId());
384 return false;
385 }
386
387 provisionTransparentFlows(subsPort.deviceId(), uplinkPort.number(), subsPort.port(),
388 cTag.get(), sTag.get());
389 return true;
390 } else {
391 log.warn("Provisioning failed for subscriber: {}", subscriberId);
392 return false;
393 }
Amit Ghosh31939522018-08-16 13:28:21 +0100394 }
Amit Ghosh95e2f652017-08-23 12:49:46 +0100395
alshabibe0559672016-02-21 14:49:51 -0800396 @Override
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100397 public boolean removeSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag, Optional<VlanId> cTag) {
Amit Ghosh31939522018-08-16 13:28:21 +0100398 // Check if we can find the connect point to which this subscriber is connected
399 ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
400 if (subsPort == null) {
401 log.warn("ConnectPoint for {} not found", subscriberId);
402 return false;
403 }
404
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100405 if (!sTag.isPresent() && !cTag.isPresent()) {
406 return removeSubscriber(subsPort);
407 } else if (sTag.isPresent() && cTag.isPresent()) {
408 // Get the uplink port
409 Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
410 if (uplinkPort == null) {
411 log.warn("No uplink port found for OLT device {}", subsPort.deviceId());
412 return false;
413 }
414
415 unprovisionTransparentFlows(subsPort.deviceId(), uplinkPort.number(), subsPort.port(),
416 cTag.get(), sTag.get());
417 return true;
418 } else {
419 log.warn("Removing subscriber failed for: {}", subscriberId);
420 return false;
421 }
Amit Ghosh31939522018-08-16 13:28:21 +0100422 }
423
424 @Override
425 public Collection<Map.Entry<ConnectPoint, Map.Entry<VlanId, VlanId>>> getSubscribers() {
426 ArrayList<Map.Entry<ConnectPoint, Map.Entry<VlanId, VlanId>>> subs = new ArrayList<>();
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100427
Saurav Das82b8e6d2018-10-04 15:25:12 -0700428 // Get the subscribers for all the devices configured in sadis
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100429 // If the port is UNI, is enabled and exists in Sadis then copy it
430 for (Device d : deviceService.getDevices()) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700431 if (getOltInfo(d) == null) {
432 continue; // not an olt, or not configured in sadis
433 }
Gamze Abakaad329652018-12-20 10:12:21 +0000434 for (Port p : deviceService.getPorts(d.id())) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100435 if (isUniPort(d, p) && p.isEnabled()) {
436 ConnectPoint cp = new ConnectPoint(d.id(), p.number());
437
438 SubscriberAndDeviceInformation sub = getSubscriber(cp);
439 if (sub != null) {
Amit Ghosh31939522018-08-16 13:28:21 +0100440 Map.Entry<VlanId, VlanId> vlans = new AbstractMap.SimpleEntry(sub.sTag(), sub.cTag());
441 subs.add(new AbstractMap.SimpleEntry(cp, vlans));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100442 }
443 }
444 }
445 }
446
447 return subs;
Jonathan Hartfd6c1b32016-03-08 14:09:09 -0800448 }
449
450 @Override
Saurav Das82b8e6d2018-10-04 15:25:12 -0700451 public ImmutableMap<ConnectPoint, SubscriberAndDeviceInformation> getProgSubs() {
452 return ImmutableMap.copyOf(programmedSubs);
453 }
454
455 @Override
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100456 public List<DeviceId> fetchOlts() {
457 // look through all the devices and find the ones that are OLTs as per Sadis
458 List<DeviceId> olts = new ArrayList<>();
459 Iterable<Device> devices = deviceService.getDevices();
460 for (Device d : devices) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700461 if (getOltInfo(d) != null) {
462 // So this is indeed an OLT device
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100463 olts.add(d.id());
464 }
465 }
466 return olts;
alshabibe0559672016-02-21 14:49:51 -0800467 }
468
Amit Ghosh31939522018-08-16 13:28:21 +0100469 /**
470 * Finds the connect point to which a subscriber is connected.
471 *
472 * @param id The id of the subscriber, this is the same ID as in Sadis
473 * @return Subscribers ConnectPoint if found else null
474 */
475 private ConnectPoint findSubscriberConnectPoint(String id) {
476
477 Iterable<Device> devices = deviceService.getDevices();
478 for (Device d : devices) {
479 for (Port p : deviceService.getPorts(d.id())) {
480 log.trace("Comparing {} with {}", p.annotations().value(AnnotationKeys.PORT_NAME), id);
481 if (p.annotations().value(AnnotationKeys.PORT_NAME).equals(id)) {
482 log.debug("Found on device {} port {}", d.id(), p.number());
483 return new ConnectPoint(d.id(), p.number());
484 }
485 }
486 }
487 return null;
488 }
489
Gamze Abaka641fc072018-09-04 09:16:27 +0000490 private BandwidthProfileInformation getBandwidthProfileInformation(String bandwidthProfile) {
491 if (bandwidthProfile == null) {
492 return null;
493 }
494 return bpService.get(bandwidthProfile);
495 }
496
alshabibbf23a1f2016-01-14 17:27:11 -0800497 private void unprovisionSubscriber(DeviceId deviceId, PortNumber uplink,
Gamze Abaka641fc072018-09-04 09:16:27 +0000498 PortNumber subscriberPort, SubscriberAndDeviceInformation subscriber,
499 Optional<VlanId> defaultVlan) {
alshabibbf23a1f2016-01-14 17:27:11 -0800500
501 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
502 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
503
Gamze Abaka641fc072018-09-04 09:16:27 +0000504 VlanId deviceVlan = subscriber.sTag();
505 VlanId subscriberVlan = subscriber.cTag();
506
507 MeterId upstreamMeterId = bpInfoToMeter.get(subscriber.upstreamBandwidthProfile());
508 MeterId downstreamMeterId = bpInfoToMeter.get(subscriber.downstreamBandwidthProfile());
509
alshabib4ceaed32016-03-03 18:00:58 -0800510 ForwardingObjective.Builder upFwd = upBuilder(uplink, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000511 subscriberVlan, deviceVlan,
512 defaultVlan, upstreamMeterId, subscriber.technologyProfileId());
alshabib4ceaed32016-03-03 18:00:58 -0800513 ForwardingObjective.Builder downFwd = downBuilder(uplink, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000514 subscriberVlan, deviceVlan,
515 defaultVlan, downstreamMeterId, subscriber.technologyProfileId());
alshabibbf23a1f2016-01-14 17:27:11 -0800516
alshabib4ceaed32016-03-03 18:00:58 -0800517 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
518 @Override
519 public void onSuccess(Objective objective) {
520 upFuture.complete(null);
521 }
alshabibbf23a1f2016-01-14 17:27:11 -0800522
alshabib4ceaed32016-03-03 18:00:58 -0800523 @Override
524 public void onError(Objective objective, ObjectiveError error) {
525 upFuture.complete(error);
526 }
527 }));
528
529 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
530 @Override
531 public void onSuccess(Objective objective) {
532 downFuture.complete(null);
533 }
534
535 @Override
536 public void onError(Objective objective, ObjectiveError error) {
537 downFuture.complete(error);
538 }
539 }));
alshabibbf23a1f2016-01-14 17:27:11 -0800540
541 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
542 if (upStatus == null && downStatus == null) {
543 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_UNREGISTERED,
Gamze Abaka641fc072018-09-04 09:16:27 +0000544 deviceId,
545 deviceVlan,
546 subscriberVlan));
alshabibbf23a1f2016-01-14 17:27:11 -0800547 } else if (downStatus != null) {
548 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000549 "on port {} failed downstream uninstallation: {}",
550 subscriberVlan, deviceId, subscriberPort, downStatus);
alshabibbf23a1f2016-01-14 17:27:11 -0800551 } else if (upStatus != null) {
552 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000553 "on port {} failed upstream uninstallation: {}",
554 subscriberVlan, deviceId, subscriberPort, upStatus);
alshabibbf23a1f2016-01-14 17:27:11 -0800555 }
556 }, oltInstallers);
alshabibb7a9e172016-01-13 11:23:53 -0800557
Jonathan Harte533a422015-10-20 17:31:24 -0700558 }
559
Gamze Abaka641fc072018-09-04 09:16:27 +0000560 private void provisionVlans(ConnectPoint port, PortNumber uplinkPort, Optional<VlanId> defaultVlan,
561 SubscriberAndDeviceInformation sub) {
562
563 log.info("Provisioning vlans...");
564
565 DeviceId deviceId = port.deviceId();
566 PortNumber subscriberPort = port.port();
567 VlanId deviceVlan = sub.sTag();
568 VlanId subscriberVlan = sub.cTag();
569 int techProfId = sub.technologyProfileId();
570
571 BandwidthProfileInformation upstreamBpInfo = getBandwidthProfileInformation(sub.upstreamBandwidthProfile());
572 BandwidthProfileInformation downstreamBpInfo = getBandwidthProfileInformation(sub.downstreamBandwidthProfile());
573
574 MeterId usptreamMeterId = createMeter(deviceId, upstreamBpInfo);
575 MeterId downstreamMeterId = createMeter(deviceId, downstreamBpInfo);
Jonathan Harte533a422015-10-20 17:31:24 -0700576
alshabib3ea82642016-01-12 18:06:53 -0800577 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
578 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
579
alshabib4ceaed32016-03-03 18:00:58 -0800580 ForwardingObjective.Builder upFwd = upBuilder(uplinkPort, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000581 subscriberVlan, deviceVlan,
582 defaultVlan, usptreamMeterId, techProfId);
Jonathan Harte533a422015-10-20 17:31:24 -0700583
alshabib4ceaed32016-03-03 18:00:58 -0800584 ForwardingObjective.Builder downFwd = downBuilder(uplinkPort, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000585 subscriberVlan, deviceVlan,
586 defaultVlan, downstreamMeterId, techProfId);
alshabib3ea82642016-01-12 18:06:53 -0800587
alshabibbf23a1f2016-01-14 17:27:11 -0800588 flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
589 @Override
590 public void onSuccess(Objective objective) {
591 upFuture.complete(null);
592 }
593
594 @Override
595 public void onError(Objective objective, ObjectiveError error) {
596 upFuture.complete(error);
597 }
598 }));
599
alshabibbf23a1f2016-01-14 17:27:11 -0800600 flowObjectiveService.forward(deviceId, downFwd.add(new ObjectiveContext() {
601 @Override
602 public void onSuccess(Objective objective) {
603 downFuture.complete(null);
604 }
605
606 @Override
607 public void onError(Objective objective, ObjectiveError error) {
608 downFuture.complete(error);
609 }
610 }));
alshabib3ea82642016-01-12 18:06:53 -0800611
612 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
613 if (upStatus == null && downStatus == null) {
614 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_REGISTERED,
Gamze Abaka641fc072018-09-04 09:16:27 +0000615 deviceId,
616 deviceVlan,
617 subscriberVlan));
alshabib50d9fc52016-02-12 15:47:20 -0800618
alshabib3ea82642016-01-12 18:06:53 -0800619 } else if (downStatus != null) {
620 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000621 "on port {} failed downstream installation: {}",
622 subscriberVlan, deviceId, subscriberPort, downStatus);
alshabib3ea82642016-01-12 18:06:53 -0800623 } else if (upStatus != null) {
624 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000625 "on port {} failed upstream installation: {}",
626 subscriberVlan, deviceId, subscriberPort, upStatus);
alshabib3ea82642016-01-12 18:06:53 -0800627 }
628 }, oltInstallers);
629
Jonathan Harte533a422015-10-20 17:31:24 -0700630 }
631
Gamze Abaka641fc072018-09-04 09:16:27 +0000632 private MeterId createMeter(DeviceId deviceId, BandwidthProfileInformation bpInfo) {
633
634 if (bpInfo == null) {
635 log.warn("Bandwidth profile information is not found");
636 return null;
637 }
638
639 MeterId meterId = bpInfoToMeter.get(bpInfo.id());
640 if (meterId != null) {
641 log.info("Meter is already added. MeterId {}", meterId);
642 return meterId;
643 }
644
645 List<Band> meterBands = createMeterBands(bpInfo);
646
647 MeterRequest meterRequest = DefaultMeterRequest.builder()
648 .withBands(meterBands)
649 .withUnit(Meter.Unit.KB_PER_SEC)
650 .forDevice(deviceId)
651 .fromApp(appId)
652 .burst()
653 .add();
654
655 Meter meter = meterService.submit(meterRequest);
656 bpInfoToMeter.put(bpInfo.id(), meter.id());
657 log.info("Meter is created. Meter Id {}", meter.id());
658 return meter.id();
659 }
660
661 private List<Band> createMeterBands(BandwidthProfileInformation bpInfo) {
662 List<Band> meterBands = new ArrayList<>();
663
664 meterBands.add(createMeterBand(bpInfo.committedInformationRate(), bpInfo.committedBurstSize()));
665 meterBands.add(createMeterBand(bpInfo.exceededInformationRate(), bpInfo.exceededBurstSize()));
Gamze Abakaad329652018-12-20 10:12:21 +0000666 meterBands.add(createMeterBand(bpInfo.assuredInformationRate(), 0L));
Gamze Abaka641fc072018-09-04 09:16:27 +0000667
Gamze Abaka641fc072018-09-04 09:16:27 +0000668 return meterBands;
669 }
670
671 private Band createMeterBand(long rate, Long burst) {
672 return DefaultBand.builder()
673 .withRate(rate) //already Kbps
674 .burstSize(burst) // already Kbits
675 .ofType(Band.Type.DROP) // no matter
676 .build();
677 }
678
alshabib4ceaed32016-03-03 18:00:58 -0800679 private ForwardingObjective.Builder downBuilder(PortNumber uplinkPort,
680 PortNumber subscriberPort,
681 VlanId subscriberVlan,
682 VlanId deviceVlan,
Gamze Abaka641fc072018-09-04 09:16:27 +0000683 Optional<VlanId> defaultVlan,
684 MeterId meterId,
685 int techProfId) {
alshabib4ceaed32016-03-03 18:00:58 -0800686 TrafficSelector downstream = DefaultTrafficSelector.builder()
687 .matchVlanId(deviceVlan)
688 .matchInPort(uplinkPort)
689 .matchInnerVlanId(subscriberVlan)
690 .build();
691
Gamze Abaka641fc072018-09-04 09:16:27 +0000692 TrafficTreatment.Builder downstreamTreatmentBuilder = DefaultTrafficTreatment.builder()
alshabib4ceaed32016-03-03 18:00:58 -0800693 .popVlan()
694 .setVlanId(defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan)))
Gamze Abaka641fc072018-09-04 09:16:27 +0000695 .setOutput(subscriberPort);
696
697 if (meterId != null) {
698 downstreamTreatmentBuilder.meter(meterId);
699 }
700
Gamze Abakaad329652018-12-20 10:12:21 +0000701 downstreamTreatmentBuilder.writeMetadata(createMetadata(subscriberVlan, techProfId, subscriberPort), 0);
alshabib4ceaed32016-03-03 18:00:58 -0800702
703 return DefaultForwardingObjective.builder()
704 .withFlag(ForwardingObjective.Flag.VERSATILE)
705 .withPriority(1000)
706 .makePermanent()
707 .withSelector(downstream)
708 .fromApp(appId)
Gamze Abaka641fc072018-09-04 09:16:27 +0000709 .withTreatment(downstreamTreatmentBuilder.build());
alshabib4ceaed32016-03-03 18:00:58 -0800710 }
711
712 private ForwardingObjective.Builder upBuilder(PortNumber uplinkPort,
713 PortNumber subscriberPort,
714 VlanId subscriberVlan,
715 VlanId deviceVlan,
Gamze Abaka641fc072018-09-04 09:16:27 +0000716 Optional<VlanId> defaultVlan,
717 MeterId meterId,
718 int technologyProfileId) {
719
720
721 VlanId dVlan = defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan));
722
723 if (subscriberVlan.toShort() == 4096) {
724 dVlan = subscriberVlan;
725 }
726
alshabib4ceaed32016-03-03 18:00:58 -0800727 TrafficSelector upstream = DefaultTrafficSelector.builder()
Gamze Abaka641fc072018-09-04 09:16:27 +0000728 .matchVlanId(dVlan)
alshabib4ceaed32016-03-03 18:00:58 -0800729 .matchInPort(subscriberPort)
730 .build();
731
732
Gamze Abaka641fc072018-09-04 09:16:27 +0000733 TrafficTreatment.Builder upstreamTreatmentBuilder = DefaultTrafficTreatment.builder()
alshabib4ceaed32016-03-03 18:00:58 -0800734 .pushVlan()
735 .setVlanId(subscriberVlan)
736 .pushVlan()
737 .setVlanId(deviceVlan)
Gamze Abaka641fc072018-09-04 09:16:27 +0000738 .setOutput(uplinkPort);
739
740 if (meterId != null) {
741 upstreamTreatmentBuilder.meter(meterId);
742 }
743
Gamze Abakaad329652018-12-20 10:12:21 +0000744 upstreamTreatmentBuilder.writeMetadata(createMetadata(deviceVlan, technologyProfileId, uplinkPort), 0L);
alshabib4ceaed32016-03-03 18:00:58 -0800745
746 return DefaultForwardingObjective.builder()
747 .withFlag(ForwardingObjective.Flag.VERSATILE)
748 .withPriority(1000)
749 .makePermanent()
750 .withSelector(upstream)
751 .fromApp(appId)
Gamze Abaka641fc072018-09-04 09:16:27 +0000752 .withTreatment(upstreamTreatmentBuilder.build());
alshabib4ceaed32016-03-03 18:00:58 -0800753 }
Gamze Abakaad329652018-12-20 10:12:21 +0000754
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100755 private void provisionTransparentFlows(DeviceId deviceId, PortNumber uplinkPort,
756 PortNumber subscriberPort,
757 VlanId innerVlan,
758 VlanId outerVlan) {
759
760 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
761 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
762
763 ForwardingObjective.Builder upFwd = transparentUpBuilder(uplinkPort, subscriberPort,
764 innerVlan, outerVlan);
765
766
767 ForwardingObjective.Builder downFwd = transparentDownBuilder(uplinkPort, subscriberPort,
768 innerVlan, outerVlan);
769
770 ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
771
772 additionalVlans.put(cp, new AbstractMap.SimpleEntry(outerVlan, innerVlan));
773
774 flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
775 @Override
776 public void onSuccess(Objective objective) {
777 upFuture.complete(null);
778 }
779
780 @Override
781 public void onError(Objective objective, ObjectiveError error) {
782 upFuture.complete(error);
783 }
784 }));
785
786 flowObjectiveService.forward(deviceId, downFwd.add(new ObjectiveContext() {
787 @Override
788 public void onSuccess(Objective objective) {
789 downFuture.complete(null);
790 }
791
792 @Override
793 public void onError(Objective objective, ObjectiveError error) {
794 downFuture.complete(error);
795 }
796 }));
797
798 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
799 if (downStatus != null) {
800 log.error("Flow with innervlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000801 "on port {} failed downstream installation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100802 innerVlan, outerVlan, deviceId, subscriberPort, downStatus);
803 } else if (upStatus != null) {
804 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000805 "on port {} failed upstream installation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100806 innerVlan, outerVlan, deviceId, subscriberPort, upStatus);
807 }
808 }, oltInstallers);
809
810 }
811
812 private ForwardingObjective.Builder transparentDownBuilder(PortNumber uplinkPort,
813 PortNumber subscriberPort,
814 VlanId innerVlan,
815 VlanId outerVlan) {
816 TrafficSelector downstream = DefaultTrafficSelector.builder()
817 .matchVlanId(outerVlan)
818 .matchInPort(uplinkPort)
819 .matchInnerVlanId(innerVlan)
820 .build();
821
822 TrafficTreatment downstreamTreatment = DefaultTrafficTreatment.builder()
823 .setOutput(subscriberPort)
824 .build();
825
826 return DefaultForwardingObjective.builder()
827 .withFlag(ForwardingObjective.Flag.VERSATILE)
828 .withPriority(1000)
829 .makePermanent()
830 .withSelector(downstream)
831 .fromApp(appId)
832 .withTreatment(downstreamTreatment);
833 }
834
835 private ForwardingObjective.Builder transparentUpBuilder(PortNumber uplinkPort,
836 PortNumber subscriberPort,
837 VlanId innerVlan,
838 VlanId outerVlan) {
839 TrafficSelector upstream = DefaultTrafficSelector.builder()
840 .matchVlanId(outerVlan)
841 .matchInPort(subscriberPort)
842 .matchInnerVlanId(innerVlan)
843 .build();
844
845 TrafficTreatment upstreamTreatment = DefaultTrafficTreatment.builder()
846 .setOutput(uplinkPort)
847 .build();
848
849 return DefaultForwardingObjective.builder()
850 .withFlag(ForwardingObjective.Flag.VERSATILE)
851 .withPriority(1000)
852 .makePermanent()
853 .withSelector(upstream)
854 .fromApp(appId)
855 .withTreatment(upstreamTreatment);
856 }
857
858 private void unprovisionTransparentFlows(DeviceId deviceId, PortNumber uplink,
859 PortNumber subscriberPort, VlanId innerVlan,
860 VlanId outerVlan) {
861
862 ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
863
864 additionalVlans.remove(cp, new AbstractMap.SimpleEntry(outerVlan, innerVlan));
865
866 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
867 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
868
869 ForwardingObjective.Builder upFwd = transparentUpBuilder(uplink, subscriberPort,
870 innerVlan, outerVlan);
871 ForwardingObjective.Builder downFwd = transparentDownBuilder(uplink, subscriberPort,
872 innerVlan, outerVlan);
873
874
875 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
876 @Override
877 public void onSuccess(Objective objective) {
878 upFuture.complete(null);
879 }
880
881 @Override
882 public void onError(Objective objective, ObjectiveError error) {
883 upFuture.complete(error);
884 }
885 }));
886
887 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
888 @Override
889 public void onSuccess(Objective objective) {
890 downFuture.complete(null);
891 }
892
893 @Override
894 public void onError(Objective objective, ObjectiveError error) {
895 downFuture.complete(error);
896 }
897 }));
898
899 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
900 if (downStatus != null) {
901 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000902 "on port {} failed downstream uninstallation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100903 innerVlan, outerVlan, deviceId, subscriberPort, downStatus);
904 } else if (upStatus != null) {
905 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000906 "on port {} failed upstream uninstallation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100907 innerVlan, outerVlan, deviceId, subscriberPort, upStatus);
908 }
909 }, oltInstallers);
910
911 }
912
Saurav Das82b8e6d2018-10-04 15:25:12 -0700913 private void processEapolFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
alshabib09753b52016-03-04 14:55:19 -0800914 if (!mastershipService.isLocalMaster(devId)) {
915 return;
916 }
alshabibbb83aa22016-02-10 15:08:23 -0800917 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Gamze Abakaad329652018-12-20 10:12:21 +0000918 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
alshabibbb83aa22016-02-10 15:08:23 -0800919
Gamze Abakaad329652018-12-20 10:12:21 +0000920 BandwidthProfileInformation defaultBpInfo = getBandwidthProfileInformation(defaultBpId);
921 if (defaultBpInfo != null) {
922 MeterId meterId = createMeter(devId, defaultBpInfo);
923 treatmentBuilder.meter(meterId);
924 } else {
925 log.warn("Default bandwidth profile is not found. Authentication flow will be installed without meter");
926 }
927
928 //Authentication trap flow uses only tech profile id as metadata
alshabibbb83aa22016-02-10 15:08:23 -0800929 FilteringObjective eapol = (install ? builder.permit() : builder.deny())
alshabib50d9fc52016-02-12 15:47:20 -0800930 .withKey(Criteria.matchInPort(port))
alshabibdec2e252016-01-15 12:20:25 -0800931 .addCondition(Criteria.matchEthType(EthType.EtherType.EAPOL.ethType()))
Gamze Abakaad329652018-12-20 10:12:21 +0000932 .withMeta(treatmentBuilder
933 .writeMetadata((long) defaultTechProfileId << 32, 0)
Gamze Abaka641fc072018-09-04 09:16:27 +0000934 .setOutput(PortNumber.CONTROLLER).build())
alshabibdec2e252016-01-15 12:20:25 -0800935 .fromApp(appId)
Matt Jeanneret3f579262018-06-14 17:16:23 -0400936 .withPriority(10000)
alshabibdec2e252016-01-15 12:20:25 -0800937 .add(new ObjectiveContext() {
938 @Override
939 public void onSuccess(Objective objective) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700940 log.info("Eapol filter for {} on {} {}.",
Gamze Abaka641fc072018-09-04 09:16:27 +0000941 devId, port, (install) ? "installed" : "removed");
alshabibdec2e252016-01-15 12:20:25 -0800942 }
943
944 @Override
945 public void onError(Objective objective, ObjectiveError error) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700946 log.info("Eapol filter for {} on {} failed {} because {}",
Gamze Abaka641fc072018-09-04 09:16:27 +0000947 devId, port, (install) ? "installation" : "removal",
948 error);
alshabibdec2e252016-01-15 12:20:25 -0800949 }
950 });
951
alshabibdec2e252016-01-15 12:20:25 -0800952 flowObjectiveService.filter(devId, eapol);
alshabib000b6fc2016-02-01 17:25:00 -0800953
alshabibdec2e252016-01-15 12:20:25 -0800954 }
955
Jonathan Hart403372d2018-08-22 11:44:13 -0700956 /**
957 * Installs trap filtering objectives for particular traffic types on an
958 * NNI port.
959 *
Gamze Abakaad329652018-12-20 10:12:21 +0000960 * @param devId device ID
961 * @param port port number
Jonathan Hart403372d2018-08-22 11:44:13 -0700962 * @param install true to install, false to remove
963 */
964 private void processNniFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
965 processLldpFilteringObjective(devId, port, install);
Matteo Scandolo63460d12018-11-02 16:19:04 -0700966 if (enableDhcpOnProvisioning) {
967 processDhcpFilteringObjectives(devId, port, install, false);
968 }
Jonathan Hart403372d2018-08-22 11:44:13 -0700969 }
970
971 private void processLldpFilteringObjective(DeviceId devId, PortNumber port, boolean install) {
972 if (!mastershipService.isLocalMaster(devId)) {
973 return;
974 }
975 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
976
977 FilteringObjective lldp = (install ? builder.permit() : builder.deny())
978 .withKey(Criteria.matchInPort(port))
979 .addCondition(Criteria.matchEthType(EthType.EtherType.LLDP.ethType()))
980 .withMeta(DefaultTrafficTreatment.builder()
981 .setOutput(PortNumber.CONTROLLER).build())
982 .fromApp(appId)
983 .withPriority(10000)
984 .add(new ObjectiveContext() {
985 @Override
986 public void onSuccess(Objective objective) {
Matteo Scandolo63460d12018-11-02 16:19:04 -0700987 log.info("LLDP filter for device {} on port {} {}.",
Saurav Das82b8e6d2018-10-04 15:25:12 -0700988 devId, port, (install) ? "installed" : "removed");
Jonathan Hart403372d2018-08-22 11:44:13 -0700989 }
990
991 @Override
992 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo63460d12018-11-02 16:19:04 -0700993 log.info("LLDP filter for device {} on port {} failed {} because {}",
Saurav Das82b8e6d2018-10-04 15:25:12 -0700994 devId, port, (install) ? "installation" : "removal",
995 error);
Jonathan Hart403372d2018-08-22 11:44:13 -0700996 }
997 });
998
999 flowObjectiveService.filter(devId, lldp);
1000
1001 }
1002
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001003 /**
1004 * Trap dhcp packets to the controller.
1005 *
Gamze Abakaad329652018-12-20 10:12:21 +00001006 * @param devId the device identifier
1007 * @param port the port for which this trap flow is designated
1008 * @param install true to install the flow, false to remove the flow
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001009 * @param upstream true if trapped packets are flowing upstream towards
Gamze Abakaad329652018-12-20 10:12:21 +00001010 * server, false if packets are flowing dowstream towards client
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001011 */
1012 private void processDhcpFilteringObjectives(DeviceId devId, PortNumber port,
1013 boolean install,
1014 boolean upstream) {
Amit Ghosh95e2f652017-08-23 12:49:46 +01001015 if (!mastershipService.isLocalMaster(devId)) {
1016 return;
1017 }
Amit Ghosh95e2f652017-08-23 12:49:46 +01001018
Matteo Scandolo63460d12018-11-02 16:19:04 -07001019 if (enableDhcpV4) {
1020 int udpSrc = (upstream) ? 68 : 67;
1021 int udpDst = (upstream) ? 67 : 68;
1022
1023 EthType ethType = EthType.EtherType.IPV4.ethType();
1024 byte protocol = IPv4.PROTOCOL_UDP;
1025
1026 this.addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType, protocol, install);
1027 }
1028
1029 if (enableDhcpV6) {
1030 int udpSrc = (upstream) ? 547 : 546;
1031 int udpDst = (upstream) ? 546 : 547;
1032
1033 EthType ethType = EthType.EtherType.IPV6.ethType();
1034 byte protocol = IPv6.PROTOCOL_UDP;
1035
1036 this.addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType, protocol, install);
1037 }
1038
1039 }
1040
1041 private void addDhcpFilteringObjectives(DeviceId devId,
1042 PortNumber port,
1043 int udpSrc,
1044 int udpDst,
1045 EthType ethType,
1046 byte protocol,
1047 boolean install) {
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001048
1049 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Amit Ghosh95e2f652017-08-23 12:49:46 +01001050 FilteringObjective dhcpUpstream = (install ? builder.permit() : builder.deny())
1051 .withKey(Criteria.matchInPort(port))
Matteo Scandolo63460d12018-11-02 16:19:04 -07001052 .addCondition(Criteria.matchEthType(ethType))
1053 .addCondition(Criteria.matchIPProtocol(protocol))
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001054 .addCondition(Criteria.matchUdpSrc(TpPort.tpPort(udpSrc)))
1055 .addCondition(Criteria.matchUdpDst(TpPort.tpPort(udpDst)))
Amit Ghosh95e2f652017-08-23 12:49:46 +01001056 .withMeta(DefaultTrafficTreatment.builder()
Gamze Abaka641fc072018-09-04 09:16:27 +00001057 .setOutput(PortNumber.CONTROLLER).build())
Amit Ghosh95e2f652017-08-23 12:49:46 +01001058 .fromApp(appId)
Matt Jeanneret3f579262018-06-14 17:16:23 -04001059 .withPriority(10000)
Amit Ghosh95e2f652017-08-23 12:49:46 +01001060 .add(new ObjectiveContext() {
1061 @Override
1062 public void onSuccess(Objective objective) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001063 log.info("DHCP {} filter for device {} on port {} {}.",
Gamze Abakaad329652018-12-20 10:12:21 +00001064 (ethType.equals(EthType.EtherType.IPV4.ethType())) ? "v4" : "v6",
1065 devId, port, (install) ? "installed" : "removed");
Amit Ghosh95e2f652017-08-23 12:49:46 +01001066 }
1067
1068 @Override
1069 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001070 log.info("DHCP {} filter for device {} on port {} failed {} because {}",
Gamze Abakaad329652018-12-20 10:12:21 +00001071 (ethType.equals(EthType.EtherType.IPV4.ethType())) ? "v4" : "v6",
1072 devId, port, (install) ? "installation" : "removal",
1073 error);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001074 }
1075 });
1076
1077 flowObjectiveService.filter(devId, dhcpUpstream);
1078 }
1079
1080 private void processIgmpFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
1081 if (!mastershipService.isLocalMaster(devId)) {
1082 return;
1083 }
1084
Gamze Abaka641fc072018-09-04 09:16:27 +00001085 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Amit Ghosh95e2f652017-08-23 12:49:46 +01001086
1087 builder = install ? builder.permit() : builder.deny();
1088
1089 FilteringObjective igmp = builder
1090 .withKey(Criteria.matchInPort(port))
1091 .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
1092 .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_IGMP))
1093 .withMeta(DefaultTrafficTreatment.builder()
Gamze Abaka641fc072018-09-04 09:16:27 +00001094 .setOutput(PortNumber.CONTROLLER).build())
Amit Ghosh95e2f652017-08-23 12:49:46 +01001095 .fromApp(appId)
1096 .withPriority(10000)
1097 .add(new ObjectiveContext() {
1098 @Override
1099 public void onSuccess(Objective objective) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001100 log.info("Igmp filter for {} on {} {}.",
Gamze Abaka641fc072018-09-04 09:16:27 +00001101 devId, port, (install) ? "installed" : "removed");
Amit Ghosh95e2f652017-08-23 12:49:46 +01001102 }
1103
1104 @Override
1105 public void onError(Objective objective, ObjectiveError error) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001106 log.info("Igmp filter for {} on {} failed {} because {}.",
Gamze Abaka641fc072018-09-04 09:16:27 +00001107 devId, port, (install) ? "installation" : "removal",
1108 error);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001109 }
1110 });
1111
1112 flowObjectiveService.filter(devId, igmp);
1113 }
1114
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001115 /**
Jonathan Hart403372d2018-08-22 11:44:13 -07001116 * Creates trap flows for device, including DHCP and LLDP trap on NNI and
1117 * EAPOL trap on the UNIs, if device is present in Sadis config.
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001118 *
1119 * @param dev Device to look for
1120 */
Jonathan Hart403372d2018-08-22 11:44:13 -07001121 private void checkAndCreateDeviceFlows(Device dev) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001122 // we create only for the ones we are master of
1123 if (!mastershipService.isLocalMaster(dev.id())) {
Gamze Abaka641fc072018-09-04 09:16:27 +00001124 return;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001125 }
1126 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +00001127 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Jonathan Hart403372d2018-08-22 11:44:13 -07001128 log.debug("checkAndCreateDeviceFlows: deviceInfo {}", deviceInfo);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001129
1130 if (deviceInfo != null) {
Jonathan Hart403372d2018-08-22 11:44:13 -07001131 // This is an OLT device as per Sadis, we create flows for UNI and NNI ports
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001132 for (Port p : deviceService.getPorts(dev.id())) {
1133 if (isUniPort(dev, p)) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001134 processEapolFilteringObjectives(dev.id(), p.number(), true);
Jonathan Hart403372d2018-08-22 11:44:13 -07001135 } else {
1136 processNniFilteringObjectives(dev.id(), p.number(), true);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001137 }
1138 }
1139 }
1140 }
1141
Jonathan Hart403372d2018-08-22 11:44:13 -07001142
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001143 /**
1144 * Get the uplink for of the OLT device.
Gamze Abakaad329652018-12-20 10:12:21 +00001145 * <p>
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001146 * This assumes that the OLT has a single uplink port. When more uplink ports need to be supported
1147 * this logic needs to be changed
1148 *
1149 * @param dev Device to look for
1150 * @return The uplink Port of the OLT
1151 */
1152 private Port getUplinkPort(Device dev) {
1153 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +00001154 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001155 log.debug("getUplinkPort: deviceInfo {}", deviceInfo);
Saurav Das82b8e6d2018-10-04 15:25:12 -07001156 if (deviceInfo == null) {
1157 log.warn("Device {} is not configured in SADIS .. cannot fetch device"
1158 + " info", dev.id());
1159 return null;
1160 }
1161 // Return the port that has been configured as the uplink port of this OLT in Sadis
Gamze Abakaad329652018-12-20 10:12:21 +00001162 for (Port p : deviceService.getPorts(dev.id())) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001163 if (p.number().toLong() == deviceInfo.uplinkPort()) {
1164 log.debug("getUplinkPort: Found port {}", p);
1165 return p;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001166 }
1167 }
1168
Saurav Das82b8e6d2018-10-04 15:25:12 -07001169 log.debug("getUplinkPort: No uplink port found for OLT {}", dev.id());
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001170 return null;
1171 }
1172
1173 /**
1174 * Return the subscriber on a port.
1175 *
Matteo Scandolo962a6ad2018-12-11 15:39:42 -08001176 * @param cp ConnectPoint on which to find the subscriber
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001177 * @return subscriber if found else null
1178 */
Matteo Scandolo962a6ad2018-12-11 15:39:42 -08001179 SubscriberAndDeviceInformation getSubscriber(ConnectPoint cp) {
1180 Port port = deviceService.getPort(cp);
1181 checkNotNull(port, "Invalid connect point");
1182 String portName = port.annotations().value(AnnotationKeys.PORT_NAME);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001183 return subsService.get(portName);
1184 }
1185
Gamze Abakaad329652018-12-20 10:12:21 +00001186 /**
1187 * Write metadata instruction value (metadata) is 8 bytes.
1188 *
1189 * MS 2 bytes: C Tag
1190 * Next 2 bytes: Technology Profile Id
1191 * Next 4 bytes: Port number (uni or nni)
1192 */
1193
1194 private Long createMetadata(VlanId innerVlan, int techProfileId, PortNumber egressPort) {
1195
1196 if (techProfileId == -1) {
1197 techProfileId = DEFAULT_TP_ID;
1198 }
1199
1200 return ((long) (innerVlan.id()) << 48 | (long) techProfileId << 32) | egressPort.toLong();
1201 }
1202
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001203 private boolean isUniPort(Device d, Port p) {
1204 Port ulPort = getUplinkPort(d);
1205 if (ulPort != null) {
1206 return (ulPort.number().toLong() != p.number().toLong());
1207 }
1208 return false;
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001209 }
1210
Jonathan Hart4c538002018-08-23 10:11:54 -07001211 private SubscriberAndDeviceInformation getOltInfo(Device dev) {
1212 String devSerialNo = dev.serialNumber();
Gamze Abaka641fc072018-09-04 09:16:27 +00001213 return subsService.get(devSerialNo);
Jonathan Hart4c538002018-08-23 10:11:54 -07001214 }
1215
alshabibf0e7e702015-05-30 18:22:36 -07001216 private class InternalDeviceListener implements DeviceListener {
1217 @Override
1218 public void event(DeviceEvent event) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001219 eventExecutor.execute(() -> {
1220 DeviceId devId = event.subject().id();
1221 Device dev = event.subject();
Jonathan Hart4c538002018-08-23 10:11:54 -07001222
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001223 if (event.type() == DeviceEvent.Type.PORT_STATS_UPDATED) {
1224 return;
1225 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001226
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001227 if (getOltInfo(dev) == null) {
1228 log.debug("No device info found, this is not an OLT");
1229 return;
1230 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001231
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001232 log.debug("OLT got {} event for {}", event.type(), event.subject());
Jonathan Hart4c538002018-08-23 10:11:54 -07001233
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001234 switch (event.type()) {
1235 //TODO: Port handling and bookkeeping should be improved once
1236 // olt firmware handles correct behaviour.
1237 case PORT_ADDED:
1238 if (isUniPort(dev, event.port())) {
1239 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, event.port()));
Jonathan Hart4c538002018-08-23 10:11:54 -07001240
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001241 if (event.port().isEnabled()) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001242 processEapolFilteringObjectives(devId, event.port().number(), true);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001243 }
1244 } else {
1245 checkAndCreateDeviceFlows(dev);
1246 }
1247 break;
1248 case PORT_REMOVED:
1249 if (isUniPort(dev, event.port())) {
1250 if (event.port().isEnabled()) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001251 processEapolFilteringObjectives(devId, event.port().number(), false);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001252 removeSubscriber(new ConnectPoint(devId, event.port().number()));
1253 }
1254
1255 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, event.port()));
1256 }
1257
1258 break;
1259 case PORT_UPDATED:
1260 if (!isUniPort(dev, event.port())) {
1261 break;
1262 }
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001263
1264 if (event.port().isEnabled()) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001265 processEapolFilteringObjectives(devId, event.port().number(), true);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001266 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, event.port()));
1267 } else {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001268 processEapolFilteringObjectives(devId, event.port().number(), false);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001269 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, event.port()));
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001270 }
alshabibbb83aa22016-02-10 15:08:23 -08001271 break;
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001272 case DEVICE_ADDED:
alshabib7c190012016-02-09 18:22:33 -08001273 post(new AccessDeviceEvent(
1274 AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
1275 null, null));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001276
1277 // Send UNI_ADDED events for all existing ports
1278 deviceService.getPorts(devId).stream()
1279 .filter(p -> isUniPort(dev, p))
1280 .filter(Port::isEnabled)
1281 .forEach(p -> post(new AccessDeviceEvent(
1282 AccessDeviceEvent.Type.UNI_ADDED, devId, p)));
1283
Jonathan Hart403372d2018-08-22 11:44:13 -07001284 checkAndCreateDeviceFlows(dev);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001285 break;
1286 case DEVICE_REMOVED:
1287 deviceService.getPorts(devId).stream()
1288 .filter(p -> isUniPort(dev, p))
1289 .forEach(p -> post(new AccessDeviceEvent(
1290 AccessDeviceEvent.Type.UNI_REMOVED, devId, p)));
1291
alshabib7c190012016-02-09 18:22:33 -08001292 post(new AccessDeviceEvent(
1293 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
1294 null, null));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001295 break;
1296 case DEVICE_AVAILABILITY_CHANGED:
1297 if (deviceService.isAvailable(devId)) {
1298 post(new AccessDeviceEvent(
1299 AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
1300 null, null));
1301 checkAndCreateDeviceFlows(dev);
1302 } else {
1303 post(new AccessDeviceEvent(
1304 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
1305 null, null));
1306 }
1307 break;
1308 case DEVICE_UPDATED:
1309 case DEVICE_SUSPENDED:
1310 case PORT_STATS_UPDATED:
1311 default:
1312 return;
1313 }
1314 });
alshabibf0e7e702015-05-30 18:22:36 -07001315 }
1316 }
Gamze Abaka641fc072018-09-04 09:16:27 +00001317
1318 private class InternalMeterListener implements MeterListener {
1319
1320 @Override
1321 public void event(MeterEvent meterEvent) {
1322 if (deleteMeters && MeterEvent.Type.METER_REFERENCE_COUNT_ZERO.equals(meterEvent.type())) {
1323 log.debug("Zero Count Meter Event is received. Meter is {}", meterEvent.subject());
1324 Meter meter = meterEvent.subject();
1325 if (meter != null && appId.equals(meter.appId())) {
1326 deleteMeter(meter.deviceId(), meter.id());
1327 }
1328 } else if (MeterEvent.Type.METER_REMOVED.equals(meterEvent.type())) {
1329 log.debug("Meter removed event is received. Meter is {}", meterEvent.subject());
1330 removeMeterFromBpMap(meterEvent.subject());
1331 }
1332 }
1333
1334 private void deleteMeter(DeviceId deviceId, MeterId meterId) {
1335 Meter meter = meterService.getMeter(deviceId, meterId);
1336 MeterRequest meterRequest = DefaultMeterRequest.builder()
1337 .withBands(meter.bands())
1338 .withUnit(meter.unit())
1339 .forDevice(deviceId)
1340 .fromApp(appId)
1341 .burst()
1342 .remove();
1343
1344 meterService.withdraw(meterRequest, meterId);
1345
1346 }
1347
1348 private void removeMeterFromBpMap(Meter meter) {
1349 for (Map.Entry<String, MeterId> entry : bpInfoToMeter.entrySet()) {
1350 if (entry.getValue().equals(meter.id())) {
1351 bpInfoToMeter.remove(entry.getKey());
1352 log.info("Deleted from the internal map. Profile {} and Meter {}", entry.getKey(), meter.id());
1353 break;
1354 }
1355 }
1356 }
1357 }
1358}