From 0e9f3189ca87d181164484deda1f15de20b37a33 Mon Sep 17 00:00:00 2001 From: Andy Bavier Date: Tue, 1 Oct 2013 10:51:29 -0400 Subject: [PATCH] Set up dnsmasq for Public networks --- plugins/planetstack-net.py | 148 ++++++++++++++++++++++++------------- 1 file changed, 98 insertions(+), 50 deletions(-) diff --git a/plugins/planetstack-net.py b/plugins/planetstack-net.py index e23744e..1a686d4 100644 --- a/plugins/planetstack-net.py +++ b/plugins/planetstack-net.py @@ -32,6 +32,16 @@ import logger plugin = "planetstack-net" +nat_net_name = "nat-net" +nat_net_id = None +site_net_id = None + +quantum_auth_url = "http://viccidev1:5000/v2.0/" +quantum_username = None +quantum_password = None +quantum_tenant_name = None + + # Helper functions for converting to CIDR notation def get_net_size(netmask): binary_str = '' @@ -144,34 +154,33 @@ def dnsmasq_sighup(dev): except: logger.log("%s: Sending SIGHUP to dnsmasq FAILED on dev %s" % (plugin, dev)) -# Enable dnsmasq for this interface +# Enable dnsmasq for this interface. +# It's possible that we could get by with a single instance of dnsmasq running on +# all devices but I haven't tried it. def start_dnsmasq(dev, interface): if not dnsmasq_running(dev): + # The '--dhcp-range=,static' argument to dnsmasq ensures that it only + # hands out IP addresses to clients listed in the hostsfile + cmd = ['/usr/sbin/dnsmasq', + '--strict-order', + '--bind-interfaces', + '--local=//', + '--domain-needed', + '--pid-file=%s' % get_pidfile(dev), + '--conf-file=', + '--interface=%s' % dev, + '--except-interface=lo', + '--dhcp-leasefile=%s' % get_leasefile(dev), + '--dhcp-hostsfile=%s' % get_hostsfile(dev), + '--dhcp-no-override', + '--dhcp-range=%s,static' % interface['ip']] + try: logger.log('%s: starting dnsmasq on device %s' % (plugin, dev)) - iprange = ipaddr_range(interface['network'], interface['broadcast']) - logger.log('%s: IP range: %s' % (plugin, iprange)) - subprocess.check_call(['/usr/sbin/dnsmasq', - '--strict-order', - '--bind-interfaces', - '--local=//', - '--domain-needed', - '--pid-file=%s' % get_pidfile(dev), - '--conf-file=', - '--interface=%s' % dev, - '--dhcp-range=%s,120' % iprange, - '--dhcp-leasefile=%s' % get_leasefile(dev), - '--dhcp-hostsfile=%s' % get_hostsfile(dev), - '--dhcp-no-override']) + subprocess.check_call(cmd) except: logger.log('%s: FAILED to start dnsmasq for device %s' % (plugin, dev)) - -nat_net_name = "nat-net" -nat_net_id = None -quantum_auth_url = "http://viccidev1:5000/v2.0/" -quantum_username = None -quantum_password = None -quantum_tenant_name = None + logger.log(' '.join(cmd)) def convert_ovs_output_to_dict(out): decoded = json.loads(out.strip()) @@ -210,30 +219,36 @@ def convert_ovs_output_to_dict(out): # 2) Sets up iptables rules in the 'planetstack-net' chain based on # the nat:forward_ports field in the Port record. -def process_quantum_ports(dev): +def get_local_quantum_ports(): + ports = [] + # Get local information for VM interfaces from OvS ovs_out = subprocess.check_output(['/usr/bin/ovs-vsctl', '-f', 'json', 'find', 'Interface', 'external_ids:iface-id!="absent"']) records = convert_ovs_output_to_dict(ovs_out) - # Extract Quantum Port IDs from OvS records - port_ids = [] - for rec in records: - port_ids.append(rec['external_ids']['iface-id']) + if records: + # Extract Quantum Port IDs from OvS records + port_ids = [] + for rec in records: + port_ids.append(rec['external_ids']['iface-id']) - # Get the full info on these ports from Quantum - quantum = client.Client(username=quantum_username, - password=quantum_password, - tenant_name=quantum_tenant_name, - auth_url=quantum_auth_url) - ports = quantum.list_ports(id=port_ids) - # logger.log("%s: %s" % (plugin, ports)) + # Get the full info on these ports from Quantum + quantum = client.Client(username=quantum_username, + password=quantum_password, + tenant_name=quantum_tenant_name, + auth_url=quantum_auth_url) + ports = quantum.list_ports(id=port_ids)['ports'] + return ports + + +def write_dnsmasq_hostsfile(dev, ports, net_id): # Write relevant entries to dnsmasq hostsfile logger.log("%s: Writing hostsfile for %s" % (plugin, dev)) f = open(get_hostsfile(dev), 'w') - for port in ports['ports']: - if port['network_id'] == nat_net_id: + for port in ports: + if port['network_id'] == net_id: entry = "%s,%s\n" % (port['mac_address'], port['fixed_ips'][0]['ip_address']) f.write(entry) logger.log("%s: %s" % (plugin, entry)) @@ -242,8 +257,9 @@ def process_quantum_ports(dev): # Send SIGHUP to dnsmasq to make it re-read hostsfile dnsmasq_sighup(dev) +def set_up_port_forwarding(dev, ports): # Set up iptables rules for port forwarding - for port in ports['ports']: + for port in ports: if port['network_id'] == nat_net_id: for fw in port['nat:forward_ports']: ipaddr = port['fixed_ips'][0]['ip_address'] @@ -256,12 +272,20 @@ def process_quantum_ports(dev): add_iptables_rule('nat', plugin, ['-i', 'br-eth0', '-p', protocol, '--dport', fwport, '-j', 'DNAT', '--to-destination', ipaddr]) - + +def get_net_id_by_name(name): + quantum = client.Client(username=quantum_username, + password=quantum_password, + tenant_name=quantum_tenant_name, + auth_url=quantum_auth_url) + + net = quantum.list_networks(name=name) + return net['networks'][0]['id'] + def start(): global quantum_username global quantum_password global quantum_tenant_name - global nat_net_id logger.log("%s: plugin starting up..." % plugin) @@ -271,18 +295,32 @@ def start(): quantum_password = parser.get("DEFAULT", "quantum_admin_password") quantum_tenant_name = parser.get("DEFAULT", "quantum_admin_tenant_name") - quantum = client.Client(username=quantum_username, - password=quantum_password, - tenant_name=quantum_tenant_name, - auth_url=quantum_auth_url) - net = quantum.list_networks(name=nat_net_name) - nat_net_id = net['networks'][0]['id'] +def GetSlivers(data, config=None, plc=None): + global nat_net_id + global site_net_id + + if not nat_net_id: + try: + nat_net_id = get_net_id_by_name(nat_net_name) + logger.log("%s: %s id is %s..." % (plugin, nat_net_name, nat_net_id)) + except: + logger.log("%s: no network called %s..." % (plugin, nat_net_name)) - logger.log("%s: %s id is %s..." % (plugin, nat_net_name, nat_net_id)) -def GetSlivers(data, config=None, plc=None): + # Fix me + # site_net_name = "devel" + site_net_name = "sharednet1" + if not site_net_id: + try: + site_net_id = get_net_id_by_name(site_net_name) + logger.log("%s: %s id is %s..." % (plugin, site_net_name, site_net_id)) + except: + logger.log("%s: no network called %s..." % (plugin, site_net_name)) + reset_iptables_chain() + ports = get_local_quantum_ports() + for interface in data['interfaces']: try: settings = plc.GetInterfaceTags({'interface_tag_id': interface['interface_tag_ids']}) @@ -301,8 +339,18 @@ def GetSlivers(data, config=None, plc=None): continue logger.log('%s: Processing device %s' % (plugin, dev)) - - if 'NAT' in tags: + + # Process Private-Nat networks + if 'NAT' in tags and nat_net_id: add_iptables_masq(dev, interface) - process_quantum_ports(dev) + write_dnsmasq_hostsfile(dev, ports, nat_net_id) + set_up_port_forwarding(dev, ports) start_dnsmasq(dev, interface) + + # Process Public networks + if interface['is_primary'] and site_net_id: + if 'OVS_BRIDGE' in tags: + dev = tags['OVS_BRIDGE'] + write_dnsmasq_hostsfile(dev, ports, site_net_id) + start_dnsmasq(dev, interface) + -- 2.47.0