230
232
raise SystemExit(1)
232
def _list_namespaces(self):
233
"""Get a set of all router namespaces on host
235
The argument routers is the list of routers that are recorded in
236
the database as being hosted on this node.
239
root_ip = ip_lib.IPWrapper(self.root_helper)
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)))
246
LOG.exception(_LE('RuntimeError in obtaining router list '
247
'for namespace cleanup.'))
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)
255
def _cleanup_namespaces(self, router_namespaces, router_ids):
256
"""Destroy stale router namespaces on host when L3 agent restarts
258
This routine is called when self._clean_stale_namespaces is True.
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.
263
# Don't destroy namespaces of routers this agent handles.
264
ns_to_ignore = self._get_routers_namespaces(router_ids)
266
ns_to_destroy = router_namespaces - ns_to_ignore
267
for ns in ns_to_destroy:
269
self._destroy_namespace(ns)
271
LOG.exception(_LE('Failed to destroy stale router namespace '
273
self._clean_stale_namespaces = False
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)
283
def _delete_namespace(self, ns_ip, ns):
285
ns_ip.netns.delete(ns)
287
LOG.exception(_LE('Failed trying to delete namespace: %s'), ns)
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,
304
prefix=EXTERNAL_DEV_PREFIX)
306
if self.conf.router_delete_namespaces:
307
self._delete_namespace(ns_ip, ns)
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'])
314
ip_wrapper.netns.execute(['sysctl', '-w',
315
'net.ipv6.conf.all.forwarding=1'])
317
def _create_router_namespace(self, ri):
318
self._create_namespace(ri.ns_name)
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:
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)
408
322
self.event_observers.notify(
409
323
adv_svc.AdvancedService.after_router_removed, ri)
411
def _set_subnet_info(self, port):
412
ips = port['fixed_ips']
414
raise Exception(_("Router port %s has no IP address") % port['id'])
416
LOG.error(_LE("Ignoring multiple IPs on router port %s"),
418
prefixlen = netaddr.IPNetwork(port['subnet']['cidr']).prefixlen
419
port['ip_cidr'] = "%s/%s" % (ips[0]['ip_address'], prefixlen)
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]
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]
438
new_ipv6_port = False
439
old_ipv6_port = False
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):
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):
457
if new_ipv6_port or old_ipv6_port:
458
ra.enable_ipv6_ra(ri.router_id,
461
self.get_internal_device_name,
462
self.process_monitor)
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',
473
self.driver.unplug(stale_dev,
474
namespace=ri.ns_name,
475
prefix=INTERNAL_DEV_PREFIX)
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'])
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,
522
def _put_fips_in_error_state(self, ri):
524
for fip in ri.router.get(l3_constants.FLOATINGIP_KEY, []):
525
fip_statuses[fip['id']] = l3_constants.FLOATINGIP_STATUS_ERROR
528
def _process_snat_dnat_for_fip(self, ri):
530
self.process_router_floating_ip_nat_rules(ri)
532
# TODO(salv-orlando): Less broad catching
533
raise n_exc.FloatingIpSetupException('L3 agent failure to setup '
534
'NAT for floating IPs')
536
def _configure_fip_addresses(self, ri, interface_name):
538
return self.process_router_floating_ip_addresses(
541
# TODO(salv-orlando): Less broad catching
542
raise n_exc.FloatingIpSetupException('L3 agent failure to setup '
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)
644
472
iptables_manager.apply()
646
def process_router_floating_ip_nat_rules(self, ri):
647
"""Configure NAT rules for the router's floating IPs.
649
Configures iptables rules for the floating ips of the given router
651
# Clear out all iptables rules for floating ips
652
ri.iptables_manager.ipv4['nat'].clear_rules_by_tag('floating_ip')
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,
664
ri.iptables_manager.apply()
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)
669
481
is_first = ri.fip_ns.subscribe(ri.router_id)
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'))
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)
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)
696
503
return self.get_external_device_name(ex_gw_port['id'])
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)
703
ri._add_vip(ip_cidr, interface_name)
705
net = netaddr.IPNetwork(ip_cidr)
707
device.addr.add(net.version, ip_cidr, str(net.broadcast))
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)
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,
724
self.conf.send_arp_for_ha,
726
return l3_constants.FLOATINGIP_STATUS_ACTIVE
728
def _remove_floating_ip(self, ri, device, ip_cidr):
730
ri._remove_vip(ip_cidr)
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,
737
if ri.router['distributed']:
738
self.floating_ip_removed_dist(ri, ip_cidr)
740
def _get_router_cidrs(self, ri, device):
742
return set(ri._ha_get_existing_cidrs(device.name))
744
return set([addr['cidr'] for addr in device.addr.list()])
746
def process_router_floating_ip_addresses(self, ri, interface_name):
747
"""Configure IP addresses on router's external gateway interface.
749
Ensures addresses for existing floating IPs and cleans up
750
those that should not longer be configured.
754
if interface_name is None:
755
LOG.debug('No Interface for floating IPs router: %s',
759
device = ip_lib.IPDevice(interface_name, self.root_helper,
760
namespace=ri.ns_name)
761
existing_cidrs = self._get_router_cidrs(ri, device)
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)
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)
783
def _get_ex_gw_port(self, ri):
784
return ri.router.get('gw_port')
786
def get_internal_device_name(self, port_id):
787
return (INTERNAL_DEV_PREFIX + port_id)[:self.driver.DEV_NAME_LEN]
789
505
def get_external_device_name(self, port_id):
790
506
return (EXTERNAL_DEV_PREFIX + port_id)[:self.driver.DEV_NAME_LEN]
792
def get_ns_name(self, router_id):
793
return (NS_PREFIX + router_id)
795
def get_router_id(self, ns_name):
796
return ns_name[len(NS_PREFIX):]
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]
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'])
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)
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,
822
525
for port in snat_ports:
823
526
for ip in port['fixed_ips']:
824
self._update_arp_entry(ri, ip['ip_address'],
826
ip['subnet_id'], 'add')
527
ri._update_arp_entry(ip['ip_address'],
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]
884
586
ip_lib.send_gratuitous_arp(ns_name,
887
self.conf.send_arp_for_ha,
589
self.conf.send_arp_for_ha)
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(
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()
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'],
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
904
611
# not hosting agent - no work to do
905
612
LOG.debug('DVR: CSNAT not hosted: %s', ex_gw_port)
926
633
(interface_name, ex_gw_ip))]
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,
935
self.driver.plug(network_id, port_id, interface_name, mac_address,
940
self.driver.init_l3(interface_name, [internal_cidr],
942
ip_address = internal_cidr.split('/')[0]
943
ip_lib.send_gratuitous_arp(ns_name,
946
self.conf.send_arp_for_ha,
949
def internal_network_added(self, ri, port):
950
network_id = port['network_id']
952
internal_cidr = port['ip_cidr']
953
mac_address = port['mac_address']
955
interface_name = self.get_internal_device_name(port_id)
957
self._internal_network_added(ri.ns_name, network_id, port_id,
958
internal_cidr, mac_address,
959
interface_name, INTERNAL_DEV_PREFIX,
963
ri._ha_disable_addressing_on_interface(interface_name)
964
ri._add_vip(internal_cidr, interface_name)
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)
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)
978
self.get_snat_int_device_name(sn_port['id']))
979
self._internal_network_added(ns_name,
980
sn_port['network_id'],
983
sn_port['mac_address'],
985
dvr.SNAT_INT_DEV_PREFIX)
987
def internal_network_removed(self, ri, port):
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,
999
self.get_snat_int_device_name(snat_port['id'])
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,
1006
self.driver.unplug(snat_interface, namespace=ns_name,
1009
if ip_lib.device_exists(interface_name,
1010
root_helper=self.root_helper,
1011
namespace=ri.ns_name):
1013
ri._clear_vips(interface_name)
1014
self.driver.unplug(interface_name, namespace=ri.ns_name,
1015
prefix=INTERNAL_DEV_PREFIX)
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))]
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)
1185
816
self.fullsync = False
1186
817
LOG.debug("periodic_sync_routers_task successfully completed")
1188
# Resync is not necessary for the cleanup of stale namespaces
1189
819
curr_router_ids = set([r['id'] for r in routers])
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)
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)
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)
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)
1219
def routes_updated(self, ri):
1220
new_routes = ri.router['routes']
1222
ri._process_virtual_routes(new_routes)
1225
old_routes = ri.routes
1226
adds, removes = common_utils.diff_list_of_dict(old_routes,
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
1242
837
class L3NATAgentWithStateReport(L3NATAgent):