blob: 8b71a0a40c1f92858d62951537d1f064381447a5 [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
alshabibbf23a1f2016-01-14 17:27:11 -080018import com.google.common.collect.Maps;
alshabibf0e7e702015-05-30 18:22:36 -070019import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
alshabibe0559672016-02-21 14:49:51 -080022import org.apache.felix.scr.annotations.Modified;
23import org.apache.felix.scr.annotations.Property;
alshabibf0e7e702015-05-30 18:22:36 -070024import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
Jonathan Harte533a422015-10-20 17:31:24 -070026import org.apache.felix.scr.annotations.Service;
alshabibdec2e252016-01-15 12:20:25 -080027import org.onlab.packet.EthType;
Amit Ghosh95e2f652017-08-23 12:49:46 +010028import org.onlab.packet.IPv4;
29import org.onlab.packet.TpPort;
alshabibf0e7e702015-05-30 18:22:36 -070030import org.onlab.packet.VlanId;
Amit Ghosh95e2f652017-08-23 12:49:46 +010031import org.onlab.util.Tools;
alshabibe0559672016-02-21 14:49:51 -080032import org.onosproject.cfg.ComponentConfigService;
alshabibf0e7e702015-05-30 18:22:36 -070033import org.onosproject.core.ApplicationId;
34import org.onosproject.core.CoreService;
alshabib8e4fd2f2016-01-12 15:55:53 -080035import org.onosproject.event.AbstractListenerManager;
alshabib09753b52016-03-04 14:55:19 -080036import org.onosproject.mastership.MastershipService;
Jonathan Harte533a422015-10-20 17:31:24 -070037import org.onosproject.net.ConnectPoint;
alshabibf0e7e702015-05-30 18:22:36 -070038import org.onosproject.net.DeviceId;
alshabibdec2e252016-01-15 12:20:25 -080039import org.onosproject.net.Port;
alshabibf0e7e702015-05-30 18:22:36 -070040import org.onosproject.net.PortNumber;
Jonathan Harte533a422015-10-20 17:31:24 -070041import org.onosproject.net.config.ConfigFactory;
42import org.onosproject.net.config.NetworkConfigEvent;
43import org.onosproject.net.config.NetworkConfigListener;
44import org.onosproject.net.config.NetworkConfigRegistry;
45import org.onosproject.net.config.basics.SubjectFactories;
alshabibf0e7e702015-05-30 18:22:36 -070046import org.onosproject.net.device.DeviceEvent;
47import org.onosproject.net.device.DeviceListener;
48import org.onosproject.net.device.DeviceService;
49import org.onosproject.net.flow.DefaultTrafficSelector;
50import org.onosproject.net.flow.DefaultTrafficTreatment;
51import org.onosproject.net.flow.TrafficSelector;
52import org.onosproject.net.flow.TrafficTreatment;
alshabibdec2e252016-01-15 12:20:25 -080053import org.onosproject.net.flow.criteria.Criteria;
54import org.onosproject.net.flowobjective.DefaultFilteringObjective;
alshabibf0e7e702015-05-30 18:22:36 -070055import org.onosproject.net.flowobjective.DefaultForwardingObjective;
alshabibdec2e252016-01-15 12:20:25 -080056import org.onosproject.net.flowobjective.FilteringObjective;
alshabibf0e7e702015-05-30 18:22:36 -070057import org.onosproject.net.flowobjective.FlowObjectiveService;
58import org.onosproject.net.flowobjective.ForwardingObjective;
alshabib3ea82642016-01-12 18:06:53 -080059import org.onosproject.net.flowobjective.Objective;
60import org.onosproject.net.flowobjective.ObjectiveContext;
61import org.onosproject.net.flowobjective.ObjectiveError;
Jonathan Hart94b90492018-04-24 14:02:25 -070062import org.onosproject.store.serializers.KryoNamespaces;
63import org.onosproject.store.service.Serializer;
64import org.onosproject.store.service.StorageService;
alshabibf3a573e2016-06-01 17:39:10 -070065import org.opencord.cordconfig.access.AccessDeviceConfig;
66import org.opencord.cordconfig.access.AccessDeviceData;
alshabib36a4d732016-06-01 16:03:59 -070067import org.opencord.olt.AccessDeviceEvent;
68import org.opencord.olt.AccessDeviceListener;
69import org.opencord.olt.AccessDeviceService;
alshabibe0559672016-02-21 14:49:51 -080070import org.osgi.service.component.ComponentContext;
alshabibf0e7e702015-05-30 18:22:36 -070071import org.slf4j.Logger;
72
Jonathan Hartfd6c1b32016-03-08 14:09:09 -080073import java.util.Collection;
alshabibe0559672016-02-21 14:49:51 -080074import java.util.Dictionary;
alshabibbb83aa22016-02-10 15:08:23 -080075import java.util.List;
Jonathan Harte533a422015-10-20 17:31:24 -070076import java.util.Map;
Jonathan Hart52998382015-11-10 16:09:22 -080077import java.util.Optional;
alshabibe0559672016-02-21 14:49:51 -080078import java.util.Properties;
alshabib3ea82642016-01-12 18:06:53 -080079import java.util.concurrent.CompletableFuture;
Jonathan Harte533a422015-10-20 17:31:24 -070080import java.util.concurrent.ConcurrentHashMap;
alshabib3ea82642016-01-12 18:06:53 -080081import java.util.concurrent.ExecutorService;
82import java.util.concurrent.Executors;
alshabibf0e7e702015-05-30 18:22:36 -070083
Jonathan Hart94b90492018-04-24 14:02:25 -070084import static com.google.common.base.Preconditions.checkNotNull;
alshabibe0559672016-02-21 14:49:51 -080085import static com.google.common.base.Strings.isNullOrEmpty;
86import static org.onlab.util.Tools.get;
alshabib3ea82642016-01-12 18:06:53 -080087import static org.onlab.util.Tools.groupedThreads;
alshabibf0e7e702015-05-30 18:22:36 -070088import static org.slf4j.LoggerFactory.getLogger;
89
90/**
Jonathan Harte533a422015-10-20 17:31:24 -070091 * Provisions rules on access devices.
alshabibf0e7e702015-05-30 18:22:36 -070092 */
Jonathan Harte533a422015-10-20 17:31:24 -070093@Service
alshabibf0e7e702015-05-30 18:22:36 -070094@Component(immediate = true)
alshabib8e4fd2f2016-01-12 15:55:53 -080095public class Olt
96 extends AbstractListenerManager<AccessDeviceEvent, AccessDeviceListener>
97 implements AccessDeviceService {
Charles Chan54f110f2017-01-20 11:22:42 -080098 private static final String APP_NAME = "org.opencord.olt";
alshabibe0559672016-02-21 14:49:51 -080099
100 private static final short DEFAULT_VLAN = 0;
alshabib4ceaed32016-03-03 18:00:58 -0800101 private static final String SUBSCRIBERS = "existing-subscribers";
alshabibe0559672016-02-21 14:49:51 -0800102
alshabibf0e7e702015-05-30 18:22:36 -0700103 private final Logger log = getLogger(getClass());
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 protected FlowObjectiveService flowObjectiveService;
107
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabib09753b52016-03-04 14:55:19 -0800109 protected MastershipService mastershipService;
110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibf0e7e702015-05-30 18:22:36 -0700112 protected DeviceService deviceService;
113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected CoreService coreService;
116
Jonathan Harte533a422015-10-20 17:31:24 -0700117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
118 protected NetworkConfigRegistry networkConfig;
119
alshabibe0559672016-02-21 14:49:51 -0800120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
121 protected ComponentConfigService componentConfigService;
122
alshabib4ceaed32016-03-03 18:00:58 -0800123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
124 protected StorageService storageService;
alshabibe0559672016-02-21 14:49:51 -0800125
126 @Property(name = "defaultVlan", intValue = DEFAULT_VLAN,
127 label = "Default VLAN RG<->ONU traffic")
128 private int defaultVlan = DEFAULT_VLAN;
129
Amit Ghosh95e2f652017-08-23 12:49:46 +0100130 @Property(name = "enableDhcpIgmpOnProvisioning", boolValue = false,
131 label = "Create the DHCP and IGMP Flow rules when a subscriber is provisioned")
132 protected boolean enableDhcpIgmpOnProvisioning = false;
133
alshabibf0e7e702015-05-30 18:22:36 -0700134 private final DeviceListener deviceListener = new InternalDeviceListener();
135
136 private ApplicationId appId;
137
alshabib3ea82642016-01-12 18:06:53 -0800138 private ExecutorService oltInstallers = Executors.newFixedThreadPool(4,
alshabibbf23a1f2016-01-14 17:27:11 -0800139 groupedThreads("onos/olt-service",
140 "olt-installer-%d"));
alshabib4ae2b402015-06-05 14:55:24 -0700141
Jonathan Harte533a422015-10-20 17:31:24 -0700142 private Map<DeviceId, AccessDeviceData> oltData = new ConcurrentHashMap<>();
143
alshabib4ceaed32016-03-03 18:00:58 -0800144 private Map<ConnectPoint, VlanId> subscribers;
alshabibbf23a1f2016-01-14 17:27:11 -0800145
Jonathan Harte533a422015-10-20 17:31:24 -0700146 private InternalNetworkConfigListener configListener =
147 new InternalNetworkConfigListener();
148 private static final Class<AccessDeviceConfig> CONFIG_CLASS =
149 AccessDeviceConfig.class;
150
151 private ConfigFactory<DeviceId, AccessDeviceConfig> configFactory =
152 new ConfigFactory<DeviceId, AccessDeviceConfig>(
153 SubjectFactories.DEVICE_SUBJECT_FACTORY, CONFIG_CLASS, "accessDevice") {
alshabibbf23a1f2016-01-14 17:27:11 -0800154 @Override
155 public AccessDeviceConfig createConfig() {
156 return new AccessDeviceConfig();
157 }
158 };
159
alshabibf0e7e702015-05-30 18:22:36 -0700160
161 @Activate
alshabibe0559672016-02-21 14:49:51 -0800162 public void activate(ComponentContext context) {
163 modified(context);
Charles Chan54f110f2017-01-20 11:22:42 -0800164 appId = coreService.registerApplication(APP_NAME);
alshabibe0559672016-02-21 14:49:51 -0800165 componentConfigService.registerProperties(getClass());
alshabibc4dfe852015-06-05 13:35:13 -0700166
alshabib8e4fd2f2016-01-12 15:55:53 -0800167 eventDispatcher.addSink(AccessDeviceEvent.class, listenerRegistry);
168
Jonathan Harte533a422015-10-20 17:31:24 -0700169 networkConfig.registerConfigFactory(configFactory);
170 networkConfig.addListener(configListener);
171
alshabibdec2e252016-01-15 12:20:25 -0800172
Jonathan Harte533a422015-10-20 17:31:24 -0700173 networkConfig.getSubjects(DeviceId.class, AccessDeviceConfig.class).forEach(
174 subject -> {
175 AccessDeviceConfig config = networkConfig.getConfig(subject, AccessDeviceConfig.class);
176 if (config != null) {
177 AccessDeviceData data = config.getOlt();
178 oltData.put(data.deviceId(), data);
179 }
180 }
181 );
182
alshabibdec2e252016-01-15 12:20:25 -0800183 oltData.keySet().stream()
184 .flatMap(did -> deviceService.getPorts(did).stream())
alshabib62e9ce72016-02-11 17:31:36 -0800185 .filter(p -> !oltData.get(p.element().id()).uplink().equals(p.number()))
alshabibdec2e252016-01-15 12:20:25 -0800186 .filter(p -> p.isEnabled())
alshabib50d9fc52016-02-12 15:47:20 -0800187 .forEach(p -> processFilteringObjectives((DeviceId) p.element().id(),
188 p.number(), true));
alshabibdec2e252016-01-15 12:20:25 -0800189
alshabib4ceaed32016-03-03 18:00:58 -0800190 subscribers = storageService.<ConnectPoint, VlanId>consistentMapBuilder()
191 .withName(SUBSCRIBERS)
192 .withSerializer(Serializer.using(KryoNamespaces.API))
193 .build().asJavaMap();
194
alshabibba357492016-01-27 13:49:46 -0800195 deviceService.addListener(deviceListener);
196
alshabibf0e7e702015-05-30 18:22:36 -0700197 log.info("Started with Application ID {}", appId.id());
198 }
199
200 @Deactivate
201 public void deactivate() {
alshabibe0559672016-02-21 14:49:51 -0800202 componentConfigService.unregisterProperties(getClass(), false);
alshabib62e9ce72016-02-11 17:31:36 -0800203 deviceService.removeListener(deviceListener);
Jonathan Harte533a422015-10-20 17:31:24 -0700204 networkConfig.removeListener(configListener);
205 networkConfig.unregisterConfigFactory(configFactory);
alshabibf0e7e702015-05-30 18:22:36 -0700206 log.info("Stopped");
207 }
208
alshabibe0559672016-02-21 14:49:51 -0800209 @Modified
210 public void modified(ComponentContext context) {
211 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
212
213 try {
214 String s = get(properties, "defaultVlan");
215 defaultVlan = isNullOrEmpty(s) ? DEFAULT_VLAN : Integer.parseInt(s.trim());
Amit Ghosh95e2f652017-08-23 12:49:46 +0100216
217 Boolean o = Tools.isPropertyEnabled(properties, "enableDhcpIgmpOnProvisioning");
218 if (o != null) {
219 enableDhcpIgmpOnProvisioning = o;
220 }
alshabibe0559672016-02-21 14:49:51 -0800221 } catch (Exception e) {
222 defaultVlan = DEFAULT_VLAN;
223 }
224 }
225
alshabib32232c82016-02-25 17:57:24 -0500226 @Override
Jonathan Harte533a422015-10-20 17:31:24 -0700227 public void provisionSubscriber(ConnectPoint port, VlanId vlan) {
Jonathan Hart94b90492018-04-24 14:02:25 -0700228 checkNotNull(deviceService.getPort(port.deviceId(), port.port()),
229 "Invalid connect point");
Jonathan Harte533a422015-10-20 17:31:24 -0700230 AccessDeviceData olt = oltData.get(port.deviceId());
231
232 if (olt == null) {
233 log.warn("No data found for OLT device {}", port.deviceId());
Jonathan Hart94b90492018-04-24 14:02:25 -0700234 throw new IllegalArgumentException("Missing OLT configuration for device");
Jonathan Harte533a422015-10-20 17:31:24 -0700235 }
236
Amit Ghosh95e2f652017-08-23 12:49:46 +0100237 if (enableDhcpIgmpOnProvisioning) {
238 processDhcpFilteringObjectives(olt.deviceId(), port.port(), true);
239 }
240
Jonathan Hart52998382015-11-10 16:09:22 -0800241 provisionVlans(olt.deviceId(), olt.uplink(), port.port(), vlan, olt.vlan(),
Amit Ghosh95e2f652017-08-23 12:49:46 +0100242 olt.defaultVlan());
243
244 if (enableDhcpIgmpOnProvisioning) {
245 processIgmpFilteringObjectives(olt.deviceId(), port.port(), true);
246 }
alshabibb7a9e172016-01-13 11:23:53 -0800247 }
248
249 @Override
250 public void removeSubscriber(ConnectPoint port) {
alshabibbf23a1f2016-01-14 17:27:11 -0800251 AccessDeviceData olt = oltData.get(port.deviceId());
252
253 if (olt == null) {
254 log.warn("No data found for OLT device {}", port.deviceId());
255 return;
256 }
257
alshabib4ceaed32016-03-03 18:00:58 -0800258 VlanId subscriberVlan = subscribers.remove(port);
259
260 if (subscriberVlan == null) {
261 log.warn("Unknown subscriber at location {}", port);
262 return;
263 }
264
Amit Ghosh95e2f652017-08-23 12:49:46 +0100265 if (enableDhcpIgmpOnProvisioning) {
266 processDhcpFilteringObjectives(olt.deviceId(), port.port(), false);
267 }
268
alshabib4ceaed32016-03-03 18:00:58 -0800269 unprovisionSubscriber(olt.deviceId(), olt.uplink(), port.port(), subscriberVlan,
270 olt.vlan(), olt.defaultVlan());
alshabibbf23a1f2016-01-14 17:27:11 -0800271
Amit Ghosh95e2f652017-08-23 12:49:46 +0100272 if (enableDhcpIgmpOnProvisioning) {
273 processIgmpFilteringObjectives(olt.deviceId(), port.port(), false);
274 }
alshabibbf23a1f2016-01-14 17:27:11 -0800275 }
276
Amit Ghosh95e2f652017-08-23 12:49:46 +0100277
alshabibe0559672016-02-21 14:49:51 -0800278 @Override
Jonathan Hartfd6c1b32016-03-08 14:09:09 -0800279 public Collection<Map.Entry<ConnectPoint, VlanId>> getSubscribers() {
280 return subscribers.entrySet();
281 }
282
283 @Override
alshabibe0559672016-02-21 14:49:51 -0800284 public Map<DeviceId, AccessDeviceData> fetchOlts() {
285 return Maps.newHashMap(oltData);
286 }
287
alshabibbf23a1f2016-01-14 17:27:11 -0800288 private void unprovisionSubscriber(DeviceId deviceId, PortNumber uplink,
alshabib4ceaed32016-03-03 18:00:58 -0800289 PortNumber subscriberPort, VlanId subscriberVlan,
290 VlanId deviceVlan, Optional<VlanId> defaultVlan) {
alshabibbf23a1f2016-01-14 17:27:11 -0800291
292 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
293 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
294
alshabib4ceaed32016-03-03 18:00:58 -0800295 ForwardingObjective.Builder upFwd = upBuilder(uplink, subscriberPort,
296 subscriberVlan, deviceVlan,
297 defaultVlan);
298 ForwardingObjective.Builder downFwd = downBuilder(uplink, subscriberPort,
299 subscriberVlan, deviceVlan,
300 defaultVlan);
alshabibbf23a1f2016-01-14 17:27:11 -0800301
302
alshabib4ceaed32016-03-03 18:00:58 -0800303 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
304 @Override
305 public void onSuccess(Objective objective) {
306 upFuture.complete(null);
307 }
alshabibbf23a1f2016-01-14 17:27:11 -0800308
alshabib4ceaed32016-03-03 18:00:58 -0800309 @Override
310 public void onError(Objective objective, ObjectiveError error) {
311 upFuture.complete(error);
312 }
313 }));
314
315 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
316 @Override
317 public void onSuccess(Objective objective) {
318 downFuture.complete(null);
319 }
320
321 @Override
322 public void onError(Objective objective, ObjectiveError error) {
323 downFuture.complete(error);
324 }
325 }));
alshabibbf23a1f2016-01-14 17:27:11 -0800326
327 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
328 if (upStatus == null && downStatus == null) {
329 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_UNREGISTERED,
330 deviceId,
331 deviceVlan,
332 subscriberVlan));
333 } else if (downStatus != null) {
334 log.error("Subscriber with vlan {} on device {} " +
335 "on port {} failed downstream uninstallation: {}",
336 subscriberVlan, deviceId, subscriberPort, downStatus);
337 } else if (upStatus != null) {
338 log.error("Subscriber with vlan {} on device {} " +
339 "on port {} failed upstream uninstallation: {}",
340 subscriberVlan, deviceId, subscriberPort, upStatus);
341 }
342 }, oltInstallers);
alshabibb7a9e172016-01-13 11:23:53 -0800343
Jonathan Harte533a422015-10-20 17:31:24 -0700344 }
345
346 private void provisionVlans(DeviceId deviceId, PortNumber uplinkPort,
347 PortNumber subscriberPort,
Jonathan Hart52998382015-11-10 16:09:22 -0800348 VlanId subscriberVlan, VlanId deviceVlan,
349 Optional<VlanId> defaultVlan) {
Jonathan Harte533a422015-10-20 17:31:24 -0700350
alshabib3ea82642016-01-12 18:06:53 -0800351 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
352 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
353
alshabib4ceaed32016-03-03 18:00:58 -0800354 ForwardingObjective.Builder upFwd = upBuilder(uplinkPort, subscriberPort,
355 subscriberVlan, deviceVlan,
356 defaultVlan);
Jonathan Harte533a422015-10-20 17:31:24 -0700357
358
alshabib4ceaed32016-03-03 18:00:58 -0800359 ForwardingObjective.Builder downFwd = downBuilder(uplinkPort, subscriberPort,
360 subscriberVlan, deviceVlan,
361 defaultVlan);
alshabib3ea82642016-01-12 18:06:53 -0800362
alshabibbf23a1f2016-01-14 17:27:11 -0800363 ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
alshabibbf23a1f2016-01-14 17:27:11 -0800364 subscribers.put(cp, subscriberVlan);
alshabibbf23a1f2016-01-14 17:27:11 -0800365
alshabibbf23a1f2016-01-14 17:27:11 -0800366 flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
367 @Override
368 public void onSuccess(Objective objective) {
369 upFuture.complete(null);
370 }
371
372 @Override
373 public void onError(Objective objective, ObjectiveError error) {
374 upFuture.complete(error);
375 }
376 }));
377
alshabibbf23a1f2016-01-14 17:27:11 -0800378 flowObjectiveService.forward(deviceId, downFwd.add(new ObjectiveContext() {
379 @Override
380 public void onSuccess(Objective objective) {
381 downFuture.complete(null);
382 }
383
384 @Override
385 public void onError(Objective objective, ObjectiveError error) {
386 downFuture.complete(error);
387 }
388 }));
alshabib3ea82642016-01-12 18:06:53 -0800389
390 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
391 if (upStatus == null && downStatus == null) {
392 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_REGISTERED,
393 deviceId,
394 deviceVlan,
395 subscriberVlan));
alshabib50d9fc52016-02-12 15:47:20 -0800396
alshabib3ea82642016-01-12 18:06:53 -0800397 } else if (downStatus != null) {
398 log.error("Subscriber with vlan {} on device {} " +
399 "on port {} failed downstream installation: {}",
400 subscriberVlan, deviceId, subscriberPort, downStatus);
401 } else if (upStatus != null) {
402 log.error("Subscriber with vlan {} on device {} " +
403 "on port {} failed upstream installation: {}",
404 subscriberVlan, deviceId, subscriberPort, upStatus);
405 }
406 }, oltInstallers);
407
Jonathan Harte533a422015-10-20 17:31:24 -0700408 }
409
alshabib4ceaed32016-03-03 18:00:58 -0800410 private ForwardingObjective.Builder downBuilder(PortNumber uplinkPort,
411 PortNumber subscriberPort,
412 VlanId subscriberVlan,
413 VlanId deviceVlan,
414 Optional<VlanId> defaultVlan) {
415 TrafficSelector downstream = DefaultTrafficSelector.builder()
416 .matchVlanId(deviceVlan)
417 .matchInPort(uplinkPort)
418 .matchInnerVlanId(subscriberVlan)
419 .build();
420
421 TrafficTreatment downstreamTreatment = DefaultTrafficTreatment.builder()
422 .popVlan()
423 .setVlanId(defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan)))
424 .setOutput(subscriberPort)
425 .build();
426
427 return DefaultForwardingObjective.builder()
428 .withFlag(ForwardingObjective.Flag.VERSATILE)
429 .withPriority(1000)
430 .makePermanent()
431 .withSelector(downstream)
432 .fromApp(appId)
433 .withTreatment(downstreamTreatment);
434 }
435
436 private ForwardingObjective.Builder upBuilder(PortNumber uplinkPort,
437 PortNumber subscriberPort,
438 VlanId subscriberVlan,
439 VlanId deviceVlan,
440 Optional<VlanId> defaultVlan) {
441 TrafficSelector upstream = DefaultTrafficSelector.builder()
442 .matchVlanId(defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan)))
443 .matchInPort(subscriberPort)
444 .build();
445
446
447 TrafficTreatment upstreamTreatment = DefaultTrafficTreatment.builder()
448 .pushVlan()
449 .setVlanId(subscriberVlan)
450 .pushVlan()
451 .setVlanId(deviceVlan)
452 .setOutput(uplinkPort)
453 .build();
454
455 return DefaultForwardingObjective.builder()
456 .withFlag(ForwardingObjective.Flag.VERSATILE)
457 .withPriority(1000)
458 .makePermanent()
459 .withSelector(upstream)
460 .fromApp(appId)
461 .withTreatment(upstreamTreatment);
462 }
463
alshabib50d9fc52016-02-12 15:47:20 -0800464 private void processFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
alshabib09753b52016-03-04 14:55:19 -0800465 if (!mastershipService.isLocalMaster(devId)) {
466 return;
467 }
alshabibbb83aa22016-02-10 15:08:23 -0800468 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
469
470 FilteringObjective eapol = (install ? builder.permit() : builder.deny())
alshabib50d9fc52016-02-12 15:47:20 -0800471 .withKey(Criteria.matchInPort(port))
alshabibdec2e252016-01-15 12:20:25 -0800472 .addCondition(Criteria.matchEthType(EthType.EtherType.EAPOL.ethType()))
473 .withMeta(DefaultTrafficTreatment.builder()
474 .setOutput(PortNumber.CONTROLLER).build())
475 .fromApp(appId)
476 .withPriority(1000)
477 .add(new ObjectiveContext() {
478 @Override
479 public void onSuccess(Objective objective) {
480 log.info("Eapol filter for {} on {} installed.",
481 devId, port);
482 }
483
484 @Override
485 public void onError(Objective objective, ObjectiveError error) {
486 log.info("Eapol filter for {} on {} failed because {}",
487 devId, port, error);
488 }
489 });
490
alshabibdec2e252016-01-15 12:20:25 -0800491 flowObjectiveService.filter(devId, eapol);
alshabib000b6fc2016-02-01 17:25:00 -0800492
alshabibdec2e252016-01-15 12:20:25 -0800493 }
494
Amit Ghosh95e2f652017-08-23 12:49:46 +0100495 private void processDhcpFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
496 if (!mastershipService.isLocalMaster(devId)) {
497 return;
498 }
499 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
500
501 FilteringObjective dhcpUpstream = (install ? builder.permit() : builder.deny())
502 .withKey(Criteria.matchInPort(port))
503 .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
504 .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_UDP))
505 .addCondition(Criteria.matchUdpSrc(TpPort.tpPort(68)))
506 .addCondition(Criteria.matchUdpDst(TpPort.tpPort(67)))
507 .withMeta(DefaultTrafficTreatment.builder()
508 .setOutput(PortNumber.CONTROLLER).build())
509 .fromApp(appId)
510 .withPriority(1000)
511 .add(new ObjectiveContext() {
512 @Override
513 public void onSuccess(Objective objective) {
514 log.info("DHCP filter for {} on {} installed.",
515 devId, port);
516 }
517
518 @Override
519 public void onError(Objective objective, ObjectiveError error) {
520 log.info("DHCP filter for {} on {} failed because {}",
521 devId, port, error);
522 }
523 });
524
525 flowObjectiveService.filter(devId, dhcpUpstream);
526 }
527
528 private void processIgmpFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
529 if (!mastershipService.isLocalMaster(devId)) {
530 return;
531 }
532
533 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
534
535 builder = install ? builder.permit() : builder.deny();
536
537 FilteringObjective igmp = builder
538 .withKey(Criteria.matchInPort(port))
539 .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
540 .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_IGMP))
541 .withMeta(DefaultTrafficTreatment.builder()
542 .setOutput(PortNumber.CONTROLLER).build())
543 .fromApp(appId)
544 .withPriority(10000)
545 .add(new ObjectiveContext() {
546 @Override
547 public void onSuccess(Objective objective) {
548 log.info("Igmp filter for {} on {} installed.",
549 devId, port);
550 }
551
552 @Override
553 public void onError(Objective objective, ObjectiveError error) {
554 log.info("Igmp filter for {} on {} failed because {}.",
555 devId, port, error);
556 }
557 });
558
559 flowObjectiveService.filter(devId, igmp);
560 }
561
alshabibf0e7e702015-05-30 18:22:36 -0700562 private class InternalDeviceListener implements DeviceListener {
563 @Override
564 public void event(DeviceEvent event) {
alshabib3ea82642016-01-12 18:06:53 -0800565 DeviceId devId = event.subject().id();
566 if (!oltData.containsKey(devId)) {
alshabib8e4fd2f2016-01-12 15:55:53 -0800567 return;
568 }
alshabibf0e7e702015-05-30 18:22:36 -0700569 switch (event.type()) {
Jonathan Hartfd6c1b32016-03-08 14:09:09 -0800570 //TODO: Port handling and bookkeeping should be improved once
alshabibdec2e252016-01-15 12:20:25 -0800571 // olt firmware handles correct behaviour.
alshabibf0e7e702015-05-30 18:22:36 -0700572 case PORT_ADDED:
alshabibbb83aa22016-02-10 15:08:23 -0800573 if (!oltData.get(devId).uplink().equals(event.port().number()) &&
574 event.port().isEnabled()) {
alshabib50d9fc52016-02-12 15:47:20 -0800575 processFilteringObjectives(devId, event.port().number(), true);
alshabibdec2e252016-01-15 12:20:25 -0800576 }
577 break;
578 case PORT_REMOVED:
579 AccessDeviceData olt = oltData.get(devId);
alshabib4ceaed32016-03-03 18:00:58 -0800580 VlanId vlan = subscribers.get(new ConnectPoint(devId,
581 event.port().number()));
dvaddirec63dc822017-10-05 22:25:13 +0530582 if (vlan != null) {
583 unprovisionSubscriber(devId, olt.uplink(),
584 event.port().number(),
585 vlan, olt.vlan(), olt.defaultVlan());
586 }
alshabibbb83aa22016-02-10 15:08:23 -0800587 if (!oltData.get(devId).uplink().equals(event.port().number()) &&
588 event.port().isEnabled()) {
alshabib50d9fc52016-02-12 15:47:20 -0800589 processFilteringObjectives(devId, event.port().number(), false);
alshabibbb83aa22016-02-10 15:08:23 -0800590 }
alshabibdec2e252016-01-15 12:20:25 -0800591 break;
alshabibf0e7e702015-05-30 18:22:36 -0700592 case PORT_UPDATED:
alshabibbb83aa22016-02-10 15:08:23 -0800593 if (oltData.get(devId).uplink().equals(event.port().number())) {
594 break;
595 }
596 if (event.port().isEnabled()) {
alshabib50d9fc52016-02-12 15:47:20 -0800597 processFilteringObjectives(devId, event.port().number(), true);
alshabibbb83aa22016-02-10 15:08:23 -0800598 } else {
alshabib50d9fc52016-02-12 15:47:20 -0800599 processFilteringObjectives(devId, event.port().number(), false);
alshabibbb83aa22016-02-10 15:08:23 -0800600 }
alshabibf0e7e702015-05-30 18:22:36 -0700601 break;
602 case DEVICE_ADDED:
alshabib8e4fd2f2016-01-12 15:55:53 -0800603 post(new AccessDeviceEvent(
604 AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
605 null, null));
alshabibe0559672016-02-21 14:49:51 -0800606 provisionDefaultFlows(devId);
alshabib8e4fd2f2016-01-12 15:55:53 -0800607 break;
alshabibf0e7e702015-05-30 18:22:36 -0700608 case DEVICE_REMOVED:
alshabib8e4fd2f2016-01-12 15:55:53 -0800609 post(new AccessDeviceEvent(
610 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
611 null, null));
612 break;
alshabib7c190012016-02-09 18:22:33 -0800613 case DEVICE_AVAILABILITY_CHANGED:
614 if (deviceService.isAvailable(devId)) {
615 post(new AccessDeviceEvent(
616 AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
617 null, null));
618 } else {
619 post(new AccessDeviceEvent(
620 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
621 null, null));
622 }
623 break;
alshabib8e4fd2f2016-01-12 15:55:53 -0800624 case DEVICE_UPDATED:
alshabibf0e7e702015-05-30 18:22:36 -0700625 case DEVICE_SUSPENDED:
alshabibf0e7e702015-05-30 18:22:36 -0700626 case PORT_STATS_UPDATED:
627 default:
628 return;
629 }
630 }
631 }
632
Jonathan Harte533a422015-10-20 17:31:24 -0700633 private class InternalNetworkConfigListener implements NetworkConfigListener {
634 @Override
635 public void event(NetworkConfigEvent event) {
636 switch (event.type()) {
637
alshabibbf23a1f2016-01-14 17:27:11 -0800638 case CONFIG_ADDED:
639 case CONFIG_UPDATED:
alshabibe0559672016-02-21 14:49:51 -0800640
641 AccessDeviceConfig config =
642 networkConfig.getConfig((DeviceId) event.subject(), CONFIG_CLASS);
643 if (config != null) {
644 oltData.put(config.getOlt().deviceId(), config.getOlt());
645 provisionDefaultFlows((DeviceId) event.subject());
Jonathan Harte533a422015-10-20 17:31:24 -0700646 }
alshabibe0559672016-02-21 14:49:51 -0800647
alshabibbf23a1f2016-01-14 17:27:11 -0800648 break;
alshabibe0559672016-02-21 14:49:51 -0800649 case CONFIG_REGISTERED:
alshabibbf23a1f2016-01-14 17:27:11 -0800650 case CONFIG_UNREGISTERED:
alshabibe0559672016-02-21 14:49:51 -0800651 break;
alshabibbf23a1f2016-01-14 17:27:11 -0800652 case CONFIG_REMOVED:
alshabibe0559672016-02-21 14:49:51 -0800653 oltData.remove(event.subject());
alshabibbf23a1f2016-01-14 17:27:11 -0800654 default:
655 break;
Jonathan Harte533a422015-10-20 17:31:24 -0700656 }
657 }
alshabibe0559672016-02-21 14:49:51 -0800658
659 @Override
660 public boolean isRelevant(NetworkConfigEvent event) {
661 return event.configClass().equals(CONFIG_CLASS);
662 }
Jonathan Harte533a422015-10-20 17:31:24 -0700663 }
alshabibf0e7e702015-05-30 18:22:36 -0700664
alshabibbb83aa22016-02-10 15:08:23 -0800665 private void provisionDefaultFlows(DeviceId deviceId) {
alshabib09753b52016-03-04 14:55:19 -0800666 if (!mastershipService.isLocalMaster(deviceId)) {
667 return;
668 }
alshabibbb83aa22016-02-10 15:08:23 -0800669 List<Port> ports = deviceService.getPorts(deviceId);
670
671 ports.stream()
672 .filter(p -> !oltData.get(p.element().id()).uplink().equals(p.number()))
673 .filter(p -> p.isEnabled())
alshabib50d9fc52016-02-12 15:47:20 -0800674 .forEach(p -> processFilteringObjectives((DeviceId) p.element().id(),
675 p.number(), true));
alshabibbb83aa22016-02-10 15:08:23 -0800676
677 }
678
alshabibf0e7e702015-05-30 18:22:36 -0700679}