blob: 2116c706eae07bd992f030ed5eb7c85194526f53 [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;
48import org.onlab.packet.TpPort;
alshabibf0e7e702015-05-30 18:22:36 -070049import org.onlab.packet.VlanId;
Amit Ghosh95e2f652017-08-23 12:49:46 +010050import org.onlab.util.Tools;
alshabibe0559672016-02-21 14:49:51 -080051import org.onosproject.cfg.ComponentConfigService;
alshabibf0e7e702015-05-30 18:22:36 -070052import org.onosproject.core.ApplicationId;
53import org.onosproject.core.CoreService;
alshabib8e4fd2f2016-01-12 15:55:53 -080054import org.onosproject.event.AbstractListenerManager;
alshabib09753b52016-03-04 14:55:19 -080055import org.onosproject.mastership.MastershipService;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010056import org.onosproject.net.AnnotationKeys;
Jonathan Harte533a422015-10-20 17:31:24 -070057import org.onosproject.net.ConnectPoint;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010058import org.onosproject.net.Device;
alshabibf0e7e702015-05-30 18:22:36 -070059import org.onosproject.net.DeviceId;
alshabibdec2e252016-01-15 12:20:25 -080060import org.onosproject.net.Port;
alshabibf0e7e702015-05-30 18:22:36 -070061import org.onosproject.net.PortNumber;
62import org.onosproject.net.device.DeviceEvent;
63import org.onosproject.net.device.DeviceListener;
64import org.onosproject.net.device.DeviceService;
65import org.onosproject.net.flow.DefaultTrafficSelector;
66import org.onosproject.net.flow.DefaultTrafficTreatment;
67import org.onosproject.net.flow.TrafficSelector;
68import org.onosproject.net.flow.TrafficTreatment;
alshabibdec2e252016-01-15 12:20:25 -080069import org.onosproject.net.flow.criteria.Criteria;
70import org.onosproject.net.flowobjective.DefaultFilteringObjective;
alshabibf0e7e702015-05-30 18:22:36 -070071import org.onosproject.net.flowobjective.DefaultForwardingObjective;
alshabibdec2e252016-01-15 12:20:25 -080072import org.onosproject.net.flowobjective.FilteringObjective;
alshabibf0e7e702015-05-30 18:22:36 -070073import org.onosproject.net.flowobjective.FlowObjectiveService;
74import org.onosproject.net.flowobjective.ForwardingObjective;
alshabib3ea82642016-01-12 18:06:53 -080075import org.onosproject.net.flowobjective.Objective;
76import org.onosproject.net.flowobjective.ObjectiveContext;
77import org.onosproject.net.flowobjective.ObjectiveError;
Amit Ghoshe1d3f092018-10-09 19:44:33 +010078import org.onosproject.store.serializers.KryoNamespaces;
79import org.onosproject.store.service.ConsistentMultimap;
80import org.onosproject.store.service.Serializer;
81import org.onosproject.store.service.StorageService;
alshabib36a4d732016-06-01 16:03:59 -070082import org.opencord.olt.AccessDeviceEvent;
83import org.opencord.olt.AccessDeviceListener;
84import org.opencord.olt.AccessDeviceService;
Amit Ghosh31939522018-08-16 13:28:21 +010085import org.opencord.olt.AccessSubscriberId;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010086import org.opencord.sadis.SubscriberAndDeviceInformation;
87import org.opencord.sadis.SubscriberAndDeviceInformationService;
alshabibe0559672016-02-21 14:49:51 -080088import org.osgi.service.component.ComponentContext;
alshabibf0e7e702015-05-30 18:22:36 -070089import org.slf4j.Logger;
90
Amit Ghoshe1d3f092018-10-09 19:44:33 +010091
Saurav Das82b8e6d2018-10-04 15:25:12 -070092import com.google.common.collect.ImmutableMap;
93import com.google.common.collect.Maps;
alshabibf0e7e702015-05-30 18:22:36 -070094
95/**
Jonathan Harte533a422015-10-20 17:31:24 -070096 * Provisions rules on access devices.
alshabibf0e7e702015-05-30 18:22:36 -070097 */
Jonathan Harte533a422015-10-20 17:31:24 -070098@Service
alshabibf0e7e702015-05-30 18:22:36 -070099@Component(immediate = true)
alshabib8e4fd2f2016-01-12 15:55:53 -0800100public class Olt
101 extends AbstractListenerManager<AccessDeviceEvent, AccessDeviceListener>
102 implements AccessDeviceService {
Charles Chan54f110f2017-01-20 11:22:42 -0800103 private static final String APP_NAME = "org.opencord.olt";
alshabibe0559672016-02-21 14:49:51 -0800104
105 private static final short DEFAULT_VLAN = 0;
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100106 private static final String ADDITIONAL_VLANS = "additional-vlans";
alshabibe0559672016-02-21 14:49:51 -0800107
alshabibf0e7e702015-05-30 18:22:36 -0700108 private final Logger log = getLogger(getClass());
109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected FlowObjectiveService flowObjectiveService;
112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabib09753b52016-03-04 14:55:19 -0800114 protected MastershipService mastershipService;
115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibf0e7e702015-05-30 18:22:36 -0700117 protected DeviceService deviceService;
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
120 protected CoreService coreService;
121
Jonathan Harte533a422015-10-20 17:31:24 -0700122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibe0559672016-02-21 14:49:51 -0800123 protected ComponentConfigService componentConfigService;
124
alshabib4ceaed32016-03-03 18:00:58 -0800125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100126 protected SubscriberAndDeviceInformationService subsService;
alshabibe0559672016-02-21 14:49:51 -0800127
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100128 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
129 protected StorageService storageService;
130
alshabibe0559672016-02-21 14:49:51 -0800131 @Property(name = "defaultVlan", intValue = DEFAULT_VLAN,
132 label = "Default VLAN RG<->ONU traffic")
133 private int defaultVlan = DEFAULT_VLAN;
134
Matt Jeanneret3f579262018-06-14 17:16:23 -0400135 @Property(name = "enableDhcpOnProvisioning", boolValue = true,
136 label = "Create the DHCP Flow rules when a subscriber is provisioned")
137 protected boolean enableDhcpOnProvisioning = false;
138
139 @Property(name = "enableIgmpOnProvisioning", boolValue = false,
140 label = "Create IGMP Flow rules when a subscriber is provisioned")
141 protected boolean enableIgmpOnProvisioning = false;
Amit Ghosh95e2f652017-08-23 12:49:46 +0100142
alshabibf0e7e702015-05-30 18:22:36 -0700143 private final DeviceListener deviceListener = new InternalDeviceListener();
144
145 private ApplicationId appId;
146
Saurav Das82b8e6d2018-10-04 15:25:12 -0700147 private ExecutorService oltInstallers = Executors
148 .newFixedThreadPool(4, groupedThreads("onos/olt-service",
149 "olt-installer-%d"));
alshabibf0e7e702015-05-30 18:22:36 -0700150
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100151 private ConsistentMultimap<ConnectPoint, Map.Entry<VlanId, VlanId>> additionalVlans;
152
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700153 protected ExecutorService eventExecutor;
154
Saurav Das82b8e6d2018-10-04 15:25:12 -0700155 private Map<ConnectPoint, SubscriberAndDeviceInformation> programmedSubs;
156
alshabibf0e7e702015-05-30 18:22:36 -0700157 @Activate
alshabibe0559672016-02-21 14:49:51 -0800158 public void activate(ComponentContext context) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700159 eventExecutor = newSingleThreadScheduledExecutor(groupedThreads("onos/olt", "events-%d", log));
alshabibe0559672016-02-21 14:49:51 -0800160 modified(context);
Charles Chan54f110f2017-01-20 11:22:42 -0800161 appId = coreService.registerApplication(APP_NAME);
alshabibe0559672016-02-21 14:49:51 -0800162 componentConfigService.registerProperties(getClass());
Saurav Das82b8e6d2018-10-04 15:25:12 -0700163 programmedSubs = Maps.newConcurrentMap();
alshabibc4dfe852015-06-05 13:35:13 -0700164
alshabib8e4fd2f2016-01-12 15:55:53 -0800165 eventDispatcher.addSink(AccessDeviceEvent.class, listenerRegistry);
166
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100167 // look for all provisioned devices in Sadis and create EAPOL flows for the
168 // UNI ports
169 Iterable<Device> devices = deviceService.getDevices();
170 for (Device d : devices) {
Jonathan Hart403372d2018-08-22 11:44:13 -0700171 checkAndCreateDeviceFlows(d);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100172 }
alshabib4ceaed32016-03-03 18:00:58 -0800173
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100174 additionalVlans = storageService.<ConnectPoint, Map.Entry<VlanId, VlanId>>consistentMultimapBuilder()
175 .withName(ADDITIONAL_VLANS)
176 .withSerializer(Serializer.using(Arrays.asList(KryoNamespaces.API),
177 AbstractMap.SimpleEntry.class))
178 .build();
179
alshabibba357492016-01-27 13:49:46 -0800180 deviceService.addListener(deviceListener);
181
alshabibf0e7e702015-05-30 18:22:36 -0700182 log.info("Started with Application ID {}", appId.id());
183 }
184
185 @Deactivate
186 public void deactivate() {
alshabibe0559672016-02-21 14:49:51 -0800187 componentConfigService.unregisterProperties(getClass(), false);
alshabib62e9ce72016-02-11 17:31:36 -0800188 deviceService.removeListener(deviceListener);
Jonathan Hart5f1c8142018-07-24 17:31:59 -0700189 eventDispatcher.removeSink(AccessDeviceEvent.class);
alshabibf0e7e702015-05-30 18:22:36 -0700190 log.info("Stopped");
191 }
192
alshabibe0559672016-02-21 14:49:51 -0800193 @Modified
194 public void modified(ComponentContext context) {
195 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
196
197 try {
198 String s = get(properties, "defaultVlan");
199 defaultVlan = isNullOrEmpty(s) ? DEFAULT_VLAN : Integer.parseInt(s.trim());
Amit Ghosh95e2f652017-08-23 12:49:46 +0100200
Matt Jeanneret3f579262018-06-14 17:16:23 -0400201 Boolean o = Tools.isPropertyEnabled(properties, "enableDhcpOnProvisioning");
Amit Ghosh95e2f652017-08-23 12:49:46 +0100202 if (o != null) {
Matt Jeanneret3f579262018-06-14 17:16:23 -0400203 enableDhcpOnProvisioning = o;
Amit Ghosh95e2f652017-08-23 12:49:46 +0100204 }
Matt Jeanneret3f579262018-06-14 17:16:23 -0400205
206 Boolean p = Tools.isPropertyEnabled(properties, "enableIgmpOnProvisioning");
207 if (p != null) {
208 enableIgmpOnProvisioning = p;
209 }
210
alshabibe0559672016-02-21 14:49:51 -0800211 } catch (Exception e) {
212 defaultVlan = DEFAULT_VLAN;
213 }
214 }
215
alshabib32232c82016-02-25 17:57:24 -0500216 @Override
Amit Ghosh31939522018-08-16 13:28:21 +0100217 public boolean provisionSubscriber(ConnectPoint port) {
Jonathan Hart94b90492018-04-24 14:02:25 -0700218 checkNotNull(deviceService.getPort(port.deviceId(), port.port()),
219 "Invalid connect point");
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100220 // Find the subscriber on this connect point
221 SubscriberAndDeviceInformation sub = getSubscriber(port);
222 if (sub == null) {
223 log.warn("No subscriber found for {}", port);
Amit Ghosh31939522018-08-16 13:28:21 +0100224 return false;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100225 }
Jonathan Harte533a422015-10-20 17:31:24 -0700226
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100227 // Get the uplink port
228 Port uplinkPort = getUplinkPort(deviceService.getDevice(port.deviceId()));
229 if (uplinkPort == null) {
230 log.warn("No uplink port found for OLT device {}", port.deviceId());
Amit Ghosh31939522018-08-16 13:28:21 +0100231 return false;
Jonathan Harte533a422015-10-20 17:31:24 -0700232 }
233
Matt Jeanneret3f579262018-06-14 17:16:23 -0400234 if (enableDhcpOnProvisioning) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100235 processDhcpFilteringObjectives(port.deviceId(), port.port(), true);
Amit Ghosh95e2f652017-08-23 12:49:46 +0100236 }
Saurav Das82b8e6d2018-10-04 15:25:12 -0700237 log.info("Programming vlans for subscriber: {}", sub);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100238 Optional<VlanId> defaultVlan = Optional.empty();
Saurav Das82b8e6d2018-10-04 15:25:12 -0700239 provisionVlans(port.deviceId(), uplinkPort.number(), port.port(),
240 sub.cTag(), sub.sTag(), defaultVlan);
Amit Ghosh95e2f652017-08-23 12:49:46 +0100241
Matt Jeanneret3f579262018-06-14 17:16:23 -0400242 if (enableIgmpOnProvisioning) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100243 processIgmpFilteringObjectives(port.deviceId(), port.port(), true);
Amit Ghosh95e2f652017-08-23 12:49:46 +0100244 }
Saurav Das82b8e6d2018-10-04 15:25:12 -0700245 // cache subscriber info
246 programmedSubs.put(port, sub);
Amit Ghosh31939522018-08-16 13:28:21 +0100247 return true;
alshabibb7a9e172016-01-13 11:23:53 -0800248 }
249
250 @Override
Amit Ghosh31939522018-08-16 13:28:21 +0100251 public boolean removeSubscriber(ConnectPoint port) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100252 // Get the subscriber connected to this port from Sadis
253 SubscriberAndDeviceInformation subscriber = getSubscriber(port);
254 if (subscriber == null) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700255 log.warn("Subscriber on port {} not found in sadis .. checking "
256 + "local cache", port);
257 subscriber = programmedSubs.get(port);
258 if (subscriber == null) {
259 log.warn("Subscriber on port {} was not previously programmed", port);
260 return false;
261 }
alshabibbf23a1f2016-01-14 17:27:11 -0800262 }
263
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100264 // Get the uplink port
265 Port uplinkPort = getUplinkPort(deviceService.getDevice(port.deviceId()));
266 if (uplinkPort == null) {
267 log.warn("No uplink port found for OLT device {}", port.deviceId());
Amit Ghosh31939522018-08-16 13:28:21 +0100268 return false;
alshabib4ceaed32016-03-03 18:00:58 -0800269 }
270
Matt Jeanneret3f579262018-06-14 17:16:23 -0400271 if (enableDhcpOnProvisioning) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100272 processDhcpFilteringObjectives(port.deviceId(), port.port(), false);
Amit Ghosh95e2f652017-08-23 12:49:46 +0100273 }
274
Saurav Das82b8e6d2018-10-04 15:25:12 -0700275 log.info("Removing programmed vlans for subscriber: {}", subscriber);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100276 Optional<VlanId> defaultVlan = Optional.empty();
Saurav Das82b8e6d2018-10-04 15:25:12 -0700277 unprovisionSubscriber(port.deviceId(), uplinkPort.number(), port.port(),
278 subscriber.cTag(), subscriber.sTag(), defaultVlan);
alshabibbf23a1f2016-01-14 17:27:11 -0800279
Matt Jeanneret3f579262018-06-14 17:16:23 -0400280 if (enableIgmpOnProvisioning) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100281 processIgmpFilteringObjectives(port.deviceId(), port.port(), false);
Amit Ghosh95e2f652017-08-23 12:49:46 +0100282 }
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100283
284 // Remove if there are any flows for the additional Vlans
285 Collection<? extends Map.Entry<VlanId, VlanId>> vlansList = additionalVlans.get(port).value();
286
287 // Remove the flows for the additional vlans for this subscriber
288 for (Map.Entry<VlanId, VlanId> vlans : vlansList) {
289 unprovisionTransparentFlows(port.deviceId(), uplinkPort.number(), port.port(),
290 vlans.getValue(), vlans.getKey());
291
292 // Remove it from the map also
293 additionalVlans.remove(port, vlans);
294 }
295
Saurav Das82b8e6d2018-10-04 15:25:12 -0700296 programmedSubs.remove(port);
Amit Ghosh31939522018-08-16 13:28:21 +0100297 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800298 }
299
Amit Ghosh31939522018-08-16 13:28:21 +0100300 @Override
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100301 public boolean provisionSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag, Optional<VlanId> cTag) {
Amit Ghosh31939522018-08-16 13:28:21 +0100302 // Check if we can find the connect point to which this subscriber is connected
303 ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
304 if (subsPort == null) {
305 log.warn("ConnectPoint for {} not found", subscriberId);
306 return false;
307 }
308
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100309 if (!sTag.isPresent() && !cTag.isPresent()) {
310 return provisionSubscriber(subsPort);
311 } else if (sTag.isPresent() && cTag.isPresent()) {
312 Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
313 if (uplinkPort == null) {
314 log.warn("No uplink port found for OLT device {}", subsPort.deviceId());
315 return false;
316 }
317
318 provisionTransparentFlows(subsPort.deviceId(), uplinkPort.number(), subsPort.port(),
319 cTag.get(), sTag.get());
320 return true;
321 } else {
322 log.warn("Provisioning failed for subscriber: {}", subscriberId);
323 return false;
324 }
Amit Ghosh31939522018-08-16 13:28:21 +0100325 }
Amit Ghosh95e2f652017-08-23 12:49:46 +0100326
alshabibe0559672016-02-21 14:49:51 -0800327 @Override
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100328 public boolean removeSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag, Optional<VlanId> cTag) {
Amit Ghosh31939522018-08-16 13:28:21 +0100329 // Check if we can find the connect point to which this subscriber is connected
330 ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
331 if (subsPort == null) {
332 log.warn("ConnectPoint for {} not found", subscriberId);
333 return false;
334 }
335
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100336 if (!sTag.isPresent() && !cTag.isPresent()) {
337 return removeSubscriber(subsPort);
338 } else if (sTag.isPresent() && cTag.isPresent()) {
339 // Get the uplink port
340 Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
341 if (uplinkPort == null) {
342 log.warn("No uplink port found for OLT device {}", subsPort.deviceId());
343 return false;
344 }
345
346 unprovisionTransparentFlows(subsPort.deviceId(), uplinkPort.number(), subsPort.port(),
347 cTag.get(), sTag.get());
348 return true;
349 } else {
350 log.warn("Removing subscriber failed for: {}", subscriberId);
351 return false;
352 }
Amit Ghosh31939522018-08-16 13:28:21 +0100353 }
354
355 @Override
356 public Collection<Map.Entry<ConnectPoint, Map.Entry<VlanId, VlanId>>> getSubscribers() {
357 ArrayList<Map.Entry<ConnectPoint, Map.Entry<VlanId, VlanId>>> subs = new ArrayList<>();
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100358
Saurav Das82b8e6d2018-10-04 15:25:12 -0700359 // Get the subscribers for all the devices configured in sadis
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100360 // If the port is UNI, is enabled and exists in Sadis then copy it
361 for (Device d : deviceService.getDevices()) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700362 if (getOltInfo(d) == null) {
363 continue; // not an olt, or not configured in sadis
364 }
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100365 for (Port p: deviceService.getPorts(d.id())) {
366 if (isUniPort(d, p) && p.isEnabled()) {
367 ConnectPoint cp = new ConnectPoint(d.id(), p.number());
368
369 SubscriberAndDeviceInformation sub = getSubscriber(cp);
370 if (sub != null) {
Amit Ghosh31939522018-08-16 13:28:21 +0100371 Map.Entry<VlanId, VlanId> vlans = new AbstractMap.SimpleEntry(sub.sTag(), sub.cTag());
372 subs.add(new AbstractMap.SimpleEntry(cp, vlans));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100373 }
374 }
375 }
376 }
377
378 return subs;
Jonathan Hartfd6c1b32016-03-08 14:09:09 -0800379 }
380
381 @Override
Saurav Das82b8e6d2018-10-04 15:25:12 -0700382 public ImmutableMap<ConnectPoint, SubscriberAndDeviceInformation> getProgSubs() {
383 return ImmutableMap.copyOf(programmedSubs);
384 }
385
386 @Override
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100387 public List<DeviceId> fetchOlts() {
388 // look through all the devices and find the ones that are OLTs as per Sadis
389 List<DeviceId> olts = new ArrayList<>();
390 Iterable<Device> devices = deviceService.getDevices();
391 for (Device d : devices) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700392 if (getOltInfo(d) != null) {
393 // So this is indeed an OLT device
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100394 olts.add(d.id());
395 }
396 }
397 return olts;
alshabibe0559672016-02-21 14:49:51 -0800398 }
399
Amit Ghosh31939522018-08-16 13:28:21 +0100400 /**
401 * Finds the connect point to which a subscriber is connected.
402 *
403 * @param id The id of the subscriber, this is the same ID as in Sadis
404 * @return Subscribers ConnectPoint if found else null
405 */
406 private ConnectPoint findSubscriberConnectPoint(String id) {
407
408 Iterable<Device> devices = deviceService.getDevices();
409 for (Device d : devices) {
410 for (Port p : deviceService.getPorts(d.id())) {
411 log.trace("Comparing {} with {}", p.annotations().value(AnnotationKeys.PORT_NAME), id);
412 if (p.annotations().value(AnnotationKeys.PORT_NAME).equals(id)) {
413 log.debug("Found on device {} port {}", d.id(), p.number());
414 return new ConnectPoint(d.id(), p.number());
415 }
416 }
417 }
418 return null;
419 }
420
alshabibbf23a1f2016-01-14 17:27:11 -0800421 private void unprovisionSubscriber(DeviceId deviceId, PortNumber uplink,
Saurav Das82b8e6d2018-10-04 15:25:12 -0700422 PortNumber subscriberPort, VlanId cVlan,
423 VlanId sVlan, Optional<VlanId> defaultVlan) {
alshabibbf23a1f2016-01-14 17:27:11 -0800424
425 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
426 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
427
alshabib4ceaed32016-03-03 18:00:58 -0800428 ForwardingObjective.Builder upFwd = upBuilder(uplink, subscriberPort,
Saurav Das82b8e6d2018-10-04 15:25:12 -0700429 cVlan, sVlan,
alshabib4ceaed32016-03-03 18:00:58 -0800430 defaultVlan);
431 ForwardingObjective.Builder downFwd = downBuilder(uplink, subscriberPort,
Saurav Das82b8e6d2018-10-04 15:25:12 -0700432 cVlan, sVlan,
alshabib4ceaed32016-03-03 18:00:58 -0800433 defaultVlan);
alshabibbf23a1f2016-01-14 17:27:11 -0800434
alshabib4ceaed32016-03-03 18:00:58 -0800435 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
436 @Override
437 public void onSuccess(Objective objective) {
438 upFuture.complete(null);
439 }
alshabibbf23a1f2016-01-14 17:27:11 -0800440
alshabib4ceaed32016-03-03 18:00:58 -0800441 @Override
442 public void onError(Objective objective, ObjectiveError error) {
443 upFuture.complete(error);
444 }
445 }));
446
447 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
448 @Override
449 public void onSuccess(Objective objective) {
450 downFuture.complete(null);
451 }
452
453 @Override
454 public void onError(Objective objective, ObjectiveError error) {
455 downFuture.complete(error);
456 }
457 }));
alshabibbf23a1f2016-01-14 17:27:11 -0800458
459 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
460 if (upStatus == null && downStatus == null) {
461 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_UNREGISTERED,
462 deviceId,
Saurav Das82b8e6d2018-10-04 15:25:12 -0700463 sVlan,
464 cVlan));
alshabibbf23a1f2016-01-14 17:27:11 -0800465 } else if (downStatus != null) {
466 log.error("Subscriber with vlan {} on device {} " +
467 "on port {} failed downstream uninstallation: {}",
Saurav Das82b8e6d2018-10-04 15:25:12 -0700468 cVlan, deviceId, subscriberPort, downStatus);
alshabibbf23a1f2016-01-14 17:27:11 -0800469 } else if (upStatus != null) {
470 log.error("Subscriber with vlan {} on device {} " +
471 "on port {} failed upstream uninstallation: {}",
Saurav Das82b8e6d2018-10-04 15:25:12 -0700472 cVlan, deviceId, subscriberPort, upStatus);
alshabibbf23a1f2016-01-14 17:27:11 -0800473 }
474 }, oltInstallers);
alshabibb7a9e172016-01-13 11:23:53 -0800475
Jonathan Harte533a422015-10-20 17:31:24 -0700476 }
477
478 private void provisionVlans(DeviceId deviceId, PortNumber uplinkPort,
479 PortNumber subscriberPort,
Jonathan Hart52998382015-11-10 16:09:22 -0800480 VlanId subscriberVlan, VlanId deviceVlan,
481 Optional<VlanId> defaultVlan) {
Jonathan Harte533a422015-10-20 17:31:24 -0700482
alshabib3ea82642016-01-12 18:06:53 -0800483 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
484 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
485
alshabib4ceaed32016-03-03 18:00:58 -0800486 ForwardingObjective.Builder upFwd = upBuilder(uplinkPort, subscriberPort,
487 subscriberVlan, deviceVlan,
488 defaultVlan);
Jonathan Harte533a422015-10-20 17:31:24 -0700489
490
alshabib4ceaed32016-03-03 18:00:58 -0800491 ForwardingObjective.Builder downFwd = downBuilder(uplinkPort, subscriberPort,
492 subscriberVlan, deviceVlan,
493 defaultVlan);
alshabib3ea82642016-01-12 18:06:53 -0800494
alshabibbf23a1f2016-01-14 17:27:11 -0800495 flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
496 @Override
497 public void onSuccess(Objective objective) {
498 upFuture.complete(null);
499 }
500
501 @Override
502 public void onError(Objective objective, ObjectiveError error) {
503 upFuture.complete(error);
504 }
505 }));
506
alshabibbf23a1f2016-01-14 17:27:11 -0800507 flowObjectiveService.forward(deviceId, downFwd.add(new ObjectiveContext() {
508 @Override
509 public void onSuccess(Objective objective) {
510 downFuture.complete(null);
511 }
512
513 @Override
514 public void onError(Objective objective, ObjectiveError error) {
515 downFuture.complete(error);
516 }
517 }));
alshabib3ea82642016-01-12 18:06:53 -0800518
519 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
520 if (upStatus == null && downStatus == null) {
521 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_REGISTERED,
522 deviceId,
523 deviceVlan,
524 subscriberVlan));
alshabib50d9fc52016-02-12 15:47:20 -0800525
alshabib3ea82642016-01-12 18:06:53 -0800526 } else if (downStatus != null) {
527 log.error("Subscriber with vlan {} on device {} " +
528 "on port {} failed downstream installation: {}",
529 subscriberVlan, deviceId, subscriberPort, downStatus);
530 } else if (upStatus != null) {
531 log.error("Subscriber with vlan {} on device {} " +
532 "on port {} failed upstream installation: {}",
533 subscriberVlan, deviceId, subscriberPort, upStatus);
534 }
535 }, oltInstallers);
536
Jonathan Harte533a422015-10-20 17:31:24 -0700537 }
538
alshabib4ceaed32016-03-03 18:00:58 -0800539 private ForwardingObjective.Builder downBuilder(PortNumber uplinkPort,
540 PortNumber subscriberPort,
541 VlanId subscriberVlan,
542 VlanId deviceVlan,
543 Optional<VlanId> defaultVlan) {
544 TrafficSelector downstream = DefaultTrafficSelector.builder()
545 .matchVlanId(deviceVlan)
546 .matchInPort(uplinkPort)
547 .matchInnerVlanId(subscriberVlan)
548 .build();
549
550 TrafficTreatment downstreamTreatment = DefaultTrafficTreatment.builder()
551 .popVlan()
552 .setVlanId(defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan)))
553 .setOutput(subscriberPort)
554 .build();
555
556 return DefaultForwardingObjective.builder()
557 .withFlag(ForwardingObjective.Flag.VERSATILE)
558 .withPriority(1000)
559 .makePermanent()
560 .withSelector(downstream)
561 .fromApp(appId)
562 .withTreatment(downstreamTreatment);
563 }
564
565 private ForwardingObjective.Builder upBuilder(PortNumber uplinkPort,
566 PortNumber subscriberPort,
567 VlanId subscriberVlan,
568 VlanId deviceVlan,
569 Optional<VlanId> defaultVlan) {
570 TrafficSelector upstream = DefaultTrafficSelector.builder()
571 .matchVlanId(defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan)))
572 .matchInPort(subscriberPort)
573 .build();
574
575
576 TrafficTreatment upstreamTreatment = DefaultTrafficTreatment.builder()
577 .pushVlan()
578 .setVlanId(subscriberVlan)
579 .pushVlan()
580 .setVlanId(deviceVlan)
581 .setOutput(uplinkPort)
582 .build();
583
584 return DefaultForwardingObjective.builder()
585 .withFlag(ForwardingObjective.Flag.VERSATILE)
586 .withPriority(1000)
587 .makePermanent()
588 .withSelector(upstream)
589 .fromApp(appId)
590 .withTreatment(upstreamTreatment);
591 }
592
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100593 private void provisionTransparentFlows(DeviceId deviceId, PortNumber uplinkPort,
594 PortNumber subscriberPort,
595 VlanId innerVlan,
596 VlanId outerVlan) {
597
598 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
599 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
600
601 ForwardingObjective.Builder upFwd = transparentUpBuilder(uplinkPort, subscriberPort,
602 innerVlan, outerVlan);
603
604
605 ForwardingObjective.Builder downFwd = transparentDownBuilder(uplinkPort, subscriberPort,
606 innerVlan, outerVlan);
607
608 ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
609
610 additionalVlans.put(cp, new AbstractMap.SimpleEntry(outerVlan, innerVlan));
611
612 flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
613 @Override
614 public void onSuccess(Objective objective) {
615 upFuture.complete(null);
616 }
617
618 @Override
619 public void onError(Objective objective, ObjectiveError error) {
620 upFuture.complete(error);
621 }
622 }));
623
624 flowObjectiveService.forward(deviceId, downFwd.add(new ObjectiveContext() {
625 @Override
626 public void onSuccess(Objective objective) {
627 downFuture.complete(null);
628 }
629
630 @Override
631 public void onError(Objective objective, ObjectiveError error) {
632 downFuture.complete(error);
633 }
634 }));
635
636 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
637 if (downStatus != null) {
638 log.error("Flow with innervlan {} and outerVlan {} on device {} " +
639 "on port {} failed downstream installation: {}",
640 innerVlan, outerVlan, deviceId, subscriberPort, downStatus);
641 } else if (upStatus != null) {
642 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
643 "on port {} failed upstream installation: {}",
644 innerVlan, outerVlan, deviceId, subscriberPort, upStatus);
645 }
646 }, oltInstallers);
647
648 }
649
650 private ForwardingObjective.Builder transparentDownBuilder(PortNumber uplinkPort,
651 PortNumber subscriberPort,
652 VlanId innerVlan,
653 VlanId outerVlan) {
654 TrafficSelector downstream = DefaultTrafficSelector.builder()
655 .matchVlanId(outerVlan)
656 .matchInPort(uplinkPort)
657 .matchInnerVlanId(innerVlan)
658 .build();
659
660 TrafficTreatment downstreamTreatment = DefaultTrafficTreatment.builder()
661 .setOutput(subscriberPort)
662 .build();
663
664 return DefaultForwardingObjective.builder()
665 .withFlag(ForwardingObjective.Flag.VERSATILE)
666 .withPriority(1000)
667 .makePermanent()
668 .withSelector(downstream)
669 .fromApp(appId)
670 .withTreatment(downstreamTreatment);
671 }
672
673 private ForwardingObjective.Builder transparentUpBuilder(PortNumber uplinkPort,
674 PortNumber subscriberPort,
675 VlanId innerVlan,
676 VlanId outerVlan) {
677 TrafficSelector upstream = DefaultTrafficSelector.builder()
678 .matchVlanId(outerVlan)
679 .matchInPort(subscriberPort)
680 .matchInnerVlanId(innerVlan)
681 .build();
682
683 TrafficTreatment upstreamTreatment = DefaultTrafficTreatment.builder()
684 .setOutput(uplinkPort)
685 .build();
686
687 return DefaultForwardingObjective.builder()
688 .withFlag(ForwardingObjective.Flag.VERSATILE)
689 .withPriority(1000)
690 .makePermanent()
691 .withSelector(upstream)
692 .fromApp(appId)
693 .withTreatment(upstreamTreatment);
694 }
695
696 private void unprovisionTransparentFlows(DeviceId deviceId, PortNumber uplink,
697 PortNumber subscriberPort, VlanId innerVlan,
698 VlanId outerVlan) {
699
700 ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
701
702 additionalVlans.remove(cp, new AbstractMap.SimpleEntry(outerVlan, innerVlan));
703
704 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
705 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
706
707 ForwardingObjective.Builder upFwd = transparentUpBuilder(uplink, subscriberPort,
708 innerVlan, outerVlan);
709 ForwardingObjective.Builder downFwd = transparentDownBuilder(uplink, subscriberPort,
710 innerVlan, outerVlan);
711
712
713 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
714 @Override
715 public void onSuccess(Objective objective) {
716 upFuture.complete(null);
717 }
718
719 @Override
720 public void onError(Objective objective, ObjectiveError error) {
721 upFuture.complete(error);
722 }
723 }));
724
725 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
726 @Override
727 public void onSuccess(Objective objective) {
728 downFuture.complete(null);
729 }
730
731 @Override
732 public void onError(Objective objective, ObjectiveError error) {
733 downFuture.complete(error);
734 }
735 }));
736
737 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
738 if (downStatus != null) {
739 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
740 "on port {} failed downstream uninstallation: {}",
741 innerVlan, outerVlan, deviceId, subscriberPort, downStatus);
742 } else if (upStatus != null) {
743 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
744 "on port {} failed upstream uninstallation: {}",
745 innerVlan, outerVlan, deviceId, subscriberPort, upStatus);
746 }
747 }, oltInstallers);
748
749 }
750
Saurav Das82b8e6d2018-10-04 15:25:12 -0700751 private void processEapolFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
alshabib09753b52016-03-04 14:55:19 -0800752 if (!mastershipService.isLocalMaster(devId)) {
753 return;
754 }
alshabibbb83aa22016-02-10 15:08:23 -0800755 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
756
757 FilteringObjective eapol = (install ? builder.permit() : builder.deny())
alshabib50d9fc52016-02-12 15:47:20 -0800758 .withKey(Criteria.matchInPort(port))
alshabibdec2e252016-01-15 12:20:25 -0800759 .addCondition(Criteria.matchEthType(EthType.EtherType.EAPOL.ethType()))
760 .withMeta(DefaultTrafficTreatment.builder()
761 .setOutput(PortNumber.CONTROLLER).build())
762 .fromApp(appId)
Matt Jeanneret3f579262018-06-14 17:16:23 -0400763 .withPriority(10000)
alshabibdec2e252016-01-15 12:20:25 -0800764 .add(new ObjectiveContext() {
765 @Override
766 public void onSuccess(Objective objective) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700767 log.info("Eapol filter for {} on {} {}.",
768 devId, port, (install) ? "installed" : "removed");
alshabibdec2e252016-01-15 12:20:25 -0800769 }
770
771 @Override
772 public void onError(Objective objective, ObjectiveError error) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700773 log.info("Eapol filter for {} on {} failed {} because {}",
774 devId, port, (install) ? "installation" : "removal",
775 error);
alshabibdec2e252016-01-15 12:20:25 -0800776 }
777 });
778
alshabibdec2e252016-01-15 12:20:25 -0800779 flowObjectiveService.filter(devId, eapol);
alshabib000b6fc2016-02-01 17:25:00 -0800780
alshabibdec2e252016-01-15 12:20:25 -0800781 }
782
Jonathan Hart403372d2018-08-22 11:44:13 -0700783 /**
784 * Installs trap filtering objectives for particular traffic types on an
785 * NNI port.
786 *
787 * @param devId device ID
788 * @param port port number
789 * @param install true to install, false to remove
790 */
791 private void processNniFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
792 processLldpFilteringObjective(devId, port, install);
793 processDhcpFilteringObjectives(devId, port, install);
794 }
795
796 private void processLldpFilteringObjective(DeviceId devId, PortNumber port, boolean install) {
797 if (!mastershipService.isLocalMaster(devId)) {
798 return;
799 }
800 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
801
802 FilteringObjective lldp = (install ? builder.permit() : builder.deny())
803 .withKey(Criteria.matchInPort(port))
804 .addCondition(Criteria.matchEthType(EthType.EtherType.LLDP.ethType()))
805 .withMeta(DefaultTrafficTreatment.builder()
806 .setOutput(PortNumber.CONTROLLER).build())
807 .fromApp(appId)
808 .withPriority(10000)
809 .add(new ObjectiveContext() {
810 @Override
811 public void onSuccess(Objective objective) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700812 log.info("LLDP filter for {} on {} {}.",
813 devId, port, (install) ? "installed" : "removed");
Jonathan Hart403372d2018-08-22 11:44:13 -0700814 }
815
816 @Override
817 public void onError(Objective objective, ObjectiveError error) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700818 log.info("LLDP filter for {} on {} failed {} because {}",
819 devId, port, (install) ? "installation" : "removal",
820 error);
Jonathan Hart403372d2018-08-22 11:44:13 -0700821 }
822 });
823
824 flowObjectiveService.filter(devId, lldp);
825
826 }
827
Amit Ghosh95e2f652017-08-23 12:49:46 +0100828 private void processDhcpFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
829 if (!mastershipService.isLocalMaster(devId)) {
830 return;
831 }
832 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
833
834 FilteringObjective dhcpUpstream = (install ? builder.permit() : builder.deny())
835 .withKey(Criteria.matchInPort(port))
836 .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
837 .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_UDP))
838 .addCondition(Criteria.matchUdpSrc(TpPort.tpPort(68)))
839 .addCondition(Criteria.matchUdpDst(TpPort.tpPort(67)))
840 .withMeta(DefaultTrafficTreatment.builder()
841 .setOutput(PortNumber.CONTROLLER).build())
842 .fromApp(appId)
Matt Jeanneret3f579262018-06-14 17:16:23 -0400843 .withPriority(10000)
Amit Ghosh95e2f652017-08-23 12:49:46 +0100844 .add(new ObjectiveContext() {
845 @Override
846 public void onSuccess(Objective objective) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700847 log.info("DHCP filter for {} on {} {}.",
848 devId, port, (install) ? "installed" : "removed");
Amit Ghosh95e2f652017-08-23 12:49:46 +0100849 }
850
851 @Override
852 public void onError(Objective objective, ObjectiveError error) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700853 log.info("DHCP filter for {} on {} failed {} because {}",
854 devId, port, (install) ? "installation" : "removal",
855 error);
Amit Ghosh95e2f652017-08-23 12:49:46 +0100856 }
857 });
858
859 flowObjectiveService.filter(devId, dhcpUpstream);
860 }
861
862 private void processIgmpFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
863 if (!mastershipService.isLocalMaster(devId)) {
864 return;
865 }
866
867 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
868
869 builder = install ? builder.permit() : builder.deny();
870
871 FilteringObjective igmp = builder
872 .withKey(Criteria.matchInPort(port))
873 .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
874 .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_IGMP))
875 .withMeta(DefaultTrafficTreatment.builder()
876 .setOutput(PortNumber.CONTROLLER).build())
877 .fromApp(appId)
878 .withPriority(10000)
879 .add(new ObjectiveContext() {
880 @Override
881 public void onSuccess(Objective objective) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700882 log.info("Igmp filter for {} on {} {}.",
883 devId, port, (install) ? "installed" : "removed");
Amit Ghosh95e2f652017-08-23 12:49:46 +0100884 }
885
886 @Override
887 public void onError(Objective objective, ObjectiveError error) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700888 log.info("Igmp filter for {} on {} failed {} because {}.",
889 devId, port, (install) ? "installation" : "removal",
890 error);
Amit Ghosh95e2f652017-08-23 12:49:46 +0100891 }
892 });
893
894 flowObjectiveService.filter(devId, igmp);
895 }
896
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100897 /**
Jonathan Hart403372d2018-08-22 11:44:13 -0700898 * Creates trap flows for device, including DHCP and LLDP trap on NNI and
899 * EAPOL trap on the UNIs, if device is present in Sadis config.
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100900 *
901 * @param dev Device to look for
902 */
Jonathan Hart403372d2018-08-22 11:44:13 -0700903 private void checkAndCreateDeviceFlows(Device dev) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100904 // we create only for the ones we are master of
905 if (!mastershipService.isLocalMaster(dev.id())) {
906 return;
907 }
908 // check if this device is provisioned in Sadis
909 String devSerialNo = dev.serialNumber();
910 SubscriberAndDeviceInformation deviceInfo = subsService.get(devSerialNo);
Jonathan Hart403372d2018-08-22 11:44:13 -0700911 log.debug("checkAndCreateDeviceFlows: deviceInfo {}", deviceInfo);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100912
913 if (deviceInfo != null) {
Jonathan Hart403372d2018-08-22 11:44:13 -0700914 // This is an OLT device as per Sadis, we create flows for UNI and NNI ports
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100915 for (Port p : deviceService.getPorts(dev.id())) {
916 if (isUniPort(dev, p)) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700917 processEapolFilteringObjectives(dev.id(), p.number(), true);
Jonathan Hart403372d2018-08-22 11:44:13 -0700918 } else {
919 processNniFilteringObjectives(dev.id(), p.number(), true);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100920 }
921 }
922 }
923 }
924
Jonathan Hart403372d2018-08-22 11:44:13 -0700925
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100926 /**
927 * Get the uplink for of the OLT device.
928 *
929 * This assumes that the OLT has a single uplink port. When more uplink ports need to be supported
930 * this logic needs to be changed
931 *
932 * @param dev Device to look for
933 * @return The uplink Port of the OLT
934 */
935 private Port getUplinkPort(Device dev) {
936 // check if this device is provisioned in Sadis
937 String devSerialNo = dev.serialNumber();
938 SubscriberAndDeviceInformation deviceInfo = subsService.get(devSerialNo);
939 log.debug("getUplinkPort: deviceInfo {}", deviceInfo);
Saurav Das82b8e6d2018-10-04 15:25:12 -0700940 if (deviceInfo == null) {
941 log.warn("Device {} is not configured in SADIS .. cannot fetch device"
942 + " info", dev.id());
943 return null;
944 }
945 // Return the port that has been configured as the uplink port of this OLT in Sadis
946 for (Port p: deviceService.getPorts(dev.id())) {
947 if (p.number().toLong() == deviceInfo.uplinkPort()) {
948 log.debug("getUplinkPort: Found port {}", p);
949 return p;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100950 }
951 }
952
Saurav Das82b8e6d2018-10-04 15:25:12 -0700953 log.debug("getUplinkPort: No uplink port found for OLT {}", dev.id());
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100954 return null;
955 }
956
957 /**
958 * Return the subscriber on a port.
959 *
960 * @param port On which to find the subscriber
961 * @return subscriber if found else null
962 */
963 private SubscriberAndDeviceInformation getSubscriber(ConnectPoint port) {
964 String portName = deviceService.getPort(port).annotations()
965 .value(AnnotationKeys.PORT_NAME);
966
967 return subsService.get(portName);
968 }
969
970 private boolean isUniPort(Device d, Port p) {
971 Port ulPort = getUplinkPort(d);
972 if (ulPort != null) {
973 return (ulPort.number().toLong() != p.number().toLong());
974 }
975 return false;
Jonathan Hart1d34c8b2018-05-05 15:37:28 -0700976 }
977
Jonathan Hart4c538002018-08-23 10:11:54 -0700978 private SubscriberAndDeviceInformation getOltInfo(Device dev) {
979 String devSerialNo = dev.serialNumber();
980 SubscriberAndDeviceInformation deviceInfo = subsService.get(devSerialNo);
981 return deviceInfo;
982 }
983
alshabibf0e7e702015-05-30 18:22:36 -0700984 private class InternalDeviceListener implements DeviceListener {
985 @Override
986 public void event(DeviceEvent event) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700987 eventExecutor.execute(() -> {
988 DeviceId devId = event.subject().id();
989 Device dev = event.subject();
Jonathan Hart4c538002018-08-23 10:11:54 -0700990
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700991 if (event.type() == DeviceEvent.Type.PORT_STATS_UPDATED) {
992 return;
993 }
Jonathan Hart4c538002018-08-23 10:11:54 -0700994
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700995 if (getOltInfo(dev) == null) {
996 log.debug("No device info found, this is not an OLT");
997 return;
998 }
Jonathan Hart4c538002018-08-23 10:11:54 -0700999
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001000 log.debug("OLT got {} event for {}", event.type(), event.subject());
Jonathan Hart4c538002018-08-23 10:11:54 -07001001
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001002 switch (event.type()) {
1003 //TODO: Port handling and bookkeeping should be improved once
1004 // olt firmware handles correct behaviour.
1005 case PORT_ADDED:
1006 if (isUniPort(dev, event.port())) {
1007 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, event.port()));
Jonathan Hart4c538002018-08-23 10:11:54 -07001008
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001009 if (event.port().isEnabled()) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001010 processEapolFilteringObjectives(devId, event.port().number(), true);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001011 }
1012 } else {
1013 checkAndCreateDeviceFlows(dev);
1014 }
1015 break;
1016 case PORT_REMOVED:
1017 if (isUniPort(dev, event.port())) {
1018 if (event.port().isEnabled()) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001019 processEapolFilteringObjectives(devId, event.port().number(), false);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001020 removeSubscriber(new ConnectPoint(devId, event.port().number()));
1021 }
1022
1023 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, event.port()));
1024 }
1025
1026 break;
1027 case PORT_UPDATED:
1028 if (!isUniPort(dev, event.port())) {
1029 break;
1030 }
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001031
1032 if (event.port().isEnabled()) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001033 processEapolFilteringObjectives(devId, event.port().number(), true);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001034 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, event.port()));
1035 } else {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001036 processEapolFilteringObjectives(devId, event.port().number(), false);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001037 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, event.port()));
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001038 }
alshabibbb83aa22016-02-10 15:08:23 -08001039 break;
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001040 case DEVICE_ADDED:
alshabib7c190012016-02-09 18:22:33 -08001041 post(new AccessDeviceEvent(
1042 AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
1043 null, null));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001044
1045 // Send UNI_ADDED events for all existing ports
1046 deviceService.getPorts(devId).stream()
1047 .filter(p -> isUniPort(dev, p))
1048 .filter(Port::isEnabled)
1049 .forEach(p -> post(new AccessDeviceEvent(
1050 AccessDeviceEvent.Type.UNI_ADDED, devId, p)));
1051
Jonathan Hart403372d2018-08-22 11:44:13 -07001052 checkAndCreateDeviceFlows(dev);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001053 break;
1054 case DEVICE_REMOVED:
1055 deviceService.getPorts(devId).stream()
1056 .filter(p -> isUniPort(dev, p))
1057 .forEach(p -> post(new AccessDeviceEvent(
1058 AccessDeviceEvent.Type.UNI_REMOVED, devId, p)));
1059
alshabib7c190012016-02-09 18:22:33 -08001060 post(new AccessDeviceEvent(
1061 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
1062 null, null));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001063 break;
1064 case DEVICE_AVAILABILITY_CHANGED:
1065 if (deviceService.isAvailable(devId)) {
1066 post(new AccessDeviceEvent(
1067 AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
1068 null, null));
1069 checkAndCreateDeviceFlows(dev);
1070 } else {
1071 post(new AccessDeviceEvent(
1072 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
1073 null, null));
1074 }
1075 break;
1076 case DEVICE_UPDATED:
1077 case DEVICE_SUSPENDED:
1078 case PORT_STATS_UPDATED:
1079 default:
1080 return;
1081 }
1082 });
alshabibf0e7e702015-05-30 18:22:36 -07001083 }
1084 }
alshabibf0e7e702015-05-30 18:22:36 -07001085}