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

« back to all changes in this revision

Viewing changes to neutron/agent/l3/agent.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:
15
15
 
16
16
import eventlet
17
17
import netaddr
18
 
from oslo.config import cfg
19
 
from oslo import messaging
20
 
from oslo.utils import excutils
21
 
from oslo.utils import importutils
22
 
from oslo.utils import timeutils
 
18
from oslo_config import cfg
 
19
from oslo_log import log as logging
 
20
import oslo_messaging
 
21
from oslo_utils import excutils
 
22
from oslo_utils import importutils
 
23
from oslo_utils import timeutils
23
24
 
24
 
from neutron.agent.common import config
25
25
from neutron.agent.l3 import dvr
26
 
from neutron.agent.l3 import dvr_fip_ns
27
26
from neutron.agent.l3 import dvr_router
28
27
from neutron.agent.l3 import event_observers
29
28
from neutron.agent.l3 import ha
30
29
from neutron.agent.l3 import ha_router
31
30
from neutron.agent.l3 import legacy_router
 
31
from neutron.agent.l3 import namespace_manager
 
32
from neutron.agent.l3 import namespaces
32
33
from neutron.agent.l3 import router_processing_queue as queue
33
34
from neutron.agent.linux import external_process
34
35
from neutron.agent.linux import ip_lib
44
45
from neutron import context as n_context
45
46
from neutron.i18n import _LE, _LI, _LW
46
47
from neutron import manager
47
 
from neutron.openstack.common import log as logging
48
48
from neutron.openstack.common import loopingcall
49
49
from neutron.openstack.common import periodic_task
50
50
from neutron.services import advanced_service as adv_svc
56
56
    from neutron.services.firewall.agents.l3reference import firewall_l3_agent
57
57
 
58
58
LOG = logging.getLogger(__name__)
59
 
NS_PREFIX = 'qrouter-'
60
 
INTERNAL_DEV_PREFIX = 'qr-'
61
 
EXTERNAL_DEV_PREFIX = 'qg-'
 
59
# TODO(Carl) Following constants retained to increase SNR during refactoring
 
60
NS_PREFIX = namespaces.NS_PREFIX
 
61
INTERNAL_DEV_PREFIX = namespaces.INTERNAL_DEV_PREFIX
 
62
EXTERNAL_DEV_PREFIX = namespaces.EXTERNAL_DEV_PREFIX
62
63
 
63
64
 
64
65
class L3PluginApi(object):
77
78
 
78
79
    def __init__(self, topic, host):
79
80
        self.host = host
80
 
        target = messaging.Target(topic=topic, version='1.0')
 
81
        target = oslo_messaging.Target(topic=topic, version='1.0')
81
82
        self.client = n_rpc.get_client(target)
82
83
 
83
84
    def get_routers(self, context, router_ids=None):
89
90
    def get_external_network_id(self, context):
90
91
        """Make a remote process call to retrieve the external network id.
91
92
 
92
 
        @raise messaging.RemoteError: with TooManyExternalNetworks as
93
 
                                      exc_type if there are more than one
94
 
                                      external network
 
93
        @raise oslo_messaging.RemoteError: with TooManyExternalNetworks as
 
94
                                           exc_type if there are more than one
 
95
                                           external network
95
96
        """
96
97
        cctxt = self.client.prepare()
97
98
        return cctxt.call(context, 'get_external_network_id', host=self.host)
138
139
              - del_arp_entry
139
140
              Needed by the L3 service when dealing with DVR
140
141
    """
141
 
    target = messaging.Target(version='1.2')
 
142
    target = oslo_messaging.Target(version='1.2')
142
143
 
143
144
    def __init__(self, host, conf=None):
144
145
        if conf:
145
146
            self.conf = conf
146
147
        else:
147
148
            self.conf = cfg.CONF
148
 
        self.root_helper = config.get_root_helper(self.conf)
149
149
        self.router_info = {}
150
150
 
151
151
        self._check_config_params()
152
152
 
153
153
        self.process_monitor = external_process.ProcessMonitor(
154
154
            config=self.conf,
155
 
            root_helper=self.root_helper,
156
155
            resource_type='router')
157
156
 
158
157
        try:
178
177
            try:
179
178
                self.neutron_service_plugins = (
180
179
                    self.plugin_rpc.get_service_plugin_list(self.context))
181
 
            except messaging.RemoteError as e:
 
180
            except oslo_messaging.RemoteError as e:
182
181
                with excutils.save_and_reraise_exception() as ctx:
183
182
                    ctx.reraise = False
184
183
                    LOG.warning(_LW('l3-agent cannot check service plugins '
189
188
                                    'UnsupportedVersion you can ignore this '
190
189
                                    'warning. Detail message: %s'), e)
191
190
                self.neutron_service_plugins = None
192
 
            except messaging.MessagingTimeout as e:
 
191
            except oslo_messaging.MessagingTimeout as e:
193
192
                with excutils.save_and_reraise_exception() as ctx:
194
193
                    if retry_count > 0:
195
194
                        ctx.reraise = False
200
199
                        continue
201
200
            break
202
201
 
203
 
        self._clean_stale_namespaces = self.conf.use_namespaces
 
202
        self.namespaces_manager = namespace_manager.NamespaceManager(
 
203
            self.conf,
 
204
            self.driver,
 
205
            self.conf.use_namespaces)
204
206
 
205
207
        self._queue = queue.RouterProcessingQueue()
206
208
        self.event_observers = event_observers.L3EventObservers()
210
212
        self.use_ipv6 = ipv6_utils.is_enabled()
211
213
 
212
214
        if self.conf.enable_metadata_proxy:
213
 
            driver = metadata_driver.MetadataDriver.instance(self)
214
 
            self.event_observers.add(driver)
 
215
            self.metadata_driver = metadata_driver.MetadataDriver(self)
 
216
            self.event_observers.add(self.metadata_driver)
215
217
 
216
218
    def _check_config_params(self):
217
219
        """Check items in configuration files.
229
231
            LOG.error(msg)
230
232
            raise SystemExit(1)
231
233
 
232
 
    def _list_namespaces(self):
233
 
        """Get a set of all router namespaces on host
234
 
 
235
 
        The argument routers is the list of routers that are recorded in
236
 
        the database as being hosted on this node.
237
 
        """
238
 
        try:
239
 
            root_ip = ip_lib.IPWrapper(self.root_helper)
