~ubuntu-branches/ubuntu/vivid/neutron/vivid-updates

« back to all changes in this revision

Viewing changes to neutron/plugins/vmware/nsxlib/router.py

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2015-03-30 11:17:19 UTC
  • mfrom: (1.1.21)
  • Revision ID: package-import@ubuntu.com-20150330111719-h0gx7233p4jkkgfh
Tags: 1:2015.1~b3-0ubuntu1
* New upstream milestone release:
  - d/control: Align version requirements with upstream.
  - d/control: Add new dependency on oslo-log.
  - d/p/*: Rebase.
  - d/control,d/neutron-plugin-hyperv*: Dropped, decomposed into
    separate project upstream.
  - d/control,d/neutron-plugin-openflow*: Dropped, decomposed into
    separate project upstream.
  - d/neutron-common.install: Add neutron-rootwrap-daemon and 
    neutron-keepalived-state-change binaries.
  - d/rules: Ignore neutron-hyperv-agent when installing; only for Windows.
  - d/neutron-plugin-cisco.install: Drop neutron-cisco-cfg-agent as
    decomposed into separate project upstream.
  - d/neutron-plugin-vmware.install: Drop neutron-check-nsx-config and
    neutron-nsx-manage as decomposed into separate project upstream.
  - d/control: Add dependency on python-neutron-fwaas to neutron-l3-agent.
* d/pydist-overrides: Add overrides for oslo packages.
* d/control: Fixup type in package description (LP: #1263539).
* d/p/fixup-driver-test-execution.patch: Cherry pick fix from upstream VCS
  to support unit test exection in out-of-tree vendor drivers.
* d/neutron-common.postinst: Allow general access to /etc/neutron but limit
  access to root/neutron to /etc/neutron/neutron.conf to support execution
  of unit tests in decomposed vendor drivers.
* d/control: Add dependency on python-neutron-fwaas to neutron-l3-agent
  package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright 2014 VMware, Inc.
2
 
# All Rights Reserved
3
 
#
4
 
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
5
 
#    not use this file except in compliance with the License. You may obtain
6
 
#    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, WITHOUT
12
 
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
 
#    License for the specific language governing permissions and limitations
14
 
#    under the License.
15
 
 
16
 
from oslo.config import cfg
17
 
from oslo.serialization import jsonutils
18
 
from oslo.utils import excutils
19
 
 
20
 
from neutron.common import exceptions as exception
21
 
from neutron.i18n import _LE, _LI, _LW
22
 
from neutron.openstack.common import log
23
 
from neutron.plugins.vmware.api_client import exception as api_exc
24
 
from neutron.plugins.vmware.common import exceptions as nsx_exc
25
 
from neutron.plugins.vmware.common import utils
26
 
from neutron.plugins.vmware import nsxlib
27
 
from neutron.plugins.vmware.nsxlib import switch
28
 
from neutron.plugins.vmware.nsxlib import versioning
29
 
 
30
 
# @versioning.versioned decorator makes the apparent function body
31
 
# totally unrelated to the real function.  This confuses pylint :(
32
 
# pylint: disable=assignment-from-no-return
33
 
 
34
 
HTTP_GET = "GET"
35
 
HTTP_POST = "POST"
36
 
HTTP_DELETE = "DELETE"
37
 
HTTP_PUT = "PUT"
38
 
 
39
 
LROUTER_RESOURCE = "lrouter"
40
 
LROUTER_RESOURCE = "lrouter"
41
 
LROUTERPORT_RESOURCE = "lport/%s" % LROUTER_RESOURCE
42
 
LROUTERRIB_RESOURCE = "rib/%s" % LROUTER_RESOURCE
43
 
LROUTERNAT_RESOURCE = "nat/lrouter"
44
 
# Constants for NAT rules
45
 
MATCH_KEYS = ["destination_ip_addresses", "destination_port_max",
46
 
              "destination_port_min", "source_ip_addresses",
47
 
              "source_port_max", "source_port_min", "protocol"]
48
 
 
49
 
LOG = log.getLogger(__name__)
50
 
 
51
 
 
52
 
def _prepare_lrouter_body(name, neutron_router_id, tenant_id,
53
 
                          router_type, distributed=None, **kwargs):
54
 
    body = {
55
 
        "display_name": utils.check_and_truncate(name),
56
 
        "tags": utils.get_tags(os_tid=tenant_id,
57
 
                               q_router_id=neutron_router_id),
58
 
        "routing_config": {
59
 
            "type": router_type
60
 
        },
61
 
        "type": "LogicalRouterConfig",
62
 
        "replication_mode": cfg.CONF.NSX.replication_mode,
63
 
    }
64
 
    # add the distributed key only if not None (ie: True or False)
65
 
    if distributed is not None:
66
 
        body['distributed'] = distributed
67
 
    if kwargs:
68
 
        body["routing_config"].update(kwargs)
69
 
    return body
70
 
 
71
 
 
72
 
def _create_implicit_routing_lrouter(cluster, neutron_router_id, tenant_id,
73
 
                                     display_name, nexthop, distributed=None):
74
 
    implicit_routing_config = {
75
 
        "default_route_next_hop": {
76
 
            "gateway_ip_address": nexthop,
77
 
            "type": "RouterNextHop"
78
 
        },
79
 
    }
80
 
    lrouter_obj = _prepare_lrouter_body(
81
 
        display_name, neutron_router_id, tenant_id,
82
 
        "SingleDefaultRouteImplicitRoutingConfig",
83
 
        distributed=distributed,
84
 
        **implicit_routing_config)
85
 
    return nsxlib.do_request(HTTP_POST,
86
 
                             nsxlib._build_uri_path(LROUTER_RESOURCE),
87
 
                             jsonutils.dumps(lrouter_obj), cluster=cluster)
88
 
 
89
 
 
90
 
def create_implicit_routing_lrouter(cluster, neutron_router_id, tenant_id,
91
 
                                    display_name, nexthop):
92
 
    """Create a NSX logical router on the specified cluster.
93
 
 
94
 
        :param cluster: The target NSX cluster
95
 
        :param tenant_id: Identifier of the Openstack tenant for which
96
 
        the logical router is being created
97
 
        :param display_name: Descriptive name of this logical router
98
 
        :param nexthop: External gateway IP address for the logical router
99
 
        :raise NsxApiException: if there is a problem while communicating
100
 
        with the NSX controller
101
 
    """
102
 
    return _create_implicit_routing_lrouter(
103
 
        cluster, neutron_router_id, tenant_id, display_name, nexthop)
104
 
 
105
 
 
106
 
def create_implicit_routing_lrouter_with_distribution(
107
 
    cluster, neutron_router_id, tenant_id, display_name,
108
 
    nexthop, distributed=None):
109
 
    """Create a NSX logical router on the specified cluster.
110
 
 
111
 
    This function also allows for creating distributed lrouters
112
 
    :param cluster: The target NSX cluster
113
 
    :param tenant_id: Identifier of the Openstack tenant for which
114
 
    the logical router is being created
115
 
    :param display_name: Descriptive name of this logical router
116
 
    :param nexthop: External gateway IP address for the logical router
117
 
    :param distributed: True for distributed logical routers
118
 
    :raise NsxApiException: if there is a problem while communicating
119
 
    with the NSX controller
120
 
    """
121
 
    return _create_implicit_routing_lrouter(
122
 
        cluster, neutron_router_id, tenant_id,
123
 
        display_name, nexthop, distributed)
124
 
 
125
 
 
126
 
def create_explicit_routing_lrouter(cluster, neutron_router_id, tenant_id,
127
 
                                    display_name, nexthop, distributed=None):
128
 
    lrouter_obj = _prepare_lrouter_body(
129
 
        display_name, neutron_router_id, tenant_id,
130
 
        "RoutingTableRoutingConfig", distributed=distributed)
131
 
    router = nsxlib.do_request(HTTP_POST,
132
 
                               nsxlib._build_uri_path(LROUTER_RESOURCE),
133
 
                               jsonutils.dumps(lrouter_obj), cluster=cluster)
134
 
    default_gw = {'prefix': '0.0.0.0/0', 'next_hop_ip': nexthop}
135
 
    create_explicit_route_lrouter(cluster, router['uuid'], default_gw)
136
 
    return router
137
 
 
138
 
 
139
 
def delete_lrouter(cluster, lrouter_id):
140
 
    nsxlib.do_request(HTTP_DELETE,
141
 
                      nsxlib._build_uri_path(LROUTER_RESOURCE,
142
 
                                             resource_id=lrouter_id),
143
 
                      cluster=cluster)
144
 
 
145
 
 
146
 
def get_lrouter(cluster, lrouter_id):
147
 
    return nsxlib.do_request(HTTP_GET,
148
 
                             nsxlib._build_uri_path(
149
 
                                 LROUTER_RESOURCE,
150
 
                                 resource_id=lrouter_id,
151
 
                                 relations='LogicalRouterStatus'),
152
 
                             cluster=cluster)
153
 
 
154
 
 
155
 
def query_lrouters(cluster, fields=None, filters=None):
156
 
    return nsxlib.get_all_query_pages(
157
 
        nsxlib._build_uri_path(LROUTER_RESOURCE,
158
 
                               fields=fields,
159
 
                               relations='LogicalRouterStatus',
160
 
                               filters=filters),
161
 
        cluster)
162
 
 
163
 
 
164
 
def get_lrouters(cluster, tenant_id, fields=None, filters=None):
165
 
    # FIXME(salv-orlando): Fields parameter is ignored in this routine
166
 
    actual_filters = {}
167
 
    if filters:
168
 
        actual_filters.update(filters)
169
 
    if tenant_id:
170
 
        actual_filters['tag'] = tenant_id
171
 
        actual_filters['tag_scope'] = 'os_tid'
172
 
    lrouter_fields = "uuid,display_name,fabric_status,tags"
173
 
    return query_lrouters(cluster, lrouter_fields, actual_filters)
174
 
 
175
 
 
176
 
def update_implicit_routing_lrouter(cluster, r_id, display_name, nexthop):
177
 
    lrouter_obj = get_lrouter(cluster, r_id)
178
 
    if not display_name and not nexthop:
179
 
        # Nothing to update
180
 
        return lrouter_obj
181
 
    # It seems that this is faster than the doing an if on display_name
182
 
    lrouter_obj["display_name"] = (utils.check_and_truncate(display_name) or
183
 
                                   lrouter_obj["display_name"])
184
 
    if nexthop:
185
 
        nh_element = lrouter_obj["routing_config"].get(
186
 
            "default_route_next_hop")
187
 
        if nh_element:
188
 
            nh_element["gateway_ip_address"] = nexthop
189
 
    return nsxlib.do_request(HTTP_PUT,
190
 
                             nsxlib._build_uri_path(LROUTER_RESOURCE,
191
 
                                                    resource_id=r_id),
192
 
                             jsonutils.dumps(lrouter_obj),
193
 
                             cluster=cluster)
194
 
 
195
 
 
196
 
def get_explicit_routes_lrouter(cluster, router_id, protocol_type='static'):
197
 
    static_filter = {'protocol': protocol_type}
198
 
    existing_routes = nsxlib.do_request(
199
 
        HTTP_GET,
200
 
        nsxlib._build_uri_path(LROUTERRIB_RESOURCE,
201
 
                               filters=static_filter,
202
 
                               fields="*",
203
 
                               parent_resource_id=router_id),
204
 
        cluster=cluster)['results']
205
 
    return existing_routes
206
 
 
207
 
 
208
 
def delete_explicit_route_lrouter(cluster, router_id, route_id):
209
 
    nsxlib.do_request(HTTP_DELETE,
210
 
                      nsxlib._build_uri_path(LROUTERRIB_RESOURCE,
211
 
                                             resource_id=route_id,
212
 
                                             parent_resource_id=router_id),
213
 
                      cluster=cluster)
214
 
 
215
 
 
216
 
def create_explicit_route_lrouter(cluster, router_id, route):
217
 
    next_hop_ip = route.get("nexthop") or route.get("next_hop_ip")
218
 
    prefix = route.get("destination") or route.get("prefix")
219
 
    uuid = nsxlib.do_request(
220
 
        HTTP_POST,
221
 
        nsxlib._build_uri_path(LROUTERRIB_RESOURCE,
222
 
                               parent_resource_id=router_id),
223
 
        jsonutils.dumps({
224
 
            "action": "accept",
225
 
            "next_hop_ip": next_hop_ip,
226
 
            "prefix": prefix,
227
 
            "protocol": "static"
228
 
        }),
229
 
        cluster=cluster)['uuid']
230
 
    return uuid
231
 
 
232
 
 
233
 
def update_explicit_routes_lrouter(cluster, router_id, routes):
234
 
    # Update in bulk: delete them all, and add the ones specified
235
 
    # but keep track of what is been modified to allow roll-backs
236
 
    # in case of failures
237
 
    nsx_routes = get_explicit_routes_lrouter(cluster, router_id)
238
 
    try:
239
 
        deleted_routes = []
240
 
        added_routes = []
241
 
        # omit the default route (0.0.0.0/0) from the processing;
242
 
        # this must be handled through the nexthop for the router
243
 
        for route in nsx_routes:
244
 
            prefix = route.get("destination") or route.get("prefix")
245
 
            if prefix != '0.0.0.0/0':
246
 
                delete_explicit_route_lrouter(cluster,
247
 
                                              router_id,
248
 
                                              route['uuid'])
249
 
                deleted_routes.append(route)
250
 
        for route in routes:
251
 
            prefix = route.get("destination") or route.get("prefix")
252
 
            if prefix != '0.0.0.0/0':
253
 
                uuid = create_explicit_route_lrouter(cluster,
254
 
                                                     router_id, route)
255
 
                added_routes.append(uuid)
256
 
    except api_exc.NsxApiException:
257
 
        LOG.exception(_LE('Cannot update NSX routes %(routes)s for '
258
 
                          'router %(router_id)s'),
259
 
                      {'routes': routes, 'router_id': router_id})
260
 
        # Roll back to keep NSX in consistent state
261
 
        with excutils.save_and_reraise_exception():
262
 
            if nsx_routes:
263
 
                if deleted_routes:
264
 
                    for route in deleted_routes:
265
 
                        create_explicit_route_lrouter(cluster,
266
 
                                                      router_id, route)
267
 
                if added_routes:
268
 
                    for route_id in added_routes:
269
 
                        delete_explicit_route_lrouter(cluster,
270
 
                                                      router_id, route_id)
271
 
    return nsx_routes
272
 
 
273
 
 
274
 
def get_default_route_explicit_routing_lrouter_v33(cluster, router_id):
275
 
    static_filter = {"protocol": "static",
276
 
                     "prefix": "0.0.0.0/0"}
277
 
    default_route = nsxlib.do_request(
278
 
        HTTP_GET,
279
 
        nsxlib._build_uri_path(LROUTERRIB_RESOURCE,
280
 
                               filters=static_filter,
281
 
                               fields="*",
282
 
                               parent_resource_id=router_id),
283
 
        cluster=cluster)["results"][0]
284
 
    return default_route
285
 
 
286
 
 
287
 
def get_default_route_explicit_routing_lrouter_v32(cluster, router_id):
288
 
    # Scan all routes because 3.2 does not support query by prefix
289
 
    all_routes = get_explicit_routes_lrouter(cluster, router_id)
290
 
    for route in all_routes:
291
 
        if route['prefix'] == '0.0.0.0/0':
292
 
            return route
293
 
 
294
 
 
295
 
def update_default_gw_explicit_routing_lrouter(cluster, router_id, next_hop):
296
 
    default_route = get_default_route_explicit_routing_lrouter(cluster,
297
 
                                                               router_id)
298
 
    if next_hop != default_route["next_hop_ip"]:
299
 
        new_default_route = {"action": "accept",
300
 
                             "next_hop_ip": next_hop,
301
 
                             "prefix": "0.0.0.0/0",
302
 
                             "protocol": "static"}
303
 
        nsxlib.do_request(HTTP_PUT,
304
 
                          nsxlib._build_uri_path(
305
 
                              LROUTERRIB_RESOURCE,
306
 
                              resource_id=default_route['uuid'],
307
 
                              parent_resource_id=router_id),
308
 
                          jsonutils.dumps(new_default_route),
309
 
                          cluster=cluster)
310
 
 
311
 
 
312
 
def update_explicit_routing_lrouter(cluster, router_id,
313
 
                                    display_name, next_hop, routes=None):
314
 
    update_implicit_routing_lrouter(cluster, router_id, display_name, next_hop)
315
 
    if next_hop:
316
 
        update_default_gw_explicit_routing_lrouter(cluster,
317
 
                                                   router_id, next_hop)
318
 
    if routes is not None:
319
 
        return update_explicit_routes_lrouter(cluster, router_id, routes)
320
 
 
321
 
 
322
 
def query_lrouter_lports(cluster, lr_uuid, fields="*",
323
 
                         filters=None, relations=None):
324
 
    uri = nsxlib._build_uri_path(LROUTERPORT_RESOURCE,
325
 
                                 parent_resource_id=lr_uuid,
326
 
                                 fields=fields, filters=filters,
327
 
                                 relations=relations)
328
 
    return nsxlib.do_request(HTTP_GET, uri, cluster=cluster)['results']
329
 
 
330
 
 
331
 
def create_router_lport(cluster, lrouter_uuid, tenant_id, neutron_port_id,
332
 
                        display_name, admin_status_enabled, ip_addresses,
333
 
                        mac_address=None):
334
 
    """Creates a logical port on the assigned logical router."""
335
 
    lport_obj = dict(
336
 
        admin_status_enabled=admin_status_enabled,
337
 
        display_name=display_name,
338
 
        tags=utils.get_tags(os_tid=tenant_id, q_port_id=neutron_port_id),
339
 
        ip_addresses=ip_addresses,
340
 
        type="LogicalRouterPortConfig"
341
 
    )
342
 
    # Only add the mac_address to lport_obj if present. This is because
343
 
    # when creating the fake_ext_gw there is no mac_address present.
344
 
    if mac_address:
345
 
        lport_obj['mac_address'] = mac_address
346
 
    path = nsxlib._build_uri_path(LROUTERPORT_RESOURCE,
347
 
                                  parent_resource_id=lrouter_uuid)
348
 
    result = nsxlib.do_request(HTTP_POST, path, jsonutils.dumps(lport_obj),
349
 
                               cluster=cluster)
350
 
 
351
 
    LOG.debug("Created logical port %(lport_uuid)s on "
352
 
              "logical router %(lrouter_uuid)s",
353
 
              {'lport_uuid': result['uuid'],
354
 
               'lrouter_uuid': lrouter_uuid})
355
 
    return result
356
 
 
357
 
 
358
 
def update_router_lport(cluster, lrouter_uuid, lrouter_port_uuid,
359
 
                        tenant_id, neutron_port_id, display_name,
360
 
                        admin_status_enabled, ip_addresses):
361
 
    """Updates a logical port on the assigned logical router."""
362
 
    lport_obj = dict(
363
 
        admin_status_enabled=admin_status_enabled,
364
 
        display_name=display_name,
365
 
        tags=utils.get_tags(os_tid=tenant_id, q_port_id=neutron_port_id),
366
 
        ip_addresses=ip_addresses,
367
 
        type="LogicalRouterPortConfig"
368
 
    )
369
 
    # Do not pass null items to NSX
370
 
    for key in lport_obj.keys():
371
 
        if lport_obj[key] is None:
372
 
            del lport_obj[key]
373
 
    path = nsxlib._build_uri_path(LROUTERPORT_RESOURCE,
374
 
                                  lrouter_port_uuid,
375
 
                                  parent_resource_id=lrouter_uuid)
376
 
    result = nsxlib.do_request(HTTP_PUT, path,
377
 
                               jsonutils.dumps(lport_obj),
378
 
                               cluster=cluster)
379
 
    LOG.debug("Updated logical port %(lport_uuid)s on "
380
 
              "logical router %(lrouter_uuid)s",
381
 
              {'lport_uuid': lrouter_port_uuid, 'lrouter_uuid': lrouter_uuid})
382
 
    return result
383
 
 
384
 
 
385
 
def delete_router_lport(cluster, lrouter_uuid, lport_uuid):
386
 
    """Creates a logical port on the assigned logical router."""
387
 
    path = nsxlib._build_uri_path(LROUTERPORT_RESOURCE, lport_uuid,
388
 
                                  lrouter_uuid)
389
 
    nsxlib.do_request(HTTP_DELETE, path, cluster=cluster)
390
 
    LOG.debug("Delete logical router port %(lport_uuid)s on "
391
 
              "logical router %(lrouter_uuid)s",
392
 
              {'lport_uuid': lport_uuid,
393
 
               'lrouter_uuid': lrouter_uuid})
394
 
 
395
 
 
396
 
def delete_peer_router_lport(cluster, lr_uuid, ls_uuid, lp_uuid):
397
 
    nsx_port = switch.get_port(cluster, ls_uuid, lp_uuid,
398
 
                               relations="LogicalPortAttachment")
399
 
    relations = nsx_port.get('_relations')
400
 
    if relations:
401
 
        att_data = relations.get('LogicalPortAttachment')
402
 
        if att_data:
403
 
            lrp_uuid = att_data.get('peer_port_uuid')
404
 
            if lrp_uuid:
405
 
                delete_router_lport(cluster, lr_uuid, lrp_uuid)
406
 
 
407
 
 
408
 
def find_router_gw_port(context, cluster, router_id):
409
 
    """Retrieves the external gateway port for a NSX logical router."""
410
 
 
411
 
    # Find the uuid of nsx ext gw logical router port
412
 
    # TODO(salvatore-orlando): Consider storing it in Neutron DB
413
 
    results = query_lrouter_lports(
414
 
        cluster, router_id,
415
 
        relations="LogicalPortAttachment")
416
 
    for lport in results:
417
 
        if '_relations' in lport:
418
 
            attachment = lport['_relations'].get('LogicalPortAttachment')
419
 
            if attachment and attachment.get('type') == 'L3GatewayAttachment':
420
 
                return lport
421
 
 
422
 
 
423
 
def plug_router_port_attachment(cluster, router_id, port_id,
424
 
                                attachment_uuid, nsx_attachment_type,
425
 
                                attachment_vlan=None):
426
 
    """Attach a router port to the given attachment.
427
 
 
428
 
    Current attachment types:
429
 
       - PatchAttachment [-> logical switch port uuid]
430
 
       - L3GatewayAttachment [-> L3GatewayService uuid]
431
 
    For the latter attachment type a VLAN ID can be specified as well.
432
 
    """
433
 
    uri = nsxlib._build_uri_path(LROUTERPORT_RESOURCE, port_id, router_id,
434
 
                                 is_attachment=True)
435
 
    attach_obj = {}
436
 
    attach_obj["type"] = nsx_attachment_type
437
 
    if nsx_attachment_type == "PatchAttachment":
438
 
        attach_obj["peer_port_uuid"] = attachment_uuid
439
 
    elif nsx_attachment_type == "L3GatewayAttachment":
440
 
        attach_obj["l3_gateway_service_uuid"] = attachment_uuid
441
 
        if attachment_vlan:
442
 
            attach_obj['vlan_id'] = attachment_vlan
443
 
    else:
444
 
        raise nsx_exc.InvalidAttachmentType(
445
 
            attachment_type=nsx_attachment_type)
446
 
    return nsxlib.do_request(
447
 
        HTTP_PUT, uri, jsonutils.dumps(attach_obj), cluster=cluster)
448
 
 
449
 
 
450
 
def _create_nat_match_obj(**kwargs):
451
 
    nat_match_obj = {'ethertype': 'IPv4'}
452
 
    delta = set(kwargs.keys()) - set(MATCH_KEYS)
453
 
    if delta:
454
 
        raise Exception(_("Invalid keys for NAT match: %s"), delta)
455
 
    nat_match_obj.update(kwargs)
456
 
    return nat_match_obj
457
 
 
458
 
 
459
 
def _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj):
460
 
    LOG.debug("Creating NAT rule: %s", nat_rule_obj)
461
 
    uri = nsxlib._build_uri_path(LROUTERNAT_RESOURCE,
462
 
                                 parent_resource_id=router_id)
463
 
    return nsxlib.do_request(HTTP_POST, uri, jsonutils.dumps(nat_rule_obj),
464
 
                             cluster=cluster)
465
 
 
466
 
 
467
 
def _build_snat_rule_obj(min_src_ip, max_src_ip, nat_match_obj):
468
 
    return {"to_source_ip_address_min": min_src_ip,
469
 
            "to_source_ip_address_max": max_src_ip,
470
 
            "type": "SourceNatRule",
471
 
            "match": nat_match_obj}
472
 
 
473
 
 
474
 
def create_lrouter_nosnat_rule_v2(cluster, _router_id, _match_criteria=None):
475
 
    LOG.info(_LI("No SNAT rules cannot be applied as they are not available "
476
 
                 "in this version of the NSX platform"))
477
 
 
478
 
 
479
 
def create_lrouter_nodnat_rule_v2(cluster, _router_id, _match_criteria=None):
480
 
    LOG.info(_LI("No DNAT rules cannot be applied as they are not available "
481
 
                 "in this version of the NSX platform"))
482
 
 
483
 
 
484
 
def create_lrouter_snat_rule_v2(cluster, router_id,
485
 
                                min_src_ip, max_src_ip, match_criteria=None):
486
 
 
487
 
    nat_match_obj = _create_nat_match_obj(**match_criteria)
488
 
    nat_rule_obj = _build_snat_rule_obj(min_src_ip, max_src_ip, nat_match_obj)
489
 
    return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
490
 
 
491
 
 
492
 
def create_lrouter_dnat_rule_v2(cluster, router_id, dst_ip,
493
 
                                to_dst_port=None, match_criteria=None):
494
 
 
495
 
    nat_match_obj = _create_nat_match_obj(**match_criteria)
496
 
    nat_rule_obj = {
497
 
        "to_destination_ip_address_min": dst_ip,
498
 
        "to_destination_ip_address_max": dst_ip,
499
 
        "type": "DestinationNatRule",
500
 
        "match": nat_match_obj
501
 
    }
502
 
    if to_dst_port:
503
 
        nat_rule_obj['to_destination_port'] = to_dst_port
504
 
    return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
505
 
 
506
 
 
507
 
def create_lrouter_nosnat_rule_v3(cluster, router_id, order=None,
508
 
                                  match_criteria=None):
509
 
    nat_match_obj = _create_nat_match_obj(**match_criteria)
510
 
    nat_rule_obj = {
511
 
        "type": "NoSourceNatRule",
512
 
        "match": nat_match_obj
513
 
    }
514
 
    if order:
515
 
        nat_rule_obj['order'] = order
516
 
    return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
517
 
 
518
 
 
519
 
def create_lrouter_nodnat_rule_v3(cluster, router_id, order=None,
520
 
                                  match_criteria=None):
521
 
    nat_match_obj = _create_nat_match_obj(**match_criteria)
522
 
    nat_rule_obj = {
523
 
        "type": "NoDestinationNatRule",
524
 
        "match": nat_match_obj
525
 
    }
526
 
    if order:
527
 
        nat_rule_obj['order'] = order
528
 
    return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
529
 
 
530
 
 
531
 
def create_lrouter_snat_rule_v3(cluster, router_id, min_src_ip, max_src_ip,
532
 
                                order=None, match_criteria=None):
533
 
    nat_match_obj = _create_nat_match_obj(**match_criteria)
534
 
    nat_rule_obj = _build_snat_rule_obj(min_src_ip, max_src_ip, nat_match_obj)
535
 
    if order:
536
 
        nat_rule_obj['order'] = order
537
 
    return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
538
 
 
539
 
 
540
 
def create_lrouter_dnat_rule_v3(cluster, router_id, dst_ip, to_dst_port=None,
541
 
                                order=None, match_criteria=None):
542
 
 
543
 
    nat_match_obj = _create_nat_match_obj(**match_criteria)
544
 
    nat_rule_obj = {
545
 
        "to_destination_ip_address": dst_ip,
546
 
        "type": "DestinationNatRule",
547
 
        "match": nat_match_obj
548
 
    }
549
 
    if to_dst_port:
550
 
        nat_rule_obj['to_destination_port'] = to_dst_port
551
 
    if order:
552
 
        nat_rule_obj['order'] = order
553
 
    return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
554
 
 
555
 
 
556
 
def delete_nat_rules_by_match(cluster, router_id, rule_type,
557
 
                              max_num_expected,
558
 
                              min_num_expected=0,
559
 
                              raise_on_len_mismatch=True,
560
 
                              **kwargs):
561
 
    # remove nat rules
562
 
    nat_rules = query_nat_rules(cluster, router_id)
563
 
    to_delete_ids = []
564
 
    for r in nat_rules:
565
 
        if (r['type'] != rule_type):
566
 
            continue
567
 
 
568
 
        for key, value in kwargs.iteritems():
569
 
            if not (key in r['match'] and r['match'][key] == value):
570
 
                break
571
 
        else:
572
 
            to_delete_ids.append(r['uuid'])
573
 
    num_rules_to_delete = len(to_delete_ids)
574
 
    if (num_rules_to_delete < min_num_expected or
575
 
        num_rules_to_delete > max_num_expected):
576
 
        if raise_on_len_mismatch:
577
 
            raise nsx_exc.NatRuleMismatch(actual_rules=num_rules_to_delete,
578
 
                                          min_rules=min_num_expected,
579
 
                                          max_rules=max_num_expected)
580
 
        else:
581
 
            LOG.warn(_LW("Found %(actual_rule_num)d matching NAT rules, which "
582
 
                         "is not in the expected range (%(min_exp_rule_num)d,"
583
 
                         "%(max_exp_rule_num)d)"),
584
 
                     {'actual_rule_num': num_rules_to_delete,
585
 
                      'min_exp_rule_num': min_num_expected,
586
 
                      'max_exp_rule_num': max_num_expected})
587
 
 
588
 
    for rule_id in to_delete_ids:
589
 
        delete_router_nat_rule(cluster, router_id, rule_id)
590
 
    # Return number of deleted rules - useful at least for
591
 
    # testing purposes
592
 
    return num_rules_to_delete
593
 
 
594
 
 
595
 
def delete_router_nat_rule(cluster, router_id, rule_id):
596
 
    uri = nsxlib._build_uri_path(LROUTERNAT_RESOURCE, rule_id, router_id)
597
 
    nsxlib.do_request(HTTP_DELETE, uri, cluster=cluster)
598
 
 
599
 
 
600
 
def query_nat_rules(cluster, router_id, fields="*", filters=None):
601
 
    uri = nsxlib._build_uri_path(LROUTERNAT_RESOURCE,
602
 
                                 parent_resource_id=router_id,
603
 
                                 fields=fields, filters=filters)
604
 
    return nsxlib.get_all_query_pages(uri, cluster)
605
 
 
606
 
 
607
 
# NOTE(salvatore-orlando): The following FIXME applies in general to
608
 
# each operation on list attributes.
609
 
# FIXME(salvatore-orlando): need a lock around the list of IPs on an iface
610
 
def update_lrouter_port_ips(cluster, lrouter_id, lport_id,
611
 
                            ips_to_add, ips_to_remove):
612
 
    uri = nsxlib._build_uri_path(LROUTERPORT_RESOURCE, lport_id, lrouter_id)
613
 
    try:
614
 
        port = nsxlib.do_request(HTTP_GET, uri, cluster=cluster)
615
 
        # TODO(salvatore-orlando): Enforce ips_to_add intersection with
616
 
        # ips_to_remove is empty
617
 
        ip_address_set = set(port['ip_addresses'])
618
 
        ip_address_set = ip_address_set - set(ips_to_remove)
619
 
        ip_address_set = ip_address_set | set(ips_to_add)
620
 
        # Set is not JSON serializable - convert to list
621
 
        port['ip_addresses'] = list(ip_address_set)
622
 
        nsxlib.do_request(HTTP_PUT, uri, jsonutils.dumps(port),
623
 
                          cluster=cluster)
624
 
    except exception.NotFound:
625
 
        # FIXME(salv-orlando):avoid raising different exception
626
 
        data = {'lport_id': lport_id, 'lrouter_id': lrouter_id}
627
 
        msg = (_("Router Port %(lport_id)s not found on router "
628
 
                 "%(lrouter_id)s") % data)
629
 
        LOG.exception(msg)
630
 
        raise nsx_exc.NsxPluginException(err_msg=msg)
631
 
    except api_exc.NsxApiException as e:
632
 
        msg = _("An exception occurred while updating IP addresses on a "
633
 
                "router logical port:%s") % e
634
 
        LOG.exception(msg)
635
 
        raise nsx_exc.NsxPluginException(err_msg=msg)
636
 
 
637
 
 
638
 
ROUTER_FUNC_DICT = {
639
 
    'create_lrouter': {
640
 
        2: {versioning.DEFAULT_VERSION: create_implicit_routing_lrouter, },
641
 
        3: {versioning.DEFAULT_VERSION: create_implicit_routing_lrouter,
642
 
            1: create_implicit_routing_lrouter_with_distribution,
643
 
            2: create_explicit_routing_lrouter, }, },
644
 
    'update_lrouter': {
645
 
        2: {versioning.DEFAULT_VERSION: update_implicit_routing_lrouter, },
646
 
        3: {versioning.DEFAULT_VERSION: update_implicit_routing_lrouter,
647
 
            2: update_explicit_routing_lrouter, }, },
648
 
    'create_lrouter_dnat_rule': {
649
 
        2: {versioning.DEFAULT_VERSION: create_lrouter_dnat_rule_v2, },
650
 
        3: {versioning.DEFAULT_VERSION: create_lrouter_dnat_rule_v3, }, },
651
 
    'create_lrouter_snat_rule': {
652
 
        2: {versioning.DEFAULT_VERSION: create_lrouter_snat_rule_v2, },
653
 
        3: {versioning.DEFAULT_VERSION: create_lrouter_snat_rule_v3, }, },
654
 
    'create_lrouter_nosnat_rule': {
655
 
        2: {versioning.DEFAULT_VERSION: create_lrouter_nosnat_rule_v2, },
656
 
        3: {versioning.DEFAULT_VERSION: create_lrouter_nosnat_rule_v3, }, },
657
 
    'create_lrouter_nodnat_rule': {
658
 
        2: {versioning.DEFAULT_VERSION: create_lrouter_nodnat_rule_v2, },
659
 
        3: {versioning.DEFAULT_VERSION: create_lrouter_nodnat_rule_v3, }, },
660
 
    'get_default_route_explicit_routing_lrouter': {
661
 
        3: {versioning.DEFAULT_VERSION:
662
 
            get_default_route_explicit_routing_lrouter_v32,
663
 
            2: get_default_route_explicit_routing_lrouter_v32, }, },
664
 
}
665
 
 
666
 
 
667
 
@versioning.versioned(ROUTER_FUNC_DICT)
668
 
def create_lrouter(cluster, *args, **kwargs):
669
 
    if kwargs.get('distributed', None):
670
 
        v = cluster.api_client.get_version()
671
 
        if (v.major, v.minor) < (3, 1):
672
 
            raise nsx_exc.InvalidVersion(version=v)
673
 
        return v
674
 
 
675
 
 
676
 
@versioning.versioned(ROUTER_FUNC_DICT)
677
 
def get_default_route_explicit_routing_lrouter(cluster, *args, **kwargs):
678
 
    pass
679
 
 
680
 
 
681
 
@versioning.versioned(ROUTER_FUNC_DICT)
682
 
def update_lrouter(cluster, *args, **kwargs):
683
 
    if kwargs.get('routes', None):
684
 
        v = cluster.api_client.get_version()
685
 
        if (v.major, v.minor) < (3, 2):
686
 
            raise nsx_exc.InvalidVersion(version=v)
687
 
        return v
688
 
 
689
 
 
690
 
@versioning.versioned(ROUTER_FUNC_DICT)
691
 
def create_lrouter_dnat_rule(cluster, *args, **kwargs):
692
 
    pass
693
 
 
694
 
 
695
 
@versioning.versioned(ROUTER_FUNC_DICT)
696
 
def create_lrouter_snat_rule(cluster, *args, **kwargs):
697
 
    pass
698
 
 
699
 
 
700
 
@versioning.versioned(ROUTER_FUNC_DICT)
701
 
def create_lrouter_nosnat_rule(cluster, *args, **kwargs):
702
 
    pass
703
 
 
704
 
 
705
 
@versioning.versioned(ROUTER_FUNC_DICT)
706
 
def create_lrouter_nodnat_rule(cluster, *args, **kwargs):
707
 
    pass