blob: f3f2ceea1b355fe0d2c4083aa79c798efb94c021 [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;
77import java.util.Set;
samanwita pal2a313402015-09-14 16:03:22 -070078import java.util.concurrent.TimeUnit;
samanwita palf28207b2015-09-04 10:41:56 -070079
80import static org.onlab.packet.MacAddress.valueOf;
81import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
82
83/**
84 * Skeletal ONOS DHCP Server application.
85 */
86@Component(immediate = true)
87@Service
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -070088public class DhcpManager implements DhcpService {
samanwita palf28207b2015-09-04 10:41:56 -070089
90 private static final ProviderId PID = new ProviderId("of", "org.onosproject.dhcp", true);
91 private final Logger log = LoggerFactory.getLogger(getClass());
92
Thomas Vachuska00090442015-09-11 18:08:04 -070093 private final InternalConfigListener cfgListener = new InternalConfigListener();
samanwita palf28207b2015-09-04 10:41:56 -070094
95 private final Set<ConfigFactory> factories = ImmutableSet.of(
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -070096 new ConfigFactory<ApplicationId, DhcpConfig>(APP_SUBJECT_FACTORY,
97 DhcpConfig.class,
samanwita palf28207b2015-09-04 10:41:56 -070098 "dhcp") {
99 @Override
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700100 public DhcpConfig createConfig() {
101 return new DhcpConfig();
samanwita palf28207b2015-09-04 10:41:56 -0700102 }
samanwita palf28207b2015-09-04 10:41:56 -0700103 }
104 );
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 protected NetworkConfigRegistry cfgService;
107
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected PacketService packetService;
110
111 private DHCPPacketProcessor processor = new DHCPPacketProcessor();
112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected CoreService coreService;
115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700117 protected DhcpStore dhcpStore;
samanwita palf28207b2015-09-04 10:41:56 -0700118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
120 protected HostProviderRegistry hostProviderRegistry;
121
122 protected HostProviderService hostProviderService;
123
samanwita pal2a313402015-09-14 16:03:22 -0700124 private final HostProvider hostProvider = new InternalHostProvider();
125
samanwita palf28207b2015-09-04 10:41:56 -0700126 private ApplicationId appId;
127
128 // Hardcoded values are default values.
129
samanwita pal2a313402015-09-14 16:03:22 -0700130 private static Ip4Address myIP = Ip4Address.valueOf("10.0.0.2");
samanwita palf28207b2015-09-04 10:41:56 -0700131
132 private static MacAddress myMAC = valueOf("4f:4f:4f:4f:4f:4f");
133
134 /**
135 * leaseTime - 10 mins or 600s.
136 * renewalTime - 5 mins or 300s.
137 * rebindingTime - 6 mins or 360s.
138 */
139
140 private static int leaseTime = 600;
141
142 private static int renewalTime = 300;
143
144 private static int rebindingTime = 360;
145
146 private static byte packetTTL = (byte) 127;
147
samanwita pal2a313402015-09-14 16:03:22 -0700148 private static Ip4Address subnetMask = Ip4Address.valueOf("255.0.0.0");
samanwita palf28207b2015-09-04 10:41:56 -0700149
samanwita pal2a313402015-09-14 16:03:22 -0700150 private static Ip4Address broadcastAddress = Ip4Address.valueOf("10.255.255.255");
samanwita palf28207b2015-09-04 10:41:56 -0700151
samanwita pal2a313402015-09-14 16:03:22 -0700152 private static Ip4Address routerAddress = Ip4Address.valueOf("10.0.0.2");
samanwita palf28207b2015-09-04 10:41:56 -0700153
samanwita pal2a313402015-09-14 16:03:22 -0700154 private static Ip4Address domainServer = Ip4Address.valueOf("10.0.0.2");
155
156 protected Timeout timeout;
157
158 protected static int timerDelay = 2;
samanwita palf28207b2015-09-04 10:41:56 -0700159
160 @Activate
161 protected void activate() {
162 // start the dhcp server
163 appId = coreService.registerApplication("org.onosproject.dhcp");
164
165 cfgService.addListener(cfgListener);
166 factories.forEach(cfgService::registerConfigFactory);
Thomas Vachuska00090442015-09-11 18:08:04 -0700167 cfgListener.reconfigureNetwork(cfgService.getConfig(appId, DhcpConfig.class));
Thomas Vachuska00090442015-09-11 18:08:04 -0700168
samanwita palf28207b2015-09-04 10:41:56 -0700169 hostProviderService = hostProviderRegistry.register(hostProvider);
Thomas Vachuska2a645d42015-09-11 18:58:36 -0700170 packetService.addProcessor(processor, PacketProcessor.director(0));
samanwita palf28207b2015-09-04 10:41:56 -0700171 requestPackets();
samanwita pal2a313402015-09-14 16:03:22 -0700172 timeout = Timer.getTimer().newTimeout(new PurgeListTask(), timerDelay, TimeUnit.MINUTES);
samanwita palf28207b2015-09-04 10:41:56 -0700173 log.info("Started");
174 }
175
176 @Deactivate
177 protected void deactivate() {
178 cfgService.removeListener(cfgListener);
179 factories.forEach(cfgService::unregisterConfigFactory);
180 packetService.removeProcessor(processor);
181 hostProviderRegistry.unregister(hostProvider);
182 hostProviderService = null;
183 cancelPackets();
samanwita pal2a313402015-09-14 16:03:22 -0700184 timeout.cancel();
samanwita palf28207b2015-09-04 10:41:56 -0700185 log.info("Stopped");
186 }
187
188 /**
189 * Request packet in via PacketService.
190 */
191 private void requestPackets() {
192
193 TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
194 .matchEthType(Ethernet.TYPE_IPV4)
195 .matchIPProtocol(IPv4.PROTOCOL_UDP)
196 .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
197 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT));
198 packetService.requestPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
199
200 selectorServer = DefaultTrafficSelector.builder()
201 .matchEthType(Ethernet.TYPE_ARP);
202 packetService.requestPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
203 }
204
205 /**
206 * Cancel requested packets in via packet service.
207 */
208 private void cancelPackets() {
209 TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
210 .matchEthType(Ethernet.TYPE_IPV4)
211 .matchIPProtocol(IPv4.PROTOCOL_UDP)
212 .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
213 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT));
214 packetService.cancelPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
215
216 selectorServer = DefaultTrafficSelector.builder()
217 .matchEthType(Ethernet.TYPE_ARP);
218 packetService.cancelPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
219 }
220
221 @Override
samanwita pal2a313402015-09-14 16:03:22 -0700222 public Map<HostId, IpAssignment> listMapping() {
samanwita palf28207b2015-09-04 10:41:56 -0700223 return dhcpStore.listMapping();
224 }
225
226 @Override
227 public int getLeaseTime() {
228 return leaseTime;
229 }
230
231 @Override
232 public int getRenewalTime() {
233 return renewalTime;
234 }
235
236 @Override
237 public int getRebindingTime() {
238 return rebindingTime;
239 }
240
241 @Override
242 public boolean setStaticMapping(MacAddress macID, Ip4Address ipAddress) {
243 return dhcpStore.assignStaticIP(macID, ipAddress);
244 }
245
246 @Override
247 public boolean removeStaticMapping(MacAddress macID) {
248 return dhcpStore.removeStaticIP(macID);
249 }
250
251 @Override
252 public Iterable<Ip4Address> getAvailableIPs() {
253 return dhcpStore.getAvailableIPs();
254 }
255
256 private class DHCPPacketProcessor implements PacketProcessor {
257
258 /**
259 * Builds the DHCP Reply packet.
260 *
261 * @param packet the incoming Ethernet frame
262 * @param ipOffered the IP offered by the DHCP Server
263 * @param outgoingMessageType the message type of the outgoing packet
264 * @return the Ethernet reply frame
265 */
samanwita pal2a313402015-09-14 16:03:22 -0700266 private Ethernet buildReply(Ethernet packet, Ip4Address ipOffered, byte outgoingMessageType) {
samanwita palf28207b2015-09-04 10:41:56 -0700267
268 // Ethernet Frame.
269 Ethernet ethReply = new Ethernet();
270 ethReply.setSourceMACAddress(myMAC);
271 ethReply.setDestinationMACAddress(packet.getSourceMAC());
272 ethReply.setEtherType(Ethernet.TYPE_IPV4);
273 ethReply.setVlanID(packet.getVlanID());
274
275 // IP Packet
276 IPv4 ipv4Packet = (IPv4) packet.getPayload();
277 IPv4 ipv4Reply = new IPv4();
samanwita pal2a313402015-09-14 16:03:22 -0700278 ipv4Reply.setSourceAddress(myIP.toInt());
279 ipv4Reply.setDestinationAddress(ipOffered.toInt());
samanwita palf28207b2015-09-04 10:41:56 -0700280 ipv4Reply.setTtl(packetTTL);
281
282 // UDP Datagram.
283 UDP udpPacket = (UDP) ipv4Packet.getPayload();
284 UDP udpReply = new UDP();
285 udpReply.setSourcePort((byte) UDP.DHCP_SERVER_PORT);
286 udpReply.setDestinationPort((byte) UDP.DHCP_CLIENT_PORT);
287
288 // DHCP Payload.
289 DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
290 DHCP dhcpReply = new DHCP();
291 dhcpReply.setOpCode(DHCP.OPCODE_REPLY);
292
samanwita pal2a313402015-09-14 16:03:22 -0700293 dhcpReply.setYourIPAddress(ipOffered.toInt());
294 dhcpReply.setServerIPAddress(myIP.toInt());
samanwita palf28207b2015-09-04 10:41:56 -0700295
296 dhcpReply.setTransactionId(dhcpPacket.getTransactionId());
297 dhcpReply.setClientHardwareAddress(dhcpPacket.getClientHardwareAddress());
298 dhcpReply.setHardwareType(DHCP.HWTYPE_ETHERNET);
299 dhcpReply.setHardwareAddressLength((byte) 6);
300
301 // DHCP Options.
302 DHCPOption option = new DHCPOption();
303 List<DHCPOption> optionList = new ArrayList<>();
304
305 // DHCP Message Type.
306 option.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
307 option.setLength((byte) 1);
308 byte[] optionData = {outgoingMessageType};
309 option.setData(optionData);
310 optionList.add(option);
311
312 // DHCP Server Identifier.
313 option = new DHCPOption();
314 option.setCode(DHCP.DHCPOptionCode.OptionCode_DHCPServerIp.getValue());
315 option.setLength((byte) 4);
samanwita pal2a313402015-09-14 16:03:22 -0700316 option.setData(myIP.toOctets());
samanwita palf28207b2015-09-04 10:41:56 -0700317 optionList.add(option);
318
319 // IP Address Lease Time.
320 option = new DHCPOption();
321 option.setCode(DHCP.DHCPOptionCode.OptionCode_LeaseTime.getValue());
322 option.setLength((byte) 4);
323 option.setData(ByteBuffer.allocate(4).putInt(leaseTime).array());
324 optionList.add(option);
325
326 // IP Address Renewal Time.
327 option = new DHCPOption();
328 option.setCode(DHCP.DHCPOptionCode.OptionCode_RenewalTime.getValue());
329 option.setLength((byte) 4);
330 option.setData(ByteBuffer.allocate(4).putInt(renewalTime).array());
331 optionList.add(option);
332
333 // IP Address Rebinding Time.
334 option = new DHCPOption();
335 option.setCode(DHCP.DHCPOptionCode.OPtionCode_RebindingTime.getValue());
336 option.setLength((byte) 4);
337 option.setData(ByteBuffer.allocate(4).putInt(rebindingTime).array());
338 optionList.add(option);
339
340 // Subnet Mask.
341 option = new DHCPOption();
342 option.setCode(DHCP.DHCPOptionCode.OptionCode_SubnetMask.getValue());
343 option.setLength((byte) 4);
samanwita pal2a313402015-09-14 16:03:22 -0700344 option.setData(subnetMask.toOctets());
samanwita palf28207b2015-09-04 10:41:56 -0700345 optionList.add(option);
346
347 // Broadcast Address.
348 option = new DHCPOption();
349 option.setCode(DHCP.DHCPOptionCode.OptionCode_BroadcastAddress.getValue());
350 option.setLength((byte) 4);
samanwita pal2a313402015-09-14 16:03:22 -0700351 option.setData(broadcastAddress.toOctets());
samanwita palf28207b2015-09-04 10:41:56 -0700352 optionList.add(option);
353
354 // Router Address.
355 option = new DHCPOption();
356 option.setCode(DHCP.DHCPOptionCode.OptionCode_RouterAddress.getValue());
357 option.setLength((byte) 4);
samanwita pal2a313402015-09-14 16:03:22 -0700358 option.setData(routerAddress.toOctets());
samanwita palf28207b2015-09-04 10:41:56 -0700359 optionList.add(option);
360
361 // DNS Server Address.
362 option = new DHCPOption();
363 option.setCode(DHCP.DHCPOptionCode.OptionCode_DomainServer.getValue());
364 option.setLength((byte) 4);
samanwita pal2a313402015-09-14 16:03:22 -0700365 option.setData(domainServer.toOctets());
samanwita palf28207b2015-09-04 10:41:56 -0700366 optionList.add(option);
367
368 // End Option.
369 option = new DHCPOption();
370 option.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
371 option.setLength((byte) 1);
372 optionList.add(option);
373
374 dhcpReply.setOptions(optionList);
375
376 udpReply.setPayload(dhcpReply);
377 ipv4Reply.setPayload(udpReply);
378 ethReply.setPayload(ipv4Reply);
379
380 return ethReply;
381 }
382
383 /**
384 * Sends the Ethernet reply frame via the Packet Service.
385 *
386 * @param context the context of the incoming frame
387 * @param reply the Ethernet reply frame
388 */
389 private void sendReply(PacketContext context, Ethernet reply) {
390 if (reply != null) {
391 TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
392 ConnectPoint sourcePoint = context.inPacket().receivedFrom();
393 builder.setOutput(sourcePoint.port());
Thomas Vachuska00090442015-09-11 18:08:04 -0700394 context.block();
samanwita palf28207b2015-09-04 10:41:56 -0700395 packetService.emit(new DefaultOutboundPacket(sourcePoint.deviceId(),
samanwita pal8969cbe2015-09-04 13:31:30 -0700396 builder.build(), ByteBuffer.wrap(reply.serialize())));
samanwita palf28207b2015-09-04 10:41:56 -0700397 }
398 }
399
400 /**
401 * Processes the DHCP Payload and initiates a reply to the client.
402 *
403 * @param context context of the incoming message
404 * @param dhcpPayload the extracted DHCP payload
405 */
406 private void processDHCPPacket(PacketContext context, DHCP dhcpPayload) {
samanwita palf28207b2015-09-04 10:41:56 -0700407 Ethernet packet = context.inPacket().parsed();
408 boolean flagIfRequestedIP = false;
409 boolean flagIfServerIP = false;
410 Ip4Address requestedIP = Ip4Address.valueOf("0.0.0.0");
411 Ip4Address serverIP = Ip4Address.valueOf("0.0.0.0");
412
413 if (dhcpPayload != null) {
414
samanwita pal2a313402015-09-14 16:03:22 -0700415 DHCPPacketType incomingPacketType = DHCPPacketType.getType(0);
samanwita palf28207b2015-09-04 10:41:56 -0700416 for (DHCPOption option : dhcpPayload.getOptions()) {
417 if (option.getCode() == DHCP.DHCPOptionCode.OptionCode_MessageType.getValue()) {
418 byte[] data = option.getData();
samanwita pal2a313402015-09-14 16:03:22 -0700419 incomingPacketType = DHCPPacketType.getType(data[0]);
samanwita palf28207b2015-09-04 10:41:56 -0700420 }
421 if (option.getCode() == DHCP.DHCPOptionCode.OptionCode_RequestedIP.getValue()) {
422 byte[] data = option.getData();
423 requestedIP = Ip4Address.valueOf(data);
424 flagIfRequestedIP = true;
425 }
426 if (option.getCode() == DHCP.DHCPOptionCode.OptionCode_DHCPServerIp.getValue()) {
427 byte[] data = option.getData();
428 serverIP = Ip4Address.valueOf(data);
429 flagIfServerIP = true;
430 }
431 }
samanwita pal8969cbe2015-09-04 13:31:30 -0700432 DHCPPacketType outgoingPacketType;
samanwita palf28207b2015-09-04 10:41:56 -0700433 MacAddress clientMAC = new MacAddress(dhcpPayload.getClientHardwareAddress());
samanwita pal2a313402015-09-14 16:03:22 -0700434 VlanId vlanId = VlanId.vlanId(packet.getVlanID());
435 HostId hostId = HostId.hostId(clientMAC, vlanId);
samanwita palf28207b2015-09-04 10:41:56 -0700436
samanwita pal2a313402015-09-14 16:03:22 -0700437 if (incomingPacketType.getValue() == DHCPPacketType.DHCPDISCOVER.getValue()) {
samanwita palf28207b2015-09-04 10:41:56 -0700438
samanwita pal8969cbe2015-09-04 13:31:30 -0700439 outgoingPacketType = DHCPPacketType.DHCPOFFER;
samanwita pal2a313402015-09-14 16:03:22 -0700440 Ip4Address ipOffered = dhcpStore.suggestIP(hostId, requestedIP);
441 if (ipOffered != null) {
442 Ethernet ethReply = buildReply(packet, ipOffered,
443 (byte) outgoingPacketType.getValue());
444 sendReply(context, ethReply);
445 }
samanwita palf28207b2015-09-04 10:41:56 -0700446
samanwita pal2a313402015-09-14 16:03:22 -0700447 } else if (incomingPacketType.getValue() == DHCPPacketType.DHCPREQUEST.getValue()) {
samanwita palf28207b2015-09-04 10:41:56 -0700448
samanwita pal8969cbe2015-09-04 13:31:30 -0700449 outgoingPacketType = DHCPPacketType.DHCPACK;
samanwita palf28207b2015-09-04 10:41:56 -0700450
451 if (flagIfServerIP && flagIfRequestedIP) {
452 // SELECTING state
samanwita pal2a313402015-09-14 16:03:22 -0700453 if (myIP.equals(serverIP) &&
454 dhcpStore.assignIP(hostId, requestedIP, leaseTime)) {
samanwita palf28207b2015-09-04 10:41:56 -0700455
samanwita pal2a313402015-09-14 16:03:22 -0700456 Ethernet ethReply = buildReply(packet, requestedIP,
samanwita pal8969cbe2015-09-04 13:31:30 -0700457 (byte) outgoingPacketType.getValue());
samanwita palf28207b2015-09-04 10:41:56 -0700458 sendReply(context, ethReply);
459 discoverHost(context, requestedIP);
460 }
461 } else if (flagIfRequestedIP) {
462 // INIT-REBOOT state
samanwita pal2a313402015-09-14 16:03:22 -0700463 if (dhcpStore.assignIP(hostId, requestedIP, leaseTime)) {
464 Ethernet ethReply = buildReply(packet, requestedIP,
samanwita pal8969cbe2015-09-04 13:31:30 -0700465 (byte) outgoingPacketType.getValue());
samanwita palf28207b2015-09-04 10:41:56 -0700466 sendReply(context, ethReply);
467 discoverHost(context, requestedIP);
468 }
469 } else {
470 // RENEWING and REBINDING state
471 int ciaadr = dhcpPayload.getClientIPAddress();
472 if (ciaadr != 0) {
473 Ip4Address clientIaddr = Ip4Address.valueOf(ciaadr);
samanwita pal2a313402015-09-14 16:03:22 -0700474 if (dhcpStore.assignIP(hostId, clientIaddr, leaseTime)) {
475 Ethernet ethReply = buildReply(packet, clientIaddr,
samanwita pal8969cbe2015-09-04 13:31:30 -0700476 (byte) outgoingPacketType.getValue());
samanwita palf28207b2015-09-04 10:41:56 -0700477 sendReply(context, ethReply);
478 discoverHost(context, clientIaddr);
479 }
480 }
481 }
samanwita pal2a313402015-09-14 16:03:22 -0700482 } else if (incomingPacketType.getValue() == DHCPPacketType.DHCPRELEASE.getValue()) {
483 dhcpStore.releaseIP(hostId);
samanwita palf28207b2015-09-04 10:41:56 -0700484 }
485 }
486 }
487
488 /**
489 * Processes the ARP Payload and initiates a reply to the client.
490 *
491 * @param context context of the incoming message
492 * @param packet the ethernet payload
493 */
494 private void processARPPacket(PacketContext context, Ethernet packet) {
495
496 ARP arpPacket = (ARP) packet.getPayload();
497
498 ARP arpReply = (ARP) arpPacket.clone();
499 arpReply.setOpCode(ARP.OP_REPLY);
500
501 arpReply.setTargetProtocolAddress(arpPacket.getSenderProtocolAddress());
502 arpReply.setTargetHardwareAddress(arpPacket.getSenderHardwareAddress());
503 arpReply.setSenderProtocolAddress(arpPacket.getTargetProtocolAddress());
504 arpReply.setSenderHardwareAddress(myMAC.toBytes());
505
506 // Ethernet Frame.
507 Ethernet ethReply = new Ethernet();
508 ethReply.setSourceMACAddress(myMAC);
509 ethReply.setDestinationMACAddress(packet.getSourceMAC());
510 ethReply.setEtherType(Ethernet.TYPE_ARP);
511 ethReply.setVlanID(packet.getVlanID());
512
513 ethReply.setPayload(arpReply);
514 sendReply(context, ethReply);
515 }
516
517 /**
518 * Integrates hosts learned through DHCP into topology.
519 * @param context context of the incoming message
520 * @param ipAssigned IP Address assigned to the host by DHCP Manager
521 */
522 private void discoverHost(PacketContext context, Ip4Address ipAssigned) {
523 Ethernet packet = context.inPacket().parsed();
524 MacAddress mac = packet.getSourceMAC();
525 VlanId vlanId = VlanId.vlanId(packet.getVlanID());
526 HostLocation hostLocation = new HostLocation(context.inPacket().receivedFrom(), 0);
527
528 Set<IpAddress> ips = new HashSet<>();
529 ips.add(ipAssigned);
530
531 HostId hostId = HostId.hostId(mac, vlanId);
532 DefaultHostDescription desc = new DefaultHostDescription(mac, vlanId, hostLocation, ips);
533 hostProviderService.hostDetected(hostId, desc);
534 }
535
536
537 @Override
538 public void process(PacketContext context) {
samanwita palf28207b2015-09-04 10:41:56 -0700539 Ethernet packet = context.inPacket().parsed();
540 if (packet == null) {
541 return;
542 }
543
544 if (packet.getEtherType() == Ethernet.TYPE_IPV4) {
545 IPv4 ipv4Packet = (IPv4) packet.getPayload();
546
547 if (ipv4Packet.getProtocol() == IPv4.PROTOCOL_UDP) {
548 UDP udpPacket = (UDP) ipv4Packet.getPayload();
549
550 if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
551 udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
552 // This is meant for the dhcp server so process the packet here.
553
554 DHCP dhcpPayload = (DHCP) udpPacket.getPayload();
555 processDHCPPacket(context, dhcpPayload);
556 }
557 }
558 } else if (packet.getEtherType() == Ethernet.TYPE_ARP) {
559 ARP arpPacket = (ARP) packet.getPayload();
560
561 if ((arpPacket.getOpCode() == ARP.OP_REQUEST) &&
samanwita pal2a313402015-09-14 16:03:22 -0700562 (myIP).equals(Ip4Address.valueOf(arpPacket.getTargetProtocolAddress()))) {
samanwita palf28207b2015-09-04 10:41:56 -0700563
564 processARPPacket(context, packet);
565
566 }
567 }
568 }
569 }
570
571 private class InternalConfigListener implements NetworkConfigListener {
572
573 /**
574 * Reconfigures the DHCP Server according to the configuration parameters passed.
575 *
576 * @param cfg configuration object
577 */
Thomas Vachuskaa1da42e2015-09-09 00:45:22 -0700578 private void reconfigureNetwork(DhcpConfig cfg) {
Thomas Vachuska00090442015-09-11 18:08:04 -0700579 if (cfg == null) {
580 return;
581 }
samanwita palf28207b2015-09-04 10:41:56 -0700582 if (cfg.ip() != null) {
583 myIP = cfg.ip();
584 }
585 if (cfg.mac() != null) {
samanwita pal2a313402015-09-14 16:03:22 -0700586 myMAC = cfg.mac();
samanwita palf28207b2015-09-04 10:41:56 -0700587 }
588 if (cfg.subnetMask() != null) {
589 subnetMask = cfg.subnetMask();
590 }
591 if (cfg.broadcastAddress() != null) {
592 broadcastAddress = cfg.broadcastAddress();
593 }
594 if (cfg.routerAddress() != null) {
595 routerAddress = cfg.routerAddress();
596 }
597 if (cfg.domainServer() != null) {
598 domainServer = cfg.domainServer();
599 }
samanwita pal2a313402015-09-14 16:03:22 -0700600 if (cfg.ttl() != 0) {
601 packetTTL = (byte) cfg.ttl();
samanwita palf28207b2015-09-04 10:41:56 -0700602 }
samanwita pal2a313402015-09-14 16:03:22 -0700603 if (cfg.leaseTime() != 0) {
604 leaseTime = cfg.leaseTime();
samanwita palf28207b2015-09-04 10:41:56 -0700605 }
samanwita pal2a313402015-09-14 16:03:22 -0700606 if (cfg.renewTime() != 0) {
607 renewalTime = cfg.renewTime();
samanwita palf28207b2015-09-04 10:41:56 -0700608 }
samanwita pal2a313402015-09-14 16:03:22 -0700609 if (cfg.rebindTime() != 0) {
610 rebindingTime = cfg.rebindTime();
611 }
612 if (cfg.defaultTimeout() != 0) {
613 dhcpStore.setDefaultTimeoutForPurge(cfg.defaultTimeout());
614 }
615 if (cfg.timerDelay() != 0) {
616 timerDelay = cfg.timerDelay();
617 }
618 if ((cfg.startIp() != null) && (cfg.endIp() != null)) {
619 dhcpStore.populateIPPoolfromRange(cfg.startIp(), cfg.endIp());
samanwita palf28207b2015-09-04 10:41:56 -0700620 }
621 }
622
samanwita palf28207b2015-09-04 10:41:56 -0700623
624 @Override
625 public void event(NetworkConfigEvent event) {
626
627 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
samanwita pal2a313402015-09-14 16:03:22 -0700628 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
629 event.configClass().equals(DhcpConfig.class)) {
630
631 DhcpConfig cfg = cfgService.getConfig(appId, DhcpConfig.class);
632 reconfigureNetwork(cfg);
633 log.info("Reconfigured");
samanwita palf28207b2015-09-04 10:41:56 -0700634 }
635 }
636 }
637
638 private class InternalHostProvider extends AbstractProvider implements HostProvider {
639
640 /**
641 * Creates a provider with the supplier identifier.
642 */
643 protected InternalHostProvider() {
644 super(PID);
645 }
646
647 @Override
648 public void triggerProbe(Host host) {
649 // nothing to do
650 }
651 }
samanwita pal2a313402015-09-14 16:03:22 -0700652
653 private class PurgeListTask implements TimerTask {
654
655 @Override
656 public void run(Timeout to) {
657 IpAssignment ipAssignment;
658 Date dateNow = new Date();
659
660 Map<HostId, IpAssignment> ipAssignmentMap = dhcpStore.listMapping();
661 for (Map.Entry<HostId, IpAssignment> entry: ipAssignmentMap.entrySet()) {
662 ipAssignment = entry.getValue();
663
664 long timeLapsed = dateNow.getTime() - ipAssignment.timestamp().getTime();
665 if ((ipAssignment.assignmentStatus() != IpAssignment.AssignmentStatus.Option_Expired) &&
666 (ipAssignment.leasePeriod() > 0) && (timeLapsed > (ipAssignment.leasePeriodMs()))) {
667
668 dhcpStore.releaseIP(entry.getKey());
669 hostProviderService.hostVanished(entry.getKey());
670 }
671 }
672 timeout = Timer.getTimer().newTimeout(new PurgeListTask(), timerDelay, TimeUnit.MINUTES);
673 }
674 }
samanwita palf28207b2015-09-04 10:41:56 -0700675}