blob: f53fff8af125f064a2c12045680bc151b5a210b3 [file] [log] [blame]
Amit Ghosh47243cb2017-07-26 05:08:53 +01001/*
Deepa vaddireddy0060f532017-08-04 06:46:05 +00002 * Copyright 2017-present Open Networking Foundation
Amit Ghosh47243cb2017-07-26 05:08:53 +01003 *
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 */
Matteo Scandolo57af5d12019-04-29 17:11:41 -070016package org.opencord.dhcpl2relay.impl;
Amit Ghosh47243cb2017-07-26 05:08:53 +010017
Jonathan Hart617bc3e2020-02-14 10:42:23 -080018import com.google.common.collect.ImmutableMap;
Carmelo Casconede1e6e32019-07-15 19:39:08 -070019import com.google.common.collect.ImmutableSet;
20import com.google.common.collect.Lists;
Carmelo Casconede1e6e32019-07-15 19:39:08 -070021import com.google.common.collect.Sets;
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -030022import org.apache.commons.io.HexDump;
Amit Ghosh47243cb2017-07-26 05:08:53 +010023import org.onlab.packet.DHCP;
Deepa vaddireddy0060f532017-08-04 06:46:05 +000024import org.onlab.packet.Ethernet;
Amit Ghosh47243cb2017-07-26 05:08:53 +010025import org.onlab.packet.IPv4;
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +053026import org.onlab.packet.IpAddress;
Deepa vaddireddy0060f532017-08-04 06:46:05 +000027import org.onlab.packet.MacAddress;
Amit Ghosh47243cb2017-07-26 05:08:53 +010028import org.onlab.packet.TpPort;
29import org.onlab.packet.UDP;
30import org.onlab.packet.VlanId;
Jonathan Hartedbf6422018-05-02 17:30:05 -070031import org.onlab.packet.dhcp.DhcpOption;
Jonathan Hart617bc3e2020-02-14 10:42:23 -080032import org.onlab.util.KryoNamespace;
Amit Ghosh47243cb2017-07-26 05:08:53 +010033import org.onlab.util.Tools;
34import org.onosproject.cfg.ComponentConfigService;
Jonathan Hart617bc3e2020-02-14 10:42:23 -080035import org.onosproject.cluster.ClusterService;
36import org.onosproject.cluster.LeadershipService;
Andrea Campanella6f45a1b2020-05-08 17:50:12 +020037import org.onosproject.cluster.NodeId;
Amit Ghosh47243cb2017-07-26 05:08:53 +010038import org.onosproject.core.ApplicationId;
39import org.onosproject.core.CoreService;
Jonathan Hartc36c9552018-07-31 15:07:53 -040040import org.onosproject.event.AbstractListenerManager;
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +053041import org.onosproject.mastership.MastershipEvent;
42import org.onosproject.mastership.MastershipListener;
43import org.onosproject.mastership.MastershipService;
Amit Ghosh47243cb2017-07-26 05:08:53 +010044import org.onosproject.net.AnnotationKeys;
45import org.onosproject.net.ConnectPoint;
Amit Ghosh83c8c892017-11-09 11:08:27 +000046import org.onosproject.net.Device;
47import org.onosproject.net.DeviceId;
Amit Ghosh47243cb2017-07-26 05:08:53 +010048import org.onosproject.net.Host;
49import org.onosproject.net.Port;
Amit Ghosh83c8c892017-11-09 11:08:27 +000050import org.onosproject.net.PortNumber;
Amit Ghosh47243cb2017-07-26 05:08:53 +010051import org.onosproject.net.config.ConfigFactory;
52import org.onosproject.net.config.NetworkConfigEvent;
53import org.onosproject.net.config.NetworkConfigListener;
54import org.onosproject.net.config.NetworkConfigRegistry;
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +053055import org.onosproject.net.device.DeviceEvent;
56import org.onosproject.net.device.DeviceListener;
Amit Ghosh47243cb2017-07-26 05:08:53 +010057import org.onosproject.net.device.DeviceService;
58import org.onosproject.net.flow.DefaultTrafficSelector;
59import org.onosproject.net.flow.DefaultTrafficTreatment;
60import org.onosproject.net.flow.TrafficSelector;
61import org.onosproject.net.flow.TrafficTreatment;
Saurav Dasb4e3e102018-10-02 15:31:17 -070062import org.onosproject.net.flowobjective.FlowObjectiveService;
Amit Ghosh47243cb2017-07-26 05:08:53 +010063import org.onosproject.net.host.HostService;
64import org.onosproject.net.packet.DefaultOutboundPacket;
65import org.onosproject.net.packet.OutboundPacket;
66import org.onosproject.net.packet.PacketContext;
67import org.onosproject.net.packet.PacketPriority;
68import org.onosproject.net.packet.PacketProcessor;
69import org.onosproject.net.packet.PacketService;
Jonathan Hart617bc3e2020-02-14 10:42:23 -080070import org.onosproject.store.serializers.KryoNamespaces;
71import org.onosproject.store.service.ConsistentMap;
72import org.onosproject.store.service.Serializer;
73import org.onosproject.store.service.StorageService;
74import org.onosproject.store.service.Versioned;
Matteo Scandolo57af5d12019-04-29 17:11:41 -070075import org.opencord.dhcpl2relay.DhcpAllocationInfo;
76import org.opencord.dhcpl2relay.DhcpL2RelayEvent;
77import org.opencord.dhcpl2relay.DhcpL2RelayListener;
78import org.opencord.dhcpl2relay.DhcpL2RelayService;
Jonathan Hart77ca3152020-02-21 14:31:21 -080079import org.opencord.dhcpl2relay.DhcpL2RelayStoreDelegate;
Matteo Scandolo57af5d12019-04-29 17:11:41 -070080import org.opencord.dhcpl2relay.impl.packet.DhcpOption82;
Gamze Abakac806c6c2018-12-03 12:49:46 +000081import org.opencord.sadis.BaseInformationService;
82import org.opencord.sadis.SadisService;
Amit Ghosh47243cb2017-07-26 05:08:53 +010083import org.opencord.sadis.SubscriberAndDeviceInformation;
Gamze Abakaa64b3bc2020-01-31 06:51:43 +000084import org.opencord.sadis.UniTagInformation;
Amit Ghosh47243cb2017-07-26 05:08:53 +010085import org.osgi.service.component.ComponentContext;
Carmelo Casconede1e6e32019-07-15 19:39:08 -070086import org.osgi.service.component.annotations.Activate;
87import org.osgi.service.component.annotations.Component;
88import org.osgi.service.component.annotations.Deactivate;
89import org.osgi.service.component.annotations.Modified;
90import org.osgi.service.component.annotations.Reference;
91import org.osgi.service.component.annotations.ReferenceCardinality;
Amit Ghosh47243cb2017-07-26 05:08:53 +010092import org.slf4j.Logger;
93import org.slf4j.LoggerFactory;
94
Jonathan Hart617bc3e2020-02-14 10:42:23 -080095import java.io.ByteArrayOutputStream;
96import java.nio.ByteBuffer;
97import java.time.Instant;
Jonathan Hart617bc3e2020-02-14 10:42:23 -080098import java.util.ArrayList;
99import java.util.Dictionary;
100import java.util.List;
101import java.util.Map;
Jonathan Hart617bc3e2020-02-14 10:42:23 -0800102import java.util.Optional;
103import java.util.Set;
104import java.util.concurrent.Executors;
105import java.util.concurrent.ScheduledExecutorService;
106import java.util.concurrent.ScheduledFuture;
Jonathan Hart617bc3e2020-02-14 10:42:23 -0800107import java.util.concurrent.atomic.AtomicReference;
108import java.util.function.Predicate;
109import java.util.stream.Collectors;
110
111import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_MessageType;
112import static org.onlab.packet.MacAddress.valueOf;
Jonathan Hart617bc3e2020-02-14 10:42:23 -0800113import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
Jonathan Hart617bc3e2020-02-14 10:42:23 -0800114import static org.opencord.dhcpl2relay.impl.OsgiPropertyConstants.ENABLE_DHCP_BROADCAST_REPLIES;
115import static org.opencord.dhcpl2relay.impl.OsgiPropertyConstants.ENABLE_DHCP_BROADCAST_REPLIES_DEFAULT;
116import static org.opencord.dhcpl2relay.impl.OsgiPropertyConstants.OPTION_82;
117import static org.opencord.dhcpl2relay.impl.OsgiPropertyConstants.OPTION_82_DEFAULT;
Amit Ghosh47243cb2017-07-26 05:08:53 +0100118
119/**
120 * DHCP Relay Agent Application Component.
121 */
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700122@Component(immediate = true,
123property = {
124 OPTION_82 + ":Boolean=" + OPTION_82_DEFAULT,
125 ENABLE_DHCP_BROADCAST_REPLIES + ":Boolean=" + ENABLE_DHCP_BROADCAST_REPLIES_DEFAULT,
126})
Jonathan Hartc36c9552018-07-31 15:07:53 -0400127public class DhcpL2Relay
128 extends AbstractListenerManager<DhcpL2RelayEvent, DhcpL2RelayListener>
129 implements DhcpL2RelayService {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100130
131 public static final String DHCP_L2RELAY_APP = "org.opencord.dhcpl2relay";
Saurav Dasb4e3e102018-10-02 15:31:17 -0700132 private static final String HOST_LOC_PROVIDER =
133 "org.onosproject.provider.host.impl.HostLocationProvider";
Jonathan Hart617bc3e2020-02-14 10:42:23 -0800134 private static final String LEADER_TOPIC = "dhcpl2relay-leader";
Amit Ghosh47243cb2017-07-26 05:08:53 +0100135 private final Logger log = LoggerFactory.getLogger(getClass());
136 private final InternalConfigListener cfgListener =
137 new InternalConfigListener();
138
139 private final Set<ConfigFactory> factories = ImmutableSet.of(
140 new ConfigFactory<ApplicationId, DhcpL2RelayConfig>(APP_SUBJECT_FACTORY,
141 DhcpL2RelayConfig.class,
142 "dhcpl2relay") {
143 @Override
144 public DhcpL2RelayConfig createConfig() {
145 return new DhcpL2RelayConfig();
146 }
147 }
148 );
149
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700150 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Amit Ghosh47243cb2017-07-26 05:08:53 +0100151 protected NetworkConfigRegistry cfgService;
152
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700153 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Amit Ghosh47243cb2017-07-26 05:08:53 +0100154 protected CoreService coreService;
155
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700156 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Amit Ghosh47243cb2017-07-26 05:08:53 +0100157 protected PacketService packetService;
158
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700159 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Amit Ghosh47243cb2017-07-26 05:08:53 +0100160 protected HostService hostService;
161
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700162 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Amit Ghosh47243cb2017-07-26 05:08:53 +0100163 protected ComponentConfigService componentConfigService;
164
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700165 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Gamze Abakac806c6c2018-12-03 12:49:46 +0000166 protected SadisService sadisService;
Amit Ghosh47243cb2017-07-26 05:08:53 +0100167
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700168 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Amit Ghosh47243cb2017-07-26 05:08:53 +0100169 protected DeviceService deviceService;
170
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700171 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Amit Ghosh8951f042017-08-10 13:48:10 +0100172 protected MastershipService mastershipService;
173
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700174 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Hart617bc3e2020-02-14 10:42:23 -0800175 protected StorageService storageService;
176
177 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Saurav Dasb4e3e102018-10-02 15:31:17 -0700178 protected FlowObjectiveService flowObjectiveService;
179
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300180 @Reference(cardinality = ReferenceCardinality.MANDATORY)
181 protected DhcpL2RelayCountersStore dhcpL2RelayCounters;
182
Jonathan Hart617bc3e2020-02-14 10:42:23 -0800183 @Reference(cardinality = ReferenceCardinality.MANDATORY)
184 protected LeadershipService leadershipService;
185
186 @Reference(cardinality = ReferenceCardinality.MANDATORY)
187 protected ClusterService clusterService;
188
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300189 // OSGi Properties
Carmelo Cascone4330cf12019-11-15 21:34:02 -0800190 /** Add option 82 to relayed packets. */
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700191 protected boolean option82 = OPTION_82_DEFAULT;
Carmelo Cascone4330cf12019-11-15 21:34:02 -0800192 /** Ask the DHCP Server to send back replies as L2 broadcast. */
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700193 protected boolean enableDhcpBroadcastReplies = ENABLE_DHCP_BROADCAST_REPLIES_DEFAULT;
Amit Ghosha17354e2017-08-23 12:56:04 +0100194
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300195 ScheduledFuture<?> refreshTask;
196 ScheduledExecutorService refreshService = Executors.newSingleThreadScheduledExecutor();
197
Amit Ghosh47243cb2017-07-26 05:08:53 +0100198 private DhcpRelayPacketProcessor dhcpRelayPacketProcessor =
199 new DhcpRelayPacketProcessor();
200
Amit Ghosh8951f042017-08-10 13:48:10 +0100201 private InnerMastershipListener changeListener = new InnerMastershipListener();
202 private InnerDeviceListener deviceListener = new InnerDeviceListener();
Amit Ghosh47243cb2017-07-26 05:08:53 +0100203
Amit Ghosh8951f042017-08-10 13:48:10 +0100204 // connect points to the DHCP server
205 Set<ConnectPoint> dhcpConnectPoints;
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300206 protected AtomicReference<ConnectPoint> dhcpServerConnectPoint = new AtomicReference<>();
Amit Ghosh47243cb2017-07-26 05:08:53 +0100207 private MacAddress dhcpConnectMac = MacAddress.BROADCAST;
208 private ApplicationId appId;
209
Jonathan Hart617bc3e2020-02-14 10:42:23 -0800210 private ConsistentMap<String, DhcpAllocationInfo> allocations;
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300211 protected boolean modifyClientPktsSrcDstMac = false;
Amit Ghosh83c8c892017-11-09 11:08:27 +0000212 //Whether to use the uplink port of the OLTs to send/receive messages to the DHCP server
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300213 protected boolean useOltUplink = false;
Amit Ghosha17354e2017-08-23 12:56:04 +0100214
Gamze Abakac806c6c2018-12-03 12:49:46 +0000215 private BaseInformationService<SubscriberAndDeviceInformation> subsService;
216
Jonathan Hart77ca3152020-02-21 14:31:21 -0800217 private DhcpL2RelayStoreDelegate delegate = new InnerDhcpL2RelayStoreDelegate();
218
Amit Ghosh47243cb2017-07-26 05:08:53 +0100219 @Activate
220 protected void activate(ComponentContext context) {
221 //start the dhcp relay agent
222 appId = coreService.registerApplication(DHCP_L2RELAY_APP);
Saurav Dasb4e3e102018-10-02 15:31:17 -0700223 // ensure that host-learning via dhcp includes IP addresses
224 componentConfigService.preSetProperty(HOST_LOC_PROVIDER,
225 "useDhcp", Boolean.TRUE.toString());
Amit Ghosh47243cb2017-07-26 05:08:53 +0100226 componentConfigService.registerProperties(getClass());
Jonathan Hartc36c9552018-07-31 15:07:53 -0400227 eventDispatcher.addSink(DhcpL2RelayEvent.class, listenerRegistry);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100228
Jonathan Hart617bc3e2020-02-14 10:42:23 -0800229 KryoNamespace serializer = KryoNamespace.newBuilder()
230 .register(KryoNamespaces.API)
231 .register(Instant.class)
232 .register(DHCP.MsgType.class)
233 .register(DhcpAllocationInfo.class)
234 .build();
235
236 allocations = storageService.<String, DhcpAllocationInfo>consistentMapBuilder()
237 .withName("dhcpl2relay-allocations")
238 .withSerializer(Serializer.using(serializer))
239 .withApplicationId(appId)
240 .build();
241
242 leadershipService.runForLeadership(LEADER_TOPIC);
243
Jonathan Hart77ca3152020-02-21 14:31:21 -0800244 dhcpL2RelayCounters.setDelegate(delegate);
245
Amit Ghosh47243cb2017-07-26 05:08:53 +0100246 cfgService.addListener(cfgListener);
Amit Ghosh8951f042017-08-10 13:48:10 +0100247 mastershipService.addListener(changeListener);
248 deviceService.addListener(deviceListener);
249
Matteo Scandolo45e5a272019-09-30 09:30:32 -0700250 subsService = sadisService.getSubscriberInfoService();
251
Amit Ghosh47243cb2017-07-26 05:08:53 +0100252 factories.forEach(cfgService::registerConfigFactory);
253 //update the dhcp server configuration.
254 updateConfig();
255 //add the packet services.
256 packetService.addProcessor(dhcpRelayPacketProcessor,
257 PacketProcessor.director(0));
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000258 if (context != null) {
259 modified(context);
260 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100261
262 log.info("DHCP-L2-RELAY Started");
263 }
264
265 @Deactivate
266 protected void deactivate() {
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300267 if (refreshTask != null) {
268 refreshTask.cancel(true);
269 }
270 if (refreshService != null) {
271 refreshService.shutdownNow();
272 }
Jonathan Hart77ca3152020-02-21 14:31:21 -0800273 dhcpL2RelayCounters.unsetDelegate(delegate);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100274 cfgService.removeListener(cfgListener);
275 factories.forEach(cfgService::unregisterConfigFactory);
276 packetService.removeProcessor(dhcpRelayPacketProcessor);
Saurav Dasb4e3e102018-10-02 15:31:17 -0700277 cancelDhcpPktsFromServer();
Amit Ghosh47243cb2017-07-26 05:08:53 +0100278
279 componentConfigService.unregisterProperties(getClass(), false);
Deepa Vaddireddy77a6ac72017-09-20 20:36:52 +0530280 deviceService.removeListener(deviceListener);
281 mastershipService.removeListener(changeListener);
Jonathan Hartc36c9552018-07-31 15:07:53 -0400282 eventDispatcher.removeSink(DhcpL2RelayEvent.class);
Jonathan Hart617bc3e2020-02-14 10:42:23 -0800283 leadershipService.withdraw(LEADER_TOPIC);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100284 log.info("DHCP-L2-RELAY Stopped");
285 }
286
287 @Modified
288 protected void modified(ComponentContext context) {
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000289
Amit Ghosh47243cb2017-07-26 05:08:53 +0100290 Dictionary<?, ?> properties = context.getProperties();
291
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700292 Boolean o = Tools.isPropertyEnabled(properties, OPTION_82);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100293 if (o != null) {
294 option82 = o;
295 }
Amit Ghosh2095dc62017-09-25 20:56:55 +0100296
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700297 o = Tools.isPropertyEnabled(properties, ENABLE_DHCP_BROADCAST_REPLIES);
Amit Ghosh2095dc62017-09-25 20:56:55 +0100298 if (o != null) {
299 enableDhcpBroadcastReplies = o;
300 }
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300301 }
302
Jonathan Hart617bc3e2020-02-14 10:42:23 -0800303 @Override
304 public Map<String, DhcpAllocationInfo> getAllocationInfo() {
305 return ImmutableMap.copyOf(allocations.asJavaMap());
306 }
307
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300308 /**
Amit Ghosh47243cb2017-07-26 05:08:53 +0100309 * Checks if this app has been configured.
310 *
311 * @return true if all information we need have been initialized
312 */
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300313 protected boolean configured() {
Amit Ghosh83c8c892017-11-09 11:08:27 +0000314 if (!useOltUplink) {
315 return dhcpServerConnectPoint.get() != null;
316 }
317 return true;
Amit Ghosh47243cb2017-07-26 05:08:53 +0100318 }
319
Amit Ghosh8951f042017-08-10 13:48:10 +0100320 /**
321 * Selects a connect point through an available device for which it is the master.
322 */
323 private void selectServerConnectPoint() {
324 synchronized (this) {
325 dhcpServerConnectPoint.set(null);
326 if (dhcpConnectPoints != null) {
327 // find a connect point through a device for which we are master
328 for (ConnectPoint cp: dhcpConnectPoints) {
Andrea Campanella6f45a1b2020-05-08 17:50:12 +0200329 if (isLocalLeader(cp.deviceId())) {
Amit Ghosh8951f042017-08-10 13:48:10 +0100330 if (deviceService.isAvailable(cp.deviceId())) {
331 dhcpServerConnectPoint.set(cp);
332 }
333 log.info("DHCP connectPoint selected is {}", cp);
334 break;
335 }
336 }
337 }
338
339 log.info("DHCP Server connectPoint is {}", dhcpServerConnectPoint.get());
340
341 if (dhcpServerConnectPoint.get() == null) {
342 log.error("Master of none, can't relay DHCP Message to server");
343 }
344 }
345 }
346
347 /**
348 * Updates the network configuration.
349 */
Amit Ghosh47243cb2017-07-26 05:08:53 +0100350 private void updateConfig() {
351 DhcpL2RelayConfig cfg = cfgService.getConfig(appId, DhcpL2RelayConfig.class);
352 if (cfg == null) {
353 log.warn("Dhcp Server info not available");
354 return;
355 }
Amit Ghosh8951f042017-08-10 13:48:10 +0100356
357 dhcpConnectPoints = Sets.newConcurrentHashSet(cfg.getDhcpServerConnectPoint());
Amit Ghosh83c8c892017-11-09 11:08:27 +0000358 modifyClientPktsSrcDstMac = cfg.getModifySrcDstMacAddresses();
Saurav Dasb4e3e102018-10-02 15:31:17 -0700359 boolean prevUseOltUplink = useOltUplink;
Amit Ghosh83c8c892017-11-09 11:08:27 +0000360 useOltUplink = cfg.getUseOltUplinkForServerPktInOut();
Amit Ghosh8951f042017-08-10 13:48:10 +0100361
Saurav Dasb4e3e102018-10-02 15:31:17 -0700362 if (useOltUplink) {
363 for (ConnectPoint cp : getUplinkPortsOfOlts()) {
364 log.debug("requestDhcpPackets: ConnectPoint: {}", cp);
Matteo Scandolo45e5a272019-09-30 09:30:32 -0700365 requestDhcpPacketsFromConnectPoint(cp, Optional.ofNullable(null));
Saurav Dasb4e3e102018-10-02 15:31:17 -0700366 }
367 // check if previous config was different and so trap flows may
Saurav Dasb14f08a2019-02-22 16:34:15 -0800368 // need to be removed from other places like AGG switches
Saurav Dasb4e3e102018-10-02 15:31:17 -0700369 if (!prevUseOltUplink) {
Saurav Dasb14f08a2019-02-22 16:34:15 -0800370 addOrRemoveDhcpTrapFromServer(false);
Saurav Dasb4e3e102018-10-02 15:31:17 -0700371 }
Saurav Dasb4e3e102018-10-02 15:31:17 -0700372 } else {
Saurav Dasb14f08a2019-02-22 16:34:15 -0800373 // uplink on AGG switch
374 addOrRemoveDhcpTrapFromServer(true);
Saurav Dasb4e3e102018-10-02 15:31:17 -0700375 }
376 }
377
378 private void cancelDhcpPktsFromServer() {
379 if (useOltUplink) {
380 for (ConnectPoint cp : getUplinkPortsOfOlts()) {
381 log.debug("cancelDhcpPackets: ConnectPoint: {}", cp);
Matteo Scandolo45e5a272019-09-30 09:30:32 -0700382 cancelDhcpPacketsFromConnectPoint(cp, Optional.ofNullable(null));
Saurav Dasb4e3e102018-10-02 15:31:17 -0700383 }
384 } else {
Saurav Dasb14f08a2019-02-22 16:34:15 -0800385 // uplink on AGG switch
386 addOrRemoveDhcpTrapFromServer(false);
Amit Ghosh83c8c892017-11-09 11:08:27 +0000387 }
Saurav Dasb4e3e102018-10-02 15:31:17 -0700388 }
389
Saurav Dasb14f08a2019-02-22 16:34:15 -0800390 /**
391 * Used to add or remove DHCP trap flow for packets received from DHCP server.
392 * Typically used on a non OLT device, like an AGG switch. When adding, a
393 * new dhcp server connect point is selected from the configured options.
394 *
395 * @param add true if dhcp trap flow is to be added, false to remove the
396 * trap flow
397 */
398 private void addOrRemoveDhcpTrapFromServer(boolean add) {
399 if (add) {
400 selectServerConnectPoint();
401 log.debug("dhcp server connect point: " + dhcpServerConnectPoint);
402 }
403 if (dhcpServerConnectPoint.get() == null) {
404 log.warn("No dhcpServer connectPoint found, cannot {} dhcp trap flows",
405 (add) ? "install" : "remove");
406 return;
407 }
408 if (add) {
409 log.info("Adding trap to dhcp server connect point: "
410 + dhcpServerConnectPoint);
411 requestDhcpPacketsFromConnectPoint(dhcpServerConnectPoint.get(),
412 Optional.of(PacketPriority.HIGH1));
413 } else {
414 log.info("Removing trap from dhcp server connect point: "
415 + dhcpServerConnectPoint);
416 cancelDhcpPacketsFromConnectPoint(dhcpServerConnectPoint.get(),
417 Optional.of(PacketPriority.HIGH1));
418 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100419 }
420
421 /**
Amit Ghosh83c8c892017-11-09 11:08:27 +0000422 * Returns all the uplink ports of OLTs configured in SADIS.
423 * Only ports visible in ONOS and for which this instance is master
424 * are returned
425 */
426 private List<ConnectPoint> getUplinkPortsOfOlts() {
427 List<ConnectPoint> cps = new ArrayList<>();
428
429 // find all the olt devices and if their uplink ports are visible
430 Iterable<Device> devices = deviceService.getDevices();
431 for (Device d : devices) {
432 // check if this device is provisioned in Sadis
433
434 log.debug("getUplinkPortsOfOlts: Checking mastership of {}", d);
435 // do only for devices for which we are the master
Andrea Campanella6f45a1b2020-05-08 17:50:12 +0200436 if (!isLocalLeader(d.id())) {
Amit Ghosh83c8c892017-11-09 11:08:27 +0000437 continue;
438 }
439
440 String devSerialNo = d.serialNumber();
441 SubscriberAndDeviceInformation deviceInfo = subsService.get(devSerialNo);
442 log.debug("getUplinkPortsOfOlts: Found device: {}", deviceInfo);
443 if (deviceInfo != null) {
444 // check if the uplink port with that number is available on the device
445 PortNumber pNum = PortNumber.portNumber(deviceInfo.uplinkPort());
446 Port port = deviceService.getPort(d.id(), pNum);
447 log.debug("getUplinkPortsOfOlts: Found port: {}", port);
448 if (port != null) {
449 cps.add(new ConnectPoint(d.id(), pNum));
450 }
451 }
452 }
453 return cps;
454 }
455
456 /**
457 * Returns whether the passed port is the uplink port of the olt device.
458 */
459 private boolean isUplinkPortOfOlt(DeviceId dId, Port p) {
460 log.debug("isUplinkPortOfOlt: DeviceId: {} Port: {}", dId, p);
Amit Ghosh83c8c892017-11-09 11:08:27 +0000461
462 Device d = deviceService.getDevice(dId);
463 SubscriberAndDeviceInformation deviceInfo = subsService.get(d.serialNumber());
464
465 if (deviceInfo != null) {
466 return (deviceInfo.uplinkPort() == p.number().toLong());
467 }
468
469 return false;
470 }
471
472 /**
473 * Returns the connectPoint which is the uplink port of the OLT.
474 */
475 private ConnectPoint getUplinkConnectPointOfOlt(DeviceId dId) {
476
477 Device d = deviceService.getDevice(dId);
478 SubscriberAndDeviceInformation deviceInfo = subsService.get(d.serialNumber());
479 log.debug("getUplinkConnectPointOfOlt DeviceId: {} devInfo: {}", dId, deviceInfo);
480 if (deviceInfo != null) {
481 PortNumber pNum = PortNumber.portNumber(deviceInfo.uplinkPort());
482 Port port = deviceService.getPort(d.id(), pNum);
483 if (port != null) {
484 return new ConnectPoint(d.id(), pNum);
485 }
486 }
487
488 return null;
489 }
490
491 /**
492 * Request DHCP packet from particular connect point via PacketService.
Saurav Dasb14f08a2019-02-22 16:34:15 -0800493 * Optionally provide a priority for the trap flow. If no such priority is
494 * provided, the default priority will be used.
495 *
496 * @param cp the connect point to trap dhcp packets from
497 * @param priority of the trap flow, null to use default priority
Amit Ghosh83c8c892017-11-09 11:08:27 +0000498 */
Saurav Dasb14f08a2019-02-22 16:34:15 -0800499 private void requestDhcpPacketsFromConnectPoint(ConnectPoint cp,
500 Optional<PacketPriority> priority) {
Amit Ghosh83c8c892017-11-09 11:08:27 +0000501 TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
502 .matchEthType(Ethernet.TYPE_IPV4)
503 .matchInPort(cp.port())
504 .matchIPProtocol(IPv4.PROTOCOL_UDP)
505 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_SERVER_PORT));
506 packetService.requestPackets(selectorServer.build(),
Saurav Dasb14f08a2019-02-22 16:34:15 -0800507 priority.isPresent() ? priority.get() : PacketPriority.CONTROL,
508 appId, Optional.of(cp.deviceId()));
Amit Ghosh83c8c892017-11-09 11:08:27 +0000509 }
510
511 /**
Saurav Dasb14f08a2019-02-22 16:34:15 -0800512 * Cancel DHCP packet from particular connect point via PacketService. If
513 * the request was made with a specific packet priority, then the same
514 * priority should be used in this call.
515 *
516 * @param cp the connect point for the trap flow
517 * @param priority with which the trap flow was requested; if request
518 * priority was not specified, this param should also be null
Amit Ghosh83c8c892017-11-09 11:08:27 +0000519 */
Saurav Dasb14f08a2019-02-22 16:34:15 -0800520 private void cancelDhcpPacketsFromConnectPoint(ConnectPoint cp,
521 Optional<PacketPriority> priority) {
Amit Ghosh83c8c892017-11-09 11:08:27 +0000522 TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
523 .matchEthType(Ethernet.TYPE_IPV4)
524 .matchInPort(cp.port())
525 .matchIPProtocol(IPv4.PROTOCOL_UDP)
526 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_SERVER_PORT));
527 packetService.cancelPackets(selectorServer.build(),
Saurav Dasb14f08a2019-02-22 16:34:15 -0800528 priority.isPresent() ? priority.get() : PacketPriority.CONTROL,
529 appId, Optional.of(cp.deviceId()));
Amit Ghosh83c8c892017-11-09 11:08:27 +0000530 }
531
Amit Ghosh47243cb2017-07-26 05:08:53 +0100532 private SubscriberAndDeviceInformation getDevice(PacketContext context) {
533 String serialNo = deviceService.getDevice(context.inPacket().
534 receivedFrom().deviceId()).serialNumber();
535
536 return subsService.get(serialNo);
537 }
538
Amit Ghosh47243cb2017-07-26 05:08:53 +0100539 private MacAddress relayAgentMacAddress(PacketContext context) {
540
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000541 SubscriberAndDeviceInformation device = this.getDevice(context);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100542 if (device == null) {
543 log.warn("Device not found for {}", context.inPacket().
544 receivedFrom());
545 return null;
546 }
547
548 return device.hardwareIdentifier();
549 }
550
551 private String nasPortId(PacketContext context) {
Amit Ghosh8951f042017-08-10 13:48:10 +0100552 return nasPortId(context.inPacket().receivedFrom());
553 }
554
555 private String nasPortId(ConnectPoint cp) {
556 Port p = deviceService.getPort(cp);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100557 return p.annotations().value(AnnotationKeys.PORT_NAME);
558 }
559
560 private SubscriberAndDeviceInformation getSubscriber(PacketContext context) {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100561 return subsService.get(nasPortId(context));
562 }
563
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000564 private UniTagInformation getUnitagInformationFromPacketContext(PacketContext context,
565 SubscriberAndDeviceInformation sub) {
566 //If the ctag is defined in the tagList and dhcp is required, return the service info
567 List<UniTagInformation> tagList = sub.uniTagList();
568 for (UniTagInformation uniServiceInformation : tagList) {
569 if (uniServiceInformation.getPonCTag().toShort() == context.inPacket().parsed().getVlanID()) {
570 if (uniServiceInformation.getIsDhcpRequired()) {
571 return uniServiceInformation;
572 }
573 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100574 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100575
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000576 return null;
Amit Ghosh47243cb2017-07-26 05:08:53 +0100577 }
578
579 private class DhcpRelayPacketProcessor implements PacketProcessor {
580
581 @Override
582 public void process(PacketContext context) {
583 if (!configured()) {
584 log.warn("Missing DHCP relay config. Abort packet processing");
585 return;
586 }
587
588 // process the packet and get the payload
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530589 Ethernet packet = context.inPacket().parsed();
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000590
Amit Ghosh47243cb2017-07-26 05:08:53 +0100591 if (packet == null) {
592 log.warn("Packet is null");
593 return;
594 }
595
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530596 if (packet.getEtherType() == Ethernet.TYPE_IPV4) {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100597 IPv4 ipv4Packet = (IPv4) packet.getPayload();
598
599 if (ipv4Packet.getProtocol() == IPv4.PROTOCOL_UDP) {
600 UDP udpPacket = (UDP) ipv4Packet.getPayload();
601 if (udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT ||
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000602 udpPacket.getSourcePort() == UDP.DHCP_SERVER_PORT) {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100603 DHCP dhcpPayload = (DHCP) udpPacket.getPayload();
604 //This packet is dhcp.
605 processDhcpPacket(context, packet, dhcpPayload);
606 }
607 }
608 }
609 }
610
611 //forward the packet to ConnectPoint where the DHCP server is attached.
Amit Ghosh83c8c892017-11-09 11:08:27 +0000612 private void forwardPacket(Ethernet packet, PacketContext context) {
613 ConnectPoint toSendTo = null;
Amit Ghosh47243cb2017-07-26 05:08:53 +0100614
Amit Ghosh83c8c892017-11-09 11:08:27 +0000615 if (!useOltUplink) {
616 toSendTo = dhcpServerConnectPoint.get();
617 } else {
618 toSendTo = getUplinkConnectPointOfOlt(context.inPacket().
619 receivedFrom().deviceId());
620 }
621
622 if (toSendTo != null) {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100623 TrafficTreatment t = DefaultTrafficTreatment.builder()
Amit Ghosh83c8c892017-11-09 11:08:27 +0000624 .setOutput(toSendTo.port()).build();
Amit Ghosh47243cb2017-07-26 05:08:53 +0100625 OutboundPacket o = new DefaultOutboundPacket(
Amit Ghosh83c8c892017-11-09 11:08:27 +0000626 toSendTo.deviceId(), t,
Amit Ghosh47243cb2017-07-26 05:08:53 +0100627 ByteBuffer.wrap(packet.serialize()));
628 if (log.isTraceEnabled()) {
Saurav Das15626a02018-09-27 18:36:45 -0700629 log.trace("Relaying packet to dhcp server at {} {}",
630 toSendTo, packet);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100631 }
632 packetService.emit(o);
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300633
634 SubscriberAndDeviceInformation entry = getSubscriberInfoFromClient(context);
Jonathan Hart77ca3152020-02-21 14:31:21 -0800635 updateDhcpRelayCountersStore(entry, DhcpL2RelayCounterNames.valueOf("PACKETS_TO_SERVER"));
Amit Ghosh47243cb2017-07-26 05:08:53 +0100636 } else {
Amit Ghosh83c8c892017-11-09 11:08:27 +0000637 log.error("No connect point to send msg to DHCP Server");
Amit Ghosh47243cb2017-07-26 05:08:53 +0100638 }
639 }
640
Amit Ghosha17354e2017-08-23 12:56:04 +0100641 // get the type of the DHCP packet
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700642 private DHCP.MsgType getDhcpPacketType(DHCP dhcpPayload) {
Amit Ghosha17354e2017-08-23 12:56:04 +0100643
Jonathan Hartedbf6422018-05-02 17:30:05 -0700644 for (DhcpOption option : dhcpPayload.getOptions()) {
Amit Ghosha17354e2017-08-23 12:56:04 +0100645 if (option.getCode() == OptionCode_MessageType.getValue()) {
646 byte[] data = option.getData();
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700647 return DHCP.MsgType.getType(data[0]);
Amit Ghosha17354e2017-08-23 12:56:04 +0100648 }
649 }
650 return null;
651 }
652
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300653 private void updateDhcpRelayCountersStore(SubscriberAndDeviceInformation entry,
Jonathan Hart77ca3152020-02-21 14:31:21 -0800654 DhcpL2RelayCounterNames counterType) {
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300655 // Update global counter stats
656 dhcpL2RelayCounters.incrementCounter(DhcpL2RelayEvent.GLOBAL_COUNTER, counterType);
657 if (entry == null) {
658 log.warn("Counter not updated as subscriber info not found.");
659 } else {
660 // Update subscriber counter stats
661 dhcpL2RelayCounters.incrementCounter(entry.id(), counterType);
662 }
663 }
664
665 /*
666 * Get subscriber information based on it's context packet.
667 */
668 private SubscriberAndDeviceInformation getSubscriberInfoFromClient(PacketContext context) {
669 if (context != null) {
670 return getSubscriber(context);
671 }
672 return null;
673 }
674
675 /*
676 * Get subscriber information based on it's DHCP payload.
677 */
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000678 private SubscriberAndDeviceInformation getSubscriberInfoFromServer(DHCP dhcpPayload, PacketContext context) {
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300679 if (dhcpPayload != null) {
680 MacAddress descMac = valueOf(dhcpPayload.getClientHardwareAddress());
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000681 ConnectPoint subsCp = getConnectPointOfClient(descMac, context);
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300682
683 if (subsCp != null) {
684 String portId = nasPortId(subsCp);
685 return subsService.get(portId);
686 }
687 }
688 return null;
689 }
690
Amit Ghosh47243cb2017-07-26 05:08:53 +0100691 //process the dhcp packet before sending to server
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530692 private void processDhcpPacket(PacketContext context, Ethernet packet,
Amit Ghosh47243cb2017-07-26 05:08:53 +0100693 DHCP dhcpPayload) {
694 if (dhcpPayload == null) {
695 log.warn("DHCP payload is null");
696 return;
697 }
698
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700699 DHCP.MsgType incomingPacketType = getDhcpPacketType(dhcpPayload);
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300700 if (incomingPacketType == null) {
701 log.warn("DHCP packet type not found. Dump of ethernet pkt in hex format for troubleshooting.");
702 byte[] array = packet.serialize();
703 ByteArrayOutputStream buf = new ByteArrayOutputStream();
704 try {
705 HexDump.dump(array, 0, buf, 0);
706 log.trace(buf.toString());
707 } catch (Exception e) { }
708 return;
709 }
710
711 SubscriberAndDeviceInformation entry = null;
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000712
Saurav Das15626a02018-09-27 18:36:45 -0700713 log.info("Received DHCP Packet of type {} from {}",
714 incomingPacketType, context.inPacket().receivedFrom());
Amit Ghosh47243cb2017-07-26 05:08:53 +0100715
716 switch (incomingPacketType) {
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000717 case DHCPDISCOVER:
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530718 Ethernet ethernetPacketDiscover =
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000719 processDhcpPacketFromClient(context, packet);
720 if (ethernetPacketDiscover != null) {
Amit Ghosh83c8c892017-11-09 11:08:27 +0000721 forwardPacket(ethernetPacketDiscover, context);
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000722 }
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300723 entry = getSubscriberInfoFromClient(context);
Jonathan Hart77ca3152020-02-21 14:31:21 -0800724 updateDhcpRelayCountersStore(entry, DhcpL2RelayCounterNames.valueOf("DHCPDISCOVER"));
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000725 break;
726 case DHCPOFFER:
727 //reply to dhcp client.
Saurav Das15626a02018-09-27 18:36:45 -0700728 Ethernet ethernetPacketOffer =
729 processDhcpPacketFromServer(context, packet);
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000730 if (ethernetPacketOffer != null) {
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000731 sendReply(ethernetPacketOffer, dhcpPayload, context);
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000732 }
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000733 entry = getSubscriberInfoFromServer(dhcpPayload, context);
Jonathan Hart77ca3152020-02-21 14:31:21 -0800734 updateDhcpRelayCountersStore(entry, DhcpL2RelayCounterNames.valueOf("DHCPOFFER"));
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000735 break;
736 case DHCPREQUEST:
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530737 Ethernet ethernetPacketRequest =
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000738 processDhcpPacketFromClient(context, packet);
739 if (ethernetPacketRequest != null) {
Amit Ghosh83c8c892017-11-09 11:08:27 +0000740 forwardPacket(ethernetPacketRequest, context);
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000741 }
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300742 entry = getSubscriberInfoFromClient(context);
Jonathan Hart77ca3152020-02-21 14:31:21 -0800743 updateDhcpRelayCountersStore(entry, DhcpL2RelayCounterNames.valueOf("DHCPREQUEST"));
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000744 break;
745 case DHCPACK:
746 //reply to dhcp client.
Saurav Das15626a02018-09-27 18:36:45 -0700747 Ethernet ethernetPacketAck =
748 processDhcpPacketFromServer(context, packet);
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000749 if (ethernetPacketAck != null) {
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000750 sendReply(ethernetPacketAck, dhcpPayload, context);
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000751 }
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000752 entry = getSubscriberInfoFromServer(dhcpPayload, context);
Jonathan Hart77ca3152020-02-21 14:31:21 -0800753 updateDhcpRelayCountersStore(entry, DhcpL2RelayCounterNames.valueOf("DHCPACK"));
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300754 break;
755 case DHCPDECLINE:
Arjun E K05ad20b2020-03-13 13:25:17 +0000756 Ethernet ethernetPacketDecline =
757 processDhcpPacketFromClient(context, packet);
758 if (ethernetPacketDecline != null) {
759 forwardPacket(ethernetPacketDecline, context);
760 }
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300761 entry = getSubscriberInfoFromClient(context);
Jonathan Hart77ca3152020-02-21 14:31:21 -0800762 updateDhcpRelayCountersStore(entry, DhcpL2RelayCounterNames.valueOf("DHCPDECLINE"));
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300763 break;
764 case DHCPNAK:
Arjun E K05ad20b2020-03-13 13:25:17 +0000765 //reply to dhcp client.
766 Ethernet ethernetPacketNak =
767 processDhcpPacketFromServer(context, packet);
768 if (ethernetPacketNak != null) {
769 sendReply(ethernetPacketNak, dhcpPayload, context);
770 }
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000771 entry = getSubscriberInfoFromServer(dhcpPayload, context);
Jonathan Hart77ca3152020-02-21 14:31:21 -0800772 updateDhcpRelayCountersStore(entry, DhcpL2RelayCounterNames.valueOf("DHCPNACK"));
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300773 break;
774 case DHCPRELEASE:
Thomas Lee S0dc9a3b2020-01-14 10:42:29 +0530775 Ethernet ethernetPacketRelease =
776 processDhcpPacketFromClient(context, packet);
777 if (ethernetPacketRelease != null) {
778 forwardPacket(ethernetPacketRelease, context);
779 }
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300780 entry = getSubscriberInfoFromClient(context);
Jonathan Hart77ca3152020-02-21 14:31:21 -0800781 updateDhcpRelayCountersStore(entry, DhcpL2RelayCounterNames.valueOf("DHCPRELEASE"));
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000782 break;
783 default:
784 break;
Amit Ghosh47243cb2017-07-26 05:08:53 +0100785 }
786 }
787
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530788 private Ethernet processDhcpPacketFromClient(PacketContext context,
789 Ethernet ethernetPacket) {
Saurav Das15626a02018-09-27 18:36:45 -0700790 if (log.isTraceEnabled()) {
791 log.trace("DHCP packet received from client at {} {}",
792 context.inPacket().receivedFrom(), ethernetPacket);
793 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100794
795 MacAddress relayAgentMac = relayAgentMacAddress(context);
796 if (relayAgentMac == null) {
797 log.warn("RelayAgent MAC not found ");
Amit Ghosh47243cb2017-07-26 05:08:53 +0100798 return null;
799 }
800
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530801 Ethernet etherReply = ethernetPacket;
Amit Ghosh47243cb2017-07-26 05:08:53 +0100802
803 IPv4 ipv4Packet = (IPv4) etherReply.getPayload();
804 UDP udpPacket = (UDP) ipv4Packet.getPayload();
805 DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
806
Amit Ghosha17354e2017-08-23 12:56:04 +0100807 if (enableDhcpBroadcastReplies) {
808 // We want the reply to come back as a L2 broadcast
809 dhcpPacket.setFlags((short) 0x8000);
810 }
811
Jonathan Hartc36c9552018-07-31 15:07:53 -0400812 MacAddress clientMac = MacAddress.valueOf(dhcpPacket.getClientHardwareAddress());
813 IpAddress clientIp = IpAddress.valueOf(dhcpPacket.getClientIPAddress());
Amit Ghosha17354e2017-08-23 12:56:04 +0100814
Jonathan Hartc36c9552018-07-31 15:07:53 -0400815 SubscriberAndDeviceInformation entry = getSubscriber(context);
816 if (entry == null) {
Saurav Das15626a02018-09-27 18:36:45 -0700817 log.warn("Dropping packet as subscriber entry is not available");
Jonathan Hartc36c9552018-07-31 15:07:53 -0400818 return null;
819 }
820
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000821 UniTagInformation uniTagInformation = getUnitagInformationFromPacketContext(context, entry);
822 if (uniTagInformation == null) {
823 log.warn("Missing service information for connectPoint {} / cTag {}",
824 context.inPacket().receivedFrom(), context.inPacket().parsed().getVlanID());
825 return null;
826 }
827
Jonathan Hartc36c9552018-07-31 15:07:53 -0400828 DhcpAllocationInfo info = new DhcpAllocationInfo(
829 context.inPacket().receivedFrom(), dhcpPacket.getPacketType(),
Thomas Lee S0dc9a3b2020-01-14 10:42:29 +0530830 entry.circuitId(), clientMac, clientIp);
Jonathan Hartc36c9552018-07-31 15:07:53 -0400831
Jonathan Hart617bc3e2020-02-14 10:42:23 -0800832 allocations.put(entry.id(), info);
Jonathan Hartc36c9552018-07-31 15:07:53 -0400833
Saurav Das15626a02018-09-27 18:36:45 -0700834 post(new DhcpL2RelayEvent(DhcpL2RelayEvent.Type.UPDATED, info,
835 context.inPacket().receivedFrom()));
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000836 if (option82) {
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000837 DHCP dhcpPacketWithOption82 = addOption82(dhcpPacket, entry);
838 udpPacket.setPayload(dhcpPacketWithOption82);
839 }
840
841 ipv4Packet.setPayload(udpPacket);
842 etherReply.setPayload(ipv4Packet);
Amit Ghosh83c8c892017-11-09 11:08:27 +0000843 if (modifyClientPktsSrcDstMac) {
844 etherReply.setSourceMACAddress(relayAgentMac);
845 etherReply.setDestinationMACAddress(dhcpConnectMac);
846 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100847
Amit Ghosh8951f042017-08-10 13:48:10 +0100848 etherReply.setPriorityCode(ethernetPacket.getPriorityCode());
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000849 etherReply.setVlanID(uniTagInformation.getPonCTag().toShort());
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530850 etherReply.setQinQTPID(Ethernet.TYPE_VLAN);
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000851 etherReply.setQinQVID(uniTagInformation.getPonSTag().toShort());
852 if (uniTagInformation.getUsPonSTagPriority() != -1) {
853 etherReply.setQinQPriorityCode((byte) uniTagInformation.getUsPonSTagPriority());
854 }
Thomas Lee S0dc9a3b2020-01-14 10:42:29 +0530855 log.info("Finished processing DHCP packet of type {} from {} and relaying to dhcpServer",
856 dhcpPacket.getPacketType(), entry.id());
Amit Ghosh47243cb2017-07-26 05:08:53 +0100857 return etherReply;
858 }
859
860 //build the DHCP offer/ack with proper client port.
Saurav Das15626a02018-09-27 18:36:45 -0700861 private Ethernet processDhcpPacketFromServer(PacketContext context,
862 Ethernet ethernetPacket) {
863 if (log.isTraceEnabled()) {
864 log.trace("DHCP packet received from server at {} {}",
865 context.inPacket().receivedFrom(), ethernetPacket);
866 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100867 // get dhcp header.
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530868 Ethernet etherReply = (Ethernet) ethernetPacket.clone();
Amit Ghosh47243cb2017-07-26 05:08:53 +0100869 IPv4 ipv4Packet = (IPv4) etherReply.getPayload();
870 UDP udpPacket = (UDP) ipv4Packet.getPayload();
871 DHCP dhcpPayload = (DHCP) udpPacket.getPayload();
872
Amit Ghosh47243cb2017-07-26 05:08:53 +0100873 MacAddress dstMac = valueOf(dhcpPayload.getClientHardwareAddress());
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000874 ConnectPoint subsCp = getConnectPointOfClient(dstMac, context);
Amit Ghosh2095dc62017-09-25 20:56:55 +0100875 // If we can't find the subscriber, can't process further
876 if (subsCp == null) {
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700877 log.warn("Couldn't find connection point for mac address {} DHCPOFFERs won't be delivered", dstMac);
Amit Ghosh2095dc62017-09-25 20:56:55 +0100878 return null;
879 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100880
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000881 SubscriberAndDeviceInformation entry = getSubscriberInfoFromServer(dhcpPayload, context);
882
Thomas Lee S0dc9a3b2020-01-14 10:42:29 +0530883 // if it's an ACK packet store the information for display purpose
884 if ((getDhcpPacketType(dhcpPayload) == DHCP.MsgType.DHCPACK) && (entry != null)) {
885
886 IpAddress ip = IpAddress.valueOf(dhcpPayload.getYourIPAddress());
887 //storeDHCPAllocationInfo
888 DhcpAllocationInfo info = new DhcpAllocationInfo(subsCp,
889 dhcpPayload.getPacketType(), entry.circuitId(), dstMac, ip);
Jonathan Hart617bc3e2020-02-14 10:42:23 -0800890 allocations.put(entry.id(), info);
Thomas Lee S0dc9a3b2020-01-14 10:42:29 +0530891
892 post(new DhcpL2RelayEvent(DhcpL2RelayEvent.Type.UPDATED, info, subsCp));
893 } // end storing of info
894
895
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000896 UniTagInformation uniTagInformation = getUnitagInformationFromPacketContext(context, entry);
897 if (uniTagInformation == null) {
898 log.warn("Missing service information for connectPoint {} / cTag {}",
899 context.inPacket().receivedFrom(), context.inPacket().parsed().getVlanID());
900 return null;
901 }
902
Jonathan Hart77ca3152020-02-21 14:31:21 -0800903 updateDhcpRelayCountersStore(entry, DhcpL2RelayCounterNames.valueOf("PACKETS_FROM_SERVER"));
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300904
Amit Ghosh47243cb2017-07-26 05:08:53 +0100905 // we leave the srcMac from the original packet
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000906 etherReply.setQinQVID(VlanId.NO_VID);
907 etherReply.setQinQPriorityCode((byte) 0);
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530908 etherReply.setDestinationMACAddress(dstMac);
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000909 etherReply.setVlanID(uniTagInformation.getPonCTag().toShort());
910 if (uniTagInformation.getUsPonCTagPriority() != -1) {
911 etherReply.setPriorityCode((byte) uniTagInformation.getUsPonCTagPriority());
912 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100913
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000914 if (option82) {
915 udpPacket.setPayload(removeOption82(dhcpPayload));
916 } else {
917 udpPacket.setPayload(dhcpPayload);
918 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100919 ipv4Packet.setPayload(udpPacket);
920 etherReply.setPayload(ipv4Packet);
921
Saurav Das15626a02018-09-27 18:36:45 -0700922 log.info("Finished processing packet.. relaying to client");
Amit Ghosh47243cb2017-07-26 05:08:53 +0100923 return etherReply;
924 }
925
Amit Ghosha17354e2017-08-23 12:56:04 +0100926 /*
927 * Get ConnectPoint of the Client based on it's MAC address
928 */
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000929 private ConnectPoint getConnectPointOfClient(MacAddress dstMac, PacketContext context) {
Amit Ghosha17354e2017-08-23 12:56:04 +0100930 Set<Host> hosts = hostService.getHostsByMac(dstMac);
931 if (hosts == null || hosts.isEmpty()) {
932 log.warn("Cannot determine host for DHCP client: {}. Aborting "
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530933 + "relay for dhcp packet from server",
Amit Ghosha17354e2017-08-23 12:56:04 +0100934 dstMac);
935 return null;
936 }
937 for (Host h : hosts) {
938 // if more than one,
939 // find the connect point which has an valid entry in SADIS
940 ConnectPoint cp = new ConnectPoint(h.location().deviceId(),
941 h.location().port());
942
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000943 String portId = nasPortId(cp);
944 SubscriberAndDeviceInformation sub = subsService.get(portId);
945 if (sub == null) {
946 log.warn("Subscriber info not found for {}", cp);
947 return null;
Amit Ghosha17354e2017-08-23 12:56:04 +0100948 }
Amit Ghosha17354e2017-08-23 12:56:04 +0100949
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000950 UniTagInformation uniTagInformation = getUnitagInformationFromPacketContext(context, sub);
Jonathan Hartb4fbc922020-04-14 12:17:44 -0700951 if (uniTagInformation != null) {
952 return cp;
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000953 }
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000954 }
Jonathan Hartb4fbc922020-04-14 12:17:44 -0700955 // no sadis config found for this connectPoint/vlan
956 log.warn("Missing service information for connectPoint {} / cTag {}",
957 context.inPacket().receivedFrom(), context.inPacket().parsed().getVlanID());
958
Amit Ghosha17354e2017-08-23 12:56:04 +0100959 return null;
960 }
961
Amit Ghosh47243cb2017-07-26 05:08:53 +0100962 //send the response to the requester host.
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000963 private void sendReply(Ethernet ethPacket, DHCP dhcpPayload, PacketContext context) {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100964 MacAddress descMac = valueOf(dhcpPayload.getClientHardwareAddress());
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000965 ConnectPoint subCp = getConnectPointOfClient(descMac, context);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100966
967 // Send packet out to requester if the host information is available
Amit Ghosha17354e2017-08-23 12:56:04 +0100968 if (subCp != null) {
Saurav Das15626a02018-09-27 18:36:45 -0700969 log.info("Sending DHCP packet to client at {}", subCp);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100970 TrafficTreatment t = DefaultTrafficTreatment.builder()
Amit Ghosha17354e2017-08-23 12:56:04 +0100971 .setOutput(subCp.port()).build();
Amit Ghosh47243cb2017-07-26 05:08:53 +0100972 OutboundPacket o = new DefaultOutboundPacket(
Amit Ghosha17354e2017-08-23 12:56:04 +0100973 subCp.deviceId(), t, ByteBuffer.wrap(ethPacket.serialize()));
Amit Ghosh47243cb2017-07-26 05:08:53 +0100974 if (log.isTraceEnabled()) {
Saurav Das15626a02018-09-27 18:36:45 -0700975 log.trace("Relaying packet to dhcp client at {} {}", subCp,
976 ethPacket);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100977 }
978 packetService.emit(o);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100979 } else {
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000980 log.error("Dropping DHCP packet because can't find host for {}", descMac);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100981 }
982 }
983 }
984
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000985 private DHCP addOption82(DHCP dhcpPacket, SubscriberAndDeviceInformation entry) {
986 log.debug("option82data {} ", entry);
987
Jonathan Hartedbf6422018-05-02 17:30:05 -0700988 List<DhcpOption> options = Lists.newArrayList(dhcpPacket.getOptions());
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000989 DhcpOption82 option82 = new DhcpOption82();
990 option82.setAgentCircuitId(entry.circuitId());
991 option82.setAgentRemoteId(entry.remoteId());
Jonathan Hartedbf6422018-05-02 17:30:05 -0700992 DhcpOption option = new DhcpOption()
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530993 .setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue())
994 .setData(option82.toByteArray())
995 .setLength(option82.length());
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000996
997 options.add(options.size() - 1, option);
998 dhcpPacket.setOptions(options);
Amit Ghosh8951f042017-08-10 13:48:10 +0100999
Deepa vaddireddy0060f532017-08-04 06:46:05 +00001000 return dhcpPacket;
1001
1002 }
1003
1004 private DHCP removeOption82(DHCP dhcpPacket) {
Jonathan Hartedbf6422018-05-02 17:30:05 -07001005 List<DhcpOption> options = dhcpPacket.getOptions();
1006 List<DhcpOption> newoptions = options.stream()
Deepa vaddireddy0060f532017-08-04 06:46:05 +00001007 .filter(option -> option.getCode() != DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue())
1008 .collect(Collectors.toList());
1009
1010 return dhcpPacket.setOptions(newoptions);
1011 }
Amit Ghosh47243cb2017-07-26 05:08:53 +01001012 /**
1013 * Listener for network config events.
1014 */
1015 private class InternalConfigListener implements NetworkConfigListener {
1016
1017 @Override
1018 public void event(NetworkConfigEvent event) {
1019
1020 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
1021 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
1022 event.configClass().equals(DhcpL2RelayConfig.class)) {
1023 updateConfig();
1024 log.info("Reconfigured");
1025 }
1026 }
1027 }
Deepa vaddireddy0060f532017-08-04 06:46:05 +00001028
Amit Ghosh8951f042017-08-10 13:48:10 +01001029 /**
1030 * Handles Mastership changes for the devices which connect
1031 * to the DHCP server.
1032 */
1033 private class InnerMastershipListener implements MastershipListener {
1034 @Override
1035 public void event(MastershipEvent event) {
Amit Ghosh83c8c892017-11-09 11:08:27 +00001036 if (!useOltUplink) {
1037 if (dhcpServerConnectPoint.get() != null &&
1038 dhcpServerConnectPoint.get().deviceId().
1039 equals(event.subject())) {
1040 log.trace("Mastership Event recevived for {}", event.subject());
1041 // mastership of the device for our connect point has changed
1042 // reselect
1043 selectServerConnectPoint();
1044 }
Amit Ghosh8951f042017-08-10 13:48:10 +01001045 }
1046 }
1047 }
Deepa vaddireddy0060f532017-08-04 06:46:05 +00001048
Jonathan Hart617bc3e2020-02-14 10:42:23 -08001049 private void removeAllocations(Predicate<Map.Entry<String, Versioned<DhcpAllocationInfo>>> pred) {
1050 allocations.stream()
1051 .filter(pred)
1052 .map(Map.Entry::getKey)
1053 .collect(Collectors.toList())
1054 .forEach(allocations::remove);
1055 }
1056
Matteo Scandoloab346512020-04-17 13:39:55 -07001057 public void clearAllocations() {
1058 allocations.clear();
1059 }
1060
1061
1062 public boolean removeAllocationByConnectPoint(ConnectPoint cp) {
1063 for (String key : allocations.keySet()) {
1064 DhcpAllocationInfo entry = allocations.asJavaMap().get(key);
1065 if (entry.location().equals(cp)) {
1066 allocations.remove(key);
1067 return true;
1068 }
1069 }
1070 return false;
1071 }
1072
Andrea Campanella6f45a1b2020-05-08 17:50:12 +02001073
1074 /**
1075 * Checks for mastership or falls back to leadership on deviceId.
1076 * If the node is not master and device is available
1077 * or the device is not available and the leader is different
1078 * we let master or leader else handle it
1079 * Leadership on the device topic is needed because the master can be NONE
1080 * in case the device went away, we still need to handle events
1081 * consistently
1082 */
1083 private boolean isLocalLeader(DeviceId deviceId) {
1084 if (!mastershipService.isLocalMaster(deviceId)) {
1085 // When the device is available we just check the mastership
1086 if (deviceService.isAvailable(deviceId)) {
1087 return false;
1088 }
1089 // Fallback with Leadership service - device id is used as topic
1090 NodeId leader = leadershipService.runForLeadership(
1091 deviceId.toString()).leaderNodeId();
1092 // Verify if this node is the leader
1093 return clusterService.getLocalNode().id().equals(leader);
1094 }
1095 return true;
1096 }
1097
Amit Ghosh8951f042017-08-10 13:48:10 +01001098 /**
1099 * Handles Device status change for the devices which connect
1100 * to the DHCP server.
1101 */
1102 private class InnerDeviceListener implements DeviceListener {
1103 @Override
1104 public void event(DeviceEvent event) {
Andrea Campanella6f45a1b2020-05-08 17:50:12 +02001105 final DeviceId deviceId = event.subject().id();
1106
1107 // Ensure only one instance handles the event
1108 if (!isLocalLeader(deviceId)) {
Jonathan Hart617bc3e2020-02-14 10:42:23 -08001109 return;
1110 }
1111
Andrea Campanella6f45a1b2020-05-08 17:50:12 +02001112 log.debug("Handling event {}", event);
Jonathan Hart617bc3e2020-02-14 10:42:23 -08001113
Thomas Lee S9df15082019-12-23 11:31:15 +05301114 switch (event.type()) {
Jonathan Hart617bc3e2020-02-14 10:42:23 -08001115 case DEVICE_REMOVED:
1116 log.info("Device removed {}", event.subject().id());
1117 removeAllocations(e -> e.getValue().value().location().deviceId().equals(deviceId));
1118 break;
Thomas Lee S9df15082019-12-23 11:31:15 +05301119 case DEVICE_AVAILABILITY_CHANGED:
Jonathan Hart617bc3e2020-02-14 10:42:23 -08001120 boolean available = deviceService.isAvailable(deviceId);
1121 log.info("Device Avail Changed {} to {}", event.subject().id(), available);
1122
1123 if (!available && deviceService.getPorts(deviceId).isEmpty()) {
1124 removeAllocations(e -> e.getValue().value().location().deviceId().equals(deviceId));
1125 log.info("Device {} is removed from DHCP allocationmap ", deviceId);
Thomas Lee S9df15082019-12-23 11:31:15 +05301126 }
1127 break;
Thomas Lee S6b77ad22020-01-10 11:27:43 +05301128 case PORT_REMOVED:
1129 Port port = event.port();
Thomas Lee S6b77ad22020-01-10 11:27:43 +05301130 log.info("Port {} is deleted on device {}", port, deviceId);
Jonathan Hart617bc3e2020-02-14 10:42:23 -08001131
1132 ConnectPoint cp = new ConnectPoint(deviceId, port.number());
1133 removeAllocations(e -> e.getValue().value().location().equals(cp));
1134
Thomas Lee S6b77ad22020-01-10 11:27:43 +05301135 log.info("Port {} on device {} is removed from DHCP allocationmap", event.port(), deviceId);
1136 break;
Thomas Lee S9df15082019-12-23 11:31:15 +05301137 default:
1138 break;
1139 }
Saurav Das15626a02018-09-27 18:36:45 -07001140 if (log.isTraceEnabled() &&
1141 !event.type().equals(DeviceEvent.Type.PORT_STATS_UPDATED)) {
1142 log.trace("Device Event received for {} event {}",
1143 event.subject(), event.type());
1144 }
Amit Ghosh83c8c892017-11-09 11:08:27 +00001145 if (!useOltUplink) {
1146 if (dhcpServerConnectPoint.get() == null) {
1147 switch (event.type()) {
1148 case DEVICE_ADDED:
1149 case DEVICE_AVAILABILITY_CHANGED:
Saurav Dasb14f08a2019-02-22 16:34:15 -08001150 // some device is available check if we can get a
1151 // connect point we can use
1152 addOrRemoveDhcpTrapFromServer(true);
Amit Ghosh83c8c892017-11-09 11:08:27 +00001153 break;
1154 default:
1155 break;
1156 }
1157 return;
Amit Ghosh8951f042017-08-10 13:48:10 +01001158 }
Amit Ghosh83c8c892017-11-09 11:08:27 +00001159 if (dhcpServerConnectPoint.get().deviceId().
1160 equals(event.subject().id())) {
1161 switch (event.type()) {
1162 case DEVICE_AVAILABILITY_CHANGED:
1163 case DEVICE_REMOVED:
1164 case DEVICE_SUSPENDED:
1165 // state of our device has changed, check if we need
Saurav Dasb14f08a2019-02-22 16:34:15 -08001166 // to re-select a connectpoint
1167 addOrRemoveDhcpTrapFromServer(true);
Amit Ghosh83c8c892017-11-09 11:08:27 +00001168 break;
1169 default:
1170 break;
1171 }
1172 }
1173 } else {
Amit Ghosh8951f042017-08-10 13:48:10 +01001174 switch (event.type()) {
Amit Ghosh83c8c892017-11-09 11:08:27 +00001175 case PORT_ADDED:
Saurav Dasb4e3e102018-10-02 15:31:17 -07001176 if (useOltUplink && isUplinkPortOfOlt(event.subject().id(), event.port())) {
Saurav Dasb14f08a2019-02-22 16:34:15 -08001177 requestDhcpPacketsFromConnectPoint(
1178 new ConnectPoint(event.subject().id(), event.port().number()),
Jonathan Hart617bc3e2020-02-14 10:42:23 -08001179 Optional.empty());
Amit Ghosh83c8c892017-11-09 11:08:27 +00001180 }
Amit Ghosh8951f042017-08-10 13:48:10 +01001181 break;
1182 default:
1183 break;
1184 }
1185 }
1186 }
1187 }
Jonathan Hart77ca3152020-02-21 14:31:21 -08001188
1189 private class InnerDhcpL2RelayStoreDelegate implements DhcpL2RelayStoreDelegate {
1190 @Override
1191 public void notify(DhcpL2RelayEvent event) {
1192 if (event.type().equals(DhcpL2RelayEvent.Type.STATS_UPDATE)) {
1193 DhcpL2RelayEvent toPost = event;
1194 if (event.getSubscriberId() != null) {
1195 // infuse the event with the allocation info before posting
1196 DhcpAllocationInfo info = Versioned.valueOrNull(allocations.get(event.getSubscriberId()));
1197 toPost = new DhcpL2RelayEvent(event.type(), info, event.connectPoint(),
1198 event.getCountersEntry(), event.getSubscriberId());
1199 }
1200 post(toPost);
1201 }
1202
1203 }
1204 }
Amit Ghosh47243cb2017-07-26 05:08:53 +01001205}