240
 
 
241
 
            host_namespaces = root_ip.get_namespaces(self.root_helper)
242
 
            return set(ns for ns in host_namespaces
243
 
                       if (ns.startswith(NS_PREFIX)
244
 
                           or ns.startswith(dvr.SNAT_NS_PREFIX)))
245
 
        except RuntimeError:
246
 
            LOG.exception(_LE('RuntimeError in obtaining router list '
247
 
                            'for namespace cleanup.'))
248
 
            return set()
249
 
 
250
 
    def _get_routers_namespaces(self, router_ids):
251
 
        namespaces = set(self.get_ns_name(rid) for rid in router_ids)
252
 
        namespaces.update(self.get_snat_ns_name(rid) for rid in router_ids)
253
 
        return namespaces
254
 
 
255
 
    def _cleanup_namespaces(self, router_namespaces, router_ids):
256
 
        """Destroy stale router namespaces on host when L3 agent restarts
257
 
 
258
 
        This routine is called when self._clean_stale_namespaces is True.
259
 
 
260
 
        The argument router_namespaces is the list of all routers namespaces
261
 
        The argument router_ids is the list of ids for known routers.
262
 
        """
263
 
        # Don't destroy namespaces of routers this agent handles.
264
 
        ns_to_ignore = self._get_routers_namespaces(router_ids)
265
 
 
266
 
        ns_to_destroy = router_namespaces - ns_to_ignore
267
 
        for ns in ns_to_destroy:
268
 
            try:
269
 
                self._destroy_namespace(ns)
270
 
            except RuntimeError:
271
 
                LOG.exception(_LE('Failed to destroy stale router namespace '
272
 
                                  '%s'), ns)
273
 
        self._clean_stale_namespaces = False
274
 
 
275
 
    def _destroy_namespace(self, ns):
276
 
        if ns.startswith(NS_PREFIX):
277
 
            self._destroy_router_namespace(ns)
278
 
        elif ns.startswith(dvr_fip_ns.FIP_NS_PREFIX):
279
 
            self._destroy_fip_namespace(ns)
280
 
        elif ns.startswith(dvr.SNAT_NS_PREFIX):
281
 
            self._destroy_snat_namespace(ns)
282
 
 
283
 
    def _delete_namespace(self, ns_ip, ns):
284
 
        try:
285
 
            ns_ip.netns.delete(ns)
286
 
        except RuntimeError:
287
 
            LOG.exception(_LE('Failed trying to delete namespace: %s'), ns)
288
 
 
289
 
    def _destroy_router_namespace(self, ns):
290
 
        router_id = self.get_router_id(ns)
291
 
        ra.disable_ipv6_ra(router_id, self.process_monitor)
292
 
        ns_ip = ip_lib.IPWrapper(self.root_helper, namespace=ns)
293
 
        for d in ns_ip.get_devices(exclude_loopback=True):
294
 
            if d.name.startswith(INTERNAL_DEV_PREFIX):
295
 
                # device is on default bridge
296
 
                self.driver.unplug(d.name, namespace=ns,
297
 
                                   prefix=INTERNAL_DEV_PREFIX)
298
 
            elif d.name.startswith(dvr_fip_ns.ROUTER_2_FIP_DEV_PREFIX):
299
 
                ns_ip.del_veth(d.name)
300
 
            elif d.name.startswith(EXTERNAL_DEV_PREFIX):
301
 
                self.driver.unplug(d.name,
302
 
                                   bridge=self.conf.external_network_bridge,
303
 
                                   namespace=ns,
304
 
                                   prefix=EXTERNAL_DEV_PREFIX)
305
 
 
306
 
        if self.conf.router_delete_namespaces:
307
 
            self._delete_namespace(ns_ip, ns)
308
 
 
309
 
    def _create_namespace(self, name):
310
 
        ip_wrapper_root = ip_lib.IPWrapper(self.root_helper)
311
 
        ip_wrapper = ip_wrapper_root.ensure_namespace(name)
312
 
        ip_wrapper.netns.execute(['sysctl', '-w', 'net.ipv4.ip_forward=1'])
313
 
        if self.use_ipv6:
314
 
            ip_wrapper.netns.execute(['sysctl', '-w',
315
 
                                      'net.ipv6.conf.all.forwarding=1'])
316
 
 
317
 
    def _create_router_namespace(self, ri):
318
 
        self._create_namespace(ri.ns_name)
319
 
 
320
234
    def _fetch_external_net_id(self, force=False):
321
235
        """Find UUID of single external network for this agent."""
322
236
        if self.conf.gateway_external_network_id:
335
249
            self.target_ex_net_id = self.plugin_rpc.get_external_network_id(
336
250
                self.context)
337
251
            return self.target_ex_net_id
338
 
        except messaging.RemoteError as e:
 
252
        except oslo_messaging.RemoteError as e:
339
253
            with excutils.save_and_reraise_exception() as ctx:
340
254
                if e.exc_type == 'TooManyExternalNetworks':
341
255
                    ctx.reraise = False
351
265
        if router.get('distributed') and router.get('ha'):
352
266
            raise n_exc.DvrHaRouterNotSupported(router_id=router_id)
353
267
 
354
 
        ns_name = (self.get_ns_name(router_id)
355
 
                   if self.conf.use_namespaces else None)
356
268
        args = []
357
269
        kwargs = {
358
270
            'router_id': router_id,
359
 
            'root_helper': self.root_helper,
360
271
            'router': router,
361
272
            'use_ipv6': self.use_ipv6,
362
 
            'ns_name': ns_name,
363
273
            'agent_conf': self.conf,
364
274
            'interface_driver': self.driver,
365
275
        }
366
276
 
367
277
        if router.get('distributed'):
 
278
            kwargs['agent'] = self
 
279
            kwargs['host'] = self.host
368
280
            return dvr_router.DvrRouter(*args, **kwargs)
369
281
 
370
282
        if router.get('ha'):
374
286
 
375
287
    def _router_added(self, router_id, router):
376
288
        ri = self._create_router(router_id, router)
 
289
        ri.radvd = ra.DaemonMonitor(router['id'],
 
290
                                    ri.ns_name,
 
291
                                    self.process_monitor,
 
292
                                    ri.get_internal_device_name)
377
293
        self.event_observers.notify(
378
294
            adv_svc.AdvancedService.before_router_added, ri)
379
295
 
380
296
        self.router_info[router_id] = ri
