Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / logic / subnets.py @ 3549cb2f

History | View | Annotate | Download (10 kB)

1 9eb0710b Dionysis Grigoropoulos
# Copyright 2013 GRNET S.A. All rights reserved.
2 9eb0710b Dionysis Grigoropoulos
#
3 9eb0710b Dionysis Grigoropoulos
# Redistribution and use in source and binary forms, with or
4 9eb0710b Dionysis Grigoropoulos
# without modification, are permitted provided that the following
5 9eb0710b Dionysis Grigoropoulos
# conditions are met:
6 9eb0710b Dionysis Grigoropoulos
#
7 9eb0710b Dionysis Grigoropoulos
#   1. Redistributions of source code must retain the above
8 9eb0710b Dionysis Grigoropoulos
#      copyright notice, this list of conditions and the following
9 9eb0710b Dionysis Grigoropoulos
#      disclaimer.
10 9eb0710b Dionysis Grigoropoulos
#
11 9eb0710b Dionysis Grigoropoulos
#   2. Redistributions in binary form must reproduce the above
12 9eb0710b Dionysis Grigoropoulos
#      copyright notice, this list of conditions and the following
13 9eb0710b Dionysis Grigoropoulos
#      disclaimer in the documentation and/or other materials
14 9eb0710b Dionysis Grigoropoulos
#      provided with the distribution.
15 9eb0710b Dionysis Grigoropoulos
#
16 9eb0710b Dionysis Grigoropoulos
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 9eb0710b Dionysis Grigoropoulos
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 9eb0710b Dionysis Grigoropoulos
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 9eb0710b Dionysis Grigoropoulos
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 9eb0710b Dionysis Grigoropoulos
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 9eb0710b Dionysis Grigoropoulos
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 9eb0710b Dionysis Grigoropoulos
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 9eb0710b Dionysis Grigoropoulos
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 9eb0710b Dionysis Grigoropoulos
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 9eb0710b Dionysis Grigoropoulos
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 9eb0710b Dionysis Grigoropoulos
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 9eb0710b Dionysis Grigoropoulos
# POSSIBILITY OF SUCH DAMAGE.
28 9eb0710b Dionysis Grigoropoulos
#
29 9eb0710b Dionysis Grigoropoulos
# The views and conclusions contained in the software and
30 9eb0710b Dionysis Grigoropoulos
# documentation are those of the authors and should not be
31 9eb0710b Dionysis Grigoropoulos
# interpreted as representing official policies, either expressed
32 9eb0710b Dionysis Grigoropoulos
# or implied, of GRNET S.A.
33 9eb0710b Dionysis Grigoropoulos
34 f82dfec6 Christos Stavrakakis
import ipaddr
35 9eb0710b Dionysis Grigoropoulos
from logging import getLogger
36 f82dfec6 Christos Stavrakakis
from functools import wraps
37 f82dfec6 Christos Stavrakakis
38 f82dfec6 Christos Stavrakakis
from django.conf import settings
39 f82dfec6 Christos Stavrakakis
from django.db import transaction
40 3549cb2f Dionysis Grigoropoulos
from django.db.models import Q
41 3549cb2f Dionysis Grigoropoulos
42 9eb0710b Dionysis Grigoropoulos
from snf_django.lib import api
43 9eb0710b Dionysis Grigoropoulos
from snf_django.lib.api import faults
44 9eb0710b Dionysis Grigoropoulos
45 9eb0710b Dionysis Grigoropoulos
from synnefo.db.models import Subnet, Network, IPPoolTable
46 9eb0710b Dionysis Grigoropoulos
47 9eb0710b Dionysis Grigoropoulos
log = getLogger(__name__)
48 9eb0710b Dionysis Grigoropoulos
49 9eb0710b Dionysis Grigoropoulos
50 9eb0710b Dionysis Grigoropoulos
def subnet_command(action):
51 9eb0710b Dionysis Grigoropoulos
    def decorator(func):
52 9eb0710b Dionysis Grigoropoulos
        @wraps(func)
53 9eb0710b Dionysis Grigoropoulos
        @transaction.commit_on_success()
