blob: 0aaa8bf056f3207bb4d77af73a72648aa0ec93d3 [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
Carmelo Casconeca931162019-07-15 18:22:24 -070018import com.google.common.collect.ImmutableMap;
19import com.google.common.collect.ImmutableSet;
20import com.google.common.collect.Maps;
21import com.google.common.collect.Sets;
alshabibdec2e252016-01-15 12:20:25 -080022import org.onlab.packet.EthType;
Amit Ghosh95e2f652017-08-23 12:49:46 +010023import org.onlab.packet.IPv4;
Matteo Scandolo63460d12018-11-02 16:19:04 -070024import org.onlab.packet.IPv6;
Amit Ghosh95e2f652017-08-23 12:49:46 +010025import org.onlab.packet.TpPort;
alshabibf0e7e702015-05-30 18:22:36 -070026import org.onlab.packet.VlanId;
Amit Ghosh95e2f652017-08-23 12:49:46 +010027import org.onlab.util.Tools;
alshabibe0559672016-02-21 14:49:51 -080028import org.onosproject.cfg.ComponentConfigService;
alshabibf0e7e702015-05-30 18:22:36 -070029import org.onosproject.core.ApplicationId;
30import org.onosproject.core.CoreService;
alshabib8e4fd2f2016-01-12 15:55:53 -080031import org.onosproject.event.AbstractListenerManager;
alshabib09753b52016-03-04 14:55:19 -080032import org.onosproject.mastership.MastershipService;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010033import org.onosproject.net.AnnotationKeys;
Jonathan Harte533a422015-10-20 17:31:24 -070034import org.onosproject.net.ConnectPoint;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010035import org.onosproject.net.Device;
alshabibf0e7e702015-05-30 18:22:36 -070036import org.onosproject.net.DeviceId;
alshabibdec2e252016-01-15 12:20:25 -080037import org.onosproject.net.Port;
alshabibf0e7e702015-05-30 18:22:36 -070038import org.onosproject.net.PortNumber;
39import org.onosproject.net.device.DeviceEvent;
40import org.onosproject.net.device.DeviceListener;
41import org.onosproject.net.device.DeviceService;
42import org.onosproject.net.flow.DefaultTrafficSelector;
43import org.onosproject.net.flow.DefaultTrafficTreatment;
44import org.onosproject.net.flow.TrafficSelector;
45import org.onosproject.net.flow.TrafficTreatment;
alshabibdec2e252016-01-15 12:20:25 -080046import org.onosproject.net.flow.criteria.Criteria;
47import org.onosproject.net.flowobjective.DefaultFilteringObjective;
alshabibf0e7e702015-05-30 18:22:36 -070048import org.onosproject.net.flowobjective.DefaultForwardingObjective;
alshabibdec2e252016-01-15 12:20:25 -080049import org.onosproject.net.flowobjective.FilteringObjective;
alshabibf0e7e702015-05-30 18:22:36 -070050import org.onosproject.net.flowobjective.FlowObjectiveService;
51import org.onosproject.net.flowobjective.ForwardingObjective;
alshabib3ea82642016-01-12 18:06:53 -080052import org.onosproject.net.flowobjective.Objective;
53import org.onosproject.net.flowobjective.ObjectiveContext;
54import org.onosproject.net.flowobjective.ObjectiveError;
Gamze Abaka33feef52019-02-27 08:16:47 +000055import org.onosproject.net.meter.Band;
56import org.onosproject.net.meter.DefaultBand;
57import org.onosproject.net.meter.DefaultMeterRequest;
58import org.onosproject.net.meter.Meter;
59import org.onosproject.net.meter.MeterContext;
Saurav Daseae48de2019-06-19 13:26:15 -070060import org.onosproject.net.meter.MeterEvent;
Gamze Abaka33feef52019-02-27 08:16:47 +000061import org.onosproject.net.meter.MeterFailReason;
Saurav Daseae48de2019-06-19 13:26:15 -070062import org.onosproject.net.meter.MeterId;
Gamze Abaka33feef52019-02-27 08:16:47 +000063import org.onosproject.net.meter.MeterKey;
Gamze Abaka33feef52019-02-27 08:16:47 +000064import org.onosproject.net.meter.MeterListener;
65import org.onosproject.net.meter.MeterRequest;
Saurav Daseae48de2019-06-19 13:26:15 -070066import org.onosproject.net.meter.MeterService;
67import org.onosproject.store.serializers.KryoNamespaces;
68import org.onosproject.store.service.ConsistentMultimap;
69import org.onosproject.store.service.Serializer;
70import org.onosproject.store.service.StorageService;
alshabib36a4d732016-06-01 16:03:59 -070071import org.opencord.olt.AccessDeviceEvent;
72import org.opencord.olt.AccessDeviceListener;
73import org.opencord.olt.AccessDeviceService;
Amit Ghosh31939522018-08-16 13:28:21 +010074import org.opencord.olt.AccessSubscriberId;
Gamze Abaka641fc072018-09-04 09:16:27 +000075import org.opencord.sadis.BandwidthProfileInformation;
76import org.opencord.sadis.BaseInformationService;
77import org.opencord.sadis.SadisService;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010078import org.opencord.sadis.SubscriberAndDeviceInformation;
alshabibe0559672016-02-21 14:49:51 -080079import org.osgi.service.component.ComponentContext;
Carmelo Casconeca931162019-07-15 18:22:24 -070080import org.osgi.service.component.annotations.Activate;
81import org.osgi.service.component.annotations.Component;
82import org.osgi.service.component.annotations.Deactivate;
83import org.osgi.service.component.annotations.Modified;
84import org.osgi.service.component.annotations.Reference;
85import org.osgi.service.component.annotations.ReferenceCardinality;
alshabibf0e7e702015-05-30 18:22:36 -070086import org.slf4j.Logger;
87
Carmelo Casconeca931162019-07-15 18:22:24 -070088import java.util.AbstractMap;
89import java.util.ArrayList;
90import java.util.Arrays;
91import java.util.Collection;
92import java.util.Dictionary;
93import java.util.List;
94import java.util.Map;
95import java.util.Objects;
96import java.util.Optional;
97import java.util.Properties;
98import java.util.Set;
99import java.util.concurrent.CompletableFuture;
100import java.util.concurrent.ConcurrentHashMap;
101import java.util.concurrent.ExecutorService;
102import java.util.concurrent.Executors;
103import java.util.stream.Collectors;
104
105import static com.google.common.base.Preconditions.checkNotNull;
106import static com.google.common.base.Strings.isNullOrEmpty;
107import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
108import static org.onlab.util.Tools.get;
109import static org.onlab.util.Tools.groupedThreads;
110import static org.opencord.olt.impl.OsgiPropertyConstants.DEFAULT_BP_ID;
111import static org.opencord.olt.impl.OsgiPropertyConstants.DEFAULT_BP_ID_DEFAULT;
112import static org.opencord.olt.impl.OsgiPropertyConstants.DEFAULT_TP_ID;
113import static org.opencord.olt.impl.OsgiPropertyConstants.DEFAULT_TP_ID_DEFAULT;
114import static org.opencord.olt.impl.OsgiPropertyConstants.DEFAULT_VLAN;
115import static org.opencord.olt.impl.OsgiPropertyConstants.DEFAULT_VLAN_DEFAULT;
116import static org.opencord.olt.impl.OsgiPropertyConstants.DELETE_METERS;
117import static org.opencord.olt.impl.OsgiPropertyConstants.DELETE_METERS_DEFAULT;
118import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_DHCP_ON_PROVISIONING;
119import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_DHCP_ON_PROVISIONING_DEFAULT;
120import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_DHCP_V4;
121import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_DHCP_V4_DEFAULT;
122import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_DHCP_V6;
123import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_DHCP_V6_DEFAULT;
124import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_EAPOL;
125import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_EAPOL_DEFAULT;
126import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_IGMP_ON_PROVISIONING;
127import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_IGMP_ON_PROVISIONING_DEFAULT;
128import static org.slf4j.LoggerFactory.getLogger;
alshabibf0e7e702015-05-30 18:22:36 -0700129
130/**
Jonathan Harte533a422015-10-20 17:31:24 -0700131 * Provisions rules on access devices.
alshabibf0e7e702015-05-30 18:22:36 -0700132 */
Carmelo Casconeca931162019-07-15 18:22:24 -0700133@Component(immediate = true,
134 property = {
135 DEFAULT_VLAN + ":Integer=" + DEFAULT_VLAN_DEFAULT,
136 ENABLE_DHCP_ON_PROVISIONING + ":Boolean=" + ENABLE_DHCP_ON_PROVISIONING_DEFAULT,
137 ENABLE_DHCP_V4 + ":Boolean=" + ENABLE_DHCP_V4_DEFAULT,
138 ENABLE_DHCP_V6 + ":Boolean=" + ENABLE_DHCP_V6_DEFAULT,
139 ENABLE_IGMP_ON_PROVISIONING + ":Boolean=" + ENABLE_IGMP_ON_PROVISIONING_DEFAULT,
140 DELETE_METERS + ":Boolean=" + DELETE_METERS_DEFAULT,
141 DEFAULT_TP_ID + ":Integer=" + DEFAULT_TP_ID_DEFAULT,
142 DEFAULT_BP_ID + ":String=" + DEFAULT_BP_ID_DEFAULT,
143 ENABLE_EAPOL + ":Boolean=" + ENABLE_EAPOL_DEFAULT,
144 })
alshabib8e4fd2f2016-01-12 15:55:53 -0800145public class Olt
146 extends AbstractListenerManager<AccessDeviceEvent, AccessDeviceListener>
147 implements AccessDeviceService {
Charles Chan54f110f2017-01-20 11:22:42 -0800148 private static final String APP_NAME = "org.opencord.olt";
alshabibe0559672016-02-21 14:49:51 -0800149
Gamze Abakada282b42019-03-11 13:16:48 +0000150 private static final short EAPOL_DEFAULT_VLAN = 4091;
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100151 private static final String ADDITIONAL_VLANS = "additional-vlans";
Gamze Abaka838d8142019-02-21 07:06:55 +0000152 private static final String NO_UPLINK_PORT = "No uplink port found for OLT device {}";
153 private static final String INSTALLED = "installed";
154 private static final String REMOVED = "removed";
155 private static final String INSTALLATION = "installation";
156 private static final String REMOVAL = "removal";
alshabibe0559672016-02-21 14:49:51 -0800157
alshabibf0e7e702015-05-30 18:22:36 -0700158 private final Logger log = getLogger(getClass());
159
Carmelo Casconeca931162019-07-15 18:22:24 -0700160 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabibf0e7e702015-05-30 18:22:36 -0700161 protected FlowObjectiveService flowObjectiveService;
162
Carmelo Casconeca931162019-07-15 18:22:24 -0700163 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabib09753b52016-03-04 14:55:19 -0800164 protected MastershipService mastershipService;
165
Carmelo Casconeca931162019-07-15 18:22:24 -0700166 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabibf0e7e702015-05-30 18:22:36 -0700167 protected DeviceService deviceService;
168
Carmelo Casconeca931162019-07-15 18:22:24 -0700169 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabibf0e7e702015-05-30 18:22:36 -0700170 protected CoreService coreService;
171
Carmelo Casconeca931162019-07-15 18:22:24 -0700172 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabibe0559672016-02-21 14:49:51 -0800173 protected ComponentConfigService componentConfigService;
174
Carmelo Casconeca931162019-07-15 18:22:24 -0700175 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Gamze Abaka641fc072018-09-04 09:16:27 +0000176 protected SadisService sadisService;
177
Carmelo Casconeca931162019-07-15 18:22:24 -0700178 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Gamze Abaka641fc072018-09-04 09:16:27 +0000179 protected MeterService meterService;
alshabibe0559672016-02-21 14:49:51 -0800180
Carmelo Casconeca931162019-07-15 18:22:24 -0700181 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100182 protected StorageService storageService;
183
Carmelo Casconeca931162019-07-15 18:22:24 -0700184 /**
185 * Default VLAN RG<->ONU traffic
186 **/
187 private int defaultVlan = DEFAULT_VLAN_DEFAULT;
alshabibe0559672016-02-21 14:49:51 -0800188
Carmelo Casconeca931162019-07-15 18:22:24 -0700189 /**
190 * Create the DHCP Flow rules when a subscriber is provisioned
191 **/
192 protected boolean enableDhcpOnProvisioning = ENABLE_DHCP_ON_PROVISIONING_DEFAULT;
Matt Jeanneret3f579262018-06-14 17:16:23 -0400193
Carmelo Casconeca931162019-07-15 18:22:24 -0700194 /**
195 * Enable flows for DHCP v4
196 **/
197 protected boolean enableDhcpV4 = ENABLE_DHCP_V4_DEFAULT;
Matteo Scandolo63460d12018-11-02 16:19:04 -0700198
Carmelo Casconeca931162019-07-15 18:22:24 -0700199 /**
200 * Enable flows for DHCP v6
201 **/
202 protected boolean enableDhcpV6 = ENABLE_DHCP_V6_DEFAULT;
Matteo Scandolo63460d12018-11-02 16:19:04 -0700203
Carmelo Casconeca931162019-07-15 18:22:24 -0700204 /**
205 * Create IGMP Flow rules when a subscriber is provisioned
206 **/
207 protected boolean enableIgmpOnProvisioning = ENABLE_IGMP_ON_PROVISIONING_DEFAULT;
Amit Ghosh95e2f652017-08-23 12:49:46 +0100208
Carmelo Casconeca931162019-07-15 18:22:24 -0700209 /**
210 * Deleting Meters based on flow count statistics
211 **/
212 protected boolean deleteMeters = DELETE_METERS_DEFAULT;
Gamze Abaka641fc072018-09-04 09:16:27 +0000213
Carmelo Casconeca931162019-07-15 18:22:24 -0700214 /**
215 * Default technology profile id that is used for authentication trap flows
216 **/
217 protected int defaultTechProfileId = DEFAULT_TP_ID_DEFAULT;
Gamze Abakaad329652018-12-20 10:12:21 +0000218
Carmelo Casconeca931162019-07-15 18:22:24 -0700219 /**
220 * Default bandwidth profile id that is used for authentication trap flows
221 **/
222 protected String defaultBpId = DEFAULT_BP_ID_DEFAULT;
Gamze Abakaad329652018-12-20 10:12:21 +0000223
Carmelo Casconeca931162019-07-15 18:22:24 -0700224 /**
225 * Send EAPOL authentication trap flows before subscriber provisioning
226 **/
227 protected boolean enableEapol = ENABLE_EAPOL_DEFAULT;
Gamze Abaka33feef52019-02-27 08:16:47 +0000228
alshabibf0e7e702015-05-30 18:22:36 -0700229 private final DeviceListener deviceListener = new InternalDeviceListener();
Gamze Abaka641fc072018-09-04 09:16:27 +0000230 private final MeterListener meterListener = new InternalMeterListener();
alshabibf0e7e702015-05-30 18:22:36 -0700231
232 private ApplicationId appId;
Gamze Abaka641fc072018-09-04 09:16:27 +0000233 protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
234 private BaseInformationService<BandwidthProfileInformation> bpService;
alshabibf0e7e702015-05-30 18:22:36 -0700235
Gamze Abaka33feef52019-02-27 08:16:47 +0000236 private Map<String, List<MeterKey>> bpInfoToMeter = new ConcurrentHashMap<>();
Gamze Abaka641fc072018-09-04 09:16:27 +0000237
238 private ExecutorService oltInstallers = Executors.newFixedThreadPool(4,
239 groupedThreads("onos/olt-service",
240 "olt-installer-%d"));
alshabibf0e7e702015-05-30 18:22:36 -0700241
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100242 private ConsistentMultimap<ConnectPoint, Map.Entry<VlanId, VlanId>> additionalVlans;
243
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700244 protected ExecutorService eventExecutor;
245
Saurav Das82b8e6d2018-10-04 15:25:12 -0700246 private Map<ConnectPoint, SubscriberAndDeviceInformation> programmedSubs;
Gamze Abaka33feef52019-02-27 08:16:47 +0000247 private Set<MeterKey> programmedMeters;
Saurav Das82b8e6d2018-10-04 15:25:12 -0700248
Saurav Dasa9d5f442019-03-06 19:32:48 -0800249
alshabibf0e7e702015-05-30 18:22:36 -0700250 @Activate
alshabibe0559672016-02-21 14:49:51 -0800251 public void activate(ComponentContext context) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -0700252 eventExecutor = newSingleThreadScheduledExecutor(groupedThreads("onos/olt", "events-%d", log));
alshabibe0559672016-02-21 14:49:51 -0800253 modified(context);
Charles Chan54f110f2017-01-20 11:22:42 -0800254 appId = coreService.registerApplication(APP_NAME);
Saurav Das62ad75e2019-03-05 12:22:22 -0800255
256 // ensure that flow rules are purged from flow-store upon olt-disconnection
257 // when olt reconnects, the port-numbers may change for the ONUs
258 // making flows pushed earlier invalid
259 componentConfigService
260 .preSetProperty("org.onosproject.net.flow.impl.FlowRuleManager",
Gamze Abaka33feef52019-02-27 08:16:47 +0000261 "purgeOnDisconnection", "true");
Gamze Abakada282b42019-03-11 13:16:48 +0000262 componentConfigService
263 .preSetProperty("org.onosproject.net.meter.impl.MeterManager",
264 "purgeOnDisconnection", "true");
alshabibe0559672016-02-21 14:49:51 -0800265 componentConfigService.registerProperties(getClass());
Saurav Das82b8e6d2018-10-04 15:25:12 -0700266 programmedSubs = Maps.newConcurrentMap();
Gamze Abaka33feef52019-02-27 08:16:47 +0000267 programmedMeters = ConcurrentHashMap.newKeySet();
alshabibc4dfe852015-06-05 13:35:13 -0700268
alshabib8e4fd2f2016-01-12 15:55:53 -0800269 eventDispatcher.addSink(AccessDeviceEvent.class, listenerRegistry);
270
Gamze Abaka641fc072018-09-04 09:16:27 +0000271 subsService = sadisService.getSubscriberInfoService();
272 bpService = sadisService.getBandwidthProfileService();
273
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100274 // look for all provisioned devices in Sadis and create EAPOL flows for the
275 // UNI ports
276 Iterable<Device> devices = deviceService.getDevices();
277 for (Device d : devices) {
Jonathan Hart403372d2018-08-22 11:44:13 -0700278 checkAndCreateDeviceFlows(d);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100279 }
alshabib4ceaed32016-03-03 18:00:58 -0800280
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100281 additionalVlans = storageService.<ConnectPoint, Map.Entry<VlanId, VlanId>>consistentMultimapBuilder()
282 .withName(ADDITIONAL_VLANS)
283 .withSerializer(Serializer.using(Arrays.asList(KryoNamespaces.API),
284 AbstractMap.SimpleEntry.class))
285 .build();
286
alshabibba357492016-01-27 13:49:46 -0800287 deviceService.addListener(deviceListener);
Gamze Abaka641fc072018-09-04 09:16:27 +0000288 meterService.addListener(meterListener);
alshabibba357492016-01-27 13:49:46 -0800289
alshabibf0e7e702015-05-30 18:22:36 -0700290 log.info("Started with Application ID {}", appId.id());
291 }
292
293 @Deactivate
294 public void deactivate() {
alshabibe0559672016-02-21 14:49:51 -0800295 componentConfigService.unregisterProperties(getClass(), false);
alshabib62e9ce72016-02-11 17:31:36 -0800296 deviceService.removeListener(deviceListener);
Gamze Abaka641fc072018-09-04 09:16:27 +0000297 meterService.removeListener(meterListener);
Jonathan Hart5f1c8142018-07-24 17:31:59 -0700298 eventDispatcher.removeSink(AccessDeviceEvent.class);
alshabibf0e7e702015-05-30 18:22:36 -0700299 log.info("Stopped");
300 }
301
alshabibe0559672016-02-21 14:49:51 -0800302 @Modified
303 public void modified(ComponentContext context) {
304 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
305
306 try {
307 String s = get(properties, "defaultVlan");
Carmelo Casconeca931162019-07-15 18:22:24 -0700308 defaultVlan = isNullOrEmpty(s) ? DEFAULT_VLAN_DEFAULT : Integer.parseInt(s.trim());
Amit Ghosh95e2f652017-08-23 12:49:46 +0100309
Matt Jeanneret3f579262018-06-14 17:16:23 -0400310 Boolean o = Tools.isPropertyEnabled(properties, "enableDhcpOnProvisioning");
Amit Ghosh95e2f652017-08-23 12:49:46 +0100311 if (o != null) {
Matt Jeanneret3f579262018-06-14 17:16:23 -0400312 enableDhcpOnProvisioning = o;
Amit Ghosh95e2f652017-08-23 12:49:46 +0100313 }
Matt Jeanneret3f579262018-06-14 17:16:23 -0400314
Matteo Scandolo63460d12018-11-02 16:19:04 -0700315 Boolean v4 = Tools.isPropertyEnabled(properties, "enableDhcpV4");
316 if (v4 != null) {
317 enableDhcpV4 = v4;
318 }
319
320 Boolean v6 = Tools.isPropertyEnabled(properties, "enableDhcpV6");
321 if (v6 != null) {
322 enableDhcpV6 = v6;
323 }
324
Matt Jeanneret3f579262018-06-14 17:16:23 -0400325 Boolean p = Tools.isPropertyEnabled(properties, "enableIgmpOnProvisioning");
326 if (p != null) {
327 enableIgmpOnProvisioning = p;
328 }
329
Matteo Scandolo63460d12018-11-02 16:19:04 -0700330 log.info("DHCP Settings [enableDhcpOnProvisioning: {}, enableDhcpV4: {}, enableDhcpV6: {}]",
Gamze Abakaad329652018-12-20 10:12:21 +0000331 enableDhcpOnProvisioning, enableDhcpV4, enableDhcpV6);
Matteo Scandolo63460d12018-11-02 16:19:04 -0700332
Gamze Abaka641fc072018-09-04 09:16:27 +0000333 Boolean d = Tools.isPropertyEnabled(properties, "deleteMeters");
334 if (d != null) {
335 deleteMeters = d;
336 }
337
Gamze Abakaad329652018-12-20 10:12:21 +0000338 String tpId = get(properties, "defaultTechProfileId");
Carmelo Casconeca931162019-07-15 18:22:24 -0700339 defaultTechProfileId = isNullOrEmpty(s) ? DEFAULT_TP_ID_DEFAULT : Integer.parseInt(tpId.trim());
Gamze Abakaad329652018-12-20 10:12:21 +0000340
341 String bpId = get(properties, "defaultBpId");
342 defaultBpId = bpId;
343
Gamze Abaka33feef52019-02-27 08:16:47 +0000344 Boolean eap = Tools.isPropertyEnabled(properties, "enableEapol");
345 if (eap != null) {
346 enableEapol = eap;
347 }
348
alshabibe0559672016-02-21 14:49:51 -0800349 } catch (Exception e) {
Carmelo Casconeca931162019-07-15 18:22:24 -0700350 defaultVlan = DEFAULT_VLAN_DEFAULT;
alshabibe0559672016-02-21 14:49:51 -0800351 }
352 }
353
alshabib32232c82016-02-25 17:57:24 -0500354 @Override
Gamze Abaka838d8142019-02-21 07:06:55 +0000355 public boolean provisionSubscriber(ConnectPoint connectPoint) {
Saurav Daseae48de2019-06-19 13:26:15 -0700356 log.info("Call to provision subscriber at {}", connectPoint);
Gamze Abaka838d8142019-02-21 07:06:55 +0000357 DeviceId deviceId = connectPoint.deviceId();
358 PortNumber subscriberPortNo = connectPoint.port();
359
360 checkNotNull(deviceService.getPort(deviceId, subscriberPortNo),
Jonathan Hart94b90492018-04-24 14:02:25 -0700361 "Invalid connect point");
Hardik Windlass395ff372019-06-13 05:16:00 +0000362
363 // If the subscriber is modified then first remove the previous and proceed
364 SubscriberAndDeviceInformation subscriber = programmedSubs.get(connectPoint);
365 if (subscriber != null) {
366 log.info("Subscriber on connectionPoint {} was previously programmed, " +
367 "remove it before adding again", connectPoint);
368 removeSubscriber(connectPoint);
369 }
370
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100371 // Find the subscriber on this connect point
Gamze Abaka838d8142019-02-21 07:06:55 +0000372 SubscriberAndDeviceInformation sub = getSubscriber(connectPoint);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100373 if (sub == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000374 log.warn("No subscriber found for {}", connectPoint);
Amit Ghosh31939522018-08-16 13:28:21 +0100375 return false;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100376 }
Jonathan Harte533a422015-10-20 17:31:24 -0700377
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100378 // Get the uplink port
Gamze Abaka838d8142019-02-21 07:06:55 +0000379 Port uplinkPort = getUplinkPort(deviceService.getDevice(deviceId));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100380 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000381 log.warn(NO_UPLINK_PORT, deviceId);
Amit Ghosh31939522018-08-16 13:28:21 +0100382 return false;
Jonathan Harte533a422015-10-20 17:31:24 -0700383 }
384
Saurav Daseae48de2019-06-19 13:26:15 -0700385 SubscriberAndDeviceInformation prgSub = programmedSubs.get(connectPoint);
386 if (prgSub != null) {
387 log.warn("Subscriber {} on connectionPoint {} was previously programmed .. "
388 + "taking no action. Note that updating a subscribers params "
389 + "(vlans, bw, tpid etc) requires removing the subscriber"
390 + "before re-provisioning the subscriber", prgSub.id(),
391 connectPoint);
392 return true;
393 }
Gamze Abaka33feef52019-02-27 08:16:47 +0000394
Gamze Abaka838d8142019-02-21 07:06:55 +0000395 //delete Eapol authentication flow with default bandwidth
Gamze Abaka33feef52019-02-27 08:16:47 +0000396 //wait until Eapol rule with defaultBpId is removed to install subscriber-based rules
Saurav Daseae48de2019-06-19 13:26:15 -0700397 CompletableFuture<ObjectiveError> filterFuture = new CompletableFuture();
Gamze Abakada282b42019-03-11 13:16:48 +0000398 processEapolFilteringObjectives(deviceId, subscriberPortNo, defaultBpId, filterFuture,
399 VlanId.vlanId(EAPOL_DEFAULT_VLAN), false);
Saurav Das747a7da2019-06-27 12:28:06 -0700400 // do not remove meter from bpInfoToMeter mapping as flows for other ONUs
401 // could still be using it - this also prevents duplicate meters from being
402 // created for the same bandwidth profile
403 // we still need to remove from programmedMeters so the meter can be
404 // deleted if its reference count drops to zero
405 removeMeterIdFromPrgMeters(deviceId, defaultBpId);
Gamze Abaka838d8142019-02-21 07:06:55 +0000406
Gamze Abaka33feef52019-02-27 08:16:47 +0000407 //install subscriber flows
408 filterFuture.thenAcceptAsync(filterStatus -> {
409 if (filterStatus == null) {
410 provisionSubscriberBasedFlows(connectPoint, uplinkPort.number(), Optional.empty(), sub);
411 }
412 });
Gamze Abaka838d8142019-02-21 07:06:55 +0000413
Saurav Das82b8e6d2018-10-04 15:25:12 -0700414 // cache subscriber info
Gamze Abaka838d8142019-02-21 07:06:55 +0000415 programmedSubs.put(connectPoint, sub);
Amit Ghosh31939522018-08-16 13:28:21 +0100416 return true;
alshabibb7a9e172016-01-13 11:23:53 -0800417 }
418
419 @Override
Gamze Abaka838d8142019-02-21 07:06:55 +0000420 public boolean removeSubscriber(ConnectPoint connectPoint) {
Saurav Daseae48de2019-06-19 13:26:15 -0700421 log.info("Call to un-provision subscriber at {}", connectPoint);
Gamze Abaka838d8142019-02-21 07:06:55 +0000422
Saurav Daseae48de2019-06-19 13:26:15 -0700423 // Get the subscriber connected to this port from the local cache
424 // If we don't know about the subscriber there's no need to remove it
Gamze Abaka838d8142019-02-21 07:06:55 +0000425 DeviceId deviceId = connectPoint.deviceId();
426 PortNumber subscriberPortNo = connectPoint.port();
427
428 SubscriberAndDeviceInformation subscriber = programmedSubs.get(connectPoint);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100429 if (subscriber == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000430 log.warn("Subscriber on connectionPoint {} was not previously programmed, " +
431 "no need to remove it", connectPoint);
Matteo Scandolo962a6ad2018-12-11 15:39:42 -0800432 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800433 }
434
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100435 // Get the uplink port
Gamze Abaka838d8142019-02-21 07:06:55 +0000436 Port uplinkPort = getUplinkPort(deviceService.getDevice(deviceId));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100437 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000438 log.warn(NO_UPLINK_PORT, deviceId);
Amit Ghosh31939522018-08-16 13:28:21 +0100439 return false;
alshabib4ceaed32016-03-03 18:00:58 -0800440 }
441
Gamze Abaka33feef52019-02-27 08:16:47 +0000442 //delete dhcp & igmp trap flows
443 MeterId upstreamMeterId = getMeterIdFromBpMapping(deviceId, subscriber.upstreamBandwidthProfile());
Amit Ghosh95e2f652017-08-23 12:49:46 +0100444
Saurav Daseae48de2019-06-19 13:26:15 -0700445 // remove dhcp filters
Gamze Abaka33feef52019-02-27 08:16:47 +0000446 processDhcpFilteringObjectives(deviceId, subscriberPortNo,
447 upstreamMeterId, subscriber.technologyProfileId(), false, true);
Gamze Abaka838d8142019-02-21 07:06:55 +0000448
Saurav Daseae48de2019-06-19 13:26:15 -0700449 // remove igmp filters
Gamze Abaka33feef52019-02-27 08:16:47 +0000450 processIgmpFilteringObjectives(deviceId, subscriberPortNo,
451 upstreamMeterId, subscriber.technologyProfileId(), false);
alshabibbf23a1f2016-01-14 17:27:11 -0800452
Gamze Abaka33feef52019-02-27 08:16:47 +0000453 //unprovision vlans
454 unprovisionVlans(deviceId, uplinkPort.number(), subscriberPortNo, subscriber, Optional.empty());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100455
456 // Remove if there are any flows for the additional Vlans
Gamze Abaka838d8142019-02-21 07:06:55 +0000457 Collection<? extends Map.Entry<VlanId, VlanId>> vlansList = additionalVlans.get(connectPoint).value();
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100458
459 // Remove the flows for the additional vlans for this subscriber
460 for (Map.Entry<VlanId, VlanId> vlans : vlansList) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000461 unprovisionTransparentFlows(deviceId, uplinkPort.number(), subscriberPortNo,
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100462 vlans.getValue(), vlans.getKey());
463
464 // Remove it from the map also
Gamze Abaka838d8142019-02-21 07:06:55 +0000465 additionalVlans.remove(connectPoint, vlans);
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100466 }
467
Saurav Daseae48de2019-06-19 13:26:15 -0700468 // re-install eapol with default bandwidth profile
Gamze Abaka33feef52019-02-27 08:16:47 +0000469 processEapolFilteringObjectives(deviceId, subscriberPortNo,
Gamze Abakada282b42019-03-11 13:16:48 +0000470 subscriber.upstreamBandwidthProfile(), null, subscriber.cTag(), false);
Andy Bavier160e8682019-05-07 18:32:22 -0700471
472 Port port = deviceService.getPort(deviceId, subscriberPortNo);
473 if (port != null && port.isEnabled()) {
474 processEapolFilteringObjectives(deviceId, subscriberPortNo, defaultBpId,
475 null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
Saurav Daseae48de2019-06-19 13:26:15 -0700476 } else {
477 log.debug("Port {} is no longer enabled or it's unavailable. Not "
478 + "reprogramming default eapol flow", connectPoint);
Andy Bavier160e8682019-05-07 18:32:22 -0700479 }
Gamze Abaka33feef52019-02-27 08:16:47 +0000480
Gamze Abaka838d8142019-02-21 07:06:55 +0000481 programmedSubs.remove(connectPoint);
Amit Ghosh31939522018-08-16 13:28:21 +0100482 return true;
alshabibbf23a1f2016-01-14 17:27:11 -0800483 }
484
Amit Ghosh31939522018-08-16 13:28:21 +0100485 @Override
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100486 public boolean provisionSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag, Optional<VlanId> cTag) {
Gamze Abakaf59c0912019-04-19 08:24:28 +0000487
488 log.info("Provisioning subscriber using subscriberId {}, sTag {}, cTag {}", subscriberId, sTag, cTag);
489
Amit Ghosh31939522018-08-16 13:28:21 +0100490 // Check if we can find the connect point to which this subscriber is connected
491 ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
492 if (subsPort == null) {
493 log.warn("ConnectPoint for {} not found", subscriberId);
494 return false;
495 }
496
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100497 if (!sTag.isPresent() && !cTag.isPresent()) {
498 return provisionSubscriber(subsPort);
499 } else if (sTag.isPresent() && cTag.isPresent()) {
500 Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
501 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000502 log.warn(NO_UPLINK_PORT, subsPort.deviceId());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100503 return false;
504 }
505
Gamze Abakaf59c0912019-04-19 08:24:28 +0000506 CompletableFuture<ObjectiveError> filterFuture = new CompletableFuture();
507
508 //delete Eapol authentication flow with default bandwidth
509 //wait until Eapol rule with defaultBpId is removed to install subscriber-based rules
510 processEapolFilteringObjectives(subsPort.deviceId(), subsPort.port(), defaultBpId, filterFuture,
511 VlanId.vlanId(EAPOL_DEFAULT_VLAN), false);
Saurav Das747a7da2019-06-27 12:28:06 -0700512 // do not remove meter from bpInfoToMeter mapping as flows for other ONUs
513 // could still be using it - this also prevents duplicate meters from being
514 // created for the same bandwidth profile
515 // we still need to remove from programmedMeters so the meter can be
516 // deleted if its reference count drops to zero
517 removeMeterIdFromPrgMeters(subsPort.deviceId(), defaultBpId);
Gamze Abakaf59c0912019-04-19 08:24:28 +0000518
519 //install subscriber flows
520 filterFuture.thenAcceptAsync(filterStatus -> {
521 if (filterStatus == null) {
522 provisionTransparentFlows(subsPort.deviceId(), uplinkPort.number(), subsPort.port(),
523 cTag.get(), sTag.get());
524 }
525 });
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100526 return true;
527 } else {
528 log.warn("Provisioning failed for subscriber: {}", subscriberId);
529 return false;
530 }
Amit Ghosh31939522018-08-16 13:28:21 +0100531 }
Amit Ghosh95e2f652017-08-23 12:49:46 +0100532
alshabibe0559672016-02-21 14:49:51 -0800533 @Override
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100534 public boolean removeSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag, Optional<VlanId> cTag) {
Amit Ghosh31939522018-08-16 13:28:21 +0100535 // Check if we can find the connect point to which this subscriber is connected
536 ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
537 if (subsPort == null) {
538 log.warn("ConnectPoint for {} not found", subscriberId);
539 return false;
540 }
541
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100542 if (!sTag.isPresent() && !cTag.isPresent()) {
543 return removeSubscriber(subsPort);
544 } else if (sTag.isPresent() && cTag.isPresent()) {
545 // Get the uplink port
546 Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
547 if (uplinkPort == null) {
Gamze Abaka838d8142019-02-21 07:06:55 +0000548 log.warn(NO_UPLINK_PORT, subsPort.deviceId());
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100549 return false;
550 }
551
552 unprovisionTransparentFlows(subsPort.deviceId(), uplinkPort.number(), subsPort.port(),
553 cTag.get(), sTag.get());
Gamze Abakaf59c0912019-04-19 08:24:28 +0000554
555 programmedSubs.remove(subsPort);
556
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100557 return true;
558 } else {
559 log.warn("Removing subscriber failed for: {}", subscriberId);
560 return false;
561 }
Amit Ghosh31939522018-08-16 13:28:21 +0100562 }
563
564 @Override
565 public Collection<Map.Entry<ConnectPoint, Map.Entry<VlanId, VlanId>>> getSubscribers() {
566 ArrayList<Map.Entry<ConnectPoint, Map.Entry<VlanId, VlanId>>> subs = new ArrayList<>();
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100567
Saurav Das82b8e6d2018-10-04 15:25:12 -0700568 // Get the subscribers for all the devices configured in sadis
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100569 // If the port is UNI, is enabled and exists in Sadis then copy it
570 for (Device d : deviceService.getDevices()) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700571 if (getOltInfo(d) == null) {
572 continue; // not an olt, or not configured in sadis
573 }
Gamze Abakaad329652018-12-20 10:12:21 +0000574 for (Port p : deviceService.getPorts(d.id())) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100575 if (isUniPort(d, p) && p.isEnabled()) {
576 ConnectPoint cp = new ConnectPoint(d.id(), p.number());
577
578 SubscriberAndDeviceInformation sub = getSubscriber(cp);
579 if (sub != null) {
Amit Ghosh31939522018-08-16 13:28:21 +0100580 Map.Entry<VlanId, VlanId> vlans = new AbstractMap.SimpleEntry(sub.sTag(), sub.cTag());
581 subs.add(new AbstractMap.SimpleEntry(cp, vlans));
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100582 }
583 }
584 }
585 }
586
587 return subs;
Jonathan Hartfd6c1b32016-03-08 14:09:09 -0800588 }
589
590 @Override
Saurav Das82b8e6d2018-10-04 15:25:12 -0700591 public ImmutableMap<ConnectPoint, SubscriberAndDeviceInformation> getProgSubs() {
592 return ImmutableMap.copyOf(programmedSubs);
593 }
594
595 @Override
Gamze Abaka33feef52019-02-27 08:16:47 +0000596 public ImmutableSet<MeterKey> getProgMeters() {
597 return ImmutableSet.copyOf(programmedMeters);
598 }
599
600 @Override
601 public ImmutableMap<String, List<MeterKey>> getBpMeterMappings() {
602 return ImmutableMap.copyOf(bpInfoToMeter);
603 }
604
605 @Override
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100606 public List<DeviceId> fetchOlts() {
607 // look through all the devices and find the ones that are OLTs as per Sadis
608 List<DeviceId> olts = new ArrayList<>();
609 Iterable<Device> devices = deviceService.getDevices();
610 for (Device d : devices) {
Saurav Das82b8e6d2018-10-04 15:25:12 -0700611 if (getOltInfo(d) != null) {
612 // So this is indeed an OLT device
Amit Ghosh1ed9aef2018-07-17 17:08:16 +0100613 olts.add(d.id());
614 }
615 }
616 return olts;
alshabibe0559672016-02-21 14:49:51 -0800617 }
618
Amit Ghosh31939522018-08-16 13:28:21 +0100619 /**
620 * Finds the connect point to which a subscriber is connected.
621 *
622 * @param id The id of the subscriber, this is the same ID as in Sadis
623 * @return Subscribers ConnectPoint if found else null
624 */
625 private ConnectPoint findSubscriberConnectPoint(String id) {
626
627 Iterable<Device> devices = deviceService.getDevices();
628 for (Device d : devices) {
629 for (Port p : deviceService.getPorts(d.id())) {
630 log.trace("Comparing {} with {}", p.annotations().value(AnnotationKeys.PORT_NAME), id);
631 if (p.annotations().value(AnnotationKeys.PORT_NAME).equals(id)) {
632 log.debug("Found on device {} port {}", d.id(), p.number());
633 return new ConnectPoint(d.id(), p.number());
634 }
635 }
636 }
637 return null;
638 }
639
Gamze Abaka641fc072018-09-04 09:16:27 +0000640 private BandwidthProfileInformation getBandwidthProfileInformation(String bandwidthProfile) {
641 if (bandwidthProfile == null) {
642 return null;
643 }
644 return bpService.get(bandwidthProfile);
645 }
646
Gamze Abaka838d8142019-02-21 07:06:55 +0000647 /**
Gamze Abaka33feef52019-02-27 08:16:47 +0000648 * Removes subscriber vlan flows.
Gamze Abaka838d8142019-02-21 07:06:55 +0000649 *
650 * @param deviceId the device identifier
651 * @param uplink uplink port of the OLT
652 * @param subscriberPort uni port
653 * @param subscriber subscriber info that includes s, c tags, tech profile and bandwidth profile references
654 * @param defaultVlan default vlan of the subscriber
Gamze Abaka838d8142019-02-21 07:06:55 +0000655 */
Gamze Abaka33feef52019-02-27 08:16:47 +0000656 private void unprovisionVlans(DeviceId deviceId, PortNumber uplink,
657 PortNumber subscriberPort, SubscriberAndDeviceInformation subscriber,
658 Optional<VlanId> defaultVlan) {
Saurav Daseae48de2019-06-19 13:26:15 -0700659 log.info("Unprovisioning vlans for subscriber {} on dev/port: {}/{}",
660 subscriber, deviceId, subscriberPort);
alshabibbf23a1f2016-01-14 17:27:11 -0800661
662 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
663 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
664
Gamze Abaka641fc072018-09-04 09:16:27 +0000665 VlanId deviceVlan = subscriber.sTag();
666 VlanId subscriberVlan = subscriber.cTag();
667
Gamze Abaka33feef52019-02-27 08:16:47 +0000668 MeterId upstreamMeterId = getMeterIdFromBpMapping(deviceId, subscriber.upstreamBandwidthProfile());
669 MeterId downstreamMeterId = getMeterIdFromBpMapping(deviceId, subscriber.downstreamBandwidthProfile());
Gamze Abaka641fc072018-09-04 09:16:27 +0000670
alshabib4ceaed32016-03-03 18:00:58 -0800671 ForwardingObjective.Builder upFwd = upBuilder(uplink, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000672 subscriberVlan, deviceVlan,
673 defaultVlan, upstreamMeterId, subscriber.technologyProfileId());
alshabib4ceaed32016-03-03 18:00:58 -0800674 ForwardingObjective.Builder downFwd = downBuilder(uplink, subscriberPort,
Gamze Abaka641fc072018-09-04 09:16:27 +0000675 subscriberVlan, deviceVlan,
676 defaultVlan, downstreamMeterId, subscriber.technologyProfileId());
alshabibbf23a1f2016-01-14 17:27:11 -0800677
alshabib4ceaed32016-03-03 18:00:58 -0800678 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
679 @Override
680 public void onSuccess(Objective objective) {
681 upFuture.complete(null);
682 }
alshabibbf23a1f2016-01-14 17:27:11 -0800683
alshabib4ceaed32016-03-03 18:00:58 -0800684 @Override
685 public void onError(Objective objective, ObjectiveError error) {
686 upFuture.complete(error);
687 }
688 }));
689
690 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
691 @Override
692 public void onSuccess(Objective objective) {
693 downFuture.complete(null);
694 }
695
696 @Override
697 public void onError(Objective objective, ObjectiveError error) {
698 downFuture.complete(error);
699 }
700 }));
alshabibbf23a1f2016-01-14 17:27:11 -0800701
702 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
703 if (upStatus == null && downStatus == null) {
704 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_UNREGISTERED,
Gamze Abaka641fc072018-09-04 09:16:27 +0000705 deviceId,
706 deviceVlan,
707 subscriberVlan));
alshabibbf23a1f2016-01-14 17:27:11 -0800708 } else if (downStatus != null) {
709 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000710 "on port {} failed downstream uninstallation: {}",
711 subscriberVlan, deviceId, subscriberPort, downStatus);
alshabibbf23a1f2016-01-14 17:27:11 -0800712 } else if (upStatus != null) {
713 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000714 "on port {} failed upstream uninstallation: {}",
715 subscriberVlan, deviceId, subscriberPort, upStatus);
alshabibbf23a1f2016-01-14 17:27:11 -0800716 }
717 }, oltInstallers);
alshabibb7a9e172016-01-13 11:23:53 -0800718
Gamze Abaka33feef52019-02-27 08:16:47 +0000719 programmedMeters.remove(MeterKey.key(deviceId, upstreamMeterId));
720 programmedMeters.remove(MeterKey.key(deviceId, downstreamMeterId));
Gamze Abaka838d8142019-02-21 07:06:55 +0000721 log.debug("programmed Meters size {}", programmedMeters.size());
Jonathan Harte533a422015-10-20 17:31:24 -0700722 }
723
Gamze Abaka838d8142019-02-21 07:06:55 +0000724 /**
Gamze Abaka33feef52019-02-27 08:16:47 +0000725 * Adds subscriber vlan flows, dhcp, eapol and igmp trap flows for the related uni port.
Gamze Abaka838d8142019-02-21 07:06:55 +0000726 *
727 * @param port the connection point of the subscriber
728 * @param uplinkPort uplink port of the OLT
729 * @param defaultVlan default vlan of the subscriber
730 * @param sub subscriber information that includes s, c tags, tech profile and bandwidth profile references
Gamze Abaka838d8142019-02-21 07:06:55 +0000731 */
Saurav Daseae48de2019-06-19 13:26:15 -0700732 private void provisionSubscriberBasedFlows(ConnectPoint port, PortNumber uplinkPort,
733 Optional<VlanId> defaultVlan,
Gamze Abaka33feef52019-02-27 08:16:47 +0000734 SubscriberAndDeviceInformation sub) {
Gamze Abaka641fc072018-09-04 09:16:27 +0000735
Saurav Daseae48de2019-06-19 13:26:15 -0700736 log.info("Provisioning vlans for subscriber {} on dev/port: {}",
737 sub, port);
Gamze Abaka641fc072018-09-04 09:16:27 +0000738
739 DeviceId deviceId = port.deviceId();
740 PortNumber subscriberPort = port.port();
741 VlanId deviceVlan = sub.sTag();
742 VlanId subscriberVlan = sub.cTag();
743 int techProfId = sub.technologyProfileId();
744
745 BandwidthProfileInformation upstreamBpInfo = getBandwidthProfileInformation(sub.upstreamBandwidthProfile());
746 BandwidthProfileInformation downstreamBpInfo = getBandwidthProfileInformation(sub.downstreamBandwidthProfile());
747
alshabib3ea82642016-01-12 18:06:53 -0800748 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
749 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
Gamze Abaka33feef52019-02-27 08:16:47 +0000750 CompletableFuture<Object> upstreamMeterFuture = new CompletableFuture<>();
751 CompletableFuture<Object> downsteamMeterFuture = new CompletableFuture<>();
alshabib3ea82642016-01-12 18:06:53 -0800752
Gamze Abaka33feef52019-02-27 08:16:47 +0000753 MeterId upstreamMeterId = createMeter(deviceId, upstreamBpInfo, upstreamMeterFuture);
754 MeterId downstreamMeterId = createMeter(deviceId, downstreamBpInfo, downsteamMeterFuture);
Jonathan Harte533a422015-10-20 17:31:24 -0700755
Gamze Abaka33feef52019-02-27 08:16:47 +0000756 //install upstream flows
757 upstreamMeterFuture.thenAcceptAsync(result -> {
758 if (result == null) {
Saurav Daseae48de2019-06-19 13:26:15 -0700759 log.info("Upstream Meter {} is in the device {}. " +
Gamze Abaka33feef52019-02-27 08:16:47 +0000760 "Sending subscriber flows.", upstreamMeterId, deviceId);
761 ForwardingObjective.Builder upFwd = upBuilder(uplinkPort, subscriberPort,
762 subscriberVlan, deviceVlan,
763 defaultVlan, upstreamMeterId, techProfId);
alshabib3ea82642016-01-12 18:06:53 -0800764
Gamze Abaka33feef52019-02-27 08:16:47 +0000765
766 flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
767 @Override
768 public void onSuccess(Objective objective) {
769 upFuture.complete(null);
770 }
771
772 @Override
773 public void onError(Objective objective, ObjectiveError error) {
774 upFuture.complete(error);
775 }
776 }));
777 } else {
778 log.warn("Meter installation error while sending upstream flows. " +
779 "Result {} and MeterId {}", result, upstreamMeterId);
alshabibbf23a1f2016-01-14 17:27:11 -0800780 }
Gamze Abaka33feef52019-02-27 08:16:47 +0000781 });
alshabibbf23a1f2016-01-14 17:27:11 -0800782
Gamze Abaka33feef52019-02-27 08:16:47 +0000783 //install downstream flows
784 downsteamMeterFuture.thenAcceptAsync(result -> {
785 if (result == null) {
Saurav Daseae48de2019-06-19 13:26:15 -0700786 log.info("Downstream Meter {} is in the device {}. " +
Gamze Abaka33feef52019-02-27 08:16:47 +0000787 "Sending subscriber flows.", downstreamMeterId, deviceId);
788 ForwardingObjective.Builder downFwd = downBuilder(uplinkPort, subscriberPort,
789 subscriberVlan, deviceVlan,
790 defaultVlan, downstreamMeterId, techProfId);
791
792 flowObjectiveService.forward(deviceId, downFwd.add(new ObjectiveContext() {
793 @Override
794 public void onSuccess(Objective objective) {
795 downFuture.complete(null);
796 }
797
798 @Override
799 public void onError(Objective objective, ObjectiveError error) {
800 downFuture.complete(error);
801 }
802 }));
803 } else {
804 log.warn("Meter installation error while sending downstream flows. " +
805 "Result {} and MeterId {}", result, downstreamMeterId);
alshabibbf23a1f2016-01-14 17:27:11 -0800806 }
Gamze Abaka33feef52019-02-27 08:16:47 +0000807 });
alshabibbf23a1f2016-01-14 17:27:11 -0800808
Gamze Abaka33feef52019-02-27 08:16:47 +0000809 //send eapol & dhcp & igmp flows
810 //send Subscriber Registered event
alshabib3ea82642016-01-12 18:06:53 -0800811 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
812 if (upStatus == null && downStatus == null) {
Gamze Abaka33feef52019-02-27 08:16:47 +0000813
814 if (upstreamMeterId != null) {
815 //re-install Eapol authentication flow with the subscribers' upstream bandwidth profile
816 processEapolFilteringObjectives(deviceId, subscriberPort, sub.upstreamBandwidthProfile(),
Gamze Abakada282b42019-03-11 13:16:48 +0000817 null, sub.cTag(), true);
Gamze Abaka33feef52019-02-27 08:16:47 +0000818
819 processDhcpFilteringObjectives(deviceId, subscriberPort,
820 upstreamMeterId, sub.technologyProfileId(), true, true);
821
822 processIgmpFilteringObjectives(deviceId, subscriberPort,
823 upstreamMeterId, sub.technologyProfileId(), true);
824 }
825
alshabib3ea82642016-01-12 18:06:53 -0800826 post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_REGISTERED,
Gamze Abaka641fc072018-09-04 09:16:27 +0000827 deviceId,
828 deviceVlan,
829 subscriberVlan));
alshabib50d9fc52016-02-12 15:47:20 -0800830
alshabib3ea82642016-01-12 18:06:53 -0800831 } else if (downStatus != null) {
832 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000833 "on port {} failed downstream installation: {}",
834 subscriberVlan, deviceId, subscriberPort, downStatus);
alshabib3ea82642016-01-12 18:06:53 -0800835 } else if (upStatus != null) {
836 log.error("Subscriber with vlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +0000837 "on port {} failed upstream installation: {}",
838 subscriberVlan, deviceId, subscriberPort, upStatus);
alshabib3ea82642016-01-12 18:06:53 -0800839 }
840 }, oltInstallers);
Jonathan Harte533a422015-10-20 17:31:24 -0700841 }
842
Gamze Abaka33feef52019-02-27 08:16:47 +0000843 private MeterId createMeter(DeviceId deviceId, BandwidthProfileInformation bpInfo,
844 CompletableFuture<Object> meterFuture) {
Gamze Abaka641fc072018-09-04 09:16:27 +0000845 if (bpInfo == null) {
Saurav Daseae48de2019-06-19 13:26:15 -0700846 log.warn("Bandwidth profile information cannot be null when creating meter");
Gamze Abaka641fc072018-09-04 09:16:27 +0000847 return null;
848 }
849
Gamze Abaka33feef52019-02-27 08:16:47 +0000850 MeterId meterId = getMeterIdFromBpMapping(deviceId, bpInfo.id());
Gamze Abaka641fc072018-09-04 09:16:27 +0000851 if (meterId != null) {
Saurav Daseae48de2019-06-19 13:26:15 -0700852 log.debug("Meter {} was previously created for bp {}", meterId,
853 bpInfo.id());
Gamze Abaka33feef52019-02-27 08:16:47 +0000854 meterFuture.complete(null);
Gamze Abaka641fc072018-09-04 09:16:27 +0000855 return meterId;
856 }
857
858 List<Band> meterBands = createMeterBands(bpInfo);
859
860 MeterRequest meterRequest = DefaultMeterRequest.builder()
861 .withBands(meterBands)
862 .withUnit(Meter.Unit.KB_PER_SEC)
Gamze Abaka33feef52019-02-27 08:16:47 +0000863 .withContext(new MeterContext() {
864 @Override
865 public void onSuccess(MeterRequest op) {
Saurav Daseae48de2019-06-19 13:26:15 -0700866 log.debug("meter addition confirmed for bpInfo:{}", bpInfo);
Gamze Abaka33feef52019-02-27 08:16:47 +0000867 meterFuture.complete(null);
868 }
869
870 @Override
871 public void onError(MeterRequest op, MeterFailReason reason) {
872 meterFuture.complete(reason);
873 }
874 })
Gamze Abaka641fc072018-09-04 09:16:27 +0000875 .forDevice(deviceId)
876 .fromApp(appId)
877 .burst()
878 .add();
879
880 Meter meter = meterService.submit(meterRequest);
Gamze Abaka33feef52019-02-27 08:16:47 +0000881 addMeterIdToBpMapping(deviceId, meter.id(), bpInfo.id());
Saurav Daseae48de2019-06-19 13:26:15 -0700882 log.info("Meter creation message sent for Meter Id {}", meter.id());
Gamze Abaka33feef52019-02-27 08:16:47 +0000883 programmedMeters.add(MeterKey.key(deviceId, meter.id()));
Gamze Abaka641fc072018-09-04 09:16:27 +0000884 return meter.id();
885 }
886
887 private List<Band> createMeterBands(BandwidthProfileInformation bpInfo) {
888 List<Band> meterBands = new ArrayList<>();
889
890 meterBands.add(createMeterBand(bpInfo.committedInformationRate(), bpInfo.committedBurstSize()));
891 meterBands.add(createMeterBand(bpInfo.exceededInformationRate(), bpInfo.exceededBurstSize()));
Gamze Abakaad329652018-12-20 10:12:21 +0000892 meterBands.add(createMeterBand(bpInfo.assuredInformationRate(), 0L));
Gamze Abaka641fc072018-09-04 09:16:27 +0000893
Gamze Abaka641fc072018-09-04 09:16:27 +0000894 return meterBands;
895 }
896
897 private Band createMeterBand(long rate, Long burst) {
898 return DefaultBand.builder()
899 .withRate(rate) //already Kbps
900 .burstSize(burst) // already Kbits
901 .ofType(Band.Type.DROP) // no matter
902 .build();
903 }
904
alshabib4ceaed32016-03-03 18:00:58 -0800905 private ForwardingObjective.Builder downBuilder(PortNumber uplinkPort,
906 PortNumber subscriberPort,
907 VlanId subscriberVlan,
908 VlanId deviceVlan,
Gamze Abaka641fc072018-09-04 09:16:27 +0000909 Optional<VlanId> defaultVlan,
910 MeterId meterId,
911 int techProfId) {
alshabib4ceaed32016-03-03 18:00:58 -0800912 TrafficSelector downstream = DefaultTrafficSelector.builder()
913 .matchVlanId(deviceVlan)
914 .matchInPort(uplinkPort)
915 .matchInnerVlanId(subscriberVlan)
916 .build();
917
Gamze Abaka641fc072018-09-04 09:16:27 +0000918 TrafficTreatment.Builder downstreamTreatmentBuilder = DefaultTrafficTreatment.builder()
alshabib4ceaed32016-03-03 18:00:58 -0800919 .popVlan()
920 .setVlanId(defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan)))
Gamze Abaka641fc072018-09-04 09:16:27 +0000921 .setOutput(subscriberPort);
922
923 if (meterId != null) {
924 downstreamTreatmentBuilder.meter(meterId);
925 }
926
Gamze Abakaad329652018-12-20 10:12:21 +0000927 downstreamTreatmentBuilder.writeMetadata(createMetadata(subscriberVlan, techProfId, subscriberPort), 0);
alshabib4ceaed32016-03-03 18:00:58 -0800928
929 return DefaultForwardingObjective.builder()
930 .withFlag(ForwardingObjective.Flag.VERSATILE)
931 .withPriority(1000)
932 .makePermanent()
933 .withSelector(downstream)
934 .fromApp(appId)
Gamze Abaka641fc072018-09-04 09:16:27 +0000935 .withTreatment(downstreamTreatmentBuilder.build());
alshabib4ceaed32016-03-03 18:00:58 -0800936 }
937
938 private ForwardingObjective.Builder upBuilder(PortNumber uplinkPort,
939 PortNumber subscriberPort,
940 VlanId subscriberVlan,
941 VlanId deviceVlan,
Gamze Abaka641fc072018-09-04 09:16:27 +0000942 Optional<VlanId> defaultVlan,
943 MeterId meterId,
944 int technologyProfileId) {
945
946
947 VlanId dVlan = defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan));
948
949 if (subscriberVlan.toShort() == 4096) {
950 dVlan = subscriberVlan;
951 }
952
alshabib4ceaed32016-03-03 18:00:58 -0800953 TrafficSelector upstream = DefaultTrafficSelector.builder()
Gamze Abaka641fc072018-09-04 09:16:27 +0000954 .matchVlanId(dVlan)
alshabib4ceaed32016-03-03 18:00:58 -0800955 .matchInPort(subscriberPort)
956 .build();
957
958
Gamze Abaka641fc072018-09-04 09:16:27 +0000959 TrafficTreatment.Builder upstreamTreatmentBuilder = DefaultTrafficTreatment.builder()
alshabib4ceaed32016-03-03 18:00:58 -0800960 .pushVlan()
961 .setVlanId(subscriberVlan)
962 .pushVlan()
963 .setVlanId(deviceVlan)
Gamze Abaka641fc072018-09-04 09:16:27 +0000964 .setOutput(uplinkPort);
965
966 if (meterId != null) {
967 upstreamTreatmentBuilder.meter(meterId);
968 }
969
Gamze Abakaad329652018-12-20 10:12:21 +0000970 upstreamTreatmentBuilder.writeMetadata(createMetadata(deviceVlan, technologyProfileId, uplinkPort), 0L);
alshabib4ceaed32016-03-03 18:00:58 -0800971
972 return DefaultForwardingObjective.builder()
973 .withFlag(ForwardingObjective.Flag.VERSATILE)
974 .withPriority(1000)
975 .makePermanent()
976 .withSelector(upstream)
977 .fromApp(appId)
Gamze Abaka641fc072018-09-04 09:16:27 +0000978 .withTreatment(upstreamTreatmentBuilder.build());
alshabib4ceaed32016-03-03 18:00:58 -0800979 }
Gamze Abakaad329652018-12-20 10:12:21 +0000980
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100981 private void provisionTransparentFlows(DeviceId deviceId, PortNumber uplinkPort,
982 PortNumber subscriberPort,
983 VlanId innerVlan,
984 VlanId outerVlan) {
985
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100986 ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
987
Gamze Abakaf59c0912019-04-19 08:24:28 +0000988 SubscriberAndDeviceInformation subInfo = getSubscriber(cp);
989
990 BandwidthProfileInformation upstreamBpInfo = getBandwidthProfileInformation(
991 subInfo.upstreamBandwidthProfile());
992 BandwidthProfileInformation downstreamBpInfo = getBandwidthProfileInformation(
993 subInfo.downstreamBandwidthProfile());
994
995 CompletableFuture<Object> upstreamMeterFuture = new CompletableFuture<>();
996 CompletableFuture<Object> downsteamMeterFuture = new CompletableFuture<>();
997 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
998 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
999
1000 MeterId upstreamMeterId = createMeter(deviceId, upstreamBpInfo, upstreamMeterFuture);
1001 MeterId downstreamMeterId = createMeter(deviceId, downstreamBpInfo, downsteamMeterFuture);
1002
1003 upstreamMeterFuture.thenAcceptAsync(result -> {
1004 if (result == null) {
1005 log.info("Upstream Meter {} is sent to the device {}. " +
1006 "Sending subscriber flows.", upstreamMeterId, deviceId);
1007
1008 ForwardingObjective.Builder upFwd = transparentUpBuilder(uplinkPort, subscriberPort,
1009 innerVlan, outerVlan, upstreamMeterId, subInfo);
1010
1011 flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
1012 @Override
1013 public void onSuccess(Objective objective) {
1014 upFuture.complete(null);
1015 }
1016
1017 @Override
1018 public void onError(Objective objective, ObjectiveError error) {
1019 upFuture.complete(error);
1020 }
1021 }));
1022
1023 } else {
1024 log.warn("Meter installation error while sending upstream flows. " +
1025 "Result {} and MeterId {}", result, upstreamMeterId);
1026 }
1027 });
1028
1029 downsteamMeterFuture.thenAcceptAsync(result -> {
1030 if (result == null) {
1031 log.info("Downstream Meter {} is sent to the device {}. " +
1032 "Sending subscriber flows.", downstreamMeterId, deviceId);
1033
1034 ForwardingObjective.Builder downFwd = transparentDownBuilder(uplinkPort, subscriberPort,
1035 innerVlan, outerVlan, downstreamMeterId, subInfo);
1036
1037 flowObjectiveService.forward(deviceId, downFwd.add(new ObjectiveContext() {
1038 @Override
1039 public void onSuccess(Objective objective) {
1040 downFuture.complete(null);
1041 }
1042
1043 @Override
1044 public void onError(Objective objective, ObjectiveError error) {
1045 downFuture.complete(error);
1046 }
1047 }));
1048 } else {
1049 log.warn("Meter installation error while sending upstream flows. " +
1050 "Result {} and MeterId {}", result, downstreamMeterId);
1051 }
1052 });
1053
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001054 additionalVlans.put(cp, new AbstractMap.SimpleEntry(outerVlan, innerVlan));
1055
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001056 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
1057 if (downStatus != null) {
1058 log.error("Flow with innervlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +00001059 "on port {} failed downstream installation: {}",
Gamze Abakaf59c0912019-04-19 08:24:28 +00001060 innerVlan, outerVlan, deviceId, cp, downStatus);
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001061 } else if (upStatus != null) {
1062 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +00001063 "on port {} failed upstream installation: {}",
Gamze Abakaf59c0912019-04-19 08:24:28 +00001064 innerVlan, outerVlan, deviceId, cp, upStatus);
1065 } else {
1066 processEapolFilteringObjectives(deviceId, subscriberPort, subInfo.upstreamBandwidthProfile(),
1067 null, subInfo.cTag(), true);
1068
1069 // cache subscriber info
1070 programmedSubs.put(cp, subInfo);
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001071 }
1072 }, oltInstallers);
1073
1074 }
1075
1076 private ForwardingObjective.Builder transparentDownBuilder(PortNumber uplinkPort,
1077 PortNumber subscriberPort,
1078 VlanId innerVlan,
Gamze Abakaf59c0912019-04-19 08:24:28 +00001079 VlanId outerVlan,
1080 MeterId downstreamMeterId,
1081 SubscriberAndDeviceInformation subInfo) {
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001082 TrafficSelector downstream = DefaultTrafficSelector.builder()
1083 .matchVlanId(outerVlan)
1084 .matchInPort(uplinkPort)
1085 .matchInnerVlanId(innerVlan)
1086 .build();
1087
Gamze Abakaf59c0912019-04-19 08:24:28 +00001088 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1089 if (downstreamMeterId != null) {
1090 tBuilder.meter(downstreamMeterId);
1091 }
1092
1093 TrafficTreatment downstreamTreatment = tBuilder
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001094 .setOutput(subscriberPort)
Gamze Abakaf59c0912019-04-19 08:24:28 +00001095 .writeMetadata(createMetadata(subInfo.cTag(), subInfo.technologyProfileId(), subscriberPort), 0)
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001096 .build();
1097
1098 return DefaultForwardingObjective.builder()
1099 .withFlag(ForwardingObjective.Flag.VERSATILE)
1100 .withPriority(1000)
1101 .makePermanent()
1102 .withSelector(downstream)
1103 .fromApp(appId)
1104 .withTreatment(downstreamTreatment);
1105 }
1106
1107 private ForwardingObjective.Builder transparentUpBuilder(PortNumber uplinkPort,
1108 PortNumber subscriberPort,
1109 VlanId innerVlan,
Gamze Abakaf59c0912019-04-19 08:24:28 +00001110 VlanId outerVlan,
1111 MeterId upstreamMeterId,
1112 SubscriberAndDeviceInformation subInfo) {
1113
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001114 TrafficSelector upstream = DefaultTrafficSelector.builder()
1115 .matchVlanId(outerVlan)
1116 .matchInPort(subscriberPort)
1117 .matchInnerVlanId(innerVlan)
1118 .build();
1119
Gamze Abakaf59c0912019-04-19 08:24:28 +00001120 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1121 if (upstreamMeterId != null) {
1122 tBuilder.meter(upstreamMeterId);
1123 }
1124
1125 TrafficTreatment upstreamTreatment = tBuilder
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001126 .setOutput(uplinkPort)
Gamze Abakaf59c0912019-04-19 08:24:28 +00001127 .writeMetadata(createMetadata(subInfo.sTag(), subInfo.technologyProfileId(), uplinkPort), 0)
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001128 .build();
1129
1130 return DefaultForwardingObjective.builder()
1131 .withFlag(ForwardingObjective.Flag.VERSATILE)
1132 .withPriority(1000)
1133 .makePermanent()
1134 .withSelector(upstream)
1135 .fromApp(appId)
1136 .withTreatment(upstreamTreatment);
1137 }
1138
1139 private void unprovisionTransparentFlows(DeviceId deviceId, PortNumber uplink,
1140 PortNumber subscriberPort, VlanId innerVlan,
1141 VlanId outerVlan) {
1142
1143 ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
1144
Gamze Abakaf59c0912019-04-19 08:24:28 +00001145 SubscriberAndDeviceInformation subInfo = programmedSubs.get(cp);
1146 if (subInfo == null) {
1147 log.warn("Subscriber is not programmed before for the connectPoint {}", cp);
1148 return;
1149 }
1150
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001151 additionalVlans.remove(cp, new AbstractMap.SimpleEntry(outerVlan, innerVlan));
1152
1153 CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
1154 CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
1155
Gamze Abakaf59c0912019-04-19 08:24:28 +00001156 MeterId upstreamMeterId = getMeterIdFromBpMapping(deviceId, subInfo.upstreamBandwidthProfile());
1157 MeterId downstreamMeterId = getMeterIdFromBpMapping(deviceId, subInfo.downstreamBandwidthProfile());
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001158
Gamze Abakaf59c0912019-04-19 08:24:28 +00001159 ForwardingObjective.Builder upFwd = transparentUpBuilder(uplink, subscriberPort,
1160 innerVlan, outerVlan, upstreamMeterId, subInfo);
1161 ForwardingObjective.Builder downFwd = transparentDownBuilder(uplink, subscriberPort,
1162 innerVlan, outerVlan, downstreamMeterId, subInfo);
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001163
1164 flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
1165 @Override
1166 public void onSuccess(Objective objective) {
1167 upFuture.complete(null);
1168 }
1169
1170 @Override
1171 public void onError(Objective objective, ObjectiveError error) {
1172 upFuture.complete(error);
1173 }
1174 }));
1175
1176 flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
1177 @Override
1178 public void onSuccess(Objective objective) {
1179 downFuture.complete(null);
1180 }
1181
1182 @Override
1183 public void onError(Objective objective, ObjectiveError error) {
1184 downFuture.complete(error);
1185 }
1186 }));
1187
1188 upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
1189 if (downStatus != null) {
1190 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +00001191 "on port {} failed downstream uninstallation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001192 innerVlan, outerVlan, deviceId, subscriberPort, downStatus);
1193 } else if (upStatus != null) {
1194 log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
Gamze Abaka641fc072018-09-04 09:16:27 +00001195 "on port {} failed upstream uninstallation: {}",
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001196 innerVlan, outerVlan, deviceId, subscriberPort, upStatus);
1197 }
1198 }, oltInstallers);
1199
Gamze Abakaf59c0912019-04-19 08:24:28 +00001200 //re-install eapol
1201 processEapolFilteringObjectives(deviceId, subscriberPort,
1202 subInfo.upstreamBandwidthProfile(), null, subInfo.cTag(), false);
1203 processEapolFilteringObjectives(deviceId, subscriberPort, defaultBpId,
1204 null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
1205
1206 programmedMeters.remove(MeterKey.key(deviceId, upstreamMeterId));
1207 programmedMeters.remove(MeterKey.key(deviceId, downstreamMeterId));
Amit Ghoshe1d3f092018-10-09 19:44:33 +01001208 }
1209
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001210 private int getDefaultTechProfileId(DeviceId devId, PortNumber portNumber) {
1211 Port port = deviceService.getPort(devId, portNumber);
Andy Bavier160e8682019-05-07 18:32:22 -07001212 if (port != null) {
1213 SubscriberAndDeviceInformation info = subsService.get(port.annotations().value(AnnotationKeys.PORT_NAME));
1214 if (info != null && info.technologyProfileId() != -1) {
1215 return info.technologyProfileId();
1216 }
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001217 }
1218 return defaultTechProfileId;
1219 }
1220
Gamze Abaka838d8142019-02-21 07:06:55 +00001221 /**
Gamze Abakada282b42019-03-11 13:16:48 +00001222 * Returns the write metadata value including tech profile reference and innerVlan.
1223 * For param cVlan, null can be sent
Gamze Abaka838d8142019-02-21 07:06:55 +00001224 *
Gamze Abakada282b42019-03-11 13:16:48 +00001225 * @param cVlan c (customer) tag of one subscriber
Gamze Abaka838d8142019-02-21 07:06:55 +00001226 * @param techProfileId tech profile id of one subscriber
Gamze Abakada282b42019-03-11 13:16:48 +00001227 * @return the write metadata value including tech profile reference and innerVlan
Gamze Abaka838d8142019-02-21 07:06:55 +00001228 */
Gamze Abakada282b42019-03-11 13:16:48 +00001229 private Long createTechProfValueForWm(VlanId cVlan, int techProfileId) {
1230 if (cVlan == null) {
1231 return (long) techProfileId << 32;
1232 }
1233 return ((long) (cVlan.id()) << 48 | (long) techProfileId << 32);
Gamze Abaka838d8142019-02-21 07:06:55 +00001234 }
1235
1236 /**
1237 * Trap eapol authentication packets to the controller.
1238 *
Gamze Abaka33feef52019-02-27 08:16:47 +00001239 * @param devId the device identifier
1240 * @param portNumber the port for which this trap flow is designated
1241 * @param bpId bandwidth profile id to add the related meter to the flow
1242 * @param filterFuture completable future for this filtering objective operation
Gamze Abakada282b42019-03-11 13:16:48 +00001243 * @param vlanId the default or customer tag for a subscriber
Gamze Abaka33feef52019-02-27 08:16:47 +00001244 * @param install true to install the flow, false to remove the flow
Gamze Abaka838d8142019-02-21 07:06:55 +00001245 */
Gamze Abaka33feef52019-02-27 08:16:47 +00001246 private void processEapolFilteringObjectives(DeviceId devId, PortNumber portNumber, String bpId,
1247 CompletableFuture<ObjectiveError> filterFuture,
Gamze Abakada282b42019-03-11 13:16:48 +00001248 VlanId vlanId, boolean install) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001249 if (!enableEapol) {
1250 log.debug("Eapol filtering is disabled.");
1251 if (filterFuture != null) {
1252 filterFuture.complete(null);
1253 }
1254 return;
1255 }
1256
alshabib09753b52016-03-04 14:55:19 -08001257 if (!mastershipService.isLocalMaster(devId)) {
1258 return;
1259 }
alshabibbb83aa22016-02-10 15:08:23 -08001260 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Gamze Abakaad329652018-12-20 10:12:21 +00001261 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
Gamze Abaka33feef52019-02-27 08:16:47 +00001262 CompletableFuture<Object> meterFuture = new CompletableFuture<>();
alshabibbb83aa22016-02-10 15:08:23 -08001263
Gamze Abaka838d8142019-02-21 07:06:55 +00001264 BandwidthProfileInformation bpInfo = getBandwidthProfileInformation(bpId);
Saurav Das747a7da2019-06-27 12:28:06 -07001265 if (bpInfo == null) {
1266 log.warn("Bandwidth profile {} is not found. Authentication flow"
1267 + " will not be installed", bpId);
Gamze Abaka838d8142019-02-21 07:06:55 +00001268 return;
Gamze Abakaad329652018-12-20 10:12:21 +00001269 }
1270
Saurav Das747a7da2019-06-27 12:28:06 -07001271 // check if meter exists and create it only for an install
1272 MeterId meterId = getMeterIdFromBpMapping(devId, bpInfo.id());
1273 if (meterId == null) {
1274 if (install) {
1275 meterId = createMeter(devId, bpInfo, meterFuture);
1276 treatmentBuilder.meter(meterId);
1277 } else {
1278 // this case should not happen as the request to remove an eapol
1279 // flow should mean that the flow points to a meter that exists.
1280 // Nevertheless we can still delete the flow as we only need the
1281 // correct 'match' to do so.
1282 log.warn("Unknown meter id for bp {}, still proceeding with "
1283 + "delete of eapol flow for {}/{}", bpInfo.id(), devId,
1284 portNumber);
1285 meterFuture.complete(null);
1286 }
1287 } else {
1288 log.debug("Meter {} was previously created for bp {}", meterId,
1289 bpInfo.id());
1290 treatmentBuilder.meter(meterId);
1291 meterFuture.complete(null);
1292 }
1293
1294 final MeterId mId = meterId;
Gamze Abaka33feef52019-02-27 08:16:47 +00001295 meterFuture.thenAcceptAsync(result -> {
1296 if (result == null) {
Saurav Das747a7da2019-06-27 12:28:06 -07001297 log.info("Meter {} for {} on {}/{} exists. {} EAPOL trap flow",
1298 mId, bpId, devId, portNumber,
1299 (install) ? "Installing " : "Removing ");
Gamze Abaka33feef52019-02-27 08:16:47 +00001300 int techProfileId = getDefaultTechProfileId(devId, portNumber);
Gamze Abaka1efc80c2019-02-15 12:10:54 +00001301
Gamze Abaka33feef52019-02-27 08:16:47 +00001302 //Authentication trap flow uses only tech profile id as write metadata value
1303 FilteringObjective eapol = (install ? builder.permit() : builder.deny())
1304 .withKey(Criteria.matchInPort(portNumber))
1305 .addCondition(Criteria.matchEthType(EthType.EtherType.EAPOL.ethType()))
Gamze Abakada282b42019-03-11 13:16:48 +00001306 .addCondition(Criteria.matchVlanId(vlanId))
Gamze Abaka33feef52019-02-27 08:16:47 +00001307 .withMeta(treatmentBuilder
Gamze Abakada282b42019-03-11 13:16:48 +00001308 .writeMetadata(createTechProfValueForWm(vlanId, techProfileId), 0)
Gamze Abaka33feef52019-02-27 08:16:47 +00001309 .setOutput(PortNumber.CONTROLLER).build())
1310 .fromApp(appId)
1311 .withPriority(10000)
1312 .add(new ObjectiveContext() {
1313 @Override
1314 public void onSuccess(Objective objective) {
1315 log.info("Eapol filter for {} on {} {} with meter {}.",
Saurav Das747a7da2019-06-27 12:28:06 -07001316 devId, portNumber, (install) ? INSTALLED : REMOVED, mId);
Gamze Abaka33feef52019-02-27 08:16:47 +00001317 if (filterFuture != null) {
1318 filterFuture.complete(null);
1319 }
1320 }
alshabibdec2e252016-01-15 12:20:25 -08001321
Gamze Abaka33feef52019-02-27 08:16:47 +00001322 @Override
1323 public void onError(Objective objective, ObjectiveError error) {
1324 log.info("Eapol filter for {} on {} with meter {} failed {} because {}",
Saurav Das747a7da2019-06-27 12:28:06 -07001325 devId, portNumber, mId, (install) ? INSTALLATION : REMOVAL,
Gamze Abaka33feef52019-02-27 08:16:47 +00001326 error);
1327 if (filterFuture != null) {
1328 filterFuture.complete(error);
1329 }
1330 }
1331 });
alshabibdec2e252016-01-15 12:20:25 -08001332
Gamze Abaka33feef52019-02-27 08:16:47 +00001333 flowObjectiveService.filter(devId, eapol);
1334 } else {
1335 log.warn("Meter installation error while sending eapol trap flow. " +
Saurav Das747a7da2019-06-27 12:28:06 -07001336 "Result {} and MeterId {}", result, mId);
Gamze Abaka33feef52019-02-27 08:16:47 +00001337 }
1338 });
alshabibdec2e252016-01-15 12:20:25 -08001339 }
1340
Jonathan Hart403372d2018-08-22 11:44:13 -07001341 /**
1342 * Installs trap filtering objectives for particular traffic types on an
1343 * NNI port.
1344 *
Gamze Abakaad329652018-12-20 10:12:21 +00001345 * @param devId device ID
1346 * @param port port number
Jonathan Hart403372d2018-08-22 11:44:13 -07001347 * @param install true to install, false to remove
1348 */
1349 private void processNniFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
1350 processLldpFilteringObjective(devId, port, install);
Gamze Abaka33feef52019-02-27 08:16:47 +00001351 processDhcpFilteringObjectives(devId, port, null, -1, install, false);
Jonathan Hart403372d2018-08-22 11:44:13 -07001352 }
1353
1354 private void processLldpFilteringObjective(DeviceId devId, PortNumber port, boolean install) {
1355 if (!mastershipService.isLocalMaster(devId)) {
1356 return;
1357 }
1358 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
1359
1360 FilteringObjective lldp = (install ? builder.permit() : builder.deny())
1361 .withKey(Criteria.matchInPort(port))
1362 .addCondition(Criteria.matchEthType(EthType.EtherType.LLDP.ethType()))
1363 .withMeta(DefaultTrafficTreatment.builder()
1364 .setOutput(PortNumber.CONTROLLER).build())
1365 .fromApp(appId)
1366 .withPriority(10000)
1367 .add(new ObjectiveContext() {
1368 @Override
1369 public void onSuccess(Objective objective) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001370 log.info("LLDP filter for device {} on port {} {}.",
Gamze Abaka838d8142019-02-21 07:06:55 +00001371 devId, port, (install) ? INSTALLED : REMOVED);
Jonathan Hart403372d2018-08-22 11:44:13 -07001372 }
1373
1374 @Override
1375 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001376 log.info("LLDP filter for device {} on port {} failed {} because {}",
Gamze Abaka838d8142019-02-21 07:06:55 +00001377 devId, port, (install) ? INSTALLATION : REMOVAL,
Saurav Das82b8e6d2018-10-04 15:25:12 -07001378 error);
Jonathan Hart403372d2018-08-22 11:44:13 -07001379 }
1380 });
1381
1382 flowObjectiveService.filter(devId, lldp);
1383
1384 }
1385
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001386 /**
1387 * Trap dhcp packets to the controller.
1388 *
Gamze Abaka838d8142019-02-21 07:06:55 +00001389 * @param devId the device identifier
1390 * @param port the port for which this trap flow is designated
1391 * @param upstreamMeterId the upstream meter id that includes the upstream
1392 * bandwidth profile values such as PIR,CIR. If no meter id needs to be referenced,
1393 * null can be sent
1394 * @param techProfileId the technology profile id that is used to create write
1395 * metadata instruction value. If no tech profile id needs to be referenced,
1396 * -1 can be sent
1397 * @param install true to install the flow, false to remove the flow
1398 * @param upstream true if trapped packets are flowing upstream towards
1399 * server, false if packets are flowing downstream towards client
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001400 */
1401 private void processDhcpFilteringObjectives(DeviceId devId, PortNumber port,
Gamze Abaka838d8142019-02-21 07:06:55 +00001402 MeterId upstreamMeterId,
1403 int techProfileId,
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001404 boolean install,
1405 boolean upstream) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001406
1407 if (!enableDhcpOnProvisioning) {
1408 log.debug("Dhcp provisioning is disabled.");
1409 return;
1410 }
1411
Amit Ghosh95e2f652017-08-23 12:49:46 +01001412 if (!mastershipService.isLocalMaster(devId)) {
1413 return;
1414 }
Amit Ghosh95e2f652017-08-23 12:49:46 +01001415
Matteo Scandolo63460d12018-11-02 16:19:04 -07001416 if (enableDhcpV4) {
1417 int udpSrc = (upstream) ? 68 : 67;
1418 int udpDst = (upstream) ? 67 : 68;
1419
1420 EthType ethType = EthType.EtherType.IPV4.ethType();
1421 byte protocol = IPv4.PROTOCOL_UDP;
1422
Gamze Abaka838d8142019-02-21 07:06:55 +00001423 this.addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType,
1424 upstreamMeterId, techProfileId, protocol, install);
Matteo Scandolo63460d12018-11-02 16:19:04 -07001425 }
1426
1427 if (enableDhcpV6) {
1428 int udpSrc = (upstream) ? 547 : 546;
1429 int udpDst = (upstream) ? 546 : 547;
1430
1431 EthType ethType = EthType.EtherType.IPV6.ethType();
1432 byte protocol = IPv6.PROTOCOL_UDP;
1433
Gamze Abaka838d8142019-02-21 07:06:55 +00001434 this.addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType,
1435 upstreamMeterId, techProfileId, protocol, install);
Matteo Scandolo63460d12018-11-02 16:19:04 -07001436 }
1437
1438 }
1439
1440 private void addDhcpFilteringObjectives(DeviceId devId,
1441 PortNumber port,
1442 int udpSrc,
1443 int udpDst,
1444 EthType ethType,
Gamze Abaka838d8142019-02-21 07:06:55 +00001445 MeterId upstreamMeterId,
1446 int techProfileId,
Matteo Scandolo63460d12018-11-02 16:19:04 -07001447 byte protocol,
1448 boolean install) {
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001449
1450 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Gamze Abaka838d8142019-02-21 07:06:55 +00001451 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
1452
1453 if (upstreamMeterId != null) {
1454 treatmentBuilder.meter(upstreamMeterId);
1455 }
1456
1457 if (techProfileId != -1) {
Gamze Abakada282b42019-03-11 13:16:48 +00001458 treatmentBuilder.writeMetadata(createTechProfValueForWm(null, techProfileId), 0);
Gamze Abaka838d8142019-02-21 07:06:55 +00001459 }
1460
Amit Ghosh95e2f652017-08-23 12:49:46 +01001461 FilteringObjective dhcpUpstream = (install ? builder.permit() : builder.deny())
1462 .withKey(Criteria.matchInPort(port))
Matteo Scandolo63460d12018-11-02 16:19:04 -07001463 .addCondition(Criteria.matchEthType(ethType))
1464 .addCondition(Criteria.matchIPProtocol(protocol))
Saurav Dasacc5eeb2018-10-11 10:58:01 -07001465 .addCondition(Criteria.matchUdpSrc(TpPort.tpPort(udpSrc)))
1466 .addCondition(Criteria.matchUdpDst(TpPort.tpPort(udpDst)))
Gamze Abaka838d8142019-02-21 07:06:55 +00001467 .withMeta(treatmentBuilder
Gamze Abaka641fc072018-09-04 09:16:27 +00001468 .setOutput(PortNumber.CONTROLLER).build())
Amit Ghosh95e2f652017-08-23 12:49:46 +01001469 .fromApp(appId)
Matt Jeanneret3f579262018-06-14 17:16:23 -04001470 .withPriority(10000)
Amit Ghosh95e2f652017-08-23 12:49:46 +01001471 .add(new ObjectiveContext() {
1472 @Override
1473 public void onSuccess(Objective objective) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001474 log.info("DHCP {} filter for device {} on port {} {}.",
Gamze Abakaad329652018-12-20 10:12:21 +00001475 (ethType.equals(EthType.EtherType.IPV4.ethType())) ? "v4" : "v6",
Gamze Abaka838d8142019-02-21 07:06:55 +00001476 devId, port, (install) ? INSTALLED : REMOVED);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001477 }
1478
1479 @Override
1480 public void onError(Objective objective, ObjectiveError error) {
Matteo Scandolo63460d12018-11-02 16:19:04 -07001481 log.info("DHCP {} filter for device {} on port {} failed {} because {}",
Gamze Abakaad329652018-12-20 10:12:21 +00001482 (ethType.equals(EthType.EtherType.IPV4.ethType())) ? "v4" : "v6",
Gamze Abaka838d8142019-02-21 07:06:55 +00001483 devId, port, (install) ? INSTALLATION : REMOVAL,
Gamze Abakaad329652018-12-20 10:12:21 +00001484 error);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001485 }
1486 });
1487
1488 flowObjectiveService.filter(devId, dhcpUpstream);
1489 }
1490
Gamze Abaka838d8142019-02-21 07:06:55 +00001491 private void processIgmpFilteringObjectives(DeviceId devId, PortNumber port,
1492 MeterId upstreamMeterId,
1493 int techProfileId,
1494 boolean install) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001495
Gamze Abakaf59c0912019-04-19 08:24:28 +00001496 if (!enableIgmpOnProvisioning) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001497 log.debug("Igmp provisioning is disabled.");
1498 return;
1499 }
1500
Amit Ghosh95e2f652017-08-23 12:49:46 +01001501 if (!mastershipService.isLocalMaster(devId)) {
1502 return;
1503 }
1504
Gamze Abaka641fc072018-09-04 09:16:27 +00001505 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
Gamze Abaka838d8142019-02-21 07:06:55 +00001506 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
1507
1508 if (upstreamMeterId != null) {
1509 treatmentBuilder.meter(upstreamMeterId);
1510 }
1511
1512 if (techProfileId != -1) {
Gamze Abakada282b42019-03-11 13:16:48 +00001513 treatmentBuilder.writeMetadata(createTechProfValueForWm(null, techProfileId), 0);
Gamze Abaka838d8142019-02-21 07:06:55 +00001514 }
Amit Ghosh95e2f652017-08-23 12:49:46 +01001515
1516 builder = install ? builder.permit() : builder.deny();
1517
1518 FilteringObjective igmp = builder
1519 .withKey(Criteria.matchInPort(port))
1520 .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
1521 .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_IGMP))
Gamze Abaka838d8142019-02-21 07:06:55 +00001522 .withMeta(treatmentBuilder
Gamze Abaka641fc072018-09-04 09:16:27 +00001523 .setOutput(PortNumber.CONTROLLER).build())
Amit Ghosh95e2f652017-08-23 12:49:46 +01001524 .fromApp(appId)
1525 .withPriority(10000)
1526 .add(new ObjectiveContext() {
1527 @Override
1528 public void onSuccess(Objective objective) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001529 log.info("Igmp filter for {} on {} {}.",
Gamze Abaka838d8142019-02-21 07:06:55 +00001530 devId, port, (install) ? INSTALLED : REMOVED);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001531 }
1532
1533 @Override
1534 public void onError(Objective objective, ObjectiveError error) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001535 log.info("Igmp filter for {} on {} failed {} because {}.",
Gamze Abaka838d8142019-02-21 07:06:55 +00001536 devId, port, (install) ? INSTALLATION : REMOVAL,
Gamze Abaka641fc072018-09-04 09:16:27 +00001537 error);
Amit Ghosh95e2f652017-08-23 12:49:46 +01001538 }
1539 });
1540
1541 flowObjectiveService.filter(devId, igmp);
1542 }
1543
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001544 /**
Jonathan Hart403372d2018-08-22 11:44:13 -07001545 * Creates trap flows for device, including DHCP and LLDP trap on NNI and
1546 * EAPOL trap on the UNIs, if device is present in Sadis config.
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001547 *
1548 * @param dev Device to look for
1549 */
Jonathan Hart403372d2018-08-22 11:44:13 -07001550 private void checkAndCreateDeviceFlows(Device dev) {
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001551 // we create only for the ones we are master of
1552 if (!mastershipService.isLocalMaster(dev.id())) {
Gamze Abaka641fc072018-09-04 09:16:27 +00001553 return;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001554 }
1555 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +00001556 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Jonathan Hart403372d2018-08-22 11:44:13 -07001557 log.debug("checkAndCreateDeviceFlows: deviceInfo {}", deviceInfo);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001558
1559 if (deviceInfo != null) {
Jonathan Hart403372d2018-08-22 11:44:13 -07001560 // This is an OLT device as per Sadis, we create flows for UNI and NNI ports
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001561 for (Port p : deviceService.getPorts(dev.id())) {
1562 if (isUniPort(dev, p)) {
Gamze Abakada282b42019-03-11 13:16:48 +00001563 processEapolFilteringObjectives(dev.id(), p.number(), defaultBpId, null,
1564 VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
Jonathan Hart403372d2018-08-22 11:44:13 -07001565 } else {
1566 processNniFilteringObjectives(dev.id(), p.number(), true);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001567 }
1568 }
1569 }
1570 }
1571
Jonathan Hart403372d2018-08-22 11:44:13 -07001572
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001573 /**
1574 * Get the uplink for of the OLT device.
Gamze Abakaad329652018-12-20 10:12:21 +00001575 * <p>
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001576 * This assumes that the OLT has a single uplink port. When more uplink ports need to be supported
1577 * this logic needs to be changed
1578 *
1579 * @param dev Device to look for
1580 * @return The uplink Port of the OLT
1581 */
1582 private Port getUplinkPort(Device dev) {
1583 // check if this device is provisioned in Sadis
Gamze Abaka641fc072018-09-04 09:16:27 +00001584 SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
Saurav Daseae48de2019-06-19 13:26:15 -07001585 log.trace("getUplinkPort: deviceInfo {}", deviceInfo);
Saurav Das82b8e6d2018-10-04 15:25:12 -07001586 if (deviceInfo == null) {
1587 log.warn("Device {} is not configured in SADIS .. cannot fetch device"
1588 + " info", dev.id());
1589 return null;
1590 }
1591 // Return the port that has been configured as the uplink port of this OLT in Sadis
Gamze Abakaad329652018-12-20 10:12:21 +00001592 for (Port p : deviceService.getPorts(dev.id())) {
Saurav Das82b8e6d2018-10-04 15:25:12 -07001593 if (p.number().toLong() == deviceInfo.uplinkPort()) {
Saurav Daseae48de2019-06-19 13:26:15 -07001594 log.trace("getUplinkPort: Found port {}", p);
Saurav Das82b8e6d2018-10-04 15:25:12 -07001595 return p;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001596 }
1597 }
1598
Saurav Daseae48de2019-06-19 13:26:15 -07001599 log.warn("getUplinkPort: " + NO_UPLINK_PORT, dev.id());
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001600 return null;
1601 }
1602
1603 /**
1604 * Return the subscriber on a port.
1605 *
Matteo Scandolo962a6ad2018-12-11 15:39:42 -08001606 * @param cp ConnectPoint on which to find the subscriber
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001607 * @return subscriber if found else null
1608 */
Matteo Scandolo962a6ad2018-12-11 15:39:42 -08001609 SubscriberAndDeviceInformation getSubscriber(ConnectPoint cp) {
1610 Port port = deviceService.getPort(cp);
1611 checkNotNull(port, "Invalid connect point");
1612 String portName = port.annotations().value(AnnotationKeys.PORT_NAME);
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001613 return subsService.get(portName);
1614 }
1615
Gamze Abakaad329652018-12-20 10:12:21 +00001616 /**
1617 * Write metadata instruction value (metadata) is 8 bytes.
Gamze Abaka838d8142019-02-21 07:06:55 +00001618 * <p>
Gamze Abakaad329652018-12-20 10:12:21 +00001619 * MS 2 bytes: C Tag
1620 * Next 2 bytes: Technology Profile Id
1621 * Next 4 bytes: Port number (uni or nni)
1622 */
1623
1624 private Long createMetadata(VlanId innerVlan, int techProfileId, PortNumber egressPort) {
1625
1626 if (techProfileId == -1) {
Carmelo Casconeca931162019-07-15 18:22:24 -07001627 techProfileId = defaultTechProfileId;
Gamze Abakaad329652018-12-20 10:12:21 +00001628 }
1629
1630 return ((long) (innerVlan.id()) << 48 | (long) techProfileId << 32) | egressPort.toLong();
1631 }
1632
Amit Ghosh1ed9aef2018-07-17 17:08:16 +01001633 private boolean isUniPort(Device d, Port p) {
1634 Port ulPort = getUplinkPort(d);
1635 if (ulPort != null) {
1636 return (ulPort.number().toLong() != p.number().toLong());
1637 }
1638 return false;
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001639 }
1640
Jonathan Hart4c538002018-08-23 10:11:54 -07001641 private SubscriberAndDeviceInformation getOltInfo(Device dev) {
1642 String devSerialNo = dev.serialNumber();
Gamze Abaka641fc072018-09-04 09:16:27 +00001643 return subsService.get(devSerialNo);
Jonathan Hart4c538002018-08-23 10:11:54 -07001644 }
1645
Gamze Abaka33feef52019-02-27 08:16:47 +00001646 private MeterId getMeterIdFromBpMapping(DeviceId deviceId, String bandwidthProfile) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001647 if (bpInfoToMeter.get(bandwidthProfile) == null) {
Saurav Daseae48de2019-06-19 13:26:15 -07001648 log.warn("Bandwidth Profile '{}' is not currently mapped to a meter",
1649 bandwidthProfile);
Gamze Abaka33feef52019-02-27 08:16:47 +00001650 return null;
1651 }
1652
1653 Optional<MeterKey> meterKeyForDevice = bpInfoToMeter.get(bandwidthProfile)
1654 .stream()
1655 .filter(meterKey -> meterKey.deviceId().equals(deviceId))
1656 .findFirst();
Saurav Daseae48de2019-06-19 13:26:15 -07001657 if (meterKeyForDevice.isPresent()) {
1658 log.debug("Found meter {} for bandwidth profile {}",
1659 meterKeyForDevice.get().meterId(), bandwidthProfile);
1660 return meterKeyForDevice.get().meterId();
1661 } else {
1662 log.warn("Bandwidth profile '{}' is not currently mapped to a meter",
1663 bandwidthProfile);
1664 return null;
1665 }
Gamze Abaka33feef52019-02-27 08:16:47 +00001666 }
1667
1668 private void addMeterIdToBpMapping(DeviceId deviceId, MeterId meterId, String bandwidthProfile) {
1669
1670 if (bpInfoToMeter.get(bandwidthProfile) == null) {
1671 bpInfoToMeter.put(bandwidthProfile,
1672 new ArrayList<>(Arrays.asList(MeterKey.key(deviceId, meterId))));
1673 } else {
Gamze Abaka33feef52019-02-27 08:16:47 +00001674 List<MeterKey> meterKeyListForBp = bpInfoToMeter.get(bandwidthProfile);
1675 meterKeyListForBp.add(MeterKey.key(deviceId, meterId));
1676 }
1677 }
1678
Saurav Das747a7da2019-06-27 12:28:06 -07001679 /**
1680 * Removes meter key from programmed meters. If the meter has no reference
1681 * count in the data plane and is not present in the programmed-meters store
1682 * it will be removed.
1683 *
1684 * @param deviceId device identifier
1685 * @param bandwidthProfileId name of bandwidth profile
1686 */
1687 private void removeMeterIdFromPrgMeters(DeviceId deviceId,
1688 String bandwidthProfileId) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001689 List<MeterKey> meterKeysForBp = bpInfoToMeter.get(bandwidthProfileId);
1690 if (meterKeysForBp != null) {
1691 meterKeysForBp.stream()
1692 .filter(meterKey -> meterKey.deviceId().equals(deviceId))
1693 .findFirst().ifPresent(mk -> {
Gamze Abaka33feef52019-02-27 08:16:47 +00001694 programmedMeters.remove(mk);
1695 });
1696 }
1697 }
1698
alshabibf0e7e702015-05-30 18:22:36 -07001699 private class InternalDeviceListener implements DeviceListener {
Saurav Dasa9d5f442019-03-06 19:32:48 -08001700 private Set<DeviceId> programmedDevices = Sets.newConcurrentHashSet();
1701
alshabibf0e7e702015-05-30 18:22:36 -07001702 @Override
1703 public void event(DeviceEvent event) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001704 eventExecutor.execute(() -> {
1705 DeviceId devId = event.subject().id();
1706 Device dev = event.subject();
Gamze Abaka838d8142019-02-21 07:06:55 +00001707 Port port = event.port();
Jonathan Hart4c538002018-08-23 10:11:54 -07001708
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001709 if (event.type() == DeviceEvent.Type.PORT_STATS_UPDATED) {
1710 return;
1711 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001712
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001713 if (getOltInfo(dev) == null) {
Saurav Dasa9d5f442019-03-06 19:32:48 -08001714 // it's possible that we got an event for a previously
1715 // programmed OLT that is no longer available in SADIS
1716 // we let such events go through
1717 if (!programmedDevices.contains(devId)) {
1718 log.warn("No device info found for {}, this is either "
1719 + "not an OLT or not known to sadis", dev);
1720 return;
1721 }
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001722 }
Jonathan Hart4c538002018-08-23 10:11:54 -07001723
Saurav Daseae48de2019-06-19 13:26:15 -07001724 log.debug("OLT got {} event for {}: {}", event.type(),
1725 event.subject().id(), event);
Jonathan Hart4c538002018-08-23 10:11:54 -07001726
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001727 switch (event.type()) {
1728 //TODO: Port handling and bookkeeping should be improved once
1729 // olt firmware handles correct behaviour.
1730 case PORT_ADDED:
Gamze Abaka838d8142019-02-21 07:06:55 +00001731 if (isUniPort(dev, port)) {
1732 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, port));
Gamze Abaka838d8142019-02-21 07:06:55 +00001733 if (port.isEnabled()) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001734 processEapolFilteringObjectives(devId, port.number(), defaultBpId,
Gamze Abakada282b42019-03-11 13:16:48 +00001735 null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001736 }
1737 } else {
1738 checkAndCreateDeviceFlows(dev);
1739 }
1740 break;
1741 case PORT_REMOVED:
Gamze Abaka838d8142019-02-21 07:06:55 +00001742 if (isUniPort(dev, port)) {
Gamze Abaka853bf252019-03-25 10:27:06 +00001743 removeSubscriber(new ConnectPoint(devId, port.number()));
Andy Bavier160e8682019-05-07 18:32:22 -07001744 processEapolFilteringObjectives(devId, port.number(), defaultBpId,
1745 null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), false);
1746
Gamze Abaka838d8142019-02-21 07:06:55 +00001747 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, port));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001748 }
1749
1750 break;
1751 case PORT_UPDATED:
Gamze Abaka838d8142019-02-21 07:06:55 +00001752 if (!isUniPort(dev, port)) {
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001753 break;
1754 }
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001755
Gamze Abakada282b42019-03-11 13:16:48 +00001756 SubscriberAndDeviceInformation sub = programmedSubs
1757 .get(new ConnectPoint(devId, port.number()));
1758 VlanId vlanId = sub == null ? VlanId.vlanId(EAPOL_DEFAULT_VLAN) : sub.cTag();
1759
1760 String bpId = getCurrentBandwidthProfile(new ConnectPoint(devId, port.number()));
1761
Gamze Abaka838d8142019-02-21 07:06:55 +00001762 if (port.isEnabled()) {
Gamze Abakada282b42019-03-11 13:16:48 +00001763 processEapolFilteringObjectives(devId, port.number(), bpId,
1764 null, vlanId, true);
Gamze Abaka33feef52019-02-27 08:16:47 +00001765
Gamze Abaka838d8142019-02-21 07:06:55 +00001766 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, port));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001767 } else {
Gamze Abakada282b42019-03-11 13:16:48 +00001768 processEapolFilteringObjectives(devId, port.number(), bpId,
1769 null, vlanId, false);
Gamze Abaka838d8142019-02-21 07:06:55 +00001770 post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, port));
Jonathan Hart1d34c8b2018-05-05 15:37:28 -07001771 }
alshabibbb83aa22016-02-10 15:08:23 -08001772 break;
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001773 case DEVICE_ADDED:
alshabib7c190012016-02-09 18:22:33 -08001774 post(new AccessDeviceEvent(
1775 AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
1776 null, null));
Saurav Dasa9d5f442019-03-06 19:32:48 -08001777 programmedDevices.add(devId);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001778 // Send UNI_ADDED events for all existing ports
1779 deviceService.getPorts(devId).stream()
1780 .filter(p -> isUniPort(dev, p))
1781 .filter(Port::isEnabled)
1782 .forEach(p -> post(new AccessDeviceEvent(
1783 AccessDeviceEvent.Type.UNI_ADDED, devId, p)));
1784
Jonathan Hart403372d2018-08-22 11:44:13 -07001785 checkAndCreateDeviceFlows(dev);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001786 break;
1787 case DEVICE_REMOVED:
1788 deviceService.getPorts(devId).stream()
1789 .filter(p -> isUniPort(dev, p))
1790 .forEach(p -> post(new AccessDeviceEvent(
1791 AccessDeviceEvent.Type.UNI_REMOVED, devId, p)));
Saurav Dasa9d5f442019-03-06 19:32:48 -08001792 programmedDevices.remove(devId);
Gamze Abakada282b42019-03-11 13:16:48 +00001793 removeAllSubscribers(devId);
alshabib7c190012016-02-09 18:22:33 -08001794 post(new AccessDeviceEvent(
1795 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
1796 null, null));
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001797 break;
1798 case DEVICE_AVAILABILITY_CHANGED:
1799 if (deviceService.isAvailable(devId)) {
1800 post(new AccessDeviceEvent(
1801 AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
1802 null, null));
Gamze Abakada282b42019-03-11 13:16:48 +00001803 programmedDevices.add(devId);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001804 checkAndCreateDeviceFlows(dev);
1805 } else {
Gamze Abakada282b42019-03-11 13:16:48 +00001806 programmedDevices.remove(devId);
1807 removeAllSubscribers(devId);
Matteo Scandolo632f0fc2018-09-07 12:21:45 -07001808 post(new AccessDeviceEvent(
1809 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
1810 null, null));
1811 }
1812 break;
1813 case DEVICE_UPDATED:
1814 case DEVICE_SUSPENDED:
1815 case PORT_STATS_UPDATED:
1816 default:
1817 return;
1818 }
1819 });
alshabibf0e7e702015-05-30 18:22:36 -07001820 }
Gamze Abaka838d8142019-02-21 07:06:55 +00001821
1822 private String getCurrentBandwidthProfile(ConnectPoint connectPoint) {
1823 SubscriberAndDeviceInformation sub = programmedSubs.get(connectPoint);
1824 if (sub != null) {
1825 return sub.upstreamBandwidthProfile();
1826 }
1827 return defaultBpId;
1828 }
Gamze Abakada282b42019-03-11 13:16:48 +00001829
1830 private void removeAllSubscribers(DeviceId deviceId) {
1831 List<ConnectPoint> connectPoints = programmedSubs.keySet().stream()
1832 .filter(ks -> Objects.equals(ks.deviceId(), deviceId))
1833 .collect(Collectors.toList());
1834
1835 connectPoints.forEach(cp -> programmedSubs.remove(cp));
1836 }
alshabibf0e7e702015-05-30 18:22:36 -07001837 }
Gamze Abaka641fc072018-09-04 09:16:27 +00001838
1839 private class InternalMeterListener implements MeterListener {
1840
1841 @Override
1842 public void event(MeterEvent meterEvent) {
1843 if (deleteMeters && MeterEvent.Type.METER_REFERENCE_COUNT_ZERO.equals(meterEvent.type())) {
Saurav Daseae48de2019-06-19 13:26:15 -07001844 log.debug("Zero Count Meter {} received", meterEvent.subject());
Gamze Abaka641fc072018-09-04 09:16:27 +00001845 Meter meter = meterEvent.subject();
Gamze Abaka33feef52019-02-27 08:16:47 +00001846 if (meter != null && appId.equals(meter.appId()) &&
1847 !programmedMeters.contains(MeterKey.key(meter.deviceId(), meter.id()))) {
Saurav Daseae48de2019-06-19 13:26:15 -07001848 log.info("Deleting unreferenced, no longer programmed Meter {}",
1849 meter.id());
Gamze Abaka641fc072018-09-04 09:16:27 +00001850 deleteMeter(meter.deviceId(), meter.id());
1851 }
1852 } else if (MeterEvent.Type.METER_REMOVED.equals(meterEvent.type())) {
Saurav Daseae48de2019-06-19 13:26:15 -07001853 log.debug("Meter removed event is received. Meter is {}",
1854 meterEvent.subject());
Gamze Abaka641fc072018-09-04 09:16:27 +00001855 removeMeterFromBpMap(meterEvent.subject());
1856 }
1857 }
1858
1859 private void deleteMeter(DeviceId deviceId, MeterId meterId) {
1860 Meter meter = meterService.getMeter(deviceId, meterId);
Gamze Abaka838d8142019-02-21 07:06:55 +00001861 if (meter != null) {
1862 MeterRequest meterRequest = DefaultMeterRequest.builder()
1863 .withBands(meter.bands())
1864 .withUnit(meter.unit())
1865 .forDevice(deviceId)
1866 .fromApp(appId)
1867 .burst()
1868 .remove();
Gamze Abaka641fc072018-09-04 09:16:27 +00001869
Gamze Abaka838d8142019-02-21 07:06:55 +00001870 meterService.withdraw(meterRequest, meterId);
1871 }
Gamze Abaka641fc072018-09-04 09:16:27 +00001872 }
1873
1874 private void removeMeterFromBpMap(Meter meter) {
Gamze Abaka33feef52019-02-27 08:16:47 +00001875 bpInfoToMeter.values().forEach(meterKeys -> meterKeys.stream()
1876 .filter(meterKey -> (meterKey.deviceId().equals(meter.deviceId()))
1877 && meterKey.meterId().equals(meter.id())).findFirst().
1878 ifPresent(mk -> {
1879 meterKeys.remove(mk);
Gamze Abakada282b42019-03-11 13:16:48 +00001880 programmedMeters.remove(mk);
Gamze Abaka33feef52019-02-27 08:16:47 +00001881 log.info("Deleted from the internal map. MeterKey {}", mk);
1882 log.info("Programmed meters {}", programmedMeters);
1883 }));
Gamze Abaka641fc072018-09-04 09:16:27 +00001884 }
1885 }
Hardik Windlass395ff372019-06-13 05:16:00 +00001886}