381
 
        if self.conf.use_namespaces:
382
 
            self._create_router_namespace(ri)
 
297
        ri.create()
383
298
        self.process_router_add(ri)
384
299
 
385
300
        if ri.is_ha:
403
318
        ri.router[l3_constants.FLOATINGIP_KEY] = []
404
319
        self.process_router(ri)
405
320
        del self.router_info[router_id]
406
 
        self._destroy_router_namespace(ri.ns_name)
407
 
 
 
321
        ri.delete()
408
322
        self.event_observers.notify(
409
323
            adv_svc.AdvancedService.after_router_removed, ri)
410
324
 
411
 
    def _set_subnet_info(self, port):
412
 
        ips = port['fixed_ips']
413
 
        if not ips:
414
 
            raise Exception(_("Router port %s has no IP address") % port['id'])
415
 
        if len(ips) > 1:
416
 
            LOG.error(_LE("Ignoring multiple IPs on router port %s"),
417
 
                      port['id'])
418
 
        prefixlen = netaddr.IPNetwork(port['subnet']['cidr']).prefixlen
419
 
        port['ip_cidr'] = "%s/%s" % (ips[0]['ip_address'], prefixlen)
420
 
 
421
 
    def _get_existing_devices(self, ri):
422
 
        ip_wrapper = ip_lib.IPWrapper(root_helper=self.root_helper,
423
 
                                      namespace=ri.ns_name)
424
 
        ip_devs = ip_wrapper.get_devices(exclude_loopback=True)
425
 
        return [ip_dev.name for ip_dev in ip_devs]
426
 
 
427
 
    def _process_internal_ports(self, ri):
428
 
        internal_ports = ri.router.get(l3_constants.INTERFACE_KEY, [])
429
 
        existing_port_ids = set([p['id'] for p in ri.internal_ports])
430
 
        current_port_ids = set([p['id'] for p in internal_ports
431
 
                                if p['admin_state_up']])
432
 
        new_ports = [p for p in internal_ports if
433
 
                     p['id'] in current_port_ids and
434
 
                     p['id'] not in existing_port_ids]
435
 
        old_ports = [p for p in ri.internal_ports if
436
 
                     p['id'] not in current_port_ids]
437
 
 
438
 
        new_ipv6_port = False
439
 
        old_ipv6_port = False
440
 
        for p in new_ports:
441
 
            self._set_subnet_info(p)
442
 
            self.internal_network_added(ri, p)
443
 
            ri.internal_ports.append(p)
444
 
            self._set_subnet_arp_info(ri, p)
445
 
            if (not new_ipv6_port and
446
 
                    netaddr.IPNetwork(p['subnet']['cidr']).version == 6):
447
 
                new_ipv6_port = True
448
 
 
449
 
        for p in old_ports:
450
 
            self.internal_network_removed(ri, p)
451
 
            ri.internal_ports.remove(p)
452
 
            if (not old_ipv6_port and
453
 
                    netaddr.IPNetwork(p['subnet']['cidr']).version == 6):
454
 
                old_ipv6_port = True
455
 
 
456
 
        # Enable RA
457
 
        if new_ipv6_port or old_ipv6_port:
458
 
            ra.enable_ipv6_ra(ri.router_id,
459
 
                              ri.ns_name,
460
 
                              internal_ports,
461
 
                              self.get_internal_device_name,
462
 
                              self.process_monitor)
463
 
 
464
 
        existing_devices = self._get_existing_devices(ri)
465
 
        current_internal_devs = set([n for n in existing_devices
466
 
                                     if n.startswith(INTERNAL_DEV_PREFIX)])
467
 
        current_port_devs = set([self.get_internal_device_name(id) for
468
 
                                 id in current_port_ids])
469
 
        stale_devs = current_internal_devs - current_port_devs
470
 
        for stale_dev in stale_devs:
471
 
            LOG.debug('Deleting stale internal router device: %s',
472
 
                      stale_dev)
473
 
            self.driver.unplug(stale_dev,
474
 
                               namespace=ri.ns_name,
475
 
                               prefix=INTERNAL_DEV_PREFIX)
476
 
 
477
325
    def _process_external_gateway(self, ri):
478
 
        ex_gw_port = self._get_ex_gw_port(ri)
 
326
        ex_gw_port = ri.get_ex_gw_port()
479
327
        ex_gw_port_id = (ex_gw_port and ex_gw_port['id'] or
480
328
                         ri.ex_gw_port and ri.ex_gw_port['id'])
481
329
 
493
341
                port2_filtered = _get_filtered_dict(port2, keys_to_ignore)
494
342
                return port1_filtered == port2_filtered
495
343
 
496
 
            self._set_subnet_info(ex_gw_port)
 
344
            ri._set_subnet_info(ex_gw_port)
497
345
            if not ri.ex_gw_port:
498
346
                self.external_gateway_added(ri, ex_gw_port, interface_name)
499
347
            elif not _gateway_ports_equal(ex_gw_port, ri.ex_gw_port):
501
349
        elif not ex_gw_port and ri.ex_gw_port:
502
350
            self.external_gateway_removed(ri, ri.ex_gw_port, interface_name)
503
351
 
504
 
        existing_devices = self._get_existing_devices(ri)
 
352
        existing_devices = ri._get_existing_devices()
505
353
        stale_devs = [dev for dev in existing_devices
506
354
                      if dev.startswith(EXTERNAL_DEV_PREFIX)
507
355
                      and dev != interface_name]
515
363
 
516
364
        # Process SNAT rules for external gateway
517
365
        if (not ri.router['distributed'] or
518
 
            ex_gw_port and self.get_gw_port_host(ri.router) == self.host):
 
366
            ex_gw_port and ri.get_gw_port_host() == self.host):
519
367
            ri.perform_snat_action(self._handle_router_snat_rules,
520
368
                                   interface_name)
521
369
 
522
 
    def _put_fips_in_error_state(self, ri):
523
 
        fip_statuses = {}
524
 
        for fip in ri.router.get(l3_constants.FLOATINGIP_KEY, []):
525
 
            fip_statuses[fip['id']] = l3_constants.FLOATINGIP_STATUS_ERROR
526
 
        return fip_statuses
527
 
 
528
 
    def _process_snat_dnat_for_fip(self, ri):
529
 
        try:
530
 
            self.process_router_floating_ip_nat_rules(ri)
531
 
        except Exception:
