blob: 816f3a0e12490b4251463d789889ccc857ad223a [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 Abaka1efc80c2019-02-15 12:10:54 +0000119 private static final int DEFAULT_TP_ID = 64;
Gamze Abakaad329652018-12-20 10:12:21 +0000120 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 Abaka1efc80c2019-02-15 12:10:54 +0000169 @Property(name = "deleteMeters", boolValue = true,
Gamze Abaka641fc072018-09-04 09:16:27 +0000170 label = "Deleting Meters based on flow count statistics")
Gamze Abaka1efc80c2019-02-15 12:10:54 +0000171 protected boolean deleteMeters = true;
Gamze Abaka641fc072018-09-04 09:16:27 +0000172
Gamze Abakaad329652018-12-20 10:12:21 +0000173 @Property(name = "defaultTechProfileId", intValue = DEFAULT_TP_ID,
174 label = "Default technology profile id that is used for authentication trap flows")
175 protected int defaultTechProfileId = DEFAULT_TP_ID;
176
177 @Property(name = "defaultBpId", value = DEFAULT_BP_ID,
178 label = "Default bandwidth profile id that is used for authentication trap flows")
179 protected String defaultBpId = DEFAULT_BP_ID;
180
alshabibf0e7e702015-05-30 18:22:36 -0700181 private final DeviceListener deviceListener = new InternalDeviceListener();
Gamze Abaka641fc072018-09-04 09:16:27 +0000182 private final MeterListener meterListener = new InternalMeterListener();
alshabibf0e7e702015-05-30 18:22:36 -0700183
184 private ApplicationId appId;
Gamze Abaka641fc072018-09-04 09:16:27 +0000185 protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
186 private BaseInformationService<BandwidthProfileInformation> bpService;
alshabibf0e7e702015-05-30 18:22:36 -0700187
Gamze Abaka641fc072018-09-04 09:16:27 +0000188 private Map<String, MeterId> bpInfoToMeter = new HashMap<>();
189
190 private ExecutorService oltInstallers = Executors.newFixedThreadPool(4,
191 groupedThreads("onos/olt-service",
192 "olt-installer-%d"));
alshabibf0e7e702015-05-30 18:22:36 -0700193
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100194 private ConsistentMultimap<ConnectPoint, Map.Entry<VlanId, VlanId>> additionalVlans;
195
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700196 protected ExecutorService eventExecutor;
197
Saurav Das82b8e6d2018-10-04 15:25:12 -0700198 private Map<ConnectPoint, SubscriberAndDeviceInformation> programmedSubs;
199
alshabibf0e7e702015-05-30 18:22:36 -0700200 @Activate
alshabibe0559672016-02-21 14:49:51 -0800201 public void activate(ComponentContext context) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700202 eventExecutor = newSingleThreadScheduledExecutor(groupedThreads("onos/olt", "events-%d", log));
alshabibe0559672016-02-21 14:49:51 -0800203 modified(context);
Charles Chan54f110f2017-01-20 11:22:42 -0800204 appId = coreService.registerApplication(APP_NAME);
alshabibe0559672016-02-21 14:49:51 -0800205 componentConfigService.registerProperties(getClass());
Saurav Das82b8e6d2018-10-04 15:25:12 -0700206 programmedSubs = Maps.newConcurrentMap();
alshabibc4dfe852015-06-05 13:35:13 -0700207
alshabib8e4fd2f2016-01-12 15:55:53 -0800208 eventDispatcher.addSink(AccessDeviceEvent.class, listenerRegistry);
209
Gamze Abaka641fc072018-09-04 09:16:27 +0000210 subsService = sadisService.getSubscriberInfoService();
211 bpService = sadisService.getBandwidthProfileService();
212
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100213 // look for all provisioned devices in Sadis and create EAPOL flows for the
214 // UNI ports
215 Iterable<Device> devices = deviceService.getDevices();
216 for (Device d : devices) {
Jonathan Hart403372d2018-08-22 11:44:13 -0700217 checkAndCreateDeviceFlows(d);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100218 }
alshabib4ceaed32016-03-03 18:00:58 -0800219
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100220 additionalVlans = storageService.<ConnectPoint, Map.Entry<VlanId, VlanId>>consistentMultimapBuilder()
221 .withName(ADDITIONAL_VLANS)
222 .withSerializer(Serializer.using(Arrays.asList(KryoNamespaces.API),
223 AbstractMap.SimpleEntry.class))
224 .build();
225
alshabibba357492016-01-27 13:49:46 -0800226 deviceService.addListener(deviceListener);
Gamze Abaka641fc072018-09-04 09:16:27 +0000227 meterService.addListener(meterListener);
alshabibba357492016-01-27 13:49:46 -0800228
alshabibf0e7e702015-05-30 18:22:36 -0700229 log.info("Started with Application ID {}", appId.id());
230 }
231
232 @Deactivate
233 public void deactivate() {
alshabibe0559672016-02-21 14:49:51 -0800234 componentConfigService.unregisterProperties(getClass(), false);
alshabib62e9ce72016-02-11 17:31:36 -0800235 deviceService.removeListener(deviceListener);
Gamze Abaka641fc072018-09-04 09:16:27 +0000236 meterService.removeListener(meterListener);
Jonathan Hart5f1c8142018-07-24 17:31:59 -0700237 eventDispatcher.removeSink(AccessDeviceEvent.class);
alshabibf0e7e702015-05-30 18:22:36 -0700238 log.info("Stopped");
239 }
240
alshabibe0559672016-02-21 14:49:51 -0800241 @Modified
242 public void modified(ComponentContext context) {
243 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
244
245 try {
246 String s = get(properties, "defaultVlan");
247 defaultVlan = isNullOrEmpty(s) ? DEFAULT_VLAN : Integer.parseInt(s.trim());
Amit Ghosh95e2f652017-08-23 12:49:46 +0100248
Matt Jeanneret3f579262018-06-14 17:16:23 -0400249 Boolean o = Tools.isPropertyEnabled(properties, "enableDhcpOnProvisioning");
Amit Ghosh95e2f652017-08-23 12:49:46 +0100250 if (o != null) {
Matt Jeanneret3f579262018-06-14 17:16:23 -0400251 enableDhcpOnProvisioning = o;
Amit Ghosh95e2f652017-08-23 12:49:46 +0100252 }
Matt Jeanneret3f579262018-06-14 17:16:23 -0400253
Matteo Scandolo63460d12018-11-02 16:19:04 -0700254 Boolean v4 = Tools.isPropertyEnabled(properties, "enableDhcpV4");
255 if (v4 != null) {
256 enableDhcpV4 = v4;
257 }
258
259 Boolean v6 = Tools.isPropertyEnabled(properties, "enableDhcpV6");
260 if (v6 != null) {
261 enableDhcpV6 = v6;
262 }
263
Matt Jeanneret3f579262018-06-14 17:16:23 -0400264 Boolean p = Tools.isPropertyEnabled(properties, "enableIgmpOnProvisioning");
265 if (p != null) {
266 enableIgmpOnProvisioning = p;
267 }
268
Matteo Scandolo63460d12018-11-02 16:19:04 -0700269 log.info("DHCP Settings [enableDhcpOnProvisioning: {}, enableDhcpV4: {}, enableDhcpV6: {}]",
Gamze Abakaad329652018-12-20 10:12:21 +0000270 enableDhcpOnProvisioning, enableDhcpV4, enableDhcpV6);
Matteo Scandolo63460d12018-11-02 16:19:04 -0700271
Gamze Abaka641fc072018-09-04 09:16:27 +0000272 Boolean d = Tools.isPropertyEnabled(properties, "deleteMeters");
273 if (d != null) {
274 deleteMeters = d;
275 }
276
Gamze Abakaad329652018-12-20 10:12:21 +0000277 String tpId = get(properties, "defaultTechProfileId");
278 defaultTechProfileId = isNullOrEmpty(s) ? DEFAULT_TP_ID : Integer.parseInt(tpId.trim());
279
280 String bpId = get(properties, "defaultBpId");
281 defaultBpId = bpId;
282
alshabibe0559672016-02-21 14:49:51 -0800283 } catch (Exception e) {
284 defaultVlan = DEFAULT_VLAN;
285 }
286 }
287
alshabib32232c82016-02-25 17:57:24 -0500288 @Override
Amit Ghosh31939522018-08-16 13:28:21 +0100289 public boolean provisionSubscriber(ConnectPoint port) {
Jonathan Hart94b90492018-04-24 14:02:25 -0700290 checkNotNull(deviceService.getPort(port.deviceId(), port.port()),
291 "Invalid connect point");
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100292 // Find the subscriber on this connect point
293 SubscriberAndDeviceInformation sub = getSubscriber(port);
294 if (sub == null) {
295 log.warn("No subscriber found for {}", port);
Amit Ghosh31939522018-08-16 13:28:21 +0100296 return false;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100297 }
Jonathan Harte533a422015-10-20 17:31:24 -0700298
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100299 // Get the uplink port
300 Port uplinkPort = getUplinkPort(deviceService.getDevice(port.deviceId()));
301 if (uplinkPort == null) {
302 log.warn("No uplink port found for OLT device {}", port.deviceId());
Amit Ghosh31939522018-08-16 13:28:21 +0100303 return false;
Jonathan Harte533a422015-10-20 17:31:24 -0700304 }
305
Matt Jeanneret3f579262018-06-14 17:16:23 -0400306 if (enableDhcpOnProvisioning) {
Saurav Dasacc5eeb2018-10-11 10:58:01 -0700307 processDhcpFilteringObjectives(port.deviceId(), port.port(), true,
Gamze Abaka641fc072018-09-04 09:16:27 +0000308 true);
Amit Ghosh95e2f652017-08-23 12:49:46 +0100309 }
Saurav Das82b8e6d2018-10-04 15:25:12 -0700310 log.info("Programming vlans for subscriber: {}", sub);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100311 Optional<VlanId> defaultVlan = Optional.empty();
Gamze Abaka641fc072018-09-04 09:16:27 +0000312 provisionVlans(port, uplinkPort.number(), defaultVlan, sub);
Amit Ghosh95e2f652017-08-23 12:49:46 +0100313
Matt Jeanneret3f579262018-06-14 17:16:23 -0400314 if (enableIgmpOnProvisioning) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100315 processIgmpFilteringObjectives(port.deviceId(), port.port(), true);
Amit Ghosh95e2f652017-08-23 12:49:46 +0100316 }
Saurav Das82b8e6d2018-10-04 15:25:12 -0700317 // cache subscriber info
318 programmedSubs.put(port, sub);
Amit Ghosh31939522018-08-16 13:28:21 +0100319 return true;
alshabibb7a9e172016-01-13 11:23:53 -0800320 }
321
322 @Override
Amit Ghosh31939522018-08-16 13:28:21 +0100323 public boolean removeSubscriber(ConnectPoint port) {
Matteo Scandolo962a6ad2018-12-11 15:39:42 -0800324 // Get the subscriber connected to this port from the local cache
325 // as if we don't know about the subscriber there's no need to remove it
326 SubscriberAndDeviceInformation subscriber = programmedSubs.get(port);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100327 if (subscriber == null) {
Matteo Scandolo962a6ad2018-12-11 15:39:42 -0800328 log.warn("Subscriber on port {} was not previously programmed, no need to remove it", port);
329 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800330 }
331
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100332 // Get the uplink port
333 Port uplinkPort = getUplinkPort(deviceService.getDevice(port.deviceId()));
334 if (uplinkPort == null) {
335 log.warn("No uplink port found for OLT device {}", port.deviceId());
Amit Ghosh31939522018-08-16 13:28:21 +0100336 return false;
alshabib4ceaed32016-03-03 18:00:58 -0800337 }
338
Matt Jeanneret3f579262018-06-14 17:16:23 -0400339 if (enableDhcpOnProvisioning) {
Saurav Dasacc5eeb2018-10-11 10:58:01 -0700340 processDhcpFilteringObjectives(port.deviceId(), port.port(), false,
Gamze Abaka641fc072018-09-04 09:16:27 +0000341 true);
Amit Ghosh95e2f652017-08-23 12:49:46 +0100342 }
343
Saurav Das82b8e6d2018-10-04 15:25:12 -0700344 log.info("Removing programmed vlans for subscriber: {}", subscriber);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100345 Optional<VlanId> defaultVlan = Optional.empty();
Gamze Abaka641fc072018-09-04 09:16:27 +0000346 unprovisionSubscriber(port.deviceId(), uplinkPort.number(), port.port(), subscriber, defaultVlan);
alshabibbf23a1f2016-01-14 17:27:11 -0800347
Matt Jeanneret3f579262018-06-14 17:16:23 -0400348 if (enableIgmpOnProvisioning) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100349 processIgmpFilteringObjectives(port.deviceId(), port.port(), false);
Amit Ghosh95e2f652017-08-23 12:49:46 +0100350 }
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100351
352 // Remove if there are any flows for the additional Vlans
353 Collection<? extends Map.Entry<VlanId, VlanId>> vlansList = additionalVlans.get(port).value();
354
355 // Remove the flows for the additional vlans for this subscriber
356 for (Map.Entry<VlanId, VlanId> vlans : vlansList) {
357 unprovisionTransparentFlows(port.deviceId(), uplinkPort.number(), port.port(),
358 vlans.getValue(), vlans.getKey());
359
360 // Remove it from the map also
361 additionalVlans.remove(port, vlans);
362 }
363
Saurav Das82b8e6d2018-10-04 15:25:12 -0700364 programmedSubs.remove(port);
Amit Ghosh31939522018-08-16 13:28:21 +0100365 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800366 }
367
Amit Ghosh31939522018-08-16 13:28:21 +0100368 @Override
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100369 public boolean provisionSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag, Optional<VlanId> cTag) {
Amit Ghosh31939522018-08-16 13:28:21 +0100370 // Check if we can find the connect point to which this subscriber is connected
371 ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
372 if (subsPort == null) {
373 log.warn("ConnectPoint for {} not found", subscriberId);
374 return false;
375 }
376
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100377 if (!sTag.isPresent() && !cTag.isPresent()) {
378 return provisionSubscriber(subsPort);
379 } else if (sTag.isPresent() && cTag.isPresent()) {
380 Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
381 if (uplinkPort == null) {
382 log.warn("No uplink port found for OLT device {}", subsPort.deviceId());
383 return false;
384 }
385
386 provisionTransparentFlows(subsPort.deviceId(), uplinkPort.number(), subsPort.port(),
387 cTag.get(), sTag.get());
388 return true;
389 } else {
390 log.warn("Provisioning failed for subscriber: {}", subscriberId);
391 return false;
392 }
Amit Ghosh31939522018-08-16 13:28:21 +0100393 }
Amit Ghosh95e2f652017-08-23 12:49:46 +0100394
alshabibe0559672016-02-21 14:49:51 -0800395 @Override
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100396 public boolean removeSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag, Optional<VlanId> cTag) {
Amit Ghosh31939522018-08-16 13:28:21 +0100397 // Check if we can find the connect point to which this subscriber is connected
398 ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
399 if (subsPort == null) {
400 log.warn("ConnectPoint for {} not found", subscriberId);
401 return false;
402 }
403
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100404 if (!sTag.isPresent() && !cTag.isPresent()) {
405 return removeSubscriber(subsPort);
406 } else if (sTag.isPresent() && cTag.isPresent()) {
407 // Get the uplink port
408 Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
409 if (uplinkPort == null) {
410 log.warn("No uplink port found for OLT device {}", subsPort.deviceId());
411 return false;
412 }
413
414 unprovisionTransparentFlows(subsPort.deviceId(), uplinkPort.number(), subsPort.port(),
415 cTag.get(), sTag.get());
416 return true;
417 } else {
418 log.warn("Removing subscriber failed for: {}", subscriberId);
419 return false;
420 }
Amit Ghosh31939522018-08-16 13:28:21 +0100421 }
422
423 @Override
424 public Collection<Map.Entry<ConnectPoint, Map.Entry<VlanId, VlanId>>> getSubscribers() {
425 ArrayList<Map.Entry<ConnectPoint, Map.Entry<VlanId, VlanId>>> subs = new ArrayList<>();
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100426
Saurav Das82b8e6d2018-10-04 15:25:12 -0700427 // Get the subscribers for all the devices configured in sadis
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100428 // If the port is UNI, is enabled and exists in Sadis then copy it
429 for (Device d : deviceService.getDevices()) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700430 if (getOltInfo(d) == null) {
431 continue; // not an olt, or not configured in sadis
432 }
Gamze Abakaad329652018-12-20 10:12:21 +0000433 for (Port p : deviceService.getPorts(d.id())) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100434 if (isUniPort(d, p) && p.isEnabled()) {
435 ConnectPoint cp = new ConnectPoint(d.id(), p.number());
436
437 SubscriberAndDeviceInformation sub = getSubscriber(cp);
438 if (sub != null) {
Amit Ghosh31939522018-08-16 13:28:21 +0100439 Map.Entry<VlanId, VlanId> vlans = new AbstractMap.SimpleEntry(sub.sTag(), sub.cTag());
440 subs.add(new AbstractMap.SimpleEntry(cp, vlans));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100441 }
442 }
443 }
444 }
445
446 return subs;
Jonathan Hartfd6c1b32016-03-08 14:09:09 -0800447 }
448
449 @Override
Saurav Das82b8e6d2018-10-04 15:25:12 -0700450 public ImmutableMap<ConnectPoint, SubscriberAndDeviceInformation> getProgSubs() {
451 return ImmutableMap.copyOf(programmedSubs);
452 }
453
454 @Override
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100455 public List<DeviceId> fetchOlts() {
456 // look through all the devices and find the ones that are OLTs as per Sadis
457 List<DeviceId> olts = new ArrayList<>();
458 Iterable<Device> devices = deviceService.getDevices();
459 for (Device d : devices) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700460 if (getOltInfo(d) != null) {
461 // So this is indeed an OLT device
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100462 olts.add(d.id());
463 }
464 }
465 return olts;
alshabibe0559672016-02-21 14:49:51 -0800466 }
467
Amit Ghosh31939522018-08-16 13:28:21 +0100468 /**
469 * Finds the connect point to which a subscriber is connected.
470 *
471 * @param id The id of the subscriber, this is the same ID as in Sadis
472 * @return Subscribers ConnectPoint if found else null
473 */
474 private ConnectPoint findSubscriberConnectPoint(String id) {
475
476 Iterable<Device> devices = deviceService.getDevices();
477 for (Device d : devices) {
478 for (Port p : deviceService.getPorts(d.id())) {
479 log.trace("Comparing {} with {}", p.annotations().value(AnnotationKeys.PORT_NAME), id);
480 if (p.annotations().value(AnnotationKeys.PORT_NAME).equals(id)) {
481 log.debug("Found on device {} port {}", d.id(), p.number());
482 return new ConnectPoint(d.id(), p.number());
483 }
484 }
485 }
486 return null;
487 }
488
Gamze Abaka641fc072018-09-04 09:16:27 +0000489 private BandwidthProfileInformation getBandwidthProfileInformation(String bandwidthProfile) {
490 if (bandwidthProfile == null) {
491 return null;
492 }
493 return bpService.get(bandwidthProfile);
494 }
495
alshabibbf23a1f2016-01-14 17:27:11 -0800496 private void unprovisionSubscriber(DeviceId deviceId, PortNumber uplink,
Gamze Abaka641fc072018-09-04 09:16:27 +0000497 PortNumber subscriberPort, SubscriberAndDeviceInformation subscriber,
498 Optional<VlanId> defaultVlan) {
alshabibbf23a1f2016-01-14 17:27:11 -0800499
500 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
501 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
502
Gamze Abaka641fc072018-09-04 09:16:27 +0000503 VlanId deviceVlan = subscriber.sTag();
504 VlanId subscriberVlan = subscriber.cTag();
505
506 MeterId upstreamMeterId = bpInfoToMeter.get(subscriber.upstreamBandwidthProfile());
507 MeterId downstreamMeterId = bpInfoToMeter.get(subscriber.downstreamBandwidthProfile());
508
alshabib4ceaed32016-03-03 18:00:58 -0800509 ForwardingObjective.Builder upFwd = upBuilder(uplink, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000510 subscriberVlan, deviceVlan,
511 defaultVlan, upstreamMeterId, subscriber.technologyProfileId());
alshabib4ceaed32016-03-03 18:00:58 -0800512 ForwardingObjective.Builder downFwd = downBuilder(uplink, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000513 subscriberVlan, deviceVlan,
514 defaultVlan, downstreamMeterId, subscriber.technologyProfileId());
alshabibbf23a1f2016-01-14 17:27:11 -0800515
alshabib4ceaed32016-03-03 18:00:58 -0800516 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
517 @Override
518 public void onSuccess(Objective objective) {
519 upFuture.complete(null);
520 }
alshabibbf23a1f2016-01-14 17:27:11 -0800521
alshabib4ceaed32016-03-03 18:00:58 -0800522 @Override
523 public void onError(Objective objective, ObjectiveError error) {
524 upFuture.complete(error);
525 }
526 }));
527
528 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
529 @Override
530 public void onSuccess(Objective objective) {
531 downFuture.complete(null);
532 }
533
534 @Override
535 public void onError(Objective objective, ObjectiveError error) {
536 downFuture.complete(error);
537 }
538 }));
alshabibbf23a1f2016-01-14 17:27:11 -0800539
540 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
541 if (upStatus == null && downStatus == null) {
542 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_UNREGISTERED,
Gamze Abaka641fc072018-09-04 09:16:27 +0000543 deviceId,
544 deviceVlan,
545 subscriberVlan));
alshabibbf23a1f2016-01-14 17:27:11 -0800546 } else if (downStatus != null) {
547 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000548 "on port {} failed downstream uninstallation: {}",
549 subscriberVlan, deviceId, subscriberPort, downStatus);
alshabibbf23a1f2016-01-14 17:27:11 -0800550 } else if (upStatus != null) {
551 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000552 "on port {} failed upstream uninstallation: {}",
553 subscriberVlan, deviceId, subscriberPort, upStatus);
alshabibbf23a1f2016-01-14 17:27:11 -0800554 }
555 }, oltInstallers);
alshabibb7a9e172016-01-13 11:23:53 -0800556
Jonathan Harte533a422015-10-20 17:31:24 -0700557 }
558
Gamze Abaka641fc072018-09-04 09:16:27 +0000559 private void provisionVlans(ConnectPoint port, PortNumber uplinkPort, Optional<VlanId> defaultVlan,
560 SubscriberAndDeviceInformation sub) {
561
562 log.info("Provisioning vlans...");
563
564 DeviceId deviceId = port.deviceId();
565 PortNumber subscriberPort = port.port();
566 VlanId deviceVlan = sub.sTag();
567 VlanId subscriberVlan = sub.cTag();
568 int techProfId = sub.technologyProfileId();
569
570 BandwidthProfileInformation upstreamBpInfo = getBandwidthProfileInformation(sub.upstreamBandwidthProfile());
571 BandwidthProfileInformation downstreamBpInfo = getBandwidthProfileInformation(sub.downstreamBandwidthProfile());
572
573 MeterId usptreamMeterId = createMeter(deviceId, upstreamBpInfo);
574 MeterId downstreamMeterId = createMeter(deviceId, downstreamBpInfo);
Jonathan Harte533a422015-10-20 17:31:24 -0700575
alshabib3ea82642016-01-12 18:06:53 -0800576 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
577 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
578
alshabib4ceaed32016-03-03 18:00:58 -0800579 ForwardingObjective.Builder upFwd = upBuilder(uplinkPort, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000580 subscriberVlan, deviceVlan,
581 defaultVlan, usptreamMeterId, techProfId);
Jonathan Harte533a422015-10-20 17:31:24 -0700582
alshabib4ceaed32016-03-03 18:00:58 -0800583 ForwardingObjective.Builder downFwd = downBuilder(uplinkPort, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000584 subscriberVlan, deviceVlan,
585 defaultVlan, downstreamMeterId, techProfId);
alshabib3ea82642016-01-12 18:06:53 -0800586
alshabibbf23a1f2016-01-14 17:27:11 -0800587 flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
588 @Override
589 public void onSuccess(Objective objective) {
590 upFuture.complete(null);
591 }
592
593 @Override
594 public void onError(Objective objective, ObjectiveError error) {
595 upFuture.complete(error);
596 }
597 }));
598
alshabibbf23a1f2016-01-14 17:27:11 -0800599 flowObjectiveService.forward(deviceId, downFwd.add(new ObjectiveContext() {
600 @Override
601 public void onSuccess(Objective objective) {
602 downFuture.complete(null);
603 }
604
605 @Override
606 public void onError(Objective objective, ObjectiveError error) {
607 downFuture.complete(error);
608 }
609 }));
alshabib3ea82642016-01-12 18:06:53 -0800610
611 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
612 if (upStatus == null && downStatus == null) {
613 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_REGISTERED,
Gamze Abaka641fc072018-09-04 09:16:27 +0000614 deviceId,
615 deviceVlan,
616 subscriberVlan));
alshabib50d9fc52016-02-12 15:47:20 -0800617
alshabib3ea82642016-01-12 18:06:53 -0800618 } else if (downStatus != null) {
619 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000620 "on port {} failed downstream installation: {}",
621 subscriberVlan, deviceId, subscriberPort, downStatus);
alshabib3ea82642016-01-12 18:06:53 -0800622 } else if (upStatus != null) {
623 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000624 "on port {} failed upstream installation: {}",
625 subscriberVlan, deviceId, subscriberPort, upStatus);
alshabib3ea82642016-01-12 18:06:53 -0800626 }
627 }, oltInstallers);
628
Jonathan Harte533a422015-10-20 17:31:24 -0700629 }
630
Gamze Abaka641fc072018-09-04 09:16:27 +0000631 private MeterId createMeter(DeviceId deviceId, BandwidthProfileInformation bpInfo) {
632
633 if (bpInfo == null) {
634 log.warn("Bandwidth profile information is not found");
635 return null;
636 }
637
638 MeterId meterId = bpInfoToMeter.get(bpInfo.id());
639 if (meterId != null) {
640 log.info("Meter is already added. MeterId {}", meterId);
641 return meterId;
642 }
643
644 List<Band> meterBands = createMeterBands(bpInfo);
645
646 MeterRequest meterRequest = DefaultMeterRequest.builder()
647 .withBands(meterBands)
648 .withUnit(Meter.Unit.KB_PER_SEC)
649 .forDevice(deviceId)
650 .fromApp(appId)
651 .burst()
652 .add();
653
654 Meter meter = meterService.submit(meterRequest);
655 bpInfoToMeter.put(bpInfo.id(), meter.id());
656 log.info("Meter is created. Meter Id {}", meter.id());
657 return meter.id();
658 }
659
660 private List<Band> createMeterBands(BandwidthProfileInformation bpInfo) {
661 List<Band> meterBands = new ArrayList<>();
662
663 meterBands.add(createMeterBand(bpInfo.committedInformationRate(), bpInfo.committedBurstSize()));
664 meterBands.add(createMeterBand(bpInfo.exceededInformationRate(), bpInfo.exceededBurstSize()));
Gamze Abakaad329652018-12-20 10:12:21 +0000665 meterBands.add(createMeterBand(bpInfo.assuredInformationRate(), 0L));
Gamze Abaka641fc072018-09-04 09:16:27 +0000666
Gamze Abaka641fc072018-09-04 09:16:27 +0000667 return meterBands;
668 }
669
670 private Band createMeterBand(long rate, Long burst) {
671 return DefaultBand.builder()
672 .withRate(rate) //already Kbps
673 .burstSize(burst) // already Kbits
674 .ofType(Band.Type.DROP) // no matter
675 .build();
676 }
677
alshabib4ceaed32016-03-03 18:00:58 -0800678 private ForwardingObjective.Builder downBuilder(PortNumber uplinkPort,
679 PortNumber subscriberPort,
680 VlanId subscriberVlan,
681 VlanId deviceVlan,
Gamze Abaka641fc072018-09-04 09:16:27 +0000682 Optional<VlanId> defaultVlan,
683 MeterId meterId,
684 int techProfId) {
alshabib4ceaed32016-03-03 18:00:58 -0800685 TrafficSelector downstream = DefaultTrafficSelector.builder()
686 .matchVlanId(deviceVlan)
687 .matchInPort(uplinkPort)
688 .matchInnerVlanId(subscriberVlan)
689 .build();
690
Gamze Abaka641fc072018-09-04 09:16:27 +0000691 TrafficTreatment.Builder downstreamTreatmentBuilder = DefaultTrafficTreatment.builder()
alshabib4ceaed32016-03-03 18:00:58 -0800692 .popVlan()
693 .setVlanId(defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan)))
Gamze Abaka641fc072018-09-04 09:16:27 +0000694 .setOutput(subscriberPort);
695
696 if (meterId != null) {
697 downstreamTreatmentBuilder.meter(meterId);
698 }
699
Gamze Abakaad329652018-12-20 10:12:21 +0000700 downstreamTreatmentBuilder.writeMetadata(createMetadata(subscriberVlan, techProfId, subscriberPort), 0);
alshabib4ceaed32016-03-03 18:00:58 -0800701
702 return DefaultForwardingObjective.builder()
703 .withFlag(ForwardingObjective.Flag.VERSATILE)
704 .withPriority(1000)
705 .makePermanent()
706 .withSelector(downstream)
707 .fromApp(appId)
Gamze Abaka641fc072018-09-04 09:16:27 +0000708 .withTreatment(downstreamTreatmentBuilder.build());
alshabib4ceaed32016-03-03 18:00:58 -0800709 }
710
711 private ForwardingObjective.Builder upBuilder(PortNumber uplinkPort,
712 PortNumber subscriberPort,
713 VlanId subscriberVlan,
714 VlanId deviceVlan,
Gamze Abaka641fc072018-09-04 09:16:27 +0000715 Optional<VlanId> defaultVlan,
716 MeterId meterId,
717 int technologyProfileId) {
718
719
720 VlanId dVlan = defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan));
721
722 if (subscriberVlan.toShort() == 4096) {
723 dVlan = subscriberVlan;
724 }
725
alshabib4ceaed32016-03-03 18:00:58 -0800726 TrafficSelector upstream = DefaultTrafficSelector.builder()
Gamze Abaka641fc072018-09-04 09:16:27 +0000727 .matchVlanId(dVlan)
alshabib4ceaed32016-03-03 18:00:58 -0800728 .matchInPort(subscriberPort)
729 .build();
730
731
Gamze Abaka641fc072018-09-04 09:16:27 +0000732 TrafficTreatment.Builder upstreamTreatmentBuilder = DefaultTrafficTreatment.builder()
alshabib4ceaed32016-03-03 18:00:58 -0800733 .pushVlan()
734 .setVlanId(subscriberVlan)
735 .pushVlan()
736 .setVlanId(deviceVlan)
Gamze Abaka641fc072018-09-04 09:16:27 +0000737 .setOutput(uplinkPort);
738
739 if (meterId != null) {
740 upstreamTreatmentBuilder.meter(meterId);
741 }
742
Gamze Abakaad329652018-12-20 10:12:21 +0000743 upstreamTreatmentBuilder.writeMetadata(createMetadata(deviceVlan, technologyProfileId, uplinkPort), 0L);
alshabib4ceaed32016-03-03 18:00:58 -0800744
745 return DefaultForwardingObjective.builder()
746 .withFlag(ForwardingObjective.Flag.VERSATILE)
747 .withPriority(1000)
748 .makePermanent()
749 .withSelector(upstream)
750 .fromApp(appId)
Gamze Abaka641fc072018-09-04 09:16:27 +0000751 .withTreatment(upstreamTreatmentBuilder.build());
alshabib4ceaed32016-03-03 18:00:58 -0800752 }
Gamze Abakaad329652018-12-20 10:12:21 +0000753
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100754 private void provisionTransparentFlows(DeviceId deviceId, PortNumber uplinkPort,
755 PortNumber subscriberPort,
756 VlanId innerVlan,
757 VlanId outerVlan) {
758
759 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
760 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
761
762 ForwardingObjective.Builder upFwd = transparentUpBuilder(uplinkPort, subscriberPort,
763 innerVlan, outerVlan);
764
765
766 ForwardingObjective.Builder downFwd = transparentDownBuilder(uplinkPort, subscriberPort,
767 innerVlan, outerVlan);
768
769 ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
770
771 additionalVlans.put(cp, new AbstractMap.SimpleEntry(outerVlan, innerVlan));
772
773 flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
774 @Override
775 public void onSuccess(Objective objective) {
776 upFuture.complete(null);
777 }
778
779 @Override
780 public void onError(Objective objective, ObjectiveError error) {
781 upFuture.complete(error);
782 }
783 }));
784
785 flowObjectiveService.forward(deviceId, downFwd.add(new ObjectiveContext() {
786 @Override
787 public void onSuccess(Objective objective) {
788 downFuture.complete(null);
789 }
790
791 @Override
792 public void onError(Objective objective, ObjectiveError error) {
793 downFuture.complete(error);
794 }
795 }));
796
797 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
798 if (downStatus != null) {
799 log.error("Flow with innervlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000800 "on port {} failed downstream installation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100801 innerVlan, outerVlan, deviceId, subscriberPort, downStatus);
802 } else if (upStatus != null) {
803 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000804 "on port {} failed upstream installation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100805 innerVlan, outerVlan, deviceId, subscriberPort, upStatus);
806 }
807 }, oltInstallers);
808
809 }
810
811 private ForwardingObjective.Builder transparentDownBuilder(PortNumber uplinkPort,
812 PortNumber subscriberPort,
813 VlanId innerVlan,
814 VlanId outerVlan) {
815 TrafficSelector downstream = DefaultTrafficSelector.builder()
816 .matchVlanId(outerVlan)
817 .matchInPort(uplinkPort)
818 .matchInnerVlanId(innerVlan)
819 .build();
820
821 TrafficTreatment downstreamTreatment = DefaultTrafficTreatment.builder()
822 .setOutput(subscriberPort)
823 .build();
824
825 return DefaultForwardingObjective.builder()
826 .withFlag(ForwardingObjective.Flag.VERSATILE)
827 .withPriority(1000)
828 .makePermanent()
829 .withSelector(downstream)
830 .fromApp(appId)
831 .withTreatment(downstreamTreatment);
832 }
833
834 private ForwardingObjective.Builder transparentUpBuilder(PortNumber uplinkPort,
835 PortNumber subscriberPort,
836 VlanId innerVlan,
837 VlanId outerVlan) {
838 TrafficSelector upstream = DefaultTrafficSelector.builder()
839 .matchVlanId(outerVlan)
840 .matchInPort(subscriberPort)
841 .matchInnerVlanId(innerVlan)
842 .build();
843
844 TrafficTreatment upstreamTreatment = DefaultTrafficTreatment.builder()
845 .setOutput(uplinkPort)
846 .build();
847
848 return DefaultForwardingObjective.builder()
849 .withFlag(ForwardingObjective.Flag.VERSATILE)
850 .withPriority(1000)
851 .makePermanent()
852 .withSelector(upstream)
853 .fromApp(appId)
854 .withTreatment(upstreamTreatment);
855 }
856
857 private void unprovisionTransparentFlows(DeviceId deviceId, PortNumber uplink,
858 PortNumber subscriberPort, VlanId innerVlan,
859 VlanId outerVlan) {
860
861 ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
862
863 additionalVlans.remove(cp, new AbstractMap.SimpleEntry(outerVlan, innerVlan));
864
865 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
866 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
867
868 ForwardingObjective.Builder upFwd = transparentUpBuilder(uplink, subscriberPort,
869 innerVlan, outerVlan);
870 ForwardingObjective.Builder downFwd = transparentDownBuilder(uplink, subscriberPort,
871 innerVlan, outerVlan);
872
873
874 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
875 @Override
876 public void onSuccess(Objective objective) {
877 upFuture.complete(null);
878 }
879
880 @Override
881 public void onError(Objective objective, ObjectiveError error) {
882 upFuture.complete(error);
883 }
884 }));
885
886 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
887 @Override
888 public void onSuccess(Objective objective) {
889 downFuture.complete(null);
890 }
891
892 @Override
893 public void onError(Objective objective, ObjectiveError error) {
894 downFuture.complete(error);
895 }
896 }));
897
898 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
899 if (downStatus != null) {
900 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000901 "on port {} failed downstream uninstallation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100902 innerVlan, outerVlan, deviceId, subscriberPort, downStatus);
903 } else if (upStatus != null) {
904 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000905 "on port {} failed upstream uninstallation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100906 innerVlan, outerVlan, deviceId, subscriberPort, upStatus);
907 }
908 }, oltInstallers);
909
910 }
911
Gamze Abaka1efc80c2019-02-15 12:10:54 +0000912 private int getDefaultTechProfileId(DeviceId devId, PortNumber portNumber) {
913 Port port = deviceService.getPort(devId, portNumber);
914 SubscriberAndDeviceInformation info = subsService.get(port.annotations().value(AnnotationKeys.PORT_NAME));
915 if (info != null && info.technologyProfileId() != -1) {
916 return info.technologyProfileId();
917 }
918 return defaultTechProfileId;
919 }
920
921 private void processEapolFilteringObjectives(DeviceId devId, PortNumber portNumber, boolean install) {
alshabib09753b52016-03-04 14:55:19 -0800922 if (!mastershipService.isLocalMaster(devId)) {
923 return;
924 }
alshabibbb83aa22016-02-10 15:08:23 -0800925 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Gamze Abakaad329652018-12-20 10:12:21 +0000926 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
alshabibbb83aa22016-02-10 15:08:23 -0800927
Gamze Abakaad329652018-12-20 10:12:21 +0000928 BandwidthProfileInformation defaultBpInfo = getBandwidthProfileInformation(defaultBpId);
929 if (defaultBpInfo != null) {
930 MeterId meterId = createMeter(devId, defaultBpInfo);
931 treatmentBuilder.meter(meterId);
932 } else {
933 log.warn("Default bandwidth profile is not found. Authentication flow will be installed without meter");
934 }
935
Gamze Abaka1efc80c2019-02-15 12:10:54 +0000936 int techProfileId = getDefaultTechProfileId(devId, portNumber);
937 log.debug("Eapol trap flow will be installed using the tech profile id {}", techProfileId);
938
939 //Authentication trap flow uses only tech profile id as write metadata value
alshabibbb83aa22016-02-10 15:08:23 -0800940 FilteringObjective eapol = (install ? builder.permit() : builder.deny())
Gamze Abaka1efc80c2019-02-15 12:10:54 +0000941 .withKey(Criteria.matchInPort(portNumber))
alshabibdec2e252016-01-15 12:20:25 -0800942 .addCondition(Criteria.matchEthType(EthType.EtherType.EAPOL.ethType()))
Gamze Abakaad329652018-12-20 10:12:21 +0000943 .withMeta(treatmentBuilder
Gamze Abaka1efc80c2019-02-15 12:10:54 +0000944 .writeMetadata((long) techProfileId << 32, 0)
Gamze Abaka641fc072018-09-04 09:16:27 +0000945 .setOutput(PortNumber.CONTROLLER).build())
alshabibdec2e252016-01-15 12:20:25 -0800946 .fromApp(appId)
Matt Jeanneret3f579262018-06-14 17:16:23 -0400947 .withPriority(10000)
alshabibdec2e252016-01-15 12:20:25 -0800948 .add(new ObjectiveContext() {
949 @Override
950 public void onSuccess(Objective objective) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700951 log.info("Eapol filter for {} on {} {}.",
Gamze Abaka1efc80c2019-02-15 12:10:54 +0000952 devId, portNumber, (install) ? "installed" : "removed");
alshabibdec2e252016-01-15 12:20:25 -0800953 }
954
955 @Override
956 public void onError(Objective objective, ObjectiveError error) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700957 log.info("Eapol filter for {} on {} failed {} because {}",
Gamze Abaka1efc80c2019-02-15 12:10:54 +0000958 devId, portNumber, (install) ? "installation" : "removal",
Gamze Abaka641fc072018-09-04 09:16:27 +0000959 error);
alshabibdec2e252016-01-15 12:20:25 -0800960 }
961 });
962
alshabibdec2e252016-01-15 12:20:25 -0800963 flowObjectiveService.filter(devId, eapol);
alshabib000b6fc2016-02-01 17:25:00 -0800964
alshabibdec2e252016-01-15 12:20:25 -0800965 }
966
Jonathan Hart403372d2018-08-22 11:44:13 -0700967 /**
968 * Installs trap filtering objectives for particular traffic types on an
969 * NNI port.
970 *
Gamze Abakaad329652018-12-20 10:12:21 +0000971 * @param devId device ID
972 * @param port port number
Jonathan Hart403372d2018-08-22 11:44:13 -0700973 * @param install true to install, false to remove
974 */
975 private void processNniFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
976 processLldpFilteringObjective(devId, port, install);
Matteo Scandolo63460d12018-11-02 16:19:04 -0700977 if (enableDhcpOnProvisioning) {
978 processDhcpFilteringObjectives(devId, port, install, false);
979 }
Jonathan Hart403372d2018-08-22 11:44:13 -0700980 }
981
982 private void processLldpFilteringObjective(DeviceId devId, PortNumber port, boolean install) {
983 if (!mastershipService.isLocalMaster(devId)) {
984 return;
985 }
986 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
987
988 FilteringObjective lldp = (install ? builder.permit() : builder.deny())
989 .withKey(Criteria.matchInPort(port))
990 .addCondition(Criteria.matchEthType(EthType.EtherType.LLDP.ethType()))
991 .withMeta(DefaultTrafficTreatment.builder()
992 .setOutput(PortNumber.CONTROLLER).build())
993 .fromApp(appId)
994 .withPriority(10000)
995 .add(new ObjectiveContext() {
996 @Override
997 public void onSuccess(Objective objective) {
Matteo Scandolo63460d12018-11-02 16:19:04 -0700998 log.info("LLDP filter for device {} on port {} {}.",
Saurav Das82b8e6d2018-10-04 15:25:12 -0700999 devId, port, (install) ? "installed" : "removed");
Jonathan Hart403372d2018-08-22 11:44:13 -07001000 }
1001
1002 @Override
1003 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001004 log.info("LLDP filter for device {} on port {} failed {} because {}",
Saurav Das82b8e6d2018-10-04 15:25:12 -07001005 devId, port, (install) ? "installation" : "removal",
1006 error);
Jonathan Hart403372d2018-08-22 11:44:13 -07001007 }
1008 });
1009
1010 flowObjectiveService.filter(devId, lldp);
1011
1012 }
1013
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001014 /**
1015 * Trap dhcp packets to the controller.
1016 *
Gamze Abakaad329652018-12-20 10:12:21 +00001017 * @param devId the device identifier
1018 * @param port the port for which this trap flow is designated
1019 * @param install true to install the flow, false to remove the flow
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001020 * @param upstream true if trapped packets are flowing upstream towards
Gamze Abakaad329652018-12-20 10:12:21 +00001021 * server, false if packets are flowing dowstream towards client
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001022 */
1023 private void processDhcpFilteringObjectives(DeviceId devId, PortNumber port,
1024 boolean install,
1025 boolean upstream) {
Amit Ghosh95e2f652017-08-23 12:49:46 +01001026 if (!mastershipService.isLocalMaster(devId)) {
1027 return;
1028 }
Amit Ghosh95e2f652017-08-23 12:49:46 +01001029
Matteo Scandolo63460d12018-11-02 16:19:04 -07001030 if (enableDhcpV4) {
1031 int udpSrc = (upstream) ? 68 : 67;
1032 int udpDst = (upstream) ? 67 : 68;
1033
1034 EthType ethType = EthType.EtherType.IPV4.ethType();
1035 byte protocol = IPv4.PROTOCOL_UDP;
1036
1037 this.addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType, protocol, install);
1038 }
1039
1040 if (enableDhcpV6) {
1041 int udpSrc = (upstream) ? 547 : 546;
1042 int udpDst = (upstream) ? 546 : 547;
1043
1044 EthType ethType = EthType.EtherType.IPV6.ethType();
1045 byte protocol = IPv6.PROTOCOL_UDP;
1046
1047 this.addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType, protocol, install);
1048 }
1049
1050 }
1051
1052 private void addDhcpFilteringObjectives(DeviceId devId,
1053 PortNumber port,
1054 int udpSrc,
1055 int udpDst,
1056 EthType ethType,
1057 byte protocol,
1058 boolean install) {
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001059
1060 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Amit Ghosh95e2f652017-08-23 12:49:46 +01001061 FilteringObjective dhcpUpstream = (install ? builder.permit() : builder.deny())
1062 .withKey(Criteria.matchInPort(port))
Matteo Scandolo63460d12018-11-02 16:19:04 -07001063 .addCondition(Criteria.matchEthType(ethType))
1064 .addCondition(Criteria.matchIPProtocol(protocol))
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001065 .addCondition(Criteria.matchUdpSrc(TpPort.tpPort(udpSrc)))
1066 .addCondition(Criteria.matchUdpDst(TpPort.tpPort(udpDst)))
Amit Ghosh95e2f652017-08-23 12:49:46 +01001067 .withMeta(DefaultTrafficTreatment.builder()
Gamze Abaka641fc072018-09-04 09:16:27 +00001068 .setOutput(PortNumber.CONTROLLER).build())
Amit Ghosh95e2f652017-08-23 12:49:46 +01001069 .fromApp(appId)
Matt Jeanneret3f579262018-06-14 17:16:23 -04001070 .withPriority(10000)
Amit Ghosh95e2f652017-08-23 12:49:46 +01001071 .add(new ObjectiveContext() {
1072 @Override
1073 public void onSuccess(Objective objective) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001074 log.info("DHCP {} filter for device {} on port {} {}.",
Gamze Abakaad329652018-12-20 10:12:21 +00001075 (ethType.equals(EthType.EtherType.IPV4.ethType())) ? "v4" : "v6",
1076 devId, port, (install) ? "installed" : "removed");
Amit Ghosh95e2f652017-08-23 12:49:46 +01001077 }
1078
1079 @Override
1080 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001081 log.info("DHCP {} filter for device {} on port {} failed {} because {}",
Gamze Abakaad329652018-12-20 10:12:21 +00001082 (ethType.equals(EthType.EtherType.IPV4.ethType())) ? "v4" : "v6",
1083 devId, port, (install) ? "installation" : "removal",
1084 error);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001085 }
1086 });
1087
1088 flowObjectiveService.filter(devId, dhcpUpstream);
1089 }
1090
1091 private void processIgmpFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
1092 if (!mastershipService.isLocalMaster(devId)) {
1093 return;
1094 }
1095
Gamze Abaka641fc072018-09-04 09:16:27 +00001096 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Amit Ghosh95e2f652017-08-23 12:49:46 +01001097
1098 builder = install ? builder.permit() : builder.deny();
1099
1100 FilteringObjective igmp = builder
1101 .withKey(Criteria.matchInPort(port))
1102 .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
1103 .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_IGMP))
1104 .withMeta(DefaultTrafficTreatment.builder()
Gamze Abaka641fc072018-09-04 09:16:27 +00001105 .setOutput(PortNumber.CONTROLLER).build())
Amit Ghosh95e2f652017-08-23 12:49:46 +01001106 .fromApp(appId)
1107 .withPriority(10000)
1108 .add(new ObjectiveContext() {
1109 @Override
1110 public void onSuccess(Objective objective) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001111 log.info("Igmp filter for {} on {} {}.",
Gamze Abaka641fc072018-09-04 09:16:27 +00001112 devId, port, (install) ? "installed" : "removed");
Amit Ghosh95e2f652017-08-23 12:49:46 +01001113 }
1114
1115 @Override
1116 public void onError(Objective objective, ObjectiveError error) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001117 log.info("Igmp filter for {} on {} failed {} because {}.",
Gamze Abaka641fc072018-09-04 09:16:27 +00001118 devId, port, (install) ? "installation" : "removal",
1119 error);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001120 }
1121 });
1122
1123 flowObjectiveService.filter(devId, igmp);
1124 }
1125
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001126 /**
Jonathan Hart403372d2018-08-22 11:44:13 -07001127 * Creates trap flows for device, including DHCP and LLDP trap on NNI and
1128 * EAPOL trap on the UNIs, if device is present in Sadis config.
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001129 *
1130 * @param dev Device to look for
1131 */
Jonathan Hart403372d2018-08-22 11:44:13 -07001132 private void checkAndCreateDeviceFlows(Device dev) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001133 // we create only for the ones we are master of
1134 if (!mastershipService.isLocalMaster(dev.id())) {
Gamze Abaka641fc072018-09-04 09:16:27 +00001135 return;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001136 }
1137 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +00001138 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Jonathan Hart403372d2018-08-22 11:44:13 -07001139 log.debug("checkAndCreateDeviceFlows: deviceInfo {}", deviceInfo);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001140
1141 if (deviceInfo != null) {
Jonathan Hart403372d2018-08-22 11:44:13 -07001142 // This is an OLT device as per Sadis, we create flows for UNI and NNI ports
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001143 for (Port p : deviceService.getPorts(dev.id())) {
1144 if (isUniPort(dev, p)) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001145 processEapolFilteringObjectives(dev.id(), p.number(), true);
Jonathan Hart403372d2018-08-22 11:44:13 -07001146 } else {
1147 processNniFilteringObjectives(dev.id(), p.number(), true);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001148 }
1149 }
1150 }
1151 }
1152
Jonathan Hart403372d2018-08-22 11:44:13 -07001153
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001154 /**
1155 * Get the uplink for of the OLT device.
Gamze Abakaad329652018-12-20 10:12:21 +00001156 * <p>
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001157 * This assumes that the OLT has a single uplink port. When more uplink ports need to be supported
1158 * this logic needs to be changed
1159 *
1160 * @param dev Device to look for
1161 * @return The uplink Port of the OLT
1162 */
1163 private Port getUplinkPort(Device dev) {
1164 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +00001165 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001166 log.debug("getUplinkPort: deviceInfo {}", deviceInfo);
Saurav Das82b8e6d2018-10-04 15:25:12 -07001167 if (deviceInfo == null) {
1168 log.warn("Device {} is not configured in SADIS .. cannot fetch device"
1169 + " info", dev.id());
1170 return null;
1171 }
1172 // Return the port that has been configured as the uplink port of this OLT in Sadis
Gamze Abakaad329652018-12-20 10:12:21 +00001173 for (Port p : deviceService.getPorts(dev.id())) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001174 if (p.number().toLong() == deviceInfo.uplinkPort()) {
1175 log.debug("getUplinkPort: Found port {}", p);
1176 return p;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001177 }
1178 }
1179
Saurav Das82b8e6d2018-10-04 15:25:12 -07001180 log.debug("getUplinkPort: No uplink port found for OLT {}", dev.id());
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001181 return null;
1182 }
1183
1184 /**
1185 * Return the subscriber on a port.
1186 *
Matteo Scandolo962a6ad2018-12-11 15:39:42 -08001187 * @param cp ConnectPoint on which to find the subscriber
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001188 * @return subscriber if found else null
1189 */
Matteo Scandolo962a6ad2018-12-11 15:39:42 -08001190 SubscriberAndDeviceInformation getSubscriber(ConnectPoint cp) {
1191 Port port = deviceService.getPort(cp);
1192 checkNotNull(port, "Invalid connect point");
1193 String portName = port.annotations().value(AnnotationKeys.PORT_NAME);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001194 return subsService.get(portName);
1195 }
1196
Gamze Abakaad329652018-12-20 10:12:21 +00001197 /**
1198 * Write metadata instruction value (metadata) is 8 bytes.
1199 *
1200 * MS 2 bytes: C Tag
1201 * Next 2 bytes: Technology Profile Id
1202 * Next 4 bytes: Port number (uni or nni)
1203 */
1204
1205 private Long createMetadata(VlanId innerVlan, int techProfileId, PortNumber egressPort) {
1206
1207 if (techProfileId == -1) {
1208 techProfileId = DEFAULT_TP_ID;
1209 }
1210
1211 return ((long) (innerVlan.id()) << 48 | (long) techProfileId << 32) | egressPort.toLong();
1212 }
1213
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001214 private boolean isUniPort(Device d, Port p) {
1215 Port ulPort = getUplinkPort(d);
1216 if (ulPort != null) {
1217 return (ulPort.number().toLong() != p.number().toLong());
1218 }
1219 return false;
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001220 }
1221
Jonathan Hart4c538002018-08-23 10:11:54 -07001222 private SubscriberAndDeviceInformation getOltInfo(Device dev) {
1223 String devSerialNo = dev.serialNumber();
Gamze Abaka641fc072018-09-04 09:16:27 +00001224 return subsService.get(devSerialNo);
Jonathan Hart4c538002018-08-23 10:11:54 -07001225 }
1226
alshabibf0e7e702015-05-30 18:22:36 -07001227 private class InternalDeviceListener implements DeviceListener {
1228 @Override
1229 public void event(DeviceEvent event) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001230 eventExecutor.execute(() -> {
1231 DeviceId devId = event.subject().id();
1232 Device dev = event.subject();
Jonathan Hart4c538002018-08-23 10:11:54 -07001233
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001234 if (event.type() == DeviceEvent.Type.PORT_STATS_UPDATED) {
1235 return;
1236 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001237
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001238 if (getOltInfo(dev) == null) {
1239 log.debug("No device info found, this is not an OLT");
1240 return;
1241 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001242
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001243 log.debug("OLT got {} event for {}", event.type(), event.subject());
Jonathan Hart4c538002018-08-23 10:11:54 -07001244
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001245 switch (event.type()) {
1246 //TODO: Port handling and bookkeeping should be improved once
1247 // olt firmware handles correct behaviour.
1248 case PORT_ADDED:
1249 if (isUniPort(dev, event.port())) {
1250 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, event.port()));
Jonathan Hart4c538002018-08-23 10:11:54 -07001251
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001252 if (event.port().isEnabled()) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001253 processEapolFilteringObjectives(devId, event.port().number(), true);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001254 }
1255 } else {
1256 checkAndCreateDeviceFlows(dev);
1257 }
1258 break;
1259 case PORT_REMOVED:
1260 if (isUniPort(dev, event.port())) {
1261 if (event.port().isEnabled()) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001262 processEapolFilteringObjectives(devId, event.port().number(), false);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001263 removeSubscriber(new ConnectPoint(devId, event.port().number()));
1264 }
1265
1266 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, event.port()));
1267 }
1268
1269 break;
1270 case PORT_UPDATED:
1271 if (!isUniPort(dev, event.port())) {
1272 break;
1273 }
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001274
1275 if (event.port().isEnabled()) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001276 processEapolFilteringObjectives(devId, event.port().number(), true);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001277 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, event.port()));
1278 } else {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001279 processEapolFilteringObjectives(devId, event.port().number(), false);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001280 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, event.port()));
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001281 }
alshabibbb83aa22016-02-10 15:08:23 -08001282 break;
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001283 case DEVICE_ADDED:
alshabib7c190012016-02-09 18:22:33 -08001284 post(new AccessDeviceEvent(
1285 AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
1286 null, null));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001287
1288 // Send UNI_ADDED events for all existing ports
1289 deviceService.getPorts(devId).stream()
1290 .filter(p -> isUniPort(dev, p))
1291 .filter(Port::isEnabled)
1292 .forEach(p -> post(new AccessDeviceEvent(
1293 AccessDeviceEvent.Type.UNI_ADDED, devId, p)));
1294
Jonathan Hart403372d2018-08-22 11:44:13 -07001295 checkAndCreateDeviceFlows(dev);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001296 break;
1297 case DEVICE_REMOVED:
1298 deviceService.getPorts(devId).stream()
1299 .filter(p -> isUniPort(dev, p))
1300 .forEach(p -> post(new AccessDeviceEvent(
1301 AccessDeviceEvent.Type.UNI_REMOVED, devId, p)));
1302
alshabib7c190012016-02-09 18:22:33 -08001303 post(new AccessDeviceEvent(
1304 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
1305 null, null));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001306 break;
1307 case DEVICE_AVAILABILITY_CHANGED:
1308 if (deviceService.isAvailable(devId)) {
1309 post(new AccessDeviceEvent(
1310 AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
1311 null, null));
1312 checkAndCreateDeviceFlows(dev);
1313 } else {
1314 post(new AccessDeviceEvent(
1315 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
1316 null, null));
1317 }
1318 break;
1319 case DEVICE_UPDATED:
1320 case DEVICE_SUSPENDED:
1321 case PORT_STATS_UPDATED:
1322 default:
1323 return;
1324 }
1325 });
alshabibf0e7e702015-05-30 18:22:36 -07001326 }
1327 }
Gamze Abaka641fc072018-09-04 09:16:27 +00001328
1329 private class InternalMeterListener implements MeterListener {
1330
1331 @Override
1332 public void event(MeterEvent meterEvent) {
1333 if (deleteMeters && MeterEvent.Type.METER_REFERENCE_COUNT_ZERO.equals(meterEvent.type())) {
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001334 log.info("Zero Count Meter Event is received. Meter is {}", meterEvent.subject());
Gamze Abaka641fc072018-09-04 09:16:27 +00001335 Meter meter = meterEvent.subject();
1336 if (meter != null && appId.equals(meter.appId())) {
1337 deleteMeter(meter.deviceId(), meter.id());
1338 }
1339 } else if (MeterEvent.Type.METER_REMOVED.equals(meterEvent.type())) {
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001340 log.info("Meter removed event is received. Meter is {}", meterEvent.subject());
Gamze Abaka641fc072018-09-04 09:16:27 +00001341 removeMeterFromBpMap(meterEvent.subject());
1342 }
1343 }
1344
1345 private void deleteMeter(DeviceId deviceId, MeterId meterId) {
1346 Meter meter = meterService.getMeter(deviceId, meterId);
1347 MeterRequest meterRequest = DefaultMeterRequest.builder()
1348 .withBands(meter.bands())
1349 .withUnit(meter.unit())
1350 .forDevice(deviceId)
1351 .fromApp(appId)
1352 .burst()
1353 .remove();
1354
1355 meterService.withdraw(meterRequest, meterId);
1356
1357 }
1358
1359 private void removeMeterFromBpMap(Meter meter) {
1360 for (Map.Entry<String, MeterId> entry : bpInfoToMeter.entrySet()) {
1361 if (entry.getValue().equals(meter.id())) {
1362 bpInfoToMeter.remove(entry.getKey());
1363 log.info("Deleted from the internal map. Profile {} and Meter {}", entry.getKey(), meter.id());
1364 break;
1365 }
1366 }
1367 }
1368 }
1369}