blob: 4deb672a34dd3b83359814bcfac51e3a9f184ec0 [file] [log] [blame]
alshabibf0e7e702015-05-30 18:22:36 -07001/*
Brian O'Connord6a135a2017-08-03 22:46:05 -07002 * Copyright 2016-present Open Networking Foundation
alshabibf0e7e702015-05-30 18:22:36 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
alshabib36a4d732016-06-01 16:03:59 -070016package org.opencord.olt.impl;
alshabibf0e7e702015-05-30 18:22:36 -070017
Saurav Das82b8e6d2018-10-04 15:25:12 -070018import static com.google.common.base.Preconditions.checkNotNull;
19import static com.google.common.base.Strings.isNullOrEmpty;
20import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
21import static org.onlab.util.Tools.get;
22import static org.onlab.util.Tools.groupedThreads;
23import static org.slf4j.LoggerFactory.getLogger;
24
25import java.util.AbstractMap;
Amit Ghoshe1d3f092018-10-09 19:44:33 +010026import java.util.Arrays;
Saurav Das82b8e6d2018-10-04 15:25:12 -070027import java.util.ArrayList;
28import java.util.Collection;
29import java.util.Dictionary;
30import java.util.List;
31import java.util.Map;
32import java.util.Optional;
33import java.util.Properties;
34import java.util.concurrent.CompletableFuture;
Gamze Abaka838d8142019-02-21 07:06:55 +000035import java.util.concurrent.CopyOnWriteArrayList;
Saurav Das82b8e6d2018-10-04 15:25:12 -070036import java.util.concurrent.ExecutorService;
37import java.util.concurrent.Executors;
38
alshabibf0e7e702015-05-30 18:22:36 -070039import org.apache.felix.scr.annotations.Activate;
40import org.apache.felix.scr.annotations.Component;
41import org.apache.felix.scr.annotations.Deactivate;
alshabibe0559672016-02-21 14:49:51 -080042import org.apache.felix.scr.annotations.Modified;
43import org.apache.felix.scr.annotations.Property;
alshabibf0e7e702015-05-30 18:22:36 -070044import org.apache.felix.scr.annotations.Reference;
45import org.apache.felix.scr.annotations.ReferenceCardinality;
Jonathan Harte533a422015-10-20 17:31:24 -070046import org.apache.felix.scr.annotations.Service;
alshabibdec2e252016-01-15 12:20:25 -080047import org.onlab.packet.EthType;
Amit Ghosh95e2f652017-08-23 12:49:46 +010048import org.onlab.packet.IPv4;
Matteo Scandolo63460d12018-11-02 16:19:04 -070049import org.onlab.packet.IPv6;
Amit Ghosh95e2f652017-08-23 12:49:46 +010050import org.onlab.packet.TpPort;
alshabibf0e7e702015-05-30 18:22:36 -070051import org.onlab.packet.VlanId;
Amit Ghosh95e2f652017-08-23 12:49:46 +010052import org.onlab.util.Tools;
alshabibe0559672016-02-21 14:49:51 -080053import org.onosproject.cfg.ComponentConfigService;
alshabibf0e7e702015-05-30 18:22:36 -070054import org.onosproject.core.ApplicationId;
55import org.onosproject.core.CoreService;
alshabib8e4fd2f2016-01-12 15:55:53 -080056import org.onosproject.event.AbstractListenerManager;
alshabib09753b52016-03-04 14:55:19 -080057import org.onosproject.mastership.MastershipService;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010058import org.onosproject.net.AnnotationKeys;
Jonathan Harte533a422015-10-20 17:31:24 -070059import org.onosproject.net.ConnectPoint;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010060import org.onosproject.net.Device;
alshabibf0e7e702015-05-30 18:22:36 -070061import org.onosproject.net.DeviceId;
alshabibdec2e252016-01-15 12:20:25 -080062import org.onosproject.net.Port;
alshabibf0e7e702015-05-30 18:22:36 -070063import org.onosproject.net.PortNumber;
64import org.onosproject.net.device.DeviceEvent;
65import org.onosproject.net.device.DeviceListener;
66import org.onosproject.net.device.DeviceService;
67import org.onosproject.net.flow.DefaultTrafficSelector;
68import org.onosproject.net.flow.DefaultTrafficTreatment;
69import org.onosproject.net.flow.TrafficSelector;
70import org.onosproject.net.flow.TrafficTreatment;
alshabibdec2e252016-01-15 12:20:25 -080071import org.onosproject.net.flow.criteria.Criteria;
72import org.onosproject.net.flowobjective.DefaultFilteringObjective;
alshabibf0e7e702015-05-30 18:22:36 -070073import org.onosproject.net.flowobjective.DefaultForwardingObjective;
alshabibdec2e252016-01-15 12:20:25 -080074import org.onosproject.net.flowobjective.FilteringObjective;
alshabibf0e7e702015-05-30 18:22:36 -070075import org.onosproject.net.flowobjective.FlowObjectiveService;
76import org.onosproject.net.flowobjective.ForwardingObjective;
alshabib3ea82642016-01-12 18:06:53 -080077import org.onosproject.net.flowobjective.Objective;
78import org.onosproject.net.flowobjective.ObjectiveContext;
79import org.onosproject.net.flowobjective.ObjectiveError;
Amit Ghoshe1d3f092018-10-09 19:44:33 +010080import org.onosproject.store.serializers.KryoNamespaces;
81import org.onosproject.store.service.ConsistentMultimap;
82import org.onosproject.store.service.Serializer;
83import org.onosproject.store.service.StorageService;
Gamze Abaka641fc072018-09-04 09:16:27 +000084import org.onosproject.net.meter.Band;
85import org.onosproject.net.meter.DefaultBand;
86import org.onosproject.net.meter.DefaultMeterRequest;
87import org.onosproject.net.meter.Meter;
88import org.onosproject.net.meter.MeterService;
89import org.onosproject.net.meter.MeterListener;
90import org.onosproject.net.meter.MeterRequest;
91import org.onosproject.net.meter.MeterId;
92import org.onosproject.net.meter.MeterEvent;
alshabib36a4d732016-06-01 16:03:59 -070093import org.opencord.olt.AccessDeviceEvent;
94import org.opencord.olt.AccessDeviceListener;
95import org.opencord.olt.AccessDeviceService;
Amit Ghosh31939522018-08-16 13:28:21 +010096import org.opencord.olt.AccessSubscriberId;
Gamze Abaka641fc072018-09-04 09:16:27 +000097import org.opencord.sadis.BandwidthProfileInformation;
98import org.opencord.sadis.BaseInformationService;
99import org.opencord.sadis.SadisService;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100100import org.opencord.sadis.SubscriberAndDeviceInformation;
alshabibe0559672016-02-21 14:49:51 -0800101import org.osgi.service.component.ComponentContext;
alshabibf0e7e702015-05-30 18:22:36 -0700102import org.slf4j.Logger;
103
Gamze Abaka641fc072018-09-04 09:16:27 +0000104import java.util.HashMap;
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100105
Saurav Das82b8e6d2018-10-04 15:25:12 -0700106import com.google.common.collect.ImmutableMap;
107import com.google.common.collect.Maps;
alshabibf0e7e702015-05-30 18:22:36 -0700108
109/**
Jonathan Harte533a422015-10-20 17:31:24 -0700110 * Provisions rules on access devices.
alshabibf0e7e702015-05-30 18:22:36 -0700111 */
Jonathan Harte533a422015-10-20 17:31:24 -0700112@Service
alshabibf0e7e702015-05-30 18:22:36 -0700113@Component(immediate = true)
alshabib8e4fd2f2016-01-12 15:55:53 -0800114public class Olt
115 extends AbstractListenerManager<AccessDeviceEvent, AccessDeviceListener>
116 implements AccessDeviceService {
Charles Chan54f110f2017-01-20 11:22:42 -0800117 private static final String APP_NAME = "org.opencord.olt";
alshabibe0559672016-02-21 14:49:51 -0800118
119 private static final short DEFAULT_VLAN = 0;
Gamze Abaka1efc80c2019-02-15 12:10:54 +0000120 private static final int DEFAULT_TP_ID = 64;
Gamze Abakaad329652018-12-20 10:12:21 +0000121 private static final String DEFAULT_BP_ID = "Default";
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100122 private static final String ADDITIONAL_VLANS = "additional-vlans";
Gamze Abaka838d8142019-02-21 07:06:55 +0000123 private static final String NO_UPLINK_PORT = "No uplink port found for OLT device {}";
124 private static final String INSTALLED = "installed";
125 private static final String REMOVED = "removed";
126 private static final String INSTALLATION = "installation";
127 private static final String REMOVAL = "removal";
alshabibe0559672016-02-21 14:49:51 -0800128
alshabibf0e7e702015-05-30 18:22:36 -0700129 private final Logger log = getLogger(getClass());
130
131 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
132 protected FlowObjectiveService flowObjectiveService;
133
134 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabib09753b52016-03-04 14:55:19 -0800135 protected MastershipService mastershipService;
136
137 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibf0e7e702015-05-30 18:22:36 -0700138 protected DeviceService deviceService;
139
140 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
141 protected CoreService coreService;
142
Jonathan Harte533a422015-10-20 17:31:24 -0700143 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibe0559672016-02-21 14:49:51 -0800144 protected ComponentConfigService componentConfigService;
145
alshabib4ceaed32016-03-03 18:00:58 -0800146 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Gamze Abaka641fc072018-09-04 09:16:27 +0000147 protected SadisService sadisService;
148
149 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
150 protected MeterService meterService;
alshabibe0559672016-02-21 14:49:51 -0800151
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100152 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
153 protected StorageService storageService;
154
alshabibe0559672016-02-21 14:49:51 -0800155 @Property(name = "defaultVlan", intValue = DEFAULT_VLAN,
156 label = "Default VLAN RG<->ONU traffic")
157 private int defaultVlan = DEFAULT_VLAN;
158
Matt Jeanneret3f579262018-06-14 17:16:23 -0400159 @Property(name = "enableDhcpOnProvisioning", boolValue = true,
160 label = "Create the DHCP Flow rules when a subscriber is provisioned")
161 protected boolean enableDhcpOnProvisioning = false;
162
Matteo Scandolo63460d12018-11-02 16:19:04 -0700163 @Property(name = "enableDhcpV4", boolValue = true,
164 label = "Enable flows for DHCP v4")
165 protected boolean enableDhcpV4 = true;
166
167 @Property(name = "enableDhcpV6", boolValue = true,
168 label = "Enable flows for DHCP v6")
169 protected boolean enableDhcpV6 = false;
170
Matt Jeanneret3f579262018-06-14 17:16:23 -0400171 @Property(name = "enableIgmpOnProvisioning", boolValue = false,
172 label = "Create IGMP Flow rules when a subscriber is provisioned")
173 protected boolean enableIgmpOnProvisioning = false;
Amit Ghosh95e2f652017-08-23 12:49:46 +0100174
Gamze Abaka1efc80c2019-02-15 12:10:54 +0000175 @Property(name = "deleteMeters", boolValue = true,
Gamze Abaka641fc072018-09-04 09:16:27 +0000176 label = "Deleting Meters based on flow count statistics")
Gamze Abaka1efc80c2019-02-15 12:10:54 +0000177 protected boolean deleteMeters = true;
Gamze Abaka641fc072018-09-04 09:16:27 +0000178
Gamze Abakaad329652018-12-20 10:12:21 +0000179 @Property(name = "defaultTechProfileId", intValue = DEFAULT_TP_ID,
180 label = "Default technology profile id that is used for authentication trap flows")
181 protected int defaultTechProfileId = DEFAULT_TP_ID;
182
183 @Property(name = "defaultBpId", value = DEFAULT_BP_ID,
184 label = "Default bandwidth profile id that is used for authentication trap flows")
185 protected String defaultBpId = DEFAULT_BP_ID;
186
alshabibf0e7e702015-05-30 18:22:36 -0700187 private final DeviceListener deviceListener = new InternalDeviceListener();
Gamze Abaka641fc072018-09-04 09:16:27 +0000188 private final MeterListener meterListener = new InternalMeterListener();
alshabibf0e7e702015-05-30 18:22:36 -0700189
190 private ApplicationId appId;
Gamze Abaka641fc072018-09-04 09:16:27 +0000191 protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
192 private BaseInformationService<BandwidthProfileInformation> bpService;
alshabibf0e7e702015-05-30 18:22:36 -0700193
Gamze Abaka641fc072018-09-04 09:16:27 +0000194 private Map<String, MeterId> bpInfoToMeter = new HashMap<>();
195
196 private ExecutorService oltInstallers = Executors.newFixedThreadPool(4,
197 groupedThreads("onos/olt-service",
198 "olt-installer-%d"));
alshabibf0e7e702015-05-30 18:22:36 -0700199
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100200 private ConsistentMultimap<ConnectPoint, Map.Entry<VlanId, VlanId>> additionalVlans;
201
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700202 protected ExecutorService eventExecutor;
203
Saurav Das82b8e6d2018-10-04 15:25:12 -0700204 private Map<ConnectPoint, SubscriberAndDeviceInformation> programmedSubs;
Gamze Abaka838d8142019-02-21 07:06:55 +0000205 private List<MeterId> programmedMeters;
Saurav Das82b8e6d2018-10-04 15:25:12 -0700206
alshabibf0e7e702015-05-30 18:22:36 -0700207 @Activate
alshabibe0559672016-02-21 14:49:51 -0800208 public void activate(ComponentContext context) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700209 eventExecutor = newSingleThreadScheduledExecutor(groupedThreads("onos/olt", "events-%d", log));
alshabibe0559672016-02-21 14:49:51 -0800210 modified(context);
Charles Chan54f110f2017-01-20 11:22:42 -0800211 appId = coreService.registerApplication(APP_NAME);
alshabibe0559672016-02-21 14:49:51 -0800212 componentConfigService.registerProperties(getClass());
Saurav Das82b8e6d2018-10-04 15:25:12 -0700213 programmedSubs = Maps.newConcurrentMap();
Gamze Abaka838d8142019-02-21 07:06:55 +0000214 programmedMeters = new CopyOnWriteArrayList();
alshabibc4dfe852015-06-05 13:35:13 -0700215
alshabib8e4fd2f2016-01-12 15:55:53 -0800216 eventDispatcher.addSink(AccessDeviceEvent.class, listenerRegistry);
217
Gamze Abaka641fc072018-09-04 09:16:27 +0000218 subsService = sadisService.getSubscriberInfoService();
219 bpService = sadisService.getBandwidthProfileService();
220
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100221 // look for all provisioned devices in Sadis and create EAPOL flows for the
222 // UNI ports
223 Iterable<Device> devices = deviceService.getDevices();
224 for (Device d : devices) {
Jonathan Hart403372d2018-08-22 11:44:13 -0700225 checkAndCreateDeviceFlows(d);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100226 }
alshabib4ceaed32016-03-03 18:00:58 -0800227
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100228 additionalVlans = storageService.<ConnectPoint, Map.Entry<VlanId, VlanId>>consistentMultimapBuilder()
229 .withName(ADDITIONAL_VLANS)
230 .withSerializer(Serializer.using(Arrays.asList(KryoNamespaces.API),
231 AbstractMap.SimpleEntry.class))
232 .build();
233
alshabibba357492016-01-27 13:49:46 -0800234 deviceService.addListener(deviceListener);
Gamze Abaka641fc072018-09-04 09:16:27 +0000235 meterService.addListener(meterListener);
alshabibba357492016-01-27 13:49:46 -0800236
alshabibf0e7e702015-05-30 18:22:36 -0700237 log.info("Started with Application ID {}", appId.id());
238 }
239
240 @Deactivate
241 public void deactivate() {
alshabibe0559672016-02-21 14:49:51 -0800242 componentConfigService.unregisterProperties(getClass(), false);
alshabib62e9ce72016-02-11 17:31:36 -0800243 deviceService.removeListener(deviceListener);
Gamze Abaka641fc072018-09-04 09:16:27 +0000244 meterService.removeListener(meterListener);
Jonathan Hart5f1c8142018-07-24 17:31:59 -0700245 eventDispatcher.removeSink(AccessDeviceEvent.class);
alshabibf0e7e702015-05-30 18:22:36 -0700246 log.info("Stopped");
247 }
248
alshabibe0559672016-02-21 14:49:51 -0800249 @Modified
250 public void modified(ComponentContext context) {
251 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
252
253 try {
254 String s = get(properties, "defaultVlan");
255 defaultVlan = isNullOrEmpty(s) ? DEFAULT_VLAN : Integer.parseInt(s.trim());
Amit Ghosh95e2f652017-08-23 12:49:46 +0100256
Matt Jeanneret3f579262018-06-14 17:16:23 -0400257 Boolean o = Tools.isPropertyEnabled(properties, "enableDhcpOnProvisioning");
Amit Ghosh95e2f652017-08-23 12:49:46 +0100258 if (o != null) {
Matt Jeanneret3f579262018-06-14 17:16:23 -0400259 enableDhcpOnProvisioning = o;
Amit Ghosh95e2f652017-08-23 12:49:46 +0100260 }
Matt Jeanneret3f579262018-06-14 17:16:23 -0400261
Matteo Scandolo63460d12018-11-02 16:19:04 -0700262 Boolean v4 = Tools.isPropertyEnabled(properties, "enableDhcpV4");
263 if (v4 != null) {
264 enableDhcpV4 = v4;
265 }
266
267 Boolean v6 = Tools.isPropertyEnabled(properties, "enableDhcpV6");
268 if (v6 != null) {
269 enableDhcpV6 = v6;
270 }
271
Matt Jeanneret3f579262018-06-14 17:16:23 -0400272 Boolean p = Tools.isPropertyEnabled(properties, "enableIgmpOnProvisioning");
273 if (p != null) {
274 enableIgmpOnProvisioning = p;
275 }
276
Matteo Scandolo63460d12018-11-02 16:19:04 -0700277 log.info("DHCP Settings [enableDhcpOnProvisioning: {}, enableDhcpV4: {}, enableDhcpV6: {}]",
Gamze Abakaad329652018-12-20 10:12:21 +0000278 enableDhcpOnProvisioning, enableDhcpV4, enableDhcpV6);
Matteo Scandolo63460d12018-11-02 16:19:04 -0700279
Gamze Abaka641fc072018-09-04 09:16:27 +0000280 Boolean d = Tools.isPropertyEnabled(properties, "deleteMeters");
281 if (d != null) {
282 deleteMeters = d;
283 }
284
Gamze Abakaad329652018-12-20 10:12:21 +0000285 String tpId = get(properties, "defaultTechProfileId");
286 defaultTechProfileId = isNullOrEmpty(s) ? DEFAULT_TP_ID : Integer.parseInt(tpId.trim());
287
288 String bpId = get(properties, "defaultBpId");
289 defaultBpId = bpId;
290
alshabibe0559672016-02-21 14:49:51 -0800291 } catch (Exception e) {
292 defaultVlan = DEFAULT_VLAN;
293 }
294 }
295
alshabib32232c82016-02-25 17:57:24 -0500296 @Override
Gamze Abaka838d8142019-02-21 07:06:55 +0000297 public boolean provisionSubscriber(ConnectPoint connectPoint) {
298
299 DeviceId deviceId = connectPoint.deviceId();
300 PortNumber subscriberPortNo = connectPoint.port();
301
302 checkNotNull(deviceService.getPort(deviceId, subscriberPortNo),
Jonathan Hart94b90492018-04-24 14:02:25 -0700303 "Invalid connect point");
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100304 // Find the subscriber on this connect point
Gamze Abaka838d8142019-02-21 07:06:55 +0000305 SubscriberAndDeviceInformation sub = getSubscriber(connectPoint);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100306 if (sub == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000307 log.warn("No subscriber found for {}", connectPoint);
Amit Ghosh31939522018-08-16 13:28:21 +0100308 return false;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100309 }
Jonathan Harte533a422015-10-20 17:31:24 -0700310
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100311 // Get the uplink port
Gamze Abaka838d8142019-02-21 07:06:55 +0000312 Port uplinkPort = getUplinkPort(deviceService.getDevice(deviceId));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100313 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000314 log.warn(NO_UPLINK_PORT, deviceId);
Amit Ghosh31939522018-08-16 13:28:21 +0100315 return false;
Jonathan Harte533a422015-10-20 17:31:24 -0700316 }
317
Gamze Abaka838d8142019-02-21 07:06:55 +0000318 //delete Eapol authentication flow with default bandwidth
319 //re-install Eapol authentication flow with the subscribers' upstream bandwidth profile
320 processEapolFilteringObjectives(deviceId, subscriberPortNo, defaultBpId, false);
321 programmedMeters.remove(bpInfoToMeter.get(defaultBpId));
322 processEapolFilteringObjectives(deviceId, subscriberPortNo, sub.upstreamBandwidthProfile(), true);
323
Saurav Das82b8e6d2018-10-04 15:25:12 -0700324 log.info("Programming vlans for subscriber: {}", sub);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100325 Optional<VlanId> defaultVlan = Optional.empty();
Gamze Abaka838d8142019-02-21 07:06:55 +0000326 MeterId upstreamMeterId = provisionVlans(connectPoint, uplinkPort.number(), defaultVlan, sub);
327
328 if (enableDhcpOnProvisioning) {
329 processDhcpFilteringObjectives(deviceId, subscriberPortNo, upstreamMeterId,
330 sub.technologyProfileId(), true, true);
331 }
Amit Ghosh95e2f652017-08-23 12:49:46 +0100332
Matt Jeanneret3f579262018-06-14 17:16:23 -0400333 if (enableIgmpOnProvisioning) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000334 processIgmpFilteringObjectives(deviceId, subscriberPortNo, upstreamMeterId,
335 sub.technologyProfileId(), true);
Amit Ghosh95e2f652017-08-23 12:49:46 +0100336 }
Saurav Das82b8e6d2018-10-04 15:25:12 -0700337 // cache subscriber info
Gamze Abaka838d8142019-02-21 07:06:55 +0000338 programmedSubs.put(connectPoint, sub);
Amit Ghosh31939522018-08-16 13:28:21 +0100339 return true;
alshabibb7a9e172016-01-13 11:23:53 -0800340 }
341
342 @Override
Gamze Abaka838d8142019-02-21 07:06:55 +0000343 public boolean removeSubscriber(ConnectPoint connectPoint) {
Matteo Scandolo962a6ad2018-12-11 15:39:42 -0800344 // Get the subscriber connected to this port from the local cache
345 // as if we don't know about the subscriber there's no need to remove it
Gamze Abaka838d8142019-02-21 07:06:55 +0000346
347 DeviceId deviceId = connectPoint.deviceId();
348 PortNumber subscriberPortNo = connectPoint.port();
349
350 SubscriberAndDeviceInformation subscriber = programmedSubs.get(connectPoint);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100351 if (subscriber == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000352 log.warn("Subscriber on connectionPoint {} was not previously programmed, " +
353 "no need to remove it", connectPoint);
Matteo Scandolo962a6ad2018-12-11 15:39:42 -0800354 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800355 }
356
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100357 // Get the uplink port
Gamze Abaka838d8142019-02-21 07:06:55 +0000358 Port uplinkPort = getUplinkPort(deviceService.getDevice(deviceId));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100359 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000360 log.warn(NO_UPLINK_PORT, deviceId);
Amit Ghosh31939522018-08-16 13:28:21 +0100361 return false;
alshabib4ceaed32016-03-03 18:00:58 -0800362 }
363
Gamze Abaka838d8142019-02-21 07:06:55 +0000364 //delete Eapol authentication flow with the subscribers' upstream bandwidth profile
365 //re-install Eapol authentication flow with the default bandwidth profile
366 processEapolFilteringObjectives(deviceId, subscriberPortNo, subscriber.upstreamBandwidthProfile(), false);
367 processEapolFilteringObjectives(deviceId, subscriberPortNo, defaultBpId, true);
Amit Ghosh95e2f652017-08-23 12:49:46 +0100368
Saurav Das82b8e6d2018-10-04 15:25:12 -0700369 log.info("Removing programmed vlans for subscriber: {}", subscriber);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100370 Optional<VlanId> defaultVlan = Optional.empty();
Gamze Abaka838d8142019-02-21 07:06:55 +0000371 MeterId upstreamMeterId = unprovisionVlans(deviceId, uplinkPort.number(),
372 subscriberPortNo, subscriber, defaultVlan);
373
374 if (enableDhcpOnProvisioning) {
375 processDhcpFilteringObjectives(deviceId, subscriberPortNo,
376 upstreamMeterId, subscriber.technologyProfileId(), false, true);
377 }
alshabibbf23a1f2016-01-14 17:27:11 -0800378
Matt Jeanneret3f579262018-06-14 17:16:23 -0400379 if (enableIgmpOnProvisioning) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000380 processIgmpFilteringObjectives(deviceId, subscriberPortNo,
381 upstreamMeterId, subscriber.technologyProfileId(), false);
Amit Ghosh95e2f652017-08-23 12:49:46 +0100382 }
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100383
384 // Remove if there are any flows for the additional Vlans
Gamze Abaka838d8142019-02-21 07:06:55 +0000385 Collection<? extends Map.Entry<VlanId, VlanId>> vlansList = additionalVlans.get(connectPoint).value();
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100386
387 // Remove the flows for the additional vlans for this subscriber
388 for (Map.Entry<VlanId, VlanId> vlans : vlansList) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000389 unprovisionTransparentFlows(deviceId, uplinkPort.number(), subscriberPortNo,
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100390 vlans.getValue(), vlans.getKey());
391
392 // Remove it from the map also
Gamze Abaka838d8142019-02-21 07:06:55 +0000393 additionalVlans.remove(connectPoint, vlans);
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100394 }
395
Gamze Abaka838d8142019-02-21 07:06:55 +0000396 programmedSubs.remove(connectPoint);
Amit Ghosh31939522018-08-16 13:28:21 +0100397 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800398 }
399
Amit Ghosh31939522018-08-16 13:28:21 +0100400 @Override
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100401 public boolean provisionSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag, Optional<VlanId> cTag) {
Amit Ghosh31939522018-08-16 13:28:21 +0100402 // Check if we can find the connect point to which this subscriber is connected
403 ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
404 if (subsPort == null) {
405 log.warn("ConnectPoint for {} not found", subscriberId);
406 return false;
407 }
408
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100409 if (!sTag.isPresent() && !cTag.isPresent()) {
410 return provisionSubscriber(subsPort);
411 } else if (sTag.isPresent() && cTag.isPresent()) {
412 Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
413 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000414 log.warn(NO_UPLINK_PORT, subsPort.deviceId());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100415 return false;
416 }
417
418 provisionTransparentFlows(subsPort.deviceId(), uplinkPort.number(), subsPort.port(),
419 cTag.get(), sTag.get());
420 return true;
421 } else {
422 log.warn("Provisioning failed for subscriber: {}", subscriberId);
423 return false;
424 }
Amit Ghosh31939522018-08-16 13:28:21 +0100425 }
Amit Ghosh95e2f652017-08-23 12:49:46 +0100426
alshabibe0559672016-02-21 14:49:51 -0800427 @Override
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100428 public boolean removeSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag, Optional<VlanId> cTag) {
Amit Ghosh31939522018-08-16 13:28:21 +0100429 // Check if we can find the connect point to which this subscriber is connected
430 ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
431 if (subsPort == null) {
432 log.warn("ConnectPoint for {} not found", subscriberId);
433 return false;
434 }
435
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100436 if (!sTag.isPresent() && !cTag.isPresent()) {
437 return removeSubscriber(subsPort);
438 } else if (sTag.isPresent() && cTag.isPresent()) {
439 // Get the uplink port
440 Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
441 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000442 log.warn(NO_UPLINK_PORT, subsPort.deviceId());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100443 return false;
444 }
445
446 unprovisionTransparentFlows(subsPort.deviceId(), uplinkPort.number(), subsPort.port(),
447 cTag.get(), sTag.get());
448 return true;
449 } else {
450 log.warn("Removing subscriber failed for: {}", subscriberId);
451 return false;
452 }
Amit Ghosh31939522018-08-16 13:28:21 +0100453 }
454
455 @Override
456 public Collection<Map.Entry<ConnectPoint, Map.Entry<VlanId, VlanId>>> getSubscribers() {
457 ArrayList<Map.Entry<ConnectPoint, Map.Entry<VlanId, VlanId>>> subs = new ArrayList<>();
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100458
Saurav Das82b8e6d2018-10-04 15:25:12 -0700459 // Get the subscribers for all the devices configured in sadis
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100460 // If the port is UNI, is enabled and exists in Sadis then copy it
461 for (Device d : deviceService.getDevices()) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700462 if (getOltInfo(d) == null) {
463 continue; // not an olt, or not configured in sadis
464 }
Gamze Abakaad329652018-12-20 10:12:21 +0000465 for (Port p : deviceService.getPorts(d.id())) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100466 if (isUniPort(d, p) && p.isEnabled()) {
467 ConnectPoint cp = new ConnectPoint(d.id(), p.number());
468
469 SubscriberAndDeviceInformation sub = getSubscriber(cp);
470 if (sub != null) {
Amit Ghosh31939522018-08-16 13:28:21 +0100471 Map.Entry<VlanId, VlanId> vlans = new AbstractMap.SimpleEntry(sub.sTag(), sub.cTag());
472 subs.add(new AbstractMap.SimpleEntry(cp, vlans));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100473 }
474 }
475 }
476 }
477
478 return subs;
Jonathan Hartfd6c1b32016-03-08 14:09:09 -0800479 }
480
481 @Override
Saurav Das82b8e6d2018-10-04 15:25:12 -0700482 public ImmutableMap<ConnectPoint, SubscriberAndDeviceInformation> getProgSubs() {
483 return ImmutableMap.copyOf(programmedSubs);
484 }
485
486 @Override
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100487 public List<DeviceId> fetchOlts() {
488 // look through all the devices and find the ones that are OLTs as per Sadis
489 List<DeviceId> olts = new ArrayList<>();
490 Iterable<Device> devices = deviceService.getDevices();
491 for (Device d : devices) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700492 if (getOltInfo(d) != null) {
493 // So this is indeed an OLT device
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100494 olts.add(d.id());
495 }
496 }
497 return olts;
alshabibe0559672016-02-21 14:49:51 -0800498 }
499
Amit Ghosh31939522018-08-16 13:28:21 +0100500 /**
501 * Finds the connect point to which a subscriber is connected.
502 *
503 * @param id The id of the subscriber, this is the same ID as in Sadis
504 * @return Subscribers ConnectPoint if found else null
505 */
506 private ConnectPoint findSubscriberConnectPoint(String id) {
507
508 Iterable<Device> devices = deviceService.getDevices();
509 for (Device d : devices) {
510 for (Port p : deviceService.getPorts(d.id())) {
511 log.trace("Comparing {} with {}", p.annotations().value(AnnotationKeys.PORT_NAME), id);
512 if (p.annotations().value(AnnotationKeys.PORT_NAME).equals(id)) {
513 log.debug("Found on device {} port {}", d.id(), p.number());
514 return new ConnectPoint(d.id(), p.number());
515 }
516 }
517 }
518 return null;
519 }
520
Gamze Abaka641fc072018-09-04 09:16:27 +0000521 private BandwidthProfileInformation getBandwidthProfileInformation(String bandwidthProfile) {
522 if (bandwidthProfile == null) {
523 return null;
524 }
525 return bpService.get(bandwidthProfile);
526 }
527
Gamze Abaka838d8142019-02-21 07:06:55 +0000528 /**
529 * Removes subscriber vlan flows and returns the meter id used in the upstream bandwidth profile.
530 * This meter-id is also referenced by other upstream trap flows for this subscriber.
531 *
532 * @param deviceId the device identifier
533 * @param uplink uplink port of the OLT
534 * @param subscriberPort uni port
535 * @param subscriber subscriber info that includes s, c tags, tech profile and bandwidth profile references
536 * @param defaultVlan default vlan of the subscriber
537 * @return the meter id used in the upstream bandwidth profile
538 */
539 private MeterId unprovisionVlans(DeviceId deviceId, PortNumber uplink,
540 PortNumber subscriberPort, SubscriberAndDeviceInformation subscriber,
541 Optional<VlanId> defaultVlan) {
alshabibbf23a1f2016-01-14 17:27:11 -0800542
543 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
544 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
545
Gamze Abaka641fc072018-09-04 09:16:27 +0000546 VlanId deviceVlan = subscriber.sTag();
547 VlanId subscriberVlan = subscriber.cTag();
548
549 MeterId upstreamMeterId = bpInfoToMeter.get(subscriber.upstreamBandwidthProfile());
550 MeterId downstreamMeterId = bpInfoToMeter.get(subscriber.downstreamBandwidthProfile());
551
alshabib4ceaed32016-03-03 18:00:58 -0800552 ForwardingObjective.Builder upFwd = upBuilder(uplink, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000553 subscriberVlan, deviceVlan,
554 defaultVlan, upstreamMeterId, subscriber.technologyProfileId());
alshabib4ceaed32016-03-03 18:00:58 -0800555 ForwardingObjective.Builder downFwd = downBuilder(uplink, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000556 subscriberVlan, deviceVlan,
557 defaultVlan, downstreamMeterId, subscriber.technologyProfileId());
alshabibbf23a1f2016-01-14 17:27:11 -0800558
alshabib4ceaed32016-03-03 18:00:58 -0800559 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
560 @Override
561 public void onSuccess(Objective objective) {
562 upFuture.complete(null);
563 }
alshabibbf23a1f2016-01-14 17:27:11 -0800564
alshabib4ceaed32016-03-03 18:00:58 -0800565 @Override
566 public void onError(Objective objective, ObjectiveError error) {
567 upFuture.complete(error);
568 }
569 }));
570
571 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
572 @Override
573 public void onSuccess(Objective objective) {
574 downFuture.complete(null);
575 }
576
577 @Override
578 public void onError(Objective objective, ObjectiveError error) {
579 downFuture.complete(error);
580 }
581 }));
alshabibbf23a1f2016-01-14 17:27:11 -0800582
583 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
584 if (upStatus == null && downStatus == null) {
585 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_UNREGISTERED,
Gamze Abaka641fc072018-09-04 09:16:27 +0000586 deviceId,
587 deviceVlan,
588 subscriberVlan));
alshabibbf23a1f2016-01-14 17:27:11 -0800589 } else if (downStatus != null) {
590 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000591 "on port {} failed downstream uninstallation: {}",
592 subscriberVlan, deviceId, subscriberPort, downStatus);
alshabibbf23a1f2016-01-14 17:27:11 -0800593 } else if (upStatus != null) {
594 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000595 "on port {} failed upstream uninstallation: {}",
596 subscriberVlan, deviceId, subscriberPort, upStatus);
alshabibbf23a1f2016-01-14 17:27:11 -0800597 }
598 }, oltInstallers);
alshabibb7a9e172016-01-13 11:23:53 -0800599
Gamze Abaka838d8142019-02-21 07:06:55 +0000600 programmedMeters.remove(upstreamMeterId);
601 programmedMeters.remove(downstreamMeterId);
602 log.debug("programmed Meters size {}", programmedMeters.size());
603 return upstreamMeterId;
Jonathan Harte533a422015-10-20 17:31:24 -0700604 }
605
Gamze Abaka838d8142019-02-21 07:06:55 +0000606 /**
607 * Adds subscriber vlan flows and returns the meter id used in the upstream bandwidth profile.
608 * This meter-id will also be referenced by other upstream trap flows for this subscriber
609 *
610 * @param port the connection point of the subscriber
611 * @param uplinkPort uplink port of the OLT
612 * @param defaultVlan default vlan of the subscriber
613 * @param sub subscriber information that includes s, c tags, tech profile and bandwidth profile references
614 * @return the meter id used in the upstream bandwidth profile
615 */
616 private MeterId provisionVlans(ConnectPoint port, PortNumber uplinkPort, Optional<VlanId> defaultVlan,
617 SubscriberAndDeviceInformation sub) {
Gamze Abaka641fc072018-09-04 09:16:27 +0000618
619 log.info("Provisioning vlans...");
620
621 DeviceId deviceId = port.deviceId();
622 PortNumber subscriberPort = port.port();
623 VlanId deviceVlan = sub.sTag();
624 VlanId subscriberVlan = sub.cTag();
625 int techProfId = sub.technologyProfileId();
626
627 BandwidthProfileInformation upstreamBpInfo = getBandwidthProfileInformation(sub.upstreamBandwidthProfile());
628 BandwidthProfileInformation downstreamBpInfo = getBandwidthProfileInformation(sub.downstreamBandwidthProfile());
629
Gamze Abaka838d8142019-02-21 07:06:55 +0000630 MeterId upstreamMeterId = createMeter(deviceId, upstreamBpInfo);
Gamze Abaka641fc072018-09-04 09:16:27 +0000631 MeterId downstreamMeterId = createMeter(deviceId, downstreamBpInfo);
Jonathan Harte533a422015-10-20 17:31:24 -0700632
alshabib3ea82642016-01-12 18:06:53 -0800633 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
634 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
635
alshabib4ceaed32016-03-03 18:00:58 -0800636 ForwardingObjective.Builder upFwd = upBuilder(uplinkPort, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000637 subscriberVlan, deviceVlan,
Gamze Abaka838d8142019-02-21 07:06:55 +0000638 defaultVlan, upstreamMeterId, techProfId);
Jonathan Harte533a422015-10-20 17:31:24 -0700639
alshabib4ceaed32016-03-03 18:00:58 -0800640 ForwardingObjective.Builder downFwd = downBuilder(uplinkPort, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000641 subscriberVlan, deviceVlan,
642 defaultVlan, downstreamMeterId, techProfId);
alshabib3ea82642016-01-12 18:06:53 -0800643
alshabibbf23a1f2016-01-14 17:27:11 -0800644 flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
645 @Override
646 public void onSuccess(Objective objective) {
647 upFuture.complete(null);
648 }
649
650 @Override
651 public void onError(Objective objective, ObjectiveError error) {
652 upFuture.complete(error);
653 }
654 }));
655
alshabibbf23a1f2016-01-14 17:27:11 -0800656 flowObjectiveService.forward(deviceId, downFwd.add(new ObjectiveContext() {
657 @Override
658 public void onSuccess(Objective objective) {
659 downFuture.complete(null);
660 }
661
662 @Override
663 public void onError(Objective objective, ObjectiveError error) {
664 downFuture.complete(error);
665 }
666 }));
alshabib3ea82642016-01-12 18:06:53 -0800667
668 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
669 if (upStatus == null && downStatus == null) {
670 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_REGISTERED,
Gamze Abaka641fc072018-09-04 09:16:27 +0000671 deviceId,
672 deviceVlan,
673 subscriberVlan));
alshabib50d9fc52016-02-12 15:47:20 -0800674
alshabib3ea82642016-01-12 18:06:53 -0800675 } else if (downStatus != null) {
676 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000677 "on port {} failed downstream installation: {}",
678 subscriberVlan, deviceId, subscriberPort, downStatus);
alshabib3ea82642016-01-12 18:06:53 -0800679 } else if (upStatus != null) {
680 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000681 "on port {} failed upstream installation: {}",
682 subscriberVlan, deviceId, subscriberPort, upStatus);
alshabib3ea82642016-01-12 18:06:53 -0800683 }
684 }, oltInstallers);
685
Gamze Abaka838d8142019-02-21 07:06:55 +0000686 return upstreamMeterId;
Jonathan Harte533a422015-10-20 17:31:24 -0700687 }
688
Gamze Abaka641fc072018-09-04 09:16:27 +0000689 private MeterId createMeter(DeviceId deviceId, BandwidthProfileInformation bpInfo) {
690
691 if (bpInfo == null) {
692 log.warn("Bandwidth profile information is not found");
693 return null;
694 }
695
696 MeterId meterId = bpInfoToMeter.get(bpInfo.id());
697 if (meterId != null) {
698 log.info("Meter is already added. MeterId {}", meterId);
699 return meterId;
700 }
701
702 List<Band> meterBands = createMeterBands(bpInfo);
703
704 MeterRequest meterRequest = DefaultMeterRequest.builder()
705 .withBands(meterBands)
706 .withUnit(Meter.Unit.KB_PER_SEC)
707 .forDevice(deviceId)
708 .fromApp(appId)
709 .burst()
710 .add();
711
712 Meter meter = meterService.submit(meterRequest);
713 bpInfoToMeter.put(bpInfo.id(), meter.id());
714 log.info("Meter is created. Meter Id {}", meter.id());
Gamze Abaka838d8142019-02-21 07:06:55 +0000715 programmedMeters.add(meter.id());
716 log.debug("programmed Meters size {}", programmedMeters.size());
Gamze Abaka641fc072018-09-04 09:16:27 +0000717 return meter.id();
718 }
719
720 private List<Band> createMeterBands(BandwidthProfileInformation bpInfo) {
721 List<Band> meterBands = new ArrayList<>();
722
723 meterBands.add(createMeterBand(bpInfo.committedInformationRate(), bpInfo.committedBurstSize()));
724 meterBands.add(createMeterBand(bpInfo.exceededInformationRate(), bpInfo.exceededBurstSize()));
Gamze Abakaad329652018-12-20 10:12:21 +0000725 meterBands.add(createMeterBand(bpInfo.assuredInformationRate(), 0L));
Gamze Abaka641fc072018-09-04 09:16:27 +0000726
Gamze Abaka641fc072018-09-04 09:16:27 +0000727 return meterBands;
728 }
729
730 private Band createMeterBand(long rate, Long burst) {
731 return DefaultBand.builder()
732 .withRate(rate) //already Kbps
733 .burstSize(burst) // already Kbits
734 .ofType(Band.Type.DROP) // no matter
735 .build();
736 }
737
alshabib4ceaed32016-03-03 18:00:58 -0800738 private ForwardingObjective.Builder downBuilder(PortNumber uplinkPort,
739 PortNumber subscriberPort,
740 VlanId subscriberVlan,
741 VlanId deviceVlan,
Gamze Abaka641fc072018-09-04 09:16:27 +0000742 Optional<VlanId> defaultVlan,
743 MeterId meterId,
744 int techProfId) {
alshabib4ceaed32016-03-03 18:00:58 -0800745 TrafficSelector downstream = DefaultTrafficSelector.builder()
746 .matchVlanId(deviceVlan)
747 .matchInPort(uplinkPort)
748 .matchInnerVlanId(subscriberVlan)
749 .build();
750
Gamze Abaka641fc072018-09-04 09:16:27 +0000751 TrafficTreatment.Builder downstreamTreatmentBuilder = DefaultTrafficTreatment.builder()
alshabib4ceaed32016-03-03 18:00:58 -0800752 .popVlan()
753 .setVlanId(defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan)))
Gamze Abaka641fc072018-09-04 09:16:27 +0000754 .setOutput(subscriberPort);
755
756 if (meterId != null) {
757 downstreamTreatmentBuilder.meter(meterId);
758 }
759
Gamze Abakaad329652018-12-20 10:12:21 +0000760 downstreamTreatmentBuilder.writeMetadata(createMetadata(subscriberVlan, techProfId, subscriberPort), 0);
alshabib4ceaed32016-03-03 18:00:58 -0800761
762 return DefaultForwardingObjective.builder()
763 .withFlag(ForwardingObjective.Flag.VERSATILE)
764 .withPriority(1000)
765 .makePermanent()
766 .withSelector(downstream)
767 .fromApp(appId)
Gamze Abaka641fc072018-09-04 09:16:27 +0000768 .withTreatment(downstreamTreatmentBuilder.build());
alshabib4ceaed32016-03-03 18:00:58 -0800769 }
770
771 private ForwardingObjective.Builder upBuilder(PortNumber uplinkPort,
772 PortNumber subscriberPort,
773 VlanId subscriberVlan,
774 VlanId deviceVlan,
Gamze Abaka641fc072018-09-04 09:16:27 +0000775 Optional<VlanId> defaultVlan,
776 MeterId meterId,
777 int technologyProfileId) {
778
779
780 VlanId dVlan = defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan));
781
782 if (subscriberVlan.toShort() == 4096) {
783 dVlan = subscriberVlan;
784 }
785
alshabib4ceaed32016-03-03 18:00:58 -0800786 TrafficSelector upstream = DefaultTrafficSelector.builder()
Gamze Abaka641fc072018-09-04 09:16:27 +0000787 .matchVlanId(dVlan)
alshabib4ceaed32016-03-03 18:00:58 -0800788 .matchInPort(subscriberPort)
789 .build();
790
791
Gamze Abaka641fc072018-09-04 09:16:27 +0000792 TrafficTreatment.Builder upstreamTreatmentBuilder = DefaultTrafficTreatment.builder()
alshabib4ceaed32016-03-03 18:00:58 -0800793 .pushVlan()
794 .setVlanId(subscriberVlan)
795 .pushVlan()
796 .setVlanId(deviceVlan)
Gamze Abaka641fc072018-09-04 09:16:27 +0000797 .setOutput(uplinkPort);
798
799 if (meterId != null) {
800 upstreamTreatmentBuilder.meter(meterId);
801 }
802
Gamze Abakaad329652018-12-20 10:12:21 +0000803 upstreamTreatmentBuilder.writeMetadata(createMetadata(deviceVlan, technologyProfileId, uplinkPort), 0L);
alshabib4ceaed32016-03-03 18:00:58 -0800804
805 return DefaultForwardingObjective.builder()
806 .withFlag(ForwardingObjective.Flag.VERSATILE)
807 .withPriority(1000)
808 .makePermanent()
809 .withSelector(upstream)
810 .fromApp(appId)
Gamze Abaka641fc072018-09-04 09:16:27 +0000811 .withTreatment(upstreamTreatmentBuilder.build());
alshabib4ceaed32016-03-03 18:00:58 -0800812 }
Gamze Abakaad329652018-12-20 10:12:21 +0000813
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100814 private void provisionTransparentFlows(DeviceId deviceId, PortNumber uplinkPort,
815 PortNumber subscriberPort,
816 VlanId innerVlan,
817 VlanId outerVlan) {
818
819 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
820 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
821
822 ForwardingObjective.Builder upFwd = transparentUpBuilder(uplinkPort, subscriberPort,
823 innerVlan, outerVlan);
824
825
826 ForwardingObjective.Builder downFwd = transparentDownBuilder(uplinkPort, subscriberPort,
827 innerVlan, outerVlan);
828
829 ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
830
831 additionalVlans.put(cp, new AbstractMap.SimpleEntry(outerVlan, innerVlan));
832
833 flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
834 @Override
835 public void onSuccess(Objective objective) {
836 upFuture.complete(null);
837 }
838
839 @Override
840 public void onError(Objective objective, ObjectiveError error) {
841 upFuture.complete(error);
842 }
843 }));
844
845 flowObjectiveService.forward(deviceId, downFwd.add(new ObjectiveContext() {
846 @Override
847 public void onSuccess(Objective objective) {
848 downFuture.complete(null);
849 }
850
851 @Override
852 public void onError(Objective objective, ObjectiveError error) {
853 downFuture.complete(error);
854 }
855 }));
856
857 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
858 if (downStatus != null) {
859 log.error("Flow with innervlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000860 "on port {} failed downstream installation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100861 innerVlan, outerVlan, deviceId, subscriberPort, downStatus);
862 } else if (upStatus != null) {
863 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000864 "on port {} failed upstream installation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100865 innerVlan, outerVlan, deviceId, subscriberPort, upStatus);
866 }
867 }, oltInstallers);
868
869 }
870
871 private ForwardingObjective.Builder transparentDownBuilder(PortNumber uplinkPort,
872 PortNumber subscriberPort,
873 VlanId innerVlan,
874 VlanId outerVlan) {
875 TrafficSelector downstream = DefaultTrafficSelector.builder()
876 .matchVlanId(outerVlan)
877 .matchInPort(uplinkPort)
878 .matchInnerVlanId(innerVlan)
879 .build();
880
881 TrafficTreatment downstreamTreatment = DefaultTrafficTreatment.builder()
882 .setOutput(subscriberPort)
883 .build();
884
885 return DefaultForwardingObjective.builder()
886 .withFlag(ForwardingObjective.Flag.VERSATILE)
887 .withPriority(1000)
888 .makePermanent()
889 .withSelector(downstream)
890 .fromApp(appId)
891 .withTreatment(downstreamTreatment);
892 }
893
894 private ForwardingObjective.Builder transparentUpBuilder(PortNumber uplinkPort,
895 PortNumber subscriberPort,
896 VlanId innerVlan,
897 VlanId outerVlan) {
898 TrafficSelector upstream = DefaultTrafficSelector.builder()
899 .matchVlanId(outerVlan)
900 .matchInPort(subscriberPort)
901 .matchInnerVlanId(innerVlan)
902 .build();
903
904 TrafficTreatment upstreamTreatment = DefaultTrafficTreatment.builder()
905 .setOutput(uplinkPort)
906 .build();
907
908 return DefaultForwardingObjective.builder()
909 .withFlag(ForwardingObjective.Flag.VERSATILE)
910 .withPriority(1000)
911 .makePermanent()
912 .withSelector(upstream)
913 .fromApp(appId)
914 .withTreatment(upstreamTreatment);
915 }
916
917 private void unprovisionTransparentFlows(DeviceId deviceId, PortNumber uplink,
918 PortNumber subscriberPort, VlanId innerVlan,
919 VlanId outerVlan) {
920
921 ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
922
923 additionalVlans.remove(cp, new AbstractMap.SimpleEntry(outerVlan, innerVlan));
924
925 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
926 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
927
928 ForwardingObjective.Builder upFwd = transparentUpBuilder(uplink, subscriberPort,
929 innerVlan, outerVlan);
930 ForwardingObjective.Builder downFwd = transparentDownBuilder(uplink, subscriberPort,
931 innerVlan, outerVlan);
932
933
934 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
935 @Override
936 public void onSuccess(Objective objective) {
937 upFuture.complete(null);
938 }
939
940 @Override
941 public void onError(Objective objective, ObjectiveError error) {
942 upFuture.complete(error);
943 }
944 }));
945
946 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
947 @Override
948 public void onSuccess(Objective objective) {
949 downFuture.complete(null);
950 }
951
952 @Override
953 public void onError(Objective objective, ObjectiveError error) {
954 downFuture.complete(error);
955 }
956 }));
957
958 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
959 if (downStatus != null) {
960 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000961 "on port {} failed downstream uninstallation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100962 innerVlan, outerVlan, deviceId, subscriberPort, downStatus);
963 } else if (upStatus != null) {
964 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000965 "on port {} failed upstream uninstallation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100966 innerVlan, outerVlan, deviceId, subscriberPort, upStatus);
967 }
968 }, oltInstallers);
969
970 }
971
Gamze Abaka1efc80c2019-02-15 12:10:54 +0000972 private int getDefaultTechProfileId(DeviceId devId, PortNumber portNumber) {
973 Port port = deviceService.getPort(devId, portNumber);
974 SubscriberAndDeviceInformation info = subsService.get(port.annotations().value(AnnotationKeys.PORT_NAME));
975 if (info != null && info.technologyProfileId() != -1) {
976 return info.technologyProfileId();
977 }
978 return defaultTechProfileId;
979 }
980
Gamze Abaka838d8142019-02-21 07:06:55 +0000981 /**
982 * Returns the write metadata value including only tech profile reference.
983 *
984 * @param techProfileId tech profile id of one subscriber
985 * @return the write metadata value including only tech profile reference
986 */
987 private Long createTechProfValueForWm(int techProfileId) {
988 return (long) techProfileId << 32;
989 }
990
991 /**
992 * Trap eapol authentication packets to the controller.
993 *
994 * @param devId the device identifier
995 * @param portNumber the port for which this trap flow is designated
996 * @param bpId bandwidth profile id to add the related meter to the flow
997 * @param install true to install the flow, false to remove the flow
998 */
999 private void processEapolFilteringObjectives(DeviceId devId, PortNumber portNumber, String bpId, boolean install) {
alshabib09753b52016-03-04 14:55:19 -08001000 if (!mastershipService.isLocalMaster(devId)) {
1001 return;
1002 }
alshabibbb83aa22016-02-10 15:08:23 -08001003 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Gamze Abakaad329652018-12-20 10:12:21 +00001004 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
Gamze Abaka838d8142019-02-21 07:06:55 +00001005 MeterId meterId;
alshabibbb83aa22016-02-10 15:08:23 -08001006
Gamze Abaka838d8142019-02-21 07:06:55 +00001007 BandwidthProfileInformation bpInfo = getBandwidthProfileInformation(bpId);
1008 if (bpInfo != null) {
1009 meterId = createMeter(devId, bpInfo);
Gamze Abakaad329652018-12-20 10:12:21 +00001010 treatmentBuilder.meter(meterId);
1011 } else {
Gamze Abaka838d8142019-02-21 07:06:55 +00001012 log.warn("Bandwidth profile {} is not found. Authentication flow will not be installed", bpId);
1013 return;
Gamze Abakaad329652018-12-20 10:12:21 +00001014 }
1015
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001016 int techProfileId = getDefaultTechProfileId(devId, portNumber);
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001017
1018 //Authentication trap flow uses only tech profile id as write metadata value
alshabibbb83aa22016-02-10 15:08:23 -08001019 FilteringObjective eapol = (install ? builder.permit() : builder.deny())
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001020 .withKey(Criteria.matchInPort(portNumber))
alshabibdec2e252016-01-15 12:20:25 -08001021 .addCondition(Criteria.matchEthType(EthType.EtherType.EAPOL.ethType()))
Gamze Abakaad329652018-12-20 10:12:21 +00001022 .withMeta(treatmentBuilder
Gamze Abaka838d8142019-02-21 07:06:55 +00001023 .writeMetadata(createTechProfValueForWm(techProfileId), 0)
Gamze Abaka641fc072018-09-04 09:16:27 +00001024 .setOutput(PortNumber.CONTROLLER).build())
alshabibdec2e252016-01-15 12:20:25 -08001025 .fromApp(appId)
Matt Jeanneret3f579262018-06-14 17:16:23 -04001026 .withPriority(10000)
alshabibdec2e252016-01-15 12:20:25 -08001027 .add(new ObjectiveContext() {
1028 @Override
1029 public void onSuccess(Objective objective) {
Gamze Abaka838d8142019-02-21 07:06:55 +00001030 log.info("Eapol filter for {} on {} {} with meter {}.",
1031 devId, portNumber, (install) ? INSTALLED : REMOVED, meterId);
alshabibdec2e252016-01-15 12:20:25 -08001032 }
1033
1034 @Override
1035 public void onError(Objective objective, ObjectiveError error) {
Gamze Abaka838d8142019-02-21 07:06:55 +00001036 log.info("Eapol filter for {} on {} with meter {} failed {} because {}",
1037 devId, portNumber, meterId, (install) ? INSTALLATION : REMOVAL,
Gamze Abaka641fc072018-09-04 09:16:27 +00001038 error);
alshabibdec2e252016-01-15 12:20:25 -08001039 }
1040 });
1041
alshabibdec2e252016-01-15 12:20:25 -08001042 flowObjectiveService.filter(devId, eapol);
alshabib000b6fc2016-02-01 17:25:00 -08001043
alshabibdec2e252016-01-15 12:20:25 -08001044 }
1045
Jonathan Hart403372d2018-08-22 11:44:13 -07001046 /**
1047 * Installs trap filtering objectives for particular traffic types on an
1048 * NNI port.
1049 *
Gamze Abakaad329652018-12-20 10:12:21 +00001050 * @param devId device ID
1051 * @param port port number
Jonathan Hart403372d2018-08-22 11:44:13 -07001052 * @param install true to install, false to remove
1053 */
1054 private void processNniFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
1055 processLldpFilteringObjective(devId, port, install);
Matteo Scandolo63460d12018-11-02 16:19:04 -07001056 if (enableDhcpOnProvisioning) {
Gamze Abaka838d8142019-02-21 07:06:55 +00001057 processDhcpFilteringObjectives(devId, port, null, -1, install, false);
Matteo Scandolo63460d12018-11-02 16:19:04 -07001058 }
Jonathan Hart403372d2018-08-22 11:44:13 -07001059 }
1060
1061 private void processLldpFilteringObjective(DeviceId devId, PortNumber port, boolean install) {
1062 if (!mastershipService.isLocalMaster(devId)) {
1063 return;
1064 }
1065 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
1066
1067 FilteringObjective lldp = (install ? builder.permit() : builder.deny())
1068 .withKey(Criteria.matchInPort(port))
1069 .addCondition(Criteria.matchEthType(EthType.EtherType.LLDP.ethType()))
1070 .withMeta(DefaultTrafficTreatment.builder()
1071 .setOutput(PortNumber.CONTROLLER).build())
1072 .fromApp(appId)
1073 .withPriority(10000)
1074 .add(new ObjectiveContext() {
1075 @Override
1076 public void onSuccess(Objective objective) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001077 log.info("LLDP filter for device {} on port {} {}.",
Gamze Abaka838d8142019-02-21 07:06:55 +00001078 devId, port, (install) ? INSTALLED : REMOVED);
Jonathan Hart403372d2018-08-22 11:44:13 -07001079 }
1080
1081 @Override
1082 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001083 log.info("LLDP filter for device {} on port {} failed {} because {}",
Gamze Abaka838d8142019-02-21 07:06:55 +00001084 devId, port, (install) ? INSTALLATION : REMOVAL,
Saurav Das82b8e6d2018-10-04 15:25:12 -07001085 error);
Jonathan Hart403372d2018-08-22 11:44:13 -07001086 }
1087 });
1088
1089 flowObjectiveService.filter(devId, lldp);
1090
1091 }
1092
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001093 /**
1094 * Trap dhcp packets to the controller.
1095 *
Gamze Abaka838d8142019-02-21 07:06:55 +00001096 * @param devId the device identifier
1097 * @param port the port for which this trap flow is designated
1098 * @param upstreamMeterId the upstream meter id that includes the upstream
1099 * bandwidth profile values such as PIR,CIR. If no meter id needs to be referenced,
1100 * null can be sent
1101 * @param techProfileId the technology profile id that is used to create write
1102 * metadata instruction value. If no tech profile id needs to be referenced,
1103 * -1 can be sent
1104 * @param install true to install the flow, false to remove the flow
1105 * @param upstream true if trapped packets are flowing upstream towards
1106 * server, false if packets are flowing downstream towards client
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001107 */
1108 private void processDhcpFilteringObjectives(DeviceId devId, PortNumber port,
Gamze Abaka838d8142019-02-21 07:06:55 +00001109 MeterId upstreamMeterId,
1110 int techProfileId,
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001111 boolean install,
1112 boolean upstream) {
Amit Ghosh95e2f652017-08-23 12:49:46 +01001113 if (!mastershipService.isLocalMaster(devId)) {
1114 return;
1115 }
Amit Ghosh95e2f652017-08-23 12:49:46 +01001116
Matteo Scandolo63460d12018-11-02 16:19:04 -07001117 if (enableDhcpV4) {
1118 int udpSrc = (upstream) ? 68 : 67;
1119 int udpDst = (upstream) ? 67 : 68;
1120
1121 EthType ethType = EthType.EtherType.IPV4.ethType();
1122 byte protocol = IPv4.PROTOCOL_UDP;
1123
Gamze Abaka838d8142019-02-21 07:06:55 +00001124 this.addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType,
1125 upstreamMeterId, techProfileId, protocol, install);
Matteo Scandolo63460d12018-11-02 16:19:04 -07001126 }
1127
1128 if (enableDhcpV6) {
1129 int udpSrc = (upstream) ? 547 : 546;
1130 int udpDst = (upstream) ? 546 : 547;
1131
1132 EthType ethType = EthType.EtherType.IPV6.ethType();
1133 byte protocol = IPv6.PROTOCOL_UDP;
1134
Gamze Abaka838d8142019-02-21 07:06:55 +00001135 this.addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType,
1136 upstreamMeterId, techProfileId, protocol, install);
Matteo Scandolo63460d12018-11-02 16:19:04 -07001137 }
1138
1139 }
1140
1141 private void addDhcpFilteringObjectives(DeviceId devId,
1142 PortNumber port,
1143 int udpSrc,
1144 int udpDst,
1145 EthType ethType,
Gamze Abaka838d8142019-02-21 07:06:55 +00001146 MeterId upstreamMeterId,
1147 int techProfileId,
Matteo Scandolo63460d12018-11-02 16:19:04 -07001148 byte protocol,
1149 boolean install) {
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001150
1151 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Gamze Abaka838d8142019-02-21 07:06:55 +00001152 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
1153
1154 if (upstreamMeterId != null) {
1155 treatmentBuilder.meter(upstreamMeterId);
1156 }
1157
1158 if (techProfileId != -1) {
1159 treatmentBuilder.writeMetadata(createTechProfValueForWm(techProfileId), 0);
1160 }
1161
Amit Ghosh95e2f652017-08-23 12:49:46 +01001162 FilteringObjective dhcpUpstream = (install ? builder.permit() : builder.deny())
1163 .withKey(Criteria.matchInPort(port))
Matteo Scandolo63460d12018-11-02 16:19:04 -07001164 .addCondition(Criteria.matchEthType(ethType))
1165 .addCondition(Criteria.matchIPProtocol(protocol))
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001166 .addCondition(Criteria.matchUdpSrc(TpPort.tpPort(udpSrc)))
1167 .addCondition(Criteria.matchUdpDst(TpPort.tpPort(udpDst)))
Gamze Abaka838d8142019-02-21 07:06:55 +00001168 .withMeta(treatmentBuilder
Gamze Abaka641fc072018-09-04 09:16:27 +00001169 .setOutput(PortNumber.CONTROLLER).build())
Amit Ghosh95e2f652017-08-23 12:49:46 +01001170 .fromApp(appId)
Matt Jeanneret3f579262018-06-14 17:16:23 -04001171 .withPriority(10000)
Amit Ghosh95e2f652017-08-23 12:49:46 +01001172 .add(new ObjectiveContext() {
1173 @Override
1174 public void onSuccess(Objective objective) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001175 log.info("DHCP {} filter for device {} on port {} {}.",
Gamze Abakaad329652018-12-20 10:12:21 +00001176 (ethType.equals(EthType.EtherType.IPV4.ethType())) ? "v4" : "v6",
Gamze Abaka838d8142019-02-21 07:06:55 +00001177 devId, port, (install) ? INSTALLED : REMOVED);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001178 }
1179
1180 @Override
1181 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001182 log.info("DHCP {} filter for device {} on port {} failed {} because {}",
Gamze Abakaad329652018-12-20 10:12:21 +00001183 (ethType.equals(EthType.EtherType.IPV4.ethType())) ? "v4" : "v6",
Gamze Abaka838d8142019-02-21 07:06:55 +00001184 devId, port, (install) ? INSTALLATION : REMOVAL,
Gamze Abakaad329652018-12-20 10:12:21 +00001185 error);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001186 }
1187 });
1188
1189 flowObjectiveService.filter(devId, dhcpUpstream);
1190 }
1191
Gamze Abaka838d8142019-02-21 07:06:55 +00001192 private void processIgmpFilteringObjectives(DeviceId devId, PortNumber port,
1193 MeterId upstreamMeterId,
1194 int techProfileId,
1195 boolean install) {
Amit Ghosh95e2f652017-08-23 12:49:46 +01001196 if (!mastershipService.isLocalMaster(devId)) {
1197 return;
1198 }
1199
Gamze Abaka641fc072018-09-04 09:16:27 +00001200 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Gamze Abaka838d8142019-02-21 07:06:55 +00001201 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
1202
1203 if (upstreamMeterId != null) {
1204 treatmentBuilder.meter(upstreamMeterId);
1205 }
1206
1207 if (techProfileId != -1) {
1208 treatmentBuilder.writeMetadata(createTechProfValueForWm(techProfileId), 0);
1209 }
Amit Ghosh95e2f652017-08-23 12:49:46 +01001210
1211 builder = install ? builder.permit() : builder.deny();
1212
1213 FilteringObjective igmp = builder
1214 .withKey(Criteria.matchInPort(port))
1215 .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
1216 .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_IGMP))
Gamze Abaka838d8142019-02-21 07:06:55 +00001217 .withMeta(treatmentBuilder
Gamze Abaka641fc072018-09-04 09:16:27 +00001218 .setOutput(PortNumber.CONTROLLER).build())
Amit Ghosh95e2f652017-08-23 12:49:46 +01001219 .fromApp(appId)
1220 .withPriority(10000)
1221 .add(new ObjectiveContext() {
1222 @Override
1223 public void onSuccess(Objective objective) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001224 log.info("Igmp filter for {} on {} {}.",
Gamze Abaka838d8142019-02-21 07:06:55 +00001225 devId, port, (install) ? INSTALLED : REMOVED);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001226 }
1227
1228 @Override
1229 public void onError(Objective objective, ObjectiveError error) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001230 log.info("Igmp filter for {} on {} failed {} because {}.",
Gamze Abaka838d8142019-02-21 07:06:55 +00001231 devId, port, (install) ? INSTALLATION : REMOVAL,
Gamze Abaka641fc072018-09-04 09:16:27 +00001232 error);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001233 }
1234 });
1235
1236 flowObjectiveService.filter(devId, igmp);
1237 }
1238
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001239 /**
Jonathan Hart403372d2018-08-22 11:44:13 -07001240 * Creates trap flows for device, including DHCP and LLDP trap on NNI and
1241 * EAPOL trap on the UNIs, if device is present in Sadis config.
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001242 *
1243 * @param dev Device to look for
1244 */
Jonathan Hart403372d2018-08-22 11:44:13 -07001245 private void checkAndCreateDeviceFlows(Device dev) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001246 // we create only for the ones we are master of
1247 if (!mastershipService.isLocalMaster(dev.id())) {
Gamze Abaka641fc072018-09-04 09:16:27 +00001248 return;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001249 }
1250 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +00001251 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Jonathan Hart403372d2018-08-22 11:44:13 -07001252 log.debug("checkAndCreateDeviceFlows: deviceInfo {}", deviceInfo);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001253
1254 if (deviceInfo != null) {
Jonathan Hart403372d2018-08-22 11:44:13 -07001255 // This is an OLT device as per Sadis, we create flows for UNI and NNI ports
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001256 for (Port p : deviceService.getPorts(dev.id())) {
1257 if (isUniPort(dev, p)) {
Gamze Abaka838d8142019-02-21 07:06:55 +00001258 processEapolFilteringObjectives(dev.id(), p.number(), defaultBpId, true);
Jonathan Hart403372d2018-08-22 11:44:13 -07001259 } else {
1260 processNniFilteringObjectives(dev.id(), p.number(), true);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001261 }
1262 }
1263 }
1264 }
1265
Jonathan Hart403372d2018-08-22 11:44:13 -07001266
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001267 /**
1268 * Get the uplink for of the OLT device.
Gamze Abakaad329652018-12-20 10:12:21 +00001269 * <p>
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001270 * This assumes that the OLT has a single uplink port. When more uplink ports need to be supported
1271 * this logic needs to be changed
1272 *
1273 * @param dev Device to look for
1274 * @return The uplink Port of the OLT
1275 */
1276 private Port getUplinkPort(Device dev) {
1277 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +00001278 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001279 log.debug("getUplinkPort: deviceInfo {}", deviceInfo);
Saurav Das82b8e6d2018-10-04 15:25:12 -07001280 if (deviceInfo == null) {
1281 log.warn("Device {} is not configured in SADIS .. cannot fetch device"
1282 + " info", dev.id());
1283 return null;
1284 }
1285 // Return the port that has been configured as the uplink port of this OLT in Sadis
Gamze Abakaad329652018-12-20 10:12:21 +00001286 for (Port p : deviceService.getPorts(dev.id())) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001287 if (p.number().toLong() == deviceInfo.uplinkPort()) {
1288 log.debug("getUplinkPort: Found port {}", p);
1289 return p;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001290 }
1291 }
1292
Gamze Abaka838d8142019-02-21 07:06:55 +00001293 log.debug("getUplinkPort: " + NO_UPLINK_PORT, dev.id());
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001294 return null;
1295 }
1296
1297 /**
1298 * Return the subscriber on a port.
1299 *
Matteo Scandolo962a6ad2018-12-11 15:39:42 -08001300 * @param cp ConnectPoint on which to find the subscriber
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001301 * @return subscriber if found else null
1302 */
Matteo Scandolo962a6ad2018-12-11 15:39:42 -08001303 SubscriberAndDeviceInformation getSubscriber(ConnectPoint cp) {
1304 Port port = deviceService.getPort(cp);
1305 checkNotNull(port, "Invalid connect point");
1306 String portName = port.annotations().value(AnnotationKeys.PORT_NAME);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001307 return subsService.get(portName);
1308 }
1309
Gamze Abakaad329652018-12-20 10:12:21 +00001310 /**
1311 * Write metadata instruction value (metadata) is 8 bytes.
Gamze Abaka838d8142019-02-21 07:06:55 +00001312 * <p>
Gamze Abakaad329652018-12-20 10:12:21 +00001313 * MS 2 bytes: C Tag
1314 * Next 2 bytes: Technology Profile Id
1315 * Next 4 bytes: Port number (uni or nni)
1316 */
1317
1318 private Long createMetadata(VlanId innerVlan, int techProfileId, PortNumber egressPort) {
1319
1320 if (techProfileId == -1) {
1321 techProfileId = DEFAULT_TP_ID;
1322 }
1323
1324 return ((long) (innerVlan.id()) << 48 | (long) techProfileId << 32) | egressPort.toLong();
1325 }
1326
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001327 private boolean isUniPort(Device d, Port p) {
1328 Port ulPort = getUplinkPort(d);
1329 if (ulPort != null) {
1330 return (ulPort.number().toLong() != p.number().toLong());
1331 }
1332 return false;
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001333 }
1334
Jonathan Hart4c538002018-08-23 10:11:54 -07001335 private SubscriberAndDeviceInformation getOltInfo(Device dev) {
1336 String devSerialNo = dev.serialNumber();
Gamze Abaka641fc072018-09-04 09:16:27 +00001337 return subsService.get(devSerialNo);
Jonathan Hart4c538002018-08-23 10:11:54 -07001338 }
1339
alshabibf0e7e702015-05-30 18:22:36 -07001340 private class InternalDeviceListener implements DeviceListener {
1341 @Override
1342 public void event(DeviceEvent event) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001343 eventExecutor.execute(() -> {
1344 DeviceId devId = event.subject().id();
1345 Device dev = event.subject();
Gamze Abaka838d8142019-02-21 07:06:55 +00001346 Port port = event.port();
Jonathan Hart4c538002018-08-23 10:11:54 -07001347
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001348 if (event.type() == DeviceEvent.Type.PORT_STATS_UPDATED) {
1349 return;
1350 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001351
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001352 if (getOltInfo(dev) == null) {
1353 log.debug("No device info found, this is not an OLT");
1354 return;
1355 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001356
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001357 log.debug("OLT got {} event for {}", event.type(), event.subject());
Jonathan Hart4c538002018-08-23 10:11:54 -07001358
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001359 switch (event.type()) {
1360 //TODO: Port handling and bookkeeping should be improved once
1361 // olt firmware handles correct behaviour.
1362 case PORT_ADDED:
Gamze Abaka838d8142019-02-21 07:06:55 +00001363 if (isUniPort(dev, port)) {
1364 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, port));
Jonathan Hart4c538002018-08-23 10:11:54 -07001365
Gamze Abaka838d8142019-02-21 07:06:55 +00001366 if (port.isEnabled()) {
1367 processEapolFilteringObjectives(devId, port.number(), defaultBpId, true);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001368 }
1369 } else {
1370 checkAndCreateDeviceFlows(dev);
1371 }
1372 break;
1373 case PORT_REMOVED:
Gamze Abaka838d8142019-02-21 07:06:55 +00001374 if (isUniPort(dev, port)) {
1375 if (port.isEnabled()) {
1376 processEapolFilteringObjectives(devId, port.number(),
1377 getCurrentBandwidthProfile(new ConnectPoint(devId, port.number())),
1378 false);
1379 removeSubscriber(new ConnectPoint(devId, port.number()));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001380 }
1381
Gamze Abaka838d8142019-02-21 07:06:55 +00001382 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, port));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001383 }
1384
1385 break;
1386 case PORT_UPDATED:
Gamze Abaka838d8142019-02-21 07:06:55 +00001387 if (!isUniPort(dev, port)) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001388 break;
1389 }
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001390
Gamze Abaka838d8142019-02-21 07:06:55 +00001391 if (port.isEnabled()) {
1392 processEapolFilteringObjectives(devId, port.number(), defaultBpId, true);
1393 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, port));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001394 } else {
Gamze Abaka838d8142019-02-21 07:06:55 +00001395 processEapolFilteringObjectives(devId, port.number(),
1396 getCurrentBandwidthProfile(new ConnectPoint(devId, port.number())),
1397 false);
1398 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, port));
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001399 }
alshabibbb83aa22016-02-10 15:08:23 -08001400 break;
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001401 case DEVICE_ADDED:
alshabib7c190012016-02-09 18:22:33 -08001402 post(new AccessDeviceEvent(
1403 AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
1404 null, null));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001405
1406 // Send UNI_ADDED events for all existing ports
1407 deviceService.getPorts(devId).stream()
1408 .filter(p -> isUniPort(dev, p))
1409 .filter(Port::isEnabled)
1410 .forEach(p -> post(new AccessDeviceEvent(
1411 AccessDeviceEvent.Type.UNI_ADDED, devId, p)));
1412
Jonathan Hart403372d2018-08-22 11:44:13 -07001413 checkAndCreateDeviceFlows(dev);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001414 break;
1415 case DEVICE_REMOVED:
1416 deviceService.getPorts(devId).stream()
1417 .filter(p -> isUniPort(dev, p))
1418 .forEach(p -> post(new AccessDeviceEvent(
1419 AccessDeviceEvent.Type.UNI_REMOVED, devId, p)));
1420
alshabib7c190012016-02-09 18:22:33 -08001421 post(new AccessDeviceEvent(
1422 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
1423 null, null));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001424 break;
1425 case DEVICE_AVAILABILITY_CHANGED:
1426 if (deviceService.isAvailable(devId)) {
1427 post(new AccessDeviceEvent(
1428 AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
1429 null, null));
1430 checkAndCreateDeviceFlows(dev);
1431 } else {
1432 post(new AccessDeviceEvent(
1433 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
1434 null, null));
1435 }
1436 break;
1437 case DEVICE_UPDATED:
1438 case DEVICE_SUSPENDED:
1439 case PORT_STATS_UPDATED:
1440 default:
1441 return;
1442 }
1443 });
alshabibf0e7e702015-05-30 18:22:36 -07001444 }
Gamze Abaka838d8142019-02-21 07:06:55 +00001445
1446 private String getCurrentBandwidthProfile(ConnectPoint connectPoint) {
1447 SubscriberAndDeviceInformation sub = programmedSubs.get(connectPoint);
1448 if (sub != null) {
1449 return sub.upstreamBandwidthProfile();
1450 }
1451 return defaultBpId;
1452 }
alshabibf0e7e702015-05-30 18:22:36 -07001453 }
Gamze Abaka641fc072018-09-04 09:16:27 +00001454
1455 private class InternalMeterListener implements MeterListener {
1456
1457 @Override
1458 public void event(MeterEvent meterEvent) {
1459 if (deleteMeters && MeterEvent.Type.METER_REFERENCE_COUNT_ZERO.equals(meterEvent.type())) {
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001460 log.info("Zero Count Meter Event is received. Meter is {}", meterEvent.subject());
Gamze Abaka641fc072018-09-04 09:16:27 +00001461 Meter meter = meterEvent.subject();
Gamze Abaka838d8142019-02-21 07:06:55 +00001462 if (meter != null && appId.equals(meter.appId()) && !programmedMeters.contains(meter.id())) {
Gamze Abaka641fc072018-09-04 09:16:27 +00001463 deleteMeter(meter.deviceId(), meter.id());
1464 }
1465 } else if (MeterEvent.Type.METER_REMOVED.equals(meterEvent.type())) {
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001466 log.info("Meter removed event is received. Meter is {}", meterEvent.subject());
Gamze Abaka641fc072018-09-04 09:16:27 +00001467 removeMeterFromBpMap(meterEvent.subject());
1468 }
1469 }
1470
1471 private void deleteMeter(DeviceId deviceId, MeterId meterId) {
1472 Meter meter = meterService.getMeter(deviceId, meterId);
Gamze Abaka838d8142019-02-21 07:06:55 +00001473 if (meter != null) {
1474 MeterRequest meterRequest = DefaultMeterRequest.builder()
1475 .withBands(meter.bands())
1476 .withUnit(meter.unit())
1477 .forDevice(deviceId)
1478 .fromApp(appId)
1479 .burst()
1480 .remove();
Gamze Abaka641fc072018-09-04 09:16:27 +00001481
Gamze Abaka838d8142019-02-21 07:06:55 +00001482 meterService.withdraw(meterRequest, meterId);
1483 }
Gamze Abaka641fc072018-09-04 09:16:27 +00001484
1485 }
1486
1487 private void removeMeterFromBpMap(Meter meter) {
1488 for (Map.Entry<String, MeterId> entry : bpInfoToMeter.entrySet()) {
1489 if (entry.getValue().equals(meter.id())) {
1490 bpInfoToMeter.remove(entry.getKey());
1491 log.info("Deleted from the internal map. Profile {} and Meter {}", entry.getKey(), meter.id());
1492 break;
1493 }
1494 }
1495 }
1496 }
1497}