532
 
            # TODO(salv-orlando): Less broad catching
533
 
            raise n_exc.FloatingIpSetupException('L3 agent failure to setup '
534
 
                'NAT for floating IPs')
535
 
 
536
 
    def _configure_fip_addresses(self, ri, interface_name):
537
 
        try:
538
 
            return self.process_router_floating_ip_addresses(
539
 
                ri, interface_name)
540
 
        except Exception:
541
 
            # TODO(salv-orlando): Less broad catching
542
 
            raise n_exc.FloatingIpSetupException('L3 agent failure to setup '
543
 
                'floating IPs')
544
 
 
545
370
    def _update_fip_statuses(self, ri, existing_floating_ips, fip_statuses):
546
371
        # Identify floating IPs which were disabled
547
372
        ri.floating_ips = set(fip_statuses.keys())
548
373
        for fip_id in existing_floating_ips - ri.floating_ips:
549
374
            fip_statuses[fip_id] = l3_constants.FLOATINGIP_STATUS_DOWN
 
375
        LOG.debug('Sending floating ip statuses: %s', fip_statuses)
550
376
        # Update floating IP status on the neutron server
551
377
        self.plugin_rpc.update_floatingip_statuses(
552
378
            self.context, ri.router_id, fip_statuses)
562
388
        try:
563
389
            with ri.iptables_manager.defer_apply():
564
390
                self._process_external_gateway(ri)
565
 
                ex_gw_port = self._get_ex_gw_port(ri)
 
391
                ex_gw_port = ri.get_ex_gw_port()
566
392
                # TODO(Carl) Return after setting existing_floating_ips and
567
393
                # still call _update_fip_statuses?
568
394
                if not ex_gw_port:
572
398
                existing_floating_ips = ri.floating_ips
573
399
                if ri.router['distributed']:
574
400
                    self.create_dvr_fip_interfaces(ri, ex_gw_port)
575
 
                self._process_snat_dnat_for_fip(ri)
 
401
                ri.process_snat_dnat_for_fip()
576
402
 
577
403
            # Once NAT rules for floating IPs are safely in place
578
404
            # configure their addresses on the external gateway port
579
405
            interface_name = self._get_external_device_interface_name(
580
406
                ri, ex_gw_port)
581
 
            fip_statuses = self._configure_fip_addresses(ri, interface_name)
 
407
            fip_statuses = ri.configure_fip_addresses(interface_name)
582
408
 
583
 
        except (n_exc.FloatingIpSetupException, n_exc.IpTablesApplyException):
 
409
        except (n_exc.FloatingIpSetupException,
 
410
                n_exc.IpTablesApplyException) as e:
584
411
                # All floating IPs must be put in error state
585
 
                fip_statuses = self._put_fips_in_error_state(ri)
 
412
                LOG.exception(e)
 
413
                fip_statuses = ri.put_fips_in_error_state()
586
414
 
587
415
        self._update_fip_statuses(ri, existing_floating_ips, fip_statuses)
588
416
 
591
419
        # TODO(mrsmith) - we shouldn't need to check here
592
420
        if 'distributed' not in ri.router:
593
421
            ri.router['distributed'] = False
594
 
        ex_gw_port = self._get_ex_gw_port(ri)
 
422
        ex_gw_port = ri.get_ex_gw_port()
595
423
        if ri.router.get('distributed') and ex_gw_port:
596
424
            ri.fip_ns = self.get_fip_ns(ex_gw_port['network_id'])
597
425
            ri.fip_ns.scan_fip_ports(ri)
598
 
        self._process_internal_ports(ri)
 
426
        ri._process_internal_ports()
599
427
        self._process_external(ri)
600
428
        # Process static routes for router
601
 
        self.routes_updated(ri)
 
429
        ri.routes_updated()
602
430
 
603
431
        # Enable or disable keepalived for ha routers
604
432
        self._process_ha_router(ri)
643
471
                    break
644
472
        iptables_manager.apply()
645
473
 
646
 
    def process_router_floating_ip_nat_rules(self, ri):
647
 
        """Configure NAT rules for the router's floating IPs.
648
 
 
649
 
        Configures iptables rules for the floating ips of the given router
650
 
        """
651
 
        # Clear out all iptables rules for floating ips
652
 
        ri.iptables_manager.ipv4['nat'].clear_rules_by_tag('floating_ip')
653
 
 
654
 
        floating_ips = self.get_floating_ips(ri)
655
 
        # Loop once to ensure that floating ips are configured.
656
 
        for fip in floating_ips:
657
 
            # Rebuild iptables rules for the floating ip.
658
 
            fixed = fip['fixed_ip_address']
659
 
            fip_ip = fip['floating_ip_address']
660
 
            for chain, rule in self.floating_forward_rules(fip_ip, fixed):
661
 
                ri.iptables_manager.ipv4['nat'].add_rule(chain, rule,
662
 
                                                         tag='floating_ip')
663
 
 
664
 
        ri.iptables_manager.apply()
665
 
 
666
474
    def create_dvr_fip_interfaces(self, ri, ex_gw_port):
667
 
        floating_ips = self.get_floating_ips(ri)
 
475
        floating_ips = ri.get_floating_ips()
 
476
        fip_agent_port = ri.get_floating_agent_gw_interface(
 
477
            ex_gw_port['network_id'])
 
478
        LOG.debug("FloatingIP agent gateway port received from the plugin: "
 
479
                  "%s", fip_agent_port)
668
480
        if floating_ips:
669
481
            is_first = ri.fip_ns.subscribe(ri.router_id)
670
 
            if is_first:
671
 
                agent_gateway_port = (
672
 
                    self.plugin_rpc.get_agent_gateway_port(
673
 
                        self.context, ex_gw_port['network_id']))
674
 
                if 'subnet' not in agent_gateway_port:
 
482
            if is_first and fip_agent_port:
 
483
                if 'subnet' not in fip_agent_port:
675
484
                    LOG.error(_LE('Missing subnet/agent_gateway_port'))
676
485
                else:
677
 
                    self._set_subnet_info(agent_gateway_port)
678
 
                    ri.fip_ns.create_gateway_port(agent_gateway_port)
 
486
                    ri._set_subnet_info(fip_agent_port)
 
487
                    ri.fip_ns.create_gateway_port(fip_agent_port)
679
488
 
680
489
        if ri.fip_ns.agent_gateway_port and floating_ips:
681
490
            if ri.dist_fip_count == 0:
688
497
    def _get_external_device_interface_name(self, ri, ex_gw_port):
689
498
        if ri.router['distributed']:
690
499
            fip_int = ri.fip_ns.get_int_device_name(ri.router_id)
691
 
            if ip_lib.device_exists(fip_int,
692
 
                                    root_helper=self.root_helper,
693
 
                                    namespace=ri.fip_ns.get_name()):
 
500
            if ip_lib.device_exists(fip_int, namespace=ri.fip_ns.get_name()):
694
501
                return ri.fip_ns.get_rtr_ext_device_name(ri.router_id)
695
502
        else:
696
503
            return self.get_external_device_name(ex_gw_port['id'])
697
504
 
698
 
    def _add_floating_ip(self, ri, fip, interface_name, device):
699
 
        fip_ip = fip['floating_ip_address']
700
 
        ip_cidr = common_utils.ip_to_cidr(fip_ip)
701
 
 
702
 
        if ri.is_ha:
703
 
            ri._add_vip(ip_cidr, interface_name)
704
 
        else:
705
 
            net = netaddr.IPNetwork(ip_cidr)
706
 
            try:
707
 
                device.addr.add(net.version, ip_cidr, str(net.broadcast))
708
 
            except RuntimeError:
709
 
                # any exception occurred here should cause the floating IP
710
 
                # to be set in error state
711
 
                LOG.warn(_LW("Unable to configure IP address for "
712
 
                             "floating IP: %s"), fip['id'])
713
 
                return l3_constants.FLOATINGIP_STATUS_ERROR
714
 
            if ri.router['distributed']:
715
 
                # Special Handling for DVR - update FIP namespace
716
 
                # and ri.namespace to handle DVR based FIP
717
 
                self.floating_ip_added_dist(ri, fip, ip_cidr)
718
 
            else:
719
 
                # As GARP is processed in a distinct thread the call below
720
 
                # won't raise an exception to be handled.
721
 
                ip_lib.send_gratuitous_arp(ri.ns_name,
722
 
                                           interface_name,
723
 
                                           fip_ip,
724
 
                                           self.conf.send_arp_for_ha,
725
 
                                           self.root_helper)
726
 
            return l3_constants.FLOATINGIP_STATUS_ACTIVE
727
 
 
728
 
    def _remove_floating_ip(self, ri, device, ip_cidr):
729
 
        if ri.is_ha:
730
 
            ri._remove_vip(ip_cidr)
731
 
        else:
732
 
            net = netaddr.IPNetwork(ip_cidr)
733
 
            device.addr.delete(net.version, ip_cidr)
734
 
            self.driver.delete_conntrack_state(root_helper=self.root_helper,
735
 
                                               namespace=ri.ns_name,
736
 
                                               ip=ip_cidr)
737
 
            if ri.router['distributed']:
738
 
                self.floating_ip_removed_dist(ri, ip_cidr)
739
 
 
740
 
    def _get_router_cidrs(self, ri, device):
741
 
        if ri.is_ha:
742
 
            return set(ri._ha_get_existing_cidrs(device.name))
743
 
        else:
744
 
            return set([addr['cidr'] for addr in device.addr.list()])
745
 
 
746
 
    def process_router_floating_ip_addresses(self, ri, interface_name):
747
 
        """Configure IP addresses on router's external gateway interface.
748
 
 
749
 
        Ensures addresses for existing floating IPs and cleans up
750
 
        those that should not longer be configured.
751
 
        """
752
 
 
753
 
        fip_statuses = {}
754
 
        if interface_name is None:
755
 
            LOG.debug('No Interface for floating IPs router: %s',
756
 
                      ri.router['id'])
757
 
            return fip_statuses
758
 
 
759
 
        device = ip_lib.IPDevice(interface_name, self.root_helper,
760
 
                                 namespace=ri.ns_name)
761
 
        existing_cidrs = self._get_router_cidrs(ri, device)
762
 
        new_cidrs = set()
763
 
 
764
 
        floating_ips = self.get_floating_ips(ri)
765
 
        # Loop once to ensure that floating ips are configured.
766
 
        for fip in floating_ips:
767
 
            fip_ip = fip['floating_ip_address']
768
 
            ip_cidr = common_utils.ip_to_cidr(fip_ip)
769
 
            new_cidrs.add(ip_cidr)
770
 
            fip_statuses[fip['id']] = l3_constants.FLOATINGIP_STATUS_ACTIVE
771
 
            if ip_cidr not in existing_cidrs:
772
 
                fip_statuses[fip['id']] = self._add_floating_ip(
773
 
                    ri, fip, interface_name, device)
774
 
 
775
 
        fips_to_remove = (
776
 
            ip_cidr for ip_cidr in existing_cidrs - new_cidrs
777
 
            if common_utils.is_cidr_host(ip_cidr))
778
 
        for ip_cidr in fips_to_remove:
779
 
            self._remove_floating_ip(ri, device, ip_cidr)
780
 
 
781
 
        return fip_statuses
782
 
 
783
 
    def _get_ex_gw_port(self, ri):
784
 
        return ri.router.get('gw_port')
785
 
 
786
 
    def get_internal_device_name(self, port_id):
787
 
        return (INTERNAL_DEV_PREFIX + port_id)[:self.driver.DEV_NAME_LEN]
788
 
 
789
505
    def get_external_device_name(self, port_id):
790
506
        return (EXTERNAL_DEV_PREFIX + port_id)[:self.driver.DEV_NAME_LEN]
791
507
 
792
 
    def get_ns_name(self, router_id):
793
 
        return (NS_PREFIX + router_id)
794
 
 
795
 
    def get_router_id(self, ns_name):
796
 
        return ns_name[len(NS_PREFIX):]
797
 
 
798
 
    def get_floating_ips(self, ri):
799
 
        """Filter Floating IPs to be hosted on this agent."""
800
 
        floating_ips = ri.router.get(l3_constants.FLOATINGIP_KEY, [])
801
 
        if ri.router['distributed']:
802
 
            floating_ips = [i for i in floating_ips if i['host'] == self.host]
803
 
        return floating_ips
804
 
 
805
508
    def external_gateway_added(self, ri, ex_gw_port, interface_name):
806
509
        if ri.router['distributed']:
807
 
            ip_wrapr = ip_lib.IPWrapper(self.root_helper, namespace=ri.ns_name)
 
