blob: 96d94a2b50b67669709d8b66e6e2dfbaf5efd909 [file] [log] [blame]
samanwita palf28207b2015-09-04 10:41:56 -07001/*
samanwita pala3d1d1c2015-09-25 11:50:15 -07002 * Copyright 2015 Open Networking Laboratory
samanwita palf28207b2015-09-04 10:41:56 -07003 *
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.onosproject.dhcp.impl;
17
18import com.google.common.collect.ImmutableSet;
19import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import org.apache.felix.scr.annotations.Service;
samanwita pal2a313402015-09-14 16:03:22 -070025import org.jboss.netty.util.Timeout;
26import org.jboss.netty.util.TimerTask;
samanwita palf28207b2015-09-04 10:41:56 -070027import org.onlab.packet.ARP;
28import org.onlab.packet.DHCP;
29import org.onlab.packet.DHCPOption;
samanwita pal8969cbe2015-09-04 13:31:30 -070030import org.onlab.packet.DHCPPacketType;
samanwita palf28207b2015-09-04 10:41:56 -070031import org.onlab.packet.Ethernet;
32import org.onlab.packet.IPv4;
33import org.onlab.packet.Ip4Address;
34import org.onlab.packet.IpAddress;
35import org.onlab.packet.MacAddress;
36import org.onlab.packet.TpPort;
37import org.onlab.packet.UDP;
38import org.onlab.packet.VlanId;
samanwita pal2a313402015-09-14 16:03:22 -070039import org.onlab.util.Timer;
samanwita palf28207b2015-09-04 10:41:56 -070040import org.onosproject.core.ApplicationId;
41import org.onosproject.core.CoreService;
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -070042import org.onosproject.dhcp.DhcpService;
43import org.onosproject.dhcp.DhcpStore;
44import org.onosproject.dhcp.IpAssignment;
samanwita palf28207b2015-09-04 10:41:56 -070045import org.onosproject.net.ConnectPoint;
46import org.onosproject.net.Host;
47import org.onosproject.net.HostId;
48import org.onosproject.net.HostLocation;
samanwita pal2a313402015-09-14 16:03:22 -070049import org.onosproject.net.config.ConfigFactory;
50import org.onosproject.net.config.NetworkConfigEvent;
51import org.onosproject.net.config.NetworkConfigListener;
52import org.onosproject.net.config.NetworkConfigRegistry;
samanwita palf28207b2015-09-04 10:41:56 -070053import org.onosproject.net.flow.DefaultTrafficSelector;
54import org.onosproject.net.flow.DefaultTrafficTreatment;
55import org.onosproject.net.flow.TrafficSelector;
56import org.onosproject.net.flow.TrafficTreatment;
57import org.onosproject.net.host.DefaultHostDescription;
58import org.onosproject.net.host.HostProvider;
59import org.onosproject.net.host.HostProviderRegistry;
60import org.onosproject.net.host.HostProviderService;
61import org.onosproject.net.packet.DefaultOutboundPacket;
62import org.onosproject.net.packet.PacketContext;
63import org.onosproject.net.packet.PacketPriority;
64import org.onosproject.net.packet.PacketProcessor;
65import org.onosproject.net.packet.PacketService;
66import org.onosproject.net.provider.AbstractProvider;
67import org.onosproject.net.provider.ProviderId;
68import org.slf4j.Logger;
69import org.slf4j.LoggerFactory;
70
71import java.nio.ByteBuffer;
72import java.util.ArrayList;
samanwita pal2a313402015-09-14 16:03:22 -070073import java.util.Date;
samanwita palf28207b2015-09-04 10:41:56 -070074import java.util.HashSet;
75import java.util.List;
76import java.util.Map;
samanwita pal7ccc2bc2015-09-14 19:53:15 -070077import java.util.Objects;
samanwita palf28207b2015-09-04 10:41:56 -070078import java.util.Set;
samanwita pal2a313402015-09-14 16:03:22 -070079import java.util.concurrent.TimeUnit;
samanwita palf28207b2015-09-04 10:41:56 -070080
81import static org.onlab.packet.MacAddress.valueOf;
82import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
83
84/**
85 * Skeletal ONOS DHCP Server application.
86 */
87@Component(immediate = true)
88@Service
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -070089public class DhcpManager implements DhcpService {
samanwita palf28207b2015-09-04 10:41:56 -070090
91 private static final ProviderId PID = new ProviderId("of", "org.onosproject.dhcp", true);
92 private final Logger log = LoggerFactory.getLogger(getClass());
93
Thomas Vachuska00090442015-09-11 18:08:04 -070094 private final InternalConfigListener cfgListener = new InternalConfigListener();
samanwita palf28207b2015-09-04 10:41:56 -070095
96 private final Set<ConfigFactory> factories = ImmutableSet.of(
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -070097 new ConfigFactory<ApplicationId, DhcpConfig>(APP_SUBJECT_FACTORY,
98 DhcpConfig.class,
samanwita palf28207b2015-09-04 10:41:56 -070099 "dhcp") {
100 @Override
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700101 public DhcpConfig createConfig() {
102 return new DhcpConfig();
samanwita palf28207b2015-09-04 10:41:56 -0700103 }
samanwita palf28207b2015-09-04 10:41:56 -0700104 }
105 );
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected NetworkConfigRegistry cfgService;
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected PacketService packetService;
111
112 private DHCPPacketProcessor processor = new DHCPPacketProcessor();
113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected CoreService coreService;
116
117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700118 protected DhcpStore dhcpStore;
samanwita palf28207b2015-09-04 10:41:56 -0700119
120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
121 protected HostProviderRegistry hostProviderRegistry;
122
123 protected HostProviderService hostProviderService;
124
samanwita pal2a313402015-09-14 16:03:22 -0700125 private final HostProvider hostProvider = new InternalHostProvider();
126
samanwita palf28207b2015-09-04 10:41:56 -0700127 private ApplicationId appId;
128
129 // Hardcoded values are default values.
130
samanwita pal2a313402015-09-14 16:03:22 -0700131 private static Ip4Address myIP = Ip4Address.valueOf("10.0.0.2");
samanwita palf28207b2015-09-04 10:41:56 -0700132
133 private static MacAddress myMAC = valueOf("4f:4f:4f:4f:4f:4f");
134
135 /**
136 * leaseTime - 10 mins or 600s.
137 * renewalTime - 5 mins or 300s.
138 * rebindingTime - 6 mins or 360s.
139 */
140
141 private static int leaseTime = 600;
142
143 private static int renewalTime = 300;
144
145 private static int rebindingTime = 360;
146
147 private static byte packetTTL = (byte) 127;
148
samanwita pal2a313402015-09-14 16:03:22 -0700149 private static Ip4Address subnetMask = Ip4Address.valueOf("255.0.0.0");
samanwita palf28207b2015-09-04 10:41:56 -0700150
samanwita pal2a313402015-09-14 16:03:22 -0700151 private static Ip4Address broadcastAddress = Ip4Address.valueOf("10.255.255.255");
samanwita palf28207b2015-09-04 10:41:56 -0700152
samanwita pal2a313402015-09-14 16:03:22 -0700153 private static Ip4Address routerAddress = Ip4Address.valueOf("10.0.0.2");
samanwita palf28207b2015-09-04 10:41:56 -0700154
samanwita pal2a313402015-09-14 16:03:22 -0700155 private static Ip4Address domainServer = Ip4Address.valueOf("10.0.0.2");
156
samanwita pala3d1d1c2015-09-25 11:50:15 -0700157 private static final Ip4Address IP_BROADCAST = Ip4Address.valueOf("255.255.255.255");
158
samanwita pal2a313402015-09-14 16:03:22 -0700159 protected Timeout timeout;
160
161 protected static int timerDelay = 2;
samanwita palf28207b2015-09-04 10:41:56 -0700162
163 @Activate
164 protected void activate() {
165 // start the dhcp server
166 appId = coreService.registerApplication("org.onosproject.dhcp");
167
168 cfgService.addListener(cfgListener);
169 factories.forEach(cfgService::registerConfigFactory);
Thomas Vachuska00090442015-09-11 18:08:04 -0700170 cfgListener.reconfigureNetwork(cfgService.getConfig(appId, DhcpConfig.class));
Thomas Vachuska00090442015-09-11 18:08:04 -0700171
samanwita palf28207b2015-09-04 10:41:56 -0700172 hostProviderService = hostProviderRegistry.register(hostProvider);
Thomas Vachuska2a645d42015-09-11 18:58:36 -0700173 packetService.addProcessor(processor, PacketProcessor.director(0));
samanwita palf28207b2015-09-04 10:41:56 -0700174 requestPackets();
samanwita pal2a313402015-09-14 16:03:22 -0700175 timeout = Timer.getTimer().newTimeout(new PurgeListTask(), timerDelay, TimeUnit.MINUTES);
samanwita palf28207b2015-09-04 10:41:56 -0700176 log.info("Started");
177 }
178
179 @Deactivate
180 protected void deactivate() {
181 cfgService.removeListener(cfgListener);
182 factories.forEach(cfgService::unregisterConfigFactory);
183 packetService.removeProcessor(processor);
184 hostProviderRegistry.unregister(hostProvider);
185 hostProviderService = null;
186 cancelPackets();
samanwita pal2a313402015-09-14 16:03:22 -0700187 timeout.cancel();
samanwita palf28207b2015-09-04 10:41:56 -0700188 log.info("Stopped");
189 }
190
191 /**
192 * Request packet in via PacketService.
193 */
194 private void requestPackets() {
195
196 TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
197 .matchEthType(Ethernet.TYPE_IPV4)
198 .matchIPProtocol(IPv4.PROTOCOL_UDP)
199 .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
200 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT));
201 packetService.requestPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
202
203 selectorServer = DefaultTrafficSelector.builder()
204 .matchEthType(Ethernet.TYPE_ARP);
205 packetService.requestPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
206 }
207
208 /**
209 * Cancel requested packets in via packet service.
210 */
211 private void cancelPackets() {
212 TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
213 .matchEthType(Ethernet.TYPE_IPV4)
214 .matchIPProtocol(IPv4.PROTOCOL_UDP)
215 .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
216 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT));
217 packetService.cancelPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
218
219 selectorServer = DefaultTrafficSelector.builder()
220 .matchEthType(Ethernet.TYPE_ARP);
221 packetService.cancelPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
222 }
223
224 @Override
samanwita pal2a313402015-09-14 16:03:22 -0700225 public Map<HostId, IpAssignment> listMapping() {
samanwita pal0bff4302015-09-15 13:37:00 -0700226 return dhcpStore.listAssignedMapping();
samanwita palf28207b2015-09-04 10:41:56 -0700227 }
228
229 @Override
230 public int getLeaseTime() {
231 return leaseTime;
232 }
233
234 @Override
235 public int getRenewalTime() {
236 return renewalTime;
237 }
238
239 @Override
240 public int getRebindingTime() {
241 return rebindingTime;
242 }
243
244 @Override
245 public boolean setStaticMapping(MacAddress macID, Ip4Address ipAddress) {
246 return dhcpStore.assignStaticIP(macID, ipAddress);
247 }
248
249 @Override
250 public boolean removeStaticMapping(MacAddress macID) {
251 return dhcpStore.removeStaticIP(macID);
252 }
253
254 @Override
255 public Iterable<Ip4Address> getAvailableIPs() {
256 return dhcpStore.getAvailableIPs();
257 }
258
259 private class DHCPPacketProcessor implements PacketProcessor {
260
261 /**
262 * Builds the DHCP Reply packet.
263 *
264 * @param packet the incoming Ethernet frame
265 * @param ipOffered the IP offered by the DHCP Server
266 * @param outgoingMessageType the message type of the outgoing packet
267 * @return the Ethernet reply frame
268 */
samanwita pal2a313402015-09-14 16:03:22 -0700269 private Ethernet buildReply(Ethernet packet, Ip4Address ipOffered, byte outgoingMessageType) {
samanwita palf28207b2015-09-04 10:41:56 -0700270
271 // Ethernet Frame.
272 Ethernet ethReply = new Ethernet();
273 ethReply.setSourceMACAddress(myMAC);
274 ethReply.setDestinationMACAddress(packet.getSourceMAC());
275 ethReply.setEtherType(Ethernet.TYPE_IPV4);
276 ethReply.setVlanID(packet.getVlanID());
277
278 // IP Packet
279 IPv4 ipv4Packet = (IPv4) packet.getPayload();
280 IPv4 ipv4Reply = new IPv4();
samanwita pal2a313402015-09-14 16:03:22 -0700281 ipv4Reply.setSourceAddress(myIP.toInt());
282 ipv4Reply.setDestinationAddress(ipOffered.toInt());
samanwita palf28207b2015-09-04 10:41:56 -0700283 ipv4Reply.setTtl(packetTTL);
284
285 // UDP Datagram.
286 UDP udpPacket = (UDP) ipv4Packet.getPayload();
287 UDP udpReply = new UDP();
288 udpReply.setSourcePort((byte) UDP.DHCP_SERVER_PORT);
289 udpReply.setDestinationPort((byte) UDP.DHCP_CLIENT_PORT);
290
291 // DHCP Payload.
292 DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
293 DHCP dhcpReply = new DHCP();
294 dhcpReply.setOpCode(DHCP.OPCODE_REPLY);
samanwita pala3d1d1c2015-09-25 11:50:15 -0700295 dhcpReply.setFlags(dhcpPacket.getFlags());
296 dhcpReply.setGatewayIPAddress(dhcpPacket.getGatewayIPAddress());
samanwita palf28207b2015-09-04 10:41:56 -0700297 dhcpReply.setClientHardwareAddress(dhcpPacket.getClientHardwareAddress());
samanwita pala3d1d1c2015-09-25 11:50:15 -0700298 dhcpReply.setTransactionId(dhcpPacket.getTransactionId());
299
300 if (outgoingMessageType != DHCPPacketType.DHCPNAK.getValue()) {
301 dhcpReply.setYourIPAddress(ipOffered.toInt());
302 dhcpReply.setServerIPAddress(myIP.toInt());
303 if (dhcpPacket.getGatewayIPAddress() == 0) {
304 ipv4Reply.setDestinationAddress(IP_BROADCAST.toInt());
305 }
306 }
samanwita palf28207b2015-09-04 10:41:56 -0700307 dhcpReply.setHardwareType(DHCP.HWTYPE_ETHERNET);
308 dhcpReply.setHardwareAddressLength((byte) 6);
309
310 // DHCP Options.
311 DHCPOption option = new DHCPOption();
312 List<DHCPOption> optionList = new ArrayList<>();
313
314 // DHCP Message Type.
315 option.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
316 option.setLength((byte) 1);
317 byte[] optionData = {outgoingMessageType};
318 option.setData(optionData);
319 optionList.add(option);
320
321 // DHCP Server Identifier.
322 option = new DHCPOption();
323 option.setCode(DHCP.DHCPOptionCode.OptionCode_DHCPServerIp.getValue());
324 option.setLength((byte) 4);
samanwita pal2a313402015-09-14 16:03:22 -0700325 option.setData(myIP.toOctets());
samanwita palf28207b2015-09-04 10:41:56 -0700326 optionList.add(option);
327
samanwita pala3d1d1c2015-09-25 11:50:15 -0700328 if (outgoingMessageType != DHCPPacketType.DHCPNAK.getValue()) {
samanwita palf28207b2015-09-04 10:41:56 -0700329
samanwita pala3d1d1c2015-09-25 11:50:15 -0700330 // IP Address Lease Time.
331 option = new DHCPOption();
332 option.setCode(DHCP.DHCPOptionCode.OptionCode_LeaseTime.getValue());
333 option.setLength((byte) 4);
334 option.setData(ByteBuffer.allocate(4).putInt(leaseTime).array());
335 optionList.add(option);
samanwita palf28207b2015-09-04 10:41:56 -0700336
samanwita pala3d1d1c2015-09-25 11:50:15 -0700337 // IP Address Renewal Time.
338 option = new DHCPOption();
339 option.setCode(DHCP.DHCPOptionCode.OptionCode_RenewalTime.getValue());
340 option.setLength((byte) 4);
341 option.setData(ByteBuffer.allocate(4).putInt(renewalTime).array());
342 optionList.add(option);
samanwita palf28207b2015-09-04 10:41:56 -0700343
samanwita pala3d1d1c2015-09-25 11:50:15 -0700344 // IP Address Rebinding Time.
345 option = new DHCPOption();
346 option.setCode(DHCP.DHCPOptionCode.OPtionCode_RebindingTime.getValue());
347 option.setLength((byte) 4);
348 option.setData(ByteBuffer.allocate(4).putInt(rebindingTime).array());
349 optionList.add(option);
samanwita palf28207b2015-09-04 10:41:56 -0700350
samanwita pala3d1d1c2015-09-25 11:50:15 -0700351 // Subnet Mask.
352 option = new DHCPOption();
353 option.setCode(DHCP.DHCPOptionCode.OptionCode_SubnetMask.getValue());
354 option.setLength((byte) 4);
355 option.setData(subnetMask.toOctets());
356 optionList.add(option);
samanwita palf28207b2015-09-04 10:41:56 -0700357
samanwita pala3d1d1c2015-09-25 11:50:15 -0700358 // Broadcast Address.
359 option = new DHCPOption();
360 option.setCode(DHCP.DHCPOptionCode.OptionCode_BroadcastAddress.getValue());
361 option.setLength((byte) 4);
362 option.setData(broadcastAddress.toOctets());
363 optionList.add(option);
samanwita palf28207b2015-09-04 10:41:56 -0700364
samanwita pala3d1d1c2015-09-25 11:50:15 -0700365 // Router Address.
366 option = new DHCPOption();
367 option.setCode(DHCP.DHCPOptionCode.OptionCode_RouterAddress.getValue());
368 option.setLength((byte) 4);
369 option.setData(routerAddress.toOctets());
370 optionList.add(option);
371
372 // DNS Server Address.
373 option = new DHCPOption();
374 option.setCode(DHCP.DHCPOptionCode.OptionCode_DomainServer.getValue());
375 option.setLength((byte) 4);
376 option.setData(domainServer.toOctets());
377 optionList.add(option);
378 }
samanwita palf28207b2015-09-04 10:41:56 -0700379
380 // End Option.
381 option = new DHCPOption();
382 option.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
383 option.setLength((byte) 1);
384 optionList.add(option);
385
386 dhcpReply.setOptions(optionList);
387
388 udpReply.setPayload(dhcpReply);
389 ipv4Reply.setPayload(udpReply);
390 ethReply.setPayload(ipv4Reply);
391
392 return ethReply;
393 }
394
395 /**
396 * Sends the Ethernet reply frame via the Packet Service.
397 *
398 * @param context the context of the incoming frame
399 * @param reply the Ethernet reply frame
400 */
401 private void sendReply(PacketContext context, Ethernet reply) {
402 if (reply != null) {
403 TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
404 ConnectPoint sourcePoint = context.inPacket().receivedFrom();
405 builder.setOutput(sourcePoint.port());
Thomas Vachuska00090442015-09-11 18:08:04 -0700406 context.block();
samanwita palf28207b2015-09-04 10:41:56 -0700407 packetService.emit(new DefaultOutboundPacket(sourcePoint.deviceId(),
samanwita pal8969cbe2015-09-04 13:31:30 -0700408 builder.build(), ByteBuffer.wrap(reply.serialize())));
samanwita palf28207b2015-09-04 10:41:56 -0700409 }
410 }
411
412 /**
413 * Processes the DHCP Payload and initiates a reply to the client.
414 *
415 * @param context context of the incoming message
416 * @param dhcpPayload the extracted DHCP payload
417 */
418 private void processDHCPPacket(PacketContext context, DHCP dhcpPayload) {
samanwita palf28207b2015-09-04 10:41:56 -0700419 Ethernet packet = context.inPacket().parsed();
420 boolean flagIfRequestedIP = false;
421 boolean flagIfServerIP = false;
422 Ip4Address requestedIP = Ip4Address.valueOf("0.0.0.0");
423 Ip4Address serverIP = Ip4Address.valueOf("0.0.0.0");
424
425 if (dhcpPayload != null) {
426
samanwita pal2a313402015-09-14 16:03:22 -0700427 DHCPPacketType incomingPacketType = DHCPPacketType.getType(0);
samanwita palf28207b2015-09-04 10:41:56 -0700428 for (DHCPOption option : dhcpPayload.getOptions()) {
429 if (option.getCode() == DHCP.DHCPOptionCode.OptionCode_MessageType.getValue()) {
430 byte[] data = option.getData();
samanwita pal2a313402015-09-14 16:03:22 -0700431 incomingPacketType = DHCPPacketType.getType(data[0]);
samanwita palf28207b2015-09-04 10:41:56 -0700432 }
433 if (option.getCode() == DHCP.DHCPOptionCode.OptionCode_RequestedIP.getValue()) {
434 byte[] data = option.getData();
435 requestedIP = Ip4Address.valueOf(data);
436 flagIfRequestedIP = true;
437 }
438 if (option.getCode() == DHCP.DHCPOptionCode.OptionCode_DHCPServerIp.getValue()) {
439 byte[] data = option.getData();
440 serverIP = Ip4Address.valueOf(data);
441 flagIfServerIP = true;
442 }
443 }
samanwita pal8969cbe2015-09-04 13:31:30 -0700444 DHCPPacketType outgoingPacketType;
samanwita palf28207b2015-09-04 10:41:56 -0700445 MacAddress clientMAC = new MacAddress(dhcpPayload.getClientHardwareAddress());
samanwita pal2a313402015-09-14 16:03:22 -0700446 VlanId vlanId = VlanId.vlanId(packet.getVlanID());
447 HostId hostId = HostId.hostId(clientMAC, vlanId);
samanwita palf28207b2015-09-04 10:41:56 -0700448
samanwita pal2a313402015-09-14 16:03:22 -0700449 if (incomingPacketType.getValue() == DHCPPacketType.DHCPDISCOVER.getValue()) {
samanwita palf28207b2015-09-04 10:41:56 -0700450
samanwita pal8969cbe2015-09-04 13:31:30 -0700451 outgoingPacketType = DHCPPacketType.DHCPOFFER;
samanwita pal2a313402015-09-14 16:03:22 -0700452 Ip4Address ipOffered = dhcpStore.suggestIP(hostId, requestedIP);
453 if (ipOffered != null) {
454 Ethernet ethReply = buildReply(packet, ipOffered,
455 (byte) outgoingPacketType.getValue());
456 sendReply(context, ethReply);
457 }
samanwita palf28207b2015-09-04 10:41:56 -0700458
samanwita pal2a313402015-09-14 16:03:22 -0700459 } else if (incomingPacketType.getValue() == DHCPPacketType.DHCPREQUEST.getValue()) {
samanwita palf28207b2015-09-04 10:41:56 -0700460
samanwita palf28207b2015-09-04 10:41:56 -0700461 if (flagIfServerIP && flagIfRequestedIP) {
462 // SELECTING state
samanwita pala3d1d1c2015-09-25 11:50:15 -0700463 if (myIP.equals(serverIP)) {
samanwita palf28207b2015-09-04 10:41:56 -0700464
samanwita pala3d1d1c2015-09-25 11:50:15 -0700465 if (dhcpStore.assignIP(hostId, requestedIP, leaseTime)) {
466 outgoingPacketType = DHCPPacketType.DHCPACK;
467 discoverHost(context, requestedIP);
468 } else {
469 outgoingPacketType = DHCPPacketType.DHCPNAK;
470 }
471 Ethernet ethReply = buildReply(packet, requestedIP, (byte) outgoingPacketType.getValue());
samanwita palf28207b2015-09-04 10:41:56 -0700472 sendReply(context, ethReply);
samanwita palf28207b2015-09-04 10:41:56 -0700473 }
474 } else if (flagIfRequestedIP) {
475 // INIT-REBOOT state
samanwita pal2a313402015-09-14 16:03:22 -0700476 if (dhcpStore.assignIP(hostId, requestedIP, leaseTime)) {
samanwita pala3d1d1c2015-09-25 11:50:15 -0700477 outgoingPacketType = DHCPPacketType.DHCPACK;
478 Ethernet ethReply = buildReply(packet, requestedIP, (byte) outgoingPacketType.getValue());
samanwita palf28207b2015-09-04 10:41:56 -0700479 sendReply(context, ethReply);
480 discoverHost(context, requestedIP);
481 }
samanwita pala3d1d1c2015-09-25 11:50:15 -0700482
samanwita palf28207b2015-09-04 10:41:56 -0700483 } else {
484 // RENEWING and REBINDING state
485 int ciaadr = dhcpPayload.getClientIPAddress();
486 if (ciaadr != 0) {
487 Ip4Address clientIaddr = Ip4Address.valueOf(ciaadr);
samanwita pal2a313402015-09-14 16:03:22 -0700488 if (dhcpStore.assignIP(hostId, clientIaddr, leaseTime)) {
samanwita pala3d1d1c2015-09-25 11:50:15 -0700489 outgoingPacketType = DHCPPacketType.DHCPACK;
samanwita palf28207b2015-09-04 10:41:56 -0700490 discoverHost(context, clientIaddr);
samanwita pala3d1d1c2015-09-25 11:50:15 -0700491 } else if (packet.getEtherType() == Ethernet.TYPE_IPV4 &&
492 ((IPv4) packet.getPayload()).getDestinationAddress() == myIP.toInt()) {
493 outgoingPacketType = DHCPPacketType.DHCPNAK;
494 } else {
495 return;
samanwita palf28207b2015-09-04 10:41:56 -0700496 }
samanwita pala3d1d1c2015-09-25 11:50:15 -0700497 Ethernet ethReply = buildReply(packet, clientIaddr, (byte) outgoingPacketType.getValue());
498 sendReply(context, ethReply);
samanwita palf28207b2015-09-04 10:41:56 -0700499 }
500 }
samanwita pal2a313402015-09-14 16:03:22 -0700501 } else if (incomingPacketType.getValue() == DHCPPacketType.DHCPRELEASE.getValue()) {
samanwita palc40e5ed2015-09-24 11:01:51 -0700502 Ip4Address ip4Address = dhcpStore.releaseIP(hostId);
503 if (ip4Address != null) {
504 hostProviderService.removeIpFromHost(hostId, ip4Address);
505 }
samanwita palf28207b2015-09-04 10:41:56 -0700506 }
507 }
508 }
509
510 /**
511 * Processes the ARP Payload and initiates a reply to the client.
512 *
513 * @param context context of the incoming message
514 * @param packet the ethernet payload
515 */
516 private void processARPPacket(PacketContext context, Ethernet packet) {
517
518 ARP arpPacket = (ARP) packet.getPayload();
519
520 ARP arpReply = (ARP) arpPacket.clone();
521 arpReply.setOpCode(ARP.OP_REPLY);
522
523 arpReply.setTargetProtocolAddress(arpPacket.getSenderProtocolAddress());
524 arpReply.setTargetHardwareAddress(arpPacket.getSenderHardwareAddress());
525 arpReply.setSenderProtocolAddress(arpPacket.getTargetProtocolAddress());
526 arpReply.setSenderHardwareAddress(myMAC.toBytes());
527
528 // Ethernet Frame.
529 Ethernet ethReply = new Ethernet();
530 ethReply.setSourceMACAddress(myMAC);
531 ethReply.setDestinationMACAddress(packet.getSourceMAC());
532 ethReply.setEtherType(Ethernet.TYPE_ARP);
533 ethReply.setVlanID(packet.getVlanID());
534
535 ethReply.setPayload(arpReply);
536 sendReply(context, ethReply);
537 }
538
539 /**
540 * Integrates hosts learned through DHCP into topology.
541 * @param context context of the incoming message
542 * @param ipAssigned IP Address assigned to the host by DHCP Manager
543 */
544 private void discoverHost(PacketContext context, Ip4Address ipAssigned) {
545 Ethernet packet = context.inPacket().parsed();
546 MacAddress mac = packet.getSourceMAC();
547 VlanId vlanId = VlanId.vlanId(packet.getVlanID());
548 HostLocation hostLocation = new HostLocation(context.inPacket().receivedFrom(), 0);
549
550 Set<IpAddress> ips = new HashSet<>();
551 ips.add(ipAssigned);
552
553 HostId hostId = HostId.hostId(mac, vlanId);
554 DefaultHostDescription desc = new DefaultHostDescription(mac, vlanId, hostLocation, ips);
555 hostProviderService.hostDetected(hostId, desc);
556 }
557
558
559 @Override
560 public void process(PacketContext context) {
samanwita palf28207b2015-09-04 10:41:56 -0700561 Ethernet packet = context.inPacket().parsed();
562 if (packet == null) {
563 return;
564 }
565
566 if (packet.getEtherType() == Ethernet.TYPE_IPV4) {
567 IPv4 ipv4Packet = (IPv4) packet.getPayload();
568
569 if (ipv4Packet.getProtocol() == IPv4.PROTOCOL_UDP) {
570 UDP udpPacket = (UDP) ipv4Packet.getPayload();
571
572 if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
573 udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
574 // This is meant for the dhcp server so process the packet here.
575
576 DHCP dhcpPayload = (DHCP) udpPacket.getPayload();
577 processDHCPPacket(context, dhcpPayload);
578 }
579 }
580 } else if (packet.getEtherType() == Ethernet.TYPE_ARP) {
581 ARP arpPacket = (ARP) packet.getPayload();
582
583 if ((arpPacket.getOpCode() == ARP.OP_REQUEST) &&
samanwita pal7ccc2bc2015-09-14 19:53:15 -0700584 Objects.equals(myIP, Ip4Address.valueOf(arpPacket.getTargetProtocolAddress()))) {
samanwita palf28207b2015-09-04 10:41:56 -0700585
586 processARPPacket(context, packet);
587
588 }
589 }
590 }
591 }
592
593 private class InternalConfigListener implements NetworkConfigListener {
594
595 /**
596 * Reconfigures the DHCP Server according to the configuration parameters passed.
597 *
598 * @param cfg configuration object
599 */
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700600 private void reconfigureNetwork(DhcpConfig cfg) {
Thomas Vachuska00090442015-09-11 18:08:04 -0700601 if (cfg == null) {
602 return;
603 }
samanwita palf28207b2015-09-04 10:41:56 -0700604 if (cfg.ip() != null) {
605 myIP = cfg.ip();
606 }
607 if (cfg.mac() != null) {
samanwita pal2a313402015-09-14 16:03:22 -0700608 myMAC = cfg.mac();
samanwita palf28207b2015-09-04 10:41:56 -0700609 }
610 if (cfg.subnetMask() != null) {
611 subnetMask = cfg.subnetMask();
612 }
613 if (cfg.broadcastAddress() != null) {
614 broadcastAddress = cfg.broadcastAddress();
615 }
616 if (cfg.routerAddress() != null) {
617 routerAddress = cfg.routerAddress();
618 }
619 if (cfg.domainServer() != null) {
620 domainServer = cfg.domainServer();
621 }
samanwita pal7ccc2bc2015-09-14 19:53:15 -0700622 if (cfg.ttl() != -1) {
samanwita pal2a313402015-09-14 16:03:22 -0700623 packetTTL = (byte) cfg.ttl();
samanwita palf28207b2015-09-04 10:41:56 -0700624 }
samanwita pal7ccc2bc2015-09-14 19:53:15 -0700625 if (cfg.leaseTime() != -1) {
samanwita pal2a313402015-09-14 16:03:22 -0700626 leaseTime = cfg.leaseTime();
samanwita palf28207b2015-09-04 10:41:56 -0700627 }
samanwita pal7ccc2bc2015-09-14 19:53:15 -0700628 if (cfg.renewTime() != -1) {
samanwita pal2a313402015-09-14 16:03:22 -0700629 renewalTime = cfg.renewTime();
samanwita palf28207b2015-09-04 10:41:56 -0700630 }
samanwita pal7ccc2bc2015-09-14 19:53:15 -0700631 if (cfg.rebindTime() != -1) {
samanwita pal2a313402015-09-14 16:03:22 -0700632 rebindingTime = cfg.rebindTime();
633 }
samanwita pal7ccc2bc2015-09-14 19:53:15 -0700634 if (cfg.defaultTimeout() != -1) {
samanwita pal2a313402015-09-14 16:03:22 -0700635 dhcpStore.setDefaultTimeoutForPurge(cfg.defaultTimeout());
636 }
samanwita pal7ccc2bc2015-09-14 19:53:15 -0700637 if (cfg.timerDelay() != -1) {
samanwita pal2a313402015-09-14 16:03:22 -0700638 timerDelay = cfg.timerDelay();
639 }
640 if ((cfg.startIp() != null) && (cfg.endIp() != null)) {
641 dhcpStore.populateIPPoolfromRange(cfg.startIp(), cfg.endIp());
samanwita palf28207b2015-09-04 10:41:56 -0700642 }
643 }
644
samanwita palf28207b2015-09-04 10:41:56 -0700645
646 @Override
647 public void event(NetworkConfigEvent event) {
648
649 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
samanwita pal2a313402015-09-14 16:03:22 -0700650 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
651 event.configClass().equals(DhcpConfig.class)) {
652
653 DhcpConfig cfg = cfgService.getConfig(appId, DhcpConfig.class);
654 reconfigureNetwork(cfg);
655 log.info("Reconfigured");
samanwita palf28207b2015-09-04 10:41:56 -0700656 }
657 }
658 }
659
660 private class InternalHostProvider extends AbstractProvider implements HostProvider {
661
662 /**
663 * Creates a provider with the supplier identifier.
664 */
665 protected InternalHostProvider() {
666 super(PID);
667 }
668
669 @Override
670 public void triggerProbe(Host host) {
671 // nothing to do
672 }
673 }
samanwita pal2a313402015-09-14 16:03:22 -0700674
675 private class PurgeListTask implements TimerTask {
676
677 @Override
678 public void run(Timeout to) {
679 IpAssignment ipAssignment;
680 Date dateNow = new Date();
681
samanwita pal0bff4302015-09-15 13:37:00 -0700682 Map<HostId, IpAssignment> ipAssignmentMap = dhcpStore.listAllMapping();
samanwita pal2a313402015-09-14 16:03:22 -0700683 for (Map.Entry<HostId, IpAssignment> entry: ipAssignmentMap.entrySet()) {
684 ipAssignment = entry.getValue();
685
686 long timeLapsed = dateNow.getTime() - ipAssignment.timestamp().getTime();
687 if ((ipAssignment.assignmentStatus() != IpAssignment.AssignmentStatus.Option_Expired) &&
688 (ipAssignment.leasePeriod() > 0) && (timeLapsed > (ipAssignment.leasePeriodMs()))) {
689
samanwita palc40e5ed2015-09-24 11:01:51 -0700690 Ip4Address ip4Address = dhcpStore.releaseIP(entry.getKey());
691 if (ip4Address != null) {
692 hostProviderService.removeIpFromHost(entry.getKey(), ipAssignment.ipAddress());
693 }
samanwita pal2a313402015-09-14 16:03:22 -0700694 }
695 }
696 timeout = Timer.getTimer().newTimeout(new PurgeListTask(), timerDelay, TimeUnit.MINUTES);
697 }
698 }
samanwita palf28207b2015-09-04 10:41:56 -0700699}