2 Copyright (c) 2017 SONATA-NFV and Paderborn University
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
9 http://www.apache.org/licenses/LICENSE-2.0
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.
17 Neither the name of the SONATA-NFV, Paderborn University
18 nor the names of its contributors may be used to endorse or promote
19 products derived from this software without specific prior written
22 This work has been performed in the framework of the SONATA project,
23 funded by the European Commission under Grant number 671517 through
24 the Horizon 2020 and 5G-PPP programmes. The authors would like to
25 acknowledge the contributions of their colleagues of the SONATA
26 partner consortium (www.sonata-nfv.eu).
32 def __init__(self
, name
):
35 self
.subnet_name
= None
37 self
.subnet_creation_time
= None
38 self
.subnet_update_time
= None
39 self
.gateway_ip
= None
40 self
.segmentation_id
= None # not set
42 self
.start_end_dict
= None
43 self
._issued
_ip
_addresses
= dict()
45 def get_short_id(self
):
47 Returns a shortened UUID, with only the first 6 characters.
49 :return: First 6 characters of the UUID
52 return str(self
.id)[:6]
54 def get_new_ip_address(self
, port_name
):
56 Calculates the next unused IP Address which belongs to the subnet.
58 :param port_name: Specifies the port.
59 :type port_name: ``str``
60 :return: Returns a unused IP Address or none if all are in use.
63 if self
.start_end_dict
is None:
66 int_start_ip
= Net
.ip_2_int(self
.start_end_dict
['start']) + 2 # First address as network address not usable
67 # Second one is for gateways only
68 int_end_ip
= Net
.ip_2_int(self
.start_end_dict
['end']) - 1 # Last address for broadcasts
69 while int_start_ip
in self
._issued
_ip
_addresses
and int_start_ip
<= int_end_ip
:
72 if int_start_ip
> int_end_ip
:
75 self
._issued
_ip
_addresses
[int_start_ip
] = port_name
76 return Net
.int_2_ip(int_start_ip
) + '/' + self
._cidr
.rsplit('/', 1)[1]
78 def assign_ip_address(self
, cidr
, port_name
):
80 Assigns the IP address to the port if it is currently NOT used.
82 :param cidr: The cidr used by the port - e.g. 10.0.0.1/24
84 :param port_name: The port name
85 :type port_name: ``str``
86 :return: * *False*: If the IP address is already issued or if it is not within this subnet mask.
89 int_ip
= Net
.cidr_2_int(cidr
)
90 if int_ip
in self
._issued
_ip
_addresses
:
93 int_start_ip
= Net
.ip_2_int(self
.start_end_dict
['start']) + 1 # First address as network address not usable
94 int_end_ip
= Net
.ip_2_int(self
.start_end_dict
['end']) - 1 # Last address for broadcasts
95 if int_ip
< int_start_ip
or int_ip
> int_end_ip
:
98 self
._issued
_ip
_addresses
[int_ip
] = port_name
101 def is_my_ip(self
, cidr
, port_name
):
103 Checks if the IP is registered for this port name.
105 :param cidr: The cidr used by the port - e.g. 10.0.0.1/24
107 :param port_name: The port name
108 :type port_name: ``str``
109 :return: Returns true if the IP address belongs to the port name. Else it returns false.
111 int_ip
= Net
.cidr_2_int(cidr
)
113 if not int_ip
in self
._issued
_ip
_addresses
:
116 if self
._issued
_ip
_addresses
[int_ip
] == port_name
:
120 def withdraw_ip_address(self
, ip_address
):
122 Removes the IP address from the list of issued addresses, thus other ports can use it.
124 :param ip_address: The issued IP address.
125 :type ip_address: ``str``
127 if ip_address
is None:
130 if "/" in ip_address
:
131 address
, suffix
= ip_address
.rsplit('/', 1)
134 int_ip_address
= Net
.ip_2_int(address
)
135 if int_ip_address
in self
._issued
_ip
_addresses
.keys():
136 del self
._issued
_ip
_addresses
[int_ip_address
]
138 def reset_issued_ip_addresses(self
):
140 Resets all issued IP addresses.
142 self
._issued
_ip
_addresses
= dict()
144 def update_port_name_for_ip_address(self
, ip_address
, port_name
):
146 Updates the port name of the issued IP address.
148 :param ip_address: The already issued IP address.
149 :type ip_address: ``str``
150 :param port_name: The new port name
151 :type port_name: ``str``
153 address
, suffix
= ip_address
.rsplit('/', 1)
154 int_ip_address
= Net
.ip_2_int(address
)
155 self
._issued
_ip
_addresses
[int_ip_address
] = port_name
157 def set_cidr(self
, cidr
):
159 Sets the CIDR for the subnet. It previously checks for the correct CIDR format.
161 :param cidr: The new CIDR for the subnet.
163 :return: * *True*: When the new CIDR was set successfully.
164 * *False*: If the CIDR format was wrong.
168 if self
._cidr
is not None:
169 import emuvim
.api
.openstack
.ip_handler
as IP
170 IP
.free_cidr(self
._cidr
, self
.subnet_id
)
172 self
.reset_issued_ip_addresses()
173 self
.start_end_dict
= dict()
175 if not Net
.check_cidr_format(cidr
):
178 self
.reset_issued_ip_addresses()
179 self
.start_end_dict
= Net
.calculate_start_and_end_dict(cidr
)
192 def clear_cidr(self
):
194 self
.start_end_dict
= dict()
195 self
.reset_issued_ip_addresses()
197 def delete_subnet(self
):
198 self
.subnet_id
= None
199 self
.subnet_name
= None
200 self
.subnet_creation_time
= None
201 self
.subnet_update_time
= None
205 def calculate_start_and_end_dict(cidr
):
207 Calculates the start and end IP address for the subnet.
209 :param cidr: The CIDR for the subnet.
211 :return: Dict with start and end ip address
214 address
, suffix
= cidr
.rsplit('/', 1)
215 int_suffix
= int(suffix
)
216 int_address
= Net
.ip_2_int(address
)
217 address_space
= 2 ** 32 - 1
219 for x
in range(0, 31 - int_suffix
):
220 address_space
= ~
(~address_space |
(1 << x
))
222 start
= int_address
& address_space
223 end
= start
+ (2 ** (32 - int_suffix
) - 1)
225 return {'start': Net
.int_2_ip(start
), 'end': Net
.int_2_ip(end
)}
228 def cidr_2_int(cidr
):
231 ip
= cidr
.rsplit('/', 1)[0]
232 return Net
.ip_2_int(ip
)
237 Converts a IP address to int.
239 :param ip: IP address
241 :return: IP address as int.
244 o
= map(int, ip
.split('.'))
245 res
= (16777216 * o
[0]) + (65536 * o
[1]) + (256 * o
[2]) + o
[3]
249 def int_2_ip(int_ip
):
251 Converts a int IP address to string.
253 :param int_ip: Int IP address.
254 :type int_ip: ``int``
258 o1
= int(int_ip
/ 16777216) % 256
259 o2
= int(int_ip
/ 65536) % 256
260 o3
= int(int_ip
/ 256) % 256
261 o4
= int(int_ip
) % 256
262 return '%(o1)s.%(o2)s.%(o3)s.%(o4)s' % locals()
265 def check_cidr_format(cidr
):
267 Checks the CIDR format. An valid example is: 192.168.0.0/29
269 :param cidr: CIDR to be checked.
271 :return: * *True*: If the Format is correct.
272 * *False*: If it is not correct.
275 r
= re
.compile('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/\d{2}')
280 def create_network_dict(self
):
282 Creates the network description dictionary.
284 :return: Network description.
287 network_dict
= dict()
288 network_dict
["status"] = "ACTIVE" # TODO do we support inactive networks?
289 if self
.subnet_id
== None:
290 network_dict
["subnets"] = []
292 network_dict
["subnets"] = [self
.subnet_id
]
293 network_dict
["name"] = self
.name
294 network_dict
["admin_state_up"] = True # TODO is it always true?
295 network_dict
["tenant_id"] = "abcdefghijklmnopqrstuvwxyz123456" # TODO what should go in here
296 network_dict
["id"] = self
.id
297 network_dict
["shared"] = False # TODO is it always false?
300 def create_subnet_dict(self
):
302 Creates the subnet description dictionary.
304 :return: Subnet description.
308 subnet_dict
["name"] = self
.subnet_name
309 subnet_dict
["network_id"] = self
.id
310 subnet_dict
["tenant_id"] = "abcdefghijklmnopqrstuvwxyz123456" # TODO what should go in here?
311 subnet_dict
["created_at"] = self
.subnet_creation_time
312 subnet_dict
["dns_nameservers"] = []
313 subnet_dict
["allocation_pools"] = [self
.start_end_dict
]
314 subnet_dict
["host_routers"] = []
315 subnet_dict
["gateway_ip"] = self
.gateway_ip
316 subnet_dict
["ip_version"] = "4"
317 subnet_dict
["cidr"] = self
.get_cidr()
318 subnet_dict
["updated_at"] = self
.subnet_update_time
319 subnet_dict
["id"] = self
.subnet_id
320 subnet_dict
["enable_dhcp"] = False # TODO do we support DHCP?
323 def __eq__(self
, other
):
324 if self
.name
== other
.name
and self
.subnet_name
== other
.subnet_name
and \
325 self
.gateway_ip
== other
.gateway_ip
and \
326 self
.segmentation_id
== other
.segmentation_id
and \
327 self
._cidr
== other
._cidr
and \
328 self
.start_end_dict
== other
.start_end_dict
:
333 return hash((self
.name
,
336 self
.segmentation_id
,
338 self
.start_end_dict
))