samanwita pal
Committed by Gerrit Code Review

Moving DHCP to onos branch. REST API included, GUI to be added later.

Change-Id: Id52781ba93d48ad1d56097a9ceff7613a190c48e
Showing 21 changed files with 2922 additions and 0 deletions
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + ~ Copyright 2014 Open Networking Laboratory
4 + ~
5 + ~ Licensed under the Apache License, Version 2.0 (the "License");
6 + ~ you may not use this file except in compliance with the License.
7 + ~ You may obtain a copy of the License at
8 + ~
9 + ~ http://www.apache.org/licenses/LICENSE-2.0
10 + ~
11 + ~ Unless required by applicable law or agreed to in writing, software
12 + ~ distributed under the License is distributed on an "AS IS" BASIS,
13 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + ~ See the License for the specific language governing permissions and
15 + ~ limitations under the License.
16 + --><project xmlns="http://maven.apache.org/POM/4.0.0"
17 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
18 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
19 + <modelVersion>4.0.0</modelVersion>
20 +
21 + <parent>
22 + <artifactId>onos-apps</artifactId>
23 + <groupId>org.onosproject</groupId>
24 + <version>1.3.0-SNAPSHOT</version>
25 + <relativePath>../pom.xml</relativePath>
26 + </parent>
27 +
28 + <artifactId>onos-app-dhcp</artifactId>
29 + <packaging>bundle</packaging>
30 +
31 + <url>http://onosproject.org</url>
32 +
33 + <description>DHCP Server application</description>
34 +
35 + <properties>
36 + <onos.app.name>org.onosproject.dhcp</onos.app.name>
37 + <web.context>/onos/dhcp</web.context>
38 + <api.version>1.0.0</api.version>
39 + <api.title>DHCP Server REST API</api.title>
40 + <api.description>
41 + APIs for interacting with the DHCP Server application.
42 + </api.description>
43 + <api.package>org.onosproject.dhcp.rest</api.package>
44 + </properties>
45 +
46 + <dependencies>
47 + <dependency>
48 + <groupId>org.osgi</groupId>
49 + <artifactId>org.osgi.compendium</artifactId>
50 + </dependency>
51 +
52 + <dependency>
53 + <groupId>org.onosproject</groupId>
54 + <artifactId>onos-cli</artifactId>
55 + <version>${project.version}</version>
56 + </dependency>
57 +
58 + <dependency>
59 + <groupId>org.apache.karaf.shell</groupId>
60 + <artifactId>org.apache.karaf.shell.console</artifactId>
61 + <scope>compile</scope>
62 + </dependency>
63 +
64 + <dependency>
65 + <groupId>org.onosproject</groupId>
66 + <artifactId>onlab-junit</artifactId>
67 + <scope>test</scope>
68 + </dependency>
69 + <dependency>
70 + <groupId>org.onosproject</groupId>
71 + <artifactId>onos-core-serializers</artifactId>
72 + <version>${project.version}</version>
73 + </dependency>
74 +
75 + <dependency>
76 + <groupId>org.onosproject</groupId>
77 + <artifactId>onos-incubator-api</artifactId>
78 + <version>${project.version}</version>
79 + </dependency>
80 + <dependency>
81 + <groupId>org.onosproject</groupId>
82 + <artifactId>onos-api</artifactId>
83 + <version>${project.version}</version>
84 + <classifier>tests</classifier>
85 + <scope>test</scope>
86 + </dependency>
87 +
88 + <dependency>
89 + <groupId>org.onosproject</groupId>
90 + <artifactId>onos-rest</artifactId>
91 + <version>${project.version}</version>
92 + </dependency>
93 + <dependency>
94 + <groupId>org.onosproject</groupId>
95 + <artifactId>onlab-rest</artifactId>
96 + <version>${project.version}</version>
97 + </dependency>
98 + <dependency>
99 + <groupId>javax.ws.rs</groupId>
100 + <artifactId>jsr311-api</artifactId>
101 + <version>1.1.1</version>
102 + </dependency>
103 + <dependency>
104 + <groupId>com.sun.jersey</groupId>
105 + <artifactId>jersey-servlet</artifactId>
106 + </dependency>
107 + <dependency>
108 + <groupId>com.fasterxml.jackson.core</groupId>
109 + <artifactId>jackson-databind</artifactId>
110 + </dependency>
111 +
112 + <dependency>
113 + <groupId>com.fasterxml.jackson.core</groupId>
114 + <artifactId>jackson-annotations</artifactId>
115 + </dependency>
116 + </dependencies>
117 +
118 + <build>
119 + <plugins>
120 + <plugin>
121 + <groupId>org.apache.felix</groupId>
122 + <artifactId>maven-bundle-plugin</artifactId>
123 + <extensions>true</extensions>
124 + <configuration>
125 + <instructions>
126 + <_wab>src/main/webapp/</_wab>
127 + <Include-Resource>
128 + WEB-INF/classes/apidoc/swagger.json=target/swagger.json,
129 + {maven-resources}
130 + </Include-Resource>
131 + <Bundle-SymbolicName>
132 + ${project.groupId}.${project.artifactId}
133 + </Bundle-SymbolicName>
134 + <Import-Package>
135 + org.slf4j,
136 + org.osgi.framework,
137 + javax.ws.rs,
138 + javax.ws.rs.core,
139 + com.sun.jersey.api.core,
140 + com.sun.jersey.spi.container.servlet,
141 + com.sun.jersey.server.impl.container.servlet,
142 + com.fasterxml.jackson.databind,
143 + com.fasterxml.jackson.databind.node,
144 + com.fasterxml.jackson.core,
145 + org.apache.karaf.shell.commands,
146 + org.apache.karaf.shell.console,
147 + com.google.common.*,
148 + org.onlab.packet.*,
149 + org.onlab.rest.*,
150 + org.onosproject.*,
151 + org.onlab.util.*,
152 + org.jboss.netty.util.*
153 + </Import-Package>
154 + <Web-ContextPath>${web.context}</Web-ContextPath>
155 + </instructions>
156 + </configuration>
157 + </plugin>
158 + </plugins>
159 + </build>
160 +
161 +</project>
1 +/*
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 + */
16 +package org.onosproject.dhcp;
17 +
18 +import org.onlab.packet.Ip4Address;
19 +import org.onlab.packet.MacAddress;
20 +
21 +import java.util.Map;
22 +
23 +/**
24 + * DHCP Service Interface.
25 + */
26 +public interface DHCPService {
27 +
28 + /**
29 + * Returns a collection of all the MacAddress to IPAddress mapping.
30 + *
31 + * @return collection of mappings.
32 + */
33 + Map<MacAddress, Ip4Address> listMapping();
34 +
35 + /**
36 + * Returns the default lease time granted by the DHCP Server.
37 + *
38 + * @return lease time
39 + */
40 + int getLeaseTime();
41 +
42 + /**
43 + * Returns the default renewal time granted by the DHCP Server.
44 + *
45 + * @return renewal time
46 + */
47 + int getRenewalTime();
48 +
49 + /**
50 + * Returns the default rebinding time granted by the DHCP Server.
51 + *
52 + * @return rebinding time
53 + */
54 + int getRebindingTime();
55 +
56 + /**
57 + * Registers a static IP mapping with the DHCP Server.
58 + *
59 + * @param macID macID of the client
60 + * @param ipAddress IP Address requested for the client
61 + * @return true if the mapping was successfully registered, false otherwise
62 + */
63 + boolean setStaticMapping(MacAddress macID, Ip4Address ipAddress);
64 +
65 + /**
66 + * Removes a static IP mapping with the DHCP Server.
67 + *
68 + * @param macID macID of the client
69 + * @return true if the mapping was successfully removed, false otherwise
70 + */
71 + boolean removeStaticMapping(MacAddress macID);
72 +
73 + /**
74 + * Returns the list of all the available IPs with the server.
75 + *
76 + * @return list of available IPs
77 + */
78 + Iterable<Ip4Address> getAvailableIPs();
79 +
80 +}
1 +/*
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 + */
16 +package org.onosproject.dhcp;
17 +
18 +import org.onlab.packet.Ip4Address;
19 +import org.onlab.packet.MacAddress;
20 +
21 +import java.util.Map;
22 +
23 +/**
24 + * DHCPStore Interface.
25 + */
26 +public interface DHCPStore {
27 +
28 + /**
29 + * Appends all the IPs in a given range to the free pool of IPs.
30 + *
31 + * @param startIP Start IP for the range
32 + * @param endIP End IP for the range
33 + */
34 + void populateIPPoolfromRange(Ip4Address startIP, Ip4Address endIP);
35 +
36 + /**
37 + * Returns an IP Address for a Mac ID, in response to a DHCP DISCOVER message.
38 + *
39 + * @param macID Mac ID of the client requesting an IP
40 + * @return IP address assigned to the Mac ID
41 + */
42 + Ip4Address suggestIP(MacAddress macID, Ip4Address requestedIP);
43 +
44 + /**
45 + * Assigns the requested IP to the Mac ID, in response to a DHCP REQUEST message.
46 + *
47 + * @param macID Mac Id of the client requesting an IP
48 + * @param ipAddr IP Address being requested
49 + * @param leaseTime Lease time offered by the server for this mapping
50 + * @return returns true if the assignment was successful, false otherwise
51 + */
52 + boolean assignIP(MacAddress macID, Ip4Address ipAddr, int leaseTime);
53 +
54 + /**
55 + * Sets the default time for which suggested IP mappings are valid.
56 + *
57 + * @param timeInSeconds default time for IP mappings to be valid
58 + */
59 + void setDefaultTimeoutForPurge(int timeInSeconds);
60 +
61 + /**
62 + * Sets the delay after which the dhcp server will purge expired entries.
63 + *
64 + * @param timeInSeconds default time
65 + */
66 + void setTimerDelay(int timeInSeconds);
67 +
68 + /**
69 + * Releases the IP assigned to a Mac ID into the free pool.
70 + *
71 + * @param macID the macID for which the mapping needs to be changed
72 + */
73 + void releaseIP(MacAddress macID);
74 +
75 + /**
76 + * Returns a collection of all the MacAddress to IPAddress mapping.
77 + *
78 + * @return the collection of the mappings
79 + */
80 + Map<MacAddress, Ip4Address> listMapping();
81 +
82 + /**
83 + * Assigns the requested IP to the MAC ID (if available) for an indefinite period of time.
84 + *
85 + * @param macID macID of the client
86 + * @param ipAddr IP Address requested for the client
87 + * @return true if the mapping was successfully registered, false otherwise
88 + */
89 + boolean assignStaticIP(MacAddress macID, Ip4Address ipAddr);
90 +
91 + /**
92 + * Removes a static IP mapping associated with the given MAC ID from the DHCP Server.
93 + *
94 + * @param macID macID of the client
95 + * @return true if the mapping was successfully registered, false otherwise
96 + */
97 + boolean removeStaticIP(MacAddress macID);
98 +
99 + /**
100 + * Returns the list of all the available IPs with the server.
101 + *
102 + * @return list of available IPs
103 + */
104 + Iterable<Ip4Address> getAvailableIPs();
105 +
106 +}
1 +/*
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 + */
16 +package org.onosproject.dhcp;
17 +
18 +import com.google.common.base.MoreObjects;
19 +import org.onlab.packet.Ip4Address;
20 +
21 +import java.util.Date;
22 +
23 +import static com.google.common.base.Preconditions.checkNotNull;
24 +
25 +/**
26 + * Stores the MAC ID to IP Address mapping details.
27 + */
28 +public final class IPAssignment {
29 +
30 + private final Ip4Address ipAddress;
31 +
32 + private final Date timestamp;
33 +
34 + private final long leasePeriod;
35 +
36 + private final AssignmentStatus assignmentStatus;
37 +
38 + public enum AssignmentStatus {
39 + /**
40 + * IP has been requested by a host, but not assigned to it yet.
41 + */
42 + Option_Requested,
43 +
44 + /**
45 + * IP has been assigned to a host.
46 + */
47 + Option_Assigned,
48 +
49 + /**
50 + * IP mapping is no longer active.
51 + */
52 + Option_Expired;
53 + }
54 +
55 + /**
56 + * Constructor for IPAssignment, where the ipAddress, the lease period, the timestamp
57 + * and assignment status is supplied.
58 + *
59 + * @param ipAddress
60 + * @param leasePeriod
61 + * @param assignmentStatus
62 + */
63 + private IPAssignment(Ip4Address ipAddress,
64 + long leasePeriod,
65 + Date timestamp,
66 + AssignmentStatus assignmentStatus) {
67 + this.ipAddress = ipAddress;
68 + this.leasePeriod = leasePeriod;
69 + this.timestamp = timestamp;
70 + this.assignmentStatus = assignmentStatus;
71 + }
72 +
73 + /**
74 + * Returns the IP Address of the IP assignment.
75 + *
76 + * @return the IP address
77 + */
78 + public Ip4Address ipAddress() {
79 + return this.ipAddress;
80 + }
81 +
82 + /**
83 + * Returns the timestamp of the IP assignment.
84 + *
85 + * @return the timestamp
86 + */
87 + public Date timestamp() {
88 + return this.timestamp;
89 + }
90 +
91 + /**
92 + * Returns the assignment status of the IP assignment.
93 + *
94 + * @return the assignment status
95 + */
96 + public AssignmentStatus assignmentStatus() {
97 + return this.assignmentStatus;
98 + }
99 +
100 + /**
101 + * Returns the lease period of the IP assignment.
102 + *
103 + * @return the lease period
104 + */
105 + public int leasePeriod() {
106 + return (int) this.leasePeriod / 1000;
107 + }
108 +
109 + @Override
110 + public String toString() {
111 + return MoreObjects.toStringHelper(getClass())
112 + .add("ip", ipAddress)
113 + .add("timestamp", timestamp)
114 + .add("lease", leasePeriod)
115 + .add("assignmentStatus", assignmentStatus)
116 + .toString();
117 + }
118 +
119 + /**
120 + * Creates and returns a new builder instance.
121 + *
122 + * @return new builder
123 + */
124 + public static Builder builder() {
125 + return new Builder();
126 + }
127 +
128 + /**
129 + * Creates and returns a new builder instance that clones an existing IPAssignment.
130 + *
131 + * @return new builder
132 + */
133 + public static Builder builder(IPAssignment assignment) {
134 + return new Builder(assignment);
135 + }
136 +
137 + /**
138 + * IPAssignment Builder.
139 + */
140 + public static final class Builder {
141 +
142 + private Ip4Address ipAddress;
143 +
144 + private Date timeStamp;
145 +
146 + private long leasePeriod;
147 +
148 + private AssignmentStatus assignmentStatus;
149 +
150 + private Builder() {
151 +
152 + }
153 +
154 + private Builder(IPAssignment ipAssignment) {
155 + ipAddress = ipAssignment.ipAddress();
156 + timeStamp = ipAssignment.timestamp();
157 + leasePeriod = ipAssignment.leasePeriod() * 1000;
158 + assignmentStatus = ipAssignment.assignmentStatus();
159 + }
160 +
161 + public IPAssignment build() {
162 + validateInputs();
163 + return new IPAssignment(ipAddress,
164 + leasePeriod,
165 + timeStamp,
166 + assignmentStatus);
167 + }
168 +
169 + public Builder ipAddress(Ip4Address addr) {
170 + ipAddress = addr;
171 + return this;
172 + }
173 +
174 + public Builder timestamp(Date timestamp) {
175 + timeStamp = timestamp;
176 + return this;
177 + }
178 +
179 + public Builder leasePeriod(int leasePeriodinSeconds) {
180 + leasePeriod = leasePeriodinSeconds * 1000;
181 + return this;
182 + }
183 +
184 + public Builder assignmentStatus(AssignmentStatus status) {
185 + assignmentStatus = status;
186 + return this;
187 + }
188 +
189 + private void validateInputs() {
190 + checkNotNull(ipAddress, "IP Address must be specified");
191 + checkNotNull(assignmentStatus, "Assignment Status must be specified");
192 + checkNotNull(leasePeriod, "Lease Period must be specified");
193 + checkNotNull(timeStamp, "Timestamp must be specified");
194 +
195 + switch (assignmentStatus) {
196 + case Option_Requested:
197 + case Option_Assigned:
198 + case Option_Expired:
199 + break;
200 + default:
201 + throw new IllegalStateException("Unknown assignment status");
202 + }
203 + }
204 + }
205 +}
1 +/*
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 + */
16 +package org.onosproject.dhcp.cli;
17 +
18 +import org.apache.karaf.shell.commands.Command;
19 +import org.onosproject.cli.AbstractShellCommand;
20 +import org.onosproject.dhcp.DHCPService;
21 +
22 +/**
23 + * Lists all the default lease parameters offered by the DHCP Server.
24 + */
25 +@Command(scope = "onos", name = "dhcp-lease",
26 + description = "Lists all the default lease parameters offered by the DHCP Server")
27 +public class DHCPLeaseDetails extends AbstractShellCommand {
28 +
29 + private static final String DHCP_LEASE_FORMAT = "Lease Time: %ds\nRenewal Time: %ds\nRebinding Time: %ds";
30 +
31 + @Override
32 + protected void execute() {
33 +
34 + DHCPService dhcpService = AbstractShellCommand.get(DHCPService.class);
35 + int leaseTime = dhcpService.getLeaseTime();
36 + int renewTime = dhcpService.getRenewalTime();
37 + int rebindTime = dhcpService.getRebindingTime();
38 +
39 + print(DHCP_LEASE_FORMAT, leaseTime, renewTime, rebindTime);
40 + }
41 +}
1 +/*
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 + */
16 +package org.onosproject.dhcp.cli;
17 +
18 +import org.apache.karaf.shell.commands.Command;
19 +import org.onlab.packet.Ip4Address;
20 +import org.onlab.packet.MacAddress;
21 +import org.onosproject.cli.AbstractShellCommand;
22 +import org.onosproject.dhcp.DHCPService;
23 +
24 +import java.util.Map;
25 +
26 +/**
27 + * Lists all the MacAddress to IP Address mappings held by the DHCP Server.
28 + */
29 +@Command(scope = "onos", name = "dhcp-list",
30 + description = "Lists all the MAC to IP mappings held by the DHCP Server")
31 +public class DHCPListAllMappings extends AbstractShellCommand {
32 +
33 + private static final String DHCP_MAPPING_FORMAT = "MAC ID: %s -> IP ASSIGNED %s";
34 + @Override
35 + protected void execute() {
36 +
37 + DHCPService dhcpService = AbstractShellCommand.get(DHCPService.class);
38 + Map<MacAddress, Ip4Address> allocationMap = dhcpService.listMapping();
39 +
40 + for (Map.Entry<MacAddress, Ip4Address> entry : allocationMap.entrySet()) {
41 + print(DHCP_MAPPING_FORMAT, entry.getKey().toString(), entry.getValue().toString());
42 + }
43 + }
44 +}
1 +/*
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 + */
16 +package org.onosproject.dhcp.cli;
17 +
18 +import org.apache.karaf.shell.commands.Argument;
19 +import org.apache.karaf.shell.commands.Command;
20 +import org.onlab.packet.MacAddress;
21 +import org.onosproject.cli.AbstractShellCommand;
22 +import org.onosproject.dhcp.DHCPService;
23 +
24 +/**
25 + * Removes a static MAC Address to IP Mapping from the DHCP Server.
26 + */
27 +@Command(scope = "onos", name = "dhcp-remove-static-mapping",
28 + description = "Removes a static MAC Address to IP Mapping from the DHCP Server")
29 +public class DHCPRemoveStaticMapping extends AbstractShellCommand {
30 +
31 + @Argument(index = 0, name = "macAddr",
32 + description = "MAC Address of the client",
33 + required = true, multiValued = false)
34 + String macAddr = null;
35 +
36 + private static final String DHCP_SUCCESS = "Static Mapping Successfully Removed.";
37 + private static final String DHCP_FAILURE = "Static Mapping Removal Failed. " +
38 + "Either the mapping does not exist or it is not static.";
39 +
40 + @Override
41 + protected void execute() {
42 + DHCPService dhcpService = AbstractShellCommand.get(DHCPService.class);
43 +
44 + try {
45 + MacAddress macID = MacAddress.valueOf(macAddr);
46 + if (dhcpService.removeStaticMapping(macID)) {
47 + print(DHCP_SUCCESS);
48 + } else {
49 + print(DHCP_FAILURE);
50 + }
51 +
52 + } catch (IllegalArgumentException e) {
53 + print(e.getMessage());
54 + }
55 + }
56 +}
1 +/*
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 + */
16 +package org.onosproject.dhcp.cli;
17 +
18 +import org.apache.karaf.shell.commands.Argument;
19 +import org.apache.karaf.shell.commands.Command;
20 +import org.onlab.packet.Ip4Address;
21 +import org.onlab.packet.MacAddress;
22 +import org.onosproject.cli.AbstractShellCommand;
23 +import org.onosproject.dhcp.DHCPService;
24 +
25 +/**
26 + * Registers a static MAC Address to IP Mapping with the DHCP Server.
27 + */
28 +@Command(scope = "onos", name = "dhcp-set-static-mapping",
29 + description = "Registers a static MAC Address to IP Mapping with the DHCP Server")
30 +public class DHCPSetStaticMapping extends AbstractShellCommand {
31 +
32 + @Argument(index = 0, name = "macAddr",
33 + description = "MAC Address of the client",
34 + required = true, multiValued = false)
35 + String macAddr = null;
36 +
37 + @Argument(index = 1, name = "ipAddr",
38 + description = "IP Address requested for static mapping",
39 + required = true, multiValued = false)
40 + String ipAddr = null;
41 +
42 + private static final String DHCP_SUCCESS = "Static Mapping Successfully Added.";
43 + private static final String DHCP_FAILURE = "Static Mapping Failed. The IP maybe unavailable.";
44 + @Override
45 + protected void execute() {
46 + DHCPService dhcpService = AbstractShellCommand.get(DHCPService.class);
47 +
48 + try {
49 + MacAddress macID = MacAddress.valueOf(macAddr);
50 + Ip4Address ipAddress = Ip4Address.valueOf(ipAddr);
51 + if (dhcpService.setStaticMapping(macID, ipAddress)) {
52 + print(DHCP_SUCCESS);
53 + } else {
54 + print(DHCP_FAILURE);
55 + }
56 +
57 + } catch (IllegalArgumentException e) {
58 + print(e.getMessage());
59 + }
60 + }
61 +}
1 +/*
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 + */
16 +package org.onosproject.dhcp.cli;
17 +
18 +import org.apache.karaf.shell.console.Completer;
19 +import org.apache.karaf.shell.console.completer.StringsCompleter;
20 +import org.onlab.packet.Ip4Address;
21 +import org.onosproject.cli.AbstractShellCommand;
22 +import org.onosproject.dhcp.DHCPService;
23 +
24 +import java.util.Iterator;
25 +import java.util.List;
26 +import java.util.SortedSet;
27 +
28 +/**
29 + * Free IP Completer.
30 + */
31 +public class FreeIPCompleter implements Completer {
32 +
33 + @Override
34 + public int complete(String buffer, int cursor, List<String> candidates) {
35 + // Delegate string completer
36 + StringsCompleter delegate = new StringsCompleter();
37 + DHCPService dhcpService = AbstractShellCommand.get(DHCPService.class);
38 + Iterator<Ip4Address> it = dhcpService.getAvailableIPs().iterator();
39 + SortedSet<String> strings = delegate.getStrings();
40 +
41 + while (it.hasNext()) {
42 + strings.add(it.next().toString());
43 + }
44 +
45 + // Now let the completer do the work for figuring out what to offer.
46 + return delegate.complete(buffer, cursor, candidates);
47 + }
48 +}
1 +/*
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 + */
16 +package org.onosproject.dhcp.cli;
17 +
18 +import org.apache.karaf.shell.console.Completer;
19 +import org.apache.karaf.shell.console.completer.StringsCompleter;
20 +import org.onosproject.cli.AbstractShellCommand;
21 +import org.onosproject.net.Host;
22 +import org.onosproject.net.host.HostService;
23 +
24 +import java.util.Iterator;
25 +import java.util.List;
26 +import java.util.SortedSet;
27 +
28 +/**
29 + * MAC ID Completer.
30 + */
31 +public class MacIdCompleter implements Completer {
32 +
33 + @Override
34 + public int complete(String buffer, int cursor, List<String> candidates) {
35 + // Delegate string completer
36 + StringsCompleter delegate = new StringsCompleter();
37 + HostService service = AbstractShellCommand.get(HostService.class);
38 + Iterator<Host> it = service.getHosts().iterator();
39 + SortedSet<String> strings = delegate.getStrings();
40 +
41 + while (it.hasNext()) {
42 + strings.add(it.next().mac().toString());
43 + }
44 +
45 + // Now let the completer do the work for figuring out what to offer.
46 + return delegate.complete(buffer, cursor, candidates);
47 + }
48 +}
1 +/*
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 + */
16 +package org.onosproject.dhcp.impl;
17 +
18 +import org.onosproject.core.ApplicationId;
19 +import org.onosproject.net.config.Config;
20 +import org.onosproject.net.config.basics.BasicElementConfig;
21 +
22 +/**
23 + * DHCP Config class.
24 + */
25 +public class DHCPConfig extends Config<ApplicationId> {
26 +
27 + public static final String MY_IP = "ip";
28 + public static final String MY_MAC = "mac";
29 + public static final String SUBNET_MASK = "subnet";
30 + public static final String BROADCAST_ADDRESS = "broadcast";
31 + public static final String ROUTER_ADDRESS = "router";
32 + public static final String DOMAIN_SERVER = "domain";
33 + public static final String TTL = "ttl";
34 + public static final String LEASE_TIME = "lease";
35 + public static final String RENEW_TIME = "renew";
36 + public static final String REBIND_TIME = "rebind";
37 +
38 + /**
39 + * Returns the dhcp server ip.
40 + *
41 + * @return ip address or null if not set
42 + */
43 + public String ip() {
44 + return get(MY_IP, null);
45 + }
46 +
47 + /**
48 + * Sets the dhcp server ip.
49 + *
50 + * @param ip new ip address; null to clear
51 + * @return self
52 + */
53 + public BasicElementConfig ip(String ip) {
54 + return (BasicElementConfig) setOrClear(MY_IP, ip);
55 + }
56 +
57 + /**
58 + * Returns the dhcp server mac.
59 + *
60 + * @return server mac or null if not set
61 + */
62 + public String mac() {
63 + return get(MY_MAC, null);
64 + }
65 +
66 + /**
67 + * Sets the dhcp server mac.
68 + *
69 + * @param mac new mac address; null to clear
70 + * @return self
71 + */
72 + public BasicElementConfig mac(String mac) {
73 + return (BasicElementConfig) setOrClear(MY_MAC, mac);
74 + }
75 +
76 + /**
77 + * Returns the subnet mask.
78 + *
79 + * @return subnet mask or null if not set
80 + */
81 + public String subnetMask() {
82 + return get(SUBNET_MASK, null);
83 + }
84 +
85 + /**
86 + * Sets the subnet mask.
87 + *
88 + * @param subnet new subnet mask; null to clear
89 + * @return self
90 + */
91 + public BasicElementConfig subnetMask(String subnet) {
92 + return (BasicElementConfig) setOrClear(SUBNET_MASK, subnet);
93 + }
94 +
95 + /**
96 + * Returns the broadcast address.
97 + *
98 + * @return broadcast address or null if not set
99 + */
100 + public String broadcastAddress() {
101 + return get(BROADCAST_ADDRESS, null);
102 + }
103 +
104 + /**
105 + * Sets the broadcast address.
106 + *
107 + * @param broadcast new broadcast address; null to clear
108 + * @return self
109 + */
110 + public BasicElementConfig broadcastAddress(String broadcast) {
111 + return (BasicElementConfig) setOrClear(BROADCAST_ADDRESS, broadcast);
112 + }
113 +
114 + /**
115 + * Returns the Time To Live for the reply packets.
116 + *
117 + * @return ttl or null if not set
118 + */
119 + public String ttl() {
120 + return get(TTL, null);
121 + }
122 +
123 + /**
124 + * Sets the Time To Live for the reply packets.
125 + *
126 + * @param ttl new ttl; null to clear
127 + * @return self
128 + */
129 + public BasicElementConfig ttl(String ttl) {
130 + return (BasicElementConfig) setOrClear(TTL, ttl);
131 + }
132 +
133 + /**
134 + * Returns the Lease Time offered by the DHCP Server.
135 + *
136 + * @return lease time or null if not set
137 + */
138 + public String leaseTime() {
139 + return get(LEASE_TIME, null);
140 + }
141 +
142 + /**
143 + * Sets the Lease Time offered by the DHCP Server.
144 + *
145 + * @param lease new lease time; null to clear
146 + * @return self
147 + */
148 + public BasicElementConfig leaseTime(String lease) {
149 + return (BasicElementConfig) setOrClear(LEASE_TIME, lease);
150 + }
151 +
152 + /**
153 + * Returns the Renew Time offered by the DHCP Server.
154 + *
155 + * @return renew time or null if not set
156 + */
157 + public String renewTime() {
158 + return get(RENEW_TIME, null);
159 + }
160 +
161 + /**
162 + * Sets the Renew Time offered by the DHCP Server.
163 + *
164 + * @param renew new renew time; null to clear
165 + * @return self
166 + */
167 + public BasicElementConfig renewTime(String renew) {
168 + return (BasicElementConfig) setOrClear(RENEW_TIME, renew);
169 + }
170 +
171 + /**
172 + * Returns the Rebind Time offered by the DHCP Server.
173 + *
174 + * @return rebind time or null if not set
175 + */
176 + public String rebindTime() {
177 + return get(REBIND_TIME, null);
178 + }
179 +
180 + /**
181 + * Sets the Rebind Time offered by the DHCP Server.
182 + *
183 + * @param rebind new rebind time; null to clear
184 + * @return self
185 + */
186 + public BasicElementConfig rebindTime(String rebind) {
187 + return (BasicElementConfig) setOrClear(REBIND_TIME, rebind);
188 + }
189 +
190 + /**
191 + * Returns the Router Address.
192 + *
193 + * @return router address or null if not set
194 + */
195 + public String routerAddress() {
196 + return get(ROUTER_ADDRESS, null);
197 + }
198 +
199 + /**
200 + * Sets the Router Address.
201 + *
202 + * @param router new router address; null to clear
203 + * @return self
204 + */
205 + public BasicElementConfig routerAddress(String router) {
206 + return (BasicElementConfig) setOrClear(ROUTER_ADDRESS, router);
207 + }
208 +
209 + /**
210 + * Returns the Domain Server Address.
211 + *
212 + * @return domain server address or null if not set
213 + */
214 + public String domainServer() {
215 + return get(DOMAIN_SERVER, null);
216 + }
217 +
218 + /**
219 + * Sets the Domain Server Address.
220 + *
221 + * @param domain new domain server address; null to clear
222 + * @return self
223 + */
224 + public BasicElementConfig domainServer(String domain) {
225 + return (BasicElementConfig) setOrClear(DOMAIN_SERVER, domain);
226 + }
227 +}
1 +/*
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 + */
16 +package org.onosproject.dhcp.impl;
17 +
18 +import com.google.common.collect.ImmutableSet;
19 +import org.apache.felix.scr.annotations.Activate;
20 +import org.apache.felix.scr.annotations.Component;
21 +import org.apache.felix.scr.annotations.Deactivate;
22 +import org.apache.felix.scr.annotations.Reference;
23 +import org.apache.felix.scr.annotations.ReferenceCardinality;
24 +import org.apache.felix.scr.annotations.Service;
25 +import org.onlab.packet.ARP;
26 +import org.onlab.packet.DHCP;
27 +import org.onlab.packet.DHCPOption;
28 +import org.onlab.packet.Ethernet;
29 +import org.onlab.packet.IPv4;
30 +import org.onlab.packet.Ip4Address;
31 +import org.onlab.packet.IpAddress;
32 +import org.onlab.packet.MacAddress;
33 +import org.onlab.packet.TpPort;
34 +import org.onlab.packet.UDP;
35 +import org.onlab.packet.VlanId;
36 +import org.onosproject.core.ApplicationId;
37 +import org.onosproject.core.CoreService;
38 +import org.onosproject.dhcp.DHCPService;
39 +import org.onosproject.dhcp.DHCPStore;
40 +import org.onosproject.net.config.ConfigFactory;
41 +import org.onosproject.net.config.NetworkConfigEvent;
42 +import org.onosproject.net.config.NetworkConfigListener;
43 +import org.onosproject.net.config.NetworkConfigRegistry;
44 +
45 +import org.onosproject.net.ConnectPoint;
46 +import org.onosproject.net.Host;
47 +import org.onosproject.net.HostId;
48 +import org.onosproject.net.HostLocation;
49 +import org.onosproject.net.flow.DefaultTrafficSelector;
50 +import org.onosproject.net.flow.DefaultTrafficTreatment;
51 +import org.onosproject.net.flow.TrafficSelector;
52 +import org.onosproject.net.flow.TrafficTreatment;
53 +import org.onosproject.net.host.DefaultHostDescription;
54 +import org.onosproject.net.host.HostProvider;
55 +import org.onosproject.net.host.HostProviderRegistry;
56 +import org.onosproject.net.host.HostProviderService;
57 +import org.onosproject.net.packet.DefaultOutboundPacket;
58 +import org.onosproject.net.packet.PacketContext;
59 +import org.onosproject.net.packet.PacketPriority;
60 +import org.onosproject.net.packet.PacketProcessor;
61 +import org.onosproject.net.packet.PacketService;
62 +import org.onosproject.net.provider.AbstractProvider;
63 +import org.onosproject.net.provider.ProviderId;
64 +import org.slf4j.Logger;
65 +import org.slf4j.LoggerFactory;
66 +
67 +import java.nio.ByteBuffer;
68 +import java.util.ArrayList;
69 +import java.util.HashSet;
70 +import java.util.List;
71 +import java.util.Map;
72 +import java.util.Set;
73 +
74 +import static org.onlab.packet.MacAddress.valueOf;
75 +import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
76 +
77 +/**
78 + * Skeletal ONOS DHCP Server application.
79 + */
80 +@Component(immediate = true)
81 +@Service
82 +public class DHCPManager implements DHCPService {
83 +
84 + private static final ProviderId PID = new ProviderId("of", "org.onosproject.dhcp", true);
85 + private final Logger log = LoggerFactory.getLogger(getClass());
86 +
87 + private final NetworkConfigListener cfgListener = new InternalConfigListener();
88 +
89 + private final Set<ConfigFactory> factories = ImmutableSet.of(
90 + new ConfigFactory<ApplicationId, DHCPConfig>(APP_SUBJECT_FACTORY,
91 + DHCPConfig.class,
92 + "dhcp") {
93 + @Override
94 + public DHCPConfig createConfig() {
95 + return new DHCPConfig();
96 + }
97 + },
98 + new ConfigFactory<ApplicationId, DHCPStoreConfig>(APP_SUBJECT_FACTORY,
99 + DHCPStoreConfig.class,
100 + "dhcpstore") {
101 + @Override
102 + public DHCPStoreConfig createConfig() {
103 + return new DHCPStoreConfig();
104 + }
105 + }
106 + );
107 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 + protected NetworkConfigRegistry cfgService;
109 +
110 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 + protected PacketService packetService;
112 +
113 + private DHCPPacketProcessor processor = new DHCPPacketProcessor();
114 +
115 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
116 + protected CoreService coreService;
117 +
118 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
119 + protected DHCPStore dhcpStore;
120 +
121 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
122 + protected HostProviderRegistry hostProviderRegistry;
123 +
124 + protected HostProviderService hostProviderService;
125 +
126 + private ApplicationId appId;
127 +
128 + // Hardcoded values are default values.
129 +
130 + private static String myIP = "10.0.0.2";
131 +
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 +
148 + private static String subnetMask = "255.0.0.0";
149 +
150 + private static String broadcastAddress = "10.255.255.255";
151 +
152 + private static String routerAddress = "10.0.0.2";
153 +
154 + private static String domainServer = "10.0.0.2";
155 + private final HostProvider hostProvider = new InternalHostProvider();
156 +
157 + @Activate
158 + protected void activate() {
159 + // start the dhcp server
160 + appId = coreService.registerApplication("org.onosproject.dhcp");
161 +
162 + cfgService.addListener(cfgListener);
163 + factories.forEach(cfgService::registerConfigFactory);
164 + hostProviderService = hostProviderRegistry.register(hostProvider);
165 + packetService.addProcessor(processor, PacketProcessor.observer(1));
166 + requestPackets();
167 + log.info("Started");
168 + }
169 +
170 + @Deactivate
171 + protected void deactivate() {
172 + cfgService.removeListener(cfgListener);
173 + factories.forEach(cfgService::unregisterConfigFactory);
174 + packetService.removeProcessor(processor);
175 + hostProviderRegistry.unregister(hostProvider);
176 + hostProviderService = null;
177 + cancelPackets();
178 + log.info("Stopped");
179 + }
180 +
181 + /**
182 + * Request packet in via PacketService.
183 + */
184 + private void requestPackets() {
185 +
186 + TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
187 + .matchEthType(Ethernet.TYPE_IPV4)
188 + .matchIPProtocol(IPv4.PROTOCOL_UDP)
189 + .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
190 + .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT));
191 + packetService.requestPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
192 +
193 + selectorServer = DefaultTrafficSelector.builder()
194 + .matchEthType(Ethernet.TYPE_ARP);
195 + packetService.requestPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
196 + }
197 +
198 + /**
199 + * Cancel requested packets in via packet service.
200 + */
201 + private void cancelPackets() {
202 + TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
203 + .matchEthType(Ethernet.TYPE_IPV4)
204 + .matchIPProtocol(IPv4.PROTOCOL_UDP)
205 + .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
206 + .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT));
207 + packetService.cancelPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
208 +
209 + selectorServer = DefaultTrafficSelector.builder()
210 + .matchEthType(Ethernet.TYPE_ARP);
211 + packetService.cancelPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
212 + }
213 +
214 + @Override
215 + public Map<MacAddress, Ip4Address> listMapping() {
216 +
217 + return dhcpStore.listMapping();
218 + }
219 +
220 + @Override
221 + public int getLeaseTime() {
222 + return leaseTime;
223 + }
224 +
225 + @Override
226 + public int getRenewalTime() {
227 + return renewalTime;
228 + }
229 +
230 + @Override
231 + public int getRebindingTime() {
232 + return rebindingTime;
233 + }
234 +
235 + @Override
236 + public boolean setStaticMapping(MacAddress macID, Ip4Address ipAddress) {
237 + return dhcpStore.assignStaticIP(macID, ipAddress);
238 + }
239 +
240 + @Override
241 + public boolean removeStaticMapping(MacAddress macID) {
242 + return dhcpStore.removeStaticIP(macID);
243 + }
244 +
245 + @Override
246 + public Iterable<Ip4Address> getAvailableIPs() {
247 + return dhcpStore.getAvailableIPs();
248 + }
249 +
250 + private class DHCPPacketProcessor implements PacketProcessor {
251 +
252 + /**
253 + * Builds the DHCP Reply packet.
254 + *
255 + * @param packet the incoming Ethernet frame
256 + * @param ipOffered the IP offered by the DHCP Server
257 + * @param outgoingMessageType the message type of the outgoing packet
258 + * @return the Ethernet reply frame
259 + */
260 + private Ethernet buildReply(Ethernet packet, String ipOffered, byte outgoingMessageType) {
261 + Ip4Address myIPAddress = Ip4Address.valueOf(myIP);
262 + Ip4Address ipAddress;
263 +
264 + // Ethernet Frame.
265 + Ethernet ethReply = new Ethernet();
266 + ethReply.setSourceMACAddress(myMAC);
267 + ethReply.setDestinationMACAddress(packet.getSourceMAC());
268 + ethReply.setEtherType(Ethernet.TYPE_IPV4);
269 + ethReply.setVlanID(packet.getVlanID());
270 +
271 + // IP Packet
272 + IPv4 ipv4Packet = (IPv4) packet.getPayload();
273 + IPv4 ipv4Reply = new IPv4();
274 + ipv4Reply.setSourceAddress(myIPAddress.toInt());
275 + ipAddress = Ip4Address.valueOf(ipOffered);
276 + ipv4Reply.setDestinationAddress(ipAddress.toInt());
277 + ipv4Reply.setTtl(packetTTL);
278 +
279 + // UDP Datagram.
280 + UDP udpPacket = (UDP) ipv4Packet.getPayload();
281 + UDP udpReply = new UDP();
282 + udpReply.setSourcePort((byte) UDP.DHCP_SERVER_PORT);
283 + udpReply.setDestinationPort((byte) UDP.DHCP_CLIENT_PORT);
284 +
285 + // DHCP Payload.
286 + DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
287 + DHCP dhcpReply = new DHCP();
288 + dhcpReply.setOpCode(DHCP.OPCODE_REPLY);
289 +
290 + ipAddress = Ip4Address.valueOf(ipOffered);
291 + dhcpReply.setYourIPAddress(ipAddress.toInt());
292 + dhcpReply.setServerIPAddress(myIPAddress.toInt());
293 +
294 + dhcpReply.setTransactionId(dhcpPacket.getTransactionId());
295 + dhcpReply.setClientHardwareAddress(dhcpPacket.getClientHardwareAddress());
296 + dhcpReply.setHardwareType(DHCP.HWTYPE_ETHERNET);
297 + dhcpReply.setHardwareAddressLength((byte) 6);
298 +
299 + // DHCP Options.
300 + DHCPOption option = new DHCPOption();
301 + List<DHCPOption> optionList = new ArrayList<>();
302 +
303 + // DHCP Message Type.
304 + option.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
305 + option.setLength((byte) 1);
306 + byte[] optionData = {outgoingMessageType};
307 + option.setData(optionData);
308 + optionList.add(option);
309 +
310 + // DHCP Server Identifier.
311 + option = new DHCPOption();
312 + option.setCode(DHCP.DHCPOptionCode.OptionCode_DHCPServerIp.getValue());
313 + option.setLength((byte) 4);
314 + option.setData(myIPAddress.toOctets());
315 + optionList.add(option);
316 +
317 + // IP Address Lease Time.
318 + option = new DHCPOption();
319 + option.setCode(DHCP.DHCPOptionCode.OptionCode_LeaseTime.getValue());
320 + option.setLength((byte) 4);
321 + option.setData(ByteBuffer.allocate(4).putInt(leaseTime).array());
322 + optionList.add(option);
323 +
324 + // IP Address Renewal Time.
325 + option = new DHCPOption();
326 + option.setCode(DHCP.DHCPOptionCode.OptionCode_RenewalTime.getValue());
327 + option.setLength((byte) 4);
328 + option.setData(ByteBuffer.allocate(4).putInt(renewalTime).array());
329 + optionList.add(option);
330 +
331 + // IP Address Rebinding Time.
332 + option = new DHCPOption();
333 + option.setCode(DHCP.DHCPOptionCode.OPtionCode_RebindingTime.getValue());
334 + option.setLength((byte) 4);
335 + option.setData(ByteBuffer.allocate(4).putInt(rebindingTime).array());
336 + optionList.add(option);
337 +
338 + // Subnet Mask.
339 + option = new DHCPOption();
340 + option.setCode(DHCP.DHCPOptionCode.OptionCode_SubnetMask.getValue());
341 + option.setLength((byte) 4);
342 + ipAddress = Ip4Address.valueOf(subnetMask);
343 + option.setData(ipAddress.toOctets());
344 + optionList.add(option);
345 +
346 + // Broadcast Address.
347 + option = new DHCPOption();
348 + option.setCode(DHCP.DHCPOptionCode.OptionCode_BroadcastAddress.getValue());
349 + option.setLength((byte) 4);
350 + ipAddress = Ip4Address.valueOf(broadcastAddress);
351 + option.setData(ipAddress.toOctets());
352 + optionList.add(option);
353 +
354 + // Router Address.
355 + option = new DHCPOption();
356 + option.setCode(DHCP.DHCPOptionCode.OptionCode_RouterAddress.getValue());
357 + option.setLength((byte) 4);
358 + ipAddress = Ip4Address.valueOf(routerAddress);
359 + option.setData(ipAddress.toOctets());
360 + 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);
366 + ipAddress = Ip4Address.valueOf(domainServer);
367 + option.setData(ipAddress.toOctets());
368 + optionList.add(option);
369 +
370 + // End Option.
371 + option = new DHCPOption();
372 + option.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
373 + option.setLength((byte) 1);
374 + optionList.add(option);
375 +
376 + dhcpReply.setOptions(optionList);
377 +
378 + udpReply.setPayload(dhcpReply);
379 + ipv4Reply.setPayload(udpReply);
380 + ethReply.setPayload(ipv4Reply);
381 +
382 + return ethReply;
383 + }
384 +
385 + /**
386 + * Sends the Ethernet reply frame via the Packet Service.
387 + *
388 + * @param context the context of the incoming frame
389 + * @param reply the Ethernet reply frame
390 + */
391 + private void sendReply(PacketContext context, Ethernet reply) {
392 + if (reply != null) {
393 + TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
394 + ConnectPoint sourcePoint = context.inPacket().receivedFrom();
395 + builder.setOutput(sourcePoint.port());
396 +
397 + packetService.emit(new DefaultOutboundPacket(sourcePoint.deviceId(),
398 + builder.build(), ByteBuffer.wrap(reply.serialize())));
399 + }
400 + }
401 +
402 + /**
403 + * Processes the DHCP Payload and initiates a reply to the client.
404 + *
405 + * @param context context of the incoming message
406 + * @param dhcpPayload the extracted DHCP payload
407 + */
408 + private void processDHCPPacket(PacketContext context, DHCP dhcpPayload) {
409 +
410 + Ethernet packet = context.inPacket().parsed();
411 + boolean flagIfRequestedIP = false;
412 + boolean flagIfServerIP = false;
413 + Ip4Address requestedIP = Ip4Address.valueOf("0.0.0.0");
414 + Ip4Address serverIP = Ip4Address.valueOf("0.0.0.0");
415 +
416 + if (dhcpPayload != null) {
417 +
418 + // TODO Convert this to enum value.
419 + byte incomingPacketType = 0;
420 + for (DHCPOption option : dhcpPayload.getOptions()) {
421 + if (option.getCode() == DHCP.DHCPOptionCode.OptionCode_MessageType.getValue()) {
422 + byte[] data = option.getData();
423 + incomingPacketType = data[0];
424 + }
425 + if (option.getCode() == DHCP.DHCPOptionCode.OptionCode_RequestedIP.getValue()) {
426 + byte[] data = option.getData();
427 + requestedIP = Ip4Address.valueOf(data);
428 + flagIfRequestedIP = true;
429 + }
430 + if (option.getCode() == DHCP.DHCPOptionCode.OptionCode_DHCPServerIp.getValue()) {
431 + byte[] data = option.getData();
432 + serverIP = Ip4Address.valueOf(data);
433 + flagIfServerIP = true;
434 + }
435 + }
436 +
437 + String ipOffered = "";
438 + DHCP.DHCPMessageType outgoingPacketType;
439 + MacAddress clientMAC = new MacAddress(dhcpPayload.getClientHardwareAddress());
440 +
441 + if (incomingPacketType == DHCP.DHCPMessageType.MessageType_Discover.getValue()) {
442 +
443 + outgoingPacketType = DHCP.DHCPMessageType.MessageType_Offer;
444 + ipOffered = dhcpStore.suggestIP(clientMAC, requestedIP).toString();
445 +
446 + Ethernet ethReply = buildReply(packet, ipOffered, outgoingPacketType.getValue());
447 + sendReply(context, ethReply);
448 +
449 + } else if (incomingPacketType == DHCP.DHCPMessageType.MessageType_Request.getValue()) {
450 +
451 + outgoingPacketType = DHCP.DHCPMessageType.MessageType_ACK;
452 +
453 + if (flagIfServerIP && flagIfRequestedIP) {
454 + // SELECTING state
455 + if (myIP.equals(serverIP.toString()) &&
456 + dhcpStore.assignIP(clientMAC, requestedIP, leaseTime)) {
457 +
458 + Ethernet ethReply = buildReply(packet, requestedIP.toString(),
459 + outgoingPacketType.getValue());
460 + sendReply(context, ethReply);
461 + discoverHost(context, requestedIP);
462 + }
463 + } else if (flagIfRequestedIP) {
464 + // INIT-REBOOT state
465 + if (dhcpStore.assignIP(clientMAC, requestedIP, leaseTime)) {
466 + Ethernet ethReply = buildReply(packet, requestedIP.toString(),
467 + outgoingPacketType.getValue());
468 + sendReply(context, ethReply);
469 + discoverHost(context, requestedIP);
470 + }
471 + } else {
472 + // RENEWING and REBINDING state
473 + int ciaadr = dhcpPayload.getClientIPAddress();
474 + if (ciaadr != 0) {
475 + Ip4Address clientIaddr = Ip4Address.valueOf(ciaadr);
476 + if (dhcpStore.assignIP(clientMAC, clientIaddr, leaseTime)) {
477 + Ethernet ethReply = buildReply(packet, clientIaddr.toString(),
478 + outgoingPacketType.getValue());
479 + sendReply(context, ethReply);
480 + discoverHost(context, clientIaddr);
481 + }
482 + }
483 + }
484 + } else if (incomingPacketType == DHCP.DHCPMessageType.MessageType_Release.getValue()) {
485 +
486 + dhcpStore.releaseIP(clientMAC);
487 + }
488 + }
489 + }
490 +
491 + /**
492 + * Processes the ARP Payload and initiates a reply to the client.
493 + *
494 + * @param context context of the incoming message
495 + * @param packet the ethernet payload
496 + */
497 + private void processARPPacket(PacketContext context, Ethernet packet) {
498 +
499 + ARP arpPacket = (ARP) packet.getPayload();
500 +
501 + ARP arpReply = (ARP) arpPacket.clone();
502 + arpReply.setOpCode(ARP.OP_REPLY);
503 +
504 + arpReply.setTargetProtocolAddress(arpPacket.getSenderProtocolAddress());
505 + arpReply.setTargetHardwareAddress(arpPacket.getSenderHardwareAddress());
506 + arpReply.setSenderProtocolAddress(arpPacket.getTargetProtocolAddress());
507 + arpReply.setSenderHardwareAddress(myMAC.toBytes());
508 +
509 + // Ethernet Frame.
510 + Ethernet ethReply = new Ethernet();
511 + ethReply.setSourceMACAddress(myMAC);
512 + ethReply.setDestinationMACAddress(packet.getSourceMAC());
513 + ethReply.setEtherType(Ethernet.TYPE_ARP);
514 + ethReply.setVlanID(packet.getVlanID());
515 +
516 + ethReply.setPayload(arpReply);
517 + sendReply(context, ethReply);
518 + }
519 +
520 + /**
521 + * Integrates hosts learned through DHCP into topology.
522 + * @param context context of the incoming message
523 + * @param ipAssigned IP Address assigned to the host by DHCP Manager
524 + */
525 + private void discoverHost(PacketContext context, Ip4Address ipAssigned) {
526 + Ethernet packet = context.inPacket().parsed();
527 + MacAddress mac = packet.getSourceMAC();
528 + VlanId vlanId = VlanId.vlanId(packet.getVlanID());
529 + HostLocation hostLocation = new HostLocation(context.inPacket().receivedFrom(), 0);
530 +
531 + Set<IpAddress> ips = new HashSet<>();
532 + ips.add(ipAssigned);
533 +
534 + HostId hostId = HostId.hostId(mac, vlanId);
535 + DefaultHostDescription desc = new DefaultHostDescription(mac, vlanId, hostLocation, ips);
536 + hostProviderService.hostDetected(hostId, desc);
537 + }
538 +
539 +
540 + @Override
541 + public void process(PacketContext context) {
542 +
543 + Ethernet packet = context.inPacket().parsed();
544 + if (packet == null) {
545 + return;
546 + }
547 +
548 + if (packet.getEtherType() == Ethernet.TYPE_IPV4) {
549 + IPv4 ipv4Packet = (IPv4) packet.getPayload();
550 +
551 + if (ipv4Packet.getProtocol() == IPv4.PROTOCOL_UDP) {
552 + UDP udpPacket = (UDP) ipv4Packet.getPayload();
553 +
554 + if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
555 + udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
556 + // This is meant for the dhcp server so process the packet here.
557 +
558 + DHCP dhcpPayload = (DHCP) udpPacket.getPayload();
559 + processDHCPPacket(context, dhcpPayload);
560 + }
561 + }
562 + } else if (packet.getEtherType() == Ethernet.TYPE_ARP) {
563 + ARP arpPacket = (ARP) packet.getPayload();
564 +
565 + if ((arpPacket.getOpCode() == ARP.OP_REQUEST) &&
566 + (Ip4Address.valueOf(arpPacket.getTargetProtocolAddress()).toString().equals(myIP))) {
567 +
568 + processARPPacket(context, packet);
569 +
570 + }
571 + }
572 + }
573 + }
574 +
575 + private class InternalConfigListener implements NetworkConfigListener {
576 +
577 + /**
578 + * Reconfigures the DHCP Server according to the configuration parameters passed.
579 + *
580 + * @param cfg configuration object
581 + */
582 + private void reconfigureNetwork(DHCPConfig cfg) {
583 +
584 + if (cfg.ip() != null) {
585 + myIP = cfg.ip();
586 + }
587 + if (cfg.mac() != null) {
588 + myMAC = MacAddress.valueOf(cfg.mac());
589 + }
590 + if (cfg.subnetMask() != null) {
591 + subnetMask = cfg.subnetMask();
592 + }
593 + if (cfg.broadcastAddress() != null) {
594 + broadcastAddress = cfg.broadcastAddress();
595 + }
596 + if (cfg.routerAddress() != null) {
597 + routerAddress = cfg.routerAddress();
598 + }
599 + if (cfg.domainServer() != null) {
600 + domainServer = cfg.domainServer();
601 + }
602 + if (cfg.ttl() != null) {
603 + packetTTL = Byte.valueOf(cfg.ttl());
604 + }
605 + if (cfg.leaseTime() != null) {
606 + leaseTime = Integer.valueOf(cfg.leaseTime());
607 + }
608 + if (cfg.renewTime() != null) {
609 + renewalTime = Integer.valueOf(cfg.renewTime());
610 + }
611 + if (cfg.rebindTime() != null) {
612 + rebindingTime = Integer.valueOf(cfg.rebindTime());
613 + }
614 + }
615 +
616 + /**
617 + * Reconfigures the DHCP Store according to the configuration parameters passed.
618 + *
619 + * @param cfg configuration object
620 + */
621 + private void reconfigureStore(DHCPStoreConfig cfg) {
622 +
623 + if (cfg.defaultTimeout() != null) {
624 + dhcpStore.setDefaultTimeoutForPurge(Integer.valueOf(cfg.defaultTimeout()));
625 + }
626 + if (cfg.timerDelay() != null) {
627 + dhcpStore.setTimerDelay(Integer.valueOf(cfg.defaultTimeout()));
628 + }
629 + if ((cfg.startIP() != null) && (cfg.endIP() != null)) {
630 + dhcpStore.populateIPPoolfromRange(Ip4Address.valueOf(cfg.startIP()),
631 + Ip4Address.valueOf(cfg.endIP()));
632 + }
633 + }
634 +
635 + @Override
636 + public void event(NetworkConfigEvent event) {
637 +
638 + if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
639 + event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED)) {
640 + if (event.configClass().equals(DHCPConfig.class)) {
641 + DHCPConfig cfg = cfgService.getConfig(appId, DHCPConfig.class);
642 + reconfigureNetwork(cfg);
643 + log.info("Reconfigured Manager");
644 + }
645 + if (event.configClass().equals(DHCPStoreConfig.class)) {
646 + DHCPStoreConfig cfg = cfgService.getConfig(appId, DHCPStoreConfig.class);
647 + reconfigureStore(cfg);
648 + log.info("Reconfigured Store");
649 + }
650 + }
651 + }
652 + }
653 +
654 + private class InternalHostProvider extends AbstractProvider implements HostProvider {
655 +
656 + /**
657 + * Creates a provider with the supplier identifier.
658 + */
659 + protected InternalHostProvider() {
660 + super(PID);
661 + }
662 +
663 + @Override
664 + public void triggerProbe(Host host) {
665 + // nothing to do
666 + }
667 + }
668 +}
...\ No newline at end of file ...\ No newline at end of file
1 +/*
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 + */
16 +package org.onosproject.dhcp.impl;
17 +
18 +import org.onosproject.core.ApplicationId;
19 +import org.onosproject.net.config.Config;
20 +import org.onosproject.net.config.basics.BasicElementConfig;
21 +
22 +/**
23 + * DHCP Store Config class.
24 + */
25 +public class DHCPStoreConfig extends Config<ApplicationId> {
26 +
27 + public static final String TIMER_DELAY = "delay";
28 + public static final String DEFAULT_TIMEOUT = "timeout";
29 + public static final String START_IP = "startip";
30 + public static final String END_IP = "endip";
31 +
32 + /**
33 + * Returns the delay after which the dhcp server will purge expired entries.
34 + *
35 + * @return time delay or null if not set
36 + */
37 + public String timerDelay() {
38 + return get(TIMER_DELAY, null);
39 + }
40 +
41 + /**
42 + * Sets the delay after which the dhcp server will purge expired entries.
43 + *
44 + * @param delay new time delay; null to clear
45 + * @return self
46 + */
47 + public BasicElementConfig timerDelay(String delay) {
48 + return (BasicElementConfig) setOrClear(TIMER_DELAY, delay);
49 + }
50 +
51 + /**
52 + * Returns the default timeout for pending assignments.
53 + *
54 + * @return default timeout or null if not set
55 + */
56 + public String defaultTimeout() {
57 + return get(DEFAULT_TIMEOUT, null);
58 + }
59 +
60 + /**
61 + * Sets the default timeout for pending assignments.
62 + *
63 + * @param defaultTimeout new default timeout; null to clear
64 + * @return self
65 + */
66 + public BasicElementConfig defaultTimeout(String defaultTimeout) {
67 + return (BasicElementConfig) setOrClear(DEFAULT_TIMEOUT, defaultTimeout);
68 + }
69 +
70 + /**
71 + * Returns the start IP for the available IP Range.
72 + *
73 + * @return start IP or null if not set
74 + */
75 + public String startIP() {
76 + return get(START_IP, null);
77 + }
78 +
79 + /**
80 + * Sets the start IP for the available IP Range.
81 + *
82 + * @param startIP new start IP; null to clear
83 + * @return self
84 + */
85 + public BasicElementConfig startIP(String startIP) {
86 + return (BasicElementConfig) setOrClear(START_IP, startIP);
87 + }
88 +
89 + /**
90 + * Returns the end IP for the available IP Range.
91 + *
92 + * @return end IP or null if not set
93 + */
94 + public String endIP() {
95 + return get(END_IP, null);
96 + }
97 +
98 + /**
99 + * Sets the end IP for the available IP Range.
100 + *
101 + * @param endIP new end IP; null to clear
102 + * @return self
103 + */
104 + public BasicElementConfig endIP(String endIP) {
105 + return (BasicElementConfig) setOrClear(END_IP, endIP);
106 + }
107 +}
1 +/*
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 + */
16 +package org.onosproject.dhcp.impl;
17 +
18 +import com.google.common.collect.ImmutableSet;
19 +import org.apache.felix.scr.annotations.Activate;
20 +import org.apache.felix.scr.annotations.Component;
21 +import org.apache.felix.scr.annotations.Deactivate;
22 +import org.apache.felix.scr.annotations.Reference;
23 +import org.apache.felix.scr.annotations.ReferenceCardinality;
24 +import org.apache.felix.scr.annotations.Service;
25 +import org.jboss.netty.util.Timeout;
26 +import org.jboss.netty.util.TimerTask;
27 +import org.onlab.packet.Ip4Address;
28 +import org.onlab.packet.MacAddress;
29 +import org.onlab.util.KryoNamespace;
30 +import org.onlab.util.Timer;
31 +import org.onosproject.dhcp.DHCPStore;
32 +import org.onosproject.dhcp.IPAssignment;
33 +import org.onosproject.store.serializers.KryoNamespaces;
34 +import org.onosproject.store.service.ConsistentMap;
35 +import org.onosproject.store.service.DistributedSet;
36 +import org.onosproject.store.service.Serializer;
37 +import org.onosproject.store.service.StorageService;
38 +import org.onosproject.store.service.Versioned;
39 +import org.slf4j.Logger;
40 +import org.slf4j.LoggerFactory;
41 +
42 +import java.util.Date;
43 +import java.util.HashMap;
44 +import java.util.Map;
45 +import java.util.concurrent.TimeUnit;
46 +
47 +/**
48 + * Manages the pool of available IP Addresses in the network and
49 + * Remembers the mapping between MAC ID and IP Addresses assigned.
50 + */
51 +
52 +@Component(immediate = true)
53 +@Service
54 +public class DistributedDHCPStore implements DHCPStore {
55 +
56 + private final Logger log = LoggerFactory.getLogger(getClass());
57 +
58 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
59 + protected StorageService storageService;
60 +
61 + private ConsistentMap<MacAddress, IPAssignment> allocationMap;
62 +
63 + private DistributedSet<Ip4Address> freeIPPool;
64 +
65 + private Timeout timeout;
66 +
67 + private static Ip4Address startIPRange;
68 +
69 + private static Ip4Address endIPRange;
70 +
71 + // Hardcoded values are default values.
72 +
73 + private static int timerDelay = 2;
74 +
75 + private static int timeoutForPendingAssignments = 60;
76 +
77 + @Activate
78 + protected void activate() {
79 + allocationMap = storageService.<MacAddress, IPAssignment>consistentMapBuilder()
80 + .withName("onos-dhcp-assignedIP")
81 + .withSerializer(Serializer.using(
82 + new KryoNamespace.Builder()
83 + .register(KryoNamespaces.API)
84 + .register(IPAssignment.class,
85 + IPAssignment.AssignmentStatus.class,
86 + Date.class,
87 + long.class,
88 + Ip4Address.class)
89 + .build()))
90 + .build();
91 +
92 + freeIPPool = storageService.<Ip4Address>setBuilder()
93 + .withName("onos-dhcp-freeIP")
94 + .withSerializer(Serializer.using(KryoNamespaces.API))
95 + .build();
96 +
97 + timeout = Timer.getTimer().newTimeout(new PurgeListTask(), timerDelay, TimeUnit.MINUTES);
98 +
99 + log.info("Started");
100 + }
101 +
102 + @Deactivate
103 + protected void deactivate() {
104 + timeout.cancel();
105 + log.info("Stopped");
106 + }
107 +
108 + @Override
109 + public Ip4Address suggestIP(MacAddress macID, Ip4Address requestedIP) {
110 +
111 + IPAssignment assignmentInfo;
112 + if (allocationMap.containsKey(macID)) {
113 + assignmentInfo = allocationMap.get(macID).value();
114 + IPAssignment.AssignmentStatus status = assignmentInfo.assignmentStatus();
115 + Ip4Address ipAddr = assignmentInfo.ipAddress();
116 +
117 + if (status == IPAssignment.AssignmentStatus.Option_Assigned ||
118 + status == IPAssignment.AssignmentStatus.Option_Requested) {
119 + // Client has a currently Active Binding.
120 + if ((ipAddr.toInt() > startIPRange.toInt()) && (ipAddr.toInt() < endIPRange.toInt())) {
121 + return ipAddr;
122 + }
123 +
124 + } else if (status == IPAssignment.AssignmentStatus.Option_Expired) {
125 + // Client has a Released or Expired Binding.
126 + if (freeIPPool.contains(ipAddr)) {
127 + assignmentInfo = IPAssignment.builder()
128 + .ipAddress(ipAddr)
129 + .timestamp(new Date())
130 + .leasePeriod(timeoutForPendingAssignments)
131 + .assignmentStatus(IPAssignment.AssignmentStatus.Option_Requested)
132 + .build();
133 + if (freeIPPool.remove(ipAddr)) {
134 + allocationMap.put(macID, assignmentInfo);
135 + return ipAddr;
136 + }
137 + }
138 + }
139 + return assignmentInfo.ipAddress();
140 +
141 + } else if (requestedIP.toInt() != 0) {
142 + // Client has requested an IP.
143 + if (freeIPPool.contains(requestedIP)) {
144 + assignmentInfo = IPAssignment.builder()
145 + .ipAddress(requestedIP)
146 + .timestamp(new Date())
147 + .leasePeriod(timeoutForPendingAssignments)
148 + .assignmentStatus(IPAssignment.AssignmentStatus.Option_Requested)
149 + .build();
150 + if (freeIPPool.remove(requestedIP)) {
151 + allocationMap.put(macID, assignmentInfo);
152 + return requestedIP;
153 + }
154 + }
155 + }
156 +
157 + // Allocate a new IP from the server's pool of available IP.
158 + Ip4Address nextIPAddr = fetchNextIP();
159 + assignmentInfo = IPAssignment.builder()
160 + .ipAddress(nextIPAddr)
161 + .timestamp(new Date())
162 + .leasePeriod(timeoutForPendingAssignments)
163 + .assignmentStatus(IPAssignment.AssignmentStatus.Option_Requested)
164 + .build();
165 +
166 + allocationMap.put(macID, assignmentInfo);
167 + return nextIPAddr;
168 +
169 + }
170 +
171 + @Override
172 + public boolean assignIP(MacAddress macID, Ip4Address ipAddr, int leaseTime) {
173 +
174 + IPAssignment assignmentInfo;
175 + if (allocationMap.containsKey(macID)) {
176 + assignmentInfo = allocationMap.get(macID).value();
177 + if ((assignmentInfo.ipAddress().toInt() == ipAddr.toInt()) &&
178 + (ipAddr.toInt() > startIPRange.toInt()) && (ipAddr.toInt() < endIPRange.toInt())) {
179 +
180 + assignmentInfo = IPAssignment.builder()
181 + .ipAddress(ipAddr)
182 + .timestamp(new Date())
183 + .leasePeriod(leaseTime)
184 + .assignmentStatus(IPAssignment.AssignmentStatus.Option_Assigned)
185 + .build();
186 + allocationMap.put(macID, assignmentInfo);
187 + return true;
188 + }
189 + } else if (freeIPPool.contains(ipAddr)) {
190 + assignmentInfo = IPAssignment.builder()
191 + .ipAddress(ipAddr)
192 + .timestamp(new Date())
193 + .leasePeriod(leaseTime)
194 + .assignmentStatus(IPAssignment.AssignmentStatus.Option_Assigned)
195 + .build();
196 + if (freeIPPool.remove(ipAddr)) {
197 + allocationMap.put(macID, assignmentInfo);
198 + return true;
199 + }
200 + }
201 + return false;
202 + }
203 +
204 + @Override
205 + public void releaseIP(MacAddress macID) {
206 + if (allocationMap.containsKey(macID)) {
207 + IPAssignment newAssignment = IPAssignment.builder(allocationMap.get(macID).value())
208 + .assignmentStatus(IPAssignment.AssignmentStatus.Option_Expired)
209 + .build();
210 + Ip4Address freeIP = newAssignment.ipAddress();
211 + allocationMap.put(macID, newAssignment);
212 + freeIPPool.add(freeIP);
213 + }
214 + }
215 +
216 + @Override
217 + public void setDefaultTimeoutForPurge(int timeInSeconds) {
218 + timeoutForPendingAssignments = timeInSeconds;
219 + }
220 +
221 + @Override
222 + public void setTimerDelay(int timeInSeconds) {
223 + timerDelay = timeInSeconds;
224 + }
225 +
226 + @Override
227 + public Map<MacAddress, Ip4Address> listMapping() {
228 +
229 + Map<MacAddress, Ip4Address> allMapping = new HashMap<>();
230 + for (Map.Entry<MacAddress, Versioned<IPAssignment>> entry: allocationMap.entrySet()) {
231 + IPAssignment assignment = entry.getValue().value();
232 + if (assignment.assignmentStatus() == IPAssignment.AssignmentStatus.Option_Assigned) {
233 + allMapping.put(entry.getKey(), assignment.ipAddress());
234 + }
235 + }
236 +
237 + return allMapping;
238 + }
239 +
240 + @Override
241 + public boolean assignStaticIP(MacAddress macID, Ip4Address ipAddr) {
242 + return assignIP(macID, ipAddr, -1);
243 + }
244 +
245 + @Override
246 + public boolean removeStaticIP(MacAddress macID) {
247 + if (allocationMap.containsKey(macID)) {
248 + IPAssignment assignment = allocationMap.get(macID).value();
249 + Ip4Address freeIP = assignment.ipAddress();
250 + if (assignment.leasePeriod() < 0) {
251 + allocationMap.remove(macID);
252 + freeIPPool.add(freeIP);
253 + return true;
254 + }
255 + }
256 + return false;
257 + }
258 +
259 + @Override
260 + public Iterable<Ip4Address> getAvailableIPs() {
261 + return ImmutableSet.<Ip4Address>copyOf(freeIPPool);
262 + }
263 +
264 + @Override
265 + public void populateIPPoolfromRange(Ip4Address startIP, Ip4Address endIP) {
266 + // Clear all entries from previous range.
267 + startIPRange = startIP;
268 + endIPRange = endIP;
269 + freeIPPool.clear();
270 +
271 + int lastIP = endIP.toInt();
272 + Ip4Address nextIP;
273 + for (int loopCounter = startIP.toInt(); loopCounter <= lastIP; loopCounter++) {
274 + nextIP = Ip4Address.valueOf(loopCounter);
275 + freeIPPool.add(nextIP);
276 + }
277 + }
278 +
279 + /**
280 + * Fetches the next available IP from the free pool pf IPs.
281 + *
282 + * @return the next available IP address
283 + */
284 + private Ip4Address fetchNextIP() {
285 + for (Ip4Address freeIP : freeIPPool) {
286 + if (freeIPPool.remove(freeIP)) {
287 + return freeIP;
288 + }
289 + }
290 + return null;
291 + }
292 +
293 + /**
294 + * Purges the IP allocation map to remove expired entries and returns the freed IPs to the free pool.
295 + */
296 + private class PurgeListTask implements TimerTask {
297 +
298 + @Override
299 + public void run(Timeout to) {
300 + IPAssignment ipAssignment, newAssignment;
301 + Date dateNow = new Date();
302 + for (Map.Entry<MacAddress, Versioned<IPAssignment>> entry: allocationMap.entrySet()) {
303 + ipAssignment = entry.getValue().value();
304 + long timeLapsed = dateNow.getTime() - ipAssignment.timestamp().getTime();
305 + if ((ipAssignment.assignmentStatus() != IPAssignment.AssignmentStatus.Option_Expired) &&
306 + (ipAssignment.leasePeriod() > 0) && (timeLapsed > (ipAssignment.leasePeriod()))) {
307 + Ip4Address freeIP = ipAssignment.ipAddress();
308 +
309 + newAssignment = IPAssignment.builder(ipAssignment)
310 + .assignmentStatus(IPAssignment.AssignmentStatus.Option_Expired)
311 + .build();
312 + allocationMap.put(entry.getKey(), newAssignment);
313 +
314 + if ((freeIP.toInt() > startIPRange.toInt()) && (freeIP.toInt() < endIPRange.toInt())) {
315 + freeIPPool.add(freeIP);
316 + }
317 + }
318 + }
319 + timeout = Timer.getTimer().newTimeout(new PurgeListTask(), timerDelay, TimeUnit.MINUTES);
320 + }
321 +
322 + }
323 +
324 +}
1 +/*
2 + * Copyright 2015 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 + */
16 +package org.onosproject.dhcp.rest;
17 +
18 +import com.fasterxml.jackson.databind.JsonNode;
19 +import com.fasterxml.jackson.databind.node.ArrayNode;
20 +import com.fasterxml.jackson.databind.node.ObjectNode;
21 +import org.onlab.packet.Ip4Address;
22 +import org.onlab.packet.MacAddress;
23 +import org.onosproject.dhcp.DHCPService;
24 +import org.onosproject.rest.AbstractWebResource;
25 +
26 +import javax.ws.rs.Consumes;
27 +import javax.ws.rs.DELETE;
28 +import javax.ws.rs.GET;
29 +import javax.ws.rs.POST;
30 +import javax.ws.rs.Path;
31 +import javax.ws.rs.PathParam;
32 +import javax.ws.rs.core.MediaType;
33 +import javax.ws.rs.core.Response;
34 +import java.io.IOException;
35 +import java.io.InputStream;
36 +import java.util.Map;
37 +
38 +/**
39 + * Manage DHCP address assignments.
40 + */
41 +@Path("dhcp")
42 +public class DHCPWebResource extends AbstractWebResource {
43 +
44 + final DHCPService service = get(DHCPService.class);
45 +
46 + /**
47 + * Get DHCP server configuration data.
48 + * Shows lease, renewal and rebinding times in seconds.
49 + *
50 + * @return 200 OK
51 + */
52 + @GET
53 + @Path("config")
54 + public Response getConfigs() {
55 + DHCPService service = get(DHCPService.class);
56 + ObjectNode node = mapper().createObjectNode()
57 + .put("leaseTime", service.getLeaseTime())
58 + .put("renewalTime", service.getRenewalTime())
59 + .put("rebindingTime", service.getRebindingTime());
60 + return ok(node.toString()).build();
61 + }
62 +
63 + /**
64 + * Get all MAC/IP mappings.
65 + * Shows all MAC/IP mappings held by the DHCP server.
66 + *
67 + * @return 200 OK
68 + */
69 + @GET
70 + @Path("mappings")
71 + public Response listMappings() {
72 + ObjectNode root = mapper().createObjectNode();
73 +
74 + final Map<MacAddress, Ip4Address> intents = service.listMapping();
75 + ArrayNode arrayNode = root.putArray("mappings");
76 + intents.entrySet().forEach(i -> arrayNode.add(mapper().createObjectNode()
77 + .put("mac", i.getKey().toString())
78 + .put("ip", i.getValue().toString())));
79 +
80 + return ok(root.toString()).build();
81 + }
82 +
83 +
84 +
85 + /**
86 + * Get all available IPs.
87 + * Shows all the IPs in the free pool of the DHCP Server.
88 + *
89 + * @return 200 OK
90 + */
91 + @GET
92 + @Path("available")
93 + public Response listAvailableIPs() {
94 + final Iterable<Ip4Address> availableIPList = service.getAvailableIPs();
95 +
96 + final ObjectNode root = mapper().createObjectNode();
97 + ArrayNode arrayNode = root.putArray("availableIP");
98 + availableIPList.forEach(i -> arrayNode.add(i.toString()));
99 + return ok(root.toString()).build();
100 + }
101 +
102 + /**
103 + * Post a new static MAC/IP binding.
104 + * Registers a static binding to the DHCP server, and displays the current set of bindings.
105 + *
106 + * @return 200 OK
107 + */
108 + @POST
109 + @Path("mappings")
110 + @Consumes(MediaType.APPLICATION_JSON)
111 + public Response setMapping(InputStream stream) {
112 + ObjectNode root = mapper().createObjectNode();
113 +
114 + try {
115 + ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
116 + JsonNode macID = jsonTree.get("mac");
117 + JsonNode ip = jsonTree.get("ip");
118 + if (macID != null && ip != null) {
119 +
120 + if (!service.setStaticMapping(MacAddress.valueOf(macID.asText()),
121 + Ip4Address.valueOf(ip.asText()))) {
122 + throw new IllegalArgumentException("Static Mapping Failed. The IP maybe unavailable.");
123 + }
124 + }
125 +
126 + final Map<MacAddress, Ip4Address> intents = service.listMapping();
127 + ArrayNode arrayNode = root.putArray("mappings");
128 + intents.entrySet().forEach(i -> arrayNode.add(mapper().createObjectNode()
129 + .put("mac", i.getKey().toString())
130 + .put("ip", i.getValue().toString())));
131 + } catch (IOException e) {
132 + throw new IllegalArgumentException(e.getMessage());
133 + }
134 + return ok(root.toString()).build();
135 + }
136 +
137 + /**
138 + * Delete a static MAC/IP binding.
139 + * Removes a static binding from the DHCP Server, and displays the current set of bindings.
140 + *
141 + * @return 200 OK
142 + */
143 + @DELETE
144 + @Path("mappings/{macID}")
145 + public Response deleteMapping(@PathParam("macID") String macID) {
146 +
147 + ObjectNode root = mapper().createObjectNode();
148 +
149 + if (!service.removeStaticMapping(MacAddress.valueOf(macID))) {
150 + throw new IllegalArgumentException("Static Mapping Removal Failed.");
151 + }
152 + final Map<MacAddress, Ip4Address> intents = service.listMapping();
153 + ArrayNode arrayNode = root.putArray("mappings");
154 + intents.entrySet().forEach(i -> arrayNode.add(mapper().createObjectNode()
155 + .put("mac", i.getKey().toString())
156 + .put("ip", i.getValue().toString())));
157 +
158 + return ok(root.toString()).build();
159 + }
160 +}
1 +<!--
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 + -->
16 +<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
17 +
18 + <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
19 + <command>
20 + <action class="org.onosproject.dhcp.cli.DHCPListAllMappings"/>
21 + </command>
22 + <command>
23 + <action class="org.onosproject.dhcp.cli.DHCPLeaseDetails"/>
24 + </command>
25 + <command>
26 + <action class="org.onosproject.dhcp.cli.DHCPSetStaticMapping"/>
27 + <completers>
28 + <ref component-id="macIDCompleter"/>
29 + <ref component-id="freeIPCompleter"/>
30 + </completers>
31 + </command>
32 + <command>
33 + <action class="org.onosproject.dhcp.cli.DHCPRemoveStaticMapping"/>
34 + <completers>
35 + <ref component-id="macIDCompleter"/>
36 + </completers>
37 + </command>
38 + </command-bundle>
39 +
40 + <bean id="macIDCompleter" class="org.onosproject.dhcp.cli.MacIdCompleter"/>
41 + <bean id="freeIPCompleter" class="org.onosproject.dhcp.cli.FreeIPCompleter"/>
42 +
43 +</blueprint>
...\ No newline at end of file ...\ No newline at end of file
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + ~ Copyright 2015 Open Networking Laboratory
4 + ~
5 + ~ Licensed under the Apache License, Version 2.0 (the "License");
6 + ~ you may not use this file except in compliance with the License.
7 + ~ You may obtain a copy of the License at
8 + ~
9 + ~ http://www.apache.org/licenses/LICENSE-2.0
10 + ~
11 + ~ Unless required by applicable law or agreed to in writing, software
12 + ~ distributed under the License is distributed on an "AS IS" BASIS,
13 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + ~ See the License for the specific language governing permissions and
15 + ~ limitations under the License.
16 + -->
17 +<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
18 + xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
19 + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
20 + id="ONOS" version="2.5">
21 + <display-name>DHCP Server REST API v1.0</display-name>
22 +
23 + <servlet>
24 + <servlet-name>JAX-RS Service</servlet-name>
25 + <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
26 + <init-param>
27 + <param-name>com.sun.jersey.config.property.resourceConfigClass</param-name>
28 + <param-value>com.sun.jersey.api.core.ClassNamesResourceConfig</param-value>
29 + </init-param>
30 + <init-param>
31 + <param-name>com.sun.jersey.config.property.classnames</param-name>
32 + <param-value>
33 + org.onosproject.dhcp.rest.DHCPWebResource
34 + </param-value>
35 + </init-param>
36 + <load-on-startup>1</load-on-startup>
37 + </servlet>
38 +
39 + <servlet-mapping>
40 + <servlet-name>JAX-RS Service</servlet-name>
41 + <url-pattern>/*</url-pattern>
42 + </servlet-mapping>
43 +</web-app>
1 +/*
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 + */
16 +package org.onosproject.dhcp;
17 +
18 +import com.google.common.testing.EqualsTester;
19 +import junit.framework.TestCase;
20 +import org.junit.Assert;
21 +import org.junit.Test;
22 +import org.onlab.packet.Ip4Address;
23 +
24 +import java.util.Date;
25 +
26 +import static org.hamcrest.MatcherAssert.assertThat;
27 +import static org.hamcrest.Matchers.containsString;
28 +import static org.hamcrest.Matchers.is;
29 +import static org.junit.Assert.fail;
30 +
31 +/**
32 + * Unit Tests for IPAssignment class.
33 + */
34 +public class IPAssignmentTest extends TestCase {
35 +
36 + private final Date dateNow = new Date();
37 +
38 + private final IPAssignment stats1 = IPAssignment.builder()
39 + .ipAddress(Ip4Address.valueOf("10.10.10.10"))
40 + .leasePeriod(300)
41 + .assignmentStatus(IPAssignment.AssignmentStatus.Option_Expired)
42 + .timestamp(dateNow)
43 + .build();
44 +
45 + private final IPAssignment stats2 = IPAssignment.builder()
46 + .ipAddress(Ip4Address.valueOf("10.10.10.10"))
47 + .leasePeriod(300)
48 + .assignmentStatus(IPAssignment.AssignmentStatus.Option_Assigned)
49 + .timestamp(dateNow)
50 + .build();
51 +
52 + private final IPAssignment stats3 = IPAssignment.builder(stats1)
53 + .build();
54 +
55 + /**
56 + * Tests the constructor for the class.
57 + */
58 + @Test
59 + public void testConstruction() {
60 + assertThat(stats3.ipAddress(), is(Ip4Address.valueOf("10.10.10.10")));
61 + assertThat(stats3.timestamp(), is(dateNow));
62 + assertThat(stats3.leasePeriod(), is(300));
63 + assertThat(stats3.assignmentStatus(), is(IPAssignment.AssignmentStatus.Option_Expired));
64 + }
65 +
66 + /**
67 + * Tests the equality and inequality of objects using Guava EqualsTester.
68 + */
69 + @Test
70 + public void testEquals() {
71 + new EqualsTester()
72 + .addEqualityGroup(stats1, stats1)
73 + .addEqualityGroup(stats2)
74 + .testEquals();
75 + }
76 +
77 + /**
78 + * Tests if the toString method returns a consistent value for hashing.
79 + */
80 + @Test
81 + public void testToString() {
82 + assertThat(stats1.toString(), is(stats1.toString()));
83 + }
84 +
85 + /**
86 + * Tests if the validateInputs method returns an exception for malformed object.
87 + */
88 + @Test
89 + public void testValidateInputs() {
90 + try {
91 + IPAssignment stats4 = IPAssignment.builder()
92 + .ipAddress(Ip4Address.valueOf("10.10.10.10"))
93 + .leasePeriod(300)
94 + .build();
95 +
96 + fail("Construction of a malformed IPAssignment did not throw an exception");
97 + } catch (NullPointerException e) {
98 + Assert.assertThat(e.getMessage(), containsString("must be specified"));
99 + }
100 + }
101 +}
...\ No newline at end of file ...\ No newline at end of file
1 +/*
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 + */
16 +package org.onosproject.dhcp.impl;
17 +
18 +import com.google.common.collect.ImmutableSet;
19 +import org.junit.After;
20 +import org.junit.Before;
21 +import org.junit.Test;
22 +import org.onlab.packet.DHCP;
23 +import org.onlab.packet.DHCPOption;
24 +import org.onlab.packet.Ethernet;
25 +import org.onlab.packet.IPv4;
26 +import org.onlab.packet.Ip4Address;
27 +import org.onlab.packet.MacAddress;
28 +import org.onlab.packet.UDP;
29 +import org.onosproject.core.CoreServiceAdapter;
30 +import org.onosproject.dhcp.DHCPStore;
31 +import org.onosproject.net.config.NetworkConfigRegistryAdapter;
32 +import org.onosproject.net.Host;
33 +import org.onosproject.net.HostId;
34 +import org.onosproject.net.host.HostDescription;
35 +import org.onosproject.net.host.HostProvider;
36 +import org.onosproject.net.host.HostProviderRegistry;
37 +import org.onosproject.net.host.HostProviderService;
38 +import org.onosproject.net.packet.DefaultInboundPacket;
39 +import org.onosproject.net.packet.DefaultPacketContext;
40 +import org.onosproject.net.packet.InboundPacket;
41 +import org.onosproject.net.packet.OutboundPacket;
42 +import org.onosproject.net.packet.PacketContext;
43 +import org.onosproject.net.packet.PacketProcessor;
44 +import org.onosproject.net.packet.PacketServiceAdapter;
45 +import org.onosproject.net.provider.AbstractProvider;
46 +import org.onosproject.net.provider.AbstractProviderService;
47 +import org.onosproject.net.provider.ProviderId;
48 +
49 +import java.nio.ByteBuffer;
50 +import java.util.ArrayList;
51 +import java.util.HashMap;
52 +import java.util.List;
53 +import java.util.Map;
54 +import java.util.Set;
55 +
56 +import static org.junit.Assert.assertEquals;
57 +import static org.junit.Assert.fail;
58 +import static org.onosproject.net.NetTestTools.connectPoint;
59 +
60 +/**
61 + * Set of tests of the ONOS application component.
62 + */
63 +
64 +public class DHCPManagerTest {
65 +
66 + private DHCPManager dhcpManager;
67 +
68 + protected PacketProcessor packetProcessor;
69 +
70 + protected HostProviderService hostProviderService;
71 +
72 + private static final MacAddress CLIENT1_MAC = MacAddress.valueOf("1a:1a:1a:1a:1a:1a");
73 +
74 + private static final String EXPECTED_IP = "10.2.0.2";
75 +
76 + private static final Ip4Address BROADCAST = Ip4Address.valueOf("255.255.255.255");
77 +
78 + private static final int TRANSACTION_ID = 1000;
79 +
80 + private static final ProviderId PID = new ProviderId("of", "foo");
81 +
82 + @Before
83 + public void setUp() {
84 + dhcpManager = new DHCPManager();
85 + dhcpManager.cfgService = new TestNetworkConfigRegistry();
86 + dhcpManager.packetService = new TestPacketService();
87 + dhcpManager.coreService = new TestCoreService();
88 + dhcpManager.dhcpStore = new TestDHCPStore();
89 + hostProviderService = new TestHostProviderService(new TestHostProvider());
90 + dhcpManager.hostProviderService = hostProviderService;
91 + dhcpManager.hostProviderRegistry = new TestHostRegistry();
92 + dhcpManager.activate();
93 + }
94 +
95 + @After
96 + public void tearDown() {
97 + dhcpManager.deactivate();
98 + }
99 +
100 + /**
101 + * Tests the response to a DHCP Discover Packet.
102 + */
103 + @Test
104 + public void testDiscover() {
105 + Ethernet reply = constructDHCPPacket(DHCP.DHCPMessageType.MessageType_Discover);
106 + sendPacket(reply);
107 + }
108 +
109 + /**
110 + * Tests the response to a DHCP Request Packet.
111 + */
112 + @Test
113 + public void testRequest() {
114 + Ethernet reply = constructDHCPPacket(DHCP.DHCPMessageType.MessageType_Request);
115 + sendPacket(reply);
116 + }
117 +
118 + /**
119 + * Sends an Ethernet packet to the process method of the Packet Processor.
120 + * @param reply Ethernet packet
121 + */
122 + private void sendPacket(Ethernet reply) {
123 + final ByteBuffer byteBuffer = ByteBuffer.wrap(reply.serialize());
124 + InboundPacket inPacket = new DefaultInboundPacket(connectPoint("1", 1),
125 + reply,
126 + byteBuffer);
127 +
128 + PacketContext context = new TestPacketContext(127L, inPacket, null, false);
129 + packetProcessor.process(context);
130 + }
131 +
132 + /**
133 + * Constructs an Ethernet packet containing a DHCP Payload.
134 + * @param messageType DHCP Message Type
135 + * @return Ethernet packet
136 + */
137 + private Ethernet constructDHCPPacket(DHCP.DHCPMessageType messageType) {
138 +
139 + // Ethernet Frame.
140 + Ethernet ethReply = new Ethernet();
141 + ethReply.setSourceMACAddress(CLIENT1_MAC);
142 + ethReply.setDestinationMACAddress(MacAddress.BROADCAST);
143 + ethReply.setEtherType(Ethernet.TYPE_IPV4);
144 + ethReply.setVlanID((short) 2);
145 +
146 + // IP Packet
147 + IPv4 ipv4Reply = new IPv4();
148 + ipv4Reply.setSourceAddress(0);
149 + ipv4Reply.setDestinationAddress(BROADCAST.toInt());
150 + ipv4Reply.setTtl((byte) 127);
151 +
152 + // UDP Datagram.
153 + UDP udpReply = new UDP();
154 + udpReply.setSourcePort((byte) UDP.DHCP_CLIENT_PORT);
155 + udpReply.setDestinationPort((byte) UDP.DHCP_SERVER_PORT);
156 +
157 + // DHCP Payload.
158 + DHCP dhcpReply = new DHCP();
159 + dhcpReply.setOpCode(DHCP.OPCODE_REQUEST);
160 +
161 + dhcpReply.setYourIPAddress(0);
162 + dhcpReply.setServerIPAddress(0);
163 +
164 + dhcpReply.setTransactionId(TRANSACTION_ID);
165 + dhcpReply.setClientHardwareAddress(CLIENT1_MAC.toBytes());
166 + dhcpReply.setHardwareType(DHCP.HWTYPE_ETHERNET);
167 + dhcpReply.setHardwareAddressLength((byte) 6);
168 +
169 + // DHCP Options.
170 + DHCPOption option = new DHCPOption();
171 + List<DHCPOption> optionList = new ArrayList<>();
172 +
173 + // DHCP Message Type.
174 + option.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
175 + option.setLength((byte) 1);
176 + byte[] optionData = {messageType.getValue()};
177 + option.setData(optionData);
178 + optionList.add(option);
179 +
180 + // DHCP Requested IP.
181 + option = new DHCPOption();
182 + option.setCode(DHCP.DHCPOptionCode.OptionCode_RequestedIP.getValue());
183 + option.setLength((byte) 4);
184 + optionData = Ip4Address.valueOf(EXPECTED_IP).toOctets();
185 + option.setData(optionData);
186 + optionList.add(option);
187 +
188 + // End Option.
189 + option = new DHCPOption();
190 + option.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
191 + option.setLength((byte) 1);
192 + optionList.add(option);
193 +
194 + dhcpReply.setOptions(optionList);
195 +
196 + udpReply.setPayload(dhcpReply);
197 + ipv4Reply.setPayload(udpReply);
198 + ethReply.setPayload(ipv4Reply);
199 +
200 + return ethReply;
201 + }
202 +
203 + /**
204 + * Validates the contents of the packet sent by the DHCP Manager.
205 + * @param packet Ethernet packet received
206 + */
207 + private void validatePacket(Ethernet packet) {
208 + DHCP dhcpPacket = (DHCP) packet.getPayload().getPayload().getPayload();
209 + assertEquals(MacAddress.valueOf(dhcpPacket.getClientHardwareAddress()), CLIENT1_MAC);
210 + assertEquals(Ip4Address.valueOf(dhcpPacket.getYourIPAddress()), Ip4Address.valueOf(EXPECTED_IP));
211 + assertEquals(dhcpPacket.getTransactionId(), TRANSACTION_ID);
212 + }
213 +
214 + /**
215 + * Mocks the DHCPStore.
216 + */
217 + private final class TestDHCPStore implements DHCPStore {
218 +
219 +
220 + public void populateIPPoolfromRange(Ip4Address startIP, Ip4Address endIP) {
221 + }
222 +
223 + public Ip4Address suggestIP(MacAddress macID, Ip4Address requestedIP) {
224 + return Ip4Address.valueOf(EXPECTED_IP);
225 + }
226 +
227 + public boolean assignIP(MacAddress macID, Ip4Address ipAddr, int leaseTime) {
228 + return true;
229 + }
230 +
231 + public void setDefaultTimeoutForPurge(int timeInSeconds) {
232 + }
233 +
234 + public void setTimerDelay(int timeInSeconds) {
235 + }
236 +
237 + public void releaseIP(MacAddress macID) {
238 + }
239 +
240 + public Map<MacAddress, Ip4Address> listMapping() {
241 + Map<MacAddress, Ip4Address> map = new HashMap<>();
242 + map.put(CLIENT1_MAC, Ip4Address.valueOf(EXPECTED_IP));
243 + return map;
244 + }
245 +
246 + public boolean assignStaticIP(MacAddress macID, Ip4Address ipAddr) {
247 + return true;
248 + }
249 +
250 + public boolean removeStaticIP(MacAddress macID) {
251 + return true;
252 + }
253 +
254 + public Iterable<Ip4Address> getAvailableIPs() {
255 + List<Ip4Address> ipList = new ArrayList<>();
256 + ipList.add(Ip4Address.valueOf(EXPECTED_IP));
257 + return ImmutableSet.copyOf(ipList);
258 + }
259 + }
260 +
261 + /**
262 + * Mocks the DefaultPacket context.
263 + */
264 + private final class TestPacketContext extends DefaultPacketContext {
265 + private TestPacketContext(long time, InboundPacket inPkt,
266 + OutboundPacket outPkt, boolean block) {
267 + super(time, inPkt, outPkt, block);
268 + }
269 +
270 + @Override
271 + public void send() {
272 + // We don't send anything out.
273 + }
274 + }
275 +
276 + /**
277 + * Keeps a reference to the PacketProcessor and verifies the OutboundPackets.
278 + */
279 + private class TestPacketService extends PacketServiceAdapter {
280 +
281 + @Override
282 + public void addProcessor(PacketProcessor processor, int priority) {
283 + packetProcessor = processor;
284 + }
285 +
286 + @Override
287 + public void emit(OutboundPacket packet) {
288 + try {
289 + Ethernet eth = Ethernet.deserializer().deserialize(packet.data().array(),
290 + 0, packet.data().array().length);
291 + validatePacket(eth);
292 + } catch (Exception e) {
293 + fail(e.getMessage());
294 + }
295 + }
296 + }
297 +
298 + /**
299 + * Mocks the CoreService.
300 + */
301 + private class TestCoreService extends CoreServiceAdapter {
302 +
303 + }
304 +
305 + /**
306 + * Mocks the NetworkConfigRegistry.
307 + */
308 + private class TestNetworkConfigRegistry extends NetworkConfigRegistryAdapter {
309 +
310 + }
311 +
312 + /**
313 + * Mocks the HostProviderService.
314 + */
315 + private class TestHostProviderService extends AbstractProviderService<HostProvider>
316 + implements HostProviderService {
317 +
318 + protected TestHostProviderService(HostProvider provider) {
319 + super(provider);
320 + }
321 +
322 + @Override
323 + public void hostDetected(HostId hostId, HostDescription hostDescription) {
324 + }
325 +
326 + @Override
327 + public void hostVanished(HostId hostId) {
328 + }
329 +
330 + }
331 +
332 + /**
333 + * Mocks the HostProvider.
334 + */
335 + private static class TestHostProvider extends AbstractProvider
336 + implements HostProvider {
337 +
338 + protected TestHostProvider() {
339 + super(PID);
340 + }
341 +
342 + @Override
343 + public ProviderId id() {
344 + return PID;
345 + }
346 +
347 + @Override
348 + public void triggerProbe(Host host) {
349 + }
350 +
351 + }
352 +
353 + /**
354 + * Mocks the HostProviderRegistry.
355 + */
356 + private class TestHostRegistry implements HostProviderRegistry {
357 +
358 + @Override
359 + public HostProviderService register(HostProvider provider) {
360 + return hostProviderService;
361 + }
362 +
363 + @Override
364 + public void unregister(HostProvider provider) {
365 + }
366 +
367 + @Override
368 + public Set<ProviderId> getProviders() {
369 + return null;
370 + }
371 +
372 + }
373 +
374 +}
1 +{
2 + "apps": {
3 + "org.onosproject.dhcp" : {
4 + "dhcp" : {
5 + "ip": "10.0.0.1",
6 + "mac": "1a:2b:3c:4e:5e:6f",
7 + "subnet": "255.0.0.0",
8 + "broadcast": "10.255.255.255",
9 + "router": "10.0.0.1",
10 + "domain": "10.0.0.1",
11 + "ttl": "63",
12 + "lease": "300",
13 + "renew": "150",
14 + "rebind": "200"
15 + },
16 + "dhcpstore" : {
17 + "delay": "3",
18 + "timeout": "150",
19 + "startip": "10.0.0.110",
20 + "endip": "10.0.0.130"
21 + }
22 + }
23 + }
24 +}
...\ No newline at end of file ...\ No newline at end of file
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
57 <module>vtnrsc</module> 57 <module>vtnrsc</module>
58 <module>vtn</module> 58 <module>vtn</module>
59 <module>vtnweb</module> 59 <module>vtnweb</module>
60 + <module>onos-app-dhcp</module>
60 </modules> 61 </modules>
61 62
62 <properties> 63 <properties>
......