components/openstack/neutron/files/agent/evs_l3_agent.py
branchs11u3-sru
changeset 6035 c9748fcc32de
parent 4647 f1f27134bd1c
child 6444 bf62eba2612a
equal deleted inserted replaced
6016:a477397bba8b 6035:c9748fcc32de
     1 # vim: tabstop=4 shiftwidth=4 softtabstop=4
     1 # vim: tabstop=4 shiftwidth=4 softtabstop=4
     2 
     2 
     3 # Copyright 2012 VMware, Inc.  All rights reserved.
     3 # Copyright 2012 VMware, Inc.  All rights reserved.
     4 #
     4 #
     5 # Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
     5 # Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
     6 #
     6 #
     7 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
     7 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
     8 #    not use this file except in compliance with the License. You may obtain
     8 #    not use this file except in compliance with the License. You may obtain
     9 #    a copy of the License at
     9 #    a copy of the License at
    10 #
    10 #
    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 
    28 from oslo_log import log as logging
    29 from neutron.agent.common import config
    29 
    30 from neutron.agent import l3_agent
    30 from neutron.agent.l3 import agent as l3_agent
    31 from neutron.agent.linux import external_process
    31 from neutron.agent.l3 import router_info as router
    32 from neutron.agent.linux import utils
    32 from neutron.agent.linux import utils
    33 from neutron.agent.solaris import interface
    33 from neutron.agent.solaris import interface
       
    34 from neutron.agent.solaris import ipfilters_manager
    34 from neutron.agent.solaris import net_lib
    35 from neutron.agent.solaris import net_lib
    35 from neutron.agent.solaris import ra
    36 from neutron.agent.solaris import ra
       
    37 from neutron.callbacks import events
       
    38 from neutron.callbacks import registry
       
    39 from neutron.callbacks import resources
    36 from neutron.common import constants as l3_constants
    40 from neutron.common import constants as l3_constants
       
    41 from neutron.common import exceptions as n_exc
    37 from neutron.common import utils as common_utils
    42 from neutron.common import utils as common_utils
    38 from neutron.openstack.common import log as logging
    43 from oslo_utils import importutils
    39 
    44 from oslo_log import log as logging
       
    45 
       
    46 import neutron_vpnaas.services.vpn.agent as neutron_vpnaas
       
    47 from neutron_vpnaas.extensions import vpnaas
       
    48 from neutron_vpnaas.services.vpn import vpn_service
    40 
    49 
    41 LOG = logging.getLogger(__name__)
    50 LOG = logging.getLogger(__name__)
    42 INTERNAL_DEV_PREFIX = 'l3i'
    51 INTERNAL_DEV_PREFIX = 'l3i'
    43 EXTERNAL_DEV_PREFIX = 'l3e'
    52 EXTERNAL_DEV_PREFIX = 'l3e'
    44 FLOATING_IP_CIDR_SUFFIX = '/32'
    53 FLOATING_IP_CIDR_SUFFIX = '/32'
    45 
    54 
    46 
    55 
    47 class EVSL3NATAgent(l3_agent.L3NATAgentWithStateReport):
    56 class SolarisRouterInfo(router.RouterInfo):
    48     OPTS = [
    57 
    49         cfg.StrOpt('external_network_datalink', default='net0',
    58     def __init__(self, router_id, router, agent_conf, interface_driver,
    50                    help=_("Name of the datalink that connects to "
    59                  use_ipv6=False):
    51                           "an external network.")),
    60         super(SolarisRouterInfo, self).__init__(router_id, router, agent_conf,
    52         cfg.BoolOpt('allow_forwarding_between_networks', default=False,
    61                                                 interface_driver, use_ipv6)
    53                     help=_("Allow forwarding of packets between tenant's "
    62         self.ipfilters_manager = ipfilters_manager.IPfiltersManager()
    54                            "networks")),
    63         self.iptables_manager = None
    55     ]
    64         self.remove_route = False
    56 
    65 
    57     def __init__(self, host, conf=None):
    66     def initialize(self, process_monitor):
    58         cfg.CONF.register_opts(self.OPTS)
    67         """Initialize the router on the system.
    59         cfg.CONF.register_opts(interface.OPTS)
    68 
    60         super(EVSL3NATAgent, self).__init__(host=host, conf=conf)
    69         This differs from __init__ in that this method actually affects the
    61 
    70         system creating namespaces, starting processes, etc.  The other merely
    62     def _router_added(self, router_id, router):
    71         initializes the python object.  This separates in-memory object
    63         ri = l3_agent.RouterInfo(router_id, None,
    72         initialization from methods that actually go do stuff to the system.
    64                                  self.conf.use_namespaces, router)
    73 
    65         self.router_info[router_id] = ri
    74         :param process_monitor: The agent's process monitor instance.
    66 
       
    67         if self.conf.enable_metadata_proxy:
       
    68             self._spawn_metadata_proxy(ri.router_id, ri.ns_name)
       
    69 
       
    70     def _router_removed(self, router_id):
       
    71         ri = self.router_info.get(router_id)
       
    72         if ri is None:
       
    73             LOG.warn(_("Info for router %s were not found. "
       
    74                        "Skipping router removal"), router_id)
       
    75             return
       
    76         ri.router['gw_port'] = None
       
    77         ri.router[l3_constants.INTERFACE_KEY] = []
       
    78         ri.router[l3_constants.FLOATINGIP_KEY] = []
       
    79         self.process_router(ri)
       
    80         if self.conf.enable_metadata_proxy:
       
    81             self._destroy_metadata_proxy(ri.router_id, ri.ns_name)
       
    82 
       
    83         del self.router_info[router_id]
       
    84 
       
    85     def _get_metadata_proxy_process_manager(self, router_id, ns_name):
       
    86         return external_process.ProcessManager(
       
    87             self.conf,
       
    88             router_id,
       
    89             root_helper=None,
       
    90             namespace=ns_name)
       
    91 
       
    92     def _get_metadata_proxy_callback(self, router_id):
       
    93         """Need to override this since we need to pass the absolute
       
    94         path to neutron-ns-metadata-proxy binary.
       
    95         """
    75         """
    96         def callback(pid_file):
    76         self.process_monitor = process_monitor
    97             metadata_proxy_socket = cfg.CONF.metadata_proxy_socket
    77         self.radvd = ra.NDPD(self.router_id, self.get_internal_device_name)
    98             proxy_cmd = ['/usr/lib/neutron/neutron-ns-metadata-proxy',
    78 
    99                          '--pid_file=%s' % pid_file,
    79     def get_internal_device_name(self, port_id):
   100                          '--metadata_proxy_socket=%s' % metadata_proxy_socket,
    80         # Because of the way how dnsmasq works on Solaris, the length
   101                          '--router_id=%s' % router_id,
    81         # of datalink name cannot exceed 16 (includes terminating nul
   102                          '--state_path=%s' % self.conf.state_path,
    82         # character). So, the linkname can only have 15 characters and
   103                          '--metadata_port=%s' % self.conf.metadata_port]
    83         # the last two characters are set aside for '_0'. So, we only
   104             proxy_cmd.extend(config.get_log_args(
    84         # have 13 characters left.
   105                 cfg.CONF, 'neutron-ns-metadata-proxy-%s.log' %
    85         dname = (INTERNAL_DEV_PREFIX + port_id)[:13]
   106                 router_id))
    86         dname += '_0'
   107             return proxy_cmd
    87         return dname.replace('-', '_')
   108 
    88 
   109         return callback
    89     def get_external_device_name(self, port_id):
   110 
    90         # please see the comment above
   111     def external_gateway_snat_rules(self, ex_gw_ip, internal_cidrs,
    91         dname = (EXTERNAL_DEV_PREFIX + port_id)[:13]
   112                                     interface_name):
    92         dname += '_0'
   113         rules = []
    93         return dname.replace('-', '_')
   114         for cidr in internal_cidrs:
    94 
   115             rules.append('map %s %s -> %s/32' %
    95     def routes_updated(self):
   116                          (interface_name, cidr, ex_gw_ip))
    96         pass
   117         return rules
    97 
   118 
    98     def _get_existing_devices(self):
   119     def _handle_router_snat_rules(self, ri, ex_gw_port, internal_cidrs,
    99         return net_lib.Datalink.show_link()
   120                                   interface_name, action):
   100 
   121         assert not ri.router['distributed']
   101     def internal_network_added(self, port):
   122 
   102         internal_dlname = self.get_internal_device_name(port['id'])
   123         # Remove all the old SNAT rules
   103         # driver just returns if datalink and IP interface already exists
   124         # This is safe because if use_namespaces is set as False
   104         self.driver.plug(port['tenant_id'], port['network_id'], port['id'],
   125         # then the agent can only configure one router, otherwise
   105                          internal_dlname)
   126         # each router's SNAT rules will be in their own namespace
   106         ip_cidrs = common_utils.fixed_ip_cidrs(port['fixed_ips'])
   127 
   107         self.driver.init_l3(internal_dlname, ip_cidrs)
   128         # get only the SNAT rules
   108 
   129         old_snat_rules = [rule for rule in ri.ipfilters_manager.ipv4['nat']
   109         # Since we support shared router model, we need to block the new
   130                           if rule.startswith('map')]
   110         # internal port from reaching other tenant's ports
   131         ri.ipfilters_manager.remove_nat_rules(old_snat_rules)
   111         block_pname = self._get_ippool_name(port['mac_address'])
   132 
   112         self.ipfilters_manager.add_ippool(block_pname, None)
   133         # And add them back if the action is add_rules
   113         if self.agent_conf.allow_forwarding_between_networks:
   134         if action == 'add_rules' and ex_gw_port:
   114             # If allow_forwarding_between_networks is set, then we need to
   135             # NAT rules are added only if ex_gw_port has an IPv4 address
   115             # allow forwarding of packets between same tenant's ports.
   136             for ip_addr in ex_gw_port['fixed_ips']:
   116             allow_pname = self._get_ippool_name(port['mac_address'], '0')
   137                 ex_gw_ip = ip_addr['ip_address']
   117             self.ipfilters_manager.add_ippool(allow_pname, None)
   138                 if netaddr.IPAddress(ex_gw_ip).version == 4:
   118 
   139                     rules = self.external_gateway_snat_rules(ex_gw_ip,
   119         # walk through the other internal ports and retrieve their
   140                                                              internal_cidrs,
   120         # cidrs and at the same time add the new internal port's
   141                                                              interface_name)
   121         # cidr to them
   142                     ri.ipfilters_manager.add_nat_rules(rules)
   122         port_subnet = port['subnets'][0]['cidr']
   143                     break
   123         block_subnets = []
   144 
   124         allow_subnets = []
   145     @common_utils.exception_logger()
   125         for internal_port in self.internal_ports:
   146     def process_router(self, ri):
   126             if internal_port['mac_address'] == port['mac_address']:
   147         # TODO(mrsmith) - we shouldn't need to check here
   127                 continue
   148         if 'distributed' not in ri.router:
   128             if (self.agent_conf.allow_forwarding_between_networks and
   149             ri.router['distributed'] = False
   129                     internal_port['tenant_id'] == port['tenant_id']):
   150         ex_gw_port = self._get_ex_gw_port(ri)
   130                 allow_subnets.append(internal_port['subnets'][0]['cidr'])
   151         internal_ports = ri.router.get(l3_constants.INTERFACE_KEY, [])
   131                 # we need to add the port's subnet to this internal_port's
   152         existing_port_ids = set([p['id'] for p in ri.internal_ports])
   132                 # allowed_subnet_pool
       
   133                 iport_allow_pname = \
       
   134                     self._get_ippool_name(internal_port['mac_address'], '0')
       
   135                 self.ipfilters_manager.add_ippool(iport_allow_pname,
       
   136                                                   [port_subnet])
       
   137             else:
       
   138                 block_subnets.append(internal_port['subnets'][0]['cidr'])
       
   139                 iport_block_pname = \
       
   140                     self._get_ippool_name(internal_port['mac_address'])
       
   141                 self.ipfilters_manager.add_ippool(iport_block_pname,
       
   142                                                   [port_subnet])
       
   143         # update the new port's pool with other ports' subnet
       
   144         self.ipfilters_manager.add_ippool(block_pname, block_subnets)
       
   145         if self.agent_conf.allow_forwarding_between_networks:
       
   146             self.ipfilters_manager.add_ippool(allow_pname, allow_subnets)
       
   147 
       
   148         # now setup the IPF rules
       
   149         rules = ['block in quick on %s from %s to pool/%d' %
       
   150                  (internal_dlname, port_subnet, block_pname)]
       
   151         # pass in packets between networks that belong to same tenant
       
   152         if self.agent_conf.allow_forwarding_between_networks:
       
   153             rules.append('pass in quick on %s from %s to pool/%d' %
       
   154                          (internal_dlname, port_subnet, allow_pname))
       
   155         # if the external gateway is already setup for the shared router,
       
   156         # then we need to add Policy Based Routing (PBR) for this internal
       
   157         # network
       
   158         ex_gw_port = self.ex_gw_port
       
   159         ex_gw_ip = (ex_gw_port['subnets'][0]['gateway_ip']
       
   160                     if ex_gw_port else None)
       
   161         if ex_gw_ip:
       
   162             external_dlname = self.get_external_device_name(ex_gw_port['id'])
       
   163             rules.append('pass in on %s to %s:%s from any to !%s' %
       
   164                          (internal_dlname, external_dlname, ex_gw_ip,
       
   165                           port_subnet))
       
   166 
       
   167         ipversion = netaddr.IPNetwork(port_subnet).version
       
   168         self.ipfilters_manager.add_ipf_rules(rules, ipversion)
       
   169         if self.agent_conf.enable_metadata_proxy and ipversion == 4:
       
   170             rdr_rule = ['rdr %s 169.254.169.254/32 port 80 -> %s port %d tcp' %
       
   171                         (internal_dlname, port['fixed_ips'][0]['ip_address'],
       
   172                          self.agent_conf.metadata_port)]
       
   173             self.ipfilters_manager.add_nat_rules(rdr_rule)
       
   174 
       
   175     def internal_network_removed(self, port):
       
   176         internal_dlname = self.get_internal_device_name(port['id'])
       
   177         port_subnet = port['subnets'][0]['cidr']
       
   178         # remove all the IP filter rules that we added during
       
   179         # internal network addition
       
   180         block_pname = self._get_ippool_name(port['mac_address'])
       
   181         rules = ['block in quick on %s from %s to pool/%d' %
       
   182                  (internal_dlname, port_subnet, block_pname)]
       
   183         if self.agent_conf.allow_forwarding_between_networks:
       
   184             allow_pname = self._get_ippool_name(port['mac_address'], '0')
       
   185             rules.append('pass in quick on %s from %s to pool/%d' %
       
   186                          (internal_dlname, port_subnet, allow_pname))
       
   187 
       
   188         # remove all the IP filter rules that we added during
       
   189         # external network addition
       
   190         ex_gw_port = self.ex_gw_port
       
   191         ex_gw_ip = (ex_gw_port['subnets'][0]['gateway_ip']
       
   192                     if ex_gw_port else None)
       
   193         if ex_gw_ip:
       
   194             external_dlname = self.get_external_device_name(ex_gw_port['id'])
       
   195             rules.append('pass in on %s to %s:%s from any to !%s' %
       
   196                          (internal_dlname, external_dlname, ex_gw_ip,
       
   197                           port_subnet))
       
   198         ipversion = netaddr.IPNetwork(port['subnets'][0]['cidr']).version
       
   199         self.ipfilters_manager.remove_ipf_rules(rules, ipversion)
       
   200 
       
   201         # remove the ippool
       
   202         self.ipfilters_manager.remove_ippool(block_pname, None)
       
   203         if self.agent_conf.allow_forwarding_between_networks:
       
   204             self.ipfilters_manager.remove_ippool(allow_pname, None)
       
   205 
       
   206         for internal_port in self.internal_ports:
       
   207             if (self.agent_conf.allow_forwarding_between_networks and
       
   208                     internal_port['tenant_id'] == port['tenant_id']):
       
   209                 iport_allow_pname = \
       
   210                     self._get_ippool_name(internal_port['mac_address'], '0')
       
   211                 self.ipfilters_manager.remove_ippool(iport_allow_pname,
       
   212                                                      [port_subnet])
       
   213             else:
       
   214                 iport_block_pname = \
       
   215                     self._get_ippool_name(internal_port['mac_address'])
       
   216                 self.ipfilters_manager.remove_ippool(iport_block_pname,
       
   217                                                      [port_subnet])
       
   218         if self.agent_conf.enable_metadata_proxy and ipversion == 4:
       
   219             rdr_rule = ['rdr %s 169.254.169.254/32 port 80 -> %s port %d tcp' %
       
   220                         (internal_dlname, port['fixed_ips'][0]['ip_address'],
       
   221                          self.agent_conf.metadata_port)]
       
   222             self.ipfilters_manager.remove_nat_rules(rdr_rule)
       
   223 
       
   224         if net_lib.Datalink.datalink_exists(internal_dlname):
       
   225             self.driver.fini_l3(internal_dlname)
       
   226             self.driver.unplug(internal_dlname)
       
   227 
       
   228     def _process_internal_ports(self):
       
   229         existing_port_ids = set([p['id'] for p in self.internal_ports])
       
   230 
       
   231         internal_ports = self.router.get(l3_constants.INTERFACE_KEY, [])
   153         current_port_ids = set([p['id'] for p in internal_ports
   232         current_port_ids = set([p['id'] for p in internal_ports
   154                                 if p['admin_state_up']])
   233                                 if p['admin_state_up']])
   155         new_ports = [p for p in internal_ports if
   234 
   156                      p['id'] in current_port_ids and
   235         new_port_ids = current_port_ids - existing_port_ids
   157                      p['id'] not in existing_port_ids]
   236         new_ports = [p for p in internal_ports if p['id'] in new_port_ids]
   158         old_ports = [p for p in ri.internal_ports if
   237         old_ports = [p for p in self.internal_ports if
   159                      p['id'] not in current_port_ids]
   238                      p['id'] not in current_port_ids]
   160         new_ipv6_port = False
   239 #         updated_ports = self._get_updated_ports(self.internal_ports,
   161         old_ipv6_port = False
   240 #                                                 internal_ports)
       
   241 
       
   242         enable_ra = False
   162         for p in new_ports:
   243         for p in new_ports:
   163             self._set_subnet_info(p)
   244             self.internal_network_added(p)
   164             self.internal_network_added(ri, p)
   245             self.internal_ports.append(p)
   165             ri.internal_ports.append(p)
   246             enable_ra = enable_ra or self._port_has_ipv6_subnet(p)
   166             if (not new_ipv6_port and
       
   167                     netaddr.IPNetwork(p['subnet']['cidr']).version == 6):
       
   168                 new_ipv6_port = True
       
   169 
   247 
   170         for p in old_ports:
   248         for p in old_ports:
   171             self.internal_network_removed(ri, p)
   249             self.internal_network_removed(p)
   172             ri.internal_ports.remove(p)
   250             self.internal_ports.remove(p)
   173             if (not old_ipv6_port and
   251             enable_ra = enable_ra or self._port_has_ipv6_subnet(p)
   174                     netaddr.IPNetwork(p['subnet']['cidr']).version == 6):
   252 
   175                 old_ipv6_port = True
   253 #         if updated_ports:
   176 
   254 #             for index, p in enumerate(internal_ports):
   177         if new_ipv6_port or old_ipv6_port:
   255 #                 if not updated_ports.get(p['id']):
   178             # refresh ndpd daemon after filling in ndpd.conf
   256 #                     continue
   179             # with the right entries
   257 #                 self.internal_ports[index] = updated_ports[p['id']]
   180             ra.enable_ipv6_ra(ri.router_id,
   258 #                 interface_name = self.get_internal_device_name(p['id'])
   181                               internal_ports,
   259 #                 ip_cidrs = common_utils.fixed_ip_cidrs(p['fixed_ips'])
   182                               self.get_internal_device_name)
   260 #                 self.driver.init_l3(interface_name, ip_cidrs=ip_cidrs,
       
   261 #                         namespace=self.ns_name)
       
   262 #                 enable_ra = enable_ra or self._port_has_ipv6_subnet(p)
       
   263 
       
   264         # Enable RA
       
   265         if enable_ra:
       
   266             self.radvd.enable(internal_ports)
   183 
   267 
   184         # remove any internal stale router interfaces (i.e., l3i.. VNICs)
   268         # remove any internal stale router interfaces (i.e., l3i.. VNICs)
   185         existing_devices = net_lib.Datalink.show_vnic()
   269         existing_devices = self._get_existing_devices()
   186         current_internal_devs = set([n for n in existing_devices
   270         current_internal_devs = set(n for n in existing_devices
   187                                      if n.startswith(INTERNAL_DEV_PREFIX)])
   271                                     if n.startswith(INTERNAL_DEV_PREFIX))
   188         current_port_devs = set([self.get_internal_device_name(id) for
   272         current_port_devs = set(self.get_internal_device_name(port_id)
   189                                  id in current_port_ids])
   273                                 for port_id in current_port_ids)
   190         stale_devs = current_internal_devs - current_port_devs
   274         stale_devs = current_internal_devs - current_port_devs
   191         for stale_dev in stale_devs:
   275         for stale_dev in stale_devs:
   192             LOG.debug(_('Deleting stale internal router device: %s'),
   276             LOG.debug(_('Deleting stale internal router device: %s'),
   193                       stale_dev)
   277                       stale_dev)
   194             self.driver.fini_l3(stale_dev)
   278             self.driver.fini_l3(stale_dev)
   195             self.driver.unplug(stale_dev)
   279             self.driver.unplug(stale_dev)
   196 
   280 
   197         # TODO(salv-orlando): RouterInfo would be a better place for
   281     def _get_ippool_name(self, mac_address, suffix=None):
   198         # this logic too
   282         # Generate a unique-name for ippool(1m) from that last 3
   199         ex_gw_port_id = (ex_gw_port and ex_gw_port['id'] or
   283         # bytes of mac-address. It is called pool name, but it is
   200                          ri.ex_gw_port and ri.ex_gw_port['id'])
   284         # actually a 32 bit integer
   201 
   285         name = mac_address.split(':')[3:]
   202         interface_name = None
   286         if suffix:
   203         if ex_gw_port_id:
   287             name.append(suffix)
   204             interface_name = self.get_external_device_name(ex_gw_port_id)
   288         return int("".join(name), 16)
   205         if ex_gw_port:
   289 
   206             def _gateway_ports_equal(port1, port2):
   290     def process_floating_ip_addresses(self, interface_name):
   207                 def _get_filtered_dict(d, ignore):
   291         """Configure IP addresses on router's external gateway interface.
   208                     return dict((k, v) for k, v in d.iteritems()
   292 
   209                                 if k not in ignore)
   293         Ensures addresses for existing floating IPs and cleans up
   210 
   294         those that should not longer be configured.
   211                 keys_to_ignore = set(['binding:host_id'])
   295         """
   212                 port1_filtered = _get_filtered_dict(port1, keys_to_ignore)
   296 
   213                 port2_filtered = _get_filtered_dict(port2, keys_to_ignore)
       
   214                 return port1_filtered == port2_filtered
       
   215 
       
   216             self._set_subnet_info(ex_gw_port)
       
   217             if not ri.ex_gw_port:
       
   218                 self.external_gateway_added(ri, ex_gw_port, interface_name)
       
   219             elif not _gateway_ports_equal(ex_gw_port, ri.ex_gw_port):
       
   220                 self.external_gateway_updated(ri, ex_gw_port, interface_name)
       
   221         elif not ex_gw_port and ri.ex_gw_port:
       
   222             self.external_gateway_removed(ri, ri.ex_gw_port, interface_name)
       
   223 
       
   224         # Remove any external stale router interfaces (i.e., l3e.. VNICs)
       
   225         stale_devs = [dev for dev in existing_devices
       
   226                       if dev.startswith(EXTERNAL_DEV_PREFIX)
       
   227                       and dev != interface_name]
       
   228         for stale_dev in stale_devs:
       
   229             LOG.debug(_('Deleting stale external router device: %s'),
       
   230                       stale_dev)
       
   231             self.driver.fini_l3(stale_dev)
       
   232             self.driver.unplug(stale_dev)
       
   233 
       
   234         # Process static routes for router
       
   235         self.routes_updated(ri)
       
   236 
       
   237         # Process SNAT rules for external gateway
       
   238         if (not ri.router['distributed'] or
       
   239                 ex_gw_port and self.get_gw_port_host(ri.router) == self.host):
       
   240             # Get IPv4 only internal CIDRs
       
   241             internal_cidrs = [p['ip_cidr'] for p in ri.internal_ports
       
   242                               if netaddr.IPNetwork(p['ip_cidr']).version == 4]
       
   243             ri.perform_snat_action(self._handle_router_snat_rules,
       
   244                                    internal_cidrs, interface_name)
       
   245 
       
   246         # Process SNAT/DNAT rules for floating IPs
       
   247         fip_statuses = {}
   297         fip_statuses = {}
   248         if ex_gw_port:
   298         if interface_name is None:
   249             existing_floating_ips = ri.floating_ips
   299             LOG.debug('No Interface for floating IPs router: %s',
   250             fip_statuses = self.process_router_floating_ips(ri, ex_gw_port)
   300                       self.router['id'])
   251             # Identify floating IPs which were disabled
   301             return fip_statuses
   252             ri.floating_ips = set(fip_statuses.keys())
   302 
   253             for fip_id in existing_floating_ips - ri.floating_ips:
   303         ipintf = net_lib.IPInterface(interface_name)
   254                 fip_statuses[fip_id] = l3_constants.FLOATINGIP_STATUS_DOWN
       
   255             # Update floating IP status on the neutron server
       
   256             self.plugin_rpc.update_floatingip_statuses(
       
   257                 self.context, ri.router_id, fip_statuses)
       
   258 
       
   259         # Update ex_gw_port and enable_snat on the router info cache
       
   260         ri.ex_gw_port = ex_gw_port
       
   261         ri.enable_snat = ri.router.get('enable_snat')
       
   262 
       
   263     def process_router_floating_ips(self, ri, ex_gw_port):
       
   264         """Configure the router's floating IPs
       
   265         Configures floating ips using ipnat(1m) on the router's gateway device.
       
   266 
       
   267         Cleans up floating ips that should not longer be configured.
       
   268         """
       
   269         ifname = self.get_external_device_name(ex_gw_port['id'])
       
   270         ipintf = net_lib.IPInterface(ifname)
       
   271         ipaddr_list = ipintf.ipaddr_list()['static']
   304         ipaddr_list = ipintf.ipaddr_list()['static']
   272 
   305 
   273         existing_cidrs = set(ipaddr_list)
   306         existing_cidrs = set(ipaddr_list)
   274         new_cidrs = set()
   307         new_cidrs = set()
   275 
   308 
   276         existing_nat_rules = [nat_rule for nat_rule in
   309         existing_nat_rules = [nat_rule for nat_rule in
   277                               ri.ipfilters_manager.ipv4['nat']]
   310                               self.ipfilters_manager.ipv4['nat']]
   278         new_nat_rules = []
   311         new_nat_rules = []
   279 
   312 
       
   313         floating_ips = self.get_floating_ips()
   280         # Loop once to ensure that floating ips are configured.
   314         # Loop once to ensure that floating ips are configured.
   281         fip_statuses = {}
   315         for fip in floating_ips:
   282         for fip in ri.router.get(l3_constants.FLOATINGIP_KEY, []):
       
   283             fip_ip = fip['floating_ip_address']
   316             fip_ip = fip['floating_ip_address']
   284             fip_cidr = str(fip_ip) + FLOATING_IP_CIDR_SUFFIX
   317             fip_cidr = str(fip_ip) + FLOATING_IP_CIDR_SUFFIX
   285             new_cidrs.add(fip_cidr)
   318             new_cidrs.add(fip_cidr)
   286             fixed_cidr = str(fip['fixed_ip_address']) + '/32'
   319             fixed_cidr = str(fip['fixed_ip_address']) + '/32'
   287             nat_rule = 'bimap %s %s -> %s' % (ifname, fixed_cidr, fip_cidr)
   320             nat_rule = 'bimap %s %s -> %s' % (interface_name, fixed_cidr,
       
   321                                               fip_cidr)
   288 
   322 
   289             if fip_cidr not in existing_cidrs:
   323             if fip_cidr not in existing_cidrs:
   290                 try:
   324                 try:
   291                     ipintf.create_address(fip_cidr)
   325                     ipintf.create_address(fip_cidr)
   292                     ri.ipfilters_manager.add_nat_rules([nat_rule])
   326                     self.ipfilters_manager.add_nat_rules([nat_rule])
   293                 except Exception as err:
   327                 except Exception as err:
   294                     # TODO(gmoodalb): If we fail in add_nat_rules(), then
   328                     # TODO(gmoodalb): If we fail in add_nat_rules(), then
   295                     # we need to remove the fip_cidr address
   329                     # we need to remove the fip_cidr address
   296 
   330 
   297                     # any exception occurred here should cause the floating IP
   331                     # any exception occurred here should cause the floating IP
   301                     LOG.warn(_("Unable to configure IP address for "
   335                     LOG.warn(_("Unable to configure IP address for "
   302                                "floating IP: %s: %s") % (fip['id'], err))
   336                                "floating IP: %s: %s") % (fip['id'], err))
   303                     continue
   337                     continue
   304             fip_statuses[fip['id']] = (
   338             fip_statuses[fip['id']] = (
   305                 l3_constants.FLOATINGIP_STATUS_ACTIVE)
   339                 l3_constants.FLOATINGIP_STATUS_ACTIVE)
       
   340             LOG.debug("Floating ip %(id)s added, status %(status)s",
       
   341                       {'id': fip['id'],
       
   342                        'status': fip_statuses.get(fip['id'])})
       
   343 
   306             new_nat_rules.append(nat_rule)
   344             new_nat_rules.append(nat_rule)
   307 
   345 
   308         # remove all the old NAT rules
   346         # remove all the old NAT rules
   309         old_nat_rules = list(set(existing_nat_rules) - set(new_nat_rules))
   347         old_nat_rules = list(set(existing_nat_rules) - set(new_nat_rules))
   310         # Filter out 'bimap' NAT rules as we don't want to remove NAT rules
   348         # Filter out 'bimap' NAT rules as we don't want to remove NAT rules
   311         # that were added for Metadata server
   349         # that were added for Metadata server
   312         old_nat_rules = [rule for rule in old_nat_rules if "bimap" in rule]
   350         old_nat_rules = [rule for rule in old_nat_rules if "bimap" in rule]
   313         ri.ipfilters_manager.remove_nat_rules(old_nat_rules)
   351         self.ipfilters_manager.remove_nat_rules(old_nat_rules)
   314 
   352 
   315         # Clean up addresses that no longer belong on the gateway interface.
   353         # Clean up addresses that no longer belong on the gateway interface.
   316         for ip_cidr in existing_cidrs - new_cidrs:
   354         for ip_cidr in existing_cidrs - new_cidrs:
   317             if ip_cidr.endswith(FLOATING_IP_CIDR_SUFFIX):
   355             if ip_cidr.endswith(FLOATING_IP_CIDR_SUFFIX):
   318                 ipintf.delete_address(ip_cidr)
   356                 ipintf.delete_address(ip_cidr)
   319         return fip_statuses
   357         return fip_statuses
   320 
   358 
   321     def get_internal_device_name(self, port_id):
   359     # Todo(gmoodalb): need to do more work on ipv6 gateway
   322         # Because of the way how dnsmasq works on Solaris, the length
   360     def external_gateway_added(self, ex_gw_port, external_dlname):
   323         # of datalink name cannot exceed 16 (includes terminating nul
       
   324         # character). So, the linkname can only have 15 characters and
       
   325         # the last two characters are set aside for '_0'. So, we only
       
   326         # have 13 characters left.
       
   327         dname = (INTERNAL_DEV_PREFIX + port_id)[:13]
       
   328         dname += '_0'
       
   329         return dname.replace('-', '_')
       
   330 
       
   331     def get_external_device_name(self, port_id):
       
   332         # please see the comment above
       
   333         dname = (EXTERNAL_DEV_PREFIX + port_id)[:13]
       
   334         dname += '_0'
       
   335         return dname.replace('-', '_')
       
   336 
       
   337     def external_gateway_added(self, ri, ex_gw_port, external_dlname):
       
   338 
   361 
   339         if not net_lib.Datalink.datalink_exists(external_dlname):
   362         if not net_lib.Datalink.datalink_exists(external_dlname):
   340             dl = net_lib.Datalink(external_dlname)
   363             dl = net_lib.Datalink(external_dlname)
   341             # determine the network type of the external network
   364             # determine the network type of the external network
   342             evsname = ex_gw_port['network_id']
   365             evsname = ex_gw_port['network_id']
   355                 LOG.error(_("External network should be either Flat or "
   378                 LOG.error(_("External network should be either Flat or "
   356                             "VLAN based, and it is required to "
   379                             "VLAN based, and it is required to "
   357                             "create an external gateway port"))
   380                             "create an external gateway port"))
   358                 return
   381                 return
   359             elif (l2type == 'vlan' and
   382             elif (l2type == 'vlan' and
   360                   self.conf.get("external_network_datalink", None)):
   383                   self.agent_conf.get("external_network_datalink", None)):
   361                 LOG.warning(_("external_network_datalink is deprecated in "
   384                 LOG.warning(_("external_network_datalink is deprecated in "
   362                               "Juno and will be removed in the next release "
   385                               "Juno and will be removed in the next release "
   363                               "of Solaris OpenStack. Please use the evsadm "
   386                               "of Solaris OpenStack. Please use the evsadm "
   364                               "set-controlprop subcommand to setup the "
   387                               "set-controlprop subcommand to setup the "
   365                               "uplink-port for an external network"))
   388                               "uplink-port for an external network"))
   366                 # proceed with the old-style of doing things
   389                 # proceed with the old-style of doing things
   367                 mac_address = ex_gw_port['mac_address']
   390                 mac_address = ex_gw_port['mac_address']
   368                 dl.create_vnic(self.conf.external_network_datalink,
   391                 dl.create_vnic(self.agent_conf.external_network_datalink,
   369                                mac_address=mac_address, vid=vid)
   392                                mac_address=mac_address, vid=vid)
   370             else:
   393             else:
   371                 # This is to handle HA by Solaris Cluster and is similar to
   394                 self.driver.plug(ex_gw_port['tenant_id'],
   372                 # the code we already have for the DHCP Agent. So, when
   395                                  ex_gw_port['network_id'],
   373                 # the 1st L3 agent is down and the second L3 agent tries to
   396                                  ex_gw_port['id'], external_dlname)
   374                 # connect its VNIC to EVS, we will end up in "vport in use"
   397 
   375                 # error. So, we need to reset the vport before we connect
   398         ip_cidrs = common_utils.fixed_ip_cidrs(ex_gw_port['fixed_ips'])
   376                 # the VNIC to EVS.
   399         self.driver.init_l3(external_dlname, ip_cidrs)
   377                 cmd = ['/usr/sbin/evsadm', 'show-vport', '-f',
   400 
   378                        'vport=%s' % ex_gw_port['id'], '-co',
   401         gw_ip = ex_gw_port['subnets'][0]['gateway_ip']
   379                        'evs,vport,status']
       
   380                 stdout = utils.execute(cmd)
       
   381                 evsname, vportname, status = stdout.strip().split(':')
       
   382                 tenant_id = ex_gw_port['tenant_id']
       
   383                 if status == 'used':
       
   384                     cmd = ['/usr/sbin/evsadm', 'reset-vport', '-T', tenant_id,
       
   385                            '%s/%s' % (evsname, vportname)]
       
   386                     utils.execute(cmd)
       
   387 
       
   388                 # next remove protection setting on the VPort to allow
       
   389                 # multiple floating IPs to be configured on the l3e*
       
   390                 # interface
       
   391                 evsvport = "%s/%s" % (ex_gw_port['network_id'],
       
   392                                       ex_gw_port['id'])
       
   393                 cmd = ['/usr/sbin/evsadm', 'set-vportprop', '-T',
       
   394                        tenant_id, '-p', 'protection=none', evsvport]
       
   395                 utils.execute(cmd)
       
   396                 dl.connect_vnic(evsvport, tenant_id)
       
   397 
       
   398         self.driver.init_l3(external_dlname, [ex_gw_port['ip_cidr']])
       
   399 
       
   400         # TODO(gmoodalb): wrap route(1m) command within a class in net_lib.py
       
   401         gw_ip = ex_gw_port['subnet']['gateway_ip']
       
   402         if gw_ip:
   402         if gw_ip:
   403             cmd = ['/usr/bin/pfexec', '/usr/sbin/route', 'add', 'default',
   403             cmd = ['/usr/bin/pfexec', '/usr/sbin/route', 'add', 'default',
   404                    gw_ip]
   404                    gw_ip]
   405             stdout = utils.execute(cmd, extra_ok_codes=[errno.EEXIST])
   405             stdout = utils.execute(cmd, extra_ok_codes=[errno.EEXIST])
   406             ri.remove_route = True
   406             if 'entry exists' not in stdout:
   407             if 'entry exists' in stdout:
   407                 self.remove_route = True
   408                 ri.remove_route = False
       
   409 
   408 
   410             # for each of the internal ports, add Policy Based
   409             # for each of the internal ports, add Policy Based
   411             # Routing (PBR) rule
   410             # Routing (PBR) rule
   412             for port in ri.internal_ports:
   411             for port in self.internal_ports:
   413                 internal_dlname = self.get_internal_device_name(port['id'])
   412                 internal_dlname = self.get_internal_device_name(port['id'])
   414                 rules = ['pass in on %s to %s:%s from any to !%s' %
   413                 rules = ['pass in on %s to %s:%s from any to !%s' %
   415                          (internal_dlname, external_dlname, gw_ip,
   414                          (internal_dlname, external_dlname, gw_ip,
   416                           port['subnet']['cidr'])]
   415                           port['subnets'][0]['cidr'])]
   417                 ipversion = netaddr.IPNetwork(port['subnet']['cidr']).version
   416                 ipversion = \
   418                 ri.ipfilters_manager.add_ipf_rules(rules, ipversion)
   417                     netaddr.IPNetwork(port['subnets'][0]['cidr']).version
   419 
   418                 self.ipfilters_manager.add_ipf_rules(rules, ipversion)
   420     def external_gateway_updated(self, ri, ex_gw_port, external_dlname):
   419 
       
   420     def external_gateway_updated(self, ex_gw_port, external_dlname):
   421         # There is nothing to do on Solaris
   421         # There is nothing to do on Solaris
   422         pass
   422         pass
   423 
   423 
   424     def external_gateway_removed(self, ri, ex_gw_port, external_dlname):
   424     def external_gateway_removed(self, ex_gw_port, external_dlname):
   425         gw_ip = ex_gw_port['subnet']['gateway_ip']
   425         gw_ip = ex_gw_port['subnets'][0]['gateway_ip']
   426         if gw_ip:
   426         if gw_ip:
   427             # remove PBR rules
   427             # remove PBR rules
   428             for port in ri.internal_ports:
   428             for port in self.internal_ports:
   429                 internal_dlname = self.get_internal_device_name(port['id'])
   429                 internal_dlname = self.get_internal_device_name(port['id'])
   430                 rules = ['pass in on %s to %s:%s from any to !%s' %
   430                 rules = ['pass in on %s to %s:%s from any to !%s' %
   431                          (internal_dlname, external_dlname, gw_ip,
   431                          (internal_dlname, external_dlname, gw_ip,
   432                           port['subnet']['cidr'])]
   432                           port['subnets'][0]['cidr'])]
   433                 ipversion = netaddr.IPNetwork(port['subnet']['cidr']).version
   433                 ipversion = \
   434                 ri.ipfilters_manager.remove_ipf_rules(rules, ipversion)
   434                     netaddr.IPNetwork(port['subnets'][0]['cidr']).version
   435 
   435                 self.ipfilters_manager.remove_ipf_rules(rules, ipversion)
   436             if ri.remove_route:
   436 
       
   437             if self.remove_route:
   437                 cmd = ['/usr/bin/pfexec', '/usr/sbin/route', 'delete',
   438                 cmd = ['/usr/bin/pfexec', '/usr/sbin/route', 'delete',
   438                        'default', gw_ip]
   439                        'default', gw_ip]
   439                 utils.execute(cmd, check_exit_code=False)
   440                 utils.execute(cmd, check_exit_code=False)
   440 
   441 
   441         if net_lib.Datalink.datalink_exists(external_dlname):
   442         if net_lib.Datalink.datalink_exists(external_dlname):
   442             self.driver.fini_l3(external_dlname)
   443             self.driver.fini_l3(external_dlname)
   443             self.driver.unplug(external_dlname)
   444             self.driver.unplug(external_dlname)
   444 
   445 
   445         # remove the EVS VPort associated with external network
   446     def _process_external_gateway(self, ex_gw_port):
   446         cmd = ['/usr/sbin/evsadm', 'remove-vport',
   447         # TODO(Carl) Refactor to clarify roles of ex_gw_port vs self.ex_gw_port
   447                '-T', ex_gw_port['tenant_id'],
   448         ex_gw_port_id = (ex_gw_port and ex_gw_port['id'] or
   448                '%s/%s' % (ex_gw_port['network_id'], ex_gw_port['id'])]
   449                          self.ex_gw_port and self.ex_gw_port['id'])
       
   450 
       
   451         interface_name = None
       
   452         if ex_gw_port_id:
       
   453             interface_name = self.get_external_device_name(ex_gw_port_id)
       
   454         if ex_gw_port:
       
   455             def _gateway_ports_equal(port1, port2):
       
   456                 def _get_filtered_dict(d, ignore):
       
   457                     return dict((k, v) for k, v in d.iteritems()
       
   458                                 if k not in ignore)
       
   459 
       
   460                 keys_to_ignore = set(['binding:host_id'])
       
   461                 port1_filtered = _get_filtered_dict(port1, keys_to_ignore)
       
   462                 port2_filtered = _get_filtered_dict(port2, keys_to_ignore)
       
   463                 return port1_filtered == port2_filtered
       
   464 
       
   465             if not self.ex_gw_port:
       
   466                 self.external_gateway_added(ex_gw_port, interface_name)
       
   467             elif not _gateway_ports_equal(ex_gw_port, self.ex_gw_port):
       
   468                 self.external_gateway_updated(ex_gw_port, interface_name)
       
   469         elif not ex_gw_port and self.ex_gw_port:
       
   470             self.external_gateway_removed(self.ex_gw_port, interface_name)
       
   471 
       
   472         # Remove any external stale router interfaces (i.e., l3e.. VNICs)
       
   473         existing_devices = self._get_existing_devices()
       
   474         stale_devs = [dev for dev in existing_devices
       
   475                       if dev.startswith(EXTERNAL_DEV_PREFIX) and
       
   476                       dev != interface_name]
       
   477         for stale_dev in stale_devs:
       
   478             LOG.debug(_('Deleting stale external router device: %s'),
       
   479                       stale_dev)
       
   480             self.driver.fini_l3(stale_dev)
       
   481             self.driver.unplug(stale_dev)
       
   482 
       
   483         # Process SNAT rules for external gateway
       
   484         self.perform_snat_action(self._handle_router_snat_rules,
       
   485                                  interface_name)
       
   486 
       
   487     def external_gateway_snat_rules(self, ex_gw_ip, interface_name):
       
   488         rules = []
       
   489         ip_cidrs = []
       
   490         for port in self.internal_ports:
       
   491             if netaddr.IPNetwork(port['subnets'][0]['cidr']).version == 4:
       
   492                 ip_cidrs.extend(common_utils.fixed_ip_cidrs(port['fixed_ips']))
       
   493 
       
   494         for ip_cidr in ip_cidrs:
       
   495             rules.append('map %s %s -> %s/32' %
       
   496                          (interface_name, ip_cidr, ex_gw_ip))
       
   497         return rules
       
   498 
       
   499     def _handle_router_snat_rules(self, ex_gw_port, interface_name, action):
       
   500         # Remove all the old SNAT rules
       
   501         # This is safe because if use_namespaces is set as False
       
   502         # then the agent can only configure one router, otherwise
       
   503         # each router's SNAT rules will be in their own namespace
       
   504 
       
   505         # get only the SNAT rules
       
   506         old_snat_rules = [rule for rule in self.ipfilters_manager.ipv4['nat']
       
   507                           if rule.startswith('map')]
       
   508         self.ipfilters_manager.remove_nat_rules(old_snat_rules)
       
   509 
       
   510         # And add them back if the action is add_rules
       
   511         if action == 'add_rules' and ex_gw_port:
       
   512             # NAT rules are added only if ex_gw_port has an IPv4 address
       
   513             for ip_addr in ex_gw_port['fixed_ips']:
       
   514                 ex_gw_ip = ip_addr['ip_address']
       
   515                 if netaddr.IPAddress(ex_gw_ip).version == 4:
       
   516                     rules = self.external_gateway_snat_rules(ex_gw_ip,
       
   517                                                              interface_name)
       
   518                     self.ipfilters_manager.add_nat_rules(rules)
       
   519                     break
       
   520 
       
   521     def process_external(self, agent):
       
   522         existing_floating_ips = self.floating_ips
   449         try:
   523         try:
   450             utils.execute(cmd)
   524             ex_gw_port = self.get_ex_gw_port()
   451         except Exception as err:
   525             self._process_external_gateway(ex_gw_port)
   452             LOG.error(_("Failed to delete the EVS VPort associated with "
   526             # TODO(Carl) Return after setting existing_floating_ips and
   453                         "external network: %s") % err)
   527             # still call update_fip_statuses?
   454 
   528             if not ex_gw_port:
   455     def _get_ippool_name(self, mac_address, suffix=None):
   529                 return
   456         # Generate a unique-name for ippool(1m) from that last 3
   530 
   457         # bytes of mac-address. It is called pool name, but it is
   531             # Once NAT rules for floating IPs are safely in place
   458         # actually a 32 bit integer
   532             # configure their addresses on the external gateway port
   459         name = mac_address.split(':')[3:]
   533             interface_name = self.get_external_device_name(ex_gw_port['id'])
   460         if suffix:
   534             fip_statuses = self.configure_fip_addresses(interface_name)
   461             name.append(suffix)
   535         except (n_exc.FloatingIpSetupException,
   462         return int("".join(name), 16)
   536                 n_exc.IpTablesApplyException) as e:
   463 
   537                 # All floating IPs must be put in error state
   464     def internal_network_added(self, ri, port):
   538                 LOG.exception(e)
   465         internal_dlname = self.get_internal_device_name(port['id'])
   539                 fip_statuses = self.put_fips_in_error_state()
   466         # driver just returns if datalink and IP interface already exists
   540 
   467         self.driver.plug(port['tenant_id'], port['network_id'], port['id'],
   541         agent.update_fip_statuses(self, existing_floating_ips, fip_statuses)
   468                          internal_dlname)
   542 
   469         self.driver.init_l3(internal_dlname, [port['ip_cidr']])
   543 
   470 
   544 class EVSL3NATAgent(l3_agent.L3NATAgentWithStateReport):
   471         # Since we support shared router model, we need to block the new
   545     OPTS = [
   472         # internal port from reaching other tenant's ports
   546         cfg.StrOpt('external_network_datalink', default='net0',
   473         block_pname = self._get_ippool_name(port['mac_address'])
   547                    help=_("Name of the datalink that connects to "
   474         ri.ipfilters_manager.add_ippool(block_pname, None)
   548                           "an external network.")),
   475         if self.conf.allow_forwarding_between_networks:
   549         cfg.BoolOpt('allow_forwarding_between_networks', default=False,
   476             # If allow_forwarding_between_networks is set, then we need to
   550                     help=_("Allow forwarding of packets between tenant's "
   477             # allow forwarding of packets between same tenant's ports.
   551                            "networks")),
   478             allow_pname = self._get_ippool_name(port['mac_address'], '0')
   552     ]
   479             ri.ipfilters_manager.add_ippool(allow_pname, None)
   553 
   480 
   554     def __init__(self, host, conf=None):
   481         # walk through the other internal ports and retrieve their
   555         cfg.CONF.register_opts(self.OPTS)
   482         # cidrs and at the same time add the new internal port's
   556         cfg.CONF.register_opts(interface.OPTS)
   483         # cidr to them
   557         super(EVSL3NATAgent, self).__init__(host=host, conf=conf)
   484         port_subnet = port['subnet']['cidr']
   558         cfg.CONF.register_opts(neutron_vpnaas.vpn_agent_opts, 'vpnagent')
   485         block_subnets = []
   559         self.service = vpn_service.VPNService(self)
   486         allow_subnets = []
   560         self.device_drivers = self.service.load_device_drivers(host)
   487         for internal_port in ri.internal_ports:
   561 
   488             if internal_port['mac_address'] == port['mac_address']:
   562     def _router_added(self, router_id, router):
   489                 continue
   563         args = []
   490             if (self.conf.allow_forwarding_between_networks and
   564         kwargs = {
   491                     internal_port['tenant_id'] == port['tenant_id']):
   565             'router_id': router_id,
   492                 allow_subnets.append(internal_port['subnet']['cidr'])
   566             'router': router,
   493                 # we need to add the port's subnet to this internal_port's
   567             'use_ipv6': self.use_ipv6,
   494                 # allowed_subnet_pool
   568             'agent_conf': self.conf,
   495                 iport_allow_pname = \
   569             'interface_driver': self.driver,
   496                     self._get_ippool_name(internal_port['mac_address'], '0')
   570         }
   497                 ri.ipfilters_manager.add_ippool(iport_allow_pname,
   571         ri = SolarisRouterInfo(*args, **kwargs)
   498                                                 [port_subnet])
   572         registry.notify(resources.ROUTER, events.BEFORE_CREATE,
   499             else:
   573                         self, router=ri)
   500                 block_subnets.append(internal_port['subnet']['cidr'])
   574 
   501                 iport_block_pname = \
   575         self.router_info[router_id] = ri
   502                     self._get_ippool_name(internal_port['mac_address'])
   576 
   503                 ri.ipfilters_manager.add_ippool(iport_block_pname,
   577         ri.initialize(self.process_monitor)
   504                                                 [port_subnet])
       
   505         # update the new port's pool with other ports' subnet
       
   506         ri.ipfilters_manager.add_ippool(block_pname, block_subnets)
       
   507         if self.conf.allow_forwarding_between_networks:
       
   508             ri.ipfilters_manager.add_ippool(allow_pname, allow_subnets)
       
   509 
       
   510         # now setup the IPF rules
       
   511         rules = ['block in quick on %s from %s to pool/%d' %
       
   512                  (internal_dlname, port_subnet, block_pname)]
       
   513         # pass in packets between networks that belong to same tenant
       
   514         if self.conf.allow_forwarding_between_networks:
       
   515             rules.append('pass in quick on %s from %s to pool/%d' %
       
   516                          (internal_dlname, port_subnet, allow_pname))
       
   517         # if the external gateway is already setup for the shared router,
       
   518         # then we need to add Policy Based Routing (PBR) for this internal
       
   519         # network
       
   520         ex_gw_port = ri.ex_gw_port
       
   521         ex_gw_ip = (ex_gw_port['subnet']['gateway_ip'] if ex_gw_port else None)
       
   522         if ex_gw_ip:
       
   523             external_dlname = self.get_external_device_name(ex_gw_port['id'])
       
   524             rules.append('pass in on %s to %s:%s from any to !%s' %
       
   525                          (internal_dlname, external_dlname, ex_gw_ip,
       
   526                           port_subnet))
       
   527 
       
   528         ipversion = netaddr.IPNetwork(port_subnet).version
       
   529         ri.ipfilters_manager.add_ipf_rules(rules, ipversion)
       
   530 
       
   531         # if metadata proxy is enabled, then add the necessary
       
   532         # IP NAT rules to forward the metadata requests to the
       
   533         # metadata proxy server
       
   534         if self.conf.enable_metadata_proxy and ipversion == 4:
       
   535             # TODO(gmoodalb): when IP Filter allows redirection of packets
       
   536             # to loopback IP address, then we need to add an IPF rule allowing
       
   537             # only packets destined to 127.0.0.1:9697 to
       
   538             # neutron-ns-metadata-proxy server
       
   539             rules = ['rdr %s 169.254.169.254/32 port 80 -> %s port %d tcp' %
       
   540                      (internal_dlname, port['fixed_ips'][0]['ip_address'],
       
   541                       self.conf.metadata_port)]
       
   542             ri.ipfilters_manager.add_nat_rules(rules)
       
   543 
       
   544     def internal_network_removed(self, ri, port):
       
   545         internal_dlname = self.get_internal_device_name(port['id'])
       
   546         port_subnet = port['subnet']['cidr']
       
   547         # remove all the IP filter rules that we added during
       
   548         # internal network addition
       
   549         block_pname = self._get_ippool_name(port['mac_address'])
       
   550         rules = ['block in quick on %s from %s to pool/%d' %
       
   551                  (internal_dlname, port_subnet, block_pname)]
       
   552         if self.conf.allow_forwarding_between_networks:
       
   553             allow_pname = self._get_ippool_name(port['mac_address'], '0')
       
   554             rules.append('pass in quick on %s from %s to pool/%d' %
       
   555                          (internal_dlname, port_subnet, allow_pname))
       
   556 
       
   557         # remove all the IP filter rules that we added during
       
   558         # external network addition
       
   559         ex_gw_port = ri.ex_gw_port
       
   560         ex_gw_ip = (ex_gw_port['subnet']['gateway_ip'] if ex_gw_port else None)
       
   561         if ex_gw_ip:
       
   562             external_dlname = self.get_external_device_name(ex_gw_port['id'])
       
   563             rules.append('pass in on %s to %s:%s from any to !%s' %
       
   564                          (internal_dlname, external_dlname, ex_gw_ip,
       
   565                           port_subnet))
       
   566         ipversion = netaddr.IPNetwork(port['subnet']['cidr']).version
       
   567         ri.ipfilters_manager.remove_ipf_rules(rules, ipversion)
       
   568 
       
   569         # remove the ippool
       
   570         ri.ipfilters_manager.remove_ippool(block_pname, None)
       
   571         if self.conf.allow_forwarding_between_networks:
       
   572             ri.ipfilters_manager.remove_ippool(allow_pname, None)
       
   573 
       
   574         for internal_port in ri.internal_ports:
       
   575             if (self.conf.allow_forwarding_between_networks and
       
   576                     internal_port['tenant_id'] == port['tenant_id']):
       
   577                 iport_allow_pname = \
       
   578                     self._get_ippool_name(internal_port['mac_address'], '0')
       
   579                 ri.ipfilters_manager.remove_ippool(iport_allow_pname,
       
   580                                                    [port_subnet])
       
   581             else:
       
   582                 iport_block_pname = \
       
   583                     self._get_ippool_name(internal_port['mac_address'])
       
   584                 ri.ipfilters_manager.remove_ippool(iport_block_pname,
       
   585                                                    [port_subnet])
       
   586 
       
   587         # if metadata proxy is enabled, then remove the IP NAT rules that
       
   588         # were added while adding the internal network
       
   589         if self.conf.enable_metadata_proxy and ipversion == 4:
       
   590             rules = ['rdr %s 169.254.169.254/32 port 80 -> %s port %d tcp' %
       
   591                      (internal_dlname, port['fixed_ips'][0]['ip_address'],
       
   592                       self.conf.metadata_port)]
       
   593             ri.ipfilters_manager.remove_nat_rules(rules)
       
   594 
       
   595         if net_lib.Datalink.datalink_exists(internal_dlname):
       
   596             self.driver.fini_l3(internal_dlname)
       
   597             self.driver.unplug(internal_dlname)
       
   598 
       
   599         # remove the EVS VPort associated with internal network
       
   600         cmd = ['/usr/sbin/evsadm', 'remove-vport', '-T', port['tenant_id'],
       
   601                '%s/%s' % (port['network_id'], port['id'])]
       
   602         try:
       
   603             utils.execute(cmd)
       
   604         except Exception as err:
       
   605             LOG.error(_("Failed to delete the EVS VPort associated with "
       
   606                         "internal network: %s") % err)
       
   607 
       
   608     def routes_updated(self, ri):
       
   609         pass