510
            ip_wrapr = ip_lib.IPWrapper(namespace=ri.ns_name)
808
511
            ip_wrapr.netns.execute(['sysctl', '-w',
809
512
                                   'net.ipv4.conf.all.send_redirects=0'])
810
 
            snat_ports = self.get_snat_interfaces(ri)
 
513
            snat_ports = ri.get_snat_interfaces()
811
514
            for p in ri.internal_ports:
812
 
                gateway = self._map_internal_interfaces(ri, p, snat_ports)
813
 
                id_name = self.get_internal_device_name(p['id'])
 
515
                gateway = ri._map_internal_interfaces(p, snat_ports)
 
516
                id_name = ri.get_internal_device_name(p['id'])
814
517
                if gateway:
815
 
                    self._snat_redirect_add(ri, gateway['fixed_ips'][0]
816
 
                                            ['ip_address'], p, id_name)
 
518
                    ri._snat_redirect_add(
 
519
                        gateway['fixed_ips'][0]['ip_address'], p, id_name)
817
520
 
818
 
            if (self.conf.agent_mode == 'dvr_snat' and
819
 
                self.get_gw_port_host(ri.router) == self.host):
 
521
            if (self.conf.agent_mode == l3_constants.L3_AGENT_MODE_DVR_SNAT and
 
522
                ri.get_gw_port_host() == self.host):
820
523
                self._create_dvr_gateway(ri, ex_gw_port, interface_name,
821
524
                                         snat_ports)
822
525
            for port in snat_ports:
823
526
                for ip in port['fixed_ips']:
824
 
                    self._update_arp_entry(ri, ip['ip_address'],
825
 
                                           port['mac_address'],
826
 
                                           ip['subnet_id'], 'add')
 
527
                    ri._update_arp_entry(ip['ip_address'],
 
528
                                         port['mac_address'],
 
529
                                         ip['subnet_id'],
 
530
                                         'add')
827
531
            return
828
532
 
829
533
        # Compute a list of addresses this router is supposed to have.
830
534
        # This avoids unnecessarily removing those addresses and
831
535
        # causing a momentarily network outage.
832
 
        floating_ips = self.get_floating_ips(ri)
 
536
        floating_ips = ri.get_floating_ips()
833
537
        preserve_ips = [common_utils.ip_to_cidr(ip['floating_ip_address'])
834
538
                        for ip in floating_ips]
835
539
 
843
547
    def external_gateway_updated(self, ri, ex_gw_port, interface_name):
844
548
        preserve_ips = []
845
549
        if ri.router['distributed']:
846
 
            if (self.conf.agent_mode == 'dvr_snat' and
847
 
                self.get_gw_port_host(ri.router) == self.host):
848
 
                ns_name = self.get_snat_ns_name(ri.router['id'])
 
550
            if (self.conf.agent_mode == l3_constants.L3_AGENT_MODE_DVR_SNAT and
 
551
                ri.get_gw_port_host() == self.host):
 
552
                ns_name = ri.snat_namespace.name
849
553
            else:
850
554
                # no centralized SNAT gateway for this node/agent
851
555
                LOG.debug("not hosting snat for router: %s", ri.router['id'])
852
556
                return
853
557
        else:
854
558
            ns_name = ri.ns_name
855
 
            floating_ips = self.get_floating_ips(ri)
 
559
            floating_ips = ri.get_floating_ips()
856
560
            preserve_ips = [common_utils.ip_to_cidr(ip['floating_ip_address'])
857
561
                            for ip in floating_ips]
858
562
 
864
568
 
865
569
    def _external_gateway_added(self, ri, ex_gw_port, interface_name,
866
570
                                ns_name, preserve_ips):
867
 
        if not ip_lib.device_exists(interface_name,
868
 
                                    root_helper=self.root_helper,
869
 
                                    namespace=ns_name):
 
571
        if not ip_lib.device_exists(interface_name, namespace=ns_name):
870
572
            self.driver.plug(ex_gw_port['network_id'],
871
573
                             ex_gw_port['id'], interface_name,
872
574
                             ex_gw_port['mac_address'],
884
586
            ip_lib.send_gratuitous_arp(ns_name,
885
587
                                       interface_name,
886
588
                                       ip_address,
887
 
                                       self.conf.send_arp_for_ha,
888
 
                                       self.root_helper)
 
589
                                       self.conf.send_arp_for_ha)
889
590
 
890
591
    def external_gateway_removed(self, ri, ex_gw_port, interface_name):
891
592
        if ri.router['distributed']:
892
 
            self.process_router_floating_ip_nat_rules(ri)
893
 
            interface_name = self._get_external_device_interface_name(
894
 
                ri, ex_gw_port)
895
 
            self.process_router_floating_ip_addresses(ri, interface_name)
 
593
            # TODO(Carl) Should this be calling process_snat_dnat_for_fip?
 
594
            ri.process_floating_ip_nat_rules()
 
595
            if ri.fip_ns:
 
596
                to_fip_interface_name = (
 
597
                    self._get_external_device_interface_name(ri, ex_gw_port))
 
598
                ri.process_floating_ip_addresses(to_fip_interface_name)
 
599
            snat_ports = ri.get_snat_interfaces()
896
600
            for p in ri.internal_ports:
897
 
                internal_interface = self.get_internal_device_name(p['id'])
898
 
                self._snat_redirect_remove(ri, p, internal_interface)
 
601
                gateway = self._map_internal_interfaces(ri, p, snat_ports)
 
602
                internal_interface = ri.get_internal_device_name(p['id'])
 
603
                ri._snat_redirect_remove(gateway['fixed_ips'][0]['ip_address'],
 
604
                                         p,
 
605
                                         internal_interface)
899
606
 
900
 
            if self.conf.agent_mode == 'dvr_snat' and (
901
 
                self.get_gw_port_host(ri.router) == self.host):
902
 
                ns_name = self.get_snat_ns_name(ri.router['id'])
 
607
            if (self.conf.agent_mode == l3_constants.L3_AGENT_MODE_DVR_SNAT
 
608
                and ri.get_gw_port_host() == self.host):
 
609
                ns_name = ri.snat_namespace.name
903
610
            else:
904
611
                # not hosting agent - no work to do
905
612
                LOG.debug('DVR: CSNAT not hosted: %s', ex_gw_port)
915
622
                           namespace=ns_name,
916
623
                           prefix=EXTERNAL_DEV_PREFIX)
917
624
        if ri.router['distributed']:
918
 
            self._destroy_snat_namespace(ns_name)
 
625
            ri.delete_snat_namespace()
919
626
 
920
627
    def external_gateway_nat_rules(self, ex_gw_ip, interface_name):
921
628
        rules = [('POSTROUTING', '! -i %(interface_name)s '
926
633
                  (interface_name, ex_gw_ip))]
927
634
        return rules
928
635
 
929
 
    def _internal_network_added(self, ns_name, network_id, port_id,
930
 
                                internal_cidr, mac_address,
931
 
                                interface_name, prefix, is_ha=False):
932
 
        if not ip_lib.device_exists(interface_name,
933
 
                                    root_helper=self.root_helper,
934
 
                                    namespace=ns_name):
935
 
            self.driver.plug(network_id, port_id, interface_name, mac_address,
936
 
                             namespace=ns_name,
937
 
                             prefix=prefix)
938
 
 
939
 
        if not is_ha:
940
 
            self.driver.init_l3(interface_name, [internal_cidr],
941
 
                                namespace=ns_name)
942
 
            ip_address = internal_cidr.split('/')[0]
943
 
            ip_lib.send_gratuitous_arp(ns_name,
944
 
                                       interface_name,
945
 
                                       ip_address,
946
 
                                       self.conf.send_arp_for_ha,
947
 
                                       self.root_helper)
948
 
 
949
 
    def internal_network_added(self, ri, port):
950
 
        network_id = port['network_id']
951
 
        port_id = port['id']
952
 
        internal_cidr = port['ip_cidr']
953
 
        mac_address = port['mac_address']
954
 
 
955
 
        interface_name = self.get_internal_device_name(port_id)
956
 
 
957
 
        self._internal_network_added(ri.ns_name, network_id, port_id,
958
 
                                     internal_cidr, mac_address,
959
 
                                     interface_name, INTERNAL_DEV_PREFIX,
960
 
                                     ri.is_ha)
961
 
 
962
 
        if ri.is_ha:
963
 
            ri._ha_disable_addressing_on_interface(interface_name)
964
 
            ri._add_vip(internal_cidr, interface_name)
965
 
 
966
 
        ex_gw_port = self._get_ex_gw_port(ri)
967
 
        if ri.router['distributed'] and ex_gw_port:
968
 
            snat_ports = self.get_snat_interfaces(ri)
969
 
            sn_port = self._map_internal_interfaces(ri, port, snat_ports)
970
 
            if sn_port:
971
 
                self._snat_redirect_add(ri, sn_port['fixed_ips'][0]
972
 
                                        ['ip_address'], port, interface_name)
973
 
                if (self.conf.agent_mode == 'dvr_snat' and
974
 
                    self.get_gw_port_host(ri.router) == self.host):
975
 
                    ns_name = self.get_snat_ns_name(ri.router['id'])
976
 
                    self._set_subnet_info(sn_port)
977
 
                    interface_name = (
978
 
                          self.get_snat_int_device_name(sn_port['id']))
979
 
                    self._internal_network_added(ns_name,
980
 
                                                 sn_port['network_id'],
981
 
                                                 sn_port['id'],
982
 
                                                 sn_port['ip_cidr'],
983
 
                                                 sn_port['mac_address'],
984
 
                                                 interface_name,
985
 
                                                 dvr.SNAT_INT_DEV_PREFIX)
986
 
 
987
 
    def internal_network_removed(self, ri, port):
988
 
        port_id = port['id']
989
 
        interface_name = self.get_internal_device_name(port_id)
990
 
        if ri.router['distributed'] and ri.ex_gw_port:
991
 
            # DVR handling code for SNAT
992
 
            self._snat_redirect_remove(ri, port, interface_name)
993
 
            if self.conf.agent_mode == 'dvr_snat' and (
994
 
                ri.ex_gw_port['binding:host_id'] == self.host):
995
 
                snat_port = self._map_internal_interfaces(ri, port,
996
 
                                                          ri.snat_ports)
997
 
                if snat_port:
998
 
                    snat_interface = (
999
 
                        self.get_snat_int_device_name(snat_port['id'])
1000
 
                    )
1001
 
                    ns_name = self.get_snat_ns_name(ri.router['id'])
1002
 
                    prefix = dvr.SNAT_INT_DEV_PREFIX
1003
 
                    if ip_lib.device_exists(snat_interface,
1004
 
                                            root_helper=self.root_helper,
1005
 
                                            namespace=ns_name):
1006
 
                        self.driver.unplug(snat_interface, namespace=ns_name,
1007
 
                                           prefix=prefix)
1008
 
 
1009
 
        if ip_lib.device_exists(interface_name,
1010
 
                                root_helper=self.root_helper,
1011
 
                                namespace=ri.ns_name):
1012
 
            if ri.is_ha:
1013
 
                ri._clear_vips(interface_name)
1014
 
            self.driver.unplug(interface_name, namespace=ri.ns_name,
1015
 
                               prefix=INTERNAL_DEV_PREFIX)
1016
 
 
1017
 
    def floating_forward_rules(self, floating_ip, fixed_ip):
1018
 
        return [('PREROUTING', '-d %s -j DNAT --to %s' %
1019
 
                 (floating_ip, fixed_ip)),
1020
 
                ('OUTPUT', '-d %s -j DNAT --to %s' %
1021
 
                 (floating_ip, fixed_ip)),
1022
 
                ('float-snat', '-s %s -j SNAT --to %s' %
1023
 
                 (fixed_ip, floating_ip))]
1024
 
 
1025
636
    def router_deleted(self, context, router_id):
1026
637
        """Deal with router deletion RPC message."""
1027
638
        LOG.debug('Got router deleted notification for %s', router_id)
1123
734
                    router = routers[0]
1124
735
 
1125
736
            if not router:
1126
 
                self._router_removed(update.id)
 
737
                try:
 
738
                    self._router_removed(update.id)
 
739
                except Exception:
 
740
                    # TODO(Carl) Stop this fullsync non-sense.  Just retry this
 
741
                    # one router by sticking the update at the end of the queue
 
742
                    # at a lower priority.
 
743
                    self.fullsync = True
1127
744
                continue
1128
745
 
1129
746
            try:
1135
752
                    LOG.error(_LE("Removing incompatible router '%s'"),
1136
753
                              router['id'])
