blob: cf356772a1992f38f5aa990ad7c68e7a81a02392 [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
Saurav Das15626a02018-09-27 18:36:45 -070018import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_MessageType;
19import static org.onlab.packet.MacAddress.valueOf;
20import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
21
22import java.nio.ByteBuffer;
23import java.util.ArrayList;
24import java.util.Arrays;
25import java.util.Dictionary;
26import java.util.List;
27import java.util.Map;
28import java.util.Optional;
29import java.util.Set;
30import java.util.concurrent.atomic.AtomicReference;
31import java.util.stream.Collectors;
32
Amit Ghosh47243cb2017-07-26 05:08:53 +010033import org.apache.felix.scr.annotations.Activate;
34import org.apache.felix.scr.annotations.Component;
35import org.apache.felix.scr.annotations.Deactivate;
36import org.apache.felix.scr.annotations.Modified;
37import org.apache.felix.scr.annotations.Property;
38import org.apache.felix.scr.annotations.Reference;
39import org.apache.felix.scr.annotations.ReferenceCardinality;
Jonathan Hartc36c9552018-07-31 15:07:53 -040040import org.apache.felix.scr.annotations.Service;
Amit Ghosh47243cb2017-07-26 05:08:53 +010041import org.onlab.packet.DHCP;
Amit Ghosh47243cb2017-07-26 05:08:53 +010042import org.onlab.packet.DHCPPacketType;
Deepa vaddireddy0060f532017-08-04 06:46:05 +000043import org.onlab.packet.Ethernet;
Amit Ghosh47243cb2017-07-26 05:08:53 +010044import org.onlab.packet.IPv4;
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +053045import org.onlab.packet.IpAddress;
Deepa vaddireddy0060f532017-08-04 06:46:05 +000046import org.onlab.packet.MacAddress;
Amit Ghosh47243cb2017-07-26 05:08:53 +010047import org.onlab.packet.TpPort;
48import org.onlab.packet.UDP;
49import org.onlab.packet.VlanId;
Jonathan Hartedbf6422018-05-02 17:30:05 -070050import org.onlab.packet.dhcp.DhcpOption;
Amit Ghosh47243cb2017-07-26 05:08:53 +010051import org.onlab.util.Tools;
52import org.onosproject.cfg.ComponentConfigService;
53import org.onosproject.core.ApplicationId;
54import org.onosproject.core.CoreService;
Jonathan Hartc36c9552018-07-31 15:07:53 -040055import org.onosproject.event.AbstractListenerManager;
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +053056import org.onosproject.mastership.MastershipEvent;
57import org.onosproject.mastership.MastershipListener;
58import org.onosproject.mastership.MastershipService;
Amit Ghosh47243cb2017-07-26 05:08:53 +010059import org.onosproject.net.AnnotationKeys;
60import org.onosproject.net.ConnectPoint;
Amit Ghosh83c8c892017-11-09 11:08:27 +000061import org.onosproject.net.Device;
62import org.onosproject.net.DeviceId;
Amit Ghosh47243cb2017-07-26 05:08:53 +010063import org.onosproject.net.Host;
64import org.onosproject.net.Port;
Amit Ghosh83c8c892017-11-09 11:08:27 +000065import org.onosproject.net.PortNumber;
Amit Ghosh47243cb2017-07-26 05:08:53 +010066import org.onosproject.net.config.ConfigFactory;
67import org.onosproject.net.config.NetworkConfigEvent;
68import org.onosproject.net.config.NetworkConfigListener;
69import org.onosproject.net.config.NetworkConfigRegistry;
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +053070import org.onosproject.net.device.DeviceEvent;
71import org.onosproject.net.device.DeviceListener;
Amit Ghosh47243cb2017-07-26 05:08:53 +010072import org.onosproject.net.device.DeviceService;
73import org.onosproject.net.flow.DefaultTrafficSelector;
74import org.onosproject.net.flow.DefaultTrafficTreatment;
75import org.onosproject.net.flow.TrafficSelector;
76import org.onosproject.net.flow.TrafficTreatment;
Saurav Dasb4e3e102018-10-02 15:31:17 -070077import org.onosproject.net.flowobjective.FlowObjectiveService;
Amit Ghosh47243cb2017-07-26 05:08:53 +010078import org.onosproject.net.host.HostService;
79import org.onosproject.net.packet.DefaultOutboundPacket;
80import org.onosproject.net.packet.OutboundPacket;
81import org.onosproject.net.packet.PacketContext;
82import org.onosproject.net.packet.PacketPriority;
83import org.onosproject.net.packet.PacketProcessor;
84import org.onosproject.net.packet.PacketService;
Matteo Scandolo57af5d12019-04-29 17:11:41 -070085import org.opencord.dhcpl2relay.DhcpAllocationInfo;
86import org.opencord.dhcpl2relay.DhcpL2RelayEvent;
87import org.opencord.dhcpl2relay.DhcpL2RelayListener;
88import org.opencord.dhcpl2relay.DhcpL2RelayService;
89import org.opencord.dhcpl2relay.impl.packet.DhcpOption82;
Gamze Abakac806c6c2018-12-03 12:49:46 +000090import org.opencord.sadis.BaseInformationService;
91import org.opencord.sadis.SadisService;
Amit Ghosh47243cb2017-07-26 05:08:53 +010092import org.opencord.sadis.SubscriberAndDeviceInformation;
Amit Ghosh47243cb2017-07-26 05:08:53 +010093import org.osgi.service.component.ComponentContext;
94import org.slf4j.Logger;
95import org.slf4j.LoggerFactory;
96
Saurav Das15626a02018-09-27 18:36:45 -070097import com.google.common.collect.ImmutableSet;
98import com.google.common.collect.Lists;
99import com.google.common.collect.Maps;
100import com.google.common.collect.Sets;
Amit Ghosh47243cb2017-07-26 05:08:53 +0100101
102/**
103 * DHCP Relay Agent Application Component.
104 */
Jonathan Hartc36c9552018-07-31 15:07:53 -0400105@Service
Amit Ghosh47243cb2017-07-26 05:08:53 +0100106@Component(immediate = true)
Jonathan Hartc36c9552018-07-31 15:07:53 -0400107public class DhcpL2Relay
108 extends AbstractListenerManager<DhcpL2RelayEvent, DhcpL2RelayListener>
109 implements DhcpL2RelayService {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100110
111 public static final String DHCP_L2RELAY_APP = "org.opencord.dhcpl2relay";
Saurav Dasb4e3e102018-10-02 15:31:17 -0700112 private static final String HOST_LOC_PROVIDER =
113 "org.onosproject.provider.host.impl.HostLocationProvider";
Amit Ghosh47243cb2017-07-26 05:08:53 +0100114 private final Logger log = LoggerFactory.getLogger(getClass());
115 private final InternalConfigListener cfgListener =
116 new InternalConfigListener();
117
118 private final Set<ConfigFactory> factories = ImmutableSet.of(
119 new ConfigFactory<ApplicationId, DhcpL2RelayConfig>(APP_SUBJECT_FACTORY,
120 DhcpL2RelayConfig.class,
121 "dhcpl2relay") {
122 @Override
123 public DhcpL2RelayConfig createConfig() {
124 return new DhcpL2RelayConfig();
125 }
126 }
127 );
128
129 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
130 protected NetworkConfigRegistry cfgService;
131
132 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
133 protected CoreService coreService;
134
135 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
136 protected PacketService packetService;
137
138 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
139 protected HostService hostService;
140
141 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
142 protected ComponentConfigService componentConfigService;
143
144 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Gamze Abakac806c6c2018-12-03 12:49:46 +0000145 protected SadisService sadisService;
Amit Ghosh47243cb2017-07-26 05:08:53 +0100146
147 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
148 protected DeviceService deviceService;
149
Amit Ghosh8951f042017-08-10 13:48:10 +0100150 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
151 protected MastershipService mastershipService;
152
Saurav Dasb4e3e102018-10-02 15:31:17 -0700153 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
154 protected FlowObjectiveService flowObjectiveService;
155
Amit Ghosh47243cb2017-07-26 05:08:53 +0100156 @Property(name = "option82", boolValue = true,
157 label = "Add option 82 to relayed packets")
158 protected boolean option82 = true;
159
Amit Ghosha17354e2017-08-23 12:56:04 +0100160 @Property(name = "enableDhcpBroadcastReplies", boolValue = false,
Amit Ghosh2095dc62017-09-25 20:56:55 +0100161 label = "Ask the DHCP Server to send back replies as L2 broadcast")
Amit Ghosha17354e2017-08-23 12:56:04 +0100162 protected boolean enableDhcpBroadcastReplies = false;
163
Amit Ghosh47243cb2017-07-26 05:08:53 +0100164 private DhcpRelayPacketProcessor dhcpRelayPacketProcessor =
165 new DhcpRelayPacketProcessor();
166
Amit Ghosh8951f042017-08-10 13:48:10 +0100167 private InnerMastershipListener changeListener = new InnerMastershipListener();
168 private InnerDeviceListener deviceListener = new InnerDeviceListener();
Amit Ghosh47243cb2017-07-26 05:08:53 +0100169
Amit Ghosh8951f042017-08-10 13:48:10 +0100170 // connect points to the DHCP server
171 Set<ConnectPoint> dhcpConnectPoints;
172 private AtomicReference<ConnectPoint> dhcpServerConnectPoint = new AtomicReference<>();
Amit Ghosh47243cb2017-07-26 05:08:53 +0100173 private MacAddress dhcpConnectMac = MacAddress.BROADCAST;
174 private ApplicationId appId;
175
Amit Ghosha17354e2017-08-23 12:56:04 +0100176 static Map<String, DhcpAllocationInfo> allocationMap = Maps.newConcurrentMap();
Amit Ghosh83c8c892017-11-09 11:08:27 +0000177 private boolean modifyClientPktsSrcDstMac = false;
178 //Whether to use the uplink port of the OLTs to send/receive messages to the DHCP server
179 private boolean useOltUplink = false;
Amit Ghosha17354e2017-08-23 12:56:04 +0100180
Gamze Abakac806c6c2018-12-03 12:49:46 +0000181 private BaseInformationService<SubscriberAndDeviceInformation> subsService;
182
Amit Ghosh47243cb2017-07-26 05:08:53 +0100183 @Activate
184 protected void activate(ComponentContext context) {
185 //start the dhcp relay agent
186 appId = coreService.registerApplication(DHCP_L2RELAY_APP);
Saurav Dasb4e3e102018-10-02 15:31:17 -0700187 // ensure that host-learning via dhcp includes IP addresses
188 componentConfigService.preSetProperty(HOST_LOC_PROVIDER,
189 "useDhcp", Boolean.TRUE.toString());
Amit Ghosh47243cb2017-07-26 05:08:53 +0100190 componentConfigService.registerProperties(getClass());
Jonathan Hartc36c9552018-07-31 15:07:53 -0400191 eventDispatcher.addSink(DhcpL2RelayEvent.class, listenerRegistry);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100192
193 cfgService.addListener(cfgListener);
Amit Ghosh8951f042017-08-10 13:48:10 +0100194 mastershipService.addListener(changeListener);
195 deviceService.addListener(deviceListener);
196
Amit Ghosh47243cb2017-07-26 05:08:53 +0100197 factories.forEach(cfgService::registerConfigFactory);
198 //update the dhcp server configuration.
199 updateConfig();
200 //add the packet services.
201 packetService.addProcessor(dhcpRelayPacketProcessor,
202 PacketProcessor.director(0));
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000203 if (context != null) {
204 modified(context);
205 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100206
Gamze Abakac806c6c2018-12-03 12:49:46 +0000207 subsService = sadisService.getSubscriberInfoService();
208
Amit Ghosh47243cb2017-07-26 05:08:53 +0100209 log.info("DHCP-L2-RELAY Started");
210 }
211
212 @Deactivate
213 protected void deactivate() {
214 cfgService.removeListener(cfgListener);
215 factories.forEach(cfgService::unregisterConfigFactory);
216 packetService.removeProcessor(dhcpRelayPacketProcessor);
Saurav Dasb4e3e102018-10-02 15:31:17 -0700217 cancelDhcpPktsFromServer();
Amit Ghosh47243cb2017-07-26 05:08:53 +0100218
219 componentConfigService.unregisterProperties(getClass(), false);
Deepa Vaddireddy77a6ac72017-09-20 20:36:52 +0530220 deviceService.removeListener(deviceListener);
221 mastershipService.removeListener(changeListener);
Jonathan Hartc36c9552018-07-31 15:07:53 -0400222 eventDispatcher.removeSink(DhcpL2RelayEvent.class);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100223 log.info("DHCP-L2-RELAY Stopped");
224 }
225
226 @Modified
227 protected void modified(ComponentContext context) {
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000228
Amit Ghosh47243cb2017-07-26 05:08:53 +0100229 Dictionary<?, ?> properties = context.getProperties();
230
231 Boolean o = Tools.isPropertyEnabled(properties, "option82");
232 if (o != null) {
233 option82 = o;
234 }
Amit Ghosh2095dc62017-09-25 20:56:55 +0100235
236 o = Tools.isPropertyEnabled(properties, "enableDhcpBroadcastReplies");
237 if (o != null) {
238 enableDhcpBroadcastReplies = o;
239 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100240 }
241
242 /**
243 * Checks if this app has been configured.
244 *
245 * @return true if all information we need have been initialized
246 */
247 private boolean configured() {
Amit Ghosh83c8c892017-11-09 11:08:27 +0000248 if (!useOltUplink) {
249 return dhcpServerConnectPoint.get() != null;
250 }
251 return true;
Amit Ghosh47243cb2017-07-26 05:08:53 +0100252 }
253
Amit Ghosh8951f042017-08-10 13:48:10 +0100254 /**
255 * Selects a connect point through an available device for which it is the master.
256 */
257 private void selectServerConnectPoint() {
258 synchronized (this) {
259 dhcpServerConnectPoint.set(null);
260 if (dhcpConnectPoints != null) {
261 // find a connect point through a device for which we are master
262 for (ConnectPoint cp: dhcpConnectPoints) {
263 if (mastershipService.isLocalMaster(cp.deviceId())) {
264 if (deviceService.isAvailable(cp.deviceId())) {
265 dhcpServerConnectPoint.set(cp);
266 }
267 log.info("DHCP connectPoint selected is {}", cp);
268 break;
269 }
270 }
271 }
272
273 log.info("DHCP Server connectPoint is {}", dhcpServerConnectPoint.get());
274
275 if (dhcpServerConnectPoint.get() == null) {
276 log.error("Master of none, can't relay DHCP Message to server");
277 }
278 }
279 }
280
281 /**
282 * Updates the network configuration.
283 */
Amit Ghosh47243cb2017-07-26 05:08:53 +0100284 private void updateConfig() {
285 DhcpL2RelayConfig cfg = cfgService.getConfig(appId, DhcpL2RelayConfig.class);
286 if (cfg == null) {
287 log.warn("Dhcp Server info not available");
288 return;
289 }
Amit Ghosh8951f042017-08-10 13:48:10 +0100290
291 dhcpConnectPoints = Sets.newConcurrentHashSet(cfg.getDhcpServerConnectPoint());
Amit Ghosh83c8c892017-11-09 11:08:27 +0000292 modifyClientPktsSrcDstMac = cfg.getModifySrcDstMacAddresses();
Saurav Dasb4e3e102018-10-02 15:31:17 -0700293 boolean prevUseOltUplink = useOltUplink;
Amit Ghosh83c8c892017-11-09 11:08:27 +0000294 useOltUplink = cfg.getUseOltUplinkForServerPktInOut();
Amit Ghosh8951f042017-08-10 13:48:10 +0100295
Saurav Dasb4e3e102018-10-02 15:31:17 -0700296 if (useOltUplink) {
297 for (ConnectPoint cp : getUplinkPortsOfOlts()) {
298 log.debug("requestDhcpPackets: ConnectPoint: {}", cp);
Saurav Dasb14f08a2019-02-22 16:34:15 -0800299 requestDhcpPacketsFromConnectPoint(cp, null);
Saurav Dasb4e3e102018-10-02 15:31:17 -0700300 }
301 // check if previous config was different and so trap flows may
Saurav Dasb14f08a2019-02-22 16:34:15 -0800302 // need to be removed from other places like AGG switches
Saurav Dasb4e3e102018-10-02 15:31:17 -0700303 if (!prevUseOltUplink) {
Saurav Dasb14f08a2019-02-22 16:34:15 -0800304 addOrRemoveDhcpTrapFromServer(false);
Saurav Dasb4e3e102018-10-02 15:31:17 -0700305 }
Saurav Dasb4e3e102018-10-02 15:31:17 -0700306 } else {
Saurav Dasb14f08a2019-02-22 16:34:15 -0800307 // uplink on AGG switch
308 addOrRemoveDhcpTrapFromServer(true);
Saurav Dasb4e3e102018-10-02 15:31:17 -0700309 }
310 }
311
312 private void cancelDhcpPktsFromServer() {
313 if (useOltUplink) {
314 for (ConnectPoint cp : getUplinkPortsOfOlts()) {
315 log.debug("cancelDhcpPackets: ConnectPoint: {}", cp);
Saurav Dasb14f08a2019-02-22 16:34:15 -0800316 cancelDhcpPacketsFromConnectPoint(cp, null);
Saurav Dasb4e3e102018-10-02 15:31:17 -0700317 }
318 } else {
Saurav Dasb14f08a2019-02-22 16:34:15 -0800319 // uplink on AGG switch
320 addOrRemoveDhcpTrapFromServer(false);
Amit Ghosh83c8c892017-11-09 11:08:27 +0000321 }
Saurav Dasb4e3e102018-10-02 15:31:17 -0700322 }
323
Saurav Dasb14f08a2019-02-22 16:34:15 -0800324 /**
325 * Used to add or remove DHCP trap flow for packets received from DHCP server.
326 * Typically used on a non OLT device, like an AGG switch. When adding, a
327 * new dhcp server connect point is selected from the configured options.
328 *
329 * @param add true if dhcp trap flow is to be added, false to remove the
330 * trap flow
331 */
332 private void addOrRemoveDhcpTrapFromServer(boolean add) {
333 if (add) {
334 selectServerConnectPoint();
335 log.debug("dhcp server connect point: " + dhcpServerConnectPoint);
336 }
337 if (dhcpServerConnectPoint.get() == null) {
338 log.warn("No dhcpServer connectPoint found, cannot {} dhcp trap flows",
339 (add) ? "install" : "remove");
340 return;
341 }
342 if (add) {
343 log.info("Adding trap to dhcp server connect point: "
344 + dhcpServerConnectPoint);
345 requestDhcpPacketsFromConnectPoint(dhcpServerConnectPoint.get(),
346 Optional.of(PacketPriority.HIGH1));
347 } else {
348 log.info("Removing trap from dhcp server connect point: "
349 + dhcpServerConnectPoint);
350 cancelDhcpPacketsFromConnectPoint(dhcpServerConnectPoint.get(),
351 Optional.of(PacketPriority.HIGH1));
352 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100353 }
354
355 /**
Amit Ghosh83c8c892017-11-09 11:08:27 +0000356 * Returns all the uplink ports of OLTs configured in SADIS.
357 * Only ports visible in ONOS and for which this instance is master
358 * are returned
359 */
360 private List<ConnectPoint> getUplinkPortsOfOlts() {
361 List<ConnectPoint> cps = new ArrayList<>();
362
363 // find all the olt devices and if their uplink ports are visible
364 Iterable<Device> devices = deviceService.getDevices();
365 for (Device d : devices) {
366 // check if this device is provisioned in Sadis
367
368 log.debug("getUplinkPortsOfOlts: Checking mastership of {}", d);
369 // do only for devices for which we are the master
370 if (!mastershipService.isLocalMaster(d.id())) {
371 continue;
372 }
373
374 String devSerialNo = d.serialNumber();
375 SubscriberAndDeviceInformation deviceInfo = subsService.get(devSerialNo);
376 log.debug("getUplinkPortsOfOlts: Found device: {}", deviceInfo);
377 if (deviceInfo != null) {
378 // check if the uplink port with that number is available on the device
379 PortNumber pNum = PortNumber.portNumber(deviceInfo.uplinkPort());
380 Port port = deviceService.getPort(d.id(), pNum);
381 log.debug("getUplinkPortsOfOlts: Found port: {}", port);
382 if (port != null) {
383 cps.add(new ConnectPoint(d.id(), pNum));
384 }
385 }
386 }
387 return cps;
388 }
389
390 /**
391 * Returns whether the passed port is the uplink port of the olt device.
392 */
393 private boolean isUplinkPortOfOlt(DeviceId dId, Port p) {
394 log.debug("isUplinkPortOfOlt: DeviceId: {} Port: {}", dId, p);
395 // do only for devices for which we are the master
396 if (!mastershipService.isLocalMaster(dId)) {
397 return false;
398 }
399
400 Device d = deviceService.getDevice(dId);
401 SubscriberAndDeviceInformation deviceInfo = subsService.get(d.serialNumber());
402
403 if (deviceInfo != null) {
404 return (deviceInfo.uplinkPort() == p.number().toLong());
405 }
406
407 return false;
408 }
409
410 /**
411 * Returns the connectPoint which is the uplink port of the OLT.
412 */
413 private ConnectPoint getUplinkConnectPointOfOlt(DeviceId dId) {
414
415 Device d = deviceService.getDevice(dId);
416 SubscriberAndDeviceInformation deviceInfo = subsService.get(d.serialNumber());
417 log.debug("getUplinkConnectPointOfOlt DeviceId: {} devInfo: {}", dId, deviceInfo);
418 if (deviceInfo != null) {
419 PortNumber pNum = PortNumber.portNumber(deviceInfo.uplinkPort());
420 Port port = deviceService.getPort(d.id(), pNum);
421 if (port != null) {
422 return new ConnectPoint(d.id(), pNum);
423 }
424 }
425
426 return null;
427 }
428
429 /**
430 * Request DHCP packet from particular connect point via PacketService.
Saurav Dasb14f08a2019-02-22 16:34:15 -0800431 * Optionally provide a priority for the trap flow. If no such priority is
432 * provided, the default priority will be used.
433 *
434 * @param cp the connect point to trap dhcp packets from
435 * @param priority of the trap flow, null to use default priority
Amit Ghosh83c8c892017-11-09 11:08:27 +0000436 */
Saurav Dasb14f08a2019-02-22 16:34:15 -0800437 private void requestDhcpPacketsFromConnectPoint(ConnectPoint cp,
438 Optional<PacketPriority> priority) {
Amit Ghosh83c8c892017-11-09 11:08:27 +0000439 TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
440 .matchEthType(Ethernet.TYPE_IPV4)
441 .matchInPort(cp.port())
442 .matchIPProtocol(IPv4.PROTOCOL_UDP)
443 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_SERVER_PORT));
444 packetService.requestPackets(selectorServer.build(),
Saurav Dasb14f08a2019-02-22 16:34:15 -0800445 priority.isPresent() ? priority.get() : PacketPriority.CONTROL,
446 appId, Optional.of(cp.deviceId()));
Amit Ghosh83c8c892017-11-09 11:08:27 +0000447 }
448
449 /**
Saurav Dasb14f08a2019-02-22 16:34:15 -0800450 * Cancel DHCP packet from particular connect point via PacketService. If
451 * the request was made with a specific packet priority, then the same
452 * priority should be used in this call.
453 *
454 * @param cp the connect point for the trap flow
455 * @param priority with which the trap flow was requested; if request
456 * priority was not specified, this param should also be null
Amit Ghosh83c8c892017-11-09 11:08:27 +0000457 */
Saurav Dasb14f08a2019-02-22 16:34:15 -0800458 private void cancelDhcpPacketsFromConnectPoint(ConnectPoint cp,
459 Optional<PacketPriority> priority) {
Amit Ghosh83c8c892017-11-09 11:08:27 +0000460 TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
461 .matchEthType(Ethernet.TYPE_IPV4)
462 .matchInPort(cp.port())
463 .matchIPProtocol(IPv4.PROTOCOL_UDP)
464 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_SERVER_PORT));
465 packetService.cancelPackets(selectorServer.build(),
Saurav Dasb14f08a2019-02-22 16:34:15 -0800466 priority.isPresent() ? priority.get() : PacketPriority.CONTROL,
467 appId, Optional.of(cp.deviceId()));
Amit Ghosh83c8c892017-11-09 11:08:27 +0000468 }
469
Amit Ghosha17354e2017-08-23 12:56:04 +0100470 public static Map<String, DhcpAllocationInfo> allocationMap() {
471 return allocationMap;
472 }
473
Amit Ghosh47243cb2017-07-26 05:08:53 +0100474 private SubscriberAndDeviceInformation getDevice(PacketContext context) {
475 String serialNo = deviceService.getDevice(context.inPacket().
476 receivedFrom().deviceId()).serialNumber();
477
478 return subsService.get(serialNo);
479 }
480
481 private SubscriberAndDeviceInformation getDevice(ConnectPoint cp) {
482 String serialNo = deviceService.getDevice(cp.deviceId()).
483 serialNumber();
484
485 return subsService.get(serialNo);
486 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100487
488 private MacAddress relayAgentMacAddress(PacketContext context) {
489
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000490 SubscriberAndDeviceInformation device = this.getDevice(context);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100491 if (device == null) {
492 log.warn("Device not found for {}", context.inPacket().
493 receivedFrom());
494 return null;
495 }
496
497 return device.hardwareIdentifier();
498 }
499
500 private String nasPortId(PacketContext context) {
Amit Ghosh8951f042017-08-10 13:48:10 +0100501 return nasPortId(context.inPacket().receivedFrom());
502 }
503
504 private String nasPortId(ConnectPoint cp) {
505 Port p = deviceService.getPort(cp);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100506 return p.annotations().value(AnnotationKeys.PORT_NAME);
507 }
508
509 private SubscriberAndDeviceInformation getSubscriber(PacketContext context) {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100510 return subsService.get(nasPortId(context));
511 }
512
513 private VlanId cTag(PacketContext context) {
514 SubscriberAndDeviceInformation sub = getSubscriber(context);
515 if (sub == null) {
516 log.warn("Subscriber info not found for {}", context.inPacket().
517 receivedFrom());
518 return VlanId.NONE;
519 }
520 return sub.cTag();
521 }
522
Amit Ghosh8951f042017-08-10 13:48:10 +0100523 private VlanId cTag(ConnectPoint cp) {
524 String portId = nasPortId(cp);
525 SubscriberAndDeviceInformation sub = subsService.get(portId);
526 if (sub == null) {
527 log.warn("Subscriber info not found for {} looking for C-TAG", cp);
528 return VlanId.NONE;
529 }
530 return sub.cTag();
531 }
532
533 private VlanId sTag(ConnectPoint cp) {
534 String portId = nasPortId(cp);
535 SubscriberAndDeviceInformation sub = subsService.get(portId);
536 if (sub == null) {
537 log.warn("Subscriber info not found for {} looking for S-TAG", cp);
538 return VlanId.NONE;
539 }
540 return sub.sTag();
541 }
542
Amit Ghosh47243cb2017-07-26 05:08:53 +0100543 private VlanId sTag(PacketContext context) {
544 SubscriberAndDeviceInformation sub = getSubscriber(context);
545 if (sub == null) {
546 log.warn("Subscriber info not found for {}", context.inPacket().
547 receivedFrom());
548 return VlanId.NONE;
549 }
550 return sub.sTag();
551 }
552
553 private class DhcpRelayPacketProcessor implements PacketProcessor {
554
555 @Override
556 public void process(PacketContext context) {
557 if (!configured()) {
558 log.warn("Missing DHCP relay config. Abort packet processing");
559 return;
560 }
561
562 // process the packet and get the payload
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530563 Ethernet packet = context.inPacket().parsed();
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000564
Amit Ghosh47243cb2017-07-26 05:08:53 +0100565 if (packet == null) {
566 log.warn("Packet is null");
567 return;
568 }
569
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530570 if (packet.getEtherType() == Ethernet.TYPE_IPV4) {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100571 IPv4 ipv4Packet = (IPv4) packet.getPayload();
572
573 if (ipv4Packet.getProtocol() == IPv4.PROTOCOL_UDP) {
574 UDP udpPacket = (UDP) ipv4Packet.getPayload();
575 if (udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT ||
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000576 udpPacket.getSourcePort() == UDP.DHCP_SERVER_PORT) {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100577 DHCP dhcpPayload = (DHCP) udpPacket.getPayload();
578 //This packet is dhcp.
579 processDhcpPacket(context, packet, dhcpPayload);
580 }
581 }
582 }
583 }
584
585 //forward the packet to ConnectPoint where the DHCP server is attached.
Amit Ghosh83c8c892017-11-09 11:08:27 +0000586 private void forwardPacket(Ethernet packet, PacketContext context) {
587 ConnectPoint toSendTo = null;
Amit Ghosh47243cb2017-07-26 05:08:53 +0100588
Amit Ghosh83c8c892017-11-09 11:08:27 +0000589 if (!useOltUplink) {
590 toSendTo = dhcpServerConnectPoint.get();
591 } else {
592 toSendTo = getUplinkConnectPointOfOlt(context.inPacket().
593 receivedFrom().deviceId());
594 }
595
596 if (toSendTo != null) {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100597 TrafficTreatment t = DefaultTrafficTreatment.builder()
Amit Ghosh83c8c892017-11-09 11:08:27 +0000598 .setOutput(toSendTo.port()).build();
Amit Ghosh47243cb2017-07-26 05:08:53 +0100599 OutboundPacket o = new DefaultOutboundPacket(
Amit Ghosh83c8c892017-11-09 11:08:27 +0000600 toSendTo.deviceId(), t,
Amit Ghosh47243cb2017-07-26 05:08:53 +0100601 ByteBuffer.wrap(packet.serialize()));
602 if (log.isTraceEnabled()) {
Saurav Das15626a02018-09-27 18:36:45 -0700603 log.trace("Relaying packet to dhcp server at {} {}",
604 toSendTo, packet);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100605 }
606 packetService.emit(o);
607 } else {
Amit Ghosh83c8c892017-11-09 11:08:27 +0000608 log.error("No connect point to send msg to DHCP Server");
Amit Ghosh47243cb2017-07-26 05:08:53 +0100609 }
610 }
611
Amit Ghosha17354e2017-08-23 12:56:04 +0100612 // get the type of the DHCP packet
613 private DHCPPacketType getDhcpPacketType(DHCP dhcpPayload) {
614
Jonathan Hartedbf6422018-05-02 17:30:05 -0700615 for (DhcpOption option : dhcpPayload.getOptions()) {
Amit Ghosha17354e2017-08-23 12:56:04 +0100616 if (option.getCode() == OptionCode_MessageType.getValue()) {
617 byte[] data = option.getData();
618 return DHCPPacketType.getType(data[0]);
619 }
620 }
621 return null;
622 }
623
Amit Ghosh47243cb2017-07-26 05:08:53 +0100624 //process the dhcp packet before sending to server
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530625 private void processDhcpPacket(PacketContext context, Ethernet packet,
Amit Ghosh47243cb2017-07-26 05:08:53 +0100626 DHCP dhcpPayload) {
627 if (dhcpPayload == null) {
628 log.warn("DHCP payload is null");
629 return;
630 }
631
Amit Ghosha17354e2017-08-23 12:56:04 +0100632 DHCPPacketType incomingPacketType = getDhcpPacketType(dhcpPayload);
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000633
Saurav Das15626a02018-09-27 18:36:45 -0700634 log.info("Received DHCP Packet of type {} from {}",
635 incomingPacketType, context.inPacket().receivedFrom());
Amit Ghosh47243cb2017-07-26 05:08:53 +0100636
637 switch (incomingPacketType) {
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000638 case DHCPDISCOVER:
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530639 Ethernet ethernetPacketDiscover =
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000640 processDhcpPacketFromClient(context, packet);
641 if (ethernetPacketDiscover != null) {
Amit Ghosh83c8c892017-11-09 11:08:27 +0000642 forwardPacket(ethernetPacketDiscover, context);
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000643 }
644 break;
645 case DHCPOFFER:
646 //reply to dhcp client.
Saurav Das15626a02018-09-27 18:36:45 -0700647 Ethernet ethernetPacketOffer =
648 processDhcpPacketFromServer(context, packet);
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000649 if (ethernetPacketOffer != null) {
650 sendReply(ethernetPacketOffer, dhcpPayload);
651 }
652 break;
653 case DHCPREQUEST:
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530654 Ethernet ethernetPacketRequest =
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000655 processDhcpPacketFromClient(context, packet);
656 if (ethernetPacketRequest != null) {
Amit Ghosh83c8c892017-11-09 11:08:27 +0000657 forwardPacket(ethernetPacketRequest, context);
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000658 }
659 break;
660 case DHCPACK:
661 //reply to dhcp client.
Saurav Das15626a02018-09-27 18:36:45 -0700662 Ethernet ethernetPacketAck =
663 processDhcpPacketFromServer(context, packet);
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000664 if (ethernetPacketAck != null) {
665 sendReply(ethernetPacketAck, dhcpPayload);
666 }
667 break;
668 default:
669 break;
Amit Ghosh47243cb2017-07-26 05:08:53 +0100670 }
671 }
672
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530673 private Ethernet processDhcpPacketFromClient(PacketContext context,
674 Ethernet ethernetPacket) {
Saurav Das15626a02018-09-27 18:36:45 -0700675 if (log.isTraceEnabled()) {
676 log.trace("DHCP packet received from client at {} {}",
677 context.inPacket().receivedFrom(), ethernetPacket);
678 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100679
680 MacAddress relayAgentMac = relayAgentMacAddress(context);
681 if (relayAgentMac == null) {
682 log.warn("RelayAgent MAC not found ");
Amit Ghosh47243cb2017-07-26 05:08:53 +0100683 return null;
684 }
685
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530686 Ethernet etherReply = ethernetPacket;
Amit Ghosh47243cb2017-07-26 05:08:53 +0100687
688 IPv4 ipv4Packet = (IPv4) etherReply.getPayload();
689 UDP udpPacket = (UDP) ipv4Packet.getPayload();
690 DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
691
Amit Ghosha17354e2017-08-23 12:56:04 +0100692 if (enableDhcpBroadcastReplies) {
693 // We want the reply to come back as a L2 broadcast
694 dhcpPacket.setFlags((short) 0x8000);
695 }
696
Jonathan Hartc36c9552018-07-31 15:07:53 -0400697 MacAddress clientMac = MacAddress.valueOf(dhcpPacket.getClientHardwareAddress());
698 IpAddress clientIp = IpAddress.valueOf(dhcpPacket.getClientIPAddress());
Amit Ghosha17354e2017-08-23 12:56:04 +0100699
Jonathan Hartc36c9552018-07-31 15:07:53 -0400700 SubscriberAndDeviceInformation entry = getSubscriber(context);
701 if (entry == null) {
Saurav Das15626a02018-09-27 18:36:45 -0700702 log.warn("Dropping packet as subscriber entry is not available");
Jonathan Hartc36c9552018-07-31 15:07:53 -0400703 return null;
704 }
705
706 DhcpAllocationInfo info = new DhcpAllocationInfo(
707 context.inPacket().receivedFrom(), dhcpPacket.getPacketType(),
708 entry.nasPortId(), clientMac, clientIp);
709
710 allocationMap.put(entry.nasPortId(), info);
711
Saurav Das15626a02018-09-27 18:36:45 -0700712 post(new DhcpL2RelayEvent(DhcpL2RelayEvent.Type.UPDATED, info,
713 context.inPacket().receivedFrom()));
Amit Ghosha17354e2017-08-23 12:56:04 +0100714
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000715 if (option82) {
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000716 DHCP dhcpPacketWithOption82 = addOption82(dhcpPacket, entry);
717 udpPacket.setPayload(dhcpPacketWithOption82);
718 }
719
720 ipv4Packet.setPayload(udpPacket);
721 etherReply.setPayload(ipv4Packet);
Amit Ghosh83c8c892017-11-09 11:08:27 +0000722 if (modifyClientPktsSrcDstMac) {
723 etherReply.setSourceMACAddress(relayAgentMac);
724 etherReply.setDestinationMACAddress(dhcpConnectMac);
725 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100726
Amit Ghosh8951f042017-08-10 13:48:10 +0100727 etherReply.setPriorityCode(ethernetPacket.getPriorityCode());
Amit Ghosh47243cb2017-07-26 05:08:53 +0100728 etherReply.setVlanID(cTag(context).toShort());
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530729 etherReply.setQinQTPID(Ethernet.TYPE_VLAN);
730 etherReply.setQinQVID(sTag(context).toShort());
Saurav Das15626a02018-09-27 18:36:45 -0700731 log.info("Finished processing packet.. relaying to dhcpServer");
Amit Ghosh47243cb2017-07-26 05:08:53 +0100732 return etherReply;
733 }
734
735 //build the DHCP offer/ack with proper client port.
Saurav Das15626a02018-09-27 18:36:45 -0700736 private Ethernet processDhcpPacketFromServer(PacketContext context,
737 Ethernet ethernetPacket) {
738 if (log.isTraceEnabled()) {
739 log.trace("DHCP packet received from server at {} {}",
740 context.inPacket().receivedFrom(), ethernetPacket);
741 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100742 // get dhcp header.
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530743 Ethernet etherReply = (Ethernet) ethernetPacket.clone();
Amit Ghosh47243cb2017-07-26 05:08:53 +0100744 IPv4 ipv4Packet = (IPv4) etherReply.getPayload();
745 UDP udpPacket = (UDP) ipv4Packet.getPayload();
746 DHCP dhcpPayload = (DHCP) udpPacket.getPayload();
747
Amit Ghosh47243cb2017-07-26 05:08:53 +0100748 MacAddress dstMac = valueOf(dhcpPayload.getClientHardwareAddress());
Amit Ghosha17354e2017-08-23 12:56:04 +0100749 ConnectPoint subsCp = getConnectPointOfClient(dstMac);
Amit Ghosh2095dc62017-09-25 20:56:55 +0100750 // If we can't find the subscriber, can't process further
751 if (subsCp == null) {
752 return null;
753 }
Amit Ghosha17354e2017-08-23 12:56:04 +0100754 // if it's an ACK packet store the information for display purpose
755 if (getDhcpPacketType(dhcpPayload) == DHCPPacketType.DHCPACK) {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100756
Amit Ghosha17354e2017-08-23 12:56:04 +0100757 String portId = nasPortId(subsCp);
758 SubscriberAndDeviceInformation sub = subsService.get(portId);
759 if (sub != null) {
Jonathan Hartedbf6422018-05-02 17:30:05 -0700760 List<DhcpOption> options = dhcpPayload.getOptions();
761 List<DhcpOption> circuitIds = options.stream()
Amit Ghosha17354e2017-08-23 12:56:04 +0100762 .filter(option -> option.getCode() == DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue())
763 .collect(Collectors.toList());
764
765 String circuitId = "None";
766 if (circuitIds.size() == 1) {
Amit Ghosh2095dc62017-09-25 20:56:55 +0100767 byte[] array = circuitIds.get(0).getData();
768
769 try {
770 // we leave the first two bytes as they are the id and length
771 circuitId = new String(Arrays.copyOfRange(array, 2, array.length), "UTF-8");
772 } catch (Exception e) { }
Amit Ghosha17354e2017-08-23 12:56:04 +0100773 }
774
775 IpAddress ip = IpAddress.valueOf(dhcpPayload.getYourIPAddress());
776
777 //storeDHCPAllocationInfo
Jonathan Hartc36c9552018-07-31 15:07:53 -0400778 DhcpAllocationInfo info = new DhcpAllocationInfo(subsCp,
779 dhcpPayload.getPacketType(), circuitId, dstMac, ip);
Amit Ghosha17354e2017-08-23 12:56:04 +0100780
781 allocationMap.put(sub.nasPortId(), info);
Jonathan Hartc36c9552018-07-31 15:07:53 -0400782
783 post(new DhcpL2RelayEvent(DhcpL2RelayEvent.Type.UPDATED, info, subsCp));
Amit Ghosha17354e2017-08-23 12:56:04 +0100784 }
785 } // end storing of info
Amit Ghosh47243cb2017-07-26 05:08:53 +0100786
787 // we leave the srcMac from the original packet
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530788 etherReply.setDestinationMACAddress(dstMac);
789 etherReply.setQinQVID(sTag(subsCp).toShort());
Amit Ghosh8951f042017-08-10 13:48:10 +0100790 etherReply.setPriorityCode(ethernetPacket.getPriorityCode());
791 etherReply.setVlanID((cTag(subsCp).toShort()));
Amit Ghosh47243cb2017-07-26 05:08:53 +0100792
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000793 if (option82) {
794 udpPacket.setPayload(removeOption82(dhcpPayload));
795 } else {
796 udpPacket.setPayload(dhcpPayload);
797 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100798 ipv4Packet.setPayload(udpPacket);
799 etherReply.setPayload(ipv4Packet);
800
Saurav Das15626a02018-09-27 18:36:45 -0700801 log.info("Finished processing packet.. relaying to client");
Amit Ghosh47243cb2017-07-26 05:08:53 +0100802 return etherReply;
803 }
804
Amit Ghosha17354e2017-08-23 12:56:04 +0100805 /*
806 * Get ConnectPoint of the Client based on it's MAC address
807 */
808 private ConnectPoint getConnectPointOfClient(MacAddress dstMac) {
809 Set<Host> hosts = hostService.getHostsByMac(dstMac);
810 if (hosts == null || hosts.isEmpty()) {
811 log.warn("Cannot determine host for DHCP client: {}. Aborting "
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530812 + "relay for dhcp packet from server",
Amit Ghosha17354e2017-08-23 12:56:04 +0100813 dstMac);
814 return null;
815 }
816 for (Host h : hosts) {
817 // if more than one,
818 // find the connect point which has an valid entry in SADIS
819 ConnectPoint cp = new ConnectPoint(h.location().deviceId(),
820 h.location().port());
821
822 if (sTag(cp) != VlanId.NONE) {
823 return cp;
824 }
825 }
826
827 return null;
828 }
829
Amit Ghosh47243cb2017-07-26 05:08:53 +0100830 //send the response to the requester host.
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530831 private void sendReply(Ethernet ethPacket, DHCP dhcpPayload) {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100832 MacAddress descMac = valueOf(dhcpPayload.getClientHardwareAddress());
Amit Ghosha17354e2017-08-23 12:56:04 +0100833 ConnectPoint subCp = getConnectPointOfClient(descMac);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100834
835 // Send packet out to requester if the host information is available
Amit Ghosha17354e2017-08-23 12:56:04 +0100836 if (subCp != null) {
Saurav Das15626a02018-09-27 18:36:45 -0700837 log.info("Sending DHCP packet to client at {}", subCp);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100838 TrafficTreatment t = DefaultTrafficTreatment.builder()
Amit Ghosha17354e2017-08-23 12:56:04 +0100839 .setOutput(subCp.port()).build();
Amit Ghosh47243cb2017-07-26 05:08:53 +0100840 OutboundPacket o = new DefaultOutboundPacket(
Amit Ghosha17354e2017-08-23 12:56:04 +0100841 subCp.deviceId(), t, ByteBuffer.wrap(ethPacket.serialize()));
Amit Ghosh47243cb2017-07-26 05:08:53 +0100842 if (log.isTraceEnabled()) {
Saurav Das15626a02018-09-27 18:36:45 -0700843 log.trace("Relaying packet to dhcp client at {} {}", subCp,
844 ethPacket);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100845 }
846 packetService.emit(o);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100847 } else {
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000848 log.error("Dropping DHCP packet because can't find host for {}", descMac);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100849 }
850 }
851 }
852
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000853 private DHCP addOption82(DHCP dhcpPacket, SubscriberAndDeviceInformation entry) {
854 log.debug("option82data {} ", entry);
855
Jonathan Hartedbf6422018-05-02 17:30:05 -0700856 List<DhcpOption> options = Lists.newArrayList(dhcpPacket.getOptions());
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000857 DhcpOption82 option82 = new DhcpOption82();
858 option82.setAgentCircuitId(entry.circuitId());
859 option82.setAgentRemoteId(entry.remoteId());
Jonathan Hartedbf6422018-05-02 17:30:05 -0700860 DhcpOption option = new DhcpOption()
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530861 .setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue())
862 .setData(option82.toByteArray())
863 .setLength(option82.length());
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000864
865 options.add(options.size() - 1, option);
866 dhcpPacket.setOptions(options);
Amit Ghosh8951f042017-08-10 13:48:10 +0100867
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000868 return dhcpPacket;
869
870 }
871
872 private DHCP removeOption82(DHCP dhcpPacket) {
Jonathan Hartedbf6422018-05-02 17:30:05 -0700873 List<DhcpOption> options = dhcpPacket.getOptions();
874 List<DhcpOption> newoptions = options.stream()
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000875 .filter(option -> option.getCode() != DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue())
876 .collect(Collectors.toList());
877
878 return dhcpPacket.setOptions(newoptions);
879 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100880 /**
881 * Listener for network config events.
882 */
883 private class InternalConfigListener implements NetworkConfigListener {
884
885 @Override
886 public void event(NetworkConfigEvent event) {
887
888 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
889 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
890 event.configClass().equals(DhcpL2RelayConfig.class)) {
891 updateConfig();
892 log.info("Reconfigured");
893 }
894 }
895 }
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000896
Amit Ghosh8951f042017-08-10 13:48:10 +0100897 /**
898 * Handles Mastership changes for the devices which connect
899 * to the DHCP server.
900 */
901 private class InnerMastershipListener implements MastershipListener {
902 @Override
903 public void event(MastershipEvent event) {
Amit Ghosh83c8c892017-11-09 11:08:27 +0000904 if (!useOltUplink) {
905 if (dhcpServerConnectPoint.get() != null &&
906 dhcpServerConnectPoint.get().deviceId().
907 equals(event.subject())) {
908 log.trace("Mastership Event recevived for {}", event.subject());
909 // mastership of the device for our connect point has changed
910 // reselect
911 selectServerConnectPoint();
912 }
Amit Ghosh8951f042017-08-10 13:48:10 +0100913 }
914 }
915 }
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000916
Amit Ghosh8951f042017-08-10 13:48:10 +0100917 /**
918 * Handles Device status change for the devices which connect
919 * to the DHCP server.
920 */
921 private class InnerDeviceListener implements DeviceListener {
922 @Override
923 public void event(DeviceEvent event) {
Saurav Das15626a02018-09-27 18:36:45 -0700924 if (log.isTraceEnabled() &&
925 !event.type().equals(DeviceEvent.Type.PORT_STATS_UPDATED)) {
926 log.trace("Device Event received for {} event {}",
927 event.subject(), event.type());
928 }
Amit Ghosh83c8c892017-11-09 11:08:27 +0000929 if (!useOltUplink) {
930 if (dhcpServerConnectPoint.get() == null) {
931 switch (event.type()) {
932 case DEVICE_ADDED:
933 case DEVICE_AVAILABILITY_CHANGED:
Saurav Dasb14f08a2019-02-22 16:34:15 -0800934 // some device is available check if we can get a
935 // connect point we can use
936 addOrRemoveDhcpTrapFromServer(true);
Amit Ghosh83c8c892017-11-09 11:08:27 +0000937 break;
938 default:
939 break;
940 }
941 return;
Amit Ghosh8951f042017-08-10 13:48:10 +0100942 }
Amit Ghosh83c8c892017-11-09 11:08:27 +0000943 if (dhcpServerConnectPoint.get().deviceId().
944 equals(event.subject().id())) {
945 switch (event.type()) {
946 case DEVICE_AVAILABILITY_CHANGED:
947 case DEVICE_REMOVED:
948 case DEVICE_SUSPENDED:
949 // state of our device has changed, check if we need
Saurav Dasb14f08a2019-02-22 16:34:15 -0800950 // to re-select a connectpoint
951 addOrRemoveDhcpTrapFromServer(true);
Amit Ghosh83c8c892017-11-09 11:08:27 +0000952 break;
953 default:
954 break;
955 }
956 }
957 } else {
Amit Ghosh8951f042017-08-10 13:48:10 +0100958 switch (event.type()) {
Amit Ghosh83c8c892017-11-09 11:08:27 +0000959 case PORT_ADDED:
Saurav Dasb4e3e102018-10-02 15:31:17 -0700960 if (useOltUplink && isUplinkPortOfOlt(event.subject().id(), event.port())) {
Saurav Dasb14f08a2019-02-22 16:34:15 -0800961 requestDhcpPacketsFromConnectPoint(
962 new ConnectPoint(event.subject().id(), event.port().number()),
963 null);
Amit Ghosh83c8c892017-11-09 11:08:27 +0000964 }
Amit Ghosh8951f042017-08-10 13:48:10 +0100965 break;
966 default:
967 break;
968 }
969 }
970 }
971 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100972}