54 9eb0710b Dionysis Grigoropoulos
        def wrapper(subnet, *args, **kwargs):
55 9eb0710b Dionysis Grigoropoulos
            return func(subnet, *args, **kwargs)
56 9eb0710b Dionysis Grigoropoulos
        return wrapper
57 9eb0710b Dionysis Grigoropoulos
    return decorator
58 9eb0710b Dionysis Grigoropoulos
59 9eb0710b Dionysis Grigoropoulos
60 9eb0710b Dionysis Grigoropoulos
def list_subnets(user_id):
61 9eb0710b Dionysis Grigoropoulos
    """List all subnets of a user"""
62 3549cb2f Dionysis Grigoropoulos
    log.debug('list_subnets %s', user_id)
63 9eb0710b Dionysis Grigoropoulos
64 3549cb2f Dionysis Grigoropoulos
    user_subnets = Subnet.objects.filter((Q(network__userid=user_id) &
65 3549cb2f Dionysis Grigoropoulos
                                          Q(network__public=False)) |
66 3549cb2f Dionysis Grigoropoulos
                                         Q(network__public=True))
67 5d83d2ff Dionysis Grigoropoulos
    return user_subnets
68 9eb0710b Dionysis Grigoropoulos
69 9eb0710b Dionysis Grigoropoulos
70 9eb0710b Dionysis Grigoropoulos
@transaction.commit_on_success
71 f82dfec6 Christos Stavrakakis
def create_subnet(*args, **kwargs):
72 f82dfec6 Christos Stavrakakis
    return _create_subnet(*args, **kwargs)
73 f82dfec6 Christos Stavrakakis
74 f82dfec6 Christos Stavrakakis
75 f82dfec6 Christos Stavrakakis
def _create_subnet(network_id, user_id, cidr, name, ipversion=4, gateway=None,
76 b7311f3d Dionysis Grigoropoulos
                   dhcp=True, slaac=True, dns_nameservers=None,
77 f82dfec6 Christos Stavrakakis
                   allocation_pools=None, host_routes=None):
78 316787ab Dionysis Grigoropoulos
    """Create a subnet
79 f82dfec6 Christos Stavrakakis

80 9eb0710b Dionysis Grigoropoulos
    network_id and the desired cidr are mandatory, everything else is optional
81 316787ab Dionysis Grigoropoulos

82 9eb0710b Dionysis Grigoropoulos
    """
83 9eb0710b Dionysis Grigoropoulos
    try:
84 9eb0710b Dionysis Grigoropoulos
        network = Network.objects.get(id=network_id)
85 9eb0710b Dionysis Grigoropoulos
    except Network.DoesNotExist:
86 b7311f3d Dionysis Grigoropoulos
        raise api.faults.ItemNotFound("No network found with that id")
87 9eb0710b Dionysis Grigoropoulos
88 5d83d2ff Dionysis Grigoropoulos
    if user_id != network.userid:
89 5d83d2ff Dionysis Grigoropoulos
        raise api.faults.Unauthorized("Unauthorized operation")
90 5d83d2ff Dionysis Grigoropoulos
91 9eb0710b Dionysis Grigoropoulos
    if ipversion not in [4, 6]:
92 9eb0710b Dionysis Grigoropoulos
        raise api.faults.BadRequest("Malformed IP version type")
93 9eb0710b Dionysis Grigoropoulos
94 99718617 Dionysis Grigoropoulos
    check_number_of_subnets(network, ipversion)
95 99718617 Dionysis Grigoropoulos
96 9eb0710b Dionysis Grigoropoulos
    # Returns the first available IP in the subnet
97 99718617 Dionysis Grigoropoulos
    try:
98 f82dfec6 Christos Stavrakakis
        cidr_ip = ipaddr.IPNetwork(cidr)
99 99718617 Dionysis Grigoropoulos
    except ValueError:
100 99718617 Dionysis Grigoropoulos
        raise api.faults.BadRequest("Malformed CIDR")
101 5d83d2ff Dionysis Grigoropoulos
102 9eb0710b Dionysis Grigoropoulos
    if ipversion == 6:
