blob: 345d5ad02e5ee233366be0c786a7538034ab7cc4 [file] [log] [blame]
samanwita palf28207b2015-09-04 10:41:56 -07001/*
2 * Copyright 2014 Open Networking Laboratory
3 *
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
157 protected Timeout timeout;
158
159 protected static int timerDelay = 2;
samanwita palf28207b2015-09-04 10:41:56 -0700160
161 @Activate
162 protected void activate() {
163 // start the dhcp server
164 appId = coreService.registerApplication("org.onosproject.dhcp");
165
166 cfgService.addListener(cfgListener);
167 factories.forEach(cfgService::registerConfigFactory);
Thomas Vachuska00090442015-09-11 18:08:04 -0700168 cfgListener.reconfigureNetwork(cfgService.getConfig(appId, DhcpConfig.class));
Thomas Vachuska00090442015-09-11 18:08:04 -0700169
samanwita palf28207b2015-09-04 10:41:56 -0700170 hostProviderService = hostProviderRegistry.register(hostProvider);
Thomas Vachuska2a645d42015-09-11 18:58:36 -0700171 packetService.addProcessor(processor, PacketProcessor.director(0));
samanwita palf28207b2015-09-04 10:41:56 -0700172 requestPackets();
samanwita pal2a313402015-09-14 16:03:22 -0700173 timeout = Timer.getTimer().newTimeout(new PurgeListTask(), timerDelay, TimeUnit.MINUTES);
samanwita palf28207b2015-09-04 10:41:56 -0700174 log.info("Started");
175 }
176
177 @Deactivate
178 protected void deactivate() {
179 cfgService.removeListener(cfgListener);
180 factories.forEach(cfgService::unregisterConfigFactory);
181 packetService.removeProcessor(processor);
182 hostProviderRegistry.unregister(hostProvider);
183 hostProviderService = null;
184 cancelPackets();
samanwita pal2a313402015-09-14 16:03:22 -0700185 timeout.cancel();
samanwita palf28207b2015-09-04 10:41:56 -0700186 log.info("Stopped");
187 }
188
189 /**
190 * Request packet in via PacketService.
191 */
192 private void requestPackets() {
193
194 TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
195 .matchEthType(Ethernet.TYPE_IPV4)
196 .matchIPProtocol(IPv4.PROTOCOL_UDP)
197 .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
198 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT));
199 packetService.requestPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
200
201 selectorServer = DefaultTrafficSelector.builder()
202 .matchEthType(Ethernet.TYPE_ARP);
203 packetService.requestPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
204 }
205
206 /**
207 * Cancel requested packets in via packet service.
208 */
209 private void cancelPackets() {
210 TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
211 .matchEthType(Ethernet.TYPE_IPV4)
212 .matchIPProtocol(IPv4.PROTOCOL_UDP)
213 .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
214 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT));
215 packetService.cancelPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
216
217 selectorServer = DefaultTrafficSelector.builder()
218 .matchEthType(Ethernet.TYPE_ARP);
219 packetService.cancelPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
220 }
221
222 @Override
samanwita pal2a313402015-09-14 16:03:22 -0700223 public Map<HostId, IpAssignment> listMapping() {
samanwita pal0bff4302015-09-15 13:37:00 -0700224 return dhcpStore.listAssignedMapping();
samanwita palf28207b2015-09-04 10:41:56 -0700225 }
226
227 @Override
228 public int getLeaseTime() {
229 return leaseTime;
230 }
231
232 @Override
233 public int getRenewalTime() {
234 return renewalTime;
235 }
236
237 @Override
238 public int getRebindingTime() {
239 return rebindingTime;
240 }
241
242 @Override
243 public boolean setStaticMapping(MacAddress macID, Ip4Address ipAddress) {
244 return dhcpStore.assignStaticIP(macID, ipAddress);
245 }
246
247 @Override
248 public boolean removeStaticMapping(MacAddress macID) {
249 return dhcpStore.removeStaticIP(macID);
250 }
251
252 @Override
253 public Iterable<Ip4Address> getAvailableIPs() {
254 return dhcpStore.getAvailableIPs();
255 }
256
257 private class DHCPPacketProcessor implements PacketProcessor {
258
259 /**
260 * Builds the DHCP Reply packet.
261 *
262 * @param packet the incoming Ethernet frame
263 * @param ipOffered the IP offered by the DHCP Server
264 * @param outgoingMessageType the message type of the outgoing packet
265 * @return the Ethernet reply frame
266 */
samanwita pal2a313402015-09-14 16:03:22 -0700267 private Ethernet buildReply(Ethernet packet, Ip4Address ipOffered, byte outgoingMessageType) {
samanwita palf28207b2015-09-04 10:41:56 -0700268
269 // Ethernet Frame.
270 Ethernet ethReply = new Ethernet();
271 ethReply.setSourceMACAddress(myMAC);
272 ethReply.setDestinationMACAddress(packet.getSourceMAC());
273 ethReply.setEtherType(Ethernet.TYPE_IPV4);
274 ethReply.setVlanID(packet.getVlanID());
275
276 // IP Packet
277 IPv4 ipv4Packet = (IPv4) packet.getPayload();
278 IPv4 ipv4Reply = new IPv4();
samanwita pal2a313402015-09-14 16:03:22 -0700279 ipv4Reply.setSourceAddress(myIP.toInt());
280 ipv4Reply.setDestinationAddress(ipOffered.toInt());
samanwita palf28207b2015-09-04 10:41:56 -0700281 ipv4Reply.setTtl(packetTTL);
282
283 // UDP Datagram.
284 UDP udpPacket = (UDP) ipv4Packet.getPayload();
285 UDP udpReply = new UDP();
286 udpReply.setSourcePort((byte) UDP.DHCP_SERVER_PORT);
287 udpReply.setDestinationPort((byte) UDP.DHCP_CLIENT_PORT);
288
289 // DHCP Payload.
290 DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
291 DHCP dhcpReply = new DHCP();
292 dhcpReply.setOpCode(DHCP.OPCODE_REPLY);
293
samanwita pal2a313402015-09-14 16:03:22 -0700294 dhcpReply.setYourIPAddress(ipOffered.toInt());
295 dhcpReply.setServerIPAddress(myIP.toInt());
samanwita palf28207b2015-09-04 10:41:56 -0700296
297 dhcpReply.setTransactionId(dhcpPacket.getTransactionId());
298 dhcpReply.setClientHardwareAddress(dhcpPacket.getClientHardwareAddress());
299 dhcpReply.setHardwareType(DHCP.HWTYPE_ETHERNET);
300 dhcpReply.setHardwareAddressLength((byte) 6);
301
302 // DHCP Options.
303 DHCPOption option = new DHCPOption();
304 List<DHCPOption> optionList = new ArrayList<>();
305
306 // DHCP Message Type.
307 option.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
308 option.setLength((byte) 1);
309 byte[] optionData = {outgoingMessageType};
310 option.setData(optionData);
311 optionList.add(option);
312
313 // DHCP Server Identifier.
314 option = new DHCPOption();
315 option.setCode(DHCP.DHCPOptionCode.OptionCode_DHCPServerIp.getValue());
316 option.setLength((byte) 4);
samanwita pal2a313402015-09-14 16:03:22 -0700317 option.setData(myIP.toOctets());
samanwita palf28207b2015-09-04 10:41:56 -0700318 optionList.add(option);
319
320 // IP Address Lease Time.
321 option = new DHCPOption();
322 option.setCode(DHCP.DHCPOptionCode.OptionCode_LeaseTime.getValue());
323 option.setLength((byte) 4);
324 option.setData(ByteBuffer.allocate(4).putInt(leaseTime).array());
325 optionList.add(option);
326
327 // IP Address Renewal Time.
328 option = new DHCPOption();
329 option.setCode(DHCP.DHCPOptionCode.OptionCode_RenewalTime.getValue());
330 option.setLength((byte) 4);
331 option.setData(ByteBuffer.allocate(4).putInt(renewalTime).array());
332 optionList.add(option);
333
334 // IP Address Rebinding Time.
335 option = new DHCPOption();
336 option.setCode(DHCP.DHCPOptionCode.OPtionCode_RebindingTime.getValue());
337 option.setLength((byte) 4);
338 option.setData(ByteBuffer.allocate(4).putInt(rebindingTime).array());
339 optionList.add(option);
340
341 // Subnet Mask.
342 option = new DHCPOption();
343 option.setCode(DHCP.DHCPOptionCode.OptionCode_SubnetMask.getValue());
344 option.setLength((byte) 4);
samanwita pal2a313402015-09-14 16:03:22 -0700345 option.setData(subnetMask.toOctets());
samanwita palf28207b2015-09-04 10:41:56 -0700346 optionList.add(option);
347
348 // Broadcast Address.
349 option = new DHCPOption();
350 option.setCode(DHCP.DHCPOptionCode.OptionCode_BroadcastAddress.getValue());
351 option.setLength((byte) 4);
samanwita pal2a313402015-09-14 16:03:22 -0700352 option.setData(broadcastAddress.toOctets());
samanwita palf28207b2015-09-04 10:41:56 -0700353 optionList.add(option);
354
355 // Router Address.
356 option = new DHCPOption();
357 option.setCode(DHCP.DHCPOptionCode.OptionCode_RouterAddress.getValue());
358 option.setLength((byte) 4);
samanwita pal2a313402015-09-14 16:03:22 -0700359 option.setData(routerAddress.toOctets());
samanwita palf28207b2015-09-04 10:41:56 -0700360 optionList.add(option);
361
362 // DNS Server Address.
363 option = new DHCPOption();
364 option.setCode(DHCP.DHCPOptionCode.OptionCode_DomainServer.getValue());
365 option.setLength((byte) 4);
samanwita pal2a313402015-09-14 16:03:22 -0700366 option.setData(domainServer.toOctets());
samanwita palf28207b2015-09-04 10:41:56 -0700367 optionList.add(option);
368
369 // End Option.
370 option = new DHCPOption();
371 option.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
372 option.setLength((byte) 1);
373 optionList.add(option);
374
375 dhcpReply.setOptions(optionList);
376
377 udpReply.setPayload(dhcpReply);
378 ipv4Reply.setPayload(udpReply);
379 ethReply.setPayload(ipv4Reply);
380
381 return ethReply;
382 }
383
384 /**
385 * Sends the Ethernet reply frame via the Packet Service.
386 *
387 * @param context the context of the incoming frame
388 * @param reply the Ethernet reply frame
389 */
390 private void sendReply(PacketContext context, Ethernet reply) {
391 if (reply != null) {
392 TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
393 ConnectPoint sourcePoint = context.inPacket().receivedFrom();
394 builder.setOutput(sourcePoint.port());
Thomas Vachuska00090442015-09-11 18:08:04 -0700395 context.block();
samanwita palf28207b2015-09-04 10:41:56 -0700396 packetService.emit(new DefaultOutboundPacket(sourcePoint.deviceId(),
samanwita pal8969cbe2015-09-04 13:31:30 -0700397 builder.build(), ByteBuffer.wrap(reply.serialize())));
samanwita palf28207b2015-09-04 10:41:56 -0700398 }
399 }
400
401 /**
402 * Processes the DHCP Payload and initiates a reply to the client.
403 *
404 * @param context context of the incoming message
405 * @param dhcpPayload the extracted DHCP payload
406 */
407 private void processDHCPPacket(PacketContext context, DHCP dhcpPayload) {
samanwita palf28207b2015-09-04 10:41:56 -0700408 Ethernet packet = context.inPacket().parsed();
409 boolean flagIfRequestedIP = false;
410 boolean flagIfServerIP = false;
411 Ip4Address requestedIP = Ip4Address.valueOf("0.0.0.0");
412 Ip4Address serverIP = Ip4Address.valueOf("0.0.0.0");
413
414 if (dhcpPayload != null) {
415
samanwita pal2a313402015-09-14 16:03:22 -0700416 DHCPPacketType incomingPacketType = DHCPPacketType.getType(0);
samanwita palf28207b2015-09-04 10:41:56 -0700417 for (DHCPOption option : dhcpPayload.getOptions()) {
418 if (option.getCode() == DHCP.DHCPOptionCode.OptionCode_MessageType.getValue()) {
419 byte[] data = option.getData();
samanwita pal2a313402015-09-14 16:03:22 -0700420 incomingPacketType = DHCPPacketType.getType(data[0]);
samanwita palf28207b2015-09-04 10:41:56 -0700421 }
422 if (option.getCode() == DHCP.DHCPOptionCode.OptionCode_RequestedIP.getValue()) {
423 byte[] data = option.getData();
424 requestedIP = Ip4Address.valueOf(data);
425 flagIfRequestedIP = true;
426 }
427 if (option.getCode() == DHCP.DHCPOptionCode.OptionCode_DHCPServerIp.getValue()) {
428 byte[] data = option.getData();
429 serverIP = Ip4Address.valueOf(data);
430 flagIfServerIP = true;
431 }
432 }
samanwita pal8969cbe2015-09-04 13:31:30 -0700433 DHCPPacketType outgoingPacketType;
samanwita palf28207b2015-09-04 10:41:56 -0700434 MacAddress clientMAC = new MacAddress(dhcpPayload.getClientHardwareAddress());
samanwita pal2a313402015-09-14 16:03:22 -0700435 VlanId vlanId = VlanId.vlanId(packet.getVlanID());
436 HostId hostId = HostId.hostId(clientMAC, vlanId);
samanwita palf28207b2015-09-04 10:41:56 -0700437
samanwita pal2a313402015-09-14 16:03:22 -0700438 if (incomingPacketType.getValue() == DHCPPacketType.DHCPDISCOVER.getValue()) {
samanwita palf28207b2015-09-04 10:41:56 -0700439
samanwita pal8969cbe2015-09-04 13:31:30 -0700440 outgoingPacketType = DHCPPacketType.DHCPOFFER;
samanwita pal2a313402015-09-14 16:03:22 -0700441 Ip4Address ipOffered = dhcpStore.suggestIP(hostId, requestedIP);
442 if (ipOffered != null) {
443 Ethernet ethReply = buildReply(packet, ipOffered,
444 (byte) outgoingPacketType.getValue());
445 sendReply(context, ethReply);
446 }
samanwita palf28207b2015-09-04 10:41:56 -0700447
samanwita pal2a313402015-09-14 16:03:22 -0700448 } else if (incomingPacketType.getValue() == DHCPPacketType.DHCPREQUEST.getValue()) {
samanwita palf28207b2015-09-04 10:41:56 -0700449
samanwita pal8969cbe2015-09-04 13:31:30 -0700450 outgoingPacketType = DHCPPacketType.DHCPACK;
samanwita palf28207b2015-09-04 10:41:56 -0700451
452 if (flagIfServerIP && flagIfRequestedIP) {
453 // SELECTING state
samanwita pal2a313402015-09-14 16:03:22 -0700454 if (myIP.equals(serverIP) &&
455 dhcpStore.assignIP(hostId, requestedIP, leaseTime)) {
samanwita palf28207b2015-09-04 10:41:56 -0700456
samanwita pal2a313402015-09-14 16:03:22 -0700457 Ethernet ethReply = buildReply(packet, requestedIP,
samanwita pal8969cbe2015-09-04 13:31:30 -0700458 (byte) outgoingPacketType.getValue());
samanwita palf28207b2015-09-04 10:41:56 -0700459 sendReply(context, ethReply);
460 discoverHost(context, requestedIP);
461 }
462 } else if (flagIfRequestedIP) {
463 // INIT-REBOOT state
samanwita pal2a313402015-09-14 16:03:22 -0700464 if (dhcpStore.assignIP(hostId, requestedIP, leaseTime)) {
465 Ethernet ethReply = buildReply(packet, requestedIP,
samanwita pal8969cbe2015-09-04 13:31:30 -0700466 (byte) outgoingPacketType.getValue());
samanwita palf28207b2015-09-04 10:41:56 -0700467 sendReply(context, ethReply);
468 discoverHost(context, requestedIP);
469 }
470 } else {
471 // RENEWING and REBINDING state
472 int ciaadr = dhcpPayload.getClientIPAddress();
473 if (ciaadr != 0) {
474 Ip4Address clientIaddr = Ip4Address.valueOf(ciaadr);
samanwita pal2a313402015-09-14 16:03:22 -0700475 if (dhcpStore.assignIP(hostId, clientIaddr, leaseTime)) {
476 Ethernet ethReply = buildReply(packet, clientIaddr,
samanwita pal8969cbe2015-09-04 13:31:30 -0700477 (byte) outgoingPacketType.getValue());
samanwita palf28207b2015-09-04 10:41:56 -0700478 sendReply(context, ethReply);
479 discoverHost(context, clientIaddr);
480 }
481 }
482 }
samanwita pal2a313402015-09-14 16:03:22 -0700483 } else if (incomingPacketType.getValue() == DHCPPacketType.DHCPRELEASE.getValue()) {
484 dhcpStore.releaseIP(hostId);
samanwita palf28207b2015-09-04 10:41:56 -0700485 }
486 }
487 }
488
489 /**
490 * Processes the ARP Payload and initiates a reply to the client.
491 *
492 * @param context context of the incoming message
493 * @param packet the ethernet payload
494 */
495 private void processARPPacket(PacketContext context, Ethernet packet) {
496
497 ARP arpPacket = (ARP) packet.getPayload();
498
499 ARP arpReply = (ARP) arpPacket.clone();
500 arpReply.setOpCode(ARP.OP_REPLY);
501
502 arpReply.setTargetProtocolAddress(arpPacket.getSenderProtocolAddress());
503 arpReply.setTargetHardwareAddress(arpPacket.getSenderHardwareAddress());
504 arpReply.setSenderProtocolAddress(arpPacket.getTargetProtocolAddress());
505 arpReply.setSenderHardwareAddress(myMAC.toBytes());
506
507 // Ethernet Frame.
508 Ethernet ethReply = new Ethernet();
509 ethReply.setSourceMACAddress(myMAC);
510 ethReply.setDestinationMACAddress(packet.getSourceMAC());
511 ethReply.setEtherType(Ethernet.TYPE_ARP);
512 ethReply.setVlanID(packet.getVlanID());
513
514 ethReply.setPayload(arpReply);
515 sendReply(context, ethReply);
516 }
517
518 /**
519 * Integrates hosts learned through DHCP into topology.
520 * @param context context of the incoming message
521 * @param ipAssigned IP Address assigned to the host by DHCP Manager
522 */
523 private void discoverHost(PacketContext context, Ip4Address ipAssigned) {
524 Ethernet packet = context.inPacket().parsed();
525 MacAddress mac = packet.getSourceMAC();
526 VlanId vlanId = VlanId.vlanId(packet.getVlanID());
527 HostLocation hostLocation = new HostLocation(context.inPacket().receivedFrom(), 0);
528
529 Set<IpAddress> ips = new HashSet<>();
530 ips.add(ipAssigned);
531
532 HostId hostId = HostId.hostId(mac, vlanId);
533 DefaultHostDescription desc = new DefaultHostDescription(mac, vlanId, hostLocation, ips);
534 hostProviderService.hostDetected(hostId, desc);
535 }
536
537
538 @Override
539 public void process(PacketContext context) {
samanwita palf28207b2015-09-04 10:41:56 -0700540 Ethernet packet = context.inPacket().parsed();
541 if (packet == null) {
542 return;
543 }
544
545 if (packet.getEtherType() == Ethernet.TYPE_IPV4) {
546 IPv4 ipv4Packet = (IPv4) packet.getPayload();
547
548 if (ipv4Packet.getProtocol() == IPv4.PROTOCOL_UDP) {
549 UDP udpPacket = (UDP) ipv4Packet.getPayload();
550
551 if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
552 udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
553 // This is meant for the dhcp server so process the packet here.
554
555 DHCP dhcpPayload = (DHCP) udpPacket.getPayload();
556 processDHCPPacket(context, dhcpPayload);
557 }
558 }
559 } else if (packet.getEtherType() == Ethernet.TYPE_ARP) {
560 ARP arpPacket = (ARP) packet.getPayload();
561
562 if ((arpPacket.getOpCode() == ARP.OP_REQUEST) &&
samanwita pal7ccc2bc2015-09-14 19:53:15 -0700563 Objects.equals(myIP, Ip4Address.valueOf(arpPacket.getTargetProtocolAddress()))) {
samanwita palf28207b2015-09-04 10:41:56 -0700564
565 processARPPacket(context, packet);
566
567 }
568 }
569 }
570 }
571
572 private class InternalConfigListener implements NetworkConfigListener {
573
574 /**
575 * Reconfigures the DHCP Server according to the configuration parameters passed.
576 *
577 * @param cfg configuration object
578 */
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700579 private void reconfigureNetwork(DhcpConfig cfg) {
Thomas Vachuska00090442015-09-11 18:08:04 -0700580 if (cfg == null) {
581 return;
582 }
samanwita palf28207b2015-09-04 10:41:56 -0700583 if (cfg.ip() != null) {
584 myIP = cfg.ip();
585 }
586 if (cfg.mac() != null) {
samanwita pal2a313402015-09-14 16:03:22 -0700587 myMAC = cfg.mac();
samanwita palf28207b2015-09-04 10:41:56 -0700588 }
589 if (cfg.subnetMask() != null) {
590 subnetMask = cfg.subnetMask();
591 }
592 if (cfg.broadcastAddress() != null) {
593 broadcastAddress = cfg.broadcastAddress();
594 }
595 if (cfg.routerAddress() != null) {
596 routerAddress = cfg.routerAddress();
597 }
598 if (cfg.domainServer() != null) {
599 domainServer = cfg.domainServer();
600 }
samanwita pal7ccc2bc2015-09-14 19:53:15 -0700601 if (cfg.ttl() != -1) {
samanwita pal2a313402015-09-14 16:03:22 -0700602 packetTTL = (byte) cfg.ttl();
samanwita palf28207b2015-09-04 10:41:56 -0700603 }
samanwita pal7ccc2bc2015-09-14 19:53:15 -0700604 if (cfg.leaseTime() != -1) {
samanwita pal2a313402015-09-14 16:03:22 -0700605 leaseTime = cfg.leaseTime();
samanwita palf28207b2015-09-04 10:41:56 -0700606 }
samanwita pal7ccc2bc2015-09-14 19:53:15 -0700607 if (cfg.renewTime() != -1) {
samanwita pal2a313402015-09-14 16:03:22 -0700608 renewalTime = cfg.renewTime();
samanwita palf28207b2015-09-04 10:41:56 -0700609 }
samanwita pal7ccc2bc2015-09-14 19:53:15 -0700610 if (cfg.rebindTime() != -1) {
samanwita pal2a313402015-09-14 16:03:22 -0700611 rebindingTime = cfg.rebindTime();
612 }
samanwita pal7ccc2bc2015-09-14 19:53:15 -0700613 if (cfg.defaultTimeout() != -1) {
samanwita pal2a313402015-09-14 16:03:22 -0700614 dhcpStore.setDefaultTimeoutForPurge(cfg.defaultTimeout());
615 }
samanwita pal7ccc2bc2015-09-14 19:53:15 -0700616 if (cfg.timerDelay() != -1) {
samanwita pal2a313402015-09-14 16:03:22 -0700617 timerDelay = cfg.timerDelay();
618 }
619 if ((cfg.startIp() != null) && (cfg.endIp() != null)) {
620 dhcpStore.populateIPPoolfromRange(cfg.startIp(), cfg.endIp());
samanwita palf28207b2015-09-04 10:41:56 -0700621 }
622 }
623
samanwita palf28207b2015-09-04 10:41:56 -0700624
625 @Override
626 public void event(NetworkConfigEvent event) {
627
628 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
samanwita pal2a313402015-09-14 16:03:22 -0700629 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
630 event.configClass().equals(DhcpConfig.class)) {
631
632 DhcpConfig cfg = cfgService.getConfig(appId, DhcpConfig.class);
633 reconfigureNetwork(cfg);
634 log.info("Reconfigured");
samanwita palf28207b2015-09-04 10:41:56 -0700635 }
636 }
637 }
638
639 private class InternalHostProvider extends AbstractProvider implements HostProvider {
640
641 /**
642 * Creates a provider with the supplier identifier.
643 */
644 protected InternalHostProvider() {
645 super(PID);
646 }
647
648 @Override
649 public void triggerProbe(Host host) {
650 // nothing to do
651 }
652 }
samanwita pal2a313402015-09-14 16:03:22 -0700653
654 private class PurgeListTask implements TimerTask {
655
656 @Override
657 public void run(Timeout to) {
658 IpAssignment ipAssignment;
659 Date dateNow = new Date();
660
samanwita pal0bff4302015-09-15 13:37:00 -0700661 Map<HostId, IpAssignment> ipAssignmentMap = dhcpStore.listAllMapping();
samanwita pal2a313402015-09-14 16:03:22 -0700662 for (Map.Entry<HostId, IpAssignment> entry: ipAssignmentMap.entrySet()) {
663 ipAssignment = entry.getValue();
664
665 long timeLapsed = dateNow.getTime() - ipAssignment.timestamp().getTime();
666 if ((ipAssignment.assignmentStatus() != IpAssignment.AssignmentStatus.Option_Expired) &&
667 (ipAssignment.leasePeriod() > 0) && (timeLapsed > (ipAssignment.leasePeriodMs()))) {
668
669 dhcpStore.releaseIP(entry.getKey());
samanwita pal0bff4302015-09-15 13:37:00 -0700670 // TODO remove only the IP from the host entry when the API is in place.
samanwita pal2a313402015-09-14 16:03:22 -0700671 hostProviderService.hostVanished(entry.getKey());
672 }
673 }
674 timeout = Timer.getTimer().newTimeout(new PurgeListTask(), timerDelay, TimeUnit.MINUTES);
675 }
676 }
samanwita palf28207b2015-09-04 10:41:56 -0700677}