blob: a875245102a93993792d4f64dc7942f7a436fce7 [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;
alshabibf3a573e2016-06-01 17:39:10 -070033
alshabibf0e7e702015-05-30 18:22:36 -070034import org.onosproject.core.ApplicationId;
35import org.onosproject.core.CoreService;
alshabib8e4fd2f2016-01-12 15:55:53 -080036import org.onosproject.event.AbstractListenerManager;
alshabib09753b52016-03-04 14:55:19 -080037import org.onosproject.mastership.MastershipService;
Jonathan Harte533a422015-10-20 17:31:24 -070038import org.onosproject.net.ConnectPoint;
alshabibf0e7e702015-05-30 18:22:36 -070039import org.onosproject.net.DeviceId;
alshabibdec2e252016-01-15 12:20:25 -080040import org.onosproject.net.Port;
alshabibf0e7e702015-05-30 18:22:36 -070041import org.onosproject.net.PortNumber;
alshabibf3a573e2016-06-01 17:39:10 -070042
Jonathan Harte533a422015-10-20 17:31:24 -070043import org.onosproject.net.config.ConfigFactory;
44import org.onosproject.net.config.NetworkConfigEvent;
45import org.onosproject.net.config.NetworkConfigListener;
46import org.onosproject.net.config.NetworkConfigRegistry;
47import org.onosproject.net.config.basics.SubjectFactories;
alshabibf0e7e702015-05-30 18:22:36 -070048import org.onosproject.net.device.DeviceEvent;
49import org.onosproject.net.device.DeviceListener;
50import org.onosproject.net.device.DeviceService;
51import org.onosproject.net.flow.DefaultTrafficSelector;
52import org.onosproject.net.flow.DefaultTrafficTreatment;
53import org.onosproject.net.flow.TrafficSelector;
54import org.onosproject.net.flow.TrafficTreatment;
alshabibdec2e252016-01-15 12:20:25 -080055import org.onosproject.net.flow.criteria.Criteria;
56import org.onosproject.net.flowobjective.DefaultFilteringObjective;
alshabibf0e7e702015-05-30 18:22:36 -070057import org.onosproject.net.flowobjective.DefaultForwardingObjective;
alshabibdec2e252016-01-15 12:20:25 -080058import org.onosproject.net.flowobjective.FilteringObjective;
alshabibf0e7e702015-05-30 18:22:36 -070059import org.onosproject.net.flowobjective.FlowObjectiveService;
60import org.onosproject.net.flowobjective.ForwardingObjective;
alshabib3ea82642016-01-12 18:06:53 -080061import org.onosproject.net.flowobjective.Objective;
62import org.onosproject.net.flowobjective.ObjectiveContext;
63import org.onosproject.net.flowobjective.ObjectiveError;
alshabibf3a573e2016-06-01 17:39:10 -070064import org.opencord.cordconfig.access.AccessDeviceConfig;
65import org.opencord.cordconfig.access.AccessDeviceData;
alshabib36a4d732016-06-01 16:03:59 -070066import org.opencord.olt.AccessDeviceEvent;
67import org.opencord.olt.AccessDeviceListener;
68import org.opencord.olt.AccessDeviceService;
alshabib4ceaed32016-03-03 18:00:58 -080069import org.onosproject.store.serializers.KryoNamespaces;
70import org.onosproject.store.service.Serializer;
71import org.onosproject.store.service.StorageService;
alshabibe0559672016-02-21 14:49:51 -080072import org.osgi.service.component.ComponentContext;
alshabibf0e7e702015-05-30 18:22:36 -070073import org.slf4j.Logger;
74
Jonathan Hartfd6c1b32016-03-08 14:09:09 -080075import java.util.Collection;
alshabibe0559672016-02-21 14:49:51 -080076import java.util.Dictionary;
alshabibbb83aa22016-02-10 15:08:23 -080077import java.util.List;
Jonathan Harte533a422015-10-20 17:31:24 -070078import java.util.Map;
Jonathan Hart52998382015-11-10 16:09:22 -080079import java.util.Optional;
alshabibe0559672016-02-21 14:49:51 -080080import java.util.Properties;
alshabib3ea82642016-01-12 18:06:53 -080081import java.util.concurrent.CompletableFuture;
Jonathan Harte533a422015-10-20 17:31:24 -070082import java.util.concurrent.ConcurrentHashMap;
alshabib3ea82642016-01-12 18:06:53 -080083import java.util.concurrent.ExecutorService;
84import java.util.concurrent.Executors;
alshabibf0e7e702015-05-30 18:22:36 -070085
alshabibe0559672016-02-21 14:49:51 -080086import static com.google.common.base.Strings.isNullOrEmpty;
87import static org.onlab.util.Tools.get;
alshabib3ea82642016-01-12 18:06:53 -080088import static org.onlab.util.Tools.groupedThreads;
alshabibf0e7e702015-05-30 18:22:36 -070089import static org.slf4j.LoggerFactory.getLogger;
90
91/**
Jonathan Harte533a422015-10-20 17:31:24 -070092 * Provisions rules on access devices.
alshabibf0e7e702015-05-30 18:22:36 -070093 */
Jonathan Harte533a422015-10-20 17:31:24 -070094@Service
alshabibf0e7e702015-05-30 18:22:36 -070095@Component(immediate = true)
alshabib8e4fd2f2016-01-12 15:55:53 -080096public class Olt
97 extends AbstractListenerManager<AccessDeviceEvent, AccessDeviceListener>
98 implements AccessDeviceService {
Charles Chan54f110f2017-01-20 11:22:42 -080099 private static final String APP_NAME = "org.opencord.olt";
alshabibe0559672016-02-21 14:49:51 -0800100
101 private static final short DEFAULT_VLAN = 0;
alshabib4ceaed32016-03-03 18:00:58 -0800102 private static final String SUBSCRIBERS = "existing-subscribers";
alshabibe0559672016-02-21 14:49:51 -0800103
alshabibf0e7e702015-05-30 18:22:36 -0700104 private final Logger log = getLogger(getClass());
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected FlowObjectiveService flowObjectiveService;
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabib09753b52016-03-04 14:55:19 -0800110 protected MastershipService mastershipService;
111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibf0e7e702015-05-30 18:22:36 -0700113 protected DeviceService deviceService;
114
115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
116 protected CoreService coreService;
117
Jonathan Harte533a422015-10-20 17:31:24 -0700118 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
119 protected NetworkConfigRegistry networkConfig;
120
alshabibe0559672016-02-21 14:49:51 -0800121 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
122 protected ComponentConfigService componentConfigService;
123
alshabib4ceaed32016-03-03 18:00:58 -0800124 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
125 protected StorageService storageService;
alshabibe0559672016-02-21 14:49:51 -0800126
127 @Property(name = "defaultVlan", intValue = DEFAULT_VLAN,
128 label = "Default VLAN RG<->ONU traffic")
129 private int defaultVlan = DEFAULT_VLAN;
130
Amit Ghosh95e2f652017-08-23 12:49:46 +0100131 @Property(name = "enableDhcpIgmpOnProvisioning", boolValue = false,
132 label = "Create the DHCP and IGMP Flow rules when a subscriber is provisioned")
133 protected boolean enableDhcpIgmpOnProvisioning = false;
134
alshabibf0e7e702015-05-30 18:22:36 -0700135 private final DeviceListener deviceListener = new InternalDeviceListener();
136
137 private ApplicationId appId;
138
alshabib3ea82642016-01-12 18:06:53 -0800139 private ExecutorService oltInstallers = Executors.newFixedThreadPool(4,
alshabibbf23a1f2016-01-14 17:27:11 -0800140 groupedThreads("onos/olt-service",
141 "olt-installer-%d"));
alshabib4ae2b402015-06-05 14:55:24 -0700142
Jonathan Harte533a422015-10-20 17:31:24 -0700143 private Map<DeviceId, AccessDeviceData> oltData = new ConcurrentHashMap<>();
144
alshabib4ceaed32016-03-03 18:00:58 -0800145 private Map<ConnectPoint, VlanId> subscribers;
alshabibbf23a1f2016-01-14 17:27:11 -0800146
Jonathan Harte533a422015-10-20 17:31:24 -0700147 private InternalNetworkConfigListener configListener =
148 new InternalNetworkConfigListener();
149 private static final Class<AccessDeviceConfig> CONFIG_CLASS =
150 AccessDeviceConfig.class;
151
152 private ConfigFactory<DeviceId, AccessDeviceConfig> configFactory =
153 new ConfigFactory<DeviceId, AccessDeviceConfig>(
154 SubjectFactories.DEVICE_SUBJECT_FACTORY, CONFIG_CLASS, "accessDevice") {
alshabibbf23a1f2016-01-14 17:27:11 -0800155 @Override
156 public AccessDeviceConfig createConfig() {
157 return new AccessDeviceConfig();
158 }
159 };
160
alshabibf0e7e702015-05-30 18:22:36 -0700161
162 @Activate
alshabibe0559672016-02-21 14:49:51 -0800163 public void activate(ComponentContext context) {
164 modified(context);
Charles Chan54f110f2017-01-20 11:22:42 -0800165 appId = coreService.registerApplication(APP_NAME);
alshabibe0559672016-02-21 14:49:51 -0800166 componentConfigService.registerProperties(getClass());
alshabibc4dfe852015-06-05 13:35:13 -0700167
alshabib8e4fd2f2016-01-12 15:55:53 -0800168 eventDispatcher.addSink(AccessDeviceEvent.class, listenerRegistry);
169
Jonathan Harte533a422015-10-20 17:31:24 -0700170 networkConfig.registerConfigFactory(configFactory);
171 networkConfig.addListener(configListener);
172
alshabibdec2e252016-01-15 12:20:25 -0800173
Jonathan Harte533a422015-10-20 17:31:24 -0700174 networkConfig.getSubjects(DeviceId.class, AccessDeviceConfig.class).forEach(
175 subject -> {
176 AccessDeviceConfig config = networkConfig.getConfig(subject, AccessDeviceConfig.class);
177 if (config != null) {
178 AccessDeviceData data = config.getOlt();
179 oltData.put(data.deviceId(), data);
180 }
181 }
182 );
183
alshabibdec2e252016-01-15 12:20:25 -0800184 oltData.keySet().stream()
185 .flatMap(did -> deviceService.getPorts(did).stream())
alshabib62e9ce72016-02-11 17:31:36 -0800186 .filter(p -> !oltData.get(p.element().id()).uplink().equals(p.number()))
alshabibdec2e252016-01-15 12:20:25 -0800187 .filter(p -> p.isEnabled())
alshabib50d9fc52016-02-12 15:47:20 -0800188 .forEach(p -> processFilteringObjectives((DeviceId) p.element().id(),
189 p.number(), true));
alshabibdec2e252016-01-15 12:20:25 -0800190
alshabib4ceaed32016-03-03 18:00:58 -0800191 subscribers = storageService.<ConnectPoint, VlanId>consistentMapBuilder()
192 .withName(SUBSCRIBERS)
193 .withSerializer(Serializer.using(KryoNamespaces.API))
194 .build().asJavaMap();
195
alshabibba357492016-01-27 13:49:46 -0800196 deviceService.addListener(deviceListener);
197
alshabibf0e7e702015-05-30 18:22:36 -0700198 log.info("Started with Application ID {}", appId.id());
199 }
200
201 @Deactivate
202 public void deactivate() {
alshabibe0559672016-02-21 14:49:51 -0800203 componentConfigService.unregisterProperties(getClass(), false);
alshabib62e9ce72016-02-11 17:31:36 -0800204 deviceService.removeListener(deviceListener);
Jonathan Harte533a422015-10-20 17:31:24 -0700205 networkConfig.removeListener(configListener);
206 networkConfig.unregisterConfigFactory(configFactory);
alshabibf0e7e702015-05-30 18:22:36 -0700207 log.info("Stopped");
208 }
209
alshabibe0559672016-02-21 14:49:51 -0800210 @Modified
211 public void modified(ComponentContext context) {
212 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
213
214 try {
215 String s = get(properties, "defaultVlan");
216 defaultVlan = isNullOrEmpty(s) ? DEFAULT_VLAN : Integer.parseInt(s.trim());
Amit Ghosh95e2f652017-08-23 12:49:46 +0100217
218 Boolean o = Tools.isPropertyEnabled(properties, "enableDhcpIgmpOnProvisioning");
219 if (o != null) {
220 enableDhcpIgmpOnProvisioning = o;
221 }
alshabibe0559672016-02-21 14:49:51 -0800222 } catch (Exception e) {
223 defaultVlan = DEFAULT_VLAN;
224 }
225 }
226
alshabib32232c82016-02-25 17:57:24 -0500227 @Override
Jonathan Harte533a422015-10-20 17:31:24 -0700228 public void provisionSubscriber(ConnectPoint port, VlanId vlan) {
229 AccessDeviceData olt = oltData.get(port.deviceId());
230
231 if (olt == null) {
232 log.warn("No data found for OLT device {}", port.deviceId());
233 return;
234 }
235
Amit Ghosh95e2f652017-08-23 12:49:46 +0100236 if (enableDhcpIgmpOnProvisioning) {
237 processDhcpFilteringObjectives(olt.deviceId(), port.port(), true);
238 }
239
Jonathan Hart52998382015-11-10 16:09:22 -0800240 provisionVlans(olt.deviceId(), olt.uplink(), port.port(), vlan, olt.vlan(),
Amit Ghosh95e2f652017-08-23 12:49:46 +0100241 olt.defaultVlan());
242
243 if (enableDhcpIgmpOnProvisioning) {
244 processIgmpFilteringObjectives(olt.deviceId(), port.port(), true);
245 }
alshabibb7a9e172016-01-13 11:23:53 -0800246 }
247
248 @Override
249 public void removeSubscriber(ConnectPoint port) {
alshabibbf23a1f2016-01-14 17:27:11 -0800250 AccessDeviceData olt = oltData.get(port.deviceId());
251
252 if (olt == null) {
253 log.warn("No data found for OLT device {}", port.deviceId());
254 return;
255 }
256
alshabib4ceaed32016-03-03 18:00:58 -0800257 VlanId subscriberVlan = subscribers.remove(port);
258
259 if (subscriberVlan == null) {
260 log.warn("Unknown subscriber at location {}", port);
261 return;
262 }
263
Amit Ghosh95e2f652017-08-23 12:49:46 +0100264 if (enableDhcpIgmpOnProvisioning) {
265 processDhcpFilteringObjectives(olt.deviceId(), port.port(), false);
266 }
267
alshabib4ceaed32016-03-03 18:00:58 -0800268 unprovisionSubscriber(olt.deviceId(), olt.uplink(), port.port(), subscriberVlan,
269 olt.vlan(), olt.defaultVlan());
alshabibbf23a1f2016-01-14 17:27:11 -0800270
Amit Ghosh95e2f652017-08-23 12:49:46 +0100271 if (enableDhcpIgmpOnProvisioning) {
272 processIgmpFilteringObjectives(olt.deviceId(), port.port(), false);
273 }
alshabibbf23a1f2016-01-14 17:27:11 -0800274 }
275
Amit Ghosh95e2f652017-08-23 12:49:46 +0100276
alshabibe0559672016-02-21 14:49:51 -0800277 @Override
Jonathan Hartfd6c1b32016-03-08 14:09:09 -0800278 public Collection<Map.Entry<ConnectPoint, VlanId>> getSubscribers() {
279 return subscribers.entrySet();
280 }
281
282 @Override
alshabibe0559672016-02-21 14:49:51 -0800283 public Map<DeviceId, AccessDeviceData> fetchOlts() {
284 return Maps.newHashMap(oltData);
285 }
286
alshabibbf23a1f2016-01-14 17:27:11 -0800287 private void unprovisionSubscriber(DeviceId deviceId, PortNumber uplink,
alshabib4ceaed32016-03-03 18:00:58 -0800288 PortNumber subscriberPort, VlanId subscriberVlan,
289 VlanId deviceVlan, Optional<VlanId> defaultVlan) {
alshabibbf23a1f2016-01-14 17:27:11 -0800290
291 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
292 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
293
alshabib4ceaed32016-03-03 18:00:58 -0800294 ForwardingObjective.Builder upFwd = upBuilder(uplink, subscriberPort,
295 subscriberVlan, deviceVlan,
296 defaultVlan);
297 ForwardingObjective.Builder downFwd = downBuilder(uplink, subscriberPort,
298 subscriberVlan, deviceVlan,
299 defaultVlan);
alshabibbf23a1f2016-01-14 17:27:11 -0800300
301
alshabib4ceaed32016-03-03 18:00:58 -0800302 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
303 @Override
304 public void onSuccess(Objective objective) {
305 upFuture.complete(null);
306 }
alshabibbf23a1f2016-01-14 17:27:11 -0800307
alshabib4ceaed32016-03-03 18:00:58 -0800308 @Override
309 public void onError(Objective objective, ObjectiveError error) {
310 upFuture.complete(error);
311 }
312 }));
313
314 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
315 @Override
316 public void onSuccess(Objective objective) {
317 downFuture.complete(null);
318 }
319
320 @Override
321 public void onError(Objective objective, ObjectiveError error) {
322 downFuture.complete(error);
323 }
324 }));
alshabibbf23a1f2016-01-14 17:27:11 -0800325
326 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
327 if (upStatus == null && downStatus == null) {
328 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_UNREGISTERED,
329 deviceId,
330 deviceVlan,
331 subscriberVlan));
332 } else if (downStatus != null) {
333 log.error("Subscriber with vlan {} on device {} " +
334 "on port {} failed downstream uninstallation: {}",
335 subscriberVlan, deviceId, subscriberPort, downStatus);
336 } else if (upStatus != null) {
337 log.error("Subscriber with vlan {} on device {} " +
338 "on port {} failed upstream uninstallation: {}",
339 subscriberVlan, deviceId, subscriberPort, upStatus);
340 }
341 }, oltInstallers);
alshabibb7a9e172016-01-13 11:23:53 -0800342
Jonathan Harte533a422015-10-20 17:31:24 -0700343 }
344
345 private void provisionVlans(DeviceId deviceId, PortNumber uplinkPort,
346 PortNumber subscriberPort,
Jonathan Hart52998382015-11-10 16:09:22 -0800347 VlanId subscriberVlan, VlanId deviceVlan,
348 Optional<VlanId> defaultVlan) {
Jonathan Harte533a422015-10-20 17:31:24 -0700349
alshabib3ea82642016-01-12 18:06:53 -0800350 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
351 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
352
alshabib4ceaed32016-03-03 18:00:58 -0800353 ForwardingObjective.Builder upFwd = upBuilder(uplinkPort, subscriberPort,
354 subscriberVlan, deviceVlan,
355 defaultVlan);
Jonathan Harte533a422015-10-20 17:31:24 -0700356
357
alshabib4ceaed32016-03-03 18:00:58 -0800358 ForwardingObjective.Builder downFwd = downBuilder(uplinkPort, subscriberPort,
359 subscriberVlan, deviceVlan,
360 defaultVlan);
alshabib3ea82642016-01-12 18:06:53 -0800361
alshabibbf23a1f2016-01-14 17:27:11 -0800362 ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
alshabibbf23a1f2016-01-14 17:27:11 -0800363 subscribers.put(cp, subscriberVlan);
alshabibbf23a1f2016-01-14 17:27:11 -0800364
alshabibbf23a1f2016-01-14 17:27:11 -0800365 flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
366 @Override
367 public void onSuccess(Objective objective) {
368 upFuture.complete(null);
369 }
370
371 @Override
372 public void onError(Objective objective, ObjectiveError error) {
373 upFuture.complete(error);
374 }
375 }));
376
alshabibbf23a1f2016-01-14 17:27:11 -0800377 flowObjectiveService.forward(deviceId, downFwd.add(new ObjectiveContext() {
378 @Override
379 public void onSuccess(Objective objective) {
380 downFuture.complete(null);
381 }
382
383 @Override
384 public void onError(Objective objective, ObjectiveError error) {
385 downFuture.complete(error);
386 }
387 }));
alshabib3ea82642016-01-12 18:06:53 -0800388
389 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
390 if (upStatus == null && downStatus == null) {
391 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_REGISTERED,
392 deviceId,
393 deviceVlan,
394 subscriberVlan));
alshabib50d9fc52016-02-12 15:47:20 -0800395
alshabib3ea82642016-01-12 18:06:53 -0800396 } else if (downStatus != null) {
397 log.error("Subscriber with vlan {} on device {} " +
398 "on port {} failed downstream installation: {}",
399 subscriberVlan, deviceId, subscriberPort, downStatus);
400 } else if (upStatus != null) {
401 log.error("Subscriber with vlan {} on device {} " +
402 "on port {} failed upstream installation: {}",
403 subscriberVlan, deviceId, subscriberPort, upStatus);
404 }
405 }, oltInstallers);
406
Jonathan Harte533a422015-10-20 17:31:24 -0700407 }
408
alshabib4ceaed32016-03-03 18:00:58 -0800409 private ForwardingObjective.Builder downBuilder(PortNumber uplinkPort,
410 PortNumber subscriberPort,
411 VlanId subscriberVlan,
412 VlanId deviceVlan,
413 Optional<VlanId> defaultVlan) {
414 TrafficSelector downstream = DefaultTrafficSelector.builder()
415 .matchVlanId(deviceVlan)
416 .matchInPort(uplinkPort)
417 .matchInnerVlanId(subscriberVlan)
418 .build();
419
420 TrafficTreatment downstreamTreatment = DefaultTrafficTreatment.builder()
421 .popVlan()
422 .setVlanId(defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan)))
423 .setOutput(subscriberPort)
424 .build();
425
426 return DefaultForwardingObjective.builder()
427 .withFlag(ForwardingObjective.Flag.VERSATILE)
428 .withPriority(1000)
429 .makePermanent()
430 .withSelector(downstream)
431 .fromApp(appId)
432 .withTreatment(downstreamTreatment);
433 }
434
435 private ForwardingObjective.Builder upBuilder(PortNumber uplinkPort,
436 PortNumber subscriberPort,
437 VlanId subscriberVlan,
438 VlanId deviceVlan,
439 Optional<VlanId> defaultVlan) {
440 TrafficSelector upstream = DefaultTrafficSelector.builder()
441 .matchVlanId(defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan)))
442 .matchInPort(subscriberPort)
443 .build();
444
445
446 TrafficTreatment upstreamTreatment = DefaultTrafficTreatment.builder()
447 .pushVlan()
448 .setVlanId(subscriberVlan)
449 .pushVlan()
450 .setVlanId(deviceVlan)
451 .setOutput(uplinkPort)
452 .build();
453
454 return DefaultForwardingObjective.builder()
455 .withFlag(ForwardingObjective.Flag.VERSATILE)
456 .withPriority(1000)
457 .makePermanent()
458 .withSelector(upstream)
459 .fromApp(appId)
460 .withTreatment(upstreamTreatment);
461 }
462
alshabib50d9fc52016-02-12 15:47:20 -0800463 private void processFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
alshabib09753b52016-03-04 14:55:19 -0800464 if (!mastershipService.isLocalMaster(devId)) {
465 return;
466 }
alshabibbb83aa22016-02-10 15:08:23 -0800467 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
468
469 FilteringObjective eapol = (install ? builder.permit() : builder.deny())
alshabib50d9fc52016-02-12 15:47:20 -0800470 .withKey(Criteria.matchInPort(port))
alshabibdec2e252016-01-15 12:20:25 -0800471 .addCondition(Criteria.matchEthType(EthType.EtherType.EAPOL.ethType()))
472 .withMeta(DefaultTrafficTreatment.builder()
473 .setOutput(PortNumber.CONTROLLER).build())
474 .fromApp(appId)
475 .withPriority(1000)
476 .add(new ObjectiveContext() {
477 @Override
478 public void onSuccess(Objective objective) {
479 log.info("Eapol filter for {} on {} installed.",
480 devId, port);
481 }
482
483 @Override
484 public void onError(Objective objective, ObjectiveError error) {
485 log.info("Eapol filter for {} on {} failed because {}",
486 devId, port, error);
487 }
488 });
489
alshabibdec2e252016-01-15 12:20:25 -0800490 flowObjectiveService.filter(devId, eapol);
alshabib000b6fc2016-02-01 17:25:00 -0800491
alshabibdec2e252016-01-15 12:20:25 -0800492 }
493
Amit Ghosh95e2f652017-08-23 12:49:46 +0100494 private void processDhcpFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
495 if (!mastershipService.isLocalMaster(devId)) {
496 return;
497 }
498 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
499
500 FilteringObjective dhcpUpstream = (install ? builder.permit() : builder.deny())
501 .withKey(Criteria.matchInPort(port))
502 .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
503 .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_UDP))
504 .addCondition(Criteria.matchUdpSrc(TpPort.tpPort(68)))
505 .addCondition(Criteria.matchUdpDst(TpPort.tpPort(67)))
506 .withMeta(DefaultTrafficTreatment.builder()
507 .setOutput(PortNumber.CONTROLLER).build())
508 .fromApp(appId)
509 .withPriority(1000)
510 .add(new ObjectiveContext() {
511 @Override
512 public void onSuccess(Objective objective) {
513 log.info("DHCP filter for {} on {} installed.",
514 devId, port);
515 }
516
517 @Override
518 public void onError(Objective objective, ObjectiveError error) {
519 log.info("DHCP filter for {} on {} failed because {}",
520 devId, port, error);
521 }
522 });
523
524 flowObjectiveService.filter(devId, dhcpUpstream);
525 }
526
527 private void processIgmpFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
528 if (!mastershipService.isLocalMaster(devId)) {
529 return;
530 }
531
532 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
533
534 builder = install ? builder.permit() : builder.deny();
535
536 FilteringObjective igmp = builder
537 .withKey(Criteria.matchInPort(port))
538 .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
539 .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_IGMP))
540 .withMeta(DefaultTrafficTreatment.builder()
541 .setOutput(PortNumber.CONTROLLER).build())
542 .fromApp(appId)
543 .withPriority(10000)
544 .add(new ObjectiveContext() {
545 @Override
546 public void onSuccess(Objective objective) {
547 log.info("Igmp filter for {} on {} installed.",
548 devId, port);
549 }
550
551 @Override
552 public void onError(Objective objective, ObjectiveError error) {
553 log.info("Igmp filter for {} on {} failed because {}.",
554 devId, port, error);
555 }
556 });
557
558 flowObjectiveService.filter(devId, igmp);
559 }
560
alshabibf0e7e702015-05-30 18:22:36 -0700561 private class InternalDeviceListener implements DeviceListener {
562 @Override
563 public void event(DeviceEvent event) {
alshabib3ea82642016-01-12 18:06:53 -0800564 DeviceId devId = event.subject().id();
565 if (!oltData.containsKey(devId)) {
alshabib8e4fd2f2016-01-12 15:55:53 -0800566 return;
567 }
alshabibf0e7e702015-05-30 18:22:36 -0700568 switch (event.type()) {
Jonathan Hartfd6c1b32016-03-08 14:09:09 -0800569 //TODO: Port handling and bookkeeping should be improved once
alshabibdec2e252016-01-15 12:20:25 -0800570 // olt firmware handles correct behaviour.
alshabibf0e7e702015-05-30 18:22:36 -0700571 case PORT_ADDED:
alshabibbb83aa22016-02-10 15:08:23 -0800572 if (!oltData.get(devId).uplink().equals(event.port().number()) &&
573 event.port().isEnabled()) {
alshabib50d9fc52016-02-12 15:47:20 -0800574 processFilteringObjectives(devId, event.port().number(), true);
alshabibdec2e252016-01-15 12:20:25 -0800575 }
576 break;
577 case PORT_REMOVED:
578 AccessDeviceData olt = oltData.get(devId);
alshabib4ceaed32016-03-03 18:00:58 -0800579 VlanId vlan = subscribers.get(new ConnectPoint(devId,
580 event.port().number()));
dvaddirec63dc822017-10-05 22:25:13 +0530581 if (vlan != null) {
582 unprovisionSubscriber(devId, olt.uplink(),
583 event.port().number(),
584 vlan, olt.vlan(), olt.defaultVlan());
585 }
alshabibbb83aa22016-02-10 15:08:23 -0800586 if (!oltData.get(devId).uplink().equals(event.port().number()) &&
587 event.port().isEnabled()) {
alshabib50d9fc52016-02-12 15:47:20 -0800588 processFilteringObjectives(devId, event.port().number(), false);
alshabibbb83aa22016-02-10 15:08:23 -0800589 }
alshabibdec2e252016-01-15 12:20:25 -0800590 break;
alshabibf0e7e702015-05-30 18:22:36 -0700591 case PORT_UPDATED:
alshabibbb83aa22016-02-10 15:08:23 -0800592 if (oltData.get(devId).uplink().equals(event.port().number())) {
593 break;
594 }
595 if (event.port().isEnabled()) {
alshabib50d9fc52016-02-12 15:47:20 -0800596 processFilteringObjectives(devId, event.port().number(), true);
alshabibbb83aa22016-02-10 15:08:23 -0800597 } else {
alshabib50d9fc52016-02-12 15:47:20 -0800598 processFilteringObjectives(devId, event.port().number(), false);
alshabibbb83aa22016-02-10 15:08:23 -0800599 }
alshabibf0e7e702015-05-30 18:22:36 -0700600 break;
601 case DEVICE_ADDED:
alshabib8e4fd2f2016-01-12 15:55:53 -0800602 post(new AccessDeviceEvent(
603 AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
604 null, null));
alshabibe0559672016-02-21 14:49:51 -0800605 provisionDefaultFlows(devId);
alshabib8e4fd2f2016-01-12 15:55:53 -0800606 break;
alshabibf0e7e702015-05-30 18:22:36 -0700607 case DEVICE_REMOVED:
alshabib8e4fd2f2016-01-12 15:55:53 -0800608 post(new AccessDeviceEvent(
609 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
610 null, null));
611 break;
alshabib7c190012016-02-09 18:22:33 -0800612 case DEVICE_AVAILABILITY_CHANGED:
613 if (deviceService.isAvailable(devId)) {
614 post(new AccessDeviceEvent(
615 AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
616 null, null));
617 } else {
618 post(new AccessDeviceEvent(
619 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
620 null, null));
621 }
622 break;
alshabib8e4fd2f2016-01-12 15:55:53 -0800623 case DEVICE_UPDATED:
alshabibf0e7e702015-05-30 18:22:36 -0700624 case DEVICE_SUSPENDED:
alshabibf0e7e702015-05-30 18:22:36 -0700625 case PORT_STATS_UPDATED:
626 default:
627 return;
628 }
629 }
630 }
631
Jonathan Harte533a422015-10-20 17:31:24 -0700632 private class InternalNetworkConfigListener implements NetworkConfigListener {
633 @Override
634 public void event(NetworkConfigEvent event) {
635 switch (event.type()) {
636
alshabibbf23a1f2016-01-14 17:27:11 -0800637 case CONFIG_ADDED:
638 case CONFIG_UPDATED:
alshabibe0559672016-02-21 14:49:51 -0800639
640 AccessDeviceConfig config =
641 networkConfig.getConfig((DeviceId) event.subject(), CONFIG_CLASS);
642 if (config != null) {
643 oltData.put(config.getOlt().deviceId(), config.getOlt());
644 provisionDefaultFlows((DeviceId) event.subject());
Jonathan Harte533a422015-10-20 17:31:24 -0700645 }
alshabibe0559672016-02-21 14:49:51 -0800646
alshabibbf23a1f2016-01-14 17:27:11 -0800647 break;
alshabibe0559672016-02-21 14:49:51 -0800648 case CONFIG_REGISTERED:
alshabibbf23a1f2016-01-14 17:27:11 -0800649 case CONFIG_UNREGISTERED:
alshabibe0559672016-02-21 14:49:51 -0800650 break;
alshabibbf23a1f2016-01-14 17:27:11 -0800651 case CONFIG_REMOVED:
alshabibe0559672016-02-21 14:49:51 -0800652 oltData.remove(event.subject());
alshabibbf23a1f2016-01-14 17:27:11 -0800653 default:
654 break;
Jonathan Harte533a422015-10-20 17:31:24 -0700655 }
656 }
alshabibe0559672016-02-21 14:49:51 -0800657
658 @Override
659 public boolean isRelevant(NetworkConfigEvent event) {
660 return event.configClass().equals(CONFIG_CLASS);
661 }
Jonathan Harte533a422015-10-20 17:31:24 -0700662 }
alshabibf0e7e702015-05-30 18:22:36 -0700663
alshabibbb83aa22016-02-10 15:08:23 -0800664 private void provisionDefaultFlows(DeviceId deviceId) {
alshabib09753b52016-03-04 14:55:19 -0800665 if (!mastershipService.isLocalMaster(deviceId)) {
666 return;
667 }
alshabibbb83aa22016-02-10 15:08:23 -0800668 List<Port> ports = deviceService.getPorts(deviceId);
669
670 ports.stream()
671 .filter(p -> !oltData.get(p.element().id()).uplink().equals(p.number()))
672 .filter(p -> p.isEnabled())
alshabib50d9fc52016-02-12 15:47:20 -0800673 .forEach(p -> processFilteringObjectives((DeviceId) p.element().id(),
674 p.number(), true));
alshabibbb83aa22016-02-10 15:08:23 -0800675
676 }
677
alshabibf0e7e702015-05-30 18:22:36 -0700678}