Update SubnetConfig Validation
[controller.git] / opendaylight / switchmanager / api / src / main / java / org / opendaylight / controller / switchmanager / SubnetConfig.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.controller.switchmanager;
10
11 import java.io.Serializable;
12 import java.net.InetAddress;
13 import java.net.UnknownHostException;
14 import java.util.ArrayList;
15 import java.util.List;
16 import java.util.Set;
17
18 import javax.xml.bind.annotation.XmlAccessType;
19 import javax.xml.bind.annotation.XmlAccessorType;
20 import javax.xml.bind.annotation.XmlElement;
21 import javax.xml.bind.annotation.XmlRootElement;
22
23 import org.opendaylight.controller.sal.core.NodeConnector;
24 import org.opendaylight.controller.sal.packet.BitBufferHelper;
25 import org.opendaylight.controller.sal.utils.GUIField;
26 import org.opendaylight.controller.sal.utils.NetUtils;
27 import org.opendaylight.controller.sal.utils.Status;
28 import org.opendaylight.controller.sal.utils.StatusCode;
29
30 /**
31  * The class represents a subnet configuration.
32  */
33 @XmlRootElement
34 @XmlAccessorType(XmlAccessType.NONE)
35 public class SubnetConfig implements Cloneable, Serializable {
36     private static final long serialVersionUID = 1L;
37     private static final String prettyFields[] = { GUIField.NAME.toString(), GUIField.GATEWAYIP.toString(),
38             GUIField.NODEPORTS.toString() };
39
40     /**
41      * Name of the subnet
42      */
43     @XmlElement
44     private String name;
45     /**
46      * A.B.C.D/MM Where A.B.C.D is the Default Gateway IP (L3) or ARP Querier IP
47      * (L2)
48      */
49     @XmlElement
50     private String subnet;
51     /**
52      * Set of node connectors in the format: Port Type|Port Id@Node Type|Node Id
53      */
54     @XmlElement
55     private List<String> nodeConnectors;
56
57     public SubnetConfig() {
58     }
59
60     public SubnetConfig(String name, String subnet, List<String> nodeConnectors) {
61         this.name = name;
62         this.subnet = subnet;
63         this.nodeConnectors = nodeConnectors;
64     }
65
66     public SubnetConfig(SubnetConfig subnetConfig) {
67         name = subnetConfig.name;
68         subnet = subnetConfig.subnet;
69         nodeConnectors = (subnetConfig.nodeConnectors == null) ? null : new ArrayList<String>(
70                 subnetConfig.nodeConnectors);
71     }
72
73     public String getName() {
74         return name;
75     }
76
77     public List<String> getNodePorts() {
78         return (nodeConnectors == null) ? new ArrayList<String>(0) : new ArrayList<String>(nodeConnectors);
79     }
80
81     public String getSubnet() {
82         return subnet;
83     }
84
85     public InetAddress getIPAddress() {
86         InetAddress ip = null;
87         try {
88             ip = InetAddress.getByName(subnet.split("/")[0]);
89         } catch (UnknownHostException e1) {
90             return null;
91         }
92         return ip;
93     }
94
95     public Short getIPMaskLen() {
96         Short maskLen = 0;
97         String[] s = subnet.split("/");
98
99         try {
100             maskLen = (s.length == 2) ? Short.valueOf(s[1]) : 32;
101         } catch (NumberFormatException e) {
102             maskLen = 32;
103         }
104         return maskLen;
105     }
106
107     private Status validateSubnetAddress() {
108         if (!NetUtils.isIPAddressValid(subnet)) {
109             return new Status(StatusCode.BADREQUEST, String.format("Invalid Subnet configuration: Invalid address: %s",
110                     subnet));
111         }
112         if ((this.getIPMaskLen() == 0) || (this.getIPMaskLen() == 32)) {
113             return new Status(StatusCode.BADREQUEST, String.format("Invalid Subnet configuration: Invalid mask: /%s",
114                     this.getIPMaskLen()));
115         }
116
117         //checks that address doesn't start with 0 or 255
118         String address = subnet.split("/")[0];
119         if (address.startsWith("0.") || address.startsWith("255.")) {
120             return  new Status(StatusCode.BADREQUEST, String.format("Invalid Subnet configuration: Invalid address: %s", address));
121         }
122
123         byte[] bytePrefix = NetUtils.getSubnetPrefix(this.getIPAddress(), this.getIPMaskLen()).getAddress();
124         long prefix = BitBufferHelper.getLong(bytePrefix);
125         if (prefix == 0) {
126             return new Status(StatusCode.BADREQUEST, "Invalid network source address: subnet zero");
127         }
128
129         //check that host is not set to all 0's or 1's
130         long hostAddress = BitBufferHelper.getLong(this.getIPAddress().getAddress()) - prefix;
131         if (hostAddress == 0 || hostAddress == Math.pow(2, 32-this.getIPMaskLen()) - 1) {
132             return new Status(StatusCode.BADREQUEST, String.format("Invalid subnet gateway address: /%s", subnet));
133         }
134
135         return new Status(StatusCode.SUCCESS);
136     }
137
138     public static Status validatePorts(List<String> nodeConnectors) {
139         if (nodeConnectors != null) {
140             for (String port : nodeConnectors) {
141                 if (null == NodeConnector.fromString(port)) {
142                     return new Status(StatusCode.BADREQUEST,
143                             "Invalid Subnet configuration: Not parsable node connector: " + port);
144                 }
145             }
146         }
147         return new Status(StatusCode.SUCCESS);
148     }
149
150     private Status validateName() {
151         if (name == null || name.trim().isEmpty()) {
152             return new Status(StatusCode.BADREQUEST, "Invalid name");
153         }
154         return new Status(StatusCode.SUCCESS);
155     }
156
157     public Status validate() {
158         Status status = validateName();
159         if (status.isSuccess()) {
160             status = validateSubnetAddress();
161             if (status.isSuccess()) {
162                 status = validatePorts(this.nodeConnectors);
163             }
164         }
165         return status;
166     }
167
168     public static List<String> getGuiFieldsNames() {
169         List<String> fieldList = new ArrayList<String>();
170         for (String str : prettyFields) {
171             fieldList.add(str);
172         }
173         return fieldList;
174     }
175
176     public Set<NodeConnector> getNodeConnectors() {
177         return NodeConnector.fromString(this.nodeConnectors);
178     }
179
180     public boolean isGlobal() {
181         // If no ports are specified to be part of the domain, then it's a
182         // global domain IP
183         return (nodeConnectors == null || nodeConnectors.isEmpty());
184     }
185
186     public void addNodeConnectors(List<String> nc) {
187         if (nc != null) {
188             if (nodeConnectors == null) {
189                 nodeConnectors = new ArrayList<String>(nc);
190             } else {
191                 nodeConnectors.addAll(nc);
192             }
193         }
194     }
195
196     public void removeNodeConnectors(List<String> nc) {
197         if (nc != null && nodeConnectors != null) {
198             nodeConnectors.removeAll(nc);
199         }
200     }
201
202     @Override
203     public String toString() {
204         return ("SubnetConfig [Name=" + name + ", Subnet=" + subnet + ", NodeConnectors=" + nodeConnectors + "]");
205     }
206
207     /**
208      * Implement clonable interface
209      */
210     @Override
211     public SubnetConfig clone() {
212         return new SubnetConfig(this);
213     }
214
215     @Override
216     public int hashCode() {
217         final int prime = 31;
218         int result = 1;
219         result = prime * result + ((name == null) ? 0 : name.hashCode());
220         result = prime * result + ((nodeConnectors == null) ? 0 : nodeConnectors.hashCode());
221         result = prime * result + ((subnet == null) ? 0 : subnet.hashCode());
222         return result;
223     }
224
225     @Override
226     public boolean equals(Object obj) {
227         if (this == obj) {
228             return true;
229         }
230         if (obj == null) {
231             return false;
232         }
233         if (getClass() != obj.getClass()) {
234             return false;
235         }
236         SubnetConfig other = (SubnetConfig) obj;
237         if (name == null) {
238             if (other.name != null) {
239                 return false;
240             }
241         } else if (!name.equals(other.name)) {
242             return false;
243         }
244         if (nodeConnectors == null) {
245             if (other.nodeConnectors != null) {
246                 return false;
247             }
248         } else if (!nodeConnectors.equals(other.nodeConnectors)) {
249             return false;
250         }
251         if (subnet == null) {
252             if (other.subnet != null) {
253                 return false;
254             }
255         } else if (!subnet.equals(other.subnet)) {
256             return false;
257         }
258         return true;
259     }
260 }