blob: a3c40a83088fad7c234efbd297c8036489597fa3 [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;
26import java.util.ArrayList;
Saurav Das62ad75e2019-03-05 12:22:22 -080027import java.util.Arrays;
Saurav Das82b8e6d2018-10-04 15:25:12 -070028import java.util.Collection;
29import java.util.Dictionary;
Saurav Das62ad75e2019-03-05 12:22:22 -080030import java.util.HashMap;
Saurav Das82b8e6d2018-10-04 15:25:12 -070031import java.util.List;
32import java.util.Map;
33import java.util.Optional;
34import java.util.Properties;
35import java.util.concurrent.CompletableFuture;
Gamze Abaka838d8142019-02-21 07:06:55 +000036import java.util.concurrent.CopyOnWriteArrayList;
Saurav Das82b8e6d2018-10-04 15:25:12 -070037import java.util.concurrent.ExecutorService;
38import java.util.concurrent.Executors;
39
alshabibf0e7e702015-05-30 18:22:36 -070040import org.apache.felix.scr.annotations.Activate;
41import org.apache.felix.scr.annotations.Component;
42import org.apache.felix.scr.annotations.Deactivate;
alshabibe0559672016-02-21 14:49:51 -080043import org.apache.felix.scr.annotations.Modified;
44import org.apache.felix.scr.annotations.Property;
alshabibf0e7e702015-05-30 18:22:36 -070045import org.apache.felix.scr.annotations.Reference;
46import org.apache.felix.scr.annotations.ReferenceCardinality;
Jonathan Harte533a422015-10-20 17:31:24 -070047import org.apache.felix.scr.annotations.Service;
alshabibdec2e252016-01-15 12:20:25 -080048import org.onlab.packet.EthType;
Amit Ghosh95e2f652017-08-23 12:49:46 +010049import org.onlab.packet.IPv4;
Matteo Scandolo63460d12018-11-02 16:19:04 -070050import org.onlab.packet.IPv6;
Amit Ghosh95e2f652017-08-23 12:49:46 +010051import org.onlab.packet.TpPort;
alshabibf0e7e702015-05-30 18:22:36 -070052import org.onlab.packet.VlanId;
Amit Ghosh95e2f652017-08-23 12:49:46 +010053import org.onlab.util.Tools;
alshabibe0559672016-02-21 14:49:51 -080054import org.onosproject.cfg.ComponentConfigService;
alshabibf0e7e702015-05-30 18:22:36 -070055import org.onosproject.core.ApplicationId;
56import org.onosproject.core.CoreService;
alshabib8e4fd2f2016-01-12 15:55:53 -080057import org.onosproject.event.AbstractListenerManager;
alshabib09753b52016-03-04 14:55:19 -080058import org.onosproject.mastership.MastershipService;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010059import org.onosproject.net.AnnotationKeys;
Jonathan Harte533a422015-10-20 17:31:24 -070060import org.onosproject.net.ConnectPoint;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010061import org.onosproject.net.Device;
alshabibf0e7e702015-05-30 18:22:36 -070062import org.onosproject.net.DeviceId;
alshabibdec2e252016-01-15 12:20:25 -080063import org.onosproject.net.Port;
alshabibf0e7e702015-05-30 18:22:36 -070064import org.onosproject.net.PortNumber;
65import org.onosproject.net.device.DeviceEvent;
66import org.onosproject.net.device.DeviceListener;
67import org.onosproject.net.device.DeviceService;
68import org.onosproject.net.flow.DefaultTrafficSelector;
69import org.onosproject.net.flow.DefaultTrafficTreatment;
70import org.onosproject.net.flow.TrafficSelector;
71import org.onosproject.net.flow.TrafficTreatment;
alshabibdec2e252016-01-15 12:20:25 -080072import org.onosproject.net.flow.criteria.Criteria;
73import org.onosproject.net.flowobjective.DefaultFilteringObjective;
alshabibf0e7e702015-05-30 18:22:36 -070074import org.onosproject.net.flowobjective.DefaultForwardingObjective;
alshabibdec2e252016-01-15 12:20:25 -080075import org.onosproject.net.flowobjective.FilteringObjective;
alshabibf0e7e702015-05-30 18:22:36 -070076import org.onosproject.net.flowobjective.FlowObjectiveService;
77import org.onosproject.net.flowobjective.ForwardingObjective;
alshabib3ea82642016-01-12 18:06:53 -080078import org.onosproject.net.flowobjective.Objective;
79import org.onosproject.net.flowobjective.ObjectiveContext;
80import org.onosproject.net.flowobjective.ObjectiveError;
Gamze Abaka641fc072018-09-04 09:16:27 +000081import org.onosproject.net.meter.Band;
82import org.onosproject.net.meter.DefaultBand;
83import org.onosproject.net.meter.DefaultMeterRequest;
84import org.onosproject.net.meter.Meter;
Saurav Das62ad75e2019-03-05 12:22:22 -080085import org.onosproject.net.meter.MeterEvent;
86import org.onosproject.net.meter.MeterId;
Gamze Abaka641fc072018-09-04 09:16:27 +000087import org.onosproject.net.meter.MeterListener;
88import org.onosproject.net.meter.MeterRequest;
Saurav Das62ad75e2019-03-05 12:22:22 -080089import org.onosproject.net.meter.MeterService;
90import org.onosproject.store.serializers.KryoNamespaces;
91import org.onosproject.store.service.ConsistentMultimap;
92import org.onosproject.store.service.Serializer;
93import org.onosproject.store.service.StorageService;
alshabib36a4d732016-06-01 16:03:59 -070094import org.opencord.olt.AccessDeviceEvent;
95import org.opencord.olt.AccessDeviceListener;
96import org.opencord.olt.AccessDeviceService;
Amit Ghosh31939522018-08-16 13:28:21 +010097import org.opencord.olt.AccessSubscriberId;
Gamze Abaka641fc072018-09-04 09:16:27 +000098import org.opencord.sadis.BandwidthProfileInformation;
99import org.opencord.sadis.BaseInformationService;
100import org.opencord.sadis.SadisService;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100101import org.opencord.sadis.SubscriberAndDeviceInformation;
alshabibe0559672016-02-21 14:49:51 -0800102import org.osgi.service.component.ComponentContext;
alshabibf0e7e702015-05-30 18:22:36 -0700103import org.slf4j.Logger;
104
Saurav Das82b8e6d2018-10-04 15:25:12 -0700105import com.google.common.collect.ImmutableMap;
106import com.google.common.collect.Maps;
alshabibf0e7e702015-05-30 18:22:36 -0700107
108/**
Jonathan Harte533a422015-10-20 17:31:24 -0700109 * Provisions rules on access devices.
alshabibf0e7e702015-05-30 18:22:36 -0700110 */
Jonathan Harte533a422015-10-20 17:31:24 -0700111@Service
alshabibf0e7e702015-05-30 18:22:36 -0700112@Component(immediate = true)
alshabib8e4fd2f2016-01-12 15:55:53 -0800113public class Olt
114 extends AbstractListenerManager<AccessDeviceEvent, AccessDeviceListener>
115 implements AccessDeviceService {
Charles Chan54f110f2017-01-20 11:22:42 -0800116 private static final String APP_NAME = "org.opencord.olt";
alshabibe0559672016-02-21 14:49:51 -0800117
118 private static final short DEFAULT_VLAN = 0;
Gamze Abaka1efc80c2019-02-15 12:10:54 +0000119 private static final int DEFAULT_TP_ID = 64;
Gamze Abakaad329652018-12-20 10:12:21 +0000120 private static final String DEFAULT_BP_ID = "Default";
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100121 private static final String ADDITIONAL_VLANS = "additional-vlans";
Gamze Abaka838d8142019-02-21 07:06:55 +0000122 private static final String NO_UPLINK_PORT = "No uplink port found for OLT device {}";
123 private static final String INSTALLED = "installed";
124 private static final String REMOVED = "removed";
125 private static final String INSTALLATION = "installation";
126 private static final String REMOVAL = "removal";
alshabibe0559672016-02-21 14:49:51 -0800127
alshabibf0e7e702015-05-30 18:22:36 -0700128 private final Logger log = getLogger(getClass());
129
130 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
131 protected FlowObjectiveService flowObjectiveService;
132
133 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabib09753b52016-03-04 14:55:19 -0800134 protected MastershipService mastershipService;
135
136 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibf0e7e702015-05-30 18:22:36 -0700137 protected DeviceService deviceService;
138
139 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
140 protected CoreService coreService;
141
Jonathan Harte533a422015-10-20 17:31:24 -0700142 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibe0559672016-02-21 14:49:51 -0800143 protected ComponentConfigService componentConfigService;
144
alshabib4ceaed32016-03-03 18:00:58 -0800145 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Gamze Abaka641fc072018-09-04 09:16:27 +0000146 protected SadisService sadisService;
147
148 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
149 protected MeterService meterService;
alshabibe0559672016-02-21 14:49:51 -0800150
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100151 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
152 protected StorageService storageService;
153
alshabibe0559672016-02-21 14:49:51 -0800154 @Property(name = "defaultVlan", intValue = DEFAULT_VLAN,
155 label = "Default VLAN RG<->ONU traffic")
156 private int defaultVlan = DEFAULT_VLAN;
157
Matt Jeanneret3f579262018-06-14 17:16:23 -0400158 @Property(name = "enableDhcpOnProvisioning", boolValue = true,
159 label = "Create the DHCP Flow rules when a subscriber is provisioned")
160 protected boolean enableDhcpOnProvisioning = false;
161
Matteo Scandolo63460d12018-11-02 16:19:04 -0700162 @Property(name = "enableDhcpV4", boolValue = true,
163 label = "Enable flows for DHCP v4")
164 protected boolean enableDhcpV4 = true;
165
166 @Property(name = "enableDhcpV6", boolValue = true,
167 label = "Enable flows for DHCP v6")
168 protected boolean enableDhcpV6 = false;
169
Matt Jeanneret3f579262018-06-14 17:16:23 -0400170 @Property(name = "enableIgmpOnProvisioning", boolValue = false,
171 label = "Create IGMP Flow rules when a subscriber is provisioned")
172 protected boolean enableIgmpOnProvisioning = false;
Amit Ghosh95e2f652017-08-23 12:49:46 +0100173
Gamze Abaka1efc80c2019-02-15 12:10:54 +0000174 @Property(name = "deleteMeters", boolValue = true,
Gamze Abaka641fc072018-09-04 09:16:27 +0000175 label = "Deleting Meters based on flow count statistics")
Gamze Abaka1efc80c2019-02-15 12:10:54 +0000176 protected boolean deleteMeters = true;
Gamze Abaka641fc072018-09-04 09:16:27 +0000177
Gamze Abakaad329652018-12-20 10:12:21 +0000178 @Property(name = "defaultTechProfileId", intValue = DEFAULT_TP_ID,
179 label = "Default technology profile id that is used for authentication trap flows")
180 protected int defaultTechProfileId = DEFAULT_TP_ID;
181
182 @Property(name = "defaultBpId", value = DEFAULT_BP_ID,
183 label = "Default bandwidth profile id that is used for authentication trap flows")
184 protected String defaultBpId = DEFAULT_BP_ID;
185
alshabibf0e7e702015-05-30 18:22:36 -0700186 private final DeviceListener deviceListener = new InternalDeviceListener();
Gamze Abaka641fc072018-09-04 09:16:27 +0000187 private final MeterListener meterListener = new InternalMeterListener();
alshabibf0e7e702015-05-30 18:22:36 -0700188
189 private ApplicationId appId;
Gamze Abaka641fc072018-09-04 09:16:27 +0000190 protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
191 private BaseInformationService<BandwidthProfileInformation> bpService;
alshabibf0e7e702015-05-30 18:22:36 -0700192
Gamze Abaka641fc072018-09-04 09:16:27 +0000193 private Map<String, MeterId> bpInfoToMeter = new HashMap<>();
194
195 private ExecutorService oltInstallers = Executors.newFixedThreadPool(4,
196 groupedThreads("onos/olt-service",
197 "olt-installer-%d"));
alshabibf0e7e702015-05-30 18:22:36 -0700198
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100199 private ConsistentMultimap<ConnectPoint, Map.Entry<VlanId, VlanId>> additionalVlans;
200
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700201 protected ExecutorService eventExecutor;
202
Saurav Das82b8e6d2018-10-04 15:25:12 -0700203 private Map<ConnectPoint, SubscriberAndDeviceInformation> programmedSubs;
Gamze Abaka838d8142019-02-21 07:06:55 +0000204 private List<MeterId> programmedMeters;
Saurav Das82b8e6d2018-10-04 15:25:12 -0700205
alshabibf0e7e702015-05-30 18:22:36 -0700206 @Activate
alshabibe0559672016-02-21 14:49:51 -0800207 public void activate(ComponentContext context) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700208 eventExecutor = newSingleThreadScheduledExecutor(groupedThreads("onos/olt", "events-%d", log));
alshabibe0559672016-02-21 14:49:51 -0800209 modified(context);
Charles Chan54f110f2017-01-20 11:22:42 -0800210 appId = coreService.registerApplication(APP_NAME);
Saurav Das62ad75e2019-03-05 12:22:22 -0800211
212 // ensure that flow rules are purged from flow-store upon olt-disconnection
213 // when olt reconnects, the port-numbers may change for the ONUs
214 // making flows pushed earlier invalid
215 componentConfigService
216 .preSetProperty("org.onosproject.net.flow.impl.FlowRuleManager",
217 "purgeOnDisconnection", "true");
alshabibe0559672016-02-21 14:49:51 -0800218 componentConfigService.registerProperties(getClass());
Saurav Das82b8e6d2018-10-04 15:25:12 -0700219 programmedSubs = Maps.newConcurrentMap();
Saurav Das62ad75e2019-03-05 12:22:22 -0800220 programmedMeters = new CopyOnWriteArrayList<>();
alshabibc4dfe852015-06-05 13:35:13 -0700221
alshabib8e4fd2f2016-01-12 15:55:53 -0800222 eventDispatcher.addSink(AccessDeviceEvent.class, listenerRegistry);
223
Gamze Abaka641fc072018-09-04 09:16:27 +0000224 subsService = sadisService.getSubscriberInfoService();
225 bpService = sadisService.getBandwidthProfileService();
226
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100227 // look for all provisioned devices in Sadis and create EAPOL flows for the
228 // UNI ports
229 Iterable<Device> devices = deviceService.getDevices();
230 for (Device d : devices) {
Jonathan Hart403372d2018-08-22 11:44:13 -0700231 checkAndCreateDeviceFlows(d);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100232 }
alshabib4ceaed32016-03-03 18:00:58 -0800233
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100234 additionalVlans = storageService.<ConnectPoint, Map.Entry<VlanId, VlanId>>consistentMultimapBuilder()
235 .withName(ADDITIONAL_VLANS)
236 .withSerializer(Serializer.using(Arrays.asList(KryoNamespaces.API),
237 AbstractMap.SimpleEntry.class))
238 .build();
239
alshabibba357492016-01-27 13:49:46 -0800240 deviceService.addListener(deviceListener);
Gamze Abaka641fc072018-09-04 09:16:27 +0000241 meterService.addListener(meterListener);
alshabibba357492016-01-27 13:49:46 -0800242
alshabibf0e7e702015-05-30 18:22:36 -0700243 log.info("Started with Application ID {}", appId.id());
244 }
245
246 @Deactivate
247 public void deactivate() {
alshabibe0559672016-02-21 14:49:51 -0800248 componentConfigService.unregisterProperties(getClass(), false);
alshabib62e9ce72016-02-11 17:31:36 -0800249 deviceService.removeListener(deviceListener);
Gamze Abaka641fc072018-09-04 09:16:27 +0000250 meterService.removeListener(meterListener);
Jonathan Hart5f1c8142018-07-24 17:31:59 -0700251 eventDispatcher.removeSink(AccessDeviceEvent.class);
alshabibf0e7e702015-05-30 18:22:36 -0700252 log.info("Stopped");
253 }
254
alshabibe0559672016-02-21 14:49:51 -0800255 @Modified
256 public void modified(ComponentContext context) {
257 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
258
259 try {
260 String s = get(properties, "defaultVlan");
261 defaultVlan = isNullOrEmpty(s) ? DEFAULT_VLAN : Integer.parseInt(s.trim());
Amit Ghosh95e2f652017-08-23 12:49:46 +0100262
Matt Jeanneret3f579262018-06-14 17:16:23 -0400263 Boolean o = Tools.isPropertyEnabled(properties, "enableDhcpOnProvisioning");
Amit Ghosh95e2f652017-08-23 12:49:46 +0100264 if (o != null) {
Matt Jeanneret3f579262018-06-14 17:16:23 -0400265 enableDhcpOnProvisioning = o;
Amit Ghosh95e2f652017-08-23 12:49:46 +0100266 }
Matt Jeanneret3f579262018-06-14 17:16:23 -0400267
Matteo Scandolo63460d12018-11-02 16:19:04 -0700268 Boolean v4 = Tools.isPropertyEnabled(properties, "enableDhcpV4");
269 if (v4 != null) {
270 enableDhcpV4 = v4;
271 }
272
273 Boolean v6 = Tools.isPropertyEnabled(properties, "enableDhcpV6");
274 if (v6 != null) {
275 enableDhcpV6 = v6;
276 }
277
Matt Jeanneret3f579262018-06-14 17:16:23 -0400278 Boolean p = Tools.isPropertyEnabled(properties, "enableIgmpOnProvisioning");
279 if (p != null) {
280 enableIgmpOnProvisioning = p;
281 }
282
Matteo Scandolo63460d12018-11-02 16:19:04 -0700283 log.info("DHCP Settings [enableDhcpOnProvisioning: {}, enableDhcpV4: {}, enableDhcpV6: {}]",
Gamze Abakaad329652018-12-20 10:12:21 +0000284 enableDhcpOnProvisioning, enableDhcpV4, enableDhcpV6);
Matteo Scandolo63460d12018-11-02 16:19:04 -0700285
Gamze Abaka641fc072018-09-04 09:16:27 +0000286 Boolean d = Tools.isPropertyEnabled(properties, "deleteMeters");
287 if (d != null) {
288 deleteMeters = d;
289 }
290
Gamze Abakaad329652018-12-20 10:12:21 +0000291 String tpId = get(properties, "defaultTechProfileId");
292 defaultTechProfileId = isNullOrEmpty(s) ? DEFAULT_TP_ID : Integer.parseInt(tpId.trim());
293
294 String bpId = get(properties, "defaultBpId");
295 defaultBpId = bpId;
296
alshabibe0559672016-02-21 14:49:51 -0800297 } catch (Exception e) {
298 defaultVlan = DEFAULT_VLAN;
299 }
300 }
301
alshabib32232c82016-02-25 17:57:24 -0500302 @Override
Gamze Abaka838d8142019-02-21 07:06:55 +0000303 public boolean provisionSubscriber(ConnectPoint connectPoint) {
304
305 DeviceId deviceId = connectPoint.deviceId();
306 PortNumber subscriberPortNo = connectPoint.port();
307
308 checkNotNull(deviceService.getPort(deviceId, subscriberPortNo),
Jonathan Hart94b90492018-04-24 14:02:25 -0700309 "Invalid connect point");
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100310 // Find the subscriber on this connect point
Gamze Abaka838d8142019-02-21 07:06:55 +0000311 SubscriberAndDeviceInformation sub = getSubscriber(connectPoint);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100312 if (sub == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000313 log.warn("No subscriber found for {}", connectPoint);
Amit Ghosh31939522018-08-16 13:28:21 +0100314 return false;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100315 }
Jonathan Harte533a422015-10-20 17:31:24 -0700316
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100317 // Get the uplink port
Gamze Abaka838d8142019-02-21 07:06:55 +0000318 Port uplinkPort = getUplinkPort(deviceService.getDevice(deviceId));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100319 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000320 log.warn(NO_UPLINK_PORT, deviceId);
Amit Ghosh31939522018-08-16 13:28:21 +0100321 return false;
Jonathan Harte533a422015-10-20 17:31:24 -0700322 }
323
Gamze Abaka838d8142019-02-21 07:06:55 +0000324 //delete Eapol authentication flow with default bandwidth
325 //re-install Eapol authentication flow with the subscribers' upstream bandwidth profile
326 processEapolFilteringObjectives(deviceId, subscriberPortNo, defaultBpId, false);
327 programmedMeters.remove(bpInfoToMeter.get(defaultBpId));
328 processEapolFilteringObjectives(deviceId, subscriberPortNo, sub.upstreamBandwidthProfile(), true);
329
Saurav Das82b8e6d2018-10-04 15:25:12 -0700330 log.info("Programming vlans for subscriber: {}", sub);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100331 Optional<VlanId> defaultVlan = Optional.empty();
Gamze Abaka838d8142019-02-21 07:06:55 +0000332 MeterId upstreamMeterId = provisionVlans(connectPoint, uplinkPort.number(), defaultVlan, sub);
333
334 if (enableDhcpOnProvisioning) {
335 processDhcpFilteringObjectives(deviceId, subscriberPortNo, upstreamMeterId,
336 sub.technologyProfileId(), true, true);
337 }
Amit Ghosh95e2f652017-08-23 12:49:46 +0100338
Matt Jeanneret3f579262018-06-14 17:16:23 -0400339 if (enableIgmpOnProvisioning) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000340 processIgmpFilteringObjectives(deviceId, subscriberPortNo, upstreamMeterId,
341 sub.technologyProfileId(), true);
Amit Ghosh95e2f652017-08-23 12:49:46 +0100342 }
Saurav Das82b8e6d2018-10-04 15:25:12 -0700343 // cache subscriber info
Gamze Abaka838d8142019-02-21 07:06:55 +0000344 programmedSubs.put(connectPoint, sub);
Amit Ghosh31939522018-08-16 13:28:21 +0100345 return true;
alshabibb7a9e172016-01-13 11:23:53 -0800346 }
347
348 @Override
Gamze Abaka838d8142019-02-21 07:06:55 +0000349 public boolean removeSubscriber(ConnectPoint connectPoint) {
Matteo Scandolo962a6ad2018-12-11 15:39:42 -0800350 // Get the subscriber connected to this port from the local cache
351 // as if we don't know about the subscriber there's no need to remove it
Gamze Abaka838d8142019-02-21 07:06:55 +0000352
353 DeviceId deviceId = connectPoint.deviceId();
354 PortNumber subscriberPortNo = connectPoint.port();
355
356 SubscriberAndDeviceInformation subscriber = programmedSubs.get(connectPoint);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100357 if (subscriber == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000358 log.warn("Subscriber on connectionPoint {} was not previously programmed, " +
359 "no need to remove it", connectPoint);
Matteo Scandolo962a6ad2018-12-11 15:39:42 -0800360 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800361 }
362
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100363 // Get the uplink port
Gamze Abaka838d8142019-02-21 07:06:55 +0000364 Port uplinkPort = getUplinkPort(deviceService.getDevice(deviceId));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100365 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000366 log.warn(NO_UPLINK_PORT, deviceId);
Amit Ghosh31939522018-08-16 13:28:21 +0100367 return false;
alshabib4ceaed32016-03-03 18:00:58 -0800368 }
369
Gamze Abaka838d8142019-02-21 07:06:55 +0000370 //delete Eapol authentication flow with the subscribers' upstream bandwidth profile
371 //re-install Eapol authentication flow with the default bandwidth profile
372 processEapolFilteringObjectives(deviceId, subscriberPortNo, subscriber.upstreamBandwidthProfile(), false);
373 processEapolFilteringObjectives(deviceId, subscriberPortNo, defaultBpId, true);
Amit Ghosh95e2f652017-08-23 12:49:46 +0100374
Saurav Das82b8e6d2018-10-04 15:25:12 -0700375 log.info("Removing programmed vlans for subscriber: {}", subscriber);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100376 Optional<VlanId> defaultVlan = Optional.empty();
Gamze Abaka838d8142019-02-21 07:06:55 +0000377 MeterId upstreamMeterId = unprovisionVlans(deviceId, uplinkPort.number(),
378 subscriberPortNo, subscriber, defaultVlan);
379
380 if (enableDhcpOnProvisioning) {
381 processDhcpFilteringObjectives(deviceId, subscriberPortNo,
382 upstreamMeterId, subscriber.technologyProfileId(), false, true);
383 }
alshabibbf23a1f2016-01-14 17:27:11 -0800384
Matt Jeanneret3f579262018-06-14 17:16:23 -0400385 if (enableIgmpOnProvisioning) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000386 processIgmpFilteringObjectives(deviceId, subscriberPortNo,
387 upstreamMeterId, subscriber.technologyProfileId(), false);
Amit Ghosh95e2f652017-08-23 12:49:46 +0100388 }
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100389
390 // Remove if there are any flows for the additional Vlans
Gamze Abaka838d8142019-02-21 07:06:55 +0000391 Collection<? extends Map.Entry<VlanId, VlanId>> vlansList = additionalVlans.get(connectPoint).value();
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100392
393 // Remove the flows for the additional vlans for this subscriber
394 for (Map.Entry<VlanId, VlanId> vlans : vlansList) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000395 unprovisionTransparentFlows(deviceId, uplinkPort.number(), subscriberPortNo,
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100396 vlans.getValue(), vlans.getKey());
397
398 // Remove it from the map also
Gamze Abaka838d8142019-02-21 07:06:55 +0000399 additionalVlans.remove(connectPoint, vlans);
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100400 }
401
Gamze Abaka838d8142019-02-21 07:06:55 +0000402 programmedSubs.remove(connectPoint);
Amit Ghosh31939522018-08-16 13:28:21 +0100403 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800404 }
405
Amit Ghosh31939522018-08-16 13:28:21 +0100406 @Override
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100407 public boolean provisionSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag, Optional<VlanId> cTag) {
Amit Ghosh31939522018-08-16 13:28:21 +0100408 // Check if we can find the connect point to which this subscriber is connected
409 ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
410 if (subsPort == null) {
411 log.warn("ConnectPoint for {} not found", subscriberId);
412 return false;
413 }
414
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100415 if (!sTag.isPresent() && !cTag.isPresent()) {
416 return provisionSubscriber(subsPort);
417 } else if (sTag.isPresent() && cTag.isPresent()) {
418 Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
419 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000420 log.warn(NO_UPLINK_PORT, subsPort.deviceId());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100421 return false;
422 }
423
424 provisionTransparentFlows(subsPort.deviceId(), uplinkPort.number(), subsPort.port(),
425 cTag.get(), sTag.get());
426 return true;
427 } else {
428 log.warn("Provisioning failed for subscriber: {}", subscriberId);
429 return false;
430 }
Amit Ghosh31939522018-08-16 13:28:21 +0100431 }
Amit Ghosh95e2f652017-08-23 12:49:46 +0100432
alshabibe0559672016-02-21 14:49:51 -0800433 @Override
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100434 public boolean removeSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag, Optional<VlanId> cTag) {
Amit Ghosh31939522018-08-16 13:28:21 +0100435 // Check if we can find the connect point to which this subscriber is connected
436 ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
437 if (subsPort == null) {
438 log.warn("ConnectPoint for {} not found", subscriberId);
439 return false;
440 }
441
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100442 if (!sTag.isPresent() && !cTag.isPresent()) {
443 return removeSubscriber(subsPort);
444 } else if (sTag.isPresent() && cTag.isPresent()) {
445 // Get the uplink port
446 Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
447 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000448 log.warn(NO_UPLINK_PORT, subsPort.deviceId());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100449 return false;
450 }
451
452 unprovisionTransparentFlows(subsPort.deviceId(), uplinkPort.number(), subsPort.port(),
453 cTag.get(), sTag.get());
454 return true;
455 } else {
456 log.warn("Removing subscriber failed for: {}", subscriberId);
457 return false;
458 }
Amit Ghosh31939522018-08-16 13:28:21 +0100459 }
460
461 @Override
462 public Collection<Map.Entry<ConnectPoint, Map.Entry<VlanId, VlanId>>> getSubscribers() {
463 ArrayList<Map.Entry<ConnectPoint, Map.Entry<VlanId, VlanId>>> subs = new ArrayList<>();
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100464
Saurav Das82b8e6d2018-10-04 15:25:12 -0700465 // Get the subscribers for all the devices configured in sadis
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100466 // If the port is UNI, is enabled and exists in Sadis then copy it
467 for (Device d : deviceService.getDevices()) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700468 if (getOltInfo(d) == null) {
469 continue; // not an olt, or not configured in sadis
470 }
Gamze Abakaad329652018-12-20 10:12:21 +0000471 for (Port p : deviceService.getPorts(d.id())) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100472 if (isUniPort(d, p) && p.isEnabled()) {
473 ConnectPoint cp = new ConnectPoint(d.id(), p.number());
474
475 SubscriberAndDeviceInformation sub = getSubscriber(cp);
476 if (sub != null) {
Amit Ghosh31939522018-08-16 13:28:21 +0100477 Map.Entry<VlanId, VlanId> vlans = new AbstractMap.SimpleEntry(sub.sTag(), sub.cTag());
478 subs.add(new AbstractMap.SimpleEntry(cp, vlans));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100479 }
480 }
481 }
482 }
483
484 return subs;
Jonathan Hartfd6c1b32016-03-08 14:09:09 -0800485 }
486
487 @Override
Saurav Das82b8e6d2018-10-04 15:25:12 -0700488 public ImmutableMap<ConnectPoint, SubscriberAndDeviceInformation> getProgSubs() {
489 return ImmutableMap.copyOf(programmedSubs);
490 }
491
492 @Override
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100493 public List<DeviceId> fetchOlts() {
494 // look through all the devices and find the ones that are OLTs as per Sadis
495 List<DeviceId> olts = new ArrayList<>();
496 Iterable<Device> devices = deviceService.getDevices();
497 for (Device d : devices) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700498 if (getOltInfo(d) != null) {
499 // So this is indeed an OLT device
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100500 olts.add(d.id());
501 }
502 }
503 return olts;
alshabibe0559672016-02-21 14:49:51 -0800504 }
505
Amit Ghosh31939522018-08-16 13:28:21 +0100506 /**
507 * Finds the connect point to which a subscriber is connected.
508 *
509 * @param id The id of the subscriber, this is the same ID as in Sadis
510 * @return Subscribers ConnectPoint if found else null
511 */
512 private ConnectPoint findSubscriberConnectPoint(String id) {
513
514 Iterable<Device> devices = deviceService.getDevices();
515 for (Device d : devices) {
516 for (Port p : deviceService.getPorts(d.id())) {
517 log.trace("Comparing {} with {}", p.annotations().value(AnnotationKeys.PORT_NAME), id);
518 if (p.annotations().value(AnnotationKeys.PORT_NAME).equals(id)) {
519 log.debug("Found on device {} port {}", d.id(), p.number());
520 return new ConnectPoint(d.id(), p.number());
521 }
522 }
523 }
524 return null;
525 }
526
Gamze Abaka641fc072018-09-04 09:16:27 +0000527 private BandwidthProfileInformation getBandwidthProfileInformation(String bandwidthProfile) {
528 if (bandwidthProfile == null) {
529 return null;
530 }
531 return bpService.get(bandwidthProfile);
532 }
533
Gamze Abaka838d8142019-02-21 07:06:55 +0000534 /**
535 * Removes subscriber vlan flows and returns the meter id used in the upstream bandwidth profile.
536 * This meter-id is also referenced by other upstream trap flows for this subscriber.
537 *
538 * @param deviceId the device identifier
539 * @param uplink uplink port of the OLT
540 * @param subscriberPort uni port
541 * @param subscriber subscriber info that includes s, c tags, tech profile and bandwidth profile references
542 * @param defaultVlan default vlan of the subscriber
543 * @return the meter id used in the upstream bandwidth profile
544 */
545 private MeterId unprovisionVlans(DeviceId deviceId, PortNumber uplink,
546 PortNumber subscriberPort, SubscriberAndDeviceInformation subscriber,
547 Optional<VlanId> defaultVlan) {
alshabibbf23a1f2016-01-14 17:27:11 -0800548
549 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
550 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
551
Gamze Abaka641fc072018-09-04 09:16:27 +0000552 VlanId deviceVlan = subscriber.sTag();
553 VlanId subscriberVlan = subscriber.cTag();
554
555 MeterId upstreamMeterId = bpInfoToMeter.get(subscriber.upstreamBandwidthProfile());
556 MeterId downstreamMeterId = bpInfoToMeter.get(subscriber.downstreamBandwidthProfile());
557
alshabib4ceaed32016-03-03 18:00:58 -0800558 ForwardingObjective.Builder upFwd = upBuilder(uplink, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000559 subscriberVlan, deviceVlan,
560 defaultVlan, upstreamMeterId, subscriber.technologyProfileId());
alshabib4ceaed32016-03-03 18:00:58 -0800561 ForwardingObjective.Builder downFwd = downBuilder(uplink, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000562 subscriberVlan, deviceVlan,
563 defaultVlan, downstreamMeterId, subscriber.technologyProfileId());
alshabibbf23a1f2016-01-14 17:27:11 -0800564
alshabib4ceaed32016-03-03 18:00:58 -0800565 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
566 @Override
567 public void onSuccess(Objective objective) {
568 upFuture.complete(null);
569 }
alshabibbf23a1f2016-01-14 17:27:11 -0800570
alshabib4ceaed32016-03-03 18:00:58 -0800571 @Override
572 public void onError(Objective objective, ObjectiveError error) {
573 upFuture.complete(error);
574 }
575 }));
576
577 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
578 @Override
579 public void onSuccess(Objective objective) {
580 downFuture.complete(null);
581 }
582
583 @Override
584 public void onError(Objective objective, ObjectiveError error) {
585 downFuture.complete(error);
586 }
587 }));
alshabibbf23a1f2016-01-14 17:27:11 -0800588
589 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
590 if (upStatus == null && downStatus == null) {
591 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_UNREGISTERED,
Gamze Abaka641fc072018-09-04 09:16:27 +0000592 deviceId,
593 deviceVlan,
594 subscriberVlan));
alshabibbf23a1f2016-01-14 17:27:11 -0800595 } else if (downStatus != null) {
596 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000597 "on port {} failed downstream uninstallation: {}",
598 subscriberVlan, deviceId, subscriberPort, downStatus);
alshabibbf23a1f2016-01-14 17:27:11 -0800599 } else if (upStatus != null) {
600 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000601 "on port {} failed upstream uninstallation: {}",
602 subscriberVlan, deviceId, subscriberPort, upStatus);
alshabibbf23a1f2016-01-14 17:27:11 -0800603 }
604 }, oltInstallers);
alshabibb7a9e172016-01-13 11:23:53 -0800605
Gamze Abaka838d8142019-02-21 07:06:55 +0000606 programmedMeters.remove(upstreamMeterId);
607 programmedMeters.remove(downstreamMeterId);
608 log.debug("programmed Meters size {}", programmedMeters.size());
609 return upstreamMeterId;
Jonathan Harte533a422015-10-20 17:31:24 -0700610 }
611
Gamze Abaka838d8142019-02-21 07:06:55 +0000612 /**
613 * Adds subscriber vlan flows and returns the meter id used in the upstream bandwidth profile.
614 * This meter-id will also be referenced by other upstream trap flows for this subscriber
615 *
616 * @param port the connection point of the subscriber
617 * @param uplinkPort uplink port of the OLT
618 * @param defaultVlan default vlan of the subscriber
619 * @param sub subscriber information that includes s, c tags, tech profile and bandwidth profile references
620 * @return the meter id used in the upstream bandwidth profile
621 */
622 private MeterId provisionVlans(ConnectPoint port, PortNumber uplinkPort, Optional<VlanId> defaultVlan,
623 SubscriberAndDeviceInformation sub) {
Gamze Abaka641fc072018-09-04 09:16:27 +0000624
625 log.info("Provisioning vlans...");
626
627 DeviceId deviceId = port.deviceId();
628 PortNumber subscriberPort = port.port();
629 VlanId deviceVlan = sub.sTag();
630 VlanId subscriberVlan = sub.cTag();
631 int techProfId = sub.technologyProfileId();
632
633 BandwidthProfileInformation upstreamBpInfo = getBandwidthProfileInformation(sub.upstreamBandwidthProfile());
634 BandwidthProfileInformation downstreamBpInfo = getBandwidthProfileInformation(sub.downstreamBandwidthProfile());
635
Gamze Abaka838d8142019-02-21 07:06:55 +0000636 MeterId upstreamMeterId = createMeter(deviceId, upstreamBpInfo);
Gamze Abaka641fc072018-09-04 09:16:27 +0000637 MeterId downstreamMeterId = createMeter(deviceId, downstreamBpInfo);
Jonathan Harte533a422015-10-20 17:31:24 -0700638
alshabib3ea82642016-01-12 18:06:53 -0800639 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
640 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
641
alshabib4ceaed32016-03-03 18:00:58 -0800642 ForwardingObjective.Builder upFwd = upBuilder(uplinkPort, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000643 subscriberVlan, deviceVlan,
Gamze Abaka838d8142019-02-21 07:06:55 +0000644 defaultVlan, upstreamMeterId, techProfId);
Jonathan Harte533a422015-10-20 17:31:24 -0700645
alshabib4ceaed32016-03-03 18:00:58 -0800646 ForwardingObjective.Builder downFwd = downBuilder(uplinkPort, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000647 subscriberVlan, deviceVlan,
648 defaultVlan, downstreamMeterId, techProfId);
alshabib3ea82642016-01-12 18:06:53 -0800649
alshabibbf23a1f2016-01-14 17:27:11 -0800650 flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
651 @Override
652 public void onSuccess(Objective objective) {
653 upFuture.complete(null);
654 }
655
656 @Override
657 public void onError(Objective objective, ObjectiveError error) {
658 upFuture.complete(error);
659 }
660 }));
661
alshabibbf23a1f2016-01-14 17:27:11 -0800662 flowObjectiveService.forward(deviceId, downFwd.add(new ObjectiveContext() {
663 @Override
664 public void onSuccess(Objective objective) {
665 downFuture.complete(null);
666 }
667
668 @Override
669 public void onError(Objective objective, ObjectiveError error) {
670 downFuture.complete(error);
671 }
672 }));
alshabib3ea82642016-01-12 18:06:53 -0800673
674 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
675 if (upStatus == null && downStatus == null) {
676 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_REGISTERED,
Gamze Abaka641fc072018-09-04 09:16:27 +0000677 deviceId,
678 deviceVlan,
679 subscriberVlan));
alshabib50d9fc52016-02-12 15:47:20 -0800680
alshabib3ea82642016-01-12 18:06:53 -0800681 } else if (downStatus != null) {
682 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000683 "on port {} failed downstream installation: {}",
684 subscriberVlan, deviceId, subscriberPort, downStatus);
alshabib3ea82642016-01-12 18:06:53 -0800685 } else if (upStatus != null) {
686 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000687 "on port {} failed upstream installation: {}",
688 subscriberVlan, deviceId, subscriberPort, upStatus);
alshabib3ea82642016-01-12 18:06:53 -0800689 }
690 }, oltInstallers);
691
Gamze Abaka838d8142019-02-21 07:06:55 +0000692 return upstreamMeterId;
Jonathan Harte533a422015-10-20 17:31:24 -0700693 }
694
Gamze Abaka641fc072018-09-04 09:16:27 +0000695 private MeterId createMeter(DeviceId deviceId, BandwidthProfileInformation bpInfo) {
696
697 if (bpInfo == null) {
698 log.warn("Bandwidth profile information is not found");
699 return null;
700 }
701
702 MeterId meterId = bpInfoToMeter.get(bpInfo.id());
703 if (meterId != null) {
704 log.info("Meter is already added. MeterId {}", meterId);
705 return meterId;
706 }
707
708 List<Band> meterBands = createMeterBands(bpInfo);
709
710 MeterRequest meterRequest = DefaultMeterRequest.builder()
711 .withBands(meterBands)
712 .withUnit(Meter.Unit.KB_PER_SEC)
713 .forDevice(deviceId)
714 .fromApp(appId)
715 .burst()
716 .add();
717
718 Meter meter = meterService.submit(meterRequest);
719 bpInfoToMeter.put(bpInfo.id(), meter.id());
720 log.info("Meter is created. Meter Id {}", meter.id());
Gamze Abaka838d8142019-02-21 07:06:55 +0000721 programmedMeters.add(meter.id());
722 log.debug("programmed Meters size {}", programmedMeters.size());
Gamze Abaka641fc072018-09-04 09:16:27 +0000723 return meter.id();
724 }
725
726 private List<Band> createMeterBands(BandwidthProfileInformation bpInfo) {
727 List<Band> meterBands = new ArrayList<>();
728
729 meterBands.add(createMeterBand(bpInfo.committedInformationRate(), bpInfo.committedBurstSize()));
730 meterBands.add(createMeterBand(bpInfo.exceededInformationRate(), bpInfo.exceededBurstSize()));
Gamze Abakaad329652018-12-20 10:12:21 +0000731 meterBands.add(createMeterBand(bpInfo.assuredInformationRate(), 0L));
Gamze Abaka641fc072018-09-04 09:16:27 +0000732
Gamze Abaka641fc072018-09-04 09:16:27 +0000733 return meterBands;
734 }
735
736 private Band createMeterBand(long rate, Long burst) {
737 return DefaultBand.builder()
738 .withRate(rate) //already Kbps
739 .burstSize(burst) // already Kbits
740 .ofType(Band.Type.DROP) // no matter
741 .build();
742 }
743
alshabib4ceaed32016-03-03 18:00:58 -0800744 private ForwardingObjective.Builder downBuilder(PortNumber uplinkPort,
745 PortNumber subscriberPort,
746 VlanId subscriberVlan,
747 VlanId deviceVlan,
Gamze Abaka641fc072018-09-04 09:16:27 +0000748 Optional<VlanId> defaultVlan,
749 MeterId meterId,
750 int techProfId) {
alshabib4ceaed32016-03-03 18:00:58 -0800751 TrafficSelector downstream = DefaultTrafficSelector.builder()
752 .matchVlanId(deviceVlan)
753 .matchInPort(uplinkPort)
754 .matchInnerVlanId(subscriberVlan)
755 .build();
756
Gamze Abaka641fc072018-09-04 09:16:27 +0000757 TrafficTreatment.Builder downstreamTreatmentBuilder = DefaultTrafficTreatment.builder()
alshabib4ceaed32016-03-03 18:00:58 -0800758 .popVlan()
759 .setVlanId(defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan)))
Gamze Abaka641fc072018-09-04 09:16:27 +0000760 .setOutput(subscriberPort);
761
762 if (meterId != null) {
763 downstreamTreatmentBuilder.meter(meterId);
764 }
765
Gamze Abakaad329652018-12-20 10:12:21 +0000766 downstreamTreatmentBuilder.writeMetadata(createMetadata(subscriberVlan, techProfId, subscriberPort), 0);
alshabib4ceaed32016-03-03 18:00:58 -0800767
768 return DefaultForwardingObjective.builder()
769 .withFlag(ForwardingObjective.Flag.VERSATILE)
770 .withPriority(1000)
771 .makePermanent()
772 .withSelector(downstream)
773 .fromApp(appId)
Gamze Abaka641fc072018-09-04 09:16:27 +0000774 .withTreatment(downstreamTreatmentBuilder.build());
alshabib4ceaed32016-03-03 18:00:58 -0800775 }
776
777 private ForwardingObjective.Builder upBuilder(PortNumber uplinkPort,
778 PortNumber subscriberPort,
779 VlanId subscriberVlan,
780 VlanId deviceVlan,
Gamze Abaka641fc072018-09-04 09:16:27 +0000781 Optional<VlanId> defaultVlan,
782 MeterId meterId,
783 int technologyProfileId) {
784
785
786 VlanId dVlan = defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan));
787
788 if (subscriberVlan.toShort() == 4096) {
789 dVlan = subscriberVlan;
790 }
791
alshabib4ceaed32016-03-03 18:00:58 -0800792 TrafficSelector upstream = DefaultTrafficSelector.builder()
Gamze Abaka641fc072018-09-04 09:16:27 +0000793 .matchVlanId(dVlan)
alshabib4ceaed32016-03-03 18:00:58 -0800794 .matchInPort(subscriberPort)
795 .build();
796
797
Gamze Abaka641fc072018-09-04 09:16:27 +0000798 TrafficTreatment.Builder upstreamTreatmentBuilder = DefaultTrafficTreatment.builder()
alshabib4ceaed32016-03-03 18:00:58 -0800799 .pushVlan()
800 .setVlanId(subscriberVlan)
801 .pushVlan()
802 .setVlanId(deviceVlan)
Gamze Abaka641fc072018-09-04 09:16:27 +0000803 .setOutput(uplinkPort);
804
805 if (meterId != null) {
806 upstreamTreatmentBuilder.meter(meterId);
807 }
808
Gamze Abakaad329652018-12-20 10:12:21 +0000809 upstreamTreatmentBuilder.writeMetadata(createMetadata(deviceVlan, technologyProfileId, uplinkPort), 0L);
alshabib4ceaed32016-03-03 18:00:58 -0800810
811 return DefaultForwardingObjective.builder()
812 .withFlag(ForwardingObjective.Flag.VERSATILE)
813 .withPriority(1000)
814 .makePermanent()
815 .withSelector(upstream)
816 .fromApp(appId)
Gamze Abaka641fc072018-09-04 09:16:27 +0000817 .withTreatment(upstreamTreatmentBuilder.build());
alshabib4ceaed32016-03-03 18:00:58 -0800818 }
Gamze Abakaad329652018-12-20 10:12:21 +0000819
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100820 private void provisionTransparentFlows(DeviceId deviceId, PortNumber uplinkPort,
821 PortNumber subscriberPort,
822 VlanId innerVlan,
823 VlanId outerVlan) {
824
825 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
826 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
827
828 ForwardingObjective.Builder upFwd = transparentUpBuilder(uplinkPort, subscriberPort,
829 innerVlan, outerVlan);
830
831
832 ForwardingObjective.Builder downFwd = transparentDownBuilder(uplinkPort, subscriberPort,
833 innerVlan, outerVlan);
834
835 ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
836
837 additionalVlans.put(cp, new AbstractMap.SimpleEntry(outerVlan, innerVlan));
838
839 flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
840 @Override
841 public void onSuccess(Objective objective) {
842 upFuture.complete(null);
843 }
844
845 @Override
846 public void onError(Objective objective, ObjectiveError error) {
847 upFuture.complete(error);
848 }
849 }));
850
851 flowObjectiveService.forward(deviceId, downFwd.add(new ObjectiveContext() {
852 @Override
853 public void onSuccess(Objective objective) {
854 downFuture.complete(null);
855 }
856
857 @Override
858 public void onError(Objective objective, ObjectiveError error) {
859 downFuture.complete(error);
860 }
861 }));
862
863 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
864 if (downStatus != null) {
865 log.error("Flow with innervlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000866 "on port {} failed downstream installation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100867 innerVlan, outerVlan, deviceId, subscriberPort, downStatus);
868 } else if (upStatus != null) {
869 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000870 "on port {} failed upstream installation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100871 innerVlan, outerVlan, deviceId, subscriberPort, upStatus);
872 }
873 }, oltInstallers);
874
875 }
876
877 private ForwardingObjective.Builder transparentDownBuilder(PortNumber uplinkPort,
878 PortNumber subscriberPort,
879 VlanId innerVlan,
880 VlanId outerVlan) {
881 TrafficSelector downstream = DefaultTrafficSelector.builder()
882 .matchVlanId(outerVlan)
883 .matchInPort(uplinkPort)
884 .matchInnerVlanId(innerVlan)
885 .build();
886
887 TrafficTreatment downstreamTreatment = DefaultTrafficTreatment.builder()
888 .setOutput(subscriberPort)
889 .build();
890
891 return DefaultForwardingObjective.builder()
892 .withFlag(ForwardingObjective.Flag.VERSATILE)
893 .withPriority(1000)
894 .makePermanent()
895 .withSelector(downstream)
896 .fromApp(appId)
897 .withTreatment(downstreamTreatment);
898 }
899
900 private ForwardingObjective.Builder transparentUpBuilder(PortNumber uplinkPort,
901 PortNumber subscriberPort,
902 VlanId innerVlan,
903 VlanId outerVlan) {
904 TrafficSelector upstream = DefaultTrafficSelector.builder()
905 .matchVlanId(outerVlan)
906 .matchInPort(subscriberPort)
907 .matchInnerVlanId(innerVlan)
908 .build();
909
910 TrafficTreatment upstreamTreatment = DefaultTrafficTreatment.builder()
911 .setOutput(uplinkPort)
912 .build();
913
914 return DefaultForwardingObjective.builder()
915 .withFlag(ForwardingObjective.Flag.VERSATILE)
916 .withPriority(1000)
917 .makePermanent()
918 .withSelector(upstream)
919 .fromApp(appId)
920 .withTreatment(upstreamTreatment);
921 }
922
923 private void unprovisionTransparentFlows(DeviceId deviceId, PortNumber uplink,
924 PortNumber subscriberPort, VlanId innerVlan,
925 VlanId outerVlan) {
926
927 ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
928
929 additionalVlans.remove(cp, new AbstractMap.SimpleEntry(outerVlan, innerVlan));
930
931 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
932 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
933
934 ForwardingObjective.Builder upFwd = transparentUpBuilder(uplink, subscriberPort,
935 innerVlan, outerVlan);
936 ForwardingObjective.Builder downFwd = transparentDownBuilder(uplink, subscriberPort,
937 innerVlan, outerVlan);
938
939
940 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
941 @Override
942 public void onSuccess(Objective objective) {
943 upFuture.complete(null);
944 }
945
946 @Override
947 public void onError(Objective objective, ObjectiveError error) {
948 upFuture.complete(error);
949 }
950 }));
951
952 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
953 @Override
954 public void onSuccess(Objective objective) {
955 downFuture.complete(null);
956 }
957
958 @Override
959 public void onError(Objective objective, ObjectiveError error) {
960 downFuture.complete(error);
961 }
962 }));
963
964 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
965 if (downStatus != null) {
966 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000967 "on port {} failed downstream uninstallation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100968 innerVlan, outerVlan, deviceId, subscriberPort, downStatus);
969 } else if (upStatus != null) {
970 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000971 "on port {} failed upstream uninstallation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100972 innerVlan, outerVlan, deviceId, subscriberPort, upStatus);
973 }
974 }, oltInstallers);
975
976 }
977
Gamze Abaka1efc80c2019-02-15 12:10:54 +0000978 private int getDefaultTechProfileId(DeviceId devId, PortNumber portNumber) {
979 Port port = deviceService.getPort(devId, portNumber);
980 SubscriberAndDeviceInformation info = subsService.get(port.annotations().value(AnnotationKeys.PORT_NAME));
981 if (info != null && info.technologyProfileId() != -1) {
982 return info.technologyProfileId();
983 }
984 return defaultTechProfileId;
985 }
986
Gamze Abaka838d8142019-02-21 07:06:55 +0000987 /**
988 * Returns the write metadata value including only tech profile reference.
989 *
990 * @param techProfileId tech profile id of one subscriber
991 * @return the write metadata value including only tech profile reference
992 */
993 private Long createTechProfValueForWm(int techProfileId) {
994 return (long) techProfileId << 32;
995 }
996
997 /**
998 * Trap eapol authentication packets to the controller.
999 *
1000 * @param devId the device identifier
1001 * @param portNumber the port for which this trap flow is designated
1002 * @param bpId bandwidth profile id to add the related meter to the flow
1003 * @param install true to install the flow, false to remove the flow
1004 */
1005 private void processEapolFilteringObjectives(DeviceId devId, PortNumber portNumber, String bpId, boolean install) {
alshabib09753b52016-03-04 14:55:19 -08001006 if (!mastershipService.isLocalMaster(devId)) {
1007 return;
1008 }
alshabibbb83aa22016-02-10 15:08:23 -08001009 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Gamze Abakaad329652018-12-20 10:12:21 +00001010 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
Gamze Abaka838d8142019-02-21 07:06:55 +00001011 MeterId meterId;
alshabibbb83aa22016-02-10 15:08:23 -08001012
Gamze Abaka838d8142019-02-21 07:06:55 +00001013 BandwidthProfileInformation bpInfo = getBandwidthProfileInformation(bpId);
1014 if (bpInfo != null) {
1015 meterId = createMeter(devId, bpInfo);
Gamze Abakaad329652018-12-20 10:12:21 +00001016 treatmentBuilder.meter(meterId);
1017 } else {
Gamze Abaka838d8142019-02-21 07:06:55 +00001018 log.warn("Bandwidth profile {} is not found. Authentication flow will not be installed", bpId);
1019 return;
Gamze Abakaad329652018-12-20 10:12:21 +00001020 }
1021
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001022 int techProfileId = getDefaultTechProfileId(devId, portNumber);
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001023
1024 //Authentication trap flow uses only tech profile id as write metadata value
alshabibbb83aa22016-02-10 15:08:23 -08001025 FilteringObjective eapol = (install ? builder.permit() : builder.deny())
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001026 .withKey(Criteria.matchInPort(portNumber))
alshabibdec2e252016-01-15 12:20:25 -08001027 .addCondition(Criteria.matchEthType(EthType.EtherType.EAPOL.ethType()))
Gamze Abakaad329652018-12-20 10:12:21 +00001028 .withMeta(treatmentBuilder
Gamze Abaka838d8142019-02-21 07:06:55 +00001029 .writeMetadata(createTechProfValueForWm(techProfileId), 0)
Gamze Abaka641fc072018-09-04 09:16:27 +00001030 .setOutput(PortNumber.CONTROLLER).build())
alshabibdec2e252016-01-15 12:20:25 -08001031 .fromApp(appId)
Matt Jeanneret3f579262018-06-14 17:16:23 -04001032 .withPriority(10000)
alshabibdec2e252016-01-15 12:20:25 -08001033 .add(new ObjectiveContext() {
1034 @Override
1035 public void onSuccess(Objective objective) {
Gamze Abaka838d8142019-02-21 07:06:55 +00001036 log.info("Eapol filter for {} on {} {} with meter {}.",
1037 devId, portNumber, (install) ? INSTALLED : REMOVED, meterId);
alshabibdec2e252016-01-15 12:20:25 -08001038 }
1039
1040 @Override
1041 public void onError(Objective objective, ObjectiveError error) {
Gamze Abaka838d8142019-02-21 07:06:55 +00001042 log.info("Eapol filter for {} on {} with meter {} failed {} because {}",
1043 devId, portNumber, meterId, (install) ? INSTALLATION : REMOVAL,
Gamze Abaka641fc072018-09-04 09:16:27 +00001044 error);
alshabibdec2e252016-01-15 12:20:25 -08001045 }
1046 });
1047
alshabibdec2e252016-01-15 12:20:25 -08001048 flowObjectiveService.filter(devId, eapol);
alshabib000b6fc2016-02-01 17:25:00 -08001049
alshabibdec2e252016-01-15 12:20:25 -08001050 }
1051
Jonathan Hart403372d2018-08-22 11:44:13 -07001052 /**
1053 * Installs trap filtering objectives for particular traffic types on an
1054 * NNI port.
1055 *
Gamze Abakaad329652018-12-20 10:12:21 +00001056 * @param devId device ID
1057 * @param port port number
Jonathan Hart403372d2018-08-22 11:44:13 -07001058 * @param install true to install, false to remove
1059 */
1060 private void processNniFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
1061 processLldpFilteringObjective(devId, port, install);
Matteo Scandolo63460d12018-11-02 16:19:04 -07001062 if (enableDhcpOnProvisioning) {
Gamze Abaka838d8142019-02-21 07:06:55 +00001063 processDhcpFilteringObjectives(devId, port, null, -1, install, false);
Matteo Scandolo63460d12018-11-02 16:19:04 -07001064 }
Jonathan Hart403372d2018-08-22 11:44:13 -07001065 }
1066
1067 private void processLldpFilteringObjective(DeviceId devId, PortNumber port, boolean install) {
1068 if (!mastershipService.isLocalMaster(devId)) {
1069 return;
1070 }
1071 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
1072
1073 FilteringObjective lldp = (install ? builder.permit() : builder.deny())
1074 .withKey(Criteria.matchInPort(port))
1075 .addCondition(Criteria.matchEthType(EthType.EtherType.LLDP.ethType()))
1076 .withMeta(DefaultTrafficTreatment.builder()
1077 .setOutput(PortNumber.CONTROLLER).build())
1078 .fromApp(appId)
1079 .withPriority(10000)
1080 .add(new ObjectiveContext() {
1081 @Override
1082 public void onSuccess(Objective objective) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001083 log.info("LLDP filter for device {} on port {} {}.",
Gamze Abaka838d8142019-02-21 07:06:55 +00001084 devId, port, (install) ? INSTALLED : REMOVED);
Jonathan Hart403372d2018-08-22 11:44:13 -07001085 }
1086
1087 @Override
1088 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001089 log.info("LLDP filter for device {} on port {} failed {} because {}",
Gamze Abaka838d8142019-02-21 07:06:55 +00001090 devId, port, (install) ? INSTALLATION : REMOVAL,
Saurav Das82b8e6d2018-10-04 15:25:12 -07001091 error);
Jonathan Hart403372d2018-08-22 11:44:13 -07001092 }
1093 });
1094
1095 flowObjectiveService.filter(devId, lldp);
1096
1097 }
1098
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001099 /**
1100 * Trap dhcp packets to the controller.
1101 *
Gamze Abaka838d8142019-02-21 07:06:55 +00001102 * @param devId the device identifier
1103 * @param port the port for which this trap flow is designated
1104 * @param upstreamMeterId the upstream meter id that includes the upstream
1105 * bandwidth profile values such as PIR,CIR. If no meter id needs to be referenced,
1106 * null can be sent
1107 * @param techProfileId the technology profile id that is used to create write
1108 * metadata instruction value. If no tech profile id needs to be referenced,
1109 * -1 can be sent
1110 * @param install true to install the flow, false to remove the flow
1111 * @param upstream true if trapped packets are flowing upstream towards
1112 * server, false if packets are flowing downstream towards client
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001113 */
1114 private void processDhcpFilteringObjectives(DeviceId devId, PortNumber port,
Gamze Abaka838d8142019-02-21 07:06:55 +00001115 MeterId upstreamMeterId,
1116 int techProfileId,
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001117 boolean install,
1118 boolean upstream) {
Amit Ghosh95e2f652017-08-23 12:49:46 +01001119 if (!mastershipService.isLocalMaster(devId)) {
1120 return;
1121 }
Amit Ghosh95e2f652017-08-23 12:49:46 +01001122
Matteo Scandolo63460d12018-11-02 16:19:04 -07001123 if (enableDhcpV4) {
1124 int udpSrc = (upstream) ? 68 : 67;
1125 int udpDst = (upstream) ? 67 : 68;
1126
1127 EthType ethType = EthType.EtherType.IPV4.ethType();
1128 byte protocol = IPv4.PROTOCOL_UDP;
1129
Gamze Abaka838d8142019-02-21 07:06:55 +00001130 this.addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType,
1131 upstreamMeterId, techProfileId, protocol, install);
Matteo Scandolo63460d12018-11-02 16:19:04 -07001132 }
1133
1134 if (enableDhcpV6) {
1135 int udpSrc = (upstream) ? 547 : 546;
1136 int udpDst = (upstream) ? 546 : 547;
1137
1138 EthType ethType = EthType.EtherType.IPV6.ethType();
1139 byte protocol = IPv6.PROTOCOL_UDP;
1140
Gamze Abaka838d8142019-02-21 07:06:55 +00001141 this.addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType,
1142 upstreamMeterId, techProfileId, protocol, install);
Matteo Scandolo63460d12018-11-02 16:19:04 -07001143 }
1144
1145 }
1146
1147 private void addDhcpFilteringObjectives(DeviceId devId,
1148 PortNumber port,
1149 int udpSrc,
1150 int udpDst,
1151 EthType ethType,
Gamze Abaka838d8142019-02-21 07:06:55 +00001152 MeterId upstreamMeterId,
1153 int techProfileId,
Matteo Scandolo63460d12018-11-02 16:19:04 -07001154 byte protocol,
1155 boolean install) {
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001156
1157 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Gamze Abaka838d8142019-02-21 07:06:55 +00001158 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
1159
1160 if (upstreamMeterId != null) {
1161 treatmentBuilder.meter(upstreamMeterId);
1162 }
1163
1164 if (techProfileId != -1) {
1165 treatmentBuilder.writeMetadata(createTechProfValueForWm(techProfileId), 0);
1166 }
1167
Amit Ghosh95e2f652017-08-23 12:49:46 +01001168 FilteringObjective dhcpUpstream = (install ? builder.permit() : builder.deny())
1169 .withKey(Criteria.matchInPort(port))
Matteo Scandolo63460d12018-11-02 16:19:04 -07001170 .addCondition(Criteria.matchEthType(ethType))
1171 .addCondition(Criteria.matchIPProtocol(protocol))
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001172 .addCondition(Criteria.matchUdpSrc(TpPort.tpPort(udpSrc)))
1173 .addCondition(Criteria.matchUdpDst(TpPort.tpPort(udpDst)))
Gamze Abaka838d8142019-02-21 07:06:55 +00001174 .withMeta(treatmentBuilder
Gamze Abaka641fc072018-09-04 09:16:27 +00001175 .setOutput(PortNumber.CONTROLLER).build())
Amit Ghosh95e2f652017-08-23 12:49:46 +01001176 .fromApp(appId)
Matt Jeanneret3f579262018-06-14 17:16:23 -04001177 .withPriority(10000)
Amit Ghosh95e2f652017-08-23 12:49:46 +01001178 .add(new ObjectiveContext() {
1179 @Override
1180 public void onSuccess(Objective objective) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001181 log.info("DHCP {} filter for device {} on port {} {}.",
Gamze Abakaad329652018-12-20 10:12:21 +00001182 (ethType.equals(EthType.EtherType.IPV4.ethType())) ? "v4" : "v6",
Gamze Abaka838d8142019-02-21 07:06:55 +00001183 devId, port, (install) ? INSTALLED : REMOVED);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001184 }
1185
1186 @Override
1187 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001188 log.info("DHCP {} filter for device {} on port {} failed {} because {}",
Gamze Abakaad329652018-12-20 10:12:21 +00001189 (ethType.equals(EthType.EtherType.IPV4.ethType())) ? "v4" : "v6",
Gamze Abaka838d8142019-02-21 07:06:55 +00001190 devId, port, (install) ? INSTALLATION : REMOVAL,
Gamze Abakaad329652018-12-20 10:12:21 +00001191 error);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001192 }
1193 });
1194
1195 flowObjectiveService.filter(devId, dhcpUpstream);
1196 }
1197
Gamze Abaka838d8142019-02-21 07:06:55 +00001198 private void processIgmpFilteringObjectives(DeviceId devId, PortNumber port,
1199 MeterId upstreamMeterId,
1200 int techProfileId,
1201 boolean install) {
Amit Ghosh95e2f652017-08-23 12:49:46 +01001202 if (!mastershipService.isLocalMaster(devId)) {
1203 return;
1204 }
1205
Gamze Abaka641fc072018-09-04 09:16:27 +00001206 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Gamze Abaka838d8142019-02-21 07:06:55 +00001207 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
1208
1209 if (upstreamMeterId != null) {
1210 treatmentBuilder.meter(upstreamMeterId);
1211 }
1212
1213 if (techProfileId != -1) {
1214 treatmentBuilder.writeMetadata(createTechProfValueForWm(techProfileId), 0);
1215 }
Amit Ghosh95e2f652017-08-23 12:49:46 +01001216
1217 builder = install ? builder.permit() : builder.deny();
1218
1219 FilteringObjective igmp = builder
1220 .withKey(Criteria.matchInPort(port))
1221 .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
1222 .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_IGMP))
Gamze Abaka838d8142019-02-21 07:06:55 +00001223 .withMeta(treatmentBuilder
Gamze Abaka641fc072018-09-04 09:16:27 +00001224 .setOutput(PortNumber.CONTROLLER).build())
Amit Ghosh95e2f652017-08-23 12:49:46 +01001225 .fromApp(appId)
1226 .withPriority(10000)
1227 .add(new ObjectiveContext() {
1228 @Override
1229 public void onSuccess(Objective objective) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001230 log.info("Igmp filter for {} on {} {}.",
Gamze Abaka838d8142019-02-21 07:06:55 +00001231 devId, port, (install) ? INSTALLED : REMOVED);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001232 }
1233
1234 @Override
1235 public void onError(Objective objective, ObjectiveError error) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001236 log.info("Igmp filter for {} on {} failed {} because {}.",
Gamze Abaka838d8142019-02-21 07:06:55 +00001237 devId, port, (install) ? INSTALLATION : REMOVAL,
Gamze Abaka641fc072018-09-04 09:16:27 +00001238 error);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001239 }
1240 });
1241
1242 flowObjectiveService.filter(devId, igmp);
1243 }
1244
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001245 /**
Jonathan Hart403372d2018-08-22 11:44:13 -07001246 * Creates trap flows for device, including DHCP and LLDP trap on NNI and
1247 * EAPOL trap on the UNIs, if device is present in Sadis config.
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001248 *
1249 * @param dev Device to look for
1250 */
Jonathan Hart403372d2018-08-22 11:44:13 -07001251 private void checkAndCreateDeviceFlows(Device dev) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001252 // we create only for the ones we are master of
1253 if (!mastershipService.isLocalMaster(dev.id())) {
Gamze Abaka641fc072018-09-04 09:16:27 +00001254 return;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001255 }
1256 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +00001257 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Jonathan Hart403372d2018-08-22 11:44:13 -07001258 log.debug("checkAndCreateDeviceFlows: deviceInfo {}", deviceInfo);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001259
1260 if (deviceInfo != null) {
Jonathan Hart403372d2018-08-22 11:44:13 -07001261 // This is an OLT device as per Sadis, we create flows for UNI and NNI ports
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001262 for (Port p : deviceService.getPorts(dev.id())) {
1263 if (isUniPort(dev, p)) {
Gamze Abaka838d8142019-02-21 07:06:55 +00001264 processEapolFilteringObjectives(dev.id(), p.number(), defaultBpId, true);
Jonathan Hart403372d2018-08-22 11:44:13 -07001265 } else {
1266 processNniFilteringObjectives(dev.id(), p.number(), true);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001267 }
1268 }
1269 }
1270 }
1271
Jonathan Hart403372d2018-08-22 11:44:13 -07001272
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001273 /**
1274 * Get the uplink for of the OLT device.
Gamze Abakaad329652018-12-20 10:12:21 +00001275 * <p>
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001276 * This assumes that the OLT has a single uplink port. When more uplink ports need to be supported
1277 * this logic needs to be changed
1278 *
1279 * @param dev Device to look for
1280 * @return The uplink Port of the OLT
1281 */
1282 private Port getUplinkPort(Device dev) {
1283 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +00001284 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001285 log.debug("getUplinkPort: deviceInfo {}", deviceInfo);
Saurav Das82b8e6d2018-10-04 15:25:12 -07001286 if (deviceInfo == null) {
1287 log.warn("Device {} is not configured in SADIS .. cannot fetch device"
1288 + " info", dev.id());
1289 return null;
1290 }
1291 // Return the port that has been configured as the uplink port of this OLT in Sadis
Gamze Abakaad329652018-12-20 10:12:21 +00001292 for (Port p : deviceService.getPorts(dev.id())) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001293 if (p.number().toLong() == deviceInfo.uplinkPort()) {
1294 log.debug("getUplinkPort: Found port {}", p);
1295 return p;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001296 }
1297 }
1298
Gamze Abaka838d8142019-02-21 07:06:55 +00001299 log.debug("getUplinkPort: " + NO_UPLINK_PORT, dev.id());
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001300 return null;
1301 }
1302
1303 /**
1304 * Return the subscriber on a port.
1305 *
Matteo Scandolo962a6ad2018-12-11 15:39:42 -08001306 * @param cp ConnectPoint on which to find the subscriber
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001307 * @return subscriber if found else null
1308 */
Matteo Scandolo962a6ad2018-12-11 15:39:42 -08001309 SubscriberAndDeviceInformation getSubscriber(ConnectPoint cp) {
1310 Port port = deviceService.getPort(cp);
1311 checkNotNull(port, "Invalid connect point");
1312 String portName = port.annotations().value(AnnotationKeys.PORT_NAME);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001313 return subsService.get(portName);
1314 }
1315
Gamze Abakaad329652018-12-20 10:12:21 +00001316 /**
1317 * Write metadata instruction value (metadata) is 8 bytes.
Gamze Abaka838d8142019-02-21 07:06:55 +00001318 * <p>
Gamze Abakaad329652018-12-20 10:12:21 +00001319 * MS 2 bytes: C Tag
1320 * Next 2 bytes: Technology Profile Id
1321 * Next 4 bytes: Port number (uni or nni)
1322 */
1323
1324 private Long createMetadata(VlanId innerVlan, int techProfileId, PortNumber egressPort) {
1325
1326 if (techProfileId == -1) {
1327 techProfileId = DEFAULT_TP_ID;
1328 }
1329
1330 return ((long) (innerVlan.id()) << 48 | (long) techProfileId << 32) | egressPort.toLong();
1331 }
1332
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001333 private boolean isUniPort(Device d, Port p) {
1334 Port ulPort = getUplinkPort(d);
1335 if (ulPort != null) {
1336 return (ulPort.number().toLong() != p.number().toLong());
1337 }
1338 return false;
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001339 }
1340
Jonathan Hart4c538002018-08-23 10:11:54 -07001341 private SubscriberAndDeviceInformation getOltInfo(Device dev) {
1342 String devSerialNo = dev.serialNumber();
Gamze Abaka641fc072018-09-04 09:16:27 +00001343 return subsService.get(devSerialNo);
Jonathan Hart4c538002018-08-23 10:11:54 -07001344 }
1345
alshabibf0e7e702015-05-30 18:22:36 -07001346 private class InternalDeviceListener implements DeviceListener {
1347 @Override
1348 public void event(DeviceEvent event) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001349 eventExecutor.execute(() -> {
1350 DeviceId devId = event.subject().id();
1351 Device dev = event.subject();
Gamze Abaka838d8142019-02-21 07:06:55 +00001352 Port port = event.port();
Jonathan Hart4c538002018-08-23 10:11:54 -07001353
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001354 if (event.type() == DeviceEvent.Type.PORT_STATS_UPDATED) {
1355 return;
1356 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001357
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001358 if (getOltInfo(dev) == null) {
1359 log.debug("No device info found, this is not an OLT");
1360 return;
1361 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001362
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001363 log.debug("OLT got {} event for {}", event.type(), event.subject());
Jonathan Hart4c538002018-08-23 10:11:54 -07001364
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001365 switch (event.type()) {
1366 //TODO: Port handling and bookkeeping should be improved once
1367 // olt firmware handles correct behaviour.
1368 case PORT_ADDED:
Gamze Abaka838d8142019-02-21 07:06:55 +00001369 if (isUniPort(dev, port)) {
1370 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, port));
Jonathan Hart4c538002018-08-23 10:11:54 -07001371
Gamze Abaka838d8142019-02-21 07:06:55 +00001372 if (port.isEnabled()) {
1373 processEapolFilteringObjectives(devId, port.number(), defaultBpId, true);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001374 }
1375 } else {
1376 checkAndCreateDeviceFlows(dev);
1377 }
1378 break;
1379 case PORT_REMOVED:
Gamze Abaka838d8142019-02-21 07:06:55 +00001380 if (isUniPort(dev, port)) {
1381 if (port.isEnabled()) {
1382 processEapolFilteringObjectives(devId, port.number(),
1383 getCurrentBandwidthProfile(new ConnectPoint(devId, port.number())),
1384 false);
1385 removeSubscriber(new ConnectPoint(devId, port.number()));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001386 }
1387
Gamze Abaka838d8142019-02-21 07:06:55 +00001388 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, port));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001389 }
1390
1391 break;
1392 case PORT_UPDATED:
Gamze Abaka838d8142019-02-21 07:06:55 +00001393 if (!isUniPort(dev, port)) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001394 break;
1395 }
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001396
Gamze Abaka838d8142019-02-21 07:06:55 +00001397 if (port.isEnabled()) {
1398 processEapolFilteringObjectives(devId, port.number(), defaultBpId, true);
1399 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, port));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001400 } else {
Gamze Abaka838d8142019-02-21 07:06:55 +00001401 processEapolFilteringObjectives(devId, port.number(),
1402 getCurrentBandwidthProfile(new ConnectPoint(devId, port.number())),
1403 false);
1404 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, port));
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001405 }
alshabibbb83aa22016-02-10 15:08:23 -08001406 break;
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001407 case DEVICE_ADDED:
alshabib7c190012016-02-09 18:22:33 -08001408 post(new AccessDeviceEvent(
1409 AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
1410 null, null));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001411
1412 // Send UNI_ADDED events for all existing ports
1413 deviceService.getPorts(devId).stream()
1414 .filter(p -> isUniPort(dev, p))
1415 .filter(Port::isEnabled)
1416 .forEach(p -> post(new AccessDeviceEvent(
1417 AccessDeviceEvent.Type.UNI_ADDED, devId, p)));
1418
Jonathan Hart403372d2018-08-22 11:44:13 -07001419 checkAndCreateDeviceFlows(dev);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001420 break;
1421 case DEVICE_REMOVED:
1422 deviceService.getPorts(devId).stream()
1423 .filter(p -> isUniPort(dev, p))
1424 .forEach(p -> post(new AccessDeviceEvent(
1425 AccessDeviceEvent.Type.UNI_REMOVED, devId, p)));
1426
alshabib7c190012016-02-09 18:22:33 -08001427 post(new AccessDeviceEvent(
1428 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
1429 null, null));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001430 break;
1431 case DEVICE_AVAILABILITY_CHANGED:
1432 if (deviceService.isAvailable(devId)) {
1433 post(new AccessDeviceEvent(
1434 AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
1435 null, null));
1436 checkAndCreateDeviceFlows(dev);
1437 } else {
1438 post(new AccessDeviceEvent(
1439 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
1440 null, null));
1441 }
1442 break;
1443 case DEVICE_UPDATED:
1444 case DEVICE_SUSPENDED:
1445 case PORT_STATS_UPDATED:
1446 default:
1447 return;
1448 }
1449 });
alshabibf0e7e702015-05-30 18:22:36 -07001450 }
Gamze Abaka838d8142019-02-21 07:06:55 +00001451
1452 private String getCurrentBandwidthProfile(ConnectPoint connectPoint) {
1453 SubscriberAndDeviceInformation sub = programmedSubs.get(connectPoint);
1454 if (sub != null) {
1455 return sub.upstreamBandwidthProfile();
1456 }
1457 return defaultBpId;
1458 }
alshabibf0e7e702015-05-30 18:22:36 -07001459 }
Gamze Abaka641fc072018-09-04 09:16:27 +00001460
1461 private class InternalMeterListener implements MeterListener {
1462
1463 @Override
1464 public void event(MeterEvent meterEvent) {
1465 if (deleteMeters && MeterEvent.Type.METER_REFERENCE_COUNT_ZERO.equals(meterEvent.type())) {
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001466 log.info("Zero Count Meter Event is received. Meter is {}", meterEvent.subject());
Gamze Abaka641fc072018-09-04 09:16:27 +00001467 Meter meter = meterEvent.subject();
Gamze Abaka838d8142019-02-21 07:06:55 +00001468 if (meter != null && appId.equals(meter.appId()) && !programmedMeters.contains(meter.id())) {
Gamze Abaka641fc072018-09-04 09:16:27 +00001469 deleteMeter(meter.deviceId(), meter.id());
1470 }
1471 } else if (MeterEvent.Type.METER_REMOVED.equals(meterEvent.type())) {
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001472 log.info("Meter removed event is received. Meter is {}", meterEvent.subject());
Gamze Abaka641fc072018-09-04 09:16:27 +00001473 removeMeterFromBpMap(meterEvent.subject());
1474 }
1475 }
1476
1477 private void deleteMeter(DeviceId deviceId, MeterId meterId) {
1478 Meter meter = meterService.getMeter(deviceId, meterId);
Gamze Abaka838d8142019-02-21 07:06:55 +00001479 if (meter != null) {
1480 MeterRequest meterRequest = DefaultMeterRequest.builder()
1481 .withBands(meter.bands())
1482 .withUnit(meter.unit())
1483 .forDevice(deviceId)
1484 .fromApp(appId)
1485 .burst()
1486 .remove();
Gamze Abaka641fc072018-09-04 09:16:27 +00001487
Gamze Abaka838d8142019-02-21 07:06:55 +00001488 meterService.withdraw(meterRequest, meterId);
1489 }
Gamze Abaka641fc072018-09-04 09:16:27 +00001490
1491 }
1492
1493 private void removeMeterFromBpMap(Meter meter) {
1494 for (Map.Entry<String, MeterId> entry : bpInfoToMeter.entrySet()) {
1495 if (entry.getValue().equals(meter.id())) {
1496 bpInfoToMeter.remove(entry.getKey());
1497 log.info("Deleted from the internal map. Profile {} and Meter {}", entry.getKey(), meter.id());
1498 break;
1499 }
1500 }
1501 }
1502 }
1503}