def main(): eventlet.monkey_patch() opts = [ cfg.StrOpt('network_id'), cfg.StrOpt('router_id'), cfg.StrOpt('pid_file'), cfg.BoolOpt('daemonize', default=True), cfg.IntOpt('metadata_port', default=9697, help="TCP Port to listen for metadata server requests."), ] cfg.CONF.register_opts(opts) cfg.CONF(args=sys.argv, project='quantum') config.setup_logging(cfg.CONF) proxy = ProxyDaemon(cfg.CONF.pid_file, cfg.CONF.metadata_port, network_id=cfg.CONF.network_id, router_id=cfg.CONF.router_id) if cfg.CONF.daemonize: proxy.start() else: proxy.run()
class DhcpAgent(object): OPTS = [ cfg.StrOpt('root_helper', default='sudo'), cfg.IntOpt('resync_interval', default=30), cfg.StrOpt('dhcp_driver', default='quantum.agent.linux.dhcp.Dnsmasq', help="The driver used to manage the DHCP server."), cfg.BoolOpt('use_namespaces', default=True, help="Allow overlapping IP.") ] def __init__(self, conf): self.needs_resync = False self.conf = conf self.cache = NetworkCache() self.dhcp_driver_cls = importutils.import_class(conf.dhcp_driver) ctx = context.RequestContext('quantum', 'quantum', is_admin=True) self.plugin_rpc = DhcpPluginApi(topics.PLUGIN, ctx) self.device_manager = DeviceManager(self.conf, self.plugin_rpc) self.notifications = agent_rpc.NotificationDispatcher() self.lease_relay = DhcpLeaseRelay(self.update_lease) def run(self): """Activate the DHCP agent.""" self.sync_state() self.periodic_resync() self.lease_relay.start() self.notifications.run_dispatch(self) def call_driver(self, action, network): """Invoke an action on a DHCP driver instance.""" if self.conf.use_namespaces: namespace = NS_PREFIX + network.id else: namespace = None try: # the Driver expects something that is duck typed similar to # the base models. driver = self.dhcp_driver_cls(self.conf, network, self.conf.root_helper, self.device_manager, namespace) getattr(driver, action)() return True except Exception, e: self.needs_resync = True LOG.exception('Unable to %s dhcp.' % action)
def setup_conf(): """Setup the cfg for the clean up utility. Use separate setup_conf for the utility because there are many options from the main config that do not apply during clean-up. """ opts = [ cfg.StrOpt('root_helper', default='sudo'), cfg.StrOpt('dhcp_driver', default='quantum.agent.linux.dhcp.Dnsmasq', help="The driver used to manage the DHCP server."), cfg.StrOpt('state_path', default='.', help='Top-level directory for maintaining dhcp state'), cfg.BoolOpt('force', default=False, help='Delete the namespace by removing all devices.'), ] conf = cfg.CommonConfigOpts() conf.register_opts(opts) conf.register_opts(dhcp.OPTS) config.setup_logging(conf) return conf
default='', help='Username for qpid connection'), cfg.StrOpt('qpid_password', default='', help='Password for qpid connection'), cfg.StrOpt('qpid_sasl_mechanisms', default='', help='Space separated list of SASL mechanisms to use for auth'), cfg.IntOpt('qpid_heartbeat', default=60, help='Seconds between connection keepalive heartbeats'), cfg.StrOpt('qpid_protocol', default='tcp', help="Transport to use, either 'tcp' or 'ssl'"), cfg.BoolOpt('qpid_tcp_nodelay', default=True, help='Disable Nagle algorithm'), ] cfg.CONF.register_opts(qpid_opts) class ConsumerBase(object): """Consumer base class.""" def __init__(self, session, callback, node_name, node_opts, link_name, link_opts): """Declare a queue on an amqp session. 'session' is the amqp session to use 'callback' is the callback to call when messages are received 'node_name' is the first part of the Qpid address string, before ';'
LOG = logging.getLogger(__name__) core_opts = [ cfg.StrOpt('bind_host', default='0.0.0.0'), cfg.IntOpt('bind_port', default=9696), cfg.StrOpt('api_paste_config', default="api-paste.ini"), cfg.StrOpt('api_extensions_path', default=""), cfg.StrOpt('policy_file', default="policy.json"), cfg.StrOpt('auth_strategy', default='keystone'), cfg.StrOpt('core_plugin', default='quantum.plugins.sample.SamplePlugin.FakePlugin'), cfg.StrOpt('base_mac', default="fa:16:3e:00:00:00"), cfg.IntOpt('mac_generation_retries', default=16), cfg.BoolOpt('allow_bulk', default=True), cfg.IntOpt('max_dns_nameservers', default=5), cfg.IntOpt('max_subnet_host_routes', default=20), cfg.StrOpt('state_path', default='.'), cfg.IntOpt('dhcp_lease_duration', default=120), ] # Register the configuration options cfg.CONF.register_opts(core_opts) def parse(args): cfg.CONF(args=args, project='quantum', version='%%prog %s' % version_string()) # Validate that the base_mac is of the correct format
help='data to append to log format when level is DEBUG'), cfg.StrOpt('logging_exception_prefix', default='%(asctime)s TRACE %(name)s %(instance)s', help='prefix each line of exception output with this format'), cfg.ListOpt('default_log_levels', default=[ 'amqplib=WARN', 'sqlalchemy=WARN', 'boto=WARN', 'suds=INFO', 'keystone=INFO', 'eventlet.wsgi.server=WARN' ], help='list of logger=LEVEL pairs'), cfg.BoolOpt('publish_errors', default=False, help='publish error events'), # NOTE(mikal): there are two options here because sometimes we are handed # a full instance (and could include more information), and other times we # are just handed a UUID for the instance. cfg.StrOpt('instance_format', default='[instance: %(uuid)s] ', help='If an instance is passed with the log message, format ' 'it like this'), cfg.StrOpt('instance_uuid_format', default='[instance: %(uuid)s] ', help='If an instance UUID is passed with the log message, ' 'format it like this'), ]
import shutil import tempfile import time import weakref from eventlet import semaphore from quantum.openstack.common import cfg from quantum.openstack.common import fileutils from quantum.openstack.common import log as logging LOG = logging.getLogger(__name__) util_opts = [ cfg.BoolOpt('disable_process_locking', default=False, help='Whether to disable inter-process locks'), cfg.StrOpt('lock_path', default=os.path.abspath( os.path.join(os.path.dirname(__file__), '../')), help='Directory to use for lock files') ] CONF = cfg.CONF CONF.register_opts(util_opts) class _InterProcessLock(object): """Lock implementation which allows multiple locks, working around issues like bugs.debian.org/cgi-bin/bugreport.cgi?bug=632857 and does not require any cleanup. Since the lock is always held on a file
class L3NATAgent(object): OPTS = [ cfg.StrOpt('admin_user'), cfg.StrOpt('admin_password'), cfg.StrOpt('admin_tenant_name'), cfg.StrOpt('auth_url'), cfg.StrOpt('auth_strategy', default='keystone'), cfg.StrOpt('auth_region'), cfg.StrOpt('root_helper', default='sudo'), cfg.StrOpt('external_network_bridge', default='br-ex', help="Name of bridge used for external network traffic."), cfg.StrOpt('interface_driver', help="The driver used to manage the virtual interface."), cfg.IntOpt('polling_interval', default=3, help="The time in seconds between state poll requests."), cfg.StrOpt('metadata_ip', default='', help="IP address used by Nova metadata server."), cfg.IntOpt('metadata_port', default=8775, help="TCP Port used by Nova metadata server."), cfg.IntOpt('send_arp_for_ha', default=3, help="Send this many gratuitous ARPs for HA setup, " "set it below or equal to 0 to disable this feature."), cfg.BoolOpt('use_namespaces', default=True, help="Allow overlapping IP."), cfg.StrOpt('router_id', default='', help="If namespaces is disabled, the l3 agent can only" " confgure a router that has the matching router ID."), cfg.BoolOpt('handle_internal_only_routers', default=True, help="Agent should implement routers with no gateway"), cfg.StrOpt('gateway_external_network_id', default='', help="UUID of external network for routers implemented " "by the agents."), ] def __init__(self, conf): self.conf = conf self.router_info = {} if not conf.interface_driver: LOG.error(_('You must specify an interface driver')) sys.exit(1) try: self.driver = importutils.import_object(conf.interface_driver, conf) except: LOG.exception(_("Error importing interface driver '%s'"), conf.interface_driver) sys.exit(1) self.polling_interval = conf.polling_interval self.qclient = client.Client( username=self.conf.admin_user, password=self.conf.admin_password, tenant_name=self.conf.admin_tenant_name, auth_url=self.conf.auth_url, auth_strategy=self.conf.auth_strategy, region_name=self.conf.auth_region ) if self.conf.use_namespaces: self._destroy_all_router_namespaces() def _destroy_all_router_namespaces(self): """Destroy all router namespaces on the host to eliminate all stale linux devices, iptables rules, and namespaces. """ root_ip = ip_lib.IPWrapper(self.conf.root_helper) for ns in root_ip.get_namespaces(self.conf.root_helper): if ns.startswith(NS_PREFIX): try: self._destroy_router_namespace(ns) except: LOG.exception(_("Couldn't delete namespace '%s'"), ns) def _destroy_router_namespace(self, namespace): ns_ip = ip_lib.IPWrapper(self.conf.root_helper, namespace=namespace) for d in ns_ip.get_devices(exclude_loopback=True): if d.name.startswith(INTERNAL_DEV_PREFIX): # device is on default bridge self.driver.unplug(d.name, namespace=namespace, prefix=INTERNAL_DEV_PREFIX) elif d.name.startswith(EXTERNAL_DEV_PREFIX): self.driver.unplug(d.name, bridge=self.conf.external_network_bridge, namespace=namespace, prefix=EXTERNAL_DEV_PREFIX) #(TODO) Address the failure for the deletion of the namespace def _create_router_namespace(self, ri): ip_wrapper_root = ip_lib.IPWrapper(self.conf.root_helper) ip_wrapper = ip_wrapper_root.ensure_namespace(ri.ns_name()) ip_wrapper.netns.execute(['sysctl', '-w', 'net.ipv4.ip_forward=1']) def daemon_loop(self): #TODO(danwent): this simple diff logic does not handle if # details of a router port (e.g., IP, mac) are changed behind # our back. Will fix this properly with update notifications. while True: try: self.do_single_loop() except: LOG.exception(_("Error running l3_nat daemon_loop")) time.sleep(self.polling_interval) def _fetch_external_net_id(self): """Find UUID of single external network for this agent""" if self.conf.gateway_external_network_id: return self.conf.gateway_external_network_id params = {'router:external': True} ex_nets = self.qclient.list_networks(**params)['networks'] if len(ex_nets) > 1: raise Exception(_("Must configure 'gateway_external_network_id' " "if Quantum has more than one external " "network.")) if len(ex_nets) == 0: return None return ex_nets[0]['id'] def do_single_loop(self): if (self.conf.external_network_bridge and not ip_lib.device_exists(self.conf.external_network_bridge)): LOG.error(_("External network bridge '%s' does not exist"), self.conf.external_network_bridge) return prev_router_ids = set(self.router_info) cur_router_ids = set() target_ex_net_id = self._fetch_external_net_id() # identify and update new or modified routers for r in self.qclient.list_routers()['routers']: if not r['admin_state_up']: continue ex_net_id = (r['external_gateway_info'] and r['external_gateway_info'].get('network_id')) if not ex_net_id and not self.conf.handle_internal_only_routers: continue if ex_net_id and ex_net_id != target_ex_net_id: continue # If namespaces are disabled, only process the router associated # with the configured agent id. if (self.conf.use_namespaces or r['id'] == self.conf.router_id): cur_router_ids.add(r['id']) else: continue if r['id'] not in self.router_info: self._router_added(r['id']) ri = self.router_info[r['id']] self.process_router(ri) # identify and remove routers that no longer exist for router_id in prev_router_ids - cur_router_ids: self._router_removed(router_id) prev_router_ids = cur_router_ids def _router_added(self, router_id): ri = RouterInfo(router_id, self.conf.root_helper, self.conf.use_namespaces) self.router_info[router_id] = ri if self.conf.use_namespaces: self._create_router_namespace(ri) for c, r in self.metadata_filter_rules(): ri.iptables_manager.ipv4['filter'].add_rule(c, r) for c, r in self.metadata_nat_rules(): ri.iptables_manager.ipv4['nat'].add_rule(c, r) ri.iptables_manager.apply() def _router_removed(self, router_id): ri = self.router_info[router_id] for c, r in self.metadata_filter_rules(): ri.iptables_manager.ipv4['filter'].remove_rule(c, r) for c, r in self.metadata_nat_rules(): ri.iptables_manager.ipv4['nat'].remove_rule(c, r) ri.iptables_manager.apply() del self.router_info[router_id] self._destroy_router_namespace(ri.ns_name()) def _set_subnet_info(self, port): ips = port['fixed_ips'] if not ips: raise Exception(_("Router port %s has no IP address") % port['id']) if len(ips) > 1: LOG.error(_("Ignoring multiple IPs on router port %s"), port['id']) port['subnet'] = self.qclient.show_subnet( ips[0]['subnet_id'])['subnet'] prefixlen = netaddr.IPNetwork(port['subnet']['cidr']).prefixlen port['ip_cidr'] = "%s/%s" % (ips[0]['ip_address'], prefixlen) def process_router(self, ri): ex_gw_port = self._get_ex_gw_port(ri) internal_ports = self.qclient.list_ports( device_id=ri.router_id, device_owner=l3_db.DEVICE_OWNER_ROUTER_INTF)['ports'] existing_port_ids = set([p['id'] for p in ri.internal_ports]) current_port_ids = set([p['id'] for p in internal_ports if p['admin_state_up']]) new_ports = [p for p in internal_ports if p['id'] in current_port_ids and p['id'] not in existing_port_ids] old_ports = [p for p in ri.internal_ports if p['id'] not in current_port_ids] for p in new_ports: self._set_subnet_info(p) ri.internal_ports.append(p) self.internal_network_added(ri, ex_gw_port, p['network_id'], p['id'], p['ip_cidr'], p['mac_address']) for p in old_ports: ri.internal_ports.remove(p) self.internal_network_removed(ri, ex_gw_port, p['id'], p['ip_cidr']) internal_cidrs = [p['ip_cidr'] for p in ri.internal_ports] if ex_gw_port and not ri.ex_gw_port: self._set_subnet_info(ex_gw_port) self.external_gateway_added(ri, ex_gw_port, internal_cidrs) elif not ex_gw_port and ri.ex_gw_port: self.external_gateway_removed(ri, ri.ex_gw_port, internal_cidrs) if ri.ex_gw_port or ex_gw_port: self.process_router_floating_ips(ri, ex_gw_port) ri.ex_gw_port = ex_gw_port def process_router_floating_ips(self, ri, ex_gw_port): floating_ips = self.qclient.list_floatingips( router_id=ri.router_id)['floatingips'] existing_floating_ip_ids = set([fip['id'] for fip in ri.floating_ips]) cur_floating_ip_ids = set([fip['id'] for fip in floating_ips]) id_to_fip_map = {} for fip in floating_ips: if fip['port_id']: if fip['id'] not in existing_floating_ip_ids: ri.floating_ips.append(fip) self.floating_ip_added(ri, ex_gw_port, fip['floating_ip_address'], fip['fixed_ip_address']) # store to see if floatingip was remapped id_to_fip_map[fip['id']] = fip floating_ip_ids_to_remove = (existing_floating_ip_ids - cur_floating_ip_ids) for fip in ri.floating_ips: if fip['id'] in floating_ip_ids_to_remove: ri.floating_ips.remove(fip) self.floating_ip_removed(ri, ri.ex_gw_port, fip['floating_ip_address'], fip['fixed_ip_address']) else: # handle remapping of a floating IP new_fip = id_to_fip_map[fip['id']] new_fixed_ip = new_fip['fixed_ip_address'] existing_fixed_ip = fip['fixed_ip_address'] if (new_fixed_ip and existing_fixed_ip and new_fixed_ip != existing_fixed_ip): floating_ip = fip['floating_ip_address'] self.floating_ip_removed(ri, ri.ex_gw_port, floating_ip, existing_fixed_ip) self.floating_ip_added(ri, ri.ex_gw_port, floating_ip, new_fixed_ip) ri.floating_ips.remove(fip) ri.floating_ips.append(new_fip) def _get_ex_gw_port(self, ri): ports = self.qclient.list_ports( device_id=ri.router_id, device_owner=l3_db.DEVICE_OWNER_ROUTER_GW)['ports'] if not ports: return None elif len(ports) == 1: return ports[0] else: LOG.error(_("Ignoring multiple gateway ports for router %s"), ri.router_id) def _send_gratuitous_arp_packet(self, ri, interface_name, ip_address): if self.conf.send_arp_for_ha > 0: arping_cmd = ['arping', '-A', '-U', '-I', interface_name, '-c', self.conf.send_arp_for_ha, ip_address] try: if self.conf.use_namespaces: ip_wrapper = ip_lib.IPWrapper(self.conf.root_helper, namespace=ri.ns_name()) ip_wrapper.netns.execute(arping_cmd, check_exit_code=True) else: utils.execute(arping_cmd, check_exit_code=True, root_helper=self.conf.root_helper) except Exception as e: LOG.error(_("Failed sending gratuitous ARP: %s") % str(e)) def get_internal_device_name(self, port_id): return (INTERNAL_DEV_PREFIX + port_id)[:self.driver.DEV_NAME_LEN] def get_external_device_name(self, port_id): return (EXTERNAL_DEV_PREFIX + port_id)[:self.driver.DEV_NAME_LEN] def external_gateway_added(self, ri, ex_gw_port, internal_cidrs): interface_name = self.get_external_device_name(ex_gw_port['id']) ex_gw_ip = ex_gw_port['fixed_ips'][0]['ip_address'] if not ip_lib.device_exists(interface_name, root_helper=self.conf.root_helper, namespace=ri.ns_name()): self.driver.plug(ex_gw_port['network_id'], ex_gw_port['id'], interface_name, ex_gw_port['mac_address'], bridge=self.conf.external_network_bridge, namespace=ri.ns_name(), prefix=EXTERNAL_DEV_PREFIX) self.driver.init_l3(interface_name, [ex_gw_port['ip_cidr']], namespace=ri.ns_name()) ip_address = ex_gw_port['ip_cidr'].split('/')[0] self._send_gratuitous_arp_packet(ri, interface_name, ip_address) gw_ip = ex_gw_port['subnet']['gateway_ip'] if ex_gw_port['subnet']['gateway_ip']: cmd = ['route', 'add', 'default', 'gw', gw_ip] if self.conf.use_namespaces: ip_wrapper = ip_lib.IPWrapper(self.conf.root_helper, namespace=ri.ns_name()) ip_wrapper.netns.execute(cmd, check_exit_code=False) else: utils.execute(cmd, check_exit_code=False, root_helper=self.conf.root_helper) for (c, r) in self.external_gateway_nat_rules(ex_gw_ip, internal_cidrs, interface_name): ri.iptables_manager.ipv4['nat'].add_rule(c, r) ri.iptables_manager.apply() def external_gateway_removed(self, ri, ex_gw_port, internal_cidrs): interface_name = self.get_external_device_name(ex_gw_port['id']) if ip_lib.device_exists(interface_name, root_helper=self.conf.root_helper, namespace=ri.ns_name()): self.driver.unplug(interface_name, bridge=self.conf.external_network_bridge, namespace=ri.ns_name(), prefix=EXTERNAL_DEV_PREFIX) ex_gw_ip = ex_gw_port['fixed_ips'][0]['ip_address'] for c, r in self.external_gateway_nat_rules(ex_gw_ip, internal_cidrs, interface_name): ri.iptables_manager.ipv4['nat'].remove_rule(c, r) ri.iptables_manager.apply() def metadata_filter_rules(self): rules = [] if self.conf.metadata_ip: rules.append(('INPUT', '-s 0.0.0.0/0 -d %s ' '-p tcp -m tcp --dport %s ' '-j ACCEPT' % (self.conf.metadata_ip, self.conf.metadata_port))) return rules def metadata_nat_rules(self): rules = [] if self.conf.metadata_ip: rules.append(('PREROUTING', '-s 0.0.0.0/0 -d 169.254.169.254/32 ' '-p tcp -m tcp --dport 80 -j DNAT ' '--to-destination %s:%s' % (self.conf.metadata_ip, self.conf.metadata_port))) return rules def external_gateway_nat_rules(self, ex_gw_ip, internal_cidrs, interface_name): rules = [('POSTROUTING', '! -i %(interface_name)s ' '! -o %(interface_name)s -m conntrack ! ' '--ctstate DNAT -j ACCEPT' % locals())] for cidr in internal_cidrs: rules.extend(self.internal_network_nat_rules(ex_gw_ip, cidr)) return rules def internal_network_added(self, ri, ex_gw_port, network_id, port_id, internal_cidr, mac_address): interface_name = self.get_internal_device_name(port_id) if not ip_lib.device_exists(interface_name, root_helper=self.conf.root_helper, namespace=ri.ns_name()): self.driver.plug(network_id, port_id, interface_name, mac_address, namespace=ri.ns_name(), prefix=INTERNAL_DEV_PREFIX) self.driver.init_l3(interface_name, [internal_cidr], namespace=ri.ns_name()) ip_address = internal_cidr.split('/')[0] self._send_gratuitous_arp_packet(ri, interface_name, ip_address) if ex_gw_port: ex_gw_ip = ex_gw_port['fixed_ips'][0]['ip_address'] for c, r in self.internal_network_nat_rules(ex_gw_ip, internal_cidr): ri.iptables_manager.ipv4['nat'].add_rule(c, r) ri.iptables_manager.apply() def internal_network_removed(self, ri, ex_gw_port, port_id, internal_cidr): interface_name = self.get_internal_device_name(port_id) if ip_lib.device_exists(interface_name, root_helper=self.conf.root_helper, namespace=ri.ns_name()): self.driver.unplug(interface_name, namespace=ri.ns_name(), prefix=INTERNAL_DEV_PREFIX) if ex_gw_port: ex_gw_ip = ex_gw_port['fixed_ips'][0]['ip_address'] for c, r in self.internal_network_nat_rules(ex_gw_ip, internal_cidr): ri.iptables_manager.ipv4['nat'].remove_rule(c, r) ri.iptables_manager.apply() def internal_network_nat_rules(self, ex_gw_ip, internal_cidr): rules = [('snat', '-s %s -j SNAT --to-source %s' % (internal_cidr, ex_gw_ip))] if self.conf.metadata_ip: rules.append(('POSTROUTING', '-s %s -d %s/32 -j ACCEPT' % (internal_cidr, self.conf.metadata_ip))) return rules def floating_ip_added(self, ri, ex_gw_port, floating_ip, fixed_ip): ip_cidr = str(floating_ip) + '/32' interface_name = self.get_external_device_name(ex_gw_port['id']) device = ip_lib.IPDevice(interface_name, self.conf.root_helper, namespace=ri.ns_name()) if not ip_cidr in [addr['cidr'] for addr in device.addr.list()]: net = netaddr.IPNetwork(ip_cidr) device.addr.add(net.version, ip_cidr, str(net.broadcast)) self._send_gratuitous_arp_packet(ri, interface_name, floating_ip) for chain, rule in self.floating_forward_rules(floating_ip, fixed_ip): ri.iptables_manager.ipv4['nat'].add_rule(chain, rule) ri.iptables_manager.apply() def floating_ip_removed(self, ri, ex_gw_port, floating_ip, fixed_ip): ip_cidr = str(floating_ip) + '/32' net = netaddr.IPNetwork(ip_cidr) interface_name = self.get_external_device_name(ex_gw_port['id']) device = ip_lib.IPDevice(interface_name, self.conf.root_helper, namespace=ri.ns_name()) device.addr.delete(net.version, ip_cidr) for chain, rule in self.floating_forward_rules(floating_ip, fixed_ip): ri.iptables_manager.ipv4['nat'].remove_rule(chain, rule) ri.iptables_manager.apply() def floating_forward_rules(self, floating_ip, fixed_ip): return [('PREROUTING', '-d %s -j DNAT --to %s' % (floating_ip, fixed_ip)), ('OUTPUT', '-d %s -j DNAT --to %s' % (floating_ip, fixed_ip)), ('float-snat', '-s %s -j SNAT --to %s' % (fixed_ip, floating_ip))]
from quantum.agent.linux import ovs_lib from quantum.agent.linux import utils from quantum.common import exceptions from quantum.extensions.flavor import (FLAVOR_NETWORK) from quantum.openstack.common import cfg from quantum.openstack.common import importutils from quantum.openstack.common import log as logging LOG = logging.getLogger(__name__) OPTS = [ cfg.StrOpt('ovs_integration_bridge', default='br-int', help='Name of Open vSwitch bridge to use'), cfg.BoolOpt('ovs_use_veth', default=False, help='Uses veth for an interface or not'), cfg.StrOpt('network_device_mtu', help='MTU setting for device.'), cfg.StrOpt('meta_flavor_driver_mappings', help='Mapping between flavor and LinuxInterfaceDriver') ] class LinuxInterfaceDriver(object): __metaclass__ = abc.ABCMeta # from linux IF_NAMESIZE DEV_NAME_LEN = 14 DEV_NAME_PREFIX = 'tap' def __init__(self, conf):
qpid_opts = [ cfg.StrOpt('qpid_hostname', default='localhost', help='Qpid broker hostname'), cfg.StrOpt('qpid_port', default='5672', help='Qpid broker port'), cfg.StrOpt('qpid_username', default='', help='Username for qpid connection'), cfg.StrOpt('qpid_password', default='', help='Password for qpid connection'), cfg.StrOpt('qpid_sasl_mechanisms', default='', help='Space separated list of SASL mechanisms to use for auth'), cfg.BoolOpt('qpid_reconnect', default=True, help='Automatically reconnect'), cfg.IntOpt('qpid_reconnect_timeout', default=0, help='Reconnection timeout in seconds'), cfg.IntOpt('qpid_reconnect_limit', default=0, help='Max reconnections before giving up'), cfg.IntOpt('qpid_reconnect_interval_min', default=0, help='Minimum seconds between reconnection attempts'), cfg.IntOpt('qpid_reconnect_interval_max', default=0, help='Maximum seconds between reconnection attempts'), cfg.IntOpt('qpid_reconnect_interval', default=0, help='Equivalent to setting max and min to the same value'),
help='data to append to log format when level is DEBUG'), cfg.StrOpt('logging_exception_prefix', default='%(asctime)s %(process)d TRACE %(name)s %(instance)s', help='prefix each line of exception output with this format'), cfg.ListOpt('default_log_levels', default=[ 'amqplib=WARN', 'sqlalchemy=WARN', 'boto=WARN', 'suds=INFO', 'keystone=INFO', 'eventlet.wsgi.server=WARN' ], help='list of logger=LEVEL pairs'), cfg.BoolOpt('publish_errors', default=False, help='publish error events'), cfg.BoolOpt('fatal_deprecations', default=False, help='make deprecations fatal'), # NOTE(mikal): there are two options here because sometimes we are handed # a full instance (and could include more information), and other times we # are just handed a UUID for the instance. cfg.StrOpt('instance_format', default='[instance: %(uuid)s] ', help='If an instance is passed with the log message, format ' 'it like this'), cfg.StrOpt('instance_uuid_format', default='[instance: %(uuid)s] ', help='If an instance UUID is passed with the log message, '
cfg.IntOpt('rpc_cast_timeout', default=30, help='Seconds to wait before a cast expires (TTL). ' 'Only supported by impl_zmq.'), cfg.ListOpt('allowed_rpc_exception_modules', default=[ 'quantum.openstack.common.exception', 'nova.exception', ], help='Modules of exceptions that are permitted to be recreated' 'upon receiving exception data from an rpc call.'), cfg.StrOpt('control_exchange', default='nova', help='AMQP exchange to connect to if using RabbitMQ or Qpid'), cfg.BoolOpt('fake_rabbit', default=False, help='If passed, use a fake RabbitMQ provider'), ] cfg.CONF.register_opts(rpc_opts) def create_connection(new=True): """Create a connection to the message bus used for rpc. For some example usage of creating a connection and some consumers on that connection, see nova.service. :param new: Whether or not to create a new connection. A new connection will be created by default. If new is False, the implementation is free to return an existing connection from a
class QuantumDebugAgent(): OPTS = [ cfg.StrOpt('root_helper', default='sudo'), # Needed for drivers cfg.StrOpt('admin_user'), cfg.StrOpt('admin_password'), cfg.StrOpt('admin_tenant_name'), cfg.StrOpt('auth_url'), cfg.StrOpt('auth_strategy', default='keystone'), cfg.StrOpt('auth_region'), cfg.BoolOpt('use_namespaces', default=True), cfg.StrOpt('interface_driver', help="The driver used to manage the virtual interface.") ] def __init__(self, conf, client, driver): self.conf = conf self.client = client self.driver = driver def _get_namespace(self, port): return "qprobe-%s" % port.id def create_probe(self, network_id): network = self._get_network(network_id) port = self._create_port(network) port.network = network interface_name = self.driver.get_device_name(port) namespace = None if self.conf.use_namespaces: namespace = self._get_namespace(port) if ip_lib.device_exists(interface_name, self.conf.root_helper, namespace): LOG.debug(_('Reusing existing device: %s.') % interface_name) else: self.driver.plug(network.id, port.id, interface_name, port.mac_address, namespace=namespace) ip_cidrs = [] for fixed_ip in port.fixed_ips: subnet = fixed_ip.subnet net = netaddr.IPNetwork(subnet.cidr) ip_cidr = '%s/%s' % (fixed_ip.ip_address, net.prefixlen) ip_cidrs.append(ip_cidr) self.driver.init_l3(interface_name, ip_cidrs, namespace=namespace) return port def _get_subnet(self, subnet_id): subnet_dict = self.client.show_subnet(subnet_id)['subnet'] return DictModel(subnet_dict) def _get_network(self, network_id): network_dict = self.client.show_network(network_id)['network'] network = DictModel(network_dict) obj_subnet = [self._get_subnet(s_id) for s_id in network.subnets] network.subnets = obj_subnet return network def clear_probe(self): ports = self.client.list_ports(device_id=socket.gethostname(), device_owner=DEVICE_OWNER_PROBE) info = ports['ports'] for port in info: self.delete_probe(port['id']) def delete_probe(self, port_id): port = DictModel(self.client.show_port(port_id)['port']) ip = ip_lib.IPWrapper(self.conf.root_helper) namespace = self._get_namespace(port) if self.conf.use_namespaces and ip.netns.exists(namespace): self.driver.unplug(self.driver.get_device_name(port), namespace=namespace) ip.netns.delete(namespace) else: self.driver.unplug(self.driver.get_device_name(port)) self.client.delete_port(port.id) def list_probes(self): ports = self.client.list_ports(device_owner=DEVICE_OWNER_PROBE) info = ports['ports'] for port in info: port['device_name'] = self.driver.get_device_name(DictModel(port)) return info def exec_command(self, port_id, command=None): port = DictModel(self.client.show_port(port_id)['port']) ip = ip_lib.IPWrapper(self.conf.root_helper) namespace = self._get_namespace(port) if self.conf.use_namespaces: if not command: return "sudo ip netns exec %s" % self._get_namespace(port) namespace = ip.ensure_namespace(namespace) return namespace.netns.execute(shlex.split(command)) else: return utils.execute(shlex.split(command)) def ensure_probe(self, network_id): ports = self.client.list_ports(network_id=network_id, device_id=socket.gethostname(), device_owner=DEVICE_OWNER_PROBE) info = ports.get('ports', []) if info: return DictModel(info[0]) else: return self.create_probe(network_id) def ping_all(self, network_id=None, timeout=1): if network_id: ports = self.client.list_ports(network_id=network_id)['ports'] else: ports = self.client.list_ports()['ports'] result = "" for port in ports: probe = self.ensure_probe(port['network_id']) if port['device_owner'] == DEVICE_OWNER_PROBE: continue for fixed_ip in port['fixed_ips']: address = fixed_ip['ip_address'] subnet = self._get_subnet(fixed_ip['subnet_id']) if subnet.ip_version == 4: ping_command = 'ping' else: ping_command = 'ping6' result += self.exec_command( probe.id, '%s -c 1 -w %s %s' % (ping_command, timeout, address)) return result def _create_port(self, network): body = dict(port=dict( admin_state_up=True, network_id=network.id, device_id='%s' % socket.gethostname(), device_owner=DEVICE_OWNER_PROBE, tenant_id=network.tenant_id, fixed_ips=[dict(subnet_id=s.id) for s in network.subnets])) port_dict = self.client.create_port(body)['port'] port = DictModel(port_dict) port.network = network for fixed_ip in port.fixed_ips: fixed_ip.subnet = self._get_subnet(fixed_ip.subnet_id) return port
] ovs_opts = [ cfg.StrOpt('integration_bridge', default='br-int'), ] agent_opts = [ cfg.IntOpt('polling_interval', default=2), cfg.StrOpt('root_helper', default='sudo'), ] ofc_opts = [ cfg.StrOpt('host', default='127.0.0.1'), cfg.StrOpt('port', default='8888'), cfg.StrOpt('driver', default='trema'), cfg.BoolOpt('enable_packet_filter', default=True), cfg.BoolOpt('use_ssl', default=False), cfg.StrOpt('key_file', default=None), cfg.StrOpt('cert_file', default=None), ] cfg.CONF.register_opts(database_opts, "DATABASE") cfg.CONF.register_opts(ovs_opts, "OVS") cfg.CONF.register_opts(agent_opts, "AGENT") cfg.CONF.register_opts(ofc_opts, "OFC") # shortcuts CONF = cfg.CONF DATABASE = cfg.CONF.DATABASE OVS = cfg.CONF.OVS
# Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from quantum.openstack.common import cfg database_opts = [ cfg.StrOpt('sql_connection', default='sqlite://'), cfg.IntOpt('reconnect_interval', default=2), ] ovs_opts = [ cfg.BoolOpt('enable_tunneling', default=False), cfg.StrOpt('integration_bridge', default='br-int'), cfg.StrOpt('tunnel_bridge', default='br-tun'), cfg.StrOpt('local_ip', default='10.0.0.3'), cfg.IntOpt('vlan_min', default=1), cfg.IntOpt('vlan_max', default=4094), ] agent_opts = [ cfg.BoolOpt('target_v2_api', default=True), cfg.IntOpt('polling_interval', default=2), cfg.StrOpt('root_helper', default='sudo'), cfg.StrOpt('log_file', default=None), ]
# # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from quantum.openstack.common import cfg database_opts = [ cfg.StrOpt('sql_connection', default='sqlite://'), cfg.IntOpt('reconnect_interval', default=2), ] ovs_opts = [ cfg.BoolOpt('enable_tunneling', default=False), cfg.StrOpt('integration_bridge', default='br-int'), cfg.StrOpt('tunnel_bridge', default='br-tun'), cfg.StrOpt('local_ip', default='10.0.0.3'), cfg.IntOpt('vlan_min', default=1), cfg.IntOpt('vlan_max', default=4094), ] agent_opts = [ cfg.IntOpt('polling_interval', default=2), cfg.StrOpt('root_helper', default='sudo'), ] def parse(config_file): conf = cfg.ConfigOpts(default_config_files=[config_file])
from quantum.openstack.common import cfg DEFAULT_BRIDGE_MAPPINGS = [] DEFAULT_VLAN_RANGES = [] DEFAULT_TUNNEL_RANGES = [] database_opts = [ cfg.StrOpt('sql_connection', default='sqlite://'), cfg.IntOpt('sql_max_retries', default=-1), cfg.IntOpt('reconnect_interval', default=2), ] ovs_opts = [ cfg.StrOpt('integration_bridge', default='br-int'), cfg.BoolOpt('enable_tunneling', default=False), cfg.StrOpt('tunnel_bridge', default='br-tun'), cfg.StrOpt('local_ip', default=''), cfg.ListOpt('bridge_mappings', default=DEFAULT_BRIDGE_MAPPINGS, help="List of <physical_network>:<bridge>"), cfg.StrOpt('tenant_network_type', default='local', help="Network type for tenant networks " "(local, vlan, gre, or none)"), cfg.ListOpt('network_vlan_ranges', default=DEFAULT_VLAN_RANGES, help="List of <physical_network>:<vlan_min>:<vlan_max> " "or <physical_network>"), cfg.ListOpt('tunnel_id_ranges', default=DEFAULT_TUNNEL_RANGES,
default='', help='SSL version to use (valid only if SSL enabled)'), cfg.StrOpt('kombu_ssl_keyfile', default='', help='SSL key file (valid only if SSL enabled)'), cfg.StrOpt('kombu_ssl_certfile', default='', help='SSL cert file (valid only if SSL enabled)'), cfg.StrOpt('kombu_ssl_ca_certs', default='', help=('SSL certification authority file ' '(valid only if SSL enabled)')), cfg.StrOpt('rabbit_host', default='localhost', help='the RabbitMQ host'), cfg.IntOpt('rabbit_port', default=5672, help='the RabbitMQ port'), cfg.BoolOpt('rabbit_use_ssl', default=False, help='connect over SSL for RabbitMQ'), cfg.StrOpt('rabbit_userid', default='guest', help='the RabbitMQ userid'), cfg.StrOpt('rabbit_password', default='guest', help='the RabbitMQ password'), cfg.StrOpt('rabbit_virtual_host', default='/', help='the RabbitMQ virtual host'), cfg.IntOpt('rabbit_retry_interval', default=1, help='how frequently to retry connecting with RabbitMQ'), cfg.IntOpt('rabbit_retry_backoff', default=2, help='how long to backoff for between retries when connecting ' 'to RabbitMQ'),
LOG = logging.getLogger(__name__) core_opts = [ cfg.StrOpt('bind_host', default='0.0.0.0'), cfg.IntOpt('bind_port', default=9696), cfg.StrOpt('api_paste_config', default="api-paste.ini"), cfg.StrOpt('api_extensions_path', default=""), cfg.StrOpt('policy_file', default="policy.json"), cfg.StrOpt('auth_strategy', default='keystone'), cfg.StrOpt('core_plugin', default='quantum.plugins.sample.SamplePlugin.FakePlugin'), cfg.ListOpt('service_plugins', default=[]), cfg.StrOpt('base_mac', default="fa:16:3e:00:00:00"), cfg.IntOpt('mac_generation_retries', default=16), cfg.BoolOpt('allow_bulk', default=True), cfg.IntOpt('max_dns_nameservers', default=5), cfg.IntOpt('max_subnet_host_routes', default=20), cfg.StrOpt('state_path', default='.'), cfg.IntOpt('dhcp_lease_duration', default=120), cfg.BoolOpt('allow_overlapping_ips', default=False), cfg.StrOpt('control_exchange', default='quantum', help='AMQP exchange to connect to if using RabbitMQ or Qpid') ] # Register the configuration options cfg.CONF.register_opts(core_opts) def parse(args):
class L3NATAgent(manager.Manager): OPTS = [ cfg.StrOpt('root_helper', default='sudo'), cfg.StrOpt('external_network_bridge', default='br-ex', help="Name of bridge used for external network traffic."), cfg.StrOpt('interface_driver', help="The driver used to manage the virtual interface."), cfg.IntOpt('metadata_port', default=9697, help="TCP Port used by Quantum metadata namespace proxy."), cfg.IntOpt('send_arp_for_ha', default=3, help="Send this many gratuitous ARPs for HA setup, " "set it below or equal to 0 to disable this feature."), cfg.BoolOpt('use_namespaces', default=True, help="Allow overlapping IP."), cfg.StrOpt('router_id', default='', help="If namespaces is disabled, the l3 agent can only" " confgure a router that has the matching router ID."), cfg.BoolOpt('handle_internal_only_routers', default=True, help="Agent should implement routers with no gateway"), cfg.StrOpt('gateway_external_network_id', default='', help="UUID of external network for routers implemented " "by the agents."), cfg.StrOpt('l3_agent_manager', default='quantum.agent.l3_agent.L3NATAgent'), ] def __init__(self, host, conf=None): if conf: self.conf = conf else: self.conf = cfg.CONF self.router_info = {} if not self.conf.interface_driver: LOG.error(_('An interface driver must be specified')) sys.exit(1) try: self.driver = importutils.import_object(self.conf.interface_driver, self.conf) except: LOG.exception( _("Error importing interface driver '%s'" % self.conf.interface_driver)) sys.exit(1) self.plugin_rpc = L3PluginApi(topics.PLUGIN, host) self.fullsync = True self.sync_sem = semaphore.Semaphore(1) if self.conf.use_namespaces: self._destroy_all_router_namespaces() super(L3NATAgent, self).__init__(host=self.conf.host) def _destroy_all_router_namespaces(self): """Destroy all router namespaces on the host to eliminate all stale linux devices, iptables rules, and namespaces. """ root_ip = ip_lib.IPWrapper(self.conf.root_helper) for ns in root_ip.get_namespaces(self.conf.root_helper): if ns.startswith(NS_PREFIX): try: self._destroy_router_namespace(ns) except: LOG.exception(_("Failed deleting namespace '%s'") % ns) def _destroy_router_namespace(self, namespace): ns_ip = ip_lib.IPWrapper(self.conf.root_helper, namespace=namespace) for d in ns_ip.get_devices(exclude_loopback=True): if d.name.startswith(INTERNAL_DEV_PREFIX): # device is on default bridge self.driver.unplug(d.name, namespace=namespace, prefix=INTERNAL_DEV_PREFIX) elif d.name.startswith(EXTERNAL_DEV_PREFIX): self.driver.unplug(d.name, bridge=self.conf.external_network_bridge, namespace=namespace, prefix=EXTERNAL_DEV_PREFIX) #(TODO) Address the failure for the deletion of the namespace def _create_router_namespace(self, ri): ip_wrapper_root = ip_lib.IPWrapper(self.conf.root_helper) ip_wrapper = ip_wrapper_root.ensure_namespace(ri.ns_name()) ip_wrapper.netns.execute(['sysctl', '-w', 'net.ipv4.ip_forward=1']) def _fetch_external_net_id(self): """Find UUID of single external network for this agent""" if self.conf.gateway_external_network_id: return self.conf.gateway_external_network_id try: return self.plugin_rpc.get_external_network_id( context.get_admin_context()) except rpc_common.RemoteError as e: if e.exc_type == 'TooManyExternalNetworks': msg = _("The 'gateway_external_network_id' must be configured" " if Quantum has more than one external network.") raise Exception(msg) else: raise def _router_added(self, router_id, router=None): ri = RouterInfo(router_id, self.conf.root_helper, self.conf.use_namespaces, router) self.router_info[router_id] = ri if self.conf.use_namespaces: self._create_router_namespace(ri) for c, r in self.metadata_filter_rules(): ri.iptables_manager.ipv4['filter'].add_rule(c, r) for c, r in self.metadata_nat_rules(): ri.iptables_manager.ipv4['nat'].add_rule(c, r) ri.iptables_manager.apply() self._spawn_metadata_agent(ri) def _router_removed(self, router_id): ri = self.router_info[router_id] for c, r in self.metadata_filter_rules(): ri.iptables_manager.ipv4['filter'].remove_rule(c, r) for c, r in self.metadata_nat_rules(): ri.iptables_manager.ipv4['nat'].remove_rule(c, r) ri.iptables_manager.apply() self._destroy_metadata_agent(ri) del self.router_info[router_id] self._destroy_router_namespace(ri.ns_name()) def _spawn_metadata_agent(self, router_info): def callback(pid_file): return [ 'quantum-ns-metadata-proxy', '--pid_file=%s' % pid_file, '--router_id=%s' % router_info.router_id, '--state_path=%s' % self.conf.state_path ] pm = external_process.ProcessManager(self.conf, router_info.router_id, self.conf.root_helper, router_info.ns_name()) pm.enable(callback) def _destroy_metadata_agent(self, router_info): pm = external_process.ProcessManager(self.conf, router_info.router_id, self.conf.root_helper, router_info.ns_name()) pm.disable() def _set_subnet_info(self, port): ips = port['fixed_ips'] if not ips: raise Exception(_("Router port %s has no IP address") % port['id']) if len(ips) > 1: LOG.error( _("Ignoring multiple IPs on router port %s") % port['id']) prefixlen = netaddr.IPNetwork(port['subnet']['cidr']).prefixlen port['ip_cidr'] = "%s/%s" % (ips[0]['ip_address'], prefixlen) def process_router(self, ri): ex_gw_port = self._get_ex_gw_port(ri) internal_ports = ri.router.get(l3_constants.INTERFACE_KEY, []) existing_port_ids = set([p['id'] for p in ri.internal_ports]) current_port_ids = set( [p['id'] for p in internal_ports if p['admin_state_up']]) new_ports = [ p for p in internal_ports if p['id'] in current_port_ids and p['id'] not in existing_port_ids ] old_ports = [ p for p in ri.internal_ports if p['id'] not in current_port_ids ] for p in new_ports: self._set_subnet_info(p) ri.internal_ports.append(p) self.internal_network_added(ri, ex_gw_port, p['network_id'], p['id'], p['ip_cidr'], p['mac_address']) for p in old_ports: ri.internal_ports.remove(p) self.internal_network_removed(ri, ex_gw_port, p['id'], p['ip_cidr']) internal_cidrs = [p['ip_cidr'] for p in ri.internal_ports] if ex_gw_port and not ri.ex_gw_port: self._set_subnet_info(ex_gw_port) self.external_gateway_added(ri, ex_gw_port, internal_cidrs) elif not ex_gw_port and ri.ex_gw_port: self.external_gateway_removed(ri, ri.ex_gw_port, internal_cidrs) if ri.ex_gw_port or ex_gw_port: self.process_router_floating_ips(ri, ex_gw_port) ri.ex_gw_port = ex_gw_port def process_router_floating_ips(self, ri, ex_gw_port): floating_ips = ri.router.get(l3_constants.FLOATINGIP_KEY, []) existing_floating_ip_ids = set([fip['id'] for fip in ri.floating_ips]) cur_floating_ip_ids = set([fip['id'] for fip in floating_ips]) id_to_fip_map = {} for fip in floating_ips: if fip['port_id']: if fip['id'] not in existing_floating_ip_ids: ri.floating_ips.append(fip) self.floating_ip_added(ri, ex_gw_port, fip['floating_ip_address'], fip['fixed_ip_address']) # store to see if floatingip was remapped id_to_fip_map[fip['id']] = fip floating_ip_ids_to_remove = (existing_floating_ip_ids - cur_floating_ip_ids) for fip in ri.floating_ips: if fip['id'] in floating_ip_ids_to_remove: ri.floating_ips.remove(fip) self.floating_ip_removed(ri, ri.ex_gw_port, fip['floating_ip_address'], fip['fixed_ip_address']) else: # handle remapping of a floating IP new_fip = id_to_fip_map[fip['id']] new_fixed_ip = new_fip['fixed_ip_address'] existing_fixed_ip = fip['fixed_ip_address'] if (new_fixed_ip and existing_fixed_ip and new_fixed_ip != existing_fixed_ip): floating_ip = fip['floating_ip_address'] self.floating_ip_removed(ri, ri.ex_gw_port, floating_ip, existing_fixed_ip) self.floating_ip_added(ri, ri.ex_gw_port, floating_ip, new_fixed_ip) ri.floating_ips.remove(fip) ri.floating_ips.append(new_fip) def _get_ex_gw_port(self, ri): return ri.router.get('gw_port') def _send_gratuitous_arp_packet(self, ri, interface_name, ip_address): if self.conf.send_arp_for_ha > 0: arping_cmd = [ 'arping', '-A', '-U', '-I', interface_name, '-c', self.conf.send_arp_for_ha, ip_address ] try: if self.conf.use_namespaces: ip_wrapper = ip_lib.IPWrapper(self.conf.root_helper, namespace=ri.ns_name()) ip_wrapper.netns.execute(arping_cmd, check_exit_code=True) else: utils.execute(arping_cmd, check_exit_code=True, root_helper=self.conf.root_helper) except Exception as e: LOG.error(_("Failed sending gratuitous ARP: %s") % str(e)) def get_internal_device_name(self, port_id): return (INTERNAL_DEV_PREFIX + port_id)[:self.driver.DEV_NAME_LEN] def get_external_device_name(self, port_id): return (EXTERNAL_DEV_PREFIX + port_id)[:self.driver.DEV_NAME_LEN] def external_gateway_added(self, ri, ex_gw_port, internal_cidrs): interface_name = self.get_external_device_name(ex_gw_port['id']) ex_gw_ip = ex_gw_port['fixed_ips'][0]['ip_address'] if not ip_lib.device_exists(interface_name, root_helper=self.conf.root_helper, namespace=ri.ns_name()): self.driver.plug(ex_gw_port['network_id'], ex_gw_port['id'], interface_name, ex_gw_port['mac_address'], bridge=self.conf.external_network_bridge, namespace=ri.ns_name(), prefix=EXTERNAL_DEV_PREFIX) self.driver.init_l3(interface_name, [ex_gw_port['ip_cidr']], namespace=ri.ns_name()) ip_address = ex_gw_port['ip_cidr'].split('/')[0] self._send_gratuitous_arp_packet(ri, interface_name, ip_address) gw_ip = ex_gw_port['subnet']['gateway_ip'] if ex_gw_port['subnet']['gateway_ip']: cmd = ['route', 'add', 'default', 'gw', gw_ip] if self.conf.use_namespaces: ip_wrapper = ip_lib.IPWrapper(self.conf.root_helper, namespace=ri.ns_name()) ip_wrapper.netns.execute(cmd, check_exit_code=False) else: utils.execute(cmd, check_exit_code=False, root_helper=self.conf.root_helper) for (c, r) in self.external_gateway_nat_rules(ex_gw_ip, internal_cidrs, interface_name): ri.iptables_manager.ipv4['nat'].add_rule(c, r) ri.iptables_manager.apply() def external_gateway_removed(self, ri, ex_gw_port, internal_cidrs): interface_name = self.get_external_device_name(ex_gw_port['id']) if ip_lib.device_exists(interface_name, root_helper=self.conf.root_helper, namespace=ri.ns_name()): self.driver.unplug(interface_name, bridge=self.conf.external_network_bridge, namespace=ri.ns_name(), prefix=EXTERNAL_DEV_PREFIX) ex_gw_ip = ex_gw_port['fixed_ips'][0]['ip_address'] for c, r in self.external_gateway_nat_rules(ex_gw_ip, internal_cidrs, interface_name): ri.iptables_manager.ipv4['nat'].remove_rule(c, r) ri.iptables_manager.apply() def metadata_filter_rules(self): rules = [] rules.append(('INPUT', '-s 0.0.0.0/0 -d 127.0.0.1 ' '-p tcp -m tcp --dport %s ' '-j ACCEPT' % self.conf.metadata_port)) return rules def metadata_nat_rules(self): rules = [] rules.append(('PREROUTING', '-s 0.0.0.0/0 -d 169.254.169.254/32 ' '-p tcp -m tcp --dport 80 -j REDIRECT ' '--to-port %s' % self.conf.metadata_port)) return rules def external_gateway_nat_rules(self, ex_gw_ip, internal_cidrs, interface_name): rules = [('POSTROUTING', '! -i %(interface_name)s ' '! -o %(interface_name)s -m conntrack ! ' '--ctstate DNAT -j ACCEPT' % locals())] for cidr in internal_cidrs: rules.extend(self.internal_network_nat_rules(ex_gw_ip, cidr)) return rules def internal_network_added(self, ri, ex_gw_port, network_id, port_id, internal_cidr, mac_address): interface_name = self.get_internal_device_name(port_id) if not ip_lib.device_exists(interface_name, root_helper=self.conf.root_helper, namespace=ri.ns_name()): self.driver.plug(network_id, port_id, interface_name, mac_address, namespace=ri.ns_name(), prefix=INTERNAL_DEV_PREFIX) self.driver.init_l3(interface_name, [internal_cidr], namespace=ri.ns_name()) ip_address = internal_cidr.split('/')[0] self._send_gratuitous_arp_packet(ri, interface_name, ip_address) if ex_gw_port: ex_gw_ip = ex_gw_port['fixed_ips'][0]['ip_address'] for c, r in self.internal_network_nat_rules( ex_gw_ip, internal_cidr): ri.iptables_manager.ipv4['nat'].add_rule(c, r) ri.iptables_manager.apply() def internal_network_removed(self, ri, ex_gw_port, port_id, internal_cidr): interface_name = self.get_internal_device_name(port_id) if ip_lib.device_exists(interface_name, root_helper=self.conf.root_helper, namespace=ri.ns_name()): self.driver.unplug(interface_name, namespace=ri.ns_name(), prefix=INTERNAL_DEV_PREFIX) if ex_gw_port: ex_gw_ip = ex_gw_port['fixed_ips'][0]['ip_address'] for c, r in self.internal_network_nat_rules( ex_gw_ip, internal_cidr): ri.iptables_manager.ipv4['nat'].remove_rule(c, r) ri.iptables_manager.apply() def internal_network_nat_rules(self, ex_gw_ip, internal_cidr): rules = [('snat', '-s %s -j SNAT --to-source %s' % (internal_cidr, ex_gw_ip))] return rules def floating_ip_added(self, ri, ex_gw_port, floating_ip, fixed_ip): ip_cidr = str(floating_ip) + '/32' interface_name = self.get_external_device_name(ex_gw_port['id']) device = ip_lib.IPDevice(interface_name, self.conf.root_helper, namespace=ri.ns_name()) if not ip_cidr in [addr['cidr'] for addr in device.addr.list()]: net = netaddr.IPNetwork(ip_cidr) device.addr.add(net.version, ip_cidr, str(net.broadcast)) self._send_gratuitous_arp_packet(ri, interface_name, floating_ip) for chain, rule in self.floating_forward_rules(floating_ip, fixed_ip): ri.iptables_manager.ipv4['nat'].add_rule(chain, rule) ri.iptables_manager.apply() def floating_ip_removed(self, ri, ex_gw_port, floating_ip, fixed_ip): ip_cidr = str(floating_ip) + '/32' net = netaddr.IPNetwork(ip_cidr) interface_name = self.get_external_device_name(ex_gw_port['id']) device = ip_lib.IPDevice(interface_name, self.conf.root_helper, namespace=ri.ns_name()) device.addr.delete(net.version, ip_cidr) for chain, rule in self.floating_forward_rules(floating_ip, fixed_ip): ri.iptables_manager.ipv4['nat'].remove_rule(chain, rule) ri.iptables_manager.apply() def floating_forward_rules(self, floating_ip, fixed_ip): return [ ('PREROUTING', '-d %s -j DNAT --to %s' % (floating_ip, fixed_ip)), ('OUTPUT', '-d %s -j DNAT --to %s' % (floating_ip, fixed_ip)), ('float-snat', '-s %s -j SNAT --to %s' % (fixed_ip, floating_ip)) ] def router_deleted(self, context, router_id): """Deal with router deletion RPC message.""" with self.sync_sem: if router_id in self.router_info: try: self._router_removed(router_id) except Exception: msg = _("Failed dealing with router " "'%s' deletion RPC message") LOG.debug(msg, router_id) self.fullsync = True def routers_updated(self, context, routers): """Deal with routers modification and creation RPC message.""" if not routers: return with self.sync_sem: try: self._process_routers(routers) except Exception: msg = _("Failed dealing with routers update RPC message") LOG.debug(msg) self.fullsync = True def _process_routers(self, routers): if (self.conf.external_network_bridge and not ip_lib.device_exists(self.conf.external_network_bridge)): LOG.error( _("The external network bridge '%s' does not exist") % self.conf.external_network_bridge) return target_ex_net_id = self._fetch_external_net_id() for r in routers: if not r['admin_state_up']: continue # If namespaces are disabled, only process the router associated # with the configured agent id. if (not self.conf.use_namespaces and r['id'] != self.conf.router_id): continue ex_net_id = (r['external_gateway_info'] or {}).get('network_id') if not ex_net_id and not self.conf.handle_internal_only_routers: continue if ex_net_id and ex_net_id != target_ex_net_id: continue if r['id'] not in self.router_info: self._router_added(r['id']) ri = self.router_info[r['id']] ri.router = r self.process_router(ri) @periodic_task.periodic_task def _sync_routers_task(self, context): # we need to sync with router deletion RPC message with self.sync_sem: if self.fullsync: try: if not self.conf.use_namespaces: router_id = self.conf.router_id else: router_id = None routers = self.plugin_rpc.get_routers(context, router_id) self.router_info = {} self._process_routers(routers) self.fullsync = False except Exception: LOG.exception(_("Failed synchronizing routers")) self.fullsync = True def after_start(self): LOG.info(_("L3 agent started"))
from quantum.openstack.common import log as logging from quantum.openstack.common import rpc from quantum.plugins.bigswitch.version import version_string_with_vcs LOG = logging.getLogger(__name__) database_opts = [ cfg.StrOpt('sql_connection', default='sqlite://'), cfg.IntOpt('sql_max_retries', default=-1), cfg.IntOpt('reconnect_interval', default=2), ] restproxy_opts = [ cfg.StrOpt('servers', default='localhost:8800'), cfg.StrOpt('serverauth', default='username:password'), cfg.BoolOpt('serverssl', default=False), cfg.BoolOpt('syncdata', default=False), cfg.IntOpt('servertimeout', default=10), ] cfg.CONF.register_opts(database_opts, "DATABASE") cfg.CONF.register_opts(restproxy_opts, "RESTPROXY") # The following are used to invoke the API on the external controller NET_RESOURCE_PATH = "/tenants/%s/networks" PORT_RESOURCE_PATH = "/tenants/%s/networks/%s/ports" NETWORKS_PATH = "/tenants/%s/networks/%s" PORTS_PATH = "/tenants/%s/networks/%s/ports/%s" ATTACHMENT_PATH = "/tenants/%s/networks/%s/ports/%s/attachment" SUCCESS_CODES = range(200, 207) FAILURE_CODES = [
cfg.StrOpt('sql_connection', default='sqlite://'), cfg.IntOpt('sql_max_retries', default=-1), cfg.IntOpt('reconnect_interval', default=2), ] ovs_opts = [ cfg.StrOpt('integration_bridge', default='br-int'), cfg.StrOpt('tunnel_bridge', default='br-tun'), cfg.StrOpt('local_ip', default='10.0.0.3'), cfg.ListOpt('bridge_mappings', default=DEFAULT_BRIDGE_MAPPINGS, help="List of <physical_network>:<bridge>"), cfg.ListOpt('network_vlan_ranges', default=DEFAULT_VLAN_RANGES, help="List of <physical_network>:<vlan_min>:<vlan_max> " "or <physical_network>"), cfg.ListOpt('tunnel_id_ranges', default=DEFAULT_TUNNEL_RANGES, help="List of <tun_min>:<tun_max>"), ] agent_opts = [ cfg.IntOpt('polling_interval', default=2), cfg.StrOpt('root_helper', default='sudo'), cfg.BoolOpt('rpc', default=True), ] cfg.CONF.register_opts(database_opts, "DATABASE") cfg.CONF.register_opts(ovs_opts, "OVS") cfg.CONF.register_opts(agent_opts, "AGENT")
help='SSL cert file (valid only if SSL enabled)'), cfg.StrOpt('kombu_ssl_ca_certs', default='', help=('SSL certification authority file ' '(valid only if SSL enabled)')), cfg.StrOpt('rabbit_host', default='localhost', help='The RabbitMQ broker address where a single node is used'), cfg.IntOpt('rabbit_port', default=5672, help='The RabbitMQ broker port where a single node is used'), cfg.ListOpt('rabbit_hosts', default=['$rabbit_host:$rabbit_port'], help='RabbitMQ HA cluster host:port pairs'), cfg.BoolOpt('rabbit_use_ssl', default=False, help='connect over SSL for RabbitMQ'), cfg.StrOpt('rabbit_userid', default='guest', help='the RabbitMQ userid'), cfg.StrOpt('rabbit_password', default='guest', help='the RabbitMQ password'), cfg.StrOpt('rabbit_virtual_host', default='/', help='the RabbitMQ virtual host'), cfg.IntOpt('rabbit_retry_interval', default=1, help='how frequently to retry connecting with RabbitMQ'), cfg.IntOpt('rabbit_retry_backoff', default=2, help='how long to backoff for between retries when connecting ' 'to RabbitMQ'),
vlan_opts = [ cfg.IntOpt('vlan_start', default=1000), cfg.IntOpt('vlan_end', default=3000), ] database_opts = [ cfg.StrOpt('sql_connection', default='sqlite://'), cfg.IntOpt('reconnect_interval', default=2), ] bridge_opts = [ cfg.StrOpt('physical_interface', default='eth1'), ] agent_opts = [ cfg.IntOpt('polling_interval', default=2), cfg.StrOpt('root_helper', default='sudo'), cfg.BoolOpt('target_v2_api', default=False), ] def parse(config_file): conf = cfg.ConfigOpts() conf(args=[], default_config_files=[config_file]) conf.register_opts(vlan_opts, "VLANS") conf.register_opts(database_opts, "DATABASE") conf.register_opts(bridge_opts, "LINUX_BRIDGE") conf.register_opts(agent_opts, "AGENT") return conf