103 f82dfec6 Christos Stavrakakis
        validate_subnet_params(None, None, cidr, gateway)
104 9eb0710b Dionysis Grigoropoulos
    else:
105 f82dfec6 Christos Stavrakakis
        validate_subnet_params(cidr, gateway)
106 9eb0710b Dionysis Grigoropoulos
107 9eb0710b Dionysis Grigoropoulos
    name = check_name_length(name)
108 9eb0710b Dionysis Grigoropoulos
    sub = Subnet.objects.create(name=name, network=network, cidr=cidr,
109 9eb0710b Dionysis Grigoropoulos
                                ipversion=ipversion, gateway=gateway,
110 5d83d2ff Dionysis Grigoropoulos
                                dhcp=dhcp, host_routes=host_routes,
111 5d83d2ff Dionysis Grigoropoulos
                                dns_nameservers=dns_nameservers)
112 9eb0710b Dionysis Grigoropoulos
113 b7311f3d Dionysis Grigoropoulos
    gateway_ip = ipaddr.IPAddress(gateway) if gateway else None
114 b7311f3d Dionysis Grigoropoulos
115 9eb0710b Dionysis Grigoropoulos
    if allocation_pools is not None:
116 9eb0710b Dionysis Grigoropoulos
        # If the user specified IP allocation pools, validate them and use them
117 9eb0710b Dionysis Grigoropoulos
        if ipversion == 6:
118 9eb0710b Dionysis Grigoropoulos
            raise api.faults.Conflict("Can't allocate an IP Pool in IPv6")
119 5d83d2ff Dionysis Grigoropoulos
        validate_subpools(allocation_pools, cidr_ip, gateway_ip)
120 9eb0710b Dionysis Grigoropoulos
    if allocation_pools is None and ipversion == 4:
121 9eb0710b Dionysis Grigoropoulos
        # Check if the gateway is the first IP of the subnet, in this case
122 9eb0710b Dionysis Grigoropoulos
        # create a single ip pool
123 b7311f3d Dionysis Grigoropoulos
        if gateway_ip:
124 b7311f3d Dionysis Grigoropoulos
            if int(gateway_ip) - int(cidr_ip) == 1:
125 b7311f3d Dionysis Grigoropoulos
                allocation_pools = [[gateway_ip + 1, cidr_ip.broadcast - 1]]
126 b7311f3d Dionysis Grigoropoulos
            else:
127 b7311f3d Dionysis Grigoropoulos
                # If the gateway isn't the first available ip, create two
128 b7311f3d Dionysis Grigoropoulos
                # different ip pools adjacent to said ip
129 b7311f3d Dionysis Grigoropoulos
                allocation_pools = (([cidr_ip.network + 1, gateway_ip - 1]),
130 b7311f3d Dionysis Grigoropoulos
                                    ([gateway_ip + 1, cidr_ip.broadcast - 1]))
131 9eb0710b Dionysis Grigoropoulos
        else:
132 b7311f3d Dionysis Grigoropoulos
            allocation_pools = [[cidr_ip.network + 1, cidr_ip.broadcast - 1]]
133 9eb0710b Dionysis Grigoropoulos
134 5d83d2ff Dionysis Grigoropoulos
    if allocation_pools:
135 5d83d2ff Dionysis Grigoropoulos
        create_ip_pools(allocation_pools, cidr_ip, sub)
136 9eb0710b Dionysis Grigoropoulos
137 9eb0710b Dionysis Grigoropoulos
    return sub
138 9eb0710b Dionysis Grigoropoulos
139 9eb0710b Dionysis Grigoropoulos
140 9eb0710b Dionysis Grigoropoulos
def get_subnet(sub_id):
141 9eb0710b Dionysis Grigoropoulos
    """Show info of a specific subnet"""
142 9eb0710b Dionysis Grigoropoulos
    log.debug('get_subnet %s', sub_id)
143 9eb0710b Dionysis Grigoropoulos
    try:
144 9eb0710b Dionysis Grigoropoulos
        subnet = Subnet.objects.get(id=sub_id)
145 9eb0710b Dionysis Grigoropoulos
    except Subnet.DoesNotExist:
146 9eb0710b Dionysis Grigoropoulos
        raise api.faults.ItemNotFound("Subnet not found")
147 9eb0710b Dionysis Grigoropoulos
148 5d83d2ff Dionysis Grigoropoulos
    return subnet
149 9eb0710b Dionysis Grigoropoulos
150 9eb0710b Dionysis Grigoropoulos
151 9eb0710b Dionysis Grigoropoulos
def delete_subnet():
152 316787ab Dionysis Grigoropoulos
    """Delete a subnet, raises BadRequest
153 9eb0710b Dionysis Grigoropoulos
    A subnet is deleted ONLY when the network that it belongs to is deleted
154 316787ab Dionysis Grigoropoulos

155 9eb0710b Dionysis Grigoropoulos
    """
156 9eb0710b Dionysis Grigoropoulos
    raise api.faults.BadRequest("Deletion of a subnet is not supported")
157 9eb0710b Dionysis Grigoropoulos
158 9eb0710b Dionysis Grigoropoulos
159 9eb0710b Dionysis Grigoropoulos
@transaction.commit_on_success
160 8646e606 Dionysis Grigoropoulos
def update_subnet(sub_id, name, user_id):
161 316787ab Dionysis Grigoropoulos
    """Update the fields of a subnet
162 9eb0710b Dionysis Grigoropoulos
    Only the name can be updated
163 316787ab Dionysis Grigoropoulos

164 9eb0710b Dionysis Grigoropoulos
    """
165 5d83d2ff Dionysis Grigoropoulos
    log.info('Update subnet %s, name %s' % (sub_id, name))
166 9eb0710b Dionysis Grigoropoulos
167 9eb0710b Dionysis Grigoropoulos
    try:
168 9eb0710b Dionysis Grigoropoulos
        subnet = Subnet.objects.get(id=sub_id)
169 9eb0710b Dionysis Grigoropoulos
    except:
170 9eb0710b Dionysis Grigoropoulos
        raise api.faults.ItemNotFound("Subnet not found")
171 9eb0710b Dionysis Grigoropoulos
172 8646e606 Dionysis Grigoropoulos
    if user_id != subnet.network.userid:
173 8646e606 Dionysis Grigoropoulos
        raise api.faults.Unauthorized("Unauthorized operation")
174 8646e606 Dionysis Grigoropoulos
175 9eb0710b Dionysis Grigoropoulos
    check_name_length(name)
176 9eb0710b Dionysis Grigoropoulos
177 9eb0710b Dionysis Grigoropoulos
    subnet.name = name
178 9eb0710b Dionysis Grigoropoulos
    subnet.save()
179 9eb0710b Dionysis Grigoropoulos
180 9eb0710b Dionysis Grigoropoulos
    return subnet
181 9eb0710b Dionysis Grigoropoulos
182 9eb0710b Dionysis Grigoropoulos
183 9eb0710b Dionysis Grigoropoulos
#Utility functions
184 9eb0710b Dionysis Grigoropoulos
def create_ip_pools(pools, cidr, subnet):
185 9eb0710b Dionysis Grigoropoulos
    """Create IP Pools in the database"""
186 f82dfec6 Christos Stavrakakis
    ip_pools = []
187 9eb0710b Dionysis Grigoropoulos
    for pool in pools:
188 9eb0710b Dionysis Grigoropoulos
        size = int(pool[1]) - int(pool[0]) + 1
189 9eb0710b Dionysis Grigoropoulos
        base = str(cidr)
190 9eb0710b Dionysis Grigoropoulos
        offset = int(pool[0]) - int(cidr.network)
191 9eb0710b Dionysis Grigoropoulos
        ip_pool = IPPoolTable.objects.create(size=size, offset=offset,
192 9eb0710b Dionysis Grigoropoulos
                                             base=base, subnet=subnet)
193 f82dfec6 Christos Stavrakakis
        ip_pools.append(ip_pool)
194 f82dfec6 Christos Stavrakakis
    return ip_pools
195 9eb0710b Dionysis Grigoropoulos
196 9eb0710b Dionysis Grigoropoulos
197 9eb0710b Dionysis Grigoropoulos
def check_number_of_subnets(network, version):
198 9eb0710b Dionysis Grigoropoulos
    """Check if a user can add a subnet in a network"""
199 9eb0710b Dionysis Grigoropoulos
    if network.subnets.filter(ipversion=version):
200 9eb0710b Dionysis Grigoropoulos
        raise api.faults.BadRequest("Only one subnet of IPv4/IPv6 per "
201 9eb0710b Dionysis Grigoropoulos
                                    "network is allowed")
202 9eb0710b Dionysis Grigoropoulos
203 9eb0710b Dionysis Grigoropoulos
204 9eb0710b Dionysis Grigoropoulos
def check_name_length(name):
205 9eb0710b Dionysis Grigoropoulos
    """Check if the length of a name is within acceptable value"""
206 9eb0710b Dionysis Grigoropoulos
    if len(str(name)) > Subnet.SUBNET_NAME_LENGTH:
207 9eb0710b Dionysis Grigoropoulos
        raise api.faults.BadRequest("Subnet name too long")
208 9eb0710b Dionysis Grigoropoulos
    return name
209 9eb0710b Dionysis Grigoropoulos
210 9eb0710b Dionysis Grigoropoulos
211 9eb0710b Dionysis Grigoropoulos
def validate_subpools(pool_list, cidr, gateway):
212 316787ab Dionysis Grigoropoulos
    """Validate IP Pools
213 316787ab Dionysis Grigoropoulos

214 9eb0710b Dionysis Grigoropoulos
    Validate the given IP pools are inside the cidr range
215 9eb0710b Dionysis Grigoropoulos
    Validate there are no overlaps in the given pools
216 9eb0710b Dionysis Grigoropoulos
    Finally, validate the gateway isn't in the given ip pools
217 9eb0710b Dionysis Grigoropoulos
    Input must be a list containing a sublist with start/end ranges as
218 9eb0710b Dionysis Grigoropoulos
    ipaddr.IPAddress items eg.,
219 9eb0710b Dionysis Grigoropoulos
    [[IPv4Address('192.168.42.11'), IPv4Address('192.168.42.15')],
220 9eb0710b Dionysis Grigoropoulos
     [IPv4Address('192.168.42.30'), IPv4Address('192.168.42.60')]]
221 316787ab Dionysis Grigoropoulos

222 9eb0710b Dionysis Grigoropoulos
    """
223 9eb0710b Dionysis Grigoropoulos
    if pool_list[0][0] <= cidr.network:
224 9eb0710b Dionysis Grigoropoulos
        raise api.faults.Conflict("IP Pool out of bounds")
225 9eb0710b Dionysis Grigoropoulos
    elif pool_list[-1][1] >= cidr.broadcast:
226 9eb0710b Dionysis Grigoropoulos
        raise api.faults.Conflict("IP Pool out of bounds")
227 9eb0710b Dionysis Grigoropoulos
228 9eb0710b Dionysis Grigoropoulos
    for start, end in pool_list:
229 9eb0710b Dionysis Grigoropoulos
        if start > end:
230 9eb0710b Dionysis Grigoropoulos
            raise api.faults.Conflict("Invalid IP pool range")
231 9eb0710b Dionysis Grigoropoulos
        # Raise BadRequest if gateway is inside the pool range
232 b7311f3d Dionysis Grigoropoulos
        if gateway:
233 b7311f3d Dionysis Grigoropoulos
            if not (gateway < start or gateway > end):
234 b7311f3d Dionysis Grigoropoulos
                raise api.faults.Conflict("Gateway cannot be in pool range")
235 9eb0710b Dionysis Grigoropoulos
236 9eb0710b Dionysis Grigoropoulos
    # Check if there is a conflict between the IP Poll ranges
237 9eb0710b Dionysis Grigoropoulos
    end = cidr.network
238 9eb0710b Dionysis Grigoropoulos
    for pool in pool_list:
239 9eb0710b Dionysis Grigoropoulos
        if end >= pool[0]:
240 9eb0710b Dionysis Grigoropoulos
            raise api.faults.Conflict("IP Pool range conflict")