1137
754
                    self._router_removed(router['id'])
 
755
            except Exception:
 
756
                msg = _LE("Failed to process compatible router '%s'")
 
757
                LOG.exception(msg, update.id)
 
758
                self.fullsync = True
 
759
                continue
 
760
 
1138
761
            LOG.debug("Finished a router update for %s", update.id)
1139
762
            rp.fetched_and_processed(update.timestamp)
1140
763
 
1146
769
 
1147
770
    @periodic_task.periodic_task
1148
771
    def periodic_sync_routers_task(self, context):
1149
 
        if self.services_sync:
1150
 
            super(L3NATAgent, self).process_services_sync(context)
 
772
        self.process_services_sync(context)
1151
773
        LOG.debug("Starting periodic_sync_routers_task - fullsync:%s",
1152
774
                  self.fullsync)
1153
775
        if not self.fullsync:
1157
779
        # uncaught -- prevents setting it to False below then the next call
1158
780
        # to periodic_sync_routers_task will re-enter this code and try again.
1159
781
 
1160
 
        # Capture a picture of namespaces *before* fetching the full list from
1161
 
        # the database.  This is important to correctly identify stale ones.
1162
 
        namespaces = set()
1163
 
        if self._clean_stale_namespaces:
1164
 
            namespaces = self._list_namespaces()
 
782
        # Context manager self.namespaces_manager captures a picture of
 
783
        # namespaces *before* fetch_and_sync_all_routers fetches the full list
 
784
        # of routers from the database.  This is important to correctly
 
785
        # identify stale ones.
 
786
 
 
787
        try:
 
788
            with self.namespaces_manager as ns_manager:
 
789
                self.fetch_and_sync_all_routers(context, ns_manager)
 
790
        except n_exc.AbortSyncRouters:
 
791
            self.fullsync = True
 
792
 
 
793
    def fetch_and_sync_all_routers(self, context, ns_manager):
1165
794
        prev_router_ids = set(self.router_info)
1166
795
        timestamp = timeutils.utcnow()
1167
796
 
1172
801
                routers = self.plugin_rpc.get_routers(context,
1173
802
                                                      [self.conf.router_id])
1174
803
 
1175
 
        except messaging.MessagingException:
 
804
        except oslo_messaging.MessagingException:
1176
805
            LOG.exception(_LE("Failed synchronizing routers due to RPC error"))
 
806
            raise n_exc.AbortSyncRouters()
1177
807
        else:
1178
808
            LOG.debug('Processing :%r', routers)
1179
809
            for r in routers:
 
810
                ns_manager.keep_router(r['id'])
1180
811
                update = queue.RouterUpdate(r['id'],
1181
812
                                            queue.PRIORITY_SYNC_ROUTERS_TASK,
1182
813
                                            router=r,
1185
816
            self.fullsync = False
1186
817
            LOG.debug("periodic_sync_routers_task successfully completed")
1187
818
 
1188
 
            # Resync is not necessary for the cleanup of stale namespaces
1189
819
            curr_router_ids = set([r['id'] for r in routers])
1190
820
 
1191
 
            # Two kinds of stale routers:  Routers for which info is cached in
1192
 
            # self.router_info and the others.  First, handle the former.
 
821
            # Delete routers that have disappeared since the last sync
1193
822
            for router_id in prev_router_ids - curr_router_ids:
 
823
                ns_manager.keep_router(router_id)
1194
824
                update = queue.RouterUpdate(router_id,
1195
825
                                            queue.PRIORITY_SYNC_ROUTERS_TASK,
1196
826
                                            timestamp=timestamp,
1197
827
                                            action=queue.DELETE_ROUTER)
1198
828
                self._queue.add(update)
1199
829
 
1200
 
            # Next, one effort to clean out namespaces for which we don't have
1201
 
            # a record.  (i.e. _clean_stale_namespaces=False after one pass)
1202
 
            if self._clean_stale_namespaces:
1203
 
                ids_to_keep = curr_router_ids | prev_router_ids
1204
 
                self._cleanup_namespaces(namespaces, ids_to_keep)
1205
 
 
1206
830
    def after_start(self):
1207
831
        eventlet.spawn_n(self._process_routers_loop)
1208
832
        LOG.info(_LI("L3 agent started"))
1209
833
        # When L3 agent is ready, we immediately do a full sync
1210
834
        self.periodic_sync_routers_task(self.context)
1211
835
 
1212
 
    def _update_routing_table(self, ri, operation, route):
1213
 
        cmd = ['ip', 'route', operation, 'to', route['destination'],
1214
 
               'via', route['nexthop']]
1215
 
        ip_wrapper = ip_lib.IPWrapper(self.root_helper,
1216
 
                                      namespace=ri.ns_name)
1217
 
        ip_wrapper.netns.execute(cmd, check_exit_code=False)
1218
 
 
1219
 
    def routes_updated(self, ri):
1220
 
        new_routes = ri.router['routes']
1221
 
        if ri.is_ha:
1222
 
            ri._process_virtual_routes(new_routes)
1223
 
            return
1224
 
 
1225
 
        old_routes = ri.routes
1226
 
        adds, removes = common_utils.diff_list_of_dict(old_routes,
1227
 
                                                       new_routes)
1228
 
        for route in adds:
1229
 
            LOG.debug("Added route entry is '%s'", route)
1230
 
            # remove replaced route from deleted route
1231
 
            for del_route in removes:
1232
 
                if route['destination'] == del_route['destination']:
1233
 
                    removes.remove(del_route)
1234
 
            #replace success even if there is no existing route
1235
 
            self._update_routing_table(ri, 'replace', route)
1236
 
        for route in removes:
1237
 
            LOG.debug("Removed route entry is '%s'", route)
1238
 
            self._update_routing_table(ri, 'delete', route)
1239
 
        ri.routes = new_routes
1240
 
 
1241
836
 
1242
837
class L3NATAgentWithStateReport(L3NATAgent):
1243
838
 
1275
870
        router_infos = self.router_info.values()
1276
871
        num_routers = len(router_infos)
1277
872
        for ri in router_infos:
1278
 
            ex_gw_port = self._get_ex_gw_port(ri)
 
873
            ex_gw_port = ri.get_ex_gw_port()
1279
874
            if ex_gw_port:
1280
875
                num_ex_gw_ports += 1
1281
876
            num_interfaces += len(ri.router.get(l3_constants.INTERFACE_KEY,