blob: 9f68554f2e54b85233d08f4950bb4d0a9cd22579 [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 */
16package org.opencord.dhcpl2relay;
17
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;
Saurav Dasb4e3e102018-10-02 15:31:17 -070043import org.onlab.packet.EthType.EtherType;
Deepa vaddireddy0060f532017-08-04 06:46:05 +000044import org.onlab.packet.Ethernet;
Amit Ghosh47243cb2017-07-26 05:08:53 +010045import org.onlab.packet.IPv4;
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +053046import org.onlab.packet.IpAddress;
Deepa vaddireddy0060f532017-08-04 06:46:05 +000047import org.onlab.packet.MacAddress;
Amit Ghosh47243cb2017-07-26 05:08:53 +010048import org.onlab.packet.TpPort;
49import org.onlab.packet.UDP;
50import org.onlab.packet.VlanId;
Jonathan Hartedbf6422018-05-02 17:30:05 -070051import org.onlab.packet.dhcp.DhcpOption;
Amit Ghosh47243cb2017-07-26 05:08:53 +010052import org.onlab.util.Tools;
53import org.onosproject.cfg.ComponentConfigService;
54import org.onosproject.core.ApplicationId;
55import org.onosproject.core.CoreService;
Jonathan Hartc36c9552018-07-31 15:07:53 -040056import org.onosproject.event.AbstractListenerManager;
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +053057import org.onosproject.mastership.MastershipEvent;
58import org.onosproject.mastership.MastershipListener;
59import org.onosproject.mastership.MastershipService;
Amit Ghosh47243cb2017-07-26 05:08:53 +010060import org.onosproject.net.AnnotationKeys;
61import org.onosproject.net.ConnectPoint;
Amit Ghosh83c8c892017-11-09 11:08:27 +000062import org.onosproject.net.Device;
63import org.onosproject.net.DeviceId;
Amit Ghosh47243cb2017-07-26 05:08:53 +010064import org.onosproject.net.Host;
65import org.onosproject.net.Port;
Amit Ghosh83c8c892017-11-09 11:08:27 +000066import org.onosproject.net.PortNumber;
Amit Ghosh47243cb2017-07-26 05:08:53 +010067import org.onosproject.net.config.ConfigFactory;
68import org.onosproject.net.config.NetworkConfigEvent;
69import org.onosproject.net.config.NetworkConfigListener;
70import org.onosproject.net.config.NetworkConfigRegistry;
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +053071import org.onosproject.net.device.DeviceEvent;
72import org.onosproject.net.device.DeviceListener;
Amit Ghosh47243cb2017-07-26 05:08:53 +010073import org.onosproject.net.device.DeviceService;
74import org.onosproject.net.flow.DefaultTrafficSelector;
75import org.onosproject.net.flow.DefaultTrafficTreatment;
76import org.onosproject.net.flow.TrafficSelector;
77import org.onosproject.net.flow.TrafficTreatment;
Saurav Dasb4e3e102018-10-02 15:31:17 -070078import org.onosproject.net.flowobjective.DefaultForwardingObjective;
79import org.onosproject.net.flowobjective.FlowObjectiveService;
80import org.onosproject.net.flowobjective.ForwardingObjective;
Amit Ghosh47243cb2017-07-26 05:08:53 +010081import org.onosproject.net.host.HostService;
82import org.onosproject.net.packet.DefaultOutboundPacket;
83import org.onosproject.net.packet.OutboundPacket;
84import org.onosproject.net.packet.PacketContext;
85import org.onosproject.net.packet.PacketPriority;
86import org.onosproject.net.packet.PacketProcessor;
87import org.onosproject.net.packet.PacketService;
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +053088import org.opencord.dhcpl2relay.packet.DhcpOption82;
Amit Ghosh47243cb2017-07-26 05:08:53 +010089import org.opencord.sadis.SubscriberAndDeviceInformation;
90import org.opencord.sadis.SubscriberAndDeviceInformationService;
Amit Ghosh47243cb2017-07-26 05:08:53 +010091import org.osgi.service.component.ComponentContext;
92import org.slf4j.Logger;
93import org.slf4j.LoggerFactory;
94
Saurav Das15626a02018-09-27 18:36:45 -070095import com.google.common.collect.ImmutableSet;
96import com.google.common.collect.Lists;
97import com.google.common.collect.Maps;
98import com.google.common.collect.Sets;
Amit Ghosh47243cb2017-07-26 05:08:53 +010099
100/**
101 * DHCP Relay Agent Application Component.
102 */
Jonathan Hartc36c9552018-07-31 15:07:53 -0400103@Service
Amit Ghosh47243cb2017-07-26 05:08:53 +0100104@Component(immediate = true)
Jonathan Hartc36c9552018-07-31 15:07:53 -0400105public class DhcpL2Relay
106 extends AbstractListenerManager<DhcpL2RelayEvent, DhcpL2RelayListener>
107 implements DhcpL2RelayService {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100108
109 public static final String DHCP_L2RELAY_APP = "org.opencord.dhcpl2relay";
Saurav Dasb4e3e102018-10-02 15:31:17 -0700110 private static final String HOST_LOC_PROVIDER =
111 "org.onosproject.provider.host.impl.HostLocationProvider";
Amit Ghosh47243cb2017-07-26 05:08:53 +0100112 private final Logger log = LoggerFactory.getLogger(getClass());
113 private final InternalConfigListener cfgListener =
114 new InternalConfigListener();
115
116 private final Set<ConfigFactory> factories = ImmutableSet.of(
117 new ConfigFactory<ApplicationId, DhcpL2RelayConfig>(APP_SUBJECT_FACTORY,
118 DhcpL2RelayConfig.class,
119 "dhcpl2relay") {
120 @Override
121 public DhcpL2RelayConfig createConfig() {
122 return new DhcpL2RelayConfig();
123 }
124 }
125 );
126
127 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
128 protected NetworkConfigRegistry cfgService;
129
130 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
131 protected CoreService coreService;
132
133 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
134 protected PacketService packetService;
135
136 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
137 protected HostService hostService;
138
139 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
140 protected ComponentConfigService componentConfigService;
141
142 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
143 protected SubscriberAndDeviceInformationService subsService;
144
145 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
146 protected DeviceService deviceService;
147
Amit Ghosh8951f042017-08-10 13:48:10 +0100148 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
149 protected MastershipService mastershipService;
150
Saurav Dasb4e3e102018-10-02 15:31:17 -0700151 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
152 protected FlowObjectiveService flowObjectiveService;
153
Amit Ghosh47243cb2017-07-26 05:08:53 +0100154 @Property(name = "option82", boolValue = true,
155 label = "Add option 82 to relayed packets")
156 protected boolean option82 = true;
157
Amit Ghosha17354e2017-08-23 12:56:04 +0100158 @Property(name = "enableDhcpBroadcastReplies", boolValue = false,
Amit Ghosh2095dc62017-09-25 20:56:55 +0100159 label = "Ask the DHCP Server to send back replies as L2 broadcast")
Amit Ghosha17354e2017-08-23 12:56:04 +0100160 protected boolean enableDhcpBroadcastReplies = false;
161
Amit Ghosh47243cb2017-07-26 05:08:53 +0100162 private DhcpRelayPacketProcessor dhcpRelayPacketProcessor =
163 new DhcpRelayPacketProcessor();
164
Amit Ghosh8951f042017-08-10 13:48:10 +0100165 private InnerMastershipListener changeListener = new InnerMastershipListener();
166 private InnerDeviceListener deviceListener = new InnerDeviceListener();
Amit Ghosh47243cb2017-07-26 05:08:53 +0100167
Amit Ghosh8951f042017-08-10 13:48:10 +0100168 // connect points to the DHCP server
169 Set<ConnectPoint> dhcpConnectPoints;
170 private AtomicReference<ConnectPoint> dhcpServerConnectPoint = new AtomicReference<>();
Amit Ghosh47243cb2017-07-26 05:08:53 +0100171 private MacAddress dhcpConnectMac = MacAddress.BROADCAST;
172 private ApplicationId appId;
173
Amit Ghosha17354e2017-08-23 12:56:04 +0100174 static Map<String, DhcpAllocationInfo> allocationMap = Maps.newConcurrentMap();
Amit Ghosh83c8c892017-11-09 11:08:27 +0000175 private boolean modifyClientPktsSrcDstMac = false;
176 //Whether to use the uplink port of the OLTs to send/receive messages to the DHCP server
177 private boolean useOltUplink = false;
Amit Ghosha17354e2017-08-23 12:56:04 +0100178
Amit Ghosh47243cb2017-07-26 05:08:53 +0100179 @Activate
180 protected void activate(ComponentContext context) {
181 //start the dhcp relay agent
182 appId = coreService.registerApplication(DHCP_L2RELAY_APP);
Saurav Dasb4e3e102018-10-02 15:31:17 -0700183 // ensure that host-learning via dhcp includes IP addresses
184 componentConfigService.preSetProperty(HOST_LOC_PROVIDER,
185 "useDhcp", Boolean.TRUE.toString());
Amit Ghosh47243cb2017-07-26 05:08:53 +0100186 componentConfigService.registerProperties(getClass());
Jonathan Hartc36c9552018-07-31 15:07:53 -0400187 eventDispatcher.addSink(DhcpL2RelayEvent.class, listenerRegistry);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100188
189 cfgService.addListener(cfgListener);
Amit Ghosh8951f042017-08-10 13:48:10 +0100190 mastershipService.addListener(changeListener);
191 deviceService.addListener(deviceListener);
192
Amit Ghosh47243cb2017-07-26 05:08:53 +0100193 factories.forEach(cfgService::registerConfigFactory);
194 //update the dhcp server configuration.
195 updateConfig();
196 //add the packet services.
197 packetService.addProcessor(dhcpRelayPacketProcessor,
198 PacketProcessor.director(0));
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000199 if (context != null) {
200 modified(context);
201 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100202
203 log.info("DHCP-L2-RELAY Started");
204 }
205
206 @Deactivate
207 protected void deactivate() {
208 cfgService.removeListener(cfgListener);
209 factories.forEach(cfgService::unregisterConfigFactory);
210 packetService.removeProcessor(dhcpRelayPacketProcessor);
Saurav Dasb4e3e102018-10-02 15:31:17 -0700211 cancelDhcpPktsFromServer();
Amit Ghosh47243cb2017-07-26 05:08:53 +0100212
213 componentConfigService.unregisterProperties(getClass(), false);
Deepa Vaddireddy77a6ac72017-09-20 20:36:52 +0530214 deviceService.removeListener(deviceListener);
215 mastershipService.removeListener(changeListener);
Jonathan Hartc36c9552018-07-31 15:07:53 -0400216 eventDispatcher.removeSink(DhcpL2RelayEvent.class);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100217 log.info("DHCP-L2-RELAY Stopped");
218 }
219
220 @Modified
221 protected void modified(ComponentContext context) {
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000222
Amit Ghosh47243cb2017-07-26 05:08:53 +0100223 Dictionary<?, ?> properties = context.getProperties();
224
225 Boolean o = Tools.isPropertyEnabled(properties, "option82");
226 if (o != null) {
227 option82 = o;
228 }
Amit Ghosh2095dc62017-09-25 20:56:55 +0100229
230 o = Tools.isPropertyEnabled(properties, "enableDhcpBroadcastReplies");
231 if (o != null) {
232 enableDhcpBroadcastReplies = o;
233 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100234 }
235
236 /**
237 * Checks if this app has been configured.
238 *
239 * @return true if all information we need have been initialized
240 */
241 private boolean configured() {
Amit Ghosh83c8c892017-11-09 11:08:27 +0000242 if (!useOltUplink) {
243 return dhcpServerConnectPoint.get() != null;
244 }
245 return true;
Amit Ghosh47243cb2017-07-26 05:08:53 +0100246 }
247
Amit Ghosh8951f042017-08-10 13:48:10 +0100248 /**
249 * Selects a connect point through an available device for which it is the master.
250 */
251 private void selectServerConnectPoint() {
252 synchronized (this) {
253 dhcpServerConnectPoint.set(null);
254 if (dhcpConnectPoints != null) {
255 // find a connect point through a device for which we are master
256 for (ConnectPoint cp: dhcpConnectPoints) {
257 if (mastershipService.isLocalMaster(cp.deviceId())) {
258 if (deviceService.isAvailable(cp.deviceId())) {
259 dhcpServerConnectPoint.set(cp);
260 }
261 log.info("DHCP connectPoint selected is {}", cp);
262 break;
263 }
264 }
265 }
266
267 log.info("DHCP Server connectPoint is {}", dhcpServerConnectPoint.get());
268
269 if (dhcpServerConnectPoint.get() == null) {
270 log.error("Master of none, can't relay DHCP Message to server");
271 }
272 }
273 }
274
275 /**
276 * Updates the network configuration.
277 */
Amit Ghosh47243cb2017-07-26 05:08:53 +0100278 private void updateConfig() {
279 DhcpL2RelayConfig cfg = cfgService.getConfig(appId, DhcpL2RelayConfig.class);
280 if (cfg == null) {
281 log.warn("Dhcp Server info not available");
282 return;
283 }
Amit Ghosh8951f042017-08-10 13:48:10 +0100284
285 dhcpConnectPoints = Sets.newConcurrentHashSet(cfg.getDhcpServerConnectPoint());
Amit Ghosh83c8c892017-11-09 11:08:27 +0000286 modifyClientPktsSrcDstMac = cfg.getModifySrcDstMacAddresses();
Saurav Dasb4e3e102018-10-02 15:31:17 -0700287 boolean prevUseOltUplink = useOltUplink;
Amit Ghosh83c8c892017-11-09 11:08:27 +0000288 useOltUplink = cfg.getUseOltUplinkForServerPktInOut();
Amit Ghosh8951f042017-08-10 13:48:10 +0100289
Saurav Dasb4e3e102018-10-02 15:31:17 -0700290 if (useOltUplink) {
291 for (ConnectPoint cp : getUplinkPortsOfOlts()) {
292 log.debug("requestDhcpPackets: ConnectPoint: {}", cp);
293 requestDhcpPacketsFromConnectPoint(cp);
294 }
295 // check if previous config was different and so trap flows may
296 // need to be removed from other places
297 if (!prevUseOltUplink) {
298 if (dhcpServerConnectPoint.get() == null) {
299 log.warn("No dhcpServer connectPoint found .. cannot remove"
300 + " previously installed trap flows");
301 return;
302 }
303 // XXX change to use packet service when priority can be set
304 DefaultForwardingObjective.Builder bldr =
305 trapDhcpPktsFromServer(dhcpServerConnectPoint.get().deviceId(),
306 dhcpServerConnectPoint.get().port());
307 flowObjectiveService.forward(dhcpServerConnectPoint.get().deviceId(),
308 bldr.remove());
309 }
310
311 } else {
Amit Ghosh83c8c892017-11-09 11:08:27 +0000312 selectServerConnectPoint();
Saurav Dasb4e3e102018-10-02 15:31:17 -0700313 log.info("dhcp server connect point: " + dhcpServerConnectPoint);
314 // create flow to trap packets coming from the server to this connectpoint
315 // which is typically not on the OLT (otherwise use the OLT's uplink)
316 if (dhcpServerConnectPoint.get() == null) {
317 log.warn("No dhcpServer connectPoint found, cannot install dhcp"
318 + " trap flows");
319 return;
320 }
321 // XXX change to use packet service when priority can be set
322 DefaultForwardingObjective.Builder bldr =
323 trapDhcpPktsFromServer(dhcpServerConnectPoint.get().deviceId(),
324 dhcpServerConnectPoint.get().port());
325 flowObjectiveService.forward(dhcpServerConnectPoint.get().deviceId(),
326 bldr.add());
327 }
328 }
329
330 private void cancelDhcpPktsFromServer() {
331 if (useOltUplink) {
332 for (ConnectPoint cp : getUplinkPortsOfOlts()) {
333 log.debug("cancelDhcpPackets: ConnectPoint: {}", cp);
334 cancelDhcpPacketsFromConnectPoint(cp);
335 }
336 } else {
337 // delete flow to trap packets coming from the server to this connectpoint
338 // which is typically not on the OLT (otherwise use the OLT's uplink)
339 if (dhcpServerConnectPoint.get() == null) {
340 log.warn("No dhcpServer connectPoint found.. cannot remove dhcp"
341 + " trap flows");
342 return;
343 }
344 // XXX change to use packet service when priority can be set
345 DefaultForwardingObjective.Builder bldr =
346 trapDhcpPktsFromServer(dhcpServerConnectPoint.get().deviceId(),
347 dhcpServerConnectPoint.get().port());
348 flowObjectiveService.forward(dhcpServerConnectPoint.get().deviceId(),
349 bldr.remove());
Amit Ghosh83c8c892017-11-09 11:08:27 +0000350 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100351
Saurav Dasb4e3e102018-10-02 15:31:17 -0700352 }
353
354 private DefaultForwardingObjective.Builder trapDhcpPktsFromServer(DeviceId devId,
355 PortNumber port) {
356 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
357 .punt()
358 .wipeDeferred()
359 .build();
360 TrafficSelector downstream = DefaultTrafficSelector.builder()
361 .matchInPort(port)
362 .matchEthType(EtherType.IPV4.ethType().toShort())
363 .matchIPProtocol(IPv4.PROTOCOL_UDP)
364 .matchUdpSrc(TpPort.tpPort(67))
365 .matchUdpDst(TpPort.tpPort(68))
366 .build();
367
368 DefaultForwardingObjective.Builder bldr = DefaultForwardingObjective.builder()
369 .withPriority(61000) // XXX packet service does not allow setting this
370 .withSelector(downstream)
371 .fromApp(appId)
372 .withFlag(ForwardingObjective.Flag.VERSATILE)
373 .withTreatment(treatment)
374 .makePermanent();
375 return bldr;
Amit Ghosh47243cb2017-07-26 05:08:53 +0100376 }
377
378 /**
Amit Ghosh83c8c892017-11-09 11:08:27 +0000379 * Returns all the uplink ports of OLTs configured in SADIS.
380 * Only ports visible in ONOS and for which this instance is master
381 * are returned
382 */
383 private List<ConnectPoint> getUplinkPortsOfOlts() {
384 List<ConnectPoint> cps = new ArrayList<>();
385
386 // find all the olt devices and if their uplink ports are visible
387 Iterable<Device> devices = deviceService.getDevices();
388 for (Device d : devices) {
389 // check if this device is provisioned in Sadis
390
391 log.debug("getUplinkPortsOfOlts: Checking mastership of {}", d);
392 // do only for devices for which we are the master
393 if (!mastershipService.isLocalMaster(d.id())) {
394 continue;
395 }
396
397 String devSerialNo = d.serialNumber();
398 SubscriberAndDeviceInformation deviceInfo = subsService.get(devSerialNo);
399 log.debug("getUplinkPortsOfOlts: Found device: {}", deviceInfo);
400 if (deviceInfo != null) {
401 // check if the uplink port with that number is available on the device
402 PortNumber pNum = PortNumber.portNumber(deviceInfo.uplinkPort());
403 Port port = deviceService.getPort(d.id(), pNum);
404 log.debug("getUplinkPortsOfOlts: Found port: {}", port);
405 if (port != null) {
406 cps.add(new ConnectPoint(d.id(), pNum));
407 }
408 }
409 }
410 return cps;
411 }
412
413 /**
414 * Returns whether the passed port is the uplink port of the olt device.
415 */
416 private boolean isUplinkPortOfOlt(DeviceId dId, Port p) {
417 log.debug("isUplinkPortOfOlt: DeviceId: {} Port: {}", dId, p);
418 // do only for devices for which we are the master
419 if (!mastershipService.isLocalMaster(dId)) {
420 return false;
421 }
422
423 Device d = deviceService.getDevice(dId);
424 SubscriberAndDeviceInformation deviceInfo = subsService.get(d.serialNumber());
425
426 if (deviceInfo != null) {
427 return (deviceInfo.uplinkPort() == p.number().toLong());
428 }
429
430 return false;
431 }
432
433 /**
434 * Returns the connectPoint which is the uplink port of the OLT.
435 */
436 private ConnectPoint getUplinkConnectPointOfOlt(DeviceId dId) {
437
438 Device d = deviceService.getDevice(dId);
439 SubscriberAndDeviceInformation deviceInfo = subsService.get(d.serialNumber());
440 log.debug("getUplinkConnectPointOfOlt DeviceId: {} devInfo: {}", dId, deviceInfo);
441 if (deviceInfo != null) {
442 PortNumber pNum = PortNumber.portNumber(deviceInfo.uplinkPort());
443 Port port = deviceService.getPort(d.id(), pNum);
444 if (port != null) {
445 return new ConnectPoint(d.id(), pNum);
446 }
447 }
448
449 return null;
450 }
451
452 /**
453 * Request DHCP packet from particular connect point via PacketService.
454 */
455 private void requestDhcpPacketsFromConnectPoint(ConnectPoint cp) {
456 TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
457 .matchEthType(Ethernet.TYPE_IPV4)
458 .matchInPort(cp.port())
459 .matchIPProtocol(IPv4.PROTOCOL_UDP)
460 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_SERVER_PORT));
461 packetService.requestPackets(selectorServer.build(),
462 PacketPriority.CONTROL, appId, Optional.of(cp.deviceId()));
463 }
464
465 /**
466 * Cancel DHCP packet from particular connect point via PacketService.
467 */
468 private void cancelDhcpPacketsFromConnectPoint(ConnectPoint cp) {
469 TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
470 .matchEthType(Ethernet.TYPE_IPV4)
471 .matchInPort(cp.port())
472 .matchIPProtocol(IPv4.PROTOCOL_UDP)
473 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_SERVER_PORT));
474 packetService.cancelPackets(selectorServer.build(),
475 PacketPriority.CONTROL, appId, Optional.of(cp.deviceId()));
476 }
477
Amit Ghosha17354e2017-08-23 12:56:04 +0100478 public static Map<String, DhcpAllocationInfo> allocationMap() {
479 return allocationMap;
480 }
481
Amit Ghosh47243cb2017-07-26 05:08:53 +0100482 private SubscriberAndDeviceInformation getDevice(PacketContext context) {
483 String serialNo = deviceService.getDevice(context.inPacket().
484 receivedFrom().deviceId()).serialNumber();
485
486 return subsService.get(serialNo);
487 }
488
489 private SubscriberAndDeviceInformation getDevice(ConnectPoint cp) {
490 String serialNo = deviceService.getDevice(cp.deviceId()).
491 serialNumber();
492
493 return subsService.get(serialNo);
494 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100495
496 private MacAddress relayAgentMacAddress(PacketContext context) {
497
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000498 SubscriberAndDeviceInformation device = this.getDevice(context);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100499 if (device == null) {
500 log.warn("Device not found for {}", context.inPacket().
501 receivedFrom());
502 return null;
503 }
504
505 return device.hardwareIdentifier();
506 }
507
508 private String nasPortId(PacketContext context) {
Amit Ghosh8951f042017-08-10 13:48:10 +0100509 return nasPortId(context.inPacket().receivedFrom());
510 }
511
512 private String nasPortId(ConnectPoint cp) {
513 Port p = deviceService.getPort(cp);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100514 return p.annotations().value(AnnotationKeys.PORT_NAME);
515 }
516
517 private SubscriberAndDeviceInformation getSubscriber(PacketContext context) {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100518 return subsService.get(nasPortId(context));
519 }
520
521 private VlanId cTag(PacketContext context) {
522 SubscriberAndDeviceInformation sub = getSubscriber(context);
523 if (sub == null) {
524 log.warn("Subscriber info not found for {}", context.inPacket().
525 receivedFrom());
526 return VlanId.NONE;
527 }
528 return sub.cTag();
529 }
530
Amit Ghosh8951f042017-08-10 13:48:10 +0100531 private VlanId cTag(ConnectPoint cp) {
532 String portId = nasPortId(cp);
533 SubscriberAndDeviceInformation sub = subsService.get(portId);
534 if (sub == null) {
535 log.warn("Subscriber info not found for {} looking for C-TAG", cp);
536 return VlanId.NONE;
537 }
538 return sub.cTag();
539 }
540
541 private VlanId sTag(ConnectPoint cp) {
542 String portId = nasPortId(cp);
543 SubscriberAndDeviceInformation sub = subsService.get(portId);
544 if (sub == null) {
545 log.warn("Subscriber info not found for {} looking for S-TAG", cp);
546 return VlanId.NONE;
547 }
548 return sub.sTag();
549 }
550
Amit Ghosh47243cb2017-07-26 05:08:53 +0100551 private VlanId sTag(PacketContext context) {
552 SubscriberAndDeviceInformation sub = getSubscriber(context);
553 if (sub == null) {
554 log.warn("Subscriber info not found for {}", context.inPacket().
555 receivedFrom());
556 return VlanId.NONE;
557 }
558 return sub.sTag();
559 }
560
561 private class DhcpRelayPacketProcessor implements PacketProcessor {
562
563 @Override
564 public void process(PacketContext context) {
565 if (!configured()) {
566 log.warn("Missing DHCP relay config. Abort packet processing");
567 return;
568 }
569
570 // process the packet and get the payload
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530571 Ethernet packet = context.inPacket().parsed();
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000572
Amit Ghosh47243cb2017-07-26 05:08:53 +0100573 if (packet == null) {
574 log.warn("Packet is null");
575 return;
576 }
577
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530578 if (packet.getEtherType() == Ethernet.TYPE_IPV4) {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100579 IPv4 ipv4Packet = (IPv4) packet.getPayload();
580
581 if (ipv4Packet.getProtocol() == IPv4.PROTOCOL_UDP) {
582 UDP udpPacket = (UDP) ipv4Packet.getPayload();
583 if (udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT ||
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000584 udpPacket.getSourcePort() == UDP.DHCP_SERVER_PORT) {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100585 DHCP dhcpPayload = (DHCP) udpPacket.getPayload();
586 //This packet is dhcp.
587 processDhcpPacket(context, packet, dhcpPayload);
588 }
589 }
590 }
591 }
592
593 //forward the packet to ConnectPoint where the DHCP server is attached.
Amit Ghosh83c8c892017-11-09 11:08:27 +0000594 private void forwardPacket(Ethernet packet, PacketContext context) {
595 ConnectPoint toSendTo = null;
Amit Ghosh47243cb2017-07-26 05:08:53 +0100596
Amit Ghosh83c8c892017-11-09 11:08:27 +0000597 if (!useOltUplink) {
598 toSendTo = dhcpServerConnectPoint.get();
599 } else {
600 toSendTo = getUplinkConnectPointOfOlt(context.inPacket().
601 receivedFrom().deviceId());
602 }
603
604 if (toSendTo != null) {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100605 TrafficTreatment t = DefaultTrafficTreatment.builder()
Amit Ghosh83c8c892017-11-09 11:08:27 +0000606 .setOutput(toSendTo.port()).build();
Amit Ghosh47243cb2017-07-26 05:08:53 +0100607 OutboundPacket o = new DefaultOutboundPacket(
Amit Ghosh83c8c892017-11-09 11:08:27 +0000608 toSendTo.deviceId(), t,
Amit Ghosh47243cb2017-07-26 05:08:53 +0100609 ByteBuffer.wrap(packet.serialize()));
610 if (log.isTraceEnabled()) {
Saurav Das15626a02018-09-27 18:36:45 -0700611 log.trace("Relaying packet to dhcp server at {} {}",
612 toSendTo, packet);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100613 }
614 packetService.emit(o);
615 } else {
Amit Ghosh83c8c892017-11-09 11:08:27 +0000616 log.error("No connect point to send msg to DHCP Server");
Amit Ghosh47243cb2017-07-26 05:08:53 +0100617 }
618 }
619
Amit Ghosha17354e2017-08-23 12:56:04 +0100620 // get the type of the DHCP packet
621 private DHCPPacketType getDhcpPacketType(DHCP dhcpPayload) {
622
Jonathan Hartedbf6422018-05-02 17:30:05 -0700623 for (DhcpOption option : dhcpPayload.getOptions()) {
Amit Ghosha17354e2017-08-23 12:56:04 +0100624 if (option.getCode() == OptionCode_MessageType.getValue()) {
625 byte[] data = option.getData();
626 return DHCPPacketType.getType(data[0]);
627 }
628 }
629 return null;
630 }
631
Amit Ghosh47243cb2017-07-26 05:08:53 +0100632 //process the dhcp packet before sending to server
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530633 private void processDhcpPacket(PacketContext context, Ethernet packet,
Amit Ghosh47243cb2017-07-26 05:08:53 +0100634 DHCP dhcpPayload) {
635 if (dhcpPayload == null) {
636 log.warn("DHCP payload is null");
637 return;
638 }
639
Amit Ghosha17354e2017-08-23 12:56:04 +0100640 DHCPPacketType incomingPacketType = getDhcpPacketType(dhcpPayload);
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000641
Saurav Das15626a02018-09-27 18:36:45 -0700642 log.info("Received DHCP Packet of type {} from {}",
643 incomingPacketType, context.inPacket().receivedFrom());
Amit Ghosh47243cb2017-07-26 05:08:53 +0100644
645 switch (incomingPacketType) {
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000646 case DHCPDISCOVER:
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530647 Ethernet ethernetPacketDiscover =
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000648 processDhcpPacketFromClient(context, packet);
649 if (ethernetPacketDiscover != null) {
Amit Ghosh83c8c892017-11-09 11:08:27 +0000650 forwardPacket(ethernetPacketDiscover, context);
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000651 }
652 break;
653 case DHCPOFFER:
654 //reply to dhcp client.
Saurav Das15626a02018-09-27 18:36:45 -0700655 Ethernet ethernetPacketOffer =
656 processDhcpPacketFromServer(context, packet);
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000657 if (ethernetPacketOffer != null) {
658 sendReply(ethernetPacketOffer, dhcpPayload);
659 }
660 break;
661 case DHCPREQUEST:
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530662 Ethernet ethernetPacketRequest =
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000663 processDhcpPacketFromClient(context, packet);
664 if (ethernetPacketRequest != null) {
Amit Ghosh83c8c892017-11-09 11:08:27 +0000665 forwardPacket(ethernetPacketRequest, context);
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000666 }
667 break;
668 case DHCPACK:
669 //reply to dhcp client.
Saurav Das15626a02018-09-27 18:36:45 -0700670 Ethernet ethernetPacketAck =
671 processDhcpPacketFromServer(context, packet);
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000672 if (ethernetPacketAck != null) {
673 sendReply(ethernetPacketAck, dhcpPayload);
674 }
675 break;
676 default:
677 break;
Amit Ghosh47243cb2017-07-26 05:08:53 +0100678 }
679 }
680
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530681 private Ethernet processDhcpPacketFromClient(PacketContext context,
682 Ethernet ethernetPacket) {
Saurav Das15626a02018-09-27 18:36:45 -0700683 if (log.isTraceEnabled()) {
684 log.trace("DHCP packet received from client at {} {}",
685 context.inPacket().receivedFrom(), ethernetPacket);
686 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100687
688 MacAddress relayAgentMac = relayAgentMacAddress(context);
689 if (relayAgentMac == null) {
690 log.warn("RelayAgent MAC not found ");
Amit Ghosh47243cb2017-07-26 05:08:53 +0100691 return null;
692 }
693
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530694 Ethernet etherReply = ethernetPacket;
Amit Ghosh47243cb2017-07-26 05:08:53 +0100695
696 IPv4 ipv4Packet = (IPv4) etherReply.getPayload();
697 UDP udpPacket = (UDP) ipv4Packet.getPayload();
698 DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
699
Amit Ghosha17354e2017-08-23 12:56:04 +0100700 if (enableDhcpBroadcastReplies) {
701 // We want the reply to come back as a L2 broadcast
702 dhcpPacket.setFlags((short) 0x8000);
703 }
704
Jonathan Hartc36c9552018-07-31 15:07:53 -0400705 MacAddress clientMac = MacAddress.valueOf(dhcpPacket.getClientHardwareAddress());
706 IpAddress clientIp = IpAddress.valueOf(dhcpPacket.getClientIPAddress());
Amit Ghosha17354e2017-08-23 12:56:04 +0100707
Jonathan Hartc36c9552018-07-31 15:07:53 -0400708 SubscriberAndDeviceInformation entry = getSubscriber(context);
709 if (entry == null) {
Saurav Das15626a02018-09-27 18:36:45 -0700710 log.warn("Dropping packet as subscriber entry is not available");
Jonathan Hartc36c9552018-07-31 15:07:53 -0400711 return null;
712 }
713
714 DhcpAllocationInfo info = new DhcpAllocationInfo(
715 context.inPacket().receivedFrom(), dhcpPacket.getPacketType(),
716 entry.nasPortId(), clientMac, clientIp);
717
718 allocationMap.put(entry.nasPortId(), info);
719
Saurav Das15626a02018-09-27 18:36:45 -0700720 post(new DhcpL2RelayEvent(DhcpL2RelayEvent.Type.UPDATED, info,
721 context.inPacket().receivedFrom()));
Amit Ghosha17354e2017-08-23 12:56:04 +0100722
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000723 if (option82) {
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000724 DHCP dhcpPacketWithOption82 = addOption82(dhcpPacket, entry);
725 udpPacket.setPayload(dhcpPacketWithOption82);
726 }
727
728 ipv4Packet.setPayload(udpPacket);
729 etherReply.setPayload(ipv4Packet);
Amit Ghosh83c8c892017-11-09 11:08:27 +0000730 if (modifyClientPktsSrcDstMac) {
731 etherReply.setSourceMACAddress(relayAgentMac);
732 etherReply.setDestinationMACAddress(dhcpConnectMac);
733 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100734
Amit Ghosh8951f042017-08-10 13:48:10 +0100735 etherReply.setPriorityCode(ethernetPacket.getPriorityCode());
Amit Ghosh47243cb2017-07-26 05:08:53 +0100736 etherReply.setVlanID(cTag(context).toShort());
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530737 etherReply.setQinQTPID(Ethernet.TYPE_VLAN);
738 etherReply.setQinQVID(sTag(context).toShort());
Saurav Das15626a02018-09-27 18:36:45 -0700739 log.info("Finished processing packet.. relaying to dhcpServer");
Amit Ghosh47243cb2017-07-26 05:08:53 +0100740 return etherReply;
741 }
742
743 //build the DHCP offer/ack with proper client port.
Saurav Das15626a02018-09-27 18:36:45 -0700744 private Ethernet processDhcpPacketFromServer(PacketContext context,
745 Ethernet ethernetPacket) {
746 if (log.isTraceEnabled()) {
747 log.trace("DHCP packet received from server at {} {}",
748 context.inPacket().receivedFrom(), ethernetPacket);
749 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100750 // get dhcp header.
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530751 Ethernet etherReply = (Ethernet) ethernetPacket.clone();
Amit Ghosh47243cb2017-07-26 05:08:53 +0100752 IPv4 ipv4Packet = (IPv4) etherReply.getPayload();
753 UDP udpPacket = (UDP) ipv4Packet.getPayload();
754 DHCP dhcpPayload = (DHCP) udpPacket.getPayload();
755
Amit Ghosh47243cb2017-07-26 05:08:53 +0100756 MacAddress dstMac = valueOf(dhcpPayload.getClientHardwareAddress());
Amit Ghosha17354e2017-08-23 12:56:04 +0100757 ConnectPoint subsCp = getConnectPointOfClient(dstMac);
Amit Ghosh2095dc62017-09-25 20:56:55 +0100758 // If we can't find the subscriber, can't process further
759 if (subsCp == null) {
760 return null;
761 }
Amit Ghosha17354e2017-08-23 12:56:04 +0100762 // if it's an ACK packet store the information for display purpose
763 if (getDhcpPacketType(dhcpPayload) == DHCPPacketType.DHCPACK) {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100764
Amit Ghosha17354e2017-08-23 12:56:04 +0100765 String portId = nasPortId(subsCp);
766 SubscriberAndDeviceInformation sub = subsService.get(portId);
767 if (sub != null) {
Jonathan Hartedbf6422018-05-02 17:30:05 -0700768 List<DhcpOption> options = dhcpPayload.getOptions();
769 List<DhcpOption> circuitIds = options.stream()
Amit Ghosha17354e2017-08-23 12:56:04 +0100770 .filter(option -> option.getCode() == DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue())
771 .collect(Collectors.toList());
772
773 String circuitId = "None";
774 if (circuitIds.size() == 1) {
Amit Ghosh2095dc62017-09-25 20:56:55 +0100775 byte[] array = circuitIds.get(0).getData();
776
777 try {
778 // we leave the first two bytes as they are the id and length
779 circuitId = new String(Arrays.copyOfRange(array, 2, array.length), "UTF-8");
780 } catch (Exception e) { }
Amit Ghosha17354e2017-08-23 12:56:04 +0100781 }
782
783 IpAddress ip = IpAddress.valueOf(dhcpPayload.getYourIPAddress());
784
785 //storeDHCPAllocationInfo
Jonathan Hartc36c9552018-07-31 15:07:53 -0400786 DhcpAllocationInfo info = new DhcpAllocationInfo(subsCp,
787 dhcpPayload.getPacketType(), circuitId, dstMac, ip);
Amit Ghosha17354e2017-08-23 12:56:04 +0100788
789 allocationMap.put(sub.nasPortId(), info);
Jonathan Hartc36c9552018-07-31 15:07:53 -0400790
791 post(new DhcpL2RelayEvent(DhcpL2RelayEvent.Type.UPDATED, info, subsCp));
Amit Ghosha17354e2017-08-23 12:56:04 +0100792 }
793 } // end storing of info
Amit Ghosh47243cb2017-07-26 05:08:53 +0100794
795 // we leave the srcMac from the original packet
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530796 etherReply.setDestinationMACAddress(dstMac);
797 etherReply.setQinQVID(sTag(subsCp).toShort());
Amit Ghosh8951f042017-08-10 13:48:10 +0100798 etherReply.setPriorityCode(ethernetPacket.getPriorityCode());
799 etherReply.setVlanID((cTag(subsCp).toShort()));
Amit Ghosh47243cb2017-07-26 05:08:53 +0100800
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000801 if (option82) {
802 udpPacket.setPayload(removeOption82(dhcpPayload));
803 } else {
804 udpPacket.setPayload(dhcpPayload);
805 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100806 ipv4Packet.setPayload(udpPacket);
807 etherReply.setPayload(ipv4Packet);
808
Saurav Das15626a02018-09-27 18:36:45 -0700809 log.info("Finished processing packet.. relaying to client");
Amit Ghosh47243cb2017-07-26 05:08:53 +0100810 return etherReply;
811 }
812
Amit Ghosha17354e2017-08-23 12:56:04 +0100813 /*
814 * Get ConnectPoint of the Client based on it's MAC address
815 */
816 private ConnectPoint getConnectPointOfClient(MacAddress dstMac) {
817 Set<Host> hosts = hostService.getHostsByMac(dstMac);
818 if (hosts == null || hosts.isEmpty()) {
819 log.warn("Cannot determine host for DHCP client: {}. Aborting "
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530820 + "relay for dhcp packet from server",
Amit Ghosha17354e2017-08-23 12:56:04 +0100821 dstMac);
822 return null;
823 }
824 for (Host h : hosts) {
825 // if more than one,
826 // find the connect point which has an valid entry in SADIS
827 ConnectPoint cp = new ConnectPoint(h.location().deviceId(),
828 h.location().port());
829
830 if (sTag(cp) != VlanId.NONE) {
831 return cp;
832 }
833 }
834
835 return null;
836 }
837
Amit Ghosh47243cb2017-07-26 05:08:53 +0100838 //send the response to the requester host.
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530839 private void sendReply(Ethernet ethPacket, DHCP dhcpPayload) {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100840 MacAddress descMac = valueOf(dhcpPayload.getClientHardwareAddress());
Amit Ghosha17354e2017-08-23 12:56:04 +0100841 ConnectPoint subCp = getConnectPointOfClient(descMac);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100842
843 // Send packet out to requester if the host information is available
Amit Ghosha17354e2017-08-23 12:56:04 +0100844 if (subCp != null) {
Saurav Das15626a02018-09-27 18:36:45 -0700845 log.info("Sending DHCP packet to client at {}", subCp);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100846 TrafficTreatment t = DefaultTrafficTreatment.builder()
Amit Ghosha17354e2017-08-23 12:56:04 +0100847 .setOutput(subCp.port()).build();
Amit Ghosh47243cb2017-07-26 05:08:53 +0100848 OutboundPacket o = new DefaultOutboundPacket(
Amit Ghosha17354e2017-08-23 12:56:04 +0100849 subCp.deviceId(), t, ByteBuffer.wrap(ethPacket.serialize()));
Amit Ghosh47243cb2017-07-26 05:08:53 +0100850 if (log.isTraceEnabled()) {
Saurav Das15626a02018-09-27 18:36:45 -0700851 log.trace("Relaying packet to dhcp client at {} {}", subCp,
852 ethPacket);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100853 }
854 packetService.emit(o);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100855 } else {
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000856 log.error("Dropping DHCP packet because can't find host for {}", descMac);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100857 }
858 }
859 }
860
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000861 private DHCP addOption82(DHCP dhcpPacket, SubscriberAndDeviceInformation entry) {
862 log.debug("option82data {} ", entry);
863
Jonathan Hartedbf6422018-05-02 17:30:05 -0700864 List<DhcpOption> options = Lists.newArrayList(dhcpPacket.getOptions());
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000865 DhcpOption82 option82 = new DhcpOption82();
866 option82.setAgentCircuitId(entry.circuitId());
867 option82.setAgentRemoteId(entry.remoteId());
Jonathan Hartedbf6422018-05-02 17:30:05 -0700868 DhcpOption option = new DhcpOption()
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530869 .setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue())
870 .setData(option82.toByteArray())
871 .setLength(option82.length());
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000872
873 options.add(options.size() - 1, option);
874 dhcpPacket.setOptions(options);
Amit Ghosh8951f042017-08-10 13:48:10 +0100875
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000876 return dhcpPacket;
877
878 }
879
880 private DHCP removeOption82(DHCP dhcpPacket) {
Jonathan Hartedbf6422018-05-02 17:30:05 -0700881 List<DhcpOption> options = dhcpPacket.getOptions();
882 List<DhcpOption> newoptions = options.stream()
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000883 .filter(option -> option.getCode() != DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue())
884 .collect(Collectors.toList());
885
886 return dhcpPacket.setOptions(newoptions);
887 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100888 /**
889 * Listener for network config events.
890 */
891 private class InternalConfigListener implements NetworkConfigListener {
892
893 @Override
894 public void event(NetworkConfigEvent event) {
895
896 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
897 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
898 event.configClass().equals(DhcpL2RelayConfig.class)) {
899 updateConfig();
900 log.info("Reconfigured");
901 }
902 }
903 }
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000904
Amit Ghosh8951f042017-08-10 13:48:10 +0100905 /**
906 * Handles Mastership changes for the devices which connect
907 * to the DHCP server.
908 */
909 private class InnerMastershipListener implements MastershipListener {
910 @Override
911 public void event(MastershipEvent event) {
Amit Ghosh83c8c892017-11-09 11:08:27 +0000912 if (!useOltUplink) {
913 if (dhcpServerConnectPoint.get() != null &&
914 dhcpServerConnectPoint.get().deviceId().
915 equals(event.subject())) {
916 log.trace("Mastership Event recevived for {}", event.subject());
917 // mastership of the device for our connect point has changed
918 // reselect
919 selectServerConnectPoint();
920 }
Amit Ghosh8951f042017-08-10 13:48:10 +0100921 }
922 }
923 }
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000924
Amit Ghosh8951f042017-08-10 13:48:10 +0100925 /**
926 * Handles Device status change for the devices which connect
927 * to the DHCP server.
928 */
929 private class InnerDeviceListener implements DeviceListener {
930 @Override
931 public void event(DeviceEvent event) {
Saurav Das15626a02018-09-27 18:36:45 -0700932 if (log.isTraceEnabled() &&
933 !event.type().equals(DeviceEvent.Type.PORT_STATS_UPDATED)) {
934 log.trace("Device Event received for {} event {}",
935 event.subject(), event.type());
936 }
Amit Ghosh83c8c892017-11-09 11:08:27 +0000937 if (!useOltUplink) {
938 if (dhcpServerConnectPoint.get() == null) {
939 switch (event.type()) {
940 case DEVICE_ADDED:
941 case DEVICE_AVAILABILITY_CHANGED:
942 // some device is available check if we can get one
943 selectServerConnectPoint();
944 break;
945 default:
946 break;
947 }
948 return;
Amit Ghosh8951f042017-08-10 13:48:10 +0100949 }
Amit Ghosh83c8c892017-11-09 11:08:27 +0000950 if (dhcpServerConnectPoint.get().deviceId().
951 equals(event.subject().id())) {
952 switch (event.type()) {
953 case DEVICE_AVAILABILITY_CHANGED:
954 case DEVICE_REMOVED:
955 case DEVICE_SUSPENDED:
956 // state of our device has changed, check if we need
957 // to re-select
958 selectServerConnectPoint();
959 break;
960 default:
961 break;
962 }
963 }
964 } else {
Amit Ghosh8951f042017-08-10 13:48:10 +0100965 switch (event.type()) {
Amit Ghosh83c8c892017-11-09 11:08:27 +0000966 case PORT_ADDED:
Saurav Dasb4e3e102018-10-02 15:31:17 -0700967 if (useOltUplink && isUplinkPortOfOlt(event.subject().id(), event.port())) {
Amit Ghosh83c8c892017-11-09 11:08:27 +0000968 requestDhcpPacketsFromConnectPoint(new ConnectPoint(event.subject().id(),
969 event.port().number()));
970 }
Amit Ghosh8951f042017-08-10 13:48:10 +0100971 break;
972 default:
973 break;
974 }
975 }
976 }
977 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100978}