blob: cdffe4ed0620fe073dc35c0e6b038192f5aaa7b3 [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
18import com.google.common.collect.ImmutableSet;
Deepa vaddireddy0060f532017-08-04 06:46:05 +000019import com.google.common.collect.Lists;
20
Amit Ghosh47243cb2017-07-26 05:08:53 +010021import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
24import org.apache.felix.scr.annotations.Modified;
25import org.apache.felix.scr.annotations.Property;
26import org.apache.felix.scr.annotations.Reference;
27import org.apache.felix.scr.annotations.ReferenceCardinality;
Deepa vaddireddy0060f532017-08-04 06:46:05 +000028import org.onlab.packet.DeserializationException;
Amit Ghosh47243cb2017-07-26 05:08:53 +010029import org.onlab.packet.DHCP;
30import org.onlab.packet.DHCPOption;
31import org.onlab.packet.DHCPPacketType;
Deepa vaddireddy0060f532017-08-04 06:46:05 +000032import org.onlab.packet.Ethernet;
Amit Ghosh47243cb2017-07-26 05:08:53 +010033import org.onlab.packet.IPv4;
Deepa vaddireddy0060f532017-08-04 06:46:05 +000034import org.onlab.packet.Ip4Address;
35import org.onlab.packet.MacAddress;
Amit Ghosh47243cb2017-07-26 05:08:53 +010036import org.onlab.packet.TpPort;
37import org.onlab.packet.UDP;
38import org.onlab.packet.VlanId;
Deepa vaddireddy0060f532017-08-04 06:46:05 +000039import org.opencord.dhcpl2relay.packet.DhcpEthernet;
40import org.opencord.dhcpl2relay.packet.DhcpOption82;
Amit Ghosh47243cb2017-07-26 05:08:53 +010041import org.onlab.util.Tools;
42import org.onosproject.cfg.ComponentConfigService;
43import org.onosproject.core.ApplicationId;
44import org.onosproject.core.CoreService;
45import org.onosproject.net.AnnotationKeys;
46import org.onosproject.net.ConnectPoint;
47import org.onosproject.net.Host;
48import org.onosproject.net.Port;
49import org.onosproject.net.config.ConfigFactory;
50import org.onosproject.net.config.NetworkConfigEvent;
51import org.onosproject.net.config.NetworkConfigListener;
52import org.onosproject.net.config.NetworkConfigRegistry;
53import org.onosproject.net.device.DeviceService;
54import org.onosproject.net.flow.DefaultTrafficSelector;
55import org.onosproject.net.flow.DefaultTrafficTreatment;
56import org.onosproject.net.flow.TrafficSelector;
57import org.onosproject.net.flow.TrafficTreatment;
58import org.onosproject.net.host.HostService;
59import org.onosproject.net.packet.DefaultOutboundPacket;
60import org.onosproject.net.packet.OutboundPacket;
61import org.onosproject.net.packet.PacketContext;
62import org.onosproject.net.packet.PacketPriority;
63import org.onosproject.net.packet.PacketProcessor;
64import org.onosproject.net.packet.PacketService;
65
66import org.opencord.sadis.SubscriberAndDeviceInformation;
67import org.opencord.sadis.SubscriberAndDeviceInformationService;
Amit Ghosh47243cb2017-07-26 05:08:53 +010068import org.osgi.service.component.ComponentContext;
69import org.slf4j.Logger;
70import org.slf4j.LoggerFactory;
71
72import java.nio.ByteBuffer;
73import java.util.Dictionary;
Deepa vaddireddy0060f532017-08-04 06:46:05 +000074import java.util.List;
Amit Ghosh47243cb2017-07-26 05:08:53 +010075import java.util.Optional;
Deepa vaddireddy0060f532017-08-04 06:46:05 +000076import java.util.Set;
77import java.util.stream.Collectors;
Amit Ghosh47243cb2017-07-26 05:08:53 +010078
79import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_MessageType;
80import static org.onlab.packet.MacAddress.valueOf;
81import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
82
83/**
84 * DHCP Relay Agent Application Component.
85 */
86@Component(immediate = true)
87public class DhcpL2Relay {
88
89 public static final String DHCP_L2RELAY_APP = "org.opencord.dhcpl2relay";
90 private final Logger log = LoggerFactory.getLogger(getClass());
91 private final InternalConfigListener cfgListener =
92 new InternalConfigListener();
93
94 private final Set<ConfigFactory> factories = ImmutableSet.of(
95 new ConfigFactory<ApplicationId, DhcpL2RelayConfig>(APP_SUBJECT_FACTORY,
96 DhcpL2RelayConfig.class,
97 "dhcpl2relay") {
98 @Override
99 public DhcpL2RelayConfig createConfig() {
100 return new DhcpL2RelayConfig();
101 }
102 }
103 );
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 protected NetworkConfigRegistry cfgService;
107
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected CoreService coreService;
110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
112 protected PacketService packetService;
113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected HostService hostService;
116
117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
118 protected ComponentConfigService componentConfigService;
119
120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
121 protected SubscriberAndDeviceInformationService subsService;
122
123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
124 protected DeviceService deviceService;
125
126 @Property(name = "option82", boolValue = true,
127 label = "Add option 82 to relayed packets")
128 protected boolean option82 = true;
129
130 private DhcpRelayPacketProcessor dhcpRelayPacketProcessor =
131 new DhcpRelayPacketProcessor();
132
133
134 private ConnectPoint dhcpServerConnectPoint = null;
135 private MacAddress dhcpConnectMac = MacAddress.BROADCAST;
136 private ApplicationId appId;
137
138 @Activate
139 protected void activate(ComponentContext context) {
140 //start the dhcp relay agent
141 appId = coreService.registerApplication(DHCP_L2RELAY_APP);
142 componentConfigService.registerProperties(getClass());
143
144 cfgService.addListener(cfgListener);
145 factories.forEach(cfgService::registerConfigFactory);
146 //update the dhcp server configuration.
147 updateConfig();
148 //add the packet services.
149 packetService.addProcessor(dhcpRelayPacketProcessor,
150 PacketProcessor.director(0));
151 requestDhcpPackets();
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000152 if (context != null) {
153 modified(context);
154 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100155
156 log.info("DHCP-L2-RELAY Started");
157 }
158
159 @Deactivate
160 protected void deactivate() {
161 cfgService.removeListener(cfgListener);
162 factories.forEach(cfgService::unregisterConfigFactory);
163 packetService.removeProcessor(dhcpRelayPacketProcessor);
164 cancelDhcpPackets();
165
166 componentConfigService.unregisterProperties(getClass(), false);
167
168 log.info("DHCP-L2-RELAY Stopped");
169 }
170
171 @Modified
172 protected void modified(ComponentContext context) {
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000173
Amit Ghosh47243cb2017-07-26 05:08:53 +0100174 Dictionary<?, ?> properties = context.getProperties();
175
176 Boolean o = Tools.isPropertyEnabled(properties, "option82");
177 if (o != null) {
178 option82 = o;
179 }
180 }
181
182 /**
183 * Checks if this app has been configured.
184 *
185 * @return true if all information we need have been initialized
186 */
187 private boolean configured() {
188 return dhcpServerConnectPoint != null;
189 }
190
191 private void updateConfig() {
192 DhcpL2RelayConfig cfg = cfgService.getConfig(appId, DhcpL2RelayConfig.class);
193 if (cfg == null) {
194 log.warn("Dhcp Server info not available");
195 return;
196 }
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000197 if (dhcpServerConnectPoint == null) {
198 dhcpServerConnectPoint = cfg.getDhcpServerConnectPoint();
199 requestDhcpPackets();
200 } else {
201 cancelDhcpPackets();
202 dhcpServerConnectPoint = cfg.getDhcpServerConnectPoint();
203 requestDhcpPackets();
204 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100205
Amit Ghosh47243cb2017-07-26 05:08:53 +0100206 log.info("dhcp server connect point: " + dhcpServerConnectPoint);
207 }
208
209 /**
210 * Request DHCP packet in via PacketService.
211 */
212 private void requestDhcpPackets() {
213 if (dhcpServerConnectPoint != null) {
214 TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
215 .matchEthType(Ethernet.TYPE_IPV4)
216 .matchIPProtocol(IPv4.PROTOCOL_UDP)
217 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_SERVER_PORT));
218 packetService.requestPackets(selectorServer.build(),
219 PacketPriority.CONTROL, appId,
220 Optional.of(dhcpServerConnectPoint.deviceId()));
221
222 TrafficSelector.Builder selectorClient = DefaultTrafficSelector.builder()
223 .matchEthType(Ethernet.TYPE_IPV4)
224 .matchIPProtocol(IPv4.PROTOCOL_UDP)
225 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT));
226 packetService.requestPackets(selectorClient.build(),
227 PacketPriority.CONTROL, appId,
228 Optional.of(dhcpServerConnectPoint.deviceId()));
229 }
230 }
231
232 /**
233 * Cancel requested DHCP packets in via packet service.
234 */
235 private void cancelDhcpPackets() {
236 if (dhcpServerConnectPoint != null) {
237 TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
238 .matchEthType(Ethernet.TYPE_IPV4)
239 .matchIPProtocol(IPv4.PROTOCOL_UDP)
240 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_SERVER_PORT));
241 packetService.cancelPackets(selectorServer.build(),
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000242 PacketPriority.CONTROL, appId, Optional.of(dhcpServerConnectPoint.deviceId()));
Amit Ghosh47243cb2017-07-26 05:08:53 +0100243
244 TrafficSelector.Builder selectorClient = DefaultTrafficSelector.builder()
245 .matchEthType(Ethernet.TYPE_IPV4)
246 .matchIPProtocol(IPv4.PROTOCOL_UDP)
247 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT));
248 packetService.cancelPackets(selectorClient.build(),
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000249 PacketPriority.CONTROL, appId, Optional.of(dhcpServerConnectPoint.deviceId()));
Amit Ghosh47243cb2017-07-26 05:08:53 +0100250 }
251 }
252
253 private SubscriberAndDeviceInformation getDevice(PacketContext context) {
254 String serialNo = deviceService.getDevice(context.inPacket().
255 receivedFrom().deviceId()).serialNumber();
256
257 return subsService.get(serialNo);
258 }
259
260 private SubscriberAndDeviceInformation getDevice(ConnectPoint cp) {
261 String serialNo = deviceService.getDevice(cp.deviceId()).
262 serialNumber();
263
264 return subsService.get(serialNo);
265 }
266 private Ip4Address relayAgentIPv4Address(ConnectPoint cp) {
267
268 SubscriberAndDeviceInformation device = getDevice(cp);
269 if (device == null) {
270 log.warn("Device not found for {}", cp);
271 return null;
272 }
273
274 return device.ipAddress();
275 }
276
277 private MacAddress relayAgentMacAddress(PacketContext context) {
278
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000279 SubscriberAndDeviceInformation device = this.getDevice(context);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100280 if (device == null) {
281 log.warn("Device not found for {}", context.inPacket().
282 receivedFrom());
283 return null;
284 }
285
286 return device.hardwareIdentifier();
287 }
288
289 private String nasPortId(PacketContext context) {
290 Port p = deviceService.getPort(context.inPacket().receivedFrom());
Amit Ghosh47243cb2017-07-26 05:08:53 +0100291 return p.annotations().value(AnnotationKeys.PORT_NAME);
292 }
293
294 private SubscriberAndDeviceInformation getSubscriber(PacketContext context) {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100295 return subsService.get(nasPortId(context));
296 }
297
298 private VlanId cTag(PacketContext context) {
299 SubscriberAndDeviceInformation sub = getSubscriber(context);
300 if (sub == null) {
301 log.warn("Subscriber info not found for {}", context.inPacket().
302 receivedFrom());
303 return VlanId.NONE;
304 }
305 return sub.cTag();
306 }
307
308 private VlanId sTag(PacketContext context) {
309 SubscriberAndDeviceInformation sub = getSubscriber(context);
310 if (sub == null) {
311 log.warn("Subscriber info not found for {}", context.inPacket().
312 receivedFrom());
313 return VlanId.NONE;
314 }
315 return sub.sTag();
316 }
317
318 private class DhcpRelayPacketProcessor implements PacketProcessor {
319
320 @Override
321 public void process(PacketContext context) {
322 if (!configured()) {
323 log.warn("Missing DHCP relay config. Abort packet processing");
324 return;
325 }
326
327 // process the packet and get the payload
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000328 DhcpEthernet packet = null;
329 ByteBuffer byteBuffer = context.inPacket().unparsed();
330 try {
331 packet = DhcpEthernet.deserializer().deserialize(byteBuffer.array(), 0, byteBuffer.array().length);
332 } catch (DeserializationException e) {
333 log.warn("Unable to deserialize packet");
334 }
335
Amit Ghosh47243cb2017-07-26 05:08:53 +0100336 if (packet == null) {
337 log.warn("Packet is null");
338 return;
339 }
340
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000341 log.debug("Got a packet ", packet);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100342
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000343 if (packet.getEtherType() == DhcpEthernet.TYPE_IPV4) {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100344 IPv4 ipv4Packet = (IPv4) packet.getPayload();
345
346 if (ipv4Packet.getProtocol() == IPv4.PROTOCOL_UDP) {
347 UDP udpPacket = (UDP) ipv4Packet.getPayload();
348 if (udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT ||
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000349 udpPacket.getSourcePort() == UDP.DHCP_SERVER_PORT) {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100350 DHCP dhcpPayload = (DHCP) udpPacket.getPayload();
351 //This packet is dhcp.
352 processDhcpPacket(context, packet, dhcpPayload);
353 }
354 }
355 }
356 }
357
358 //forward the packet to ConnectPoint where the DHCP server is attached.
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000359 private void forwardPacket(DhcpEthernet packet) {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100360
361 if (dhcpServerConnectPoint != null) {
362 TrafficTreatment t = DefaultTrafficTreatment.builder()
363 .setOutput(dhcpServerConnectPoint.port()).build();
364 OutboundPacket o = new DefaultOutboundPacket(
365 dhcpServerConnectPoint.deviceId(), t,
366 ByteBuffer.wrap(packet.serialize()));
367 if (log.isTraceEnabled()) {
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000368 log.trace("Relaying packet to dhcp server {} at {}",
369 packet, dhcpServerConnectPoint);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100370 }
371 packetService.emit(o);
372 } else {
373 log.warn("No dhcp server connect point");
374 }
375 }
376
377 //process the dhcp packet before sending to server
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000378 private void processDhcpPacket(PacketContext context, DhcpEthernet packet,
Amit Ghosh47243cb2017-07-26 05:08:53 +0100379 DHCP dhcpPayload) {
380 if (dhcpPayload == null) {
381 log.warn("DHCP payload is null");
382 return;
383 }
384
385 DHCPPacketType incomingPacketType = null;
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000386
Amit Ghosh47243cb2017-07-26 05:08:53 +0100387 for (DHCPOption option : dhcpPayload.getOptions()) {
388 if (option.getCode() == OptionCode_MessageType.getValue()) {
389 byte[] data = option.getData();
390 incomingPacketType = DHCPPacketType.getType(data[0]);
391 }
392 }
393 log.info("Received DHCP Packet of type {}", incomingPacketType);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100394
395 switch (incomingPacketType) {
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000396 case DHCPDISCOVER:
397 DhcpEthernet ethernetPacketDiscover =
398 processDhcpPacketFromClient(context, packet);
399 if (ethernetPacketDiscover != null) {
400 forwardPacket(ethernetPacketDiscover);
401 }
402 break;
403 case DHCPOFFER:
404 //reply to dhcp client.
405 DhcpEthernet ethernetPacketOffer = processDhcpPacketFromServer(packet);
406 if (ethernetPacketOffer != null) {
407 sendReply(ethernetPacketOffer, dhcpPayload);
408 }
409 break;
410 case DHCPREQUEST:
411 DhcpEthernet ethernetPacketRequest =
412 processDhcpPacketFromClient(context, packet);
413 if (ethernetPacketRequest != null) {
414 forwardPacket(ethernetPacketRequest);
415 }
416 break;
417 case DHCPACK:
418 //reply to dhcp client.
419 DhcpEthernet ethernetPacketAck = processDhcpPacketFromServer(packet);
420 if (ethernetPacketAck != null) {
421 sendReply(ethernetPacketAck, dhcpPayload);
422 }
423 break;
424 default:
425 break;
Amit Ghosh47243cb2017-07-26 05:08:53 +0100426 }
427 }
428
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000429 private DhcpEthernet processDhcpPacketFromClient(PacketContext context,
430 DhcpEthernet ethernetPacket) {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100431 log.info("Processing packet from client");
432
433 MacAddress relayAgentMac = relayAgentMacAddress(context);
434 if (relayAgentMac == null) {
435 log.warn("RelayAgent MAC not found ");
Amit Ghosh47243cb2017-07-26 05:08:53 +0100436 return null;
437 }
438
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000439 DhcpEthernet etherReply = ethernetPacket;
Amit Ghosh47243cb2017-07-26 05:08:53 +0100440
441 IPv4 ipv4Packet = (IPv4) etherReply.getPayload();
442 UDP udpPacket = (UDP) ipv4Packet.getPayload();
443 DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
444
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000445 if (option82) {
446 SubscriberAndDeviceInformation entry = getSubscriber(context);
447 if (entry == null) {
448 log.info("Dropping packet as subscriber entry is not available");
449 return null;
450 }
451
452 DHCP dhcpPacketWithOption82 = addOption82(dhcpPacket, entry);
453 udpPacket.setPayload(dhcpPacketWithOption82);
454 }
455
456 ipv4Packet.setPayload(udpPacket);
457 etherReply.setPayload(ipv4Packet);
458 etherReply.setSourceMacAddress(relayAgentMac);
459 etherReply.setDestinationMacAddress(dhcpConnectMac);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100460
461 etherReply.setVlanID(cTag(context).toShort());
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000462 etherReply.setQinQtpid(DhcpEthernet.TYPE_QINQ);
463 etherReply.setQinQVid(sTag(context).toShort());
Amit Ghosh47243cb2017-07-26 05:08:53 +0100464
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000465 log.info("Finished processing packet");
Amit Ghosh47243cb2017-07-26 05:08:53 +0100466 return etherReply;
467 }
468
469 //build the DHCP offer/ack with proper client port.
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000470 private DhcpEthernet processDhcpPacketFromServer(DhcpEthernet ethernetPacket) {
471 log.info("Processing DHCP packet from server");
Amit Ghosh47243cb2017-07-26 05:08:53 +0100472 // get dhcp header.
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000473 DhcpEthernet etherReply = (DhcpEthernet) ethernetPacket.clone();
Amit Ghosh47243cb2017-07-26 05:08:53 +0100474 IPv4 ipv4Packet = (IPv4) etherReply.getPayload();
475 UDP udpPacket = (UDP) ipv4Packet.getPayload();
476 DHCP dhcpPayload = (DHCP) udpPacket.getPayload();
477
478
479 MacAddress dstMac = valueOf(dhcpPayload.getClientHardwareAddress());
480 Set<Host> hosts = hostService.getHostsByMac(dstMac);
481 if (hosts == null || hosts.isEmpty()) {
482 log.warn("Cannot determine host for DHCP client: {}. Aborting "
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000483 + "relay for dhcp packet from server {}",
484 dstMac, ethernetPacket);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100485 return null;
486 } else if (hosts.size() > 1) {
487 // XXX redo to send reply to all hosts found
488 log.warn("Multiple hosts found for mac:{}. Picking one "
489 + "host out of {}", dstMac, hosts);
490 }
491 Host host = hosts.iterator().next();
492
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000493 etherReply.setDestinationMacAddress(dstMac);
494 etherReply.setQinQVid(Ethernet.VLAN_UNTAGGED);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100495 etherReply.setPriorityCode(ethernetPacket.getPriorityCode());
496 etherReply.setVlanID((short) 0);
497
498 // we leave the srcMac from the original packet
499
500 // figure out the relay agent IP corresponding to the original request
501 Ip4Address relayAgentIP = relayAgentIPv4Address(
502 new ConnectPoint(host.location().deviceId(),
503 host.location().port()));
504 if (relayAgentIP == null) {
505 log.warn("Cannot determine relay agent Ipv4 addr for host {}. "
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000506 + "Aborting relay for dhcp packet from server {}",
Amit Ghosh47243cb2017-07-26 05:08:53 +0100507 host, ethernetPacket);
508 return null;
509 }
510
511 ipv4Packet.setSourceAddress(relayAgentIP.toInt());
512 ipv4Packet.setDestinationAddress(dhcpPayload.getYourIPAddress());
513
514 udpPacket.setDestinationPort(UDP.DHCP_CLIENT_PORT);
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000515 if (option82) {
516 udpPacket.setPayload(removeOption82(dhcpPayload));
517 } else {
518 udpPacket.setPayload(dhcpPayload);
519 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100520 ipv4Packet.setPayload(udpPacket);
521 etherReply.setPayload(ipv4Packet);
522
523 log.info("Finished processing packet");
524 return etherReply;
525 }
526
527 //send the response to the requester host.
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000528 private void sendReply(DhcpEthernet ethPacket, DHCP dhcpPayload) {
Amit Ghosh47243cb2017-07-26 05:08:53 +0100529 MacAddress descMac = valueOf(dhcpPayload.getClientHardwareAddress());
530 Host host = hostService.getHostsByMac(descMac).stream().findFirst().orElse(null);
531
532 // Send packet out to requester if the host information is available
533 if (host != null) {
534 log.info("Sending DHCP packet to host: {}", host);
535 TrafficTreatment t = DefaultTrafficTreatment.builder()
536 .setOutput(host.location().port()).build();
537 OutboundPacket o = new DefaultOutboundPacket(
538 host.location().deviceId(), t, ByteBuffer.wrap(ethPacket.serialize()));
539 if (log.isTraceEnabled()) {
540 log.trace("Relaying packet to dhcp client {}", ethPacket);
541 }
542 packetService.emit(o);
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000543 log.info("DHCP Packet sent to {}", host.location());
Amit Ghosh47243cb2017-07-26 05:08:53 +0100544 } else {
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000545 log.error("Dropping DHCP packet because can't find host for {}", descMac);
Amit Ghosh47243cb2017-07-26 05:08:53 +0100546 }
547 }
548 }
549
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000550 private DHCP addOption82(DHCP dhcpPacket, SubscriberAndDeviceInformation entry) {
551 log.debug("option82data {} ", entry);
552
553 List<DHCPOption> options = Lists.newArrayList(dhcpPacket.getOptions());
554 DhcpOption82 option82 = new DhcpOption82();
555 option82.setAgentCircuitId(entry.circuitId());
556 option82.setAgentRemoteId(entry.remoteId());
557 DHCPOption option = new DHCPOption()
558 .setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue())
559 .setData(option82.toByteArray())
560 .setLength(option82.length());
561
562 options.add(options.size() - 1, option);
563 dhcpPacket.setOptions(options);
564 return dhcpPacket;
565
566 }
567
568 private DHCP removeOption82(DHCP dhcpPacket) {
569 List<DHCPOption> options = dhcpPacket.getOptions();
570 List<DHCPOption> newoptions = options.stream()
571 .filter(option -> option.getCode() != DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue())
572 .collect(Collectors.toList());
573
574 return dhcpPacket.setOptions(newoptions);
575 }
Amit Ghosh47243cb2017-07-26 05:08:53 +0100576 /**
577 * Listener for network config events.
578 */
579 private class InternalConfigListener implements NetworkConfigListener {
580
581 @Override
582 public void event(NetworkConfigEvent event) {
583
584 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
585 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
586 event.configClass().equals(DhcpL2RelayConfig.class)) {
587 updateConfig();
588 log.info("Reconfigured");
589 }
590 }
591 }
Deepa vaddireddy0060f532017-08-04 06:46:05 +0000592
593
594
Amit Ghosh47243cb2017-07-26 05:08:53 +0100595}