241 9eb0710b Dionysis Grigoropoulos
        end = pool[1]
242 f82dfec6 Christos Stavrakakis
243 f82dfec6 Christos Stavrakakis
244 f82dfec6 Christos Stavrakakis
def validate_subnet_params(subnet=None, gateway=None, subnet6=None,
245 f82dfec6 Christos Stavrakakis
                           gateway6=None):
246 f82dfec6 Christos Stavrakakis
    if subnet:
247 f82dfec6 Christos Stavrakakis
        try:
248 f82dfec6 Christos Stavrakakis
            # Use strict option to not all subnets with host bits set
249 f82dfec6 Christos Stavrakakis
            network = ipaddr.IPv4Network(subnet, strict=True)
250 f82dfec6 Christos Stavrakakis
        except ValueError:
251 f82dfec6 Christos Stavrakakis
            raise faults.BadRequest("Invalid network IPv4 subnet")
252 f82dfec6 Christos Stavrakakis
253 f82dfec6 Christos Stavrakakis
        # Check that network size is allowed!
254 f82dfec6 Christos Stavrakakis
        prefixlen = network.prefixlen
255 f82dfec6 Christos Stavrakakis
        if prefixlen > 29 or prefixlen <= settings.MAX_CIDR_BLOCK:
256 f82dfec6 Christos Stavrakakis
            raise faults.OverLimit(
257 f82dfec6 Christos Stavrakakis
                message="Unsupported network size",
258 f82dfec6 Christos Stavrakakis
                details="Netmask must be in range: (%s, 29]" %
259 f82dfec6 Christos Stavrakakis
                settings.MAX_CIDR_BLOCK)
260 f82dfec6 Christos Stavrakakis
        if gateway:  # Check that gateway belongs to network
261 f82dfec6 Christos Stavrakakis
            try:
262 f82dfec6 Christos Stavrakakis
                gateway = ipaddr.IPv4Address(gateway)
263 f82dfec6 Christos Stavrakakis
            except ValueError:
264 f82dfec6 Christos Stavrakakis
                raise faults.BadRequest("Invalid network IPv4 gateway")
265 f82dfec6 Christos Stavrakakis
            if not gateway in network:
266 f82dfec6 Christos Stavrakakis
                raise faults.BadRequest("Invalid network IPv4 gateway")
267 f82dfec6 Christos Stavrakakis
268 f82dfec6 Christos Stavrakakis
    if subnet6:
269 f82dfec6 Christos Stavrakakis
        try:
270 f82dfec6 Christos Stavrakakis
            # Use strict option to not all subnets with host bits set
271 f82dfec6 Christos Stavrakakis
            network6 = ipaddr.IPv6Network(subnet6, strict=True)
272 f82dfec6 Christos Stavrakakis
        except ValueError:
273 f82dfec6 Christos Stavrakakis
            raise faults.BadRequest("Invalid network IPv6 subnet")
274 f82dfec6 Christos Stavrakakis
        # Check that network6 is an /64 subnet, because this is imposed by
275 f82dfec6 Christos Stavrakakis
        # 'mac2eui64' utiity.
276 f82dfec6 Christos Stavrakakis
        if network6.prefixlen != 64:
277 f82dfec6 Christos Stavrakakis
            msg = ("Unsupported IPv6 subnet size. Network netmask must be"
278 f82dfec6 Christos Stavrakakis
                   " /64")
279 f82dfec6 Christos Stavrakakis
            raise faults.BadRequest(msg)
280 f82dfec6 Christos Stavrakakis
        if gateway6:
281 f82dfec6 Christos Stavrakakis
            try:
282 f82dfec6 Christos Stavrakakis
                gateway6 = ipaddr.IPv6Address(gateway6)
283 f82dfec6 Christos Stavrakakis
            except ValueError:
284 f82dfec6 Christos Stavrakakis
                raise faults.BadRequest("Invalid network IPv6 gateway")
285 f82dfec6 Christos Stavrakakis
            if not gateway6 in network6:
286 f82dfec6 Christos Stavrakakis
                raise faults.BadRequest("Invalid network IPv6 gateway")