blob: c34d81769741974a290e30da5e72e94043e1c6f0 [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;
Amit Ghosh47243cb2017-07-26 05:08:53 +010037import org.onosproject.core.ApplicationId;
38import org.onosproject.core.CoreService;
Jonathan Hartc36c9552018-07-31 15:07:53 -040039import org.onosproject.event.AbstractListenerManager;
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +053040import org.onosproject.mastership.MastershipEvent;
41import org.onosproject.mastership.MastershipListener;
42import org.onosproject.mastership.MastershipService;
Amit Ghosh47243cb2017-07-26 05:08:53 +010043import org.onosproject.net.AnnotationKeys;
44import org.onosproject.net.ConnectPoint;
Amit Ghosh83c8c892017-11-09 11:08:27 +000045import org.onosproject.net.Device;
46import org.onosproject.net.DeviceId;
Amit Ghosh47243cb2017-07-26 05:08:53 +010047import org.onosproject.net.Host;
48import org.onosproject.net.Port;
Amit Ghosh83c8c892017-11-09 11:08:27 +000049import org.onosproject.net.PortNumber;
Amit Ghosh47243cb2017-07-26 05:08:53 +010050import org.onosproject.net.config.ConfigFactory;
51import org.onosproject.net.config.NetworkConfigEvent;
52import org.onosproject.net.config.NetworkConfigListener;
53import org.onosproject.net.config.NetworkConfigRegistry;
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +053054import org.onosproject.net.device.DeviceEvent;
55import org.onosproject.net.device.DeviceListener;
Amit Ghosh47243cb2017-07-26 05:08:53 +010056import org.onosproject.net.device.DeviceService;
57import org.onosproject.net.flow.DefaultTrafficSelector;
58import org.onosproject.net.flow.DefaultTrafficTreatment;
59import org.onosproject.net.flow.TrafficSelector;
60import org.onosproject.net.flow.TrafficTreatment;
Saurav Dasb4e3e102018-10-02 15:31:17 -070061import org.onosproject.net.flowobjective.FlowObjectiveService;
Amit Ghosh47243cb2017-07-26 05:08:53 +010062import org.onosproject.net.host.HostService;
63import org.onosproject.net.packet.DefaultOutboundPacket;
64import org.onosproject.net.packet.OutboundPacket;
65import org.onosproject.net.packet.PacketContext;
66import org.onosproject.net.packet.PacketPriority;
67import org.onosproject.net.packet.PacketProcessor;
68import org.onosproject.net.packet.PacketService;
Jonathan Hart617bc3e2020-02-14 10:42:23 -080069import org.onosproject.store.serializers.KryoNamespaces;
70import org.onosproject.store.service.ConsistentMap;
71import org.onosproject.store.service.Serializer;
72import org.onosproject.store.service.StorageService;
73import org.onosproject.store.service.Versioned;
Matteo Scandolo57af5d12019-04-29 17:11:41 -070074import org.opencord.dhcpl2relay.DhcpAllocationInfo;
75import org.opencord.dhcpl2relay.DhcpL2RelayEvent;
76import org.opencord.dhcpl2relay.DhcpL2RelayListener;
77import org.opencord.dhcpl2relay.DhcpL2RelayService;
Jonathan Hart77ca3152020-02-21 14:31:21 -080078import org.opencord.dhcpl2relay.DhcpL2RelayStoreDelegate;
Matteo Scandolo57af5d12019-04-29 17:11:41 -070079import org.opencord.dhcpl2relay.impl.packet.DhcpOption82;
Gamze Abakac806c6c2018-12-03 12:49:46 +000080import org.opencord.sadis.BaseInformationService;
81import org.opencord.sadis.SadisService;
Amit Ghosh47243cb2017-07-26 05:08:53 +010082import org.opencord.sadis.SubscriberAndDeviceInformation;
Gamze Abakaa64b3bc2020-01-31 06:51:43 +000083import org.opencord.sadis.UniTagInformation;
Amit Ghosh47243cb2017-07-26 05:08:53 +010084import org.osgi.service.component.ComponentContext;
Carmelo Casconede1e6e32019-07-15 19:39:08 -070085import org.osgi.service.component.annotations.Activate;
86import org.osgi.service.component.annotations.Component;
87import org.osgi.service.component.annotations.Deactivate;
88import org.osgi.service.component.annotations.Modified;
89import org.osgi.service.component.annotations.Reference;
90import org.osgi.service.component.annotations.ReferenceCardinality;
Amit Ghosh47243cb2017-07-26 05:08:53 +010091import org.slf4j.Logger;
92import org.slf4j.LoggerFactory;
93
Jonathan Hart617bc3e2020-02-14 10:42:23 -080094import java.io.ByteArrayOutputStream;
95import java.nio.ByteBuffer;
96import java.time.Instant;
Jonathan Hart617bc3e2020-02-14 10:42:23 -080097import java.util.ArrayList;
98import java.util.Dictionary;
99import java.util.List;
100import java.util.Map;
101import java.util.Objects;
102import 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) {
329 if (mastershipService.isLocalMaster(cp.deviceId())) {
330 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
436 if (!mastershipService.isLocalMaster(d.id())) {
437 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);
461 // do only for devices for which we are the master
462 if (!mastershipService.isLocalMaster(dId)) {
463 return false;
464 }
465
466 Device d = deviceService.getDevice(dId);
467 SubscriberAndDeviceInformation deviceInfo = subsService.get(d.serialNumber());
468
469 if (deviceInfo != null) {
470 return (deviceInfo.uplinkPort() == p.number().toLong());
471 }
472
473 return false;
474 }
475
476 /**
477 * Returns the connectPoint which is the uplink port of the OLT.
478 */
479 private ConnectPoint getUplinkConnectPointOfOlt(DeviceId dId) {
480
481 Device d = deviceService.getDevice(dId);
482 SubscriberAndDeviceInformation deviceInfo = subsService.get(d.serialNumber());
483 log.debug("getUplinkConnectPointOfOlt DeviceId: {} devInfo: {}", dId, deviceInfo);
484 if (deviceInfo != null) {
485 PortNumber pNum = PortNumber.portNumber(deviceInfo.uplinkPort());
486 Port port = deviceService.getPort(d.id(), pNum);
487 if (port != null) {
488 return new ConnectPoint(d.id(), pNum);
489 }
490 }
491
492 return null;
493 }
494
495 /**
496 * Request DHCP packet from particular connect point via PacketService.
Saurav Dasb14f08a2019-02-22 16:34:15 -0800497 * Optionally provide a priority for the trap flow. If no such priority is
498 * provided, the default priority will be used.
499 *
500 * @param cp the connect point to trap dhcp packets from
501 * @param priority of the trap flow, null to use default priority
Amit Ghosh83c8c892017-11-09 11:08:27 +0000502 */
Saurav Dasb14f08a2019-02-22 16:34:15 -0800503 private void requestDhcpPacketsFromConnectPoint(ConnectPoint cp,
504 Optional<PacketPriority> priority) {
Amit Ghosh83c8c892017-11-09 11:08:27 +0000505 TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
506 .matchEthType(Ethernet.TYPE_IPV4)
507 .matchInPort(cp.port())
508 .matchIPProtocol(IPv4.PROTOCOL_UDP)
509 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_SERVER_PORT));
510 packetService.requestPackets(selectorServer.build(),
Saurav Dasb14f08a2019-02-22 16:34:15 -0800511 priority.isPresent() ? priority.get() : PacketPriority.CONTROL,
512 appId, Optional.of(cp.deviceId()));
Amit Ghosh83c8c892017-11-09 11:08:27 +0000513 }
514
515 /**
Saurav Dasb14f08a2019-02-22 16:34:15 -0800516 * Cancel DHCP packet from particular connect point via PacketService. If
517 * the request was made with a specific packet priority, then the same
518 * priority should be used in this call.
519 *
520 * @param cp the connect point for the trap flow
521 * @param priority with which the trap flow was requested; if request
522 * priority was not specified, this param should also be null
Amit Ghosh83c8c892017-11-09 11:08:27 +0000523 */
Saurav Dasb14f08a2019-02-22 16:34:15 -0800524 private void cancelDhcpPacketsFromConnectPoint(ConnectPoint cp,
525 Optional<PacketPriority> priority) {
Amit Ghosh83c8c892017-11-09 11:08:27 +0000526 TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
527 .matchEthType(Ethernet.TYPE_IPV4)
528 .matchInPort(cp.port())
529 .matchIPProtocol(IPv4.PROTOCOL_UDP)
530 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_SERVER_PORT));
531 packetService.cancelPackets(selectorServer.build(),
Saurav Dasb14f08a2019-02-22 16:34:15 -0800532 priority.isPresent() ? priority.get() : PacketPriority.CONTROL,
533 appId, Optional.of(cp.deviceId()));
Amit Ghosh83c8c892017-11-09 11:08:27 +0000534 }
535
Amit Ghosh47243cb2017-07-26 05:08:53 +0100536 private SubscriberAndDeviceInformation getDevice(PacketContext context) {
537 String serialNo = deviceService.getDevice(context.inPacket().
538 receivedFrom().deviceId()).serialNumber();
539
540 return subsService.get(serialNo);
541 }
542
Amit Ghosh47243cb2017-07-26 05:08:53 +0100543 private MacAddress relayAgentMacAddress(PacketContext context) {
544
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000545 SubscriberAndDeviceInformation device = this.getDevice(context);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100546 if (device == null) {
547 log.warn("Device not found for {}", context.inPacket().
548 receivedFrom());
549 return null;
550 }
551
552 return device.hardwareIdentifier();
553 }
554
555 private String nasPortId(PacketContext context) {
Amit Ghosh8951f042017-08-10 13:48:10 +0100556 return nasPortId(context.inPacket().receivedFrom());
557 }
558
559 private String nasPortId(ConnectPoint cp) {
560 Port p = deviceService.getPort(cp);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100561 return p.annotations().value(AnnotationKeys.PORT_NAME);
562 }
563
564 private SubscriberAndDeviceInformation getSubscriber(PacketContext context) {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100565 return subsService.get(nasPortId(context));
566 }
567
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000568 private UniTagInformation getUnitagInformationFromPacketContext(PacketContext context,
569 SubscriberAndDeviceInformation sub) {
570 //If the ctag is defined in the tagList and dhcp is required, return the service info
571 List<UniTagInformation> tagList = sub.uniTagList();
572 for (UniTagInformation uniServiceInformation : tagList) {
573 if (uniServiceInformation.getPonCTag().toShort() == context.inPacket().parsed().getVlanID()) {
574 if (uniServiceInformation.getIsDhcpRequired()) {
575 return uniServiceInformation;
576 }
577 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100578 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100579
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000580 return null;
Amit Ghosh47243cb2017-07-26 05:08:53 +0100581 }
582
583 private class DhcpRelayPacketProcessor implements PacketProcessor {
584
585 @Override
586 public void process(PacketContext context) {
587 if (!configured()) {
588 log.warn("Missing DHCP relay config. Abort packet processing");
589 return;
590 }
591
592 // process the packet and get the payload
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530593 Ethernet packet = context.inPacket().parsed();
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000594
Amit Ghosh47243cb2017-07-26 05:08:53 +0100595 if (packet == null) {
596 log.warn("Packet is null");
597 return;
598 }
599
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530600 if (packet.getEtherType() == Ethernet.TYPE_IPV4) {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100601 IPv4 ipv4Packet = (IPv4) packet.getPayload();
602
603 if (ipv4Packet.getProtocol() == IPv4.PROTOCOL_UDP) {
604 UDP udpPacket = (UDP) ipv4Packet.getPayload();
605 if (udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT ||
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000606 udpPacket.getSourcePort() == UDP.DHCP_SERVER_PORT) {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100607 DHCP dhcpPayload = (DHCP) udpPacket.getPayload();
608 //This packet is dhcp.
609 processDhcpPacket(context, packet, dhcpPayload);
610 }
611 }
612 }
613 }
614
615 //forward the packet to ConnectPoint where the DHCP server is attached.
Amit Ghosh83c8c892017-11-09 11:08:27 +0000616 private void forwardPacket(Ethernet packet, PacketContext context) {
617 ConnectPoint toSendTo = null;
Amit Ghosh47243cb2017-07-26 05:08:53 +0100618
Amit Ghosh83c8c892017-11-09 11:08:27 +0000619 if (!useOltUplink) {
620 toSendTo = dhcpServerConnectPoint.get();
621 } else {
622 toSendTo = getUplinkConnectPointOfOlt(context.inPacket().
623 receivedFrom().deviceId());
624 }
625
626 if (toSendTo != null) {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100627 TrafficTreatment t = DefaultTrafficTreatment.builder()
Amit Ghosh83c8c892017-11-09 11:08:27 +0000628 .setOutput(toSendTo.port()).build();
Amit Ghosh47243cb2017-07-26 05:08:53 +0100629 OutboundPacket o = new DefaultOutboundPacket(
Amit Ghosh83c8c892017-11-09 11:08:27 +0000630 toSendTo.deviceId(), t,
Amit Ghosh47243cb2017-07-26 05:08:53 +0100631 ByteBuffer.wrap(packet.serialize()));
632 if (log.isTraceEnabled()) {
Saurav Das15626a02018-09-27 18:36:45 -0700633 log.trace("Relaying packet to dhcp server at {} {}",
634 toSendTo, packet);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100635 }
636 packetService.emit(o);
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300637
638 SubscriberAndDeviceInformation entry = getSubscriberInfoFromClient(context);
Jonathan Hart77ca3152020-02-21 14:31:21 -0800639 updateDhcpRelayCountersStore(entry, DhcpL2RelayCounterNames.valueOf("PACKETS_TO_SERVER"));
Amit Ghosh47243cb2017-07-26 05:08:53 +0100640 } else {
Amit Ghosh83c8c892017-11-09 11:08:27 +0000641 log.error("No connect point to send msg to DHCP Server");
Amit Ghosh47243cb2017-07-26 05:08:53 +0100642 }
643 }
644
Amit Ghosha17354e2017-08-23 12:56:04 +0100645 // get the type of the DHCP packet
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700646 private DHCP.MsgType getDhcpPacketType(DHCP dhcpPayload) {
Amit Ghosha17354e2017-08-23 12:56:04 +0100647
Jonathan Hartedbf6422018-05-02 17:30:05 -0700648 for (DhcpOption option : dhcpPayload.getOptions()) {
Amit Ghosha17354e2017-08-23 12:56:04 +0100649 if (option.getCode() == OptionCode_MessageType.getValue()) {
650 byte[] data = option.getData();
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700651 return DHCP.MsgType.getType(data[0]);
Amit Ghosha17354e2017-08-23 12:56:04 +0100652 }
653 }
654 return null;
655 }
656
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300657 private void updateDhcpRelayCountersStore(SubscriberAndDeviceInformation entry,
Jonathan Hart77ca3152020-02-21 14:31:21 -0800658 DhcpL2RelayCounterNames counterType) {
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300659 // Update global counter stats
660 dhcpL2RelayCounters.incrementCounter(DhcpL2RelayEvent.GLOBAL_COUNTER, counterType);
661 if (entry == null) {
662 log.warn("Counter not updated as subscriber info not found.");
663 } else {
664 // Update subscriber counter stats
665 dhcpL2RelayCounters.incrementCounter(entry.id(), counterType);
666 }
667 }
668
669 /*
670 * Get subscriber information based on it's context packet.
671 */
672 private SubscriberAndDeviceInformation getSubscriberInfoFromClient(PacketContext context) {
673 if (context != null) {
674 return getSubscriber(context);
675 }
676 return null;
677 }
678
679 /*
680 * Get subscriber information based on it's DHCP payload.
681 */
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000682 private SubscriberAndDeviceInformation getSubscriberInfoFromServer(DHCP dhcpPayload, PacketContext context) {
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300683 if (dhcpPayload != null) {
684 MacAddress descMac = valueOf(dhcpPayload.getClientHardwareAddress());
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000685 ConnectPoint subsCp = getConnectPointOfClient(descMac, context);
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300686
687 if (subsCp != null) {
688 String portId = nasPortId(subsCp);
689 return subsService.get(portId);
690 }
691 }
692 return null;
693 }
694
Amit Ghosh47243cb2017-07-26 05:08:53 +0100695 //process the dhcp packet before sending to server
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530696 private void processDhcpPacket(PacketContext context, Ethernet packet,
Amit Ghosh47243cb2017-07-26 05:08:53 +0100697 DHCP dhcpPayload) {
698 if (dhcpPayload == null) {
699 log.warn("DHCP payload is null");
700 return;
701 }
702
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700703 DHCP.MsgType incomingPacketType = getDhcpPacketType(dhcpPayload);
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300704 if (incomingPacketType == null) {
705 log.warn("DHCP packet type not found. Dump of ethernet pkt in hex format for troubleshooting.");
706 byte[] array = packet.serialize();
707 ByteArrayOutputStream buf = new ByteArrayOutputStream();
708 try {
709 HexDump.dump(array, 0, buf, 0);
710 log.trace(buf.toString());
711 } catch (Exception e) { }
712 return;
713 }
714
715 SubscriberAndDeviceInformation entry = null;
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000716
Saurav Das15626a02018-09-27 18:36:45 -0700717 log.info("Received DHCP Packet of type {} from {}",
718 incomingPacketType, context.inPacket().receivedFrom());
Amit Ghosh47243cb2017-07-26 05:08:53 +0100719
720 switch (incomingPacketType) {
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000721 case DHCPDISCOVER:
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530722 Ethernet ethernetPacketDiscover =
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000723 processDhcpPacketFromClient(context, packet);
724 if (ethernetPacketDiscover != null) {
Amit Ghosh83c8c892017-11-09 11:08:27 +0000725 forwardPacket(ethernetPacketDiscover, context);
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000726 }
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300727 entry = getSubscriberInfoFromClient(context);
Jonathan Hart77ca3152020-02-21 14:31:21 -0800728 updateDhcpRelayCountersStore(entry, DhcpL2RelayCounterNames.valueOf("DHCPDISCOVER"));
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000729 break;
730 case DHCPOFFER:
731 //reply to dhcp client.
Saurav Das15626a02018-09-27 18:36:45 -0700732 Ethernet ethernetPacketOffer =
733 processDhcpPacketFromServer(context, packet);
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000734 if (ethernetPacketOffer != null) {
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000735 sendReply(ethernetPacketOffer, dhcpPayload, context);
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000736 }
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000737 entry = getSubscriberInfoFromServer(dhcpPayload, context);
Jonathan Hart77ca3152020-02-21 14:31:21 -0800738 updateDhcpRelayCountersStore(entry, DhcpL2RelayCounterNames.valueOf("DHCPOFFER"));
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000739 break;
740 case DHCPREQUEST:
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530741 Ethernet ethernetPacketRequest =
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000742 processDhcpPacketFromClient(context, packet);
743 if (ethernetPacketRequest != null) {
Amit Ghosh83c8c892017-11-09 11:08:27 +0000744 forwardPacket(ethernetPacketRequest, context);
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000745 }
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300746 entry = getSubscriberInfoFromClient(context);
Jonathan Hart77ca3152020-02-21 14:31:21 -0800747 updateDhcpRelayCountersStore(entry, DhcpL2RelayCounterNames.valueOf("DHCPREQUEST"));
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000748 break;
749 case DHCPACK:
750 //reply to dhcp client.
Saurav Das15626a02018-09-27 18:36:45 -0700751 Ethernet ethernetPacketAck =
752 processDhcpPacketFromServer(context, packet);
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000753 if (ethernetPacketAck != null) {
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000754 sendReply(ethernetPacketAck, dhcpPayload, context);
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000755 }
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000756 entry = getSubscriberInfoFromServer(dhcpPayload, context);
Jonathan Hart77ca3152020-02-21 14:31:21 -0800757 updateDhcpRelayCountersStore(entry, DhcpL2RelayCounterNames.valueOf("DHCPACK"));
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300758 break;
759 case DHCPDECLINE:
Arjun E K05ad20b2020-03-13 13:25:17 +0000760 Ethernet ethernetPacketDecline =
761 processDhcpPacketFromClient(context, packet);
762 if (ethernetPacketDecline != null) {
763 forwardPacket(ethernetPacketDecline, context);
764 }
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300765 entry = getSubscriberInfoFromClient(context);
Jonathan Hart77ca3152020-02-21 14:31:21 -0800766 updateDhcpRelayCountersStore(entry, DhcpL2RelayCounterNames.valueOf("DHCPDECLINE"));
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300767 break;
768 case DHCPNAK:
Arjun E K05ad20b2020-03-13 13:25:17 +0000769 //reply to dhcp client.
770 Ethernet ethernetPacketNak =
771 processDhcpPacketFromServer(context, packet);
772 if (ethernetPacketNak != null) {
773 sendReply(ethernetPacketNak, dhcpPayload, context);
774 }
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000775 entry = getSubscriberInfoFromServer(dhcpPayload, context);
Jonathan Hart77ca3152020-02-21 14:31:21 -0800776 updateDhcpRelayCountersStore(entry, DhcpL2RelayCounterNames.valueOf("DHCPNACK"));
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300777 break;
778 case DHCPRELEASE:
Thomas Lee S0dc9a3b2020-01-14 10:42:29 +0530779 Ethernet ethernetPacketRelease =
780 processDhcpPacketFromClient(context, packet);
781 if (ethernetPacketRelease != null) {
782 forwardPacket(ethernetPacketRelease, context);
783 }
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300784 entry = getSubscriberInfoFromClient(context);
Jonathan Hart77ca3152020-02-21 14:31:21 -0800785 updateDhcpRelayCountersStore(entry, DhcpL2RelayCounterNames.valueOf("DHCPRELEASE"));
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000786 break;
787 default:
788 break;
Amit Ghosh47243cb2017-07-26 05:08:53 +0100789 }
790 }
791
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530792 private Ethernet processDhcpPacketFromClient(PacketContext context,
793 Ethernet ethernetPacket) {
Saurav Das15626a02018-09-27 18:36:45 -0700794 if (log.isTraceEnabled()) {
795 log.trace("DHCP packet received from client at {} {}",
796 context.inPacket().receivedFrom(), ethernetPacket);
797 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100798
799 MacAddress relayAgentMac = relayAgentMacAddress(context);
800 if (relayAgentMac == null) {
801 log.warn("RelayAgent MAC not found ");
Amit Ghosh47243cb2017-07-26 05:08:53 +0100802 return null;
803 }
804
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530805 Ethernet etherReply = ethernetPacket;
Amit Ghosh47243cb2017-07-26 05:08:53 +0100806
807 IPv4 ipv4Packet = (IPv4) etherReply.getPayload();
808 UDP udpPacket = (UDP) ipv4Packet.getPayload();
809 DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
810
Amit Ghosha17354e2017-08-23 12:56:04 +0100811 if (enableDhcpBroadcastReplies) {
812 // We want the reply to come back as a L2 broadcast
813 dhcpPacket.setFlags((short) 0x8000);
814 }
815
Jonathan Hartc36c9552018-07-31 15:07:53 -0400816 MacAddress clientMac = MacAddress.valueOf(dhcpPacket.getClientHardwareAddress());
817 IpAddress clientIp = IpAddress.valueOf(dhcpPacket.getClientIPAddress());
Amit Ghosha17354e2017-08-23 12:56:04 +0100818
Jonathan Hartc36c9552018-07-31 15:07:53 -0400819 SubscriberAndDeviceInformation entry = getSubscriber(context);
820 if (entry == null) {
Saurav Das15626a02018-09-27 18:36:45 -0700821 log.warn("Dropping packet as subscriber entry is not available");
Jonathan Hartc36c9552018-07-31 15:07:53 -0400822 return null;
823 }
824
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000825 UniTagInformation uniTagInformation = getUnitagInformationFromPacketContext(context, entry);
826 if (uniTagInformation == null) {
827 log.warn("Missing service information for connectPoint {} / cTag {}",
828 context.inPacket().receivedFrom(), context.inPacket().parsed().getVlanID());
829 return null;
830 }
831
Jonathan Hartc36c9552018-07-31 15:07:53 -0400832 DhcpAllocationInfo info = new DhcpAllocationInfo(
833 context.inPacket().receivedFrom(), dhcpPacket.getPacketType(),
Thomas Lee S0dc9a3b2020-01-14 10:42:29 +0530834 entry.circuitId(), clientMac, clientIp);
Jonathan Hartc36c9552018-07-31 15:07:53 -0400835
Jonathan Hart617bc3e2020-02-14 10:42:23 -0800836 allocations.put(entry.id(), info);
Jonathan Hartc36c9552018-07-31 15:07:53 -0400837
Saurav Das15626a02018-09-27 18:36:45 -0700838 post(new DhcpL2RelayEvent(DhcpL2RelayEvent.Type.UPDATED, info,
839 context.inPacket().receivedFrom()));
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000840 if (option82) {
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000841 DHCP dhcpPacketWithOption82 = addOption82(dhcpPacket, entry);
842 udpPacket.setPayload(dhcpPacketWithOption82);
843 }
844
845 ipv4Packet.setPayload(udpPacket);
846 etherReply.setPayload(ipv4Packet);
Amit Ghosh83c8c892017-11-09 11:08:27 +0000847 if (modifyClientPktsSrcDstMac) {
848 etherReply.setSourceMACAddress(relayAgentMac);
849 etherReply.setDestinationMACAddress(dhcpConnectMac);
850 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100851
Amit Ghosh8951f042017-08-10 13:48:10 +0100852 etherReply.setPriorityCode(ethernetPacket.getPriorityCode());
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000853 etherReply.setVlanID(uniTagInformation.getPonCTag().toShort());
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530854 etherReply.setQinQTPID(Ethernet.TYPE_VLAN);
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000855 etherReply.setQinQVID(uniTagInformation.getPonSTag().toShort());
856 if (uniTagInformation.getUsPonSTagPriority() != -1) {
857 etherReply.setQinQPriorityCode((byte) uniTagInformation.getUsPonSTagPriority());
858 }
Thomas Lee S0dc9a3b2020-01-14 10:42:29 +0530859 log.info("Finished processing DHCP packet of type {} from {} and relaying to dhcpServer",
860 dhcpPacket.getPacketType(), entry.id());
Amit Ghosh47243cb2017-07-26 05:08:53 +0100861 return etherReply;
862 }
863
864 //build the DHCP offer/ack with proper client port.
Saurav Das15626a02018-09-27 18:36:45 -0700865 private Ethernet processDhcpPacketFromServer(PacketContext context,
866 Ethernet ethernetPacket) {
867 if (log.isTraceEnabled()) {
868 log.trace("DHCP packet received from server at {} {}",
869 context.inPacket().receivedFrom(), ethernetPacket);
870 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100871 // get dhcp header.
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530872 Ethernet etherReply = (Ethernet) ethernetPacket.clone();
Amit Ghosh47243cb2017-07-26 05:08:53 +0100873 IPv4 ipv4Packet = (IPv4) etherReply.getPayload();
874 UDP udpPacket = (UDP) ipv4Packet.getPayload();
875 DHCP dhcpPayload = (DHCP) udpPacket.getPayload();
876
Amit Ghosh47243cb2017-07-26 05:08:53 +0100877 MacAddress dstMac = valueOf(dhcpPayload.getClientHardwareAddress());
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000878 ConnectPoint subsCp = getConnectPointOfClient(dstMac, context);
Amit Ghosh2095dc62017-09-25 20:56:55 +0100879 // If we can't find the subscriber, can't process further
880 if (subsCp == null) {
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700881 log.warn("Couldn't find connection point for mac address {} DHCPOFFERs won't be delivered", dstMac);
Amit Ghosh2095dc62017-09-25 20:56:55 +0100882 return null;
883 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100884
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000885 SubscriberAndDeviceInformation entry = getSubscriberInfoFromServer(dhcpPayload, context);
886
Thomas Lee S0dc9a3b2020-01-14 10:42:29 +0530887 // if it's an ACK packet store the information for display purpose
888 if ((getDhcpPacketType(dhcpPayload) == DHCP.MsgType.DHCPACK) && (entry != null)) {
889
890 IpAddress ip = IpAddress.valueOf(dhcpPayload.getYourIPAddress());
891 //storeDHCPAllocationInfo
892 DhcpAllocationInfo info = new DhcpAllocationInfo(subsCp,
893 dhcpPayload.getPacketType(), entry.circuitId(), dstMac, ip);
Jonathan Hart617bc3e2020-02-14 10:42:23 -0800894 allocations.put(entry.id(), info);
Thomas Lee S0dc9a3b2020-01-14 10:42:29 +0530895
896 post(new DhcpL2RelayEvent(DhcpL2RelayEvent.Type.UPDATED, info, subsCp));
897 } // end storing of info
898
899
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000900 UniTagInformation uniTagInformation = getUnitagInformationFromPacketContext(context, entry);
901 if (uniTagInformation == null) {
902 log.warn("Missing service information for connectPoint {} / cTag {}",
903 context.inPacket().receivedFrom(), context.inPacket().parsed().getVlanID());
904 return null;
905 }
906
Jonathan Hart77ca3152020-02-21 14:31:21 -0800907 updateDhcpRelayCountersStore(entry, DhcpL2RelayCounterNames.valueOf("PACKETS_FROM_SERVER"));
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300908
Amit Ghosh47243cb2017-07-26 05:08:53 +0100909 // we leave the srcMac from the original packet
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000910 etherReply.setQinQVID(VlanId.NO_VID);
911 etherReply.setQinQPriorityCode((byte) 0);
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530912 etherReply.setDestinationMACAddress(dstMac);
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000913 etherReply.setVlanID(uniTagInformation.getPonCTag().toShort());
914 if (uniTagInformation.getUsPonCTagPriority() != -1) {
915 etherReply.setPriorityCode((byte) uniTagInformation.getUsPonCTagPriority());
916 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100917
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000918 if (option82) {
919 udpPacket.setPayload(removeOption82(dhcpPayload));
920 } else {
921 udpPacket.setPayload(dhcpPayload);
922 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100923 ipv4Packet.setPayload(udpPacket);
924 etherReply.setPayload(ipv4Packet);
925
Saurav Das15626a02018-09-27 18:36:45 -0700926 log.info("Finished processing packet.. relaying to client");
Amit Ghosh47243cb2017-07-26 05:08:53 +0100927 return etherReply;
928 }
929
Amit Ghosha17354e2017-08-23 12:56:04 +0100930 /*
931 * Get ConnectPoint of the Client based on it's MAC address
932 */
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000933 private ConnectPoint getConnectPointOfClient(MacAddress dstMac, PacketContext context) {
Amit Ghosha17354e2017-08-23 12:56:04 +0100934 Set<Host> hosts = hostService.getHostsByMac(dstMac);
935 if (hosts == null || hosts.isEmpty()) {
936 log.warn("Cannot determine host for DHCP client: {}. Aborting "
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530937 + "relay for dhcp packet from server",
Amit Ghosha17354e2017-08-23 12:56:04 +0100938 dstMac);
939 return null;
940 }
941 for (Host h : hosts) {
942 // if more than one,
943 // find the connect point which has an valid entry in SADIS
944 ConnectPoint cp = new ConnectPoint(h.location().deviceId(),
945 h.location().port());
946
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000947 String portId = nasPortId(cp);
948 SubscriberAndDeviceInformation sub = subsService.get(portId);
949 if (sub == null) {
950 log.warn("Subscriber info not found for {}", cp);
951 return null;
Amit Ghosha17354e2017-08-23 12:56:04 +0100952 }
Amit Ghosha17354e2017-08-23 12:56:04 +0100953
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000954 UniTagInformation uniTagInformation = getUnitagInformationFromPacketContext(context, sub);
955 if (uniTagInformation == null) {
956 log.warn("Missing service information for connectPoint {} / cTag {}",
957 context.inPacket().receivedFrom(), context.inPacket().parsed().getVlanID());
958 return null;
959 }
960 return cp;
961 }
Amit Ghosha17354e2017-08-23 12:56:04 +0100962 return null;
963 }
964
Amit Ghosh47243cb2017-07-26 05:08:53 +0100965 //send the response to the requester host.
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000966 private void sendReply(Ethernet ethPacket, DHCP dhcpPayload, PacketContext context) {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100967 MacAddress descMac = valueOf(dhcpPayload.getClientHardwareAddress());
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000968 ConnectPoint subCp = getConnectPointOfClient(descMac, context);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100969
970 // Send packet out to requester if the host information is available
Amit Ghosha17354e2017-08-23 12:56:04 +0100971 if (subCp != null) {
Saurav Das15626a02018-09-27 18:36:45 -0700972 log.info("Sending DHCP packet to client at {}", subCp);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100973 TrafficTreatment t = DefaultTrafficTreatment.builder()
Amit Ghosha17354e2017-08-23 12:56:04 +0100974 .setOutput(subCp.port()).build();
Amit Ghosh47243cb2017-07-26 05:08:53 +0100975 OutboundPacket o = new DefaultOutboundPacket(
Amit Ghosha17354e2017-08-23 12:56:04 +0100976 subCp.deviceId(), t, ByteBuffer.wrap(ethPacket.serialize()));
Amit Ghosh47243cb2017-07-26 05:08:53 +0100977 if (log.isTraceEnabled()) {
Saurav Das15626a02018-09-27 18:36:45 -0700978 log.trace("Relaying packet to dhcp client at {} {}", subCp,
979 ethPacket);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100980 }
981 packetService.emit(o);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100982 } else {
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000983 log.error("Dropping DHCP packet because can't find host for {}", descMac);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100984 }
985 }
986 }
987
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000988 private DHCP addOption82(DHCP dhcpPacket, SubscriberAndDeviceInformation entry) {
989 log.debug("option82data {} ", entry);
990
Jonathan Hartedbf6422018-05-02 17:30:05 -0700991 List<DhcpOption> options = Lists.newArrayList(dhcpPacket.getOptions());
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000992 DhcpOption82 option82 = new DhcpOption82();
993 option82.setAgentCircuitId(entry.circuitId());
994 option82.setAgentRemoteId(entry.remoteId());
Jonathan Hartedbf6422018-05-02 17:30:05 -0700995 DhcpOption option = new DhcpOption()
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530996 .setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue())
997 .setData(option82.toByteArray())
998 .setLength(option82.length());
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000999
1000 options.add(options.size() - 1, option);
1001 dhcpPacket.setOptions(options);
Amit Ghosh8951f042017-08-10 13:48:10 +01001002
Deepa vaddireddy0060f532017-08-04 06:46:05 +00001003 return dhcpPacket;
1004
1005 }
1006
1007 private DHCP removeOption82(DHCP dhcpPacket) {
Jonathan Hartedbf6422018-05-02 17:30:05 -07001008 List<DhcpOption> options = dhcpPacket.getOptions();
1009 List<DhcpOption> newoptions = options.stream()
Deepa vaddireddy0060f532017-08-04 06:46:05 +00001010 .filter(option -> option.getCode() != DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue())
1011 .collect(Collectors.toList());
1012
1013 return dhcpPacket.setOptions(newoptions);
1014 }
Amit Ghosh47243cb2017-07-26 05:08:53 +01001015 /**
1016 * Listener for network config events.
1017 */
1018 private class InternalConfigListener implements NetworkConfigListener {
1019
1020 @Override
1021 public void event(NetworkConfigEvent event) {
1022
1023 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
1024 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
1025 event.configClass().equals(DhcpL2RelayConfig.class)) {
1026 updateConfig();
1027 log.info("Reconfigured");
1028 }
1029 }
1030 }
Deepa vaddireddy0060f532017-08-04 06:46:05 +00001031
Amit Ghosh8951f042017-08-10 13:48:10 +01001032 /**
1033 * Handles Mastership changes for the devices which connect
1034 * to the DHCP server.
1035 */
1036 private class InnerMastershipListener implements MastershipListener {
1037 @Override
1038 public void event(MastershipEvent event) {
Amit Ghosh83c8c892017-11-09 11:08:27 +00001039 if (!useOltUplink) {
1040 if (dhcpServerConnectPoint.get() != null &&
1041 dhcpServerConnectPoint.get().deviceId().
1042 equals(event.subject())) {
1043 log.trace("Mastership Event recevived for {}", event.subject());
1044 // mastership of the device for our connect point has changed
1045 // reselect
1046 selectServerConnectPoint();
1047 }
Amit Ghosh8951f042017-08-10 13:48:10 +01001048 }
1049 }
1050 }
Deepa vaddireddy0060f532017-08-04 06:46:05 +00001051
Jonathan Hart617bc3e2020-02-14 10:42:23 -08001052 private void removeAllocations(Predicate<Map.Entry<String, Versioned<DhcpAllocationInfo>>> pred) {
1053 allocations.stream()
1054 .filter(pred)
1055 .map(Map.Entry::getKey)
1056 .collect(Collectors.toList())
1057 .forEach(allocations::remove);
1058 }
1059
Amit Ghosh8951f042017-08-10 13:48:10 +01001060 /**
1061 * Handles Device status change for the devices which connect
1062 * to the DHCP server.
1063 */
1064 private class InnerDeviceListener implements DeviceListener {
1065 @Override
1066 public void event(DeviceEvent event) {
Jonathan Hart617bc3e2020-02-14 10:42:23 -08001067 // ensure only one instance handles the event
1068 if (!Objects.equals(leadershipService.getLeader(LEADER_TOPIC), clusterService.getLocalNode().id())) {
1069 return;
1070 }
1071
1072 final DeviceId deviceId = event.subject().id();
1073
Thomas Lee S9df15082019-12-23 11:31:15 +05301074 switch (event.type()) {
Jonathan Hart617bc3e2020-02-14 10:42:23 -08001075 case DEVICE_REMOVED:
1076 log.info("Device removed {}", event.subject().id());
1077 removeAllocations(e -> e.getValue().value().location().deviceId().equals(deviceId));
1078 break;
Thomas Lee S9df15082019-12-23 11:31:15 +05301079 case DEVICE_AVAILABILITY_CHANGED:
Jonathan Hart617bc3e2020-02-14 10:42:23 -08001080 boolean available = deviceService.isAvailable(deviceId);
1081 log.info("Device Avail Changed {} to {}", event.subject().id(), available);
1082
1083 if (!available && deviceService.getPorts(deviceId).isEmpty()) {
1084 removeAllocations(e -> e.getValue().value().location().deviceId().equals(deviceId));
1085 log.info("Device {} is removed from DHCP allocationmap ", deviceId);
Thomas Lee S9df15082019-12-23 11:31:15 +05301086 }
1087 break;
Thomas Lee S6b77ad22020-01-10 11:27:43 +05301088 case PORT_REMOVED:
1089 Port port = event.port();
Thomas Lee S6b77ad22020-01-10 11:27:43 +05301090 log.info("Port {} is deleted on device {}", port, deviceId);
Jonathan Hart617bc3e2020-02-14 10:42:23 -08001091
1092 ConnectPoint cp = new ConnectPoint(deviceId, port.number());
1093 removeAllocations(e -> e.getValue().value().location().equals(cp));
1094
Thomas Lee S6b77ad22020-01-10 11:27:43 +05301095 log.info("Port {} on device {} is removed from DHCP allocationmap", event.port(), deviceId);
1096 break;
Thomas Lee S9df15082019-12-23 11:31:15 +05301097 default:
1098 break;
1099 }
Saurav Das15626a02018-09-27 18:36:45 -07001100 if (log.isTraceEnabled() &&
1101 !event.type().equals(DeviceEvent.Type.PORT_STATS_UPDATED)) {
1102 log.trace("Device Event received for {} event {}",
1103 event.subject(), event.type());
1104 }
Amit Ghosh83c8c892017-11-09 11:08:27 +00001105 if (!useOltUplink) {
1106 if (dhcpServerConnectPoint.get() == null) {
1107 switch (event.type()) {
1108 case DEVICE_ADDED:
1109 case DEVICE_AVAILABILITY_CHANGED:
Saurav Dasb14f08a2019-02-22 16:34:15 -08001110 // some device is available check if we can get a
1111 // connect point we can use
1112 addOrRemoveDhcpTrapFromServer(true);
Amit Ghosh83c8c892017-11-09 11:08:27 +00001113 break;
1114 default:
1115 break;
1116 }
1117 return;
Amit Ghosh8951f042017-08-10 13:48:10 +01001118 }
Amit Ghosh83c8c892017-11-09 11:08:27 +00001119 if (dhcpServerConnectPoint.get().deviceId().
1120 equals(event.subject().id())) {
1121 switch (event.type()) {
1122 case DEVICE_AVAILABILITY_CHANGED:
1123 case DEVICE_REMOVED:
1124 case DEVICE_SUSPENDED:
1125 // state of our device has changed, check if we need
Saurav Dasb14f08a2019-02-22 16:34:15 -08001126 // to re-select a connectpoint
1127 addOrRemoveDhcpTrapFromServer(true);
Amit Ghosh83c8c892017-11-09 11:08:27 +00001128 break;
1129 default:
1130 break;
1131 }
1132 }
1133 } else {
Amit Ghosh8951f042017-08-10 13:48:10 +01001134 switch (event.type()) {
Amit Ghosh83c8c892017-11-09 11:08:27 +00001135 case PORT_ADDED:
Saurav Dasb4e3e102018-10-02 15:31:17 -07001136 if (useOltUplink && isUplinkPortOfOlt(event.subject().id(), event.port())) {
Saurav Dasb14f08a2019-02-22 16:34:15 -08001137 requestDhcpPacketsFromConnectPoint(
1138 new ConnectPoint(event.subject().id(), event.port().number()),
Jonathan Hart617bc3e2020-02-14 10:42:23 -08001139 Optional.empty());
Amit Ghosh83c8c892017-11-09 11:08:27 +00001140 }
Amit Ghosh8951f042017-08-10 13:48:10 +01001141 break;
1142 default:
1143 break;
1144 }
1145 }
1146 }
1147 }
Jonathan Hart77ca3152020-02-21 14:31:21 -08001148
1149 private class InnerDhcpL2RelayStoreDelegate implements DhcpL2RelayStoreDelegate {
1150 @Override
1151 public void notify(DhcpL2RelayEvent event) {
1152 if (event.type().equals(DhcpL2RelayEvent.Type.STATS_UPDATE)) {
1153 DhcpL2RelayEvent toPost = event;
1154 if (event.getSubscriberId() != null) {
1155 // infuse the event with the allocation info before posting
1156 DhcpAllocationInfo info = Versioned.valueOrNull(allocations.get(event.getSubscriberId()));
1157 toPost = new DhcpL2RelayEvent(event.type(), info, event.connectPoint(),
1158 event.getCountersEntry(), event.getSubscriberId());
1159 }
1160 post(toPost);
1161 }
1162
1163 }
1164 }
Amit Ghosh47243cb2017-07-26 05:08:53 +01001165}