Advertisement
Guest User

Untitled

a guest
Aug 31st, 2016
178
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 44.67 KB | None | 0 0
  1. # Copyright (c) 2014 OpenStack Foundation
  2. #
  3. #    Licensed under the Apache License, Version 2.0 (the "License"); you may
  4. #    not use this file except in compliance with the License. You may obtain
  5. #    a copy of the License at
  6. #
  7. #         http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. #    Unless required by applicable law or agreed to in writing, software
  10. #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  11. #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  12. #    License for the specific language governing permissions and limitations
  13. #    under the License.
  14.  
  15. import collections
  16. import netaddr
  17. from oslo_log import log as logging
  18.  
  19. from neutron._i18n import _, _LE, _LW
  20. from neutron.agent.l3 import namespaces
  21. from neutron.agent.linux import ip_lib
  22. from neutron.agent.linux import iptables_manager
  23. from neutron.agent.linux import ra
  24. from neutron.common import constants as l3_constants
  25. from neutron.common import exceptions as n_exc
  26. from neutron.common import ipv6_utils
  27. from neutron.common import utils as common_utils
  28. from neutron.ipam import utils as ipam_utils
  29.  
  30. LOG = logging.getLogger(__name__)
  31. INTERNAL_DEV_PREFIX = namespaces.INTERNAL_DEV_PREFIX
  32. EXTERNAL_DEV_PREFIX = namespaces.EXTERNAL_DEV_PREFIX
  33.  
  34. FLOATINGIP_STATUS_NOCHANGE = object()
  35. ADDRESS_SCOPE_MARK_MASK = "0xffff0000"
  36. ADDRESS_SCOPE_MARK_ID_MIN = 1024
  37. ADDRESS_SCOPE_MARK_ID_MAX = 2048
  38. DEFAULT_ADDRESS_SCOPE = "noscope"
  39.  
  40.  
  41. class RouterInfo(object):
  42.  
  43.     def __init__(self,
  44.                  router_id,
  45.                  router,
  46.                  agent_conf,
  47.                  interface_driver,
  48.                  use_ipv6=False):
  49.         self.router_id = router_id
  50.         self.ex_gw_port = None
  51.         self._snat_enabled = None
  52.         self.internal_ports = []
  53.         self.floating_ips = set()
  54.         # Invoke the setter for establishing initial SNAT action
  55.         self.router = router
  56.         self.use_ipv6 = use_ipv6
  57.         ns = namespaces.RouterNamespace(
  58.             router_id, agent_conf, interface_driver, use_ipv6)
  59.         self.router_namespace = ns
  60.         self.ns_name = ns.name
  61.         self.available_mark_ids = set(range(ADDRESS_SCOPE_MARK_ID_MIN,
  62.                                             ADDRESS_SCOPE_MARK_ID_MAX))
  63.         self._address_scope_to_mark_id = {
  64.             DEFAULT_ADDRESS_SCOPE: self.available_mark_ids.pop()}
  65.         self.iptables_manager = iptables_manager.IptablesManager(
  66.             use_ipv6=use_ipv6,
  67.             namespace=self.ns_name)
  68.         self.routes = []
  69.         self.agent_conf = agent_conf
  70.         self.driver = interface_driver
  71.         # radvd is a neutron.agent.linux.ra.DaemonMonitor
  72.         self.radvd = None
  73.  
  74.     def initialize(self, process_monitor):
  75.         """Initialize the router on the system.
  76.  
  77.        This differs from __init__ in that this method actually affects the
  78.        system creating namespaces, starting processes, etc.  The other merely
  79.        initializes the python object.  This separates in-memory object
  80.        initialization from methods that actually go do stuff to the system.
  81.  
  82.        :param process_monitor: The agent's process monitor instance.
  83.        """
  84.         self.process_monitor = process_monitor
  85.         self.radvd = ra.DaemonMonitor(self.router_id,
  86.                                       self.ns_name,
  87.                                       process_monitor,
  88.                                       self.get_internal_device_name,
  89.                                       self.agent_conf)
  90.  
  91.         self.router_namespace.create()
  92.  
  93.     @property
  94.     def router(self):
  95.         return self._router
  96.  
  97.     @router.setter
  98.     def router(self, value):
  99.         self._router = value
  100.         if not self._router:
  101.             return
  102.         # enable_snat by default if it wasn't specified by plugin
  103.         self._snat_enabled = self._router.get('enable_snat', True)
  104.  
  105.     def get_internal_device_name(self, port_id):
  106.         return (INTERNAL_DEV_PREFIX + port_id)[:self.driver.DEV_NAME_LEN]
  107.  
  108.     def get_external_device_name(self, port_id):
  109.         return (EXTERNAL_DEV_PREFIX + port_id)[:self.driver.DEV_NAME_LEN]
  110.  
  111.     def get_external_device_interface_name(self, ex_gw_port):
  112.         return self.get_external_device_name(ex_gw_port['id'])
  113.  
  114.     def _update_routing_table(self, operation, route, namespace):
  115.         cmd = ['ip', 'route', operation, 'to', route['destination'],
  116.                'via', route['nexthop']]
  117.         ip_wrapper = ip_lib.IPWrapper(namespace=namespace)
  118.         ip_wrapper.netns.execute(cmd, check_exit_code=False)
  119.  
  120.     def update_routing_table(self, operation, route):
  121.         self._update_routing_table(operation, route, self.ns_name)
  122.  
  123.     def routes_updated(self, old_routes, new_routes):
  124.         adds, removes = common_utils.diff_list_of_dict(old_routes,
  125.                                                        new_routes)
  126.         for route in adds:
  127.             LOG.debug("Added route entry is '%s'", route)
  128.             # remove replaced route from deleted route
  129.             for del_route in removes:
  130.                 if route['destination'] == del_route['destination']:
  131.                     removes.remove(del_route)
  132.             #replace success even if there is no existing route
  133.             self.update_routing_table('replace', route)
  134.         for route in removes:
  135.             LOG.debug("Removed route entry is '%s'", route)
  136.             self.update_routing_table('delete', route)
  137.  
  138.     def get_ex_gw_port(self):
  139.         return self.router.get('gw_port')
  140.  
  141.     def get_floating_ips(self):
  142.         """Filter Floating IPs to be hosted on this agent."""
  143.         return self.router.get(l3_constants.FLOATINGIP_KEY, [])
  144.  
  145.     def floating_forward_rules(self, floating_ip, fixed_ip):
  146.         return [('PREROUTING', '-d %s/32 -j DNAT --to-destination %s' %
  147.                  (floating_ip, fixed_ip)),
  148.                 ('OUTPUT', '-d %s/32 -j DNAT --to-destination %s' %
  149.                  (floating_ip, fixed_ip)),
  150.                 ('float-snat', '-s %s/32 -j SNAT --to-source %s' %
  151.                  (fixed_ip, floating_ip))]
  152.  
  153.     def floating_mangle_rules(self, floating_ip, fixed_ip, internal_mark):
  154.         mark_traffic_to_floating_ip = (
  155.             'floatingip', '-d %s -j MARK --set-xmark %s' % (
  156.                 floating_ip, internal_mark))
  157.         mark_traffic_from_fixed_ip = (
  158.             'FORWARD', '-s %s -j $float-snat' % fixed_ip)
  159.         return [mark_traffic_to_floating_ip, mark_traffic_from_fixed_ip]
  160.  
  161.     def get_address_scope_mark_mask(self, address_scope=None):
  162.         if not address_scope:
  163.             address_scope = DEFAULT_ADDRESS_SCOPE
  164.  
  165.         if address_scope not in self._address_scope_to_mark_id:
  166.             self._address_scope_to_mark_id[address_scope] = (
  167.                 self.available_mark_ids.pop())
  168.  
  169.         mark_id = self._address_scope_to_mark_id[address_scope]
  170.         # NOTE: Address scopes use only the upper 16 bits of the 32 fwmark
  171.         return "%s/%s" % (hex(mark_id << 16), ADDRESS_SCOPE_MARK_MASK)
  172.  
  173.     def get_port_address_scope_mark(self, port):
  174.         """Get the IP version 4 and 6 address scope mark for the port
  175.  
  176.        :param port: A port dict from the RPC call
  177.        :returns: A dict mapping the address family to the address scope mark
  178.        """
  179.         port_scopes = port.get('address_scopes', {})
  180.  
  181.         address_scope_mark_masks = (
  182.             (int(k), self.get_address_scope_mark_mask(v))
  183.             for k, v in port_scopes.items())
  184.         return collections.defaultdict(self.get_address_scope_mark_mask,
  185.                                        address_scope_mark_masks)
  186.  
  187.     def process_floating_ip_nat_rules(self):
  188.         """Configure NAT rules for the router's floating IPs.
  189.  
  190.        Configures iptables rules for the floating ips of the given router
  191.        """
  192.         # Clear out all iptables rules for floating ips
  193.         self.iptables_manager.ipv4['nat'].clear_rules_by_tag('floating_ip')
  194.  
  195.         floating_ips = self.get_floating_ips()
  196.         # Loop once to ensure that floating ips are configured.
  197.         for fip in floating_ips:
  198.             # Rebuild iptables rules for the floating ip.
  199.             fixed = fip['fixed_ip_address']
  200.             fip_ip = fip['floating_ip_address']
  201.             for chain, rule in self.floating_forward_rules(fip_ip, fixed):
  202.                 self.iptables_manager.ipv4['nat'].add_rule(chain, rule,
  203.                                                            tag='floating_ip')
  204.  
  205.         self.iptables_manager.apply()
  206.  
  207.     def process_floating_ip_address_scope_rules(self):
  208.         """Configure address scope related iptables rules for the router's
  209.         floating IPs.
  210.        """
  211.  
  212.         # Clear out all iptables rules for floating ips
  213.         self.iptables_manager.ipv4['mangle'].clear_rules_by_tag('floating_ip')
  214.         all_floating_ips = self.get_floating_ips()
  215.         ext_scope = self._get_external_address_scope()
  216.         # Filter out the floating ips that have fixed ip in the same address
  217.         # scope. Because the packets for them will always be in one address
  218.         # scope, no need to manipulate MARK/CONNMARK for them.
  219.         floating_ips = [fip for fip in all_floating_ips
  220.                         if fip.get('fixed_ip_address_scope') != ext_scope]
  221.         if floating_ips:
  222.             ext_scope_mark = self.get_address_scope_mark_mask(ext_scope)
  223.             ports_scopemark = self._get_address_scope_mark()
  224.             devices_in_ext_scope = {
  225.                 device for device, mark
  226.                 in ports_scopemark[l3_constants.IP_VERSION_4].items()
  227.                 if mark == ext_scope_mark}
  228.             # Add address scope for floatingip egress
  229.             for device in devices_in_ext_scope:
  230.                 self.iptables_manager.ipv4['mangle'].add_rule(
  231.                     'float-snat',
  232.                     '-o %s -j MARK --set-xmark %s'
  233.                     % (device, ext_scope_mark),
  234.                     tag='floating_ip')
  235.  
  236.         # Loop once to ensure that floating ips are configured.
  237.         for fip in floating_ips:
  238.             # Rebuild iptables rules for the floating ip.
  239.             fip_ip = fip['floating_ip_address']
  240.             # Send the floating ip traffic to the right address scope
  241.             fixed_ip = fip['fixed_ip_address']
  242.             fixed_scope = fip.get('fixed_ip_address_scope')
  243.             internal_mark = self.get_address_scope_mark_mask(fixed_scope)
  244.             mangle_rules = self.floating_mangle_rules(
  245.                 fip_ip, fixed_ip, internal_mark)
  246.             for chain, rule in mangle_rules:
  247.                 self.iptables_manager.ipv4['mangle'].add_rule(
  248.                     chain, rule, tag='floating_ip')
  249.  
  250.     def process_snat_dnat_for_fip(self):
  251.         try:
  252.             self.process_floating_ip_nat_rules()
  253.         except Exception:
  254.             # TODO(salv-orlando): Less broad catching
  255.             msg = _('L3 agent failure to setup NAT for floating IPs')
  256.             LOG.exception(msg)
  257.             raise n_exc.FloatingIpSetupException(msg)
  258.  
  259.     def _add_fip_addr_to_device(self, fip, device):
  260.         """Configures the floating ip address on the device.
  261.        """
  262.         try:
  263.             ip_cidr = common_utils.ip_to_cidr(fip['floating_ip_address'])
  264.             device.addr.add(ip_cidr)
  265.             return True
  266.         except RuntimeError:
  267.             # any exception occurred here should cause the floating IP
  268.             # to be set in error state
  269.             LOG.warning(_LW("Unable to configure IP address for "
  270.                             "floating IP: %s"), fip['id'])
  271.  
  272.     def add_floating_ip(self, fip, interface_name, device):
  273.         raise NotImplementedError()
  274.  
  275.     def remove_floating_ip(self, device, ip_cidr):
  276.         device.delete_addr_and_conntrack_state(ip_cidr)
  277.  
  278.     def remove_external_gateway_ip(self, device, ip_cidr):
  279.         device.delete_addr_and_conntrack_state(ip_cidr)
  280.  
  281.     def get_router_cidrs(self, device):
  282.         return set([addr['cidr'] for addr in device.addr.list()])
  283.  
  284.     def process_floating_ip_addresses(self, interface_name):
  285.         """Configure IP addresses on router's external gateway interface.
  286.  
  287.        Ensures addresses for existing floating IPs and cleans up
  288.        those that should not longer be configured.
  289.        """
  290.  
  291.         fip_statuses = {}
  292.         if interface_name is None:
  293.             LOG.debug('No Interface for floating IPs router: %s',
  294.                       self.router['id'])
  295.             return fip_statuses
  296.  
  297.         device = ip_lib.IPDevice(interface_name, namespace=self.ns_name)
  298.         existing_cidrs = self.get_router_cidrs(device)
  299.         new_cidrs = set()
  300.  
  301.         floating_ips = self.get_floating_ips()
  302.         # Loop once to ensure that floating ips are configured.
  303.         for fip in floating_ips:
  304.             fip_ip = fip['floating_ip_address']
  305.             ip_cidr = common_utils.ip_to_cidr(fip_ip)
  306.             new_cidrs.add(ip_cidr)
  307.             fip_statuses[fip['id']] = l3_constants.FLOATINGIP_STATUS_ACTIVE
  308.             if ip_cidr not in existing_cidrs:
  309.                 fip_statuses[fip['id']] = self.add_floating_ip(
  310.                     fip, interface_name, device)
  311.                 LOG.debug('Floating ip %(id)s added, status %(status)s',
  312.                           {'id': fip['id'],
  313.                            'status': fip_statuses.get(fip['id'])})
  314.             elif fip_statuses[fip['id']] == fip['status']:
  315.                 # mark the status as not changed. we can't remove it because
  316.                 # that's how the caller determines that it was removed
  317.             fip_statuses[fip['id']] = FLOATINGIP_STATUS_NOCHANGE
  318.             # If the floating IP is configured on this host,
  319.                 # we make sure the network switch knows about that
  320.                 # using a GARP
  321.                 try:
  322.                     # Therefore we first check if the floating IP is active
  323.                     # on this host
  324.                     LOG.info('Checking if alive on this host: %s',fip_ip)
  325.  
  326.                     fip_ns_name = self.fip_ns.get_name()
  327.                     interface_name = (
  328.                         self.fip_ns.get_ext_device_name(
  329.                             self.fip_ns.agent_gateway_port['id']))
  330.  
  331.                     ip_lib.IPWrapper(fip_ns_name).netns.execute(['arping', '-c', '3', '-w', '3', '-I', interface_name, fip_ip])
  332.  
  333.                     # If yes, we send out a GARP
  334.                     LOG.info('Sending GARP for: %s',fip_ip)
  335.                     ip_lib.send_ip_addr_adv_notif(fip_ns_name,
  336.                                                   interface_name,
  337.                                                   fip_ip,
  338.                                                   self.agent_conf)
  339.                 except RuntimeError:
  340.                     # If not, the floating IP might be migrated to another host
  341.                 # Do nothing
  342.         fips_to_remove = (
  343.             ip_cidr for ip_cidr in existing_cidrs - new_cidrs
  344.             if common_utils.is_cidr_host(ip_cidr))
  345.         for ip_cidr in fips_to_remove:
  346.             LOG.debug("Removing floating ip %s from interface %s in "
  347.                       "namespace %s", ip_cidr, interface_name, self.ns_name)
  348.             self.remove_floating_ip(device, ip_cidr)
  349.  
  350.         return fip_statuses
  351.  
  352.     def configure_fip_addresses(self, interface_name):
  353.         try:
  354.             return self.process_floating_ip_addresses(interface_name)
  355.         except Exception:
  356.             # TODO(salv-orlando): Less broad catching
  357.             msg = _('L3 agent failure to setup floating IPs')
  358.             LOG.exception(msg)
  359.             raise n_exc.FloatingIpSetupException(msg)
  360.  
  361.     def put_fips_in_error_state(self):
  362.         fip_statuses = {}
  363.         for fip in self.router.get(l3_constants.FLOATINGIP_KEY, []):
  364.             fip_statuses[fip['id']] = l3_constants.FLOATINGIP_STATUS_ERROR
  365.         return fip_statuses
  366.  
  367.     def delete(self, agent):
  368.         self.router['gw_port'] = None
  369.         self.router[l3_constants.INTERFACE_KEY] = []
  370.         self.router[l3_constants.FLOATINGIP_KEY] = []
  371.         self.process_delete(agent)
  372.         self.disable_radvd()
  373.         self.router_namespace.delete()
  374.  
  375.     def _internal_network_updated(self, port, subnet_id, prefix, old_prefix,
  376.                                   updated_cidrs):
  377.         interface_name = self.get_internal_device_name(port['id'])
  378.         if prefix != l3_constants.PROVISIONAL_IPV6_PD_PREFIX:
  379.             fixed_ips = port['fixed_ips']
  380.             for fixed_ip in fixed_ips:
  381.                 if fixed_ip['subnet_id'] == subnet_id:
  382.                     v6addr = common_utils.ip_to_cidr(fixed_ip['ip_address'],
  383.                                                      fixed_ip.get('prefixlen'))
  384.                     if v6addr not in updated_cidrs:
  385.                         self.driver.add_ipv6_addr(interface_name, v6addr,
  386.                                                   self.ns_name)
  387.         else:
  388.             self.driver.delete_ipv6_addr_with_prefix(interface_name,
  389.                                                      old_prefix,
  390.                                                      self.ns_name)
  391.  
  392.     def _internal_network_added(self, ns_name, network_id, port_id,
  393.                                 fixed_ips, mac_address,
  394.                                 interface_name, prefix, mtu=None):
  395.         LOG.debug("adding internal network: prefix(%s), port(%s)",
  396.                   prefix, port_id)
  397.         self.driver.plug(network_id, port_id, interface_name, mac_address,
  398.                          namespace=ns_name,
  399.                          prefix=prefix, mtu=mtu)
  400.  
  401.         ip_cidrs = common_utils.fixed_ip_cidrs(fixed_ips)
  402.         self.driver.init_router_port(
  403.             interface_name, ip_cidrs, namespace=ns_name)
  404.         for fixed_ip in fixed_ips:
  405.             ip_lib.send_ip_addr_adv_notif(ns_name,
  406.                                           interface_name,
  407.                                           fixed_ip['ip_address'],
  408.                                           self.agent_conf)
  409.  
  410.     def internal_network_added(self, port):
  411.         network_id = port['network_id']
  412.         port_id = port['id']
  413.         fixed_ips = port['fixed_ips']
  414.         mac_address = port['mac_address']
  415.  
  416.         interface_name = self.get_internal_device_name(port_id)
  417.  
  418.         self._internal_network_added(self.ns_name,
  419.                                      network_id,
  420.                                      port_id,
  421.                                      fixed_ips,
  422.                                      mac_address,
  423.                                      interface_name,
  424.                                      INTERNAL_DEV_PREFIX,
  425.                                      mtu=port.get('mtu'))
  426.  
  427.     def internal_network_removed(self, port):
  428.         interface_name = self.get_internal_device_name(port['id'])
  429.         LOG.debug("removing internal network: port(%s) interface(%s)",
  430.                   port['id'], interface_name)
  431.         if ip_lib.device_exists(interface_name, namespace=self.ns_name):
  432.             self.driver.unplug(interface_name, namespace=self.ns_name,
  433.                                prefix=INTERNAL_DEV_PREFIX)
  434.  
  435.     def _get_existing_devices(self):
  436.         ip_wrapper = ip_lib.IPWrapper(namespace=self.ns_name)
  437.         ip_devs = ip_wrapper.get_devices(exclude_loopback=True)
  438.         return [ip_dev.name for ip_dev in ip_devs]
  439.  
  440.     @staticmethod
  441.     def _get_updated_ports(existing_ports, current_ports):
  442.         updated_ports = dict()
  443.         current_ports_dict = {p['id']: p for p in current_ports}
  444.         for existing_port in existing_ports:
  445.             current_port = current_ports_dict.get(existing_port['id'])
  446.             if current_port:
  447.                 if (sorted(existing_port['fixed_ips'],
  448.                            key=common_utils.safe_sort_key) !=
  449.                         sorted(current_port['fixed_ips'],
  450.                                key=common_utils.safe_sort_key)):
  451.                     updated_ports[current_port['id']] = current_port
  452.         return updated_ports
  453.  
  454.     @staticmethod
  455.     def _port_has_ipv6_subnet(port):
  456.         if 'subnets' in port:
  457.             for subnet in port['subnets']:
  458.                 if (netaddr.IPNetwork(subnet['cidr']).version == 6 and
  459.                     subnet['cidr'] != l3_constants.PROVISIONAL_IPV6_PD_PREFIX):
  460.                     return True
  461.  
  462.     def enable_radvd(self, internal_ports=None):
  463.         LOG.debug('Spawning radvd daemon in router device: %s', self.router_id)
  464.         if not internal_ports:
  465.             internal_ports = self.internal_ports
  466.         self.radvd.enable(internal_ports)
  467.  
  468.     def disable_radvd(self):
  469.         LOG.debug('Terminating radvd daemon in router device: %s',
  470.                   self.router_id)
  471.         self.radvd.disable()
  472.  
  473.     def internal_network_updated(self, interface_name, ip_cidrs):
  474.         self.driver.init_router_port(
  475.             interface_name,
  476.             ip_cidrs=ip_cidrs,
  477.             namespace=self.ns_name)
  478.  
  479.     def address_scope_mangle_rule(self, device_name, mark_mask):
  480.         return '-i %s -j MARK --set-xmark %s' % (device_name, mark_mask)
  481.  
  482.     def address_scope_filter_rule(self, device_name, mark_mask):
  483.         return '-o %s -m mark ! --mark %s -j DROP' % (
  484.             device_name, mark_mask)
  485.  
  486.     def _process_internal_ports(self, pd):
  487.         existing_port_ids = set(p['id'] for p in self.internal_ports)
  488.  
  489.         internal_ports = self.router.get(l3_constants.INTERFACE_KEY, [])
  490.         current_port_ids = set(p['id'] for p in internal_ports
  491.                                if p['admin_state_up'])
  492.  
  493.         new_port_ids = current_port_ids - existing_port_ids
  494.         new_ports = [p for p in internal_ports if p['id'] in new_port_ids]
  495.         old_ports = [p for p in self.internal_ports
  496.                      if p['id'] not in current_port_ids]
  497.         updated_ports = self._get_updated_ports(self.internal_ports,
  498.                                                 internal_ports)
  499.  
  500.         enable_ra = False
  501.         for p in new_ports:
  502.             self.internal_network_added(p)
  503.             LOG.debug("appending port %s to internal_ports cache", p)
  504.             self.internal_ports.append(p)
  505.             enable_ra = enable_ra or self._port_has_ipv6_subnet(p)
  506.             for subnet in p['subnets']:
  507.                 if ipv6_utils.is_ipv6_pd_enabled(subnet):
  508.                     interface_name = self.get_internal_device_name(p['id'])
  509.                     pd.enable_subnet(self.router_id, subnet['id'],
  510.                                      subnet['cidr'],
  511.                                      interface_name, p['mac_address'])
  512.  
  513.         for p in old_ports:
  514.             self.internal_network_removed(p)
  515.             LOG.debug("removing port %s from internal_ports cache", p)
  516.             self.internal_ports.remove(p)
  517.             enable_ra = enable_ra or self._port_has_ipv6_subnet(p)
  518.             for subnet in p['subnets']:
  519.                 if ipv6_utils.is_ipv6_pd_enabled(subnet):
  520.                     pd.disable_subnet(self.router_id, subnet['id'])
  521.  
  522.         updated_cidrs = []
  523.         if updated_ports:
  524.             for index, p in enumerate(internal_ports):
  525.                 if not updated_ports.get(p['id']):
  526.                     continue
  527.                 self.internal_ports[index] = updated_ports[p['id']]
  528.                 interface_name = self.get_internal_device_name(p['id'])
  529.                 ip_cidrs = common_utils.fixed_ip_cidrs(p['fixed_ips'])
  530.                 LOG.debug("updating internal network for port %s", p)
  531.                 updated_cidrs += ip_cidrs
  532.                 self.internal_network_updated(interface_name, ip_cidrs)
  533.                 enable_ra = enable_ra or self._port_has_ipv6_subnet(p)
  534.  
  535.         # Check if there is any pd prefix update
  536.         for p in internal_ports:
  537.             if p['id'] in (set(current_port_ids) & set(existing_port_ids)):
  538.                 for subnet in p.get('subnets', []):
  539.                     if ipv6_utils.is_ipv6_pd_enabled(subnet):
  540.                         old_prefix = pd.update_subnet(self.router_id,
  541.                                                       subnet['id'],
  542.                                                       subnet['cidr'])
  543.                         if old_prefix:
  544.                             self._internal_network_updated(p, subnet['id'],
  545.                                                            subnet['cidr'],
  546.                                                            old_prefix,
  547.                                                            updated_cidrs)
  548.                             enable_ra = True
  549.  
  550.         # Enable RA
  551.         if enable_ra:
  552.             self.enable_radvd(internal_ports)
  553.  
  554.         existing_devices = self._get_existing_devices()
  555.         current_internal_devs = set(n for n in existing_devices
  556.                                     if n.startswith(INTERNAL_DEV_PREFIX))
  557.         current_port_devs = set(self.get_internal_device_name(port_id)
  558.                                 for port_id in current_port_ids)
  559.         stale_devs = current_internal_devs - current_port_devs
  560.         for stale_dev in stale_devs:
  561.             LOG.debug('Deleting stale internal router device: %s',
  562.                       stale_dev)
  563.             pd.remove_stale_ri_ifname(self.router_id, stale_dev)
  564.             self.driver.unplug(stale_dev,
  565.                                namespace=self.ns_name,
  566.                                prefix=INTERNAL_DEV_PREFIX)
  567.  
  568.     def _list_floating_ip_cidrs(self):
  569.         # Compute a list of addresses this router is supposed to have.
  570.         # This avoids unnecessarily removing those addresses and
  571.         # causing a momentarily network outage.
  572.         floating_ips = self.get_floating_ips()
  573.         return [common_utils.ip_to_cidr(ip['floating_ip_address'])
  574.                 for ip in floating_ips]
  575.  
  576.     def _plug_external_gateway(self, ex_gw_port, interface_name, ns_name):
  577.         self.driver.plug(ex_gw_port['network_id'],
  578.                          ex_gw_port['id'],
  579.                          interface_name,
  580.                          ex_gw_port['mac_address'],
  581.                          bridge=self.agent_conf.external_network_bridge,
  582.                          namespace=ns_name,
  583.                          prefix=EXTERNAL_DEV_PREFIX,
  584.                          mtu=ex_gw_port.get('mtu'))
  585.  
  586.     def _get_external_gw_ips(self, ex_gw_port):
  587.         gateway_ips = []
  588.         if 'subnets' in ex_gw_port:
  589.             gateway_ips = [subnet['gateway_ip']
  590.                            for subnet in ex_gw_port['subnets']
  591.                            if subnet['gateway_ip']]
  592.         if self.use_ipv6 and not self.is_v6_gateway_set(gateway_ips):
  593.             # No IPv6 gateway is available, but IPv6 is enabled.
  594.             if self.agent_conf.ipv6_gateway:
  595.                 # ipv6_gateway configured, use address for default route.
  596.                 gateway_ips.append(self.agent_conf.ipv6_gateway)
  597.         return gateway_ips
  598.  
  599.     def _add_route_to_gw(self, ex_gw_port, device_name,
  600.                          namespace, preserve_ips):
  601.         # Note: ipv6_gateway is an ipv6 LLA
  602.         # and so doesn't need a special route
  603.         for subnet in ex_gw_port.get('subnets', []):
  604.             is_gateway_not_in_subnet = (subnet['gateway_ip'] and
  605.                                         not ipam_utils.check_subnet_ip(
  606.                                                 subnet['cidr'],
  607.                                                 subnet['gateway_ip']))
  608.             if is_gateway_not_in_subnet:
  609.                 preserve_ips.append(subnet['gateway_ip'])
  610.                 device = ip_lib.IPDevice(device_name, namespace=namespace)
  611.                 device.route.add_route(subnet['gateway_ip'], scope='link')
  612.  
  613.     def _external_gateway_added(self, ex_gw_port, interface_name,
  614.                                 ns_name, preserve_ips):
  615.         LOG.debug("External gateway added: port(%s), interface(%s), ns(%s)",
  616.                   ex_gw_port, interface_name, ns_name)
  617.         self._plug_external_gateway(ex_gw_port, interface_name, ns_name)
  618.  
  619.         # Build up the interface and gateway IP addresses that
  620.         # will be added to the interface.
  621.         ip_cidrs = common_utils.fixed_ip_cidrs(ex_gw_port['fixed_ips'])
  622.  
  623.         gateway_ips = self._get_external_gw_ips(ex_gw_port)
  624.         enable_ra_on_gw = False
  625.         if self.use_ipv6 and not self.is_v6_gateway_set(gateway_ips):
  626.             # There is no IPv6 gw_ip, use RouterAdvt for default route.
  627.             enable_ra_on_gw = True
  628.  
  629.         self._add_route_to_gw(ex_gw_port, device_name=interface_name,
  630.                               namespace=ns_name, preserve_ips=preserve_ips)
  631.         self.driver.init_router_port(
  632.             interface_name,
  633.             ip_cidrs,
  634.             namespace=ns_name,
  635.             extra_subnets=ex_gw_port.get('extra_subnets', []),
  636.             preserve_ips=preserve_ips,
  637.             clean_connections=True)
  638.  
  639.         device = ip_lib.IPDevice(interface_name, namespace=ns_name)
  640.         for ip in gateway_ips or []:
  641.             device.route.add_gateway(ip)
  642.  
  643.         if enable_ra_on_gw:
  644.             self.driver.configure_ipv6_ra(ns_name, interface_name)
  645.  
  646.         for fixed_ip in ex_gw_port['fixed_ips']:
  647.             ip_lib.send_ip_addr_adv_notif(ns_name,
  648.                                           interface_name,
  649.                                           fixed_ip['ip_address'],
  650.                                           self.agent_conf)
  651.  
  652.     def is_v6_gateway_set(self, gateway_ips):
  653.         """Check to see if list of gateway_ips has an IPv6 gateway.
  654.        """
  655.         # Note - don't require a try-except here as all
  656.         # gateway_ips elements are valid addresses, if they exist.
  657.         return any(netaddr.IPAddress(gw_ip).version == 6
  658.                    for gw_ip in gateway_ips)
  659.  
  660.     def external_gateway_added(self, ex_gw_port, interface_name):
  661.         preserve_ips = self._list_floating_ip_cidrs()
  662.         self._external_gateway_added(
  663.             ex_gw_port, interface_name, self.ns_name, preserve_ips)
  664.  
  665.     def external_gateway_updated(self, ex_gw_port, interface_name):
  666.         preserve_ips = self._list_floating_ip_cidrs()
  667.         self._external_gateway_added(
  668.             ex_gw_port, interface_name, self.ns_name, preserve_ips)
  669.  
  670.     def external_gateway_removed(self, ex_gw_port, interface_name):
  671.         LOG.debug("External gateway removed: port(%s), interface(%s)",
  672.                   ex_gw_port, interface_name)
  673.         device = ip_lib.IPDevice(interface_name, namespace=self.ns_name)
  674.         for ip_addr in ex_gw_port['fixed_ips']:
  675.             self.remove_external_gateway_ip(device,
  676.                                             common_utils.ip_to_cidr(
  677.                                                 ip_addr['ip_address'],
  678.                                                 ip_addr['prefixlen']))
  679.         self.driver.unplug(interface_name,
  680.                            bridge=self.agent_conf.external_network_bridge,
  681.                            namespace=self.ns_name,
  682.                            prefix=EXTERNAL_DEV_PREFIX)
  683.  
  684.     @staticmethod
  685.     def _gateway_ports_equal(port1, port2):
  686.         return port1 == port2
  687.  
  688.     def _process_external_gateway(self, ex_gw_port, pd):
  689.         # TODO(Carl) Refactor to clarify roles of ex_gw_port vs self.ex_gw_port
  690.         ex_gw_port_id = (ex_gw_port and ex_gw_port['id'] or
  691.                          self.ex_gw_port and self.ex_gw_port['id'])
  692.  
  693.         interface_name = None
  694.         if ex_gw_port_id:
  695.             interface_name = self.get_external_device_name(ex_gw_port_id)
  696.         if ex_gw_port:
  697.             if not self.ex_gw_port:
  698.                 self.external_gateway_added(ex_gw_port, interface_name)
  699.                 pd.add_gw_interface(self.router['id'], interface_name)
  700.             elif not self._gateway_ports_equal(ex_gw_port, self.ex_gw_port):
  701.                 self.external_gateway_updated(ex_gw_port, interface_name)
  702.         elif not ex_gw_port and self.ex_gw_port:
  703.             self.external_gateway_removed(self.ex_gw_port, interface_name)
  704.             pd.remove_gw_interface(self.router['id'])
  705.  
  706.         existing_devices = self._get_existing_devices()
  707.         stale_devs = [dev for dev in existing_devices
  708.                       if dev.startswith(EXTERNAL_DEV_PREFIX)
  709.                       and dev != interface_name]
  710.         for stale_dev in stale_devs:
  711.             LOG.debug('Deleting stale external router device: %s', stale_dev)
  712.             pd.remove_gw_interface(self.router['id'])
  713.             self.driver.unplug(stale_dev,
  714.                                bridge=self.agent_conf.external_network_bridge,
  715.                                namespace=self.ns_name,
  716.                                prefix=EXTERNAL_DEV_PREFIX)
  717.  
  718.         # Process SNAT rules for external gateway
  719.         gw_port = self._router.get('gw_port')
  720.         self._handle_router_snat_rules(gw_port, interface_name)
  721.  
  722.     def external_gateway_nat_fip_rules(self, ex_gw_ip, interface_name):
  723.         dont_snat_traffic_to_internal_ports_if_not_to_floating_ip = (
  724.             'POSTROUTING', '! -i %(interface_name)s '
  725.                            '! -o %(interface_name)s -m conntrack ! '
  726.                            '--ctstate DNAT -j ACCEPT' %
  727.                            {'interface_name': interface_name})
  728.         # Makes replies come back through the router to reverse DNAT
  729.         ext_in_mark = self.agent_conf.external_ingress_mark
  730.         snat_internal_traffic_to_floating_ip = (
  731.             'snat', '-m mark ! --mark %s/%s '
  732.                     '-m conntrack --ctstate DNAT '
  733.                     '-j SNAT --to-source %s'
  734.                     % (ext_in_mark, l3_constants.ROUTER_MARK_MASK, ex_gw_ip))
  735.         return [dont_snat_traffic_to_internal_ports_if_not_to_floating_ip,
  736.                 snat_internal_traffic_to_floating_ip]
  737.  
  738.     def external_gateway_nat_snat_rules(self, ex_gw_ip, interface_name):
  739.         snat_normal_external_traffic = (
  740.             'snat', '-o %s -j SNAT --to-source %s' %
  741.                     (interface_name, ex_gw_ip))
  742.         return [snat_normal_external_traffic]
  743.  
  744.     def external_gateway_mangle_rules(self, interface_name):
  745.         mark = self.agent_conf.external_ingress_mark
  746.         mark_packets_entering_external_gateway_port = (
  747.             'mark', '-i %s -j MARK --set-xmark %s/%s' %
  748.                     (interface_name, mark, l3_constants.ROUTER_MARK_MASK))
  749.         return [mark_packets_entering_external_gateway_port]
  750.  
  751.     def _empty_snat_chains(self, iptables_manager):
  752.         iptables_manager.ipv4['nat'].empty_chain('POSTROUTING')
  753.         iptables_manager.ipv4['nat'].empty_chain('snat')
  754.         iptables_manager.ipv4['mangle'].empty_chain('mark')
  755.         iptables_manager.ipv4['mangle'].empty_chain('POSTROUTING')
  756.  
  757.     def _add_snat_rules(self, ex_gw_port, iptables_manager,
  758.                         interface_name):
  759.         self.process_external_port_address_scope_routing(iptables_manager)
  760.  
  761.         if ex_gw_port:
  762.             # ex_gw_port should not be None in this case
  763.             # NAT rules are added only if ex_gw_port has an IPv4 address
  764.             for ip_addr in ex_gw_port['fixed_ips']:
  765.                 ex_gw_ip = ip_addr['ip_address']
  766.                 if netaddr.IPAddress(ex_gw_ip).version == 4:
  767.                     if self._snat_enabled:
  768.                         rules = self.external_gateway_nat_snat_rules(
  769.                             ex_gw_ip, interface_name)
  770.                         for rule in rules:
  771.                             iptables_manager.ipv4['nat'].add_rule(*rule)
  772.  
  773.                     rules = self.external_gateway_nat_fip_rules(
  774.                         ex_gw_ip, interface_name)
  775.                     for rule in rules:
  776.                         iptables_manager.ipv4['nat'].add_rule(*rule)
  777.                     rules = self.external_gateway_mangle_rules(interface_name)
  778.                     for rule in rules:
  779.                         iptables_manager.ipv4['mangle'].add_rule(*rule)
  780.  
  781.                     break
  782.  
  783.     def _handle_router_snat_rules(self, ex_gw_port, interface_name):
  784.         self._empty_snat_chains(self.iptables_manager)
  785.  
  786.         self.iptables_manager.ipv4['nat'].add_rule('snat', '-j $float-snat')
  787.  
  788.         self._add_snat_rules(ex_gw_port,
  789.                              self.iptables_manager,
  790.                              interface_name)
  791.  
  792.     def _process_external_on_delete(self, agent):
  793.         fip_statuses = {}
  794.         try:
  795.             ex_gw_port = self.get_ex_gw_port()
  796.             self._process_external_gateway(ex_gw_port, agent.pd)
  797.             if not ex_gw_port:
  798.                 return
  799.  
  800.             interface_name = self.get_external_device_interface_name(
  801.                 ex_gw_port)
  802.             fip_statuses = self.configure_fip_addresses(interface_name)
  803.  
  804.         except (n_exc.FloatingIpSetupException):
  805.                 # All floating IPs must be put in error state
  806.                 LOG.exception(_LE("Failed to process floating IPs."))
  807.                 fip_statuses = self.put_fips_in_error_state()
  808.         finally:
  809.             self.update_fip_statuses(agent, fip_statuses)
  810.  
  811.     def process_external(self, agent):
  812.         fip_statuses = {}
  813.         try:
  814.             with self.iptables_manager.defer_apply():
  815.                 ex_gw_port = self.get_ex_gw_port()
  816.                 self._process_external_gateway(ex_gw_port, agent.pd)
  817.                 if not ex_gw_port:
  818.                     return
  819.  
  820.                 # Process SNAT/DNAT rules and addresses for floating IPs
  821.                 self.process_snat_dnat_for_fip()
  822.  
  823.             # Once NAT rules for floating IPs are safely in place
  824.             # configure their addresses on the external gateway port
  825.             interface_name = self.get_external_device_interface_name(
  826.                 ex_gw_port)
  827.             fip_statuses = self.configure_fip_addresses(interface_name)
  828.  
  829.         except (n_exc.FloatingIpSetupException,
  830.                 n_exc.IpTablesApplyException):
  831.                 # All floating IPs must be put in error state
  832.                 LOG.exception(_LE("Failed to process floating IPs."))
  833.                 fip_statuses = self.put_fips_in_error_state()
  834.         finally:
  835.             self.update_fip_statuses(agent, fip_statuses)
  836.  
  837.     def update_fip_statuses(self, agent, fip_statuses):
  838.         # Identify floating IPs which were disabled
  839.         existing_floating_ips = self.floating_ips
  840.         self.floating_ips = set(fip_statuses.keys())
  841.         for fip_id in existing_floating_ips - self.floating_ips:
  842.             fip_statuses[fip_id] = l3_constants.FLOATINGIP_STATUS_DOWN
  843.         # filter out statuses that didn't change
  844.         fip_statuses = {f: stat for f, stat in fip_statuses.items()
  845.                         if stat != FLOATINGIP_STATUS_NOCHANGE}
  846.         if not fip_statuses:
  847.             return
  848.         LOG.debug('Sending floating ip statuses: %s', fip_statuses)
  849.         # Update floating IP status on the neutron server
  850.         agent.plugin_rpc.update_floatingip_statuses(
  851.             agent.context, self.router_id, fip_statuses)
  852.  
  853.     def _get_port_devicename_scopemark(self, ports, name_generator):
  854.         devicename_scopemark = {l3_constants.IP_VERSION_4: dict(),
  855.                                 l3_constants.IP_VERSION_6: dict()}
  856.         for p in ports:
  857.             device_name = name_generator(p['id'])
  858.             ip_cidrs = common_utils.fixed_ip_cidrs(p['fixed_ips'])
  859.             port_as_marks = self.get_port_address_scope_mark(p)
  860.             for ip_version in {ip_lib.get_ip_version(cidr)
  861.                                for cidr in ip_cidrs}:
  862.                 devicename_scopemark[ip_version][device_name] = (
  863.                     port_as_marks[ip_version])
  864.  
  865.         return devicename_scopemark
  866.  
  867.     def _get_address_scope_mark(self):
  868.         # Prepare address scope iptables rule for internal ports
  869.         internal_ports = self.router.get(l3_constants.INTERFACE_KEY, [])
  870.         ports_scopemark = self._get_port_devicename_scopemark(
  871.             internal_ports, self.get_internal_device_name)
  872.  
  873.         # Prepare address scope iptables rule for external port
  874.         external_port = self.get_ex_gw_port()
  875.         if external_port:
  876.             external_port_scopemark = self._get_port_devicename_scopemark(
  877.                 [external_port], self.get_external_device_name)
  878.             for ip_version in (l3_constants.IP_VERSION_4,
  879.                                l3_constants.IP_VERSION_6):
  880.                 ports_scopemark[ip_version].update(
  881.                     external_port_scopemark[ip_version])
  882.         return ports_scopemark
  883.  
  884.     def _add_address_scope_mark(self, iptables_manager, ports_scopemark):
  885.         external_device_name = None
  886.         external_port = self.get_ex_gw_port()
  887.         if external_port:
  888.             external_device_name = self.get_external_device_name(
  889.                 external_port['id'])
  890.  
  891.         # Process address scope iptables rules
  892.         for ip_version in (l3_constants.IP_VERSION_4,
  893.                            l3_constants.IP_VERSION_6):
  894.             scopemarks = ports_scopemark[ip_version]
  895.             iptables = iptables_manager.get_tables(ip_version)
  896.             iptables['mangle'].empty_chain('scope')
  897.             iptables['filter'].empty_chain('scope')
  898.             dont_block_external = (ip_version == l3_constants.IP_VERSION_4
  899.                                    and self._snat_enabled and external_port)
  900.             for device_name, mark in scopemarks.items():
  901.                 # Add address scope iptables rule
  902.                 iptables['mangle'].add_rule(
  903.                     'scope',
  904.                     self.address_scope_mangle_rule(device_name, mark))
  905.                 if dont_block_external and device_name == external_device_name:
  906.                     continue
  907.                 iptables['filter'].add_rule(
  908.                     'scope',
  909.                     self.address_scope_filter_rule(device_name, mark))
  910.  
  911.     def process_ports_address_scope_iptables(self):
  912.         ports_scopemark = self._get_address_scope_mark()
  913.         self._add_address_scope_mark(self.iptables_manager, ports_scopemark)
  914.  
  915.     def _get_external_address_scope(self):
  916.         external_port = self.get_ex_gw_port()
  917.         if not external_port:
  918.             return
  919.  
  920.         scopes = external_port.get('address_scopes', {})
  921.         return scopes.get(str(l3_constants.IP_VERSION_4))
  922.  
  923.     def process_external_port_address_scope_routing(self, iptables_manager):
  924.         if not self._snat_enabled:
  925.             return
  926.  
  927.         external_port = self.get_ex_gw_port()
  928.         if not external_port:
  929.             return
  930.  
  931.         external_devicename = self.get_external_device_name(
  932.             external_port['id'])
  933.  
  934.         # Saves the originating address scope by saving the packet MARK to
  935.         # the CONNMARK for new connections so that returning traffic can be
  936.         # match to it.
  937.         rule = ('-o %s -m connmark --mark 0x0/0xffff0000 '
  938.                 '-j CONNMARK --save-mark '
  939.                 '--nfmask 0xffff0000 --ctmask 0xffff0000' %
  940.                 external_devicename)
  941.  
  942.         iptables_manager.ipv4['mangle'].add_rule('POSTROUTING', rule)
  943.  
  944.         address_scope = self._get_external_address_scope()
  945.         if not address_scope:
  946.             return
  947.  
  948.         # Prevents snat within the same address scope
  949.         rule = '-o %s -m connmark --mark %s -j ACCEPT' % (
  950.             external_devicename,
  951.             self.get_address_scope_mark_mask(address_scope))
  952.         iptables_manager.ipv4['nat'].add_rule('snat', rule)
  953.  
  954.     def process_address_scope(self):
  955.         with self.iptables_manager.defer_apply():
  956.             self.process_ports_address_scope_iptables()
  957.             self.process_floating_ip_address_scope_rules()
  958.  
  959.     @common_utils.exception_logger()
  960.     def process_delete(self, agent):
  961.         """Process the delete of this router
  962.  
  963.        This method is the point where the agent requests that this router
  964.        be deleted. This is a separate code path from process in that it
  965.        avoids any changes to the qrouter namespace that will be removed
  966.        at the end of the operation.
  967.  
  968.        :param agent: Passes the agent in order to send RPC messages.
  969.        """
  970.         LOG.debug("process router delete")
  971.         self._process_internal_ports(agent.pd)
  972.         agent.pd.sync_router(self.router['id'])
  973.         self._process_external_on_delete(agent)
  974.  
  975.     @common_utils.exception_logger()
  976.     def process(self, agent):
  977.         """Process updates to this router
  978.  
  979.        This method is the point where the agent requests that updates be
  980.        applied to this router.
  981.  
  982.        :param agent: Passes the agent in order to send RPC messages.
  983.        """
  984.         LOG.debug("process router updates")
  985.         self._process_internal_ports(agent.pd)
  986.         agent.pd.sync_router(self.router['id'])
  987.         self.process_external(agent)
  988.         self.process_address_scope()
  989.         # Process static routes for router
  990.         self.routes_updated(self.routes, self.router['routes'])
  991.         self.routes = self.router['routes']
  992.  
  993.         # Update ex_gw_port and enable_snat on the router info cache
  994.         self.ex_gw_port = self.get_ex_gw_port()
  995.         # TODO(Carl) FWaaS uses this.  Why is it set after processing is done?
  996.         self.enable_snat = self.router.get('enable_snat')
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement