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
apps/onos-app-dhcp/pom.xml
0 → 100644
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> | ... | ... |
-
Please register or login to post a comment