components/openstack/neutron/files/agent/l3/solaris_agent.py
changeset 6848 8e252a37ed0d
parent 6561 6c1204ee2522
equal deleted inserted replaced
6847:57069587975f 6848:8e252a37ed0d
    16 #    License for the specific language governing permissions and limitations
    16 #    License for the specific language governing permissions and limitations
    17 #    under the License.
    17 #    under the License.
    18 #
    18 #
    19 
    19 
    20 """
    20 """
    21 Based off generic l3_agent (neutron/agent/l3_agent) code
    21 Based off of generic l3_agent (neutron/agent/l3/agent.py) code
    22 """
    22 """
    23 
    23 
    24 import errno
    24 import errno
    25 import netaddr
    25 import netaddr
    26 
    26 
    27 from oslo.config import cfg
    27 from oslo_config import cfg
    28 from oslo_log import log as logging
    28 from oslo_log import log as logging
    29 
    29 
       
    30 from neutron._i18n import _, _LE, _LW
    30 from neutron.agent.common import ovs_lib
    31 from neutron.agent.common import ovs_lib
    31 from neutron.agent.l3 import agent as l3_agent
    32 from neutron.agent.l3 import agent as l3_agent
    32 from neutron.agent.l3 import router_info as router
    33 from neutron.agent.l3 import router_info as router
    33 from neutron.agent.linux import utils
    34 from neutron.agent.linux import utils
    34 from neutron.agent.solaris import interface
    35 from neutron.agent.solaris import interface
    38 from neutron.callbacks import events
    39 from neutron.callbacks import events
    39 from neutron.callbacks import registry
    40 from neutron.callbacks import registry
    40 from neutron.callbacks import resources
    41 from neutron.callbacks import resources
    41 from neutron.common import constants as l3_constants
    42 from neutron.common import constants as l3_constants
    42 from neutron.common import exceptions as n_exc
    43 from neutron.common import exceptions as n_exc
       
    44 from neutron.common import ipv6_utils
    43 from neutron.common import utils as common_utils
    45 from neutron.common import utils as common_utils
    44 
    46 
    45 from neutron_vpnaas.services.vpn import vpn_service
    47 from neutron_vpnaas.services.vpn import vpn_service
    46 import neutron_vpnaas.services.vpn.agent as neutron_vpnaas
    48 import neutron_vpnaas.services.vpn.agent as neutron_vpnaas
    47 
    49 
    58         super(SolarisRouterInfo, self).__init__(router_id, router, agent_conf,
    60         super(SolarisRouterInfo, self).__init__(router_id, router, agent_conf,
    59                                                 interface_driver, use_ipv6)
    61                                                 interface_driver, use_ipv6)
    60         self.pf = packetfilter.PacketFilter("_auto/neutron:l3:agent")
    62         self.pf = packetfilter.PacketFilter("_auto/neutron:l3:agent")
    61         self.iptables_manager = None
    63         self.iptables_manager = None
    62         self.remove_route = False
    64         self.remove_route = False
       
    65         self.router_namespace = None
       
    66         self.ns_name = None
    63         self.ipnet_gwportname = dict()
    67         self.ipnet_gwportname = dict()
    64         self.tenant_subnets = dict()
    68         self.tenant_subnets = dict()
    65         self.tenant_subnets['all_tenants'] = set()
    69         self.tenant_subnets['all_tenants'] = set()
    66 
    70 
    67     def initialize(self, process_monitor):
    71     def initialize(self, process_monitor):
    91         # please see the comment above
    95         # please see the comment above
    92         dname = (EXTERNAL_DEV_PREFIX + port_id)[:13]
    96         dname = (EXTERNAL_DEV_PREFIX + port_id)[:13]
    93         dname += '_0'
    97         dname += '_0'
    94         return dname.replace('-', '_')
    98         return dname.replace('-', '_')
    95 
    99 
    96     def routes_updated(self):
   100     def update_routing_table(self, operation, route):
    97         pass
   101         if operation == 'replace':
    98 
   102             operation = 'change'
    99     def _get_existing_devices(self):
   103             cmd = ['/usr/sbin/route', 'get', route['destination']]
   100         return net_lib.Datalink.show_link()
   104             try:
   101 
   105                 utils.execute(cmd, log_fail_as_error=False)
   102     def internal_network_added(self, port):
   106             except:
   103         internal_dlname = self.get_internal_device_name(port['id'])
   107                 operation = 'add'
   104         # driver just returns if datalink and IP interface already exists
   108             cmd = ['/usr/sbin/route', operation, route['destination'],
   105         self.driver.plug(port['tenant_id'], port['network_id'], port['id'],
   109                    route['nexthop']]
   106                          internal_dlname, port['mac_address'],
   110             utils.execute(cmd)
   107                          vif_type=port.get('binding:vif_type'))
       
   108         fixed_ips = port['fixed_ips']
       
   109         ip_cidrs = common_utils.fixed_ip_cidrs(fixed_ips)
       
   110         self.driver.init_l3(internal_dlname, ip_cidrs)
       
   111         for fixed_ip in fixed_ips:
       
   112             net_lib.send_ip_addr_adv_notif(internal_dlname,
       
   113                                            fixed_ip['ip_address'],
       
   114                                            self.agent_conf)
       
   115 
       
   116         port_subnet = port['subnets'][0]['cidr']
       
   117         ipversion = netaddr.IPNetwork(port_subnet).version
       
   118         rules = []
       
   119         # if metadata is enabled, then we need to redirect all the packets
       
   120         # arriving at 169.254.169.254:80 to neutron-metadata-proxy server
       
   121         # listening at self.agent_conf.metadata_port
       
   122         if self.agent_conf.enable_metadata_proxy and ipversion == 4:
       
   123             rules.append('pass in quick proto tcp to 169.254.169.254/32 '
       
   124                          'port 80 rdr-to 127.0.0.1 port %s label metadata_%s '
       
   125                          'reply-to %s' % (self.agent_conf.metadata_port,
       
   126                           internal_dlname, internal_dlname))
       
   127 
       
   128         # Since we support shared router model, we need to block the new
       
   129         # internal port from reaching other tenant's ports. However, if
       
   130         # allow_forwarding_between_networks is set, then we need to
       
   131         # allow forwarding of packets between same tenant's ports.
       
   132         block_tblname = 'block_%s' % internal_dlname
       
   133         rules.append('block in quick to <%s> label %s' %
       
   134                      (block_tblname, block_tblname))
       
   135         if self.agent_conf.allow_forwarding_between_networks:
       
   136             allow_tblname = 'allow_%s' % internal_dlname
       
   137             rules.append('pass in quick to <%s> reply-to %s label %s' %
       
   138                          (allow_tblname, internal_dlname, allow_tblname))
       
   139 
       
   140         # finally add all the rules in one shot
       
   141         self.pf.add_rules(rules, [internal_dlname, 'normal'])
       
   142 
       
   143         ex_gw_port = self.ex_gw_port
       
   144         if not ex_gw_port:
       
   145             return
       
   146 
       
   147         ex_gw_ip = ex_gw_port['subnets'][0]['gateway_ip']
       
   148         if not ex_gw_ip:
       
   149             return
       
   150 
       
   151         if netaddr.IPAddress(ex_gw_ip).version != 4 or ipversion != 4:
       
   152             return
       
   153 
       
   154         # if the external gateway is already setup for the shared router,
       
   155         # then we need to add Policy Based Routing (PBR) for both inbound
       
   156         # and outbound for this internal network
       
   157         external_dlname = self.get_external_device_name(ex_gw_port['id'])
       
   158         label = 'pbr_%s' % internal_dlname
       
   159         pbr_rules = ['pass in quick to !%s route-to {(%s %s)} label %s_in' %
       
   160                      (port_subnet, external_dlname, ex_gw_ip, label)]
       
   161         pbr_rules.append('pass out quick received-on %s reply-to %s@%s '
       
   162                          'label %s_out' % (external_dlname, ex_gw_ip,
       
   163                                            external_dlname, label))
       
   164 
       
   165         self.pf.add_rules(pbr_rules, [internal_dlname, 'pbr'])
       
   166         if self._snat_enabled:
       
   167             ex_gw_port_ip = ex_gw_port['fixed_ips'][0]['ip_address']
       
   168             label = 'snat_%s' % internal_dlname
       
   169             snat_rule = ('pass out quick from %s to any nat-to %s label %s '
       
   170                          'reply-to %s' % (port_subnet, ex_gw_port_ip, label,
       
   171                                           internal_dlname))
       
   172             self.pf.add_rules([snat_rule], [external_dlname, internal_dlname])
       
   173 
       
   174     def internal_network_removed(self, port):
       
   175         internal_dlname = self.get_internal_device_name(port['id'])
       
   176         # remove the anchor and tables associated with this internal port
       
   177         self.pf.remove_anchor_recursively([internal_dlname])
       
   178         if self.ex_gw_port and self._snat_enabled:
       
   179             external_dlname = self.\
       
   180                 get_external_device_name(self.ex_gw_port['id'])
       
   181             self.pf.remove_anchor_recursively([external_dlname,
       
   182                                                internal_dlname])
       
   183         if net_lib.Datalink.datalink_exists(internal_dlname):
       
   184             self.driver.fini_l3(internal_dlname)
       
   185             self.driver.unplug(internal_dlname)
       
   186 
       
   187     def _apply_common_rules(self, all_subnets, internal_ports):
       
   188         v4_subnets = [subnet for subnet in all_subnets
       
   189                       if netaddr.IPNetwork(subnet).version == 4]
       
   190         if not v4_subnets:
       
   191             return
       
   192 
       
   193         # add rule for metadata and broadcast
       
   194         allsubnets_tblname = "all_v4_subnets"
       
   195         common_aname = "common"
       
   196         self.pf.replace_table_entry(allsubnets_tblname, v4_subnets,
       
   197                                     [common_aname])
       
   198         rules = []
       
   199         # don't forward broadcast packets out of the internal subnet
       
   200         rules.append('pass in quick from <%s> to 255.255.255.255 label '
       
   201                      '%s_bcast' % (allsubnets_tblname, common_aname))
       
   202         self.pf.add_rules(rules, [common_aname])
       
   203 
       
   204     def _pre_setup_pf_rules(self, new_ports, old_ports, internal_ports):
       
   205         """We are going to do some amount of book keeping (for later use) and
       
   206         also pre-setup PF skeleton rules ahead of time to improve PF setup
       
   207         time.
       
   208         """
       
   209 
       
   210         # Process PF anchor rules for internal ports in bulk as this
       
   211         # significantly improves the PF setup time. Capture the anchor
       
   212         # rules that will be placed under _auto/neutron:l3:agent.
       
   213         new_anchor_rules = set()
       
   214         for p in new_ports:
       
   215             port_id = p['id']
       
   216             tenant_id = p['tenant_id']
       
   217             subnet = p['subnets'][0]['cidr']
       
   218             internal_dlname = self.get_internal_device_name(port_id)
       
   219             anchor_rule = 'anchor "%s/*" on %s all' % (internal_dlname,
       
   220                                                        internal_dlname)
       
   221             new_anchor_rules.add(anchor_rule)
       
   222             ipnet = netaddr.IPNetwork(subnet)
       
   223             if ipnet.version == 4:
       
   224                 self.ipnet_gwportname[ipnet] = internal_dlname
       
   225             # Capture all the subnets across all tenants and subnets
       
   226             # per-tenant. We will setup PF tables for each internal network
       
   227             # ahead of time
       
   228             self.tenant_subnets['all_tenants'].add(subnet)
       
   229             if tenant_id not in self.tenant_subnets:
       
   230                 self.tenant_subnets[tenant_id] = set()
       
   231             self.tenant_subnets[tenant_id].add(subnet)
       
   232 
       
   233         old_anchor_rules = set()
       
   234         for p in old_ports:
       
   235             port_id = p['id']
       
   236             tenant_id = p['tenant_id']
       
   237             subnet = p['subnets'][0]['cidr']
       
   238             internal_dlname = self.get_internal_device_name(port_id)
       
   239             anchor_rule = 'anchor "%s/*" on %s all' % (internal_dlname,
       
   240                                                        internal_dlname)
       
   241             old_anchor_rules.add(anchor_rule)
       
   242             ipnet = netaddr.IPNetwork(subnet)
       
   243             if ipnet.version == 4:
       
   244                 self.ipnet_gwportname.pop(ipnet, None)
       
   245             self.tenant_subnets['all_tenants'].discard(subnet)
       
   246             if tenant_id in self.tenant_subnets:
       
   247                 self.tenant_subnets[tenant_id].discard(subnet)
       
   248 
       
   249         existing_anchor_rules = set(self.pf.list_anchor_rules())
       
   250         final_anchor_rules = ((existing_anchor_rules | new_anchor_rules) -
       
   251                               old_anchor_rules)
       
   252         # add an anchor rule to capture rules common amongst all the
       
   253         # internal ports under 'common' anchor
       
   254         if internal_ports:
       
   255             final_anchor_rules.add('anchor "common" all')
       
   256             # add rule for metadata and broadcast for all tenant's networks
       
   257             self._apply_common_rules(self.tenant_subnets['all_tenants'],
       
   258                                      internal_ports)
       
   259         else:
   111         else:
   260             final_anchor_rules.discard('anchor "common" all')
   112             assert operation == 'delete'
   261             # Now that there are no internal ports, remove the common anchor
   113             cmd = ['/usr/sbin/route', 'delete', route['destination'],
   262             # that captures rules common amongst all the internal ports
   114                    route['nexthop']]
   263             self.pf.remove_anchor_recursively(['common'])
   115             utils.execute(cmd)
   264         self.pf.add_rules(list(sorted(final_anchor_rules)))
       
   265 
       
   266         # Since we support shared router model, we need to block the new
       
   267         # internal port from reaching other tenant's ports. However, if
       
   268         # allow_forwarding_between_networks is set, then we need to
       
   269         # allow forwarding of packets between same tenant's ports
       
   270         block_subnets = set()
       
   271         allow_subnets = set()
       
   272         for p in internal_ports:
       
   273             subnet = p['subnets'][0]['cidr']
       
   274             tenant_id = p['tenant_id']
       
   275             if self.agent_conf.allow_forwarding_between_networks:
       
   276                 allow_subnets = self.tenant_subnets[tenant_id] - set([subnet])
       
   277                 block_subnets = (self.tenant_subnets['all_tenants'] -
       
   278                                  self.tenant_subnets[tenant_id])
       
   279             else:
       
   280                 block_subnets = (self.tenant_subnets['all_tenants'] -
       
   281                                  set([subnet]))
       
   282             # add table entry in the global scope
       
   283             internal_dlname = self.get_internal_device_name(p['id'])
       
   284             block_tblname = "block_%s" % internal_dlname
       
   285             self.pf.replace_table_entry(block_tblname, list(block_subnets),
       
   286                                         [internal_dlname, 'normal'])
       
   287             if allow_subnets:
       
   288                 allow_tblname = "allow_%s" % internal_dlname
       
   289                 self.pf.replace_table_entry(allow_tblname, list(allow_subnets),
       
   290                                             [internal_dlname, 'normal'])
       
   291 
       
   292     def _process_internal_ports(self):
       
   293         existing_port_ids = set([p['id'] for p in self.internal_ports])
       
   294 
       
   295         internal_ports = self.router.get(l3_constants.INTERFACE_KEY, [])
       
   296         current_port_ids = set([p['id'] for p in internal_ports
       
   297                                 if p['admin_state_up']])
       
   298 
       
   299         new_port_ids = current_port_ids - existing_port_ids
       
   300         new_ports = [p for p in internal_ports if p['id'] in new_port_ids]
       
   301         old_ports = [p for p in self.internal_ports if
       
   302                      p['id'] not in current_port_ids]
       
   303 #         updated_ports = self._get_updated_ports(self.internal_ports,
       
   304 #                                                 internal_ports)
       
   305 
       
   306         if old_ports or new_ports:
       
   307             self._pre_setup_pf_rules(new_ports, old_ports, internal_ports)
       
   308 
       
   309         enable_ra = False
       
   310         for p in new_ports:
       
   311             self.internal_network_added(p)
       
   312             self.internal_ports.append(p)
       
   313             enable_ra = enable_ra or self._port_has_ipv6_subnet(p)
       
   314 
       
   315         for p in old_ports:
       
   316             self.internal_network_removed(p)
       
   317             self.internal_ports.remove(p)
       
   318             enable_ra = enable_ra or self._port_has_ipv6_subnet(p)
       
   319 
       
   320 #         if updated_ports:
       
   321 #             for index, p in enumerate(internal_ports):
       
   322 #                 if not updated_ports.get(p['id']):
       
   323 #                     continue
       
   324 #                 self.internal_ports[index] = updated_ports[p['id']]
       
   325 #                 interface_name = self.get_internal_device_name(p['id'])
       
   326 #                 ip_cidrs = common_utils.fixed_ip_cidrs(p['fixed_ips'])
       
   327 #                 self.driver.init_l3(interface_name, ip_cidrs=ip_cidrs,
       
   328 #                         namespace=self.ns_name)
       
   329 #                 enable_ra = enable_ra or self._port_has_ipv6_subnet(p)
       
   330 
       
   331         # Enable RA
       
   332         if enable_ra:
       
   333             self.radvd.enable(internal_ports)
       
   334 
       
   335         # remove any internal stale router interfaces (i.e., l3i.. VNICs)
       
   336         existing_devices = self._get_existing_devices()
       
   337         current_internal_devs = set(n for n in existing_devices
       
   338                                     if n.startswith(INTERNAL_DEV_PREFIX))
       
   339         current_port_devs = set(self.get_internal_device_name(port_id)
       
   340                                 for port_id in current_port_ids)
       
   341         stale_devs = current_internal_devs - current_port_devs
       
   342         for stale_dev in stale_devs:
       
   343             LOG.debug(_('Deleting stale internal router device: %s'),
       
   344                       stale_dev)
       
   345             self.driver.fini_l3(stale_dev)
       
   346             self.driver.unplug(stale_dev)
       
   347 
   116 
   348     def _add_floating_ip_rules(self, interface_name, fip, fip_statuses):
   117     def _add_floating_ip_rules(self, interface_name, fip, fip_statuses):
   349         fixed_ip = fip['fixed_ip_address']
   118         fixed_ip = fip['fixed_ip_address']
   350         fip_ip = fip['floating_ip_address']
   119         fip_ip = fip['floating_ip_address']
   351         for ipnet, gwportname in self.ipnet_gwportname.iteritems():
   120         for ipnet, gwportname in self.ipnet_gwportname.iteritems():
   385 
   154 
   386         existing_cidrs = set(ipaddr_list)
   155         existing_cidrs = set(ipaddr_list)
   387         new_cidrs = set()
   156         new_cidrs = set()
   388 
   157 
   389         floating_ips = self.get_floating_ips()
   158         floating_ips = self.get_floating_ips()
   390 
       
   391         # Loop once to ensure that floating ips are configured.
   159         # Loop once to ensure that floating ips are configured.
   392         for fip in floating_ips:
   160         for fip in floating_ips:
   393             fixed_ip = fip['fixed_ip_address']
   161             fixed_ip = fip['fixed_ip_address']
   394             fip_ip = fip['floating_ip_address']
   162             fip_ip = fip['floating_ip_address']
   395             fip_cidr = str(fip_ip) + FLOATING_IP_CIDR_SUFFIX
   163             fip_cidr = str(fip_ip) + FLOATING_IP_CIDR_SUFFIX
   396             new_cidrs.add(fip_cidr)
   164             new_cidrs.add(fip_cidr)
       
   165             fip_statuses[fip['id']] = l3_constants.FLOATINGIP_STATUS_ACTIVE
   397             if fip_cidr not in existing_cidrs:
   166             if fip_cidr not in existing_cidrs:
   398                 try:
   167                 try:
   399                     ipintf.create_address(fip_cidr, ifcheck=False,
   168                     ipintf.create_address(fip_cidr, ifcheck=False,
   400                                           addrcheck=False)
   169                                           addrcheck=False)
   401                     if not self._add_floating_ip_rules(interface_name, fip,
   170                     if not self._add_floating_ip_rules(interface_name, fip,
   430                     # new rules for the new fixed_ip
   199                     # new rules for the new fixed_ip
   431                     self.pf.remove_anchor([interface_name, fip_ip])
   200                     self.pf.remove_anchor([interface_name, fip_ip])
   432                     if not self._add_floating_ip_rules(interface_name, fip,
   201                     if not self._add_floating_ip_rules(interface_name, fip,
   433                                                        fip_statuses):
   202                                                        fip_statuses):
   434                         continue
   203                         continue
   435             fip_statuses[fip['id']] = l3_constants.FLOATINGIP_STATUS_ACTIVE
   204                 elif fip_statuses[fip['id']] == fip['status']:
       
   205                     # mark the status as not changed. we can't remove it
       
   206                     # because that's how the caller determines that it was
       
   207                     # removed (TODO(gmoodalb): check this)
       
   208                     fip_statuses[fip['id']] = router.FLOATINGIP_STATUS_NOCHANGE
       
   209 
   436             LOG.debug("Floating ip %(id)s added, status %(status)s",
   210             LOG.debug("Floating ip %(id)s added, status %(status)s",
   437                       {'id': fip['id'], 'status': fip_statuses.get(fip['id'])})
   211                       {'id': fip['id'],
       
   212                        'status': fip_statuses.get(fip['id'])})
   438 
   213 
   439         # Clean up addresses that no longer belong on the gateway interface and
   214         # Clean up addresses that no longer belong on the gateway interface and
   440         # remove the binat-to PF rule associated with them
   215         # remove the binat-to PF rule associated with them
   441         for ip_cidr in existing_cidrs - new_cidrs:
   216         for ip_cidr in existing_cidrs - new_cidrs:
   442             if ip_cidr.endswith(FLOATING_IP_CIDR_SUFFIX):
   217             if ip_cidr.endswith(FLOATING_IP_CIDR_SUFFIX):
       
   218                 LOG.debug("Removing floating ip %s from interface %s",
       
   219                           ip_cidr, ipintf)
   443                 self.pf.remove_anchor([interface_name, ip_cidr.split('/')[0]])
   220                 self.pf.remove_anchor([interface_name, ip_cidr.split('/')[0]])
   444                 ipintf.delete_address(ip_cidr, addrcheck=False)
   221                 ipintf.delete_address(ip_cidr, addrcheck=False)
   445         return fip_statuses
   222         return fip_statuses
   446 
   223 
       
   224     def delete(self, agent):
       
   225         self.router['gw_port'] = None
       
   226         self.router[l3_constants.INTERFACE_KEY] = []
       
   227         self.router[l3_constants.FLOATINGIP_KEY] = []
       
   228         self.process_delete(agent)
       
   229         self.disable_radvd()
       
   230 
       
   231     def internal_network_added(self, port):
       
   232         internal_dlname = self.get_internal_device_name(port['id'])
       
   233         LOG.debug("adding internal network: port(%s), interface(%s)",
       
   234                   port['id'], internal_dlname)
       
   235         # driver just returns if datalink and IP interface already exists
       
   236         self.driver.plug(port['tenant_id'], port['network_id'], port['id'],
       
   237                          internal_dlname, port['mac_address'],
       
   238                          vif_type=port.get('binding:vif_type'))
       
   239         fixed_ips = port['fixed_ips']
       
   240         ip_cidrs = common_utils.fixed_ip_cidrs(fixed_ips)
       
   241         self.driver.init_l3(internal_dlname, ip_cidrs)
       
   242         for fixed_ip in fixed_ips:
       
   243             net_lib.send_ip_addr_adv_notif(internal_dlname,
       
   244                                            fixed_ip['ip_address'],
       
   245                                            self.agent_conf)
       
   246 
       
   247         port_subnet = port['subnets'][0]['cidr']
       
   248         ipversion = netaddr.IPNetwork(port_subnet).version
       
   249         rules = []
       
   250         # if metadata is enabled, then we need to redirect all the packets
       
   251         # arriving at 169.254.169.254:80 to neutron-metadata-proxy server
       
   252         # listening at self.agent_conf.metadata_port
       
   253         if self.agent_conf.enable_metadata_proxy and ipversion == 4:
       
   254             rules.append('pass in quick proto tcp to 169.254.169.254/32 '
       
   255                          'port 80 rdr-to 127.0.0.1 port %s label metadata_%s'
       
   256                          % (self.agent_conf.metadata_port, internal_dlname))
       
   257 
       
   258         # Since we support shared router model, we need to block the new
       
   259         # internal port from reaching other tenant's ports. However, if
       
   260         # allow_forwarding_between_networks is set, then we need to
       
   261         # allow forwarding of packets between same tenant's ports.
       
   262         block_tblname = 'block_%s' % internal_dlname
       
   263         rules.append('block in quick to <%s> label %s' %
       
   264                      (block_tblname, block_tblname))
       
   265         if self.agent_conf.allow_forwarding_between_networks:
       
   266             allow_tblname = 'allow_%s' % internal_dlname
       
   267             rules.append('pass in quick to <%s> reply-to %s label %s' %
       
   268                          (allow_tblname, internal_dlname, allow_tblname))
       
   269 
       
   270         # finally add all the rules in one shot
       
   271         self.pf.add_rules(rules, [internal_dlname, 'normal'])
       
   272 
       
   273         ex_gw_port = self.ex_gw_port
       
   274         if not ex_gw_port:
       
   275             return
       
   276 
       
   277         ex_gw_ip = ex_gw_port['subnets'][0]['gateway_ip']
       
   278         if not ex_gw_ip:
       
   279             return
       
   280 
       
   281         if netaddr.IPAddress(ex_gw_ip).version != 4 or ipversion != 4:
       
   282             return
       
   283 
       
   284         # if the external gateway is already setup for the shared router,
       
   285         # then we need to add Policy Based Routing (PBR) for both inbound
       
   286         # and outbound for this internal network
       
   287         external_dlname = self.get_external_device_name(ex_gw_port['id'])
       
   288         label = 'pbr_%s' % internal_dlname
       
   289         pbr_rules = ['pass in quick to !%s route-to {(%s %s)} label %s_in' %
       
   290                      (port_subnet, external_dlname, ex_gw_ip, label)]
       
   291         pbr_rules.append('pass out quick received-on %s reply-to %s@%s '
       
   292                          'label %s_out' % (external_dlname, ex_gw_ip,
       
   293                                            external_dlname, label))
       
   294 
       
   295         self.pf.add_rules(pbr_rules, [internal_dlname, 'pbr'])
       
   296         if self._snat_enabled:
       
   297             ex_gw_port_ip = ex_gw_port['fixed_ips'][0]['ip_address']
       
   298             label = 'snat_%s' % internal_dlname
       
   299             snat_rule = ('pass out quick from %s to any nat-to %s label %s '
       
   300                          'reply-to %s' % (port_subnet, ex_gw_port_ip, label,
       
   301                                           internal_dlname))
       
   302             self.pf.add_rules([snat_rule], [external_dlname, internal_dlname])
       
   303 
       
   304     def internal_network_removed(self, port):
       
   305         internal_dlname = self.get_internal_device_name(port['id'])
       
   306         LOG.debug("removing internal network: port(%s) interface(%s)",
       
   307                   port['id'], internal_dlname)
       
   308         # remove the anchor and tables associated with this internal port
       
   309         self.pf.remove_anchor_recursively([internal_dlname])
       
   310         if self.ex_gw_port and self._snat_enabled:
       
   311             external_dlname = self.\
       
   312                 get_external_device_name(self.ex_gw_port['id'])
       
   313             self.pf.remove_anchor_recursively([external_dlname,
       
   314                                                internal_dlname])
       
   315         if net_lib.Datalink.datalink_exists(internal_dlname):
       
   316             self.driver.unplug(internal_dlname)
       
   317 
       
   318     def _get_existing_devices(self):
       
   319         return net_lib.Datalink.show_link()
       
   320 
       
   321     def internal_network_updated(self, interface_name, ip_cidrs):
       
   322         pass
       
   323 
       
   324     def _apply_common_rules(self, all_subnets, internal_ports):
       
   325         v4_subnets = [subnet for subnet in all_subnets
       
   326                       if netaddr.IPNetwork(subnet).version == 4]
       
   327         if not v4_subnets:
       
   328             return
       
   329 
       
   330         # add rule for metadata and broadcast
       
   331         allsubnets_tblname = "all_v4_subnets"
       
   332         common_aname = "common"
       
   333         self.pf.replace_table_entry(allsubnets_tblname, v4_subnets,
       
   334                                     [common_aname])
       
   335         rules = []
       
   336         # don't forward broadcast packets out of the internal subnet
       
   337         rules.append('pass in quick from <%s> to 255.255.255.255 label '
       
   338                      '%s_bcast' % (allsubnets_tblname, common_aname))
       
   339         self.pf.add_rules(rules, [common_aname])
       
   340 
       
   341     def _pre_setup_pf_rules(self, new_ports, old_ports, internal_ports):
       
   342         """We are going to do some amount of book keeping (for later use) and
       
   343         also pre-setup PF skeleton rules ahead of time to improve PF setup
       
   344         time.
       
   345         """
       
   346 
       
   347         # Process PF anchor rules for internal ports in bulk as this
       
   348         # significantly improves the PF setup time. Capture the anchor
       
   349         # rules that will be placed under _auto/neutron:l3:agent.
       
   350         new_anchor_rules = set()
       
   351         for p in new_ports:
       
   352             port_id = p['id']
       
   353             tenant_id = p['tenant_id']
       
   354             subnet = p['subnets'][0]['cidr']
       
   355             internal_dlname = self.get_internal_device_name(port_id)
       
   356             anchor_rule = 'anchor "%s/*" on %s all' % (internal_dlname,
       
   357                                                        internal_dlname)
       
   358             new_anchor_rules.add(anchor_rule)
       
   359             ipnet = netaddr.IPNetwork(subnet)
       
   360             if ipnet.version == 4:
       
   361                 self.ipnet_gwportname[ipnet] = internal_dlname
       
   362             # Capture all the subnets across all tenants and subnets
       
   363             # per-tenant. We will setup PF tables for each internal network
       
   364             # ahead of time
       
   365             self.tenant_subnets['all_tenants'].add(subnet)
       
   366             if tenant_id not in self.tenant_subnets:
       
   367                 self.tenant_subnets[tenant_id] = set()
       
   368             self.tenant_subnets[tenant_id].add(subnet)
       
   369 
       
   370         old_anchor_rules = set()
       
   371         for p in old_ports:
       
   372             port_id = p['id']
       
   373             tenant_id = p['tenant_id']
       
   374             subnet = p['subnets'][0]['cidr']
       
   375             internal_dlname = self.get_internal_device_name(port_id)
       
   376             anchor_rule = 'anchor "%s/*" on %s all' % (internal_dlname,
       
   377                                                        internal_dlname)
       
   378             old_anchor_rules.add(anchor_rule)
       
   379             ipnet = netaddr.IPNetwork(subnet)
       
   380             if ipnet.version == 4:
       
   381                 self.ipnet_gwportname.pop(ipnet, None)
       
   382             self.tenant_subnets['all_tenants'].discard(subnet)
       
   383             if tenant_id in self.tenant_subnets:
       
   384                 self.tenant_subnets[tenant_id].discard(subnet)
       
   385 
       
   386         existing_anchor_rules = set(self.pf.list_anchor_rules())
       
   387         final_anchor_rules = ((existing_anchor_rules | new_anchor_rules) -
       
   388                               old_anchor_rules)
       
   389         # add an anchor rule to capture rules common amongst all the
       
   390         # internal ports under 'common' anchor
       
   391         if internal_ports:
       
   392             final_anchor_rules.add('anchor "common" all')
       
   393             # add rule for metadata and broadcast for all tenant's networks
       
   394             self._apply_common_rules(self.tenant_subnets['all_tenants'],
       
   395                                      internal_ports)
       
   396         else:
       
   397             final_anchor_rules.discard('anchor "common" all')
       
   398             # Now that there are no internal ports, remove the common anchor
       
   399             # that captures rules common amongst all the internal ports
       
   400             self.pf.remove_anchor_recursively(['common'])
       
   401         self.pf.add_rules(list(sorted(final_anchor_rules)))
       
   402 
       
   403         # Since we support shared router model, we need to block the new
       
   404         # internal port from reaching other tenant's ports. However, if
       
   405         # allow_forwarding_between_networks is set, then we need to
       
   406         # allow forwarding of packets between same tenant's ports
       
   407         block_subnets = set()
       
   408         allow_subnets = set()
       
   409         for p in internal_ports:
       
   410             subnet = p['subnets'][0]['cidr']
       
   411             tenant_id = p['tenant_id']
       
   412             if self.agent_conf.allow_forwarding_between_networks:
       
   413                 allow_subnets = self.tenant_subnets[tenant_id] - set([subnet])
       
   414                 block_subnets = (self.tenant_subnets['all_tenants'] -
       
   415                                  self.tenant_subnets[tenant_id])
       
   416             else:
       
   417                 block_subnets = (self.tenant_subnets['all_tenants'] -
       
   418                                  set([subnet]))
       
   419             # add table entry in the global scope
       
   420             internal_dlname = self.get_internal_device_name(p['id'])
       
   421             block_tblname = "block_%s" % internal_dlname
       
   422             self.pf.replace_table_entry(block_tblname, list(block_subnets),
       
   423                                         [internal_dlname, 'normal'])
       
   424             if allow_subnets:
       
   425                 allow_tblname = "allow_%s" % internal_dlname
       
   426                 self.pf.replace_table_entry(allow_tblname, list(allow_subnets),
       
   427                                             [internal_dlname, 'normal'])
       
   428 
       
   429     def _process_internal_ports(self, pd):
       
   430         existing_port_ids = set([p['id'] for p in self.internal_ports])
       
   431 
       
   432         internal_ports = self.router.get(l3_constants.INTERFACE_KEY, [])
       
   433         current_port_ids = set([p['id'] for p in internal_ports
       
   434                                 if p['admin_state_up']])
       
   435 
       
   436         new_port_ids = current_port_ids - existing_port_ids
       
   437         new_ports = [p for p in internal_ports if p['id'] in new_port_ids]
       
   438         old_ports = [p for p in self.internal_ports if
       
   439                      p['id'] not in current_port_ids]
       
   440 #         updated_ports = self._get_updated_ports(self.internal_ports,
       
   441 #                                                 internal_ports)
       
   442 
       
   443         if old_ports or new_ports:
       
   444             self._pre_setup_pf_rules(new_ports, old_ports, internal_ports)
       
   445 
       
   446         enable_ra = False
       
   447         for p in new_ports:
       
   448             self.internal_network_added(p)
       
   449             LOG.debug("appending port %s to internal_ports cache", p)
       
   450             self.internal_ports.append(p)
       
   451             enable_ra = enable_ra or self._port_has_ipv6_subnet(p)
       
   452             for subnet in p['subnets']:
       
   453                 if ipv6_utils.is_ipv6_pd_enabled(subnet):
       
   454                     interface_name = self.get_internal_device_name(p['id'])
       
   455                     pd.enable_subnet(self.router_id, subnet['id'],
       
   456                                      subnet['cidr'],
       
   457                                      interface_name, p['mac_address'])
       
   458 
       
   459         for p in old_ports:
       
   460             self.internal_network_removed(p)
       
   461             LOG.debug("removing port %s from internal_ports cache", p)
       
   462             self.internal_ports.remove(p)
       
   463             enable_ra = enable_ra or self._port_has_ipv6_subnet(p)
       
   464             for subnet in p['subnets']:
       
   465                 if ipv6_utils.is_ipv6_pd_enabled(subnet):
       
   466                     pd.disable_subnet(self.router_id, subnet['id'])
       
   467 
       
   468 #         updated_cidres = []
       
   469 #         if updated_ports:
       
   470 #             for index, p in enumerate(internal_ports):
       
   471 #                 if not updated_ports.get(p['id']):
       
   472 #                     continue
       
   473 #                 self.internal_ports[index] = updated_ports[p['id']]
       
   474 #                 interface_name = self.get_internal_device_name(p['id'])
       
   475 #                 ip_cidrs = common_utils.fixed_ip_cidrs(p['fixed_ips'])
       
   476 #                 LOG.debug("updating internal network for port %s", p)
       
   477 #                 updated_cidrs += ip_cidrs
       
   478 
       
   479 #                 self.driver.init_l3(interface_name, ip_cidrs=ip_cidrs,
       
   480 #                         namespace=self.ns_name)
       
   481 #                 enable_ra = enable_ra or self._port_has_ipv6_subnet(p)
       
   482 
       
   483 #         # Check if there is any pd prefix update
       
   484 #         for p in internal_ports:
       
   485 #             if p['id'] in (set(current_port_ids) & set(existing_port_ids)):
       
   486 #                 for subnet in p.get('subnets', []):
       
   487 #                     if ipv6_utils.is_ipv6_pd_enabled(subnet):
       
   488 #                         old_prefix = pd.update_subnet(self.router_id,
       
   489 #                                                       subnet['id'],
       
   490 #                                                       subnet['cidr'])
       
   491 #                         if old_prefix:
       
   492 #                             self._internal_network_updated(p, subnet['id'],
       
   493 #                                                            subnet['cidr'],
       
   494 #                                                            old_prefix,
       
   495 #                                                            updated_cidrs)
       
   496 #                             enable_ra = True
       
   497         # Enable RA
       
   498         if enable_ra:
       
   499             self.radvd.enable(internal_ports)
       
   500 
       
   501         # remove any internal stale router interfaces (i.e., l3i.. VNICs)
       
   502         existing_devices = self._get_existing_devices()
       
   503         current_internal_devs = set(n for n in existing_devices
       
   504                                     if n.startswith(INTERNAL_DEV_PREFIX))
       
   505         current_port_devs = set(self.get_internal_device_name(port_id)
       
   506                                 for port_id in current_port_ids)
       
   507         stale_devs = current_internal_devs - current_port_devs
       
   508         for stale_dev in stale_devs:
       
   509             LOG.debug(_('Deleting stale internal router device: %s'),
       
   510                       stale_dev)
       
   511             pd.remove_stale_ri_ifname(self.router_id, stale_dev)
       
   512             self.driver.unplug(stale_dev)
       
   513 
   447     # TODO(gmoodalb): need to do more work on ipv6 gateway
   514     # TODO(gmoodalb): need to do more work on ipv6 gateway
   448     def external_gateway_added(self, ex_gw_port, external_dlname):
   515     def external_gateway_added(self, ex_gw_port, external_dlname):
       
   516         LOG.debug("External gateway added: port(%s), interface(%s)",
       
   517                   ex_gw_port, external_dlname)
       
   518         # TODO(gmoodalb): add MTU to plug()?
   449         self.driver.plug(ex_gw_port['tenant_id'], ex_gw_port['network_id'],
   519         self.driver.plug(ex_gw_port['tenant_id'], ex_gw_port['network_id'],
   450                          ex_gw_port['id'], external_dlname,
   520                          ex_gw_port['id'], external_dlname,
   451                          ex_gw_port['mac_address'],
   521                          ex_gw_port['mac_address'],
   452                          bridge=self.agent_conf.external_network_bridge,
   522                          bridge=self.agent_conf.external_network_bridge,
   453                          vif_type=ex_gw_port.get('binding:vif_type'))
   523                          vif_type=ex_gw_port.get('binding:vif_type'))
   491     def external_gateway_updated(self, ex_gw_port, external_dlname):
   561     def external_gateway_updated(self, ex_gw_port, external_dlname):
   492         # There is nothing to do on Solaris
   562         # There is nothing to do on Solaris
   493         pass
   563         pass
   494 
   564 
   495     def external_gateway_removed(self, ex_gw_port, external_dlname):
   565     def external_gateway_removed(self, ex_gw_port, external_dlname):
       
   566         LOG.debug("External gateway removed: port(%s), interface(%s)",
       
   567                   ex_gw_port, external_dlname)
   496         # remove nested anchor rule first
   568         # remove nested anchor rule first
   497         self.pf.remove_nested_anchor_rule(None, external_dlname)
   569         self.pf.remove_nested_anchor_rule(None, external_dlname)
   498 
   570 
   499         gw_ip = ex_gw_port['subnets'][0]['gateway_ip']
   571         gw_ip = ex_gw_port['subnets'][0]['gateway_ip']
   500         if gw_ip:
   572         if gw_ip:
   507                 cmd = ['/usr/bin/pfexec', '/usr/sbin/route', 'delete',
   579                 cmd = ['/usr/bin/pfexec', '/usr/sbin/route', 'delete',
   508                        'default', gw_ip]
   580                        'default', gw_ip]
   509                 utils.execute(cmd, check_exit_code=False)
   581                 utils.execute(cmd, check_exit_code=False)
   510 
   582 
   511         if net_lib.Datalink.datalink_exists(external_dlname):
   583         if net_lib.Datalink.datalink_exists(external_dlname):
   512             self.driver.fini_l3(external_dlname)
       
   513             self.driver.unplug(external_dlname,
   584             self.driver.unplug(external_dlname,
   514                                self.agent_conf.external_network_bridge)
   585                                self.agent_conf.external_network_bridge)
   515 
   586 
   516     def _process_external_gateway(self, ex_gw_port):
   587     def _process_external_gateway(self, ex_gw_port, pd):
   517         # TODO(Carl) Refactor to clarify roles of ex_gw_port vs self.ex_gw_port
   588         # TODO(Carl) Refactor to clarify roles of ex_gw_port vs self.ex_gw_port
   518         ex_gw_port_id = (ex_gw_port and ex_gw_port['id'] or
   589         ex_gw_port_id = (ex_gw_port and ex_gw_port['id'] or
   519                          self.ex_gw_port and self.ex_gw_port['id'])
   590                          self.ex_gw_port and self.ex_gw_port['id'])
   520 
   591 
   521         ex_gw_port_status = None
   592         ex_gw_port_status = None
   522         interface_name = None
   593         interface_name = None
   523         if ex_gw_port_id:
   594         if ex_gw_port_id:
   524             interface_name = self.get_external_device_name(ex_gw_port_id)
   595             interface_name = self.get_external_device_name(ex_gw_port_id)
   525         if ex_gw_port:
   596         if ex_gw_port:
   526             def _gateway_ports_equal(port1, port2):
       
   527                 def _get_filtered_dict(d, ignore):
       
   528                     return dict((k, v) for k, v in d.iteritems()
       
   529                                 if k not in ignore)
       
   530 
       
   531                 keys_to_ignore = set(['binding:host_id'])
       
   532                 port1_filtered = _get_filtered_dict(port1, keys_to_ignore)
       
   533                 port2_filtered = _get_filtered_dict(port2, keys_to_ignore)
       
   534                 return port1_filtered == port2_filtered
       
   535 
       
   536             if not self.ex_gw_port:
   597             if not self.ex_gw_port:
   537                 self.external_gateway_added(ex_gw_port, interface_name)
   598                 self.external_gateway_added(ex_gw_port, interface_name)
       
   599                 pd.add_gw_interface(self.router['id'], interface_name)
   538                 ex_gw_port_status = 'added'
   600                 ex_gw_port_status = 'added'
   539             elif not _gateway_ports_equal(ex_gw_port, self.ex_gw_port):
   601             elif not self._gateway_ports_equal(ex_gw_port, self.ex_gw_port):
   540                 self.external_gateway_updated(ex_gw_port, interface_name)
   602                 self.external_gateway_updated(ex_gw_port, interface_name)
   541                 ex_gw_port_status = 'updated'
   603                 ex_gw_port_status = 'updated'
   542         elif not ex_gw_port and self.ex_gw_port:
   604         elif not ex_gw_port and self.ex_gw_port:
   543             self.external_gateway_removed(self.ex_gw_port, interface_name)
   605             self.external_gateway_removed(self.ex_gw_port, interface_name)
       
   606             pd.remove_gw_interface(self.router['id'])
   544             ex_gw_port_status = 'removed'
   607             ex_gw_port_status = 'removed'
   545 
   608 
   546         # Remove any external stale router interfaces (i.e., l3e.. VNICs)
   609         # Remove any external stale router interfaces (i.e., l3e.. VNICs)
   547         existing_devices = self._get_existing_devices()
   610         existing_devices = self._get_existing_devices()
   548         stale_devs = [dev for dev in existing_devices
   611         stale_devs = [dev for dev in existing_devices
   549                       if dev.startswith(EXTERNAL_DEV_PREFIX) and
   612                       if dev.startswith(EXTERNAL_DEV_PREFIX) and
   550                       dev != interface_name]
   613                       dev != interface_name]
   551         for stale_dev in stale_devs:
   614         for stale_dev in stale_devs:
   552             LOG.debug(_('Deleting stale external router device: %s'),
   615             LOG.debug(_('Deleting stale external router device: %s'),
   553                       stale_dev)
   616                       stale_dev)
   554             self.driver.fini_l3(stale_dev)
       
   555             self.driver.unplug(stale_dev)
   617             self.driver.unplug(stale_dev)
   556 
   618 
   557         # Process SNAT rules for external gateway
   619         # Process SNAT rules for external gateway
   558         self.perform_snat_action(self._handle_router_snat_rules,
   620         gw_port = self._router.get('gw_port')
   559                                  interface_name, ex_gw_port_status)
   621         self._handle_router_snat_rules(gw_port, interface_name,
       
   622                                        ex_gw_port_status)
   560 
   623 
   561     def external_gateway_snat_rules(self, ex_gw_port_ip, external_dlname):
   624     def external_gateway_snat_rules(self, ex_gw_port_ip, external_dlname):
   562         rules = {}
   625         rules = {}
   563         for port in self.internal_ports:
   626         for port in self.internal_ports:
   564             ip_cidr = port['subnets'][0]['cidr']
   627             ip_cidr = port['subnets'][0]['cidr']
   571                 rules[internal_dlname] = [rule]
   634                 rules[internal_dlname] = [rule]
   572 
   635 
   573         return rules
   636         return rules
   574 
   637 
   575     def _handle_router_snat_rules(self, ex_gw_port, external_dlname,
   638     def _handle_router_snat_rules(self, ex_gw_port, external_dlname,
   576                                   ex_gw_port_status, action):
   639                                   ex_gw_port_status):
       
   640         # Todo(gmoodalb): need this when we support address_scope
       
   641         # self.process_external_port_address_scope_routing(iptables_manager)
       
   642 
   577         # Remove all the old SNAT rules
   643         # Remove all the old SNAT rules
   578         # This is safe because if use_namespaces is set as False
   644         # This is safe because if use_namespaces is set as False
   579         # then the agent can only configure one router, otherwise
   645         # then the agent can only configure one router, otherwise
   580         # each router's SNAT rules will be in their own namespace
   646         # each router's SNAT rules will be in their own namespace
   581         if ex_gw_port_status in ['removed', 'updated']:
   647         if ex_gw_port_status in ['removed', 'updated']:
   583             for snat_anchor in snat_anchors:
   649             for snat_anchor in snat_anchors:
   584                 if "/l3i" in snat_anchor:
   650                 if "/l3i" in snat_anchor:
   585                     self.pf.remove_anchor(snat_anchor.split('/')[-2:])
   651                     self.pf.remove_anchor(snat_anchor.split('/')[-2:])
   586 
   652 
   587         # And add them back if the action is add_rules
   653         # And add them back if the action is add_rules
   588         if action == 'add_rules' and ex_gw_port_status in ['added', 'updated']:
   654         if ex_gw_port_status in ['added', 'updated']:
   589             # NAT rules are added only if ex_gw_port has an IPv4 address
   655             # NAT rules are added only if ex_gw_port has an IPv4 address
   590             ex_gw_port_ip = ex_gw_port['fixed_ips'][0]['ip_address']
   656             ex_gw_port_ip = ex_gw_port['fixed_ips'][0]['ip_address']
   591             if netaddr.IPAddress(ex_gw_port_ip).version != 4:
   657             if netaddr.IPAddress(ex_gw_port_ip).version != 4:
   592                 return
   658                 return
   593             port_rules = self.external_gateway_snat_rules(ex_gw_port_ip,
   659             port_rules = self.external_gateway_snat_rules(ex_gw_port_ip,
   594                                                           external_dlname)
   660                                                           external_dlname)
   595             for internal_dlname, rules in port_rules.iteritems():
   661             for internal_dlname, rules in port_rules.iteritems():
   596                 self.pf.add_rules(rules, [external_dlname, internal_dlname])
   662                 self.pf.add_rules(rules, [external_dlname, internal_dlname])
   597 
   663 
   598     def process_external(self, agent):
   664     def process_external(self, agent):
   599         existing_floating_ips = self.floating_ips
   665         fip_statuses = {}
   600         try:
   666         try:
   601             ex_gw_port = self.get_ex_gw_port()
   667             ex_gw_port = self.get_ex_gw_port()
   602             self._process_external_gateway(ex_gw_port)
   668             self._process_external_gateway(ex_gw_port, agent.pd)
   603             # TODO(Carl) Return after setting existing_floating_ips and
   669             # TODO(Carl) Return after setting existing_floating_ips and
   604             # still call update_fip_statuses?
   670             # still call update_fip_statuses?
   605             if not ex_gw_port:
   671             if not ex_gw_port:
   606                 return
   672                 return
   607 
   673 
   608             # Once NAT rules for floating IPs are safely in place
   674             # Once NAT rules for floating IPs are safely in place
   609             # configure their addresses on the external gateway port
   675             # configure their addresses on the external gateway port
   610             interface_name = self.get_external_device_name(ex_gw_port['id'])
   676             interface_name = self.get_external_device_name(ex_gw_port['id'])
   611             fip_statuses = self.configure_fip_addresses(interface_name)
   677             fip_statuses = self.configure_fip_addresses(interface_name)
   612         except (n_exc.FloatingIpSetupException,
   678         except n_exc.FloatingIpSetupException:
   613                 n_exc.IpTablesApplyException) as e:
       
   614                 # All floating IPs must be put in error state
   679                 # All floating IPs must be put in error state
   615                 LOG.exception(e)
   680                 LOG.exception(_LE("Failed to process floating IPs."))
   616                 fip_statuses = self.put_fips_in_error_state()
   681                 fip_statuses = self.put_fips_in_error_state()
   617 
   682         finally:
   618         agent.update_fip_statuses(self, existing_floating_ips, fip_statuses)
   683             self.update_fip_statuses(agent, fip_statuses)
       
   684 
       
   685     def process_external_port_address_scope_routing(self, iptables_manager):
       
   686         pass
       
   687 
       
   688     def process_address_scope(self):
       
   689         pass
   619 
   690 
   620 
   691 
   621 class L3NATAgent(l3_agent.L3NATAgentWithStateReport):
   692 class L3NATAgent(l3_agent.L3NATAgentWithStateReport):
   622     OPTS = [
   693     OPTS = [
   623         cfg.StrOpt('external_network_datalink', default='net0',
       
   624                    help=_("Name of the datalink that connects to "
       
   625                           "an external network.")),
       
   626         cfg.BoolOpt('allow_forwarding_between_networks', default=False,
   694         cfg.BoolOpt('allow_forwarding_between_networks', default=False,
   627                     help=_("Allow forwarding of packets between tenant's "
   695                     help=_("Allow forwarding of packets between tenant's "
   628                            "networks")),
   696                            "networks")),
   629     ]
   697     ]
   630 
   698 
   633         cfg.CONF.register_opts(interface.OPTS)
   701         cfg.CONF.register_opts(interface.OPTS)
   634         super(L3NATAgent, self).__init__(host=host, conf=conf)
   702         super(L3NATAgent, self).__init__(host=host, conf=conf)
   635         cfg.CONF.register_opts(neutron_vpnaas.vpn_agent_opts, 'vpnagent')
   703         cfg.CONF.register_opts(neutron_vpnaas.vpn_agent_opts, 'vpnagent')
   636         self.service = vpn_service.VPNService(self)
   704         self.service = vpn_service.VPNService(self)
   637         self.device_drivers = self.service.load_device_drivers(host)
   705         self.device_drivers = self.service.load_device_drivers(host)
       
   706 
       
   707     def _check_config_params(self):
       
   708         """Check items in configuration files.
       
   709 
       
   710         Check for required and invalid configuration items.
       
   711         The actual values are not verified for correctness.
       
   712         """
       
   713         if not self.conf.interface_driver:
       
   714             msg = _LE('An interface driver must be specified')
       
   715             LOG.error(msg)
       
   716             raise SystemExit(1)
       
   717 
       
   718         if not self.conf.router_id:
       
   719             msg = _LE('Router id (router_id) is required to be set.')
       
   720             LOG.error(msg)
       
   721             raise SystemExit(1)
       
   722 
       
   723         if self.conf.ipv6_gateway:
       
   724             # ipv6_gateway configured. Check for valid v6 link-local address.
       
   725             try:
       
   726                 msg = _LE("%s used in config as ipv6_gateway is not a valid "
       
   727                           "IPv6 link-local address."),
       
   728                 ip_addr = netaddr.IPAddress(self.conf.ipv6_gateway)
       
   729                 if ip_addr.version != 6 or not ip_addr.is_link_local():
       
   730                     LOG.error(msg, self.conf.ipv6_gateway)
       
   731                     raise SystemExit(1)
       
   732             except netaddr.AddrFormatError:
       
   733                 LOG.error(msg, self.conf.ipv6_gateway)
       
   734                 raise SystemExit(1)
   638 
   735 
   639     def _router_added(self, router_id, router):
   736     def _router_added(self, router_id, router):
   640         args = []
   737         args = []
   641         kwargs = {
   738         kwargs = {
   642             'router_id': router_id,
   739             'router_id': router_id,
   658                 bridge_exists(self.conf.external_network_bridge)):
   755                 bridge_exists(self.conf.external_network_bridge)):
   659             LOG.error(_("The external network bridge '%s' does not exist"),
   756             LOG.error(_("The external network bridge '%s' does not exist"),
   660                       self.conf.external_network_bridge)
   757                       self.conf.external_network_bridge)
   661             return
   758             return
   662 
   759 
   663         # If namespaces are disabled, only process the router associated
   760         # We don't support namespaces so only process the router associated
   664         # with the configured agent id.
   761         # with the configured agent id.
   665         if (not self.conf.use_namespaces and
   762         if (router['id'] != self.conf.router_id):
   666                 router['id'] != self.conf.router_id):
       
   667             raise n_exc.RouterNotCompatibleWithAgent(router_id=router['id'])
   763             raise n_exc.RouterNotCompatibleWithAgent(router_id=router['id'])
   668 
   764 
   669         # Either ex_net_id or handle_internal_only_routers must be set
   765         # Either ex_net_id or handle_internal_only_routers must be set
   670         ex_net_id = (router['external_gateway_info'] or {}).get('network_id')
   766         ex_net_id = (router['external_gateway_info'] or {}).get('network_id')
   671         if not ex_net_id and not self.conf.handle_internal_only_routers:
   767         if not ex_net_id and not self.conf.handle_internal_only_routers: