diff options
| author | Deepak Garg <deepak.garg@citrix.com> | 2012-01-13 16:03:45 +0530 |
|---|---|---|
| committer | Vishvananda Ishaya <vishvananda@gmail.com> | 2012-01-24 22:31:35 -0800 |
| commit | fe1c97ff4c36d1cc2642d9a485f82874e4b3bda2 (patch) | |
| tree | 522e18112c95cb2006dbb6798af98ee9b11fa08c | |
| parent | 2594e480b2d90490a92865afbeecda35b29320d6 (diff) | |
| download | nova-fe1c97ff4c36d1cc2642d9a485f82874e4b3bda2.tar.gz nova-fe1c97ff4c36d1cc2642d9a485f82874e4b3bda2.tar.xz nova-fe1c97ff4c36d1cc2642d9a485f82874e4b3bda2.zip | |
Blueprint xenapi-provider-firewall and Bug #915403.
1. Provides dom0 IPtables driver to implement the Provider firewall rules.
2. Existing libvirt code has been refactored to reduce the amount of duplicated code to a minimum
3. The three provider apis in ec2/admin.py file are now fixed the following way:
a. remove_external_address_block returned 'OK' on removing blocks which didn't exist. This is now fixed.
b. block_external_addresses raised exception earlier on duplicate network blocks. Now the exception is logged and failed status message is returned.
c. all the three provider apis now logs for invalid and improper inputs and return uniform (a dictionary ) and proper status messages for all cases.
4. appropriate unit tests added to cover the same
Change-Id: I27d83186f850423a6268947aed0c9a349d8f8d65
| -rw-r--r-- | Authors | 1 | ||||
| -rw-r--r-- | nova/api/ec2/admin.py | 41 | ||||
| -rw-r--r-- | nova/compute/api.py | 2 | ||||
| -rw-r--r-- | nova/compute/manager.py | 4 | ||||
| -rwxr-xr-x | nova/network/linux_net.py | 9 | ||||
| -rw-r--r-- | nova/tests/api/ec2/test_admin.py | 59 | ||||
| -rw-r--r-- | nova/tests/test_xenapi.py | 60 | ||||
| -rw-r--r-- | nova/tests/xenapi/stubs.py | 1 | ||||
| -rw-r--r-- | nova/utils.py | 4 | ||||
| -rw-r--r-- | nova/virt/driver.py | 4 | ||||
| -rw-r--r-- | nova/virt/firewall.py | 47 | ||||
| -rw-r--r-- | nova/virt/libvirt/firewall.py | 45 | ||||
| -rw-r--r-- | nova/virt/xenapi/firewall.py | 56 | ||||
| -rw-r--r-- | nova/virt/xenapi/vmops.py | 3 | ||||
| -rw-r--r-- | nova/virt/xenapi_conn.py | 3 |
15 files changed, 263 insertions, 76 deletions
@@ -41,6 +41,7 @@ Dave Walker <DaveWalker@ubuntu.com> David Pravec <David.Pravec@danix.org> David Subiros <david.perez5@hp.com> Dean Troyer <dtroyer@gmail.com> +Deepak Garg <deepak.garg@citrix.com> Derek Higgins <higginsd@gmail.com> Devendra Modium <dmodium@isi.edu> Devin Carlen <devin.carlen@gmail.com> diff --git a/nova/api/ec2/admin.py b/nova/api/ec2/admin.py index 80a30659d..4e81debe4 100644 --- a/nova/api/ec2/admin.py +++ b/nova/api/ec2/admin.py @@ -349,8 +349,15 @@ class AdminController(object): LOG.audit(_('Blocking traffic to all projects incoming from %s'), cidr, context=context) cidr = urllib.unquote(cidr).decode() - # raise if invalid - netaddr.IPNetwork(cidr) + failed = {'status': 'Failed', 'message': ' 0 rules added'} + if not utils.is_valid_cidr(cidr): + msg = 'Improper input. Please provide a valid cidr: ' \ + 'e.g. 121.12.10.11/24.' + failed['message'] = msg + failed['message'] + return failed + #Normalizing cidr. e.g. '20.20.20.11/24' -> '20.20.20.0/24', so that + #db values stay in sync with filters' values (e.g. in iptables) + cidr = str(netaddr.IPNetwork(cidr).cidr) rule = {'cidr': cidr} tcp_rule = rule.copy() tcp_rule.update({'protocol': 'tcp', 'from_port': 1, 'to_port': 65535}) @@ -370,7 +377,9 @@ class AdminController(object): db.provider_fw_rule_create(context, icmp_rule) rules_added += 1 if not rules_added: - raise exception.ApiError(_('Duplicate rule')) + msg = 'Duplicate Rule.' + failed['message'] = msg + failed['message'] + return failed self.compute_api.trigger_provider_fw_rules_refresh(context) return {'status': 'OK', 'message': 'Added %s rules' % rules_added} @@ -385,11 +394,25 @@ class AdminController(object): def remove_external_address_block(self, context, cidr): LOG.audit(_('Removing ip block from %s'), cidr, context=context) cidr = urllib.unquote(cidr).decode() - # raise if invalid - netaddr.IPNetwork(cidr) + # Catch the exception and LOG for improper or malicious inputs. + # Also return a proper status and message in that case + failed = {'status': 'Failed', 'message': ' 0 rules deleted'} + if not utils.is_valid_cidr(cidr): + msg = 'Improper input. Please provide a valid cidr: ' \ + 'e.g. 121.12.10.11/24.' + failed['message'] = msg + failed['message'] + return failed + #Normalizing cidr. e.g. '20.20.20.11/24' -> '20.20.20.0/24', so that + #db values stay in sync with filters' values (e.g. in iptables) + cidr = str(netaddr.IPNetwork(cidr).cidr) rules = db.provider_fw_rule_get_all_by_cidr(context, cidr) - for rule in rules: - db.provider_fw_rule_destroy(context, rule['id']) - if rules: + + if not rules: + msg = 'No such CIDR currently blocked.' + failed['message'] = msg + failed['message'] + return failed + else: + for rule in rules: + db.provider_fw_rule_destroy(context, rule['id']) self.compute_api.trigger_provider_fw_rules_refresh(context) - return {'status': 'OK', 'message': 'Deleted %s rules' % len(rules)} + return {'status': 'OK', 'message': 'Deleted %s rules' % len(rules)} diff --git a/nova/compute/api.py b/nova/compute/api.py index a4c228e26..0e874358b 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -710,7 +710,7 @@ class API(base.Base): "args": {"security_group_id": group_id}}) def trigger_provider_fw_rules_refresh(self, context): - """Called when a rule is added to or removed from a security_group""" + """Called when a rule is added/removed from a provider firewall""" hosts = [x['host'] for (x, idx) in self.db.service_get_all_compute_sorted(context)] diff --git a/nova/compute/manager.py b/nova/compute/manager.py index f43c7a1a0..59e228e45 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -261,9 +261,9 @@ class ComputeManager(manager.SchedulerDependentManager): return self.driver.refresh_security_group_members(security_group_id) @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id()) - def refresh_provider_fw_rules(self, context, **_kwargs): + def refresh_provider_fw_rules(self, context, **kwargs): """This call passes straight through to the virtualization driver.""" - return self.driver.refresh_provider_fw_rules() + return self.driver.refresh_provider_fw_rules(**kwargs) def _get_instance_nw_info(self, context, instance): """Get a list of dictionaries of network data of an instance. diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index fa5e514b9..996f89a5f 100755 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -303,16 +303,17 @@ class IptablesManager(object): for cmd, tables in s: for table in tables: - current_table, _ = self.execute('%s-save' % (cmd,), - '-t', '%s' % (table,), - run_as_root=True, - attempts=5) + current_table, _err = self.execute('%s-save' % (cmd,), + '-t', '%s' % (table,), + run_as_root=True, + attempts=5) current_lines = current_table.split('\n') new_filter = self._modify_rules(current_lines, tables[table]) self.execute('%s-restore' % (cmd,), run_as_root=True, process_input='\n'.join(new_filter), attempts=5) + LOG.debug(_("IPTablesManager.apply completed with success")) def _modify_rules(self, current_lines, table, binary=None): unwrapped_chains = table.unwrapped_chains diff --git a/nova/tests/api/ec2/test_admin.py b/nova/tests/api/ec2/test_admin.py index 2b4e463ee..62eb596f3 100644 --- a/nova/tests/api/ec2/test_admin.py +++ b/nova/tests/api/ec2/test_admin.py @@ -365,24 +365,43 @@ class AdminControllerTestCase(test.TestCase): hosts = self._ac.describe_hosts(self._c)['hosts'] self.assertEqual('volume1', hosts[0]['hostname']) - def test_block_external_addresses(self): + def test_block_external_addresses_validate_output_for_valid_input(self): result = self._ac.block_external_addresses(self._c, '192.168.100.1/24') self.assertEqual('OK', result['status']) self.assertEqual('Added 3 rules', result['message']) - def test_block_external_addresses_already_existent_rule(self): - self._ac.block_external_addresses(self._c, '192.168.100.1/24') - self.assertRaises(exception.ApiError, - self._ac.block_external_addresses, - self._c, '192.168.100.1/24') + def test_block_external_addresses_validate_output_for_invalid_input(self): + result = self._ac.block_external_addresses(self._c, '12.10.10.256/24') + self.assertEqual('Failed', result['status']) + value = '0 rules added' in result['message'] + self.assertEqual(value, True) - def test_describe_external_address_blocks(self): - self._ac.block_external_addresses(self._c, '192.168.100.1/24') + def test_block_external_addresses_already_existent_rule(self): + self._ac.block_external_addresses(self._c, '192.168.100.0/24') + result = self._ac.block_external_addresses(self._c, '192.168.100.0/24') + self.assertEqual('Failed', result['status']) + value = '0 rules added' in result['message'] + self.assertEqual(value, True) + + def test_describe_external_address_blocks_normalized_output(self): + self._ac.block_external_addresses(self._c, '192.168.100.11/24') self.assertEqual( - {'externalIpBlockInfo': [{'cidr': u'192.168.100.1/24'}]}, + {'externalIpBlockInfo': [{'cidr': u'192.168.100.0/24'}]}, self._ac.describe_external_address_blocks(self._c)) - def test_remove_external_address_block(self): + def test_describe_external_address_blocks_many_inputs(self): + self._ac.block_external_addresses(self._c, '192.168.100.11/24') + self._ac.block_external_addresses(self._c, '12.12.12.10/24') + self._ac.block_external_addresses(self._c, '18.18.18.0/24') + output1 = {'cidr': u'192.168.100.0/24'} + output2 = {'cidr': u'12.12.12.0/24'} + output3 = {'cidr': u'18.18.18.0/24'} + result = self._ac.describe_external_address_blocks(self._c) + result = sorted(result['externalIpBlockInfo']) + output = sorted([output1, output2, output3]) + self.assertEqual(result, output) + + def test_remove_external_address_block_existent_rule(self): self._ac.block_external_addresses(self._c, '192.168.100.1/24') result = self._ac.remove_external_address_block(self._c, @@ -393,6 +412,26 @@ class AdminControllerTestCase(test.TestCase): result = self._ac.describe_external_address_blocks(self._c) self.assertEqual([], result['externalIpBlockInfo']) + def test_remove_external_address_block_non_existent_rule(self): + result = self._ac.remove_external_address_block(self._c, + '192.168.100.1/24') + self.assertEqual('Failed', result['status']) + value = '0 rules deleted' in result['message'] + self.assertEqual(value, True) + + result = self._ac.describe_external_address_blocks(self._c) + self.assertEqual([], result['externalIpBlockInfo']) + + def test_remove_external_address_block_invalid_input(self): + result = self._ac.remove_external_address_block(self._c, + '192.168.100/24') + self.assertEqual('Failed', result['status']) + value = '0 rules deleted' in result['message'] + self.assertEqual(value, True) + + result = self._ac.describe_external_address_blocks(self._c) + self.assertEqual([], result['externalIpBlockInfo']) + def test_start_vpn(self): def fake_launch_vpn_instance(self, *args): diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py index c3730b3ca..482cd450c 100644 --- a/nova/tests/test_xenapi.py +++ b/nova/tests/test_xenapi.py @@ -1334,6 +1334,9 @@ class XenAPIBWUsageTestCase(test.TestCase): self.assertEqual(result, []) +# TODO(salvatore-orlando): this class and +# nova.tests.test_libvirt.IPTablesFirewallDriverTestCase share a lot of code. +# Consider abstracting common code in a base class for firewall driver testing. class XenAPIDom0IptablesFirewallTestCase(test.TestCase): _in_nat_rules = [ @@ -1581,3 +1584,60 @@ class XenAPIDom0IptablesFirewallTestCase(test.TestCase): self.assertTrue(len(filter(regex.match, self._out_rules)) > 0, "Rules were not updated properly." "The rule for UDP acceptance is missing") + + def test_provider_firewall_rules(self): + # setup basic instance data + instance_ref = self._create_instance_ref() + # FRAGILE: as in libvirt tests + # peeks at how the firewall names chains + chain_name = 'inst-%s' % instance_ref['id'] + + network_info = fake_network.fake_get_instance_nw_info(self.stubs, 1, 1) + self.fw.prepare_instance_filter(instance_ref, network_info) + self.assertTrue('provider' in self.fw.iptables.ipv4['filter'].chains) + rules = [rule for rule in self.fw.iptables.ipv4['filter'].rules + if rule.chain == 'provider'] + self.assertEqual(0, len(rules)) + + admin_ctxt = context.get_admin_context() + # add a rule and send the update message, check for 1 rule + provider_fw0 = db.provider_fw_rule_create(admin_ctxt, + {'protocol': 'tcp', + 'cidr': '10.99.99.99/32', + 'from_port': 1, + 'to_port': 65535}) + self.fw.refresh_provider_fw_rules() + rules = [rule for rule in self.fw.iptables.ipv4['filter'].rules + if rule.chain == 'provider'] + self.assertEqual(1, len(rules)) + + # Add another, refresh, and make sure number of rules goes to two + provider_fw1 = db.provider_fw_rule_create(admin_ctxt, + {'protocol': 'udp', + 'cidr': '10.99.99.99/32', + 'from_port': 1, + 'to_port': 65535}) + self.fw.refresh_provider_fw_rules() + rules = [rule for rule in self.fw.iptables.ipv4['filter'].rules + if rule.chain == 'provider'] + self.assertEqual(2, len(rules)) + + # create the instance filter and make sure it has a jump rule + self.fw.prepare_instance_filter(instance_ref, network_info) + self.fw.apply_instance_filter(instance_ref, network_info) + inst_rules = [rule for rule in self.fw.iptables.ipv4['filter'].rules + if rule.chain == chain_name] + jump_rules = [rule for rule in inst_rules if '-j' in rule.rule] + provjump_rules = [] + # IptablesTable doesn't make rules unique internally + for rule in jump_rules: + if 'provider' in rule.rule and rule not in provjump_rules: + provjump_rules.append(rule) + self.assertEqual(1, len(provjump_rules)) + + # remove a rule from the db, cast to compute to refresh rule + db.provider_fw_rule_destroy(admin_ctxt, provider_fw1['id']) + self.fw.refresh_provider_fw_rules() + rules = [rule for rule in self.fw.iptables.ipv4['filter'].rules + if rule.chain == 'provider'] + self.assertEqual(1, len(rules)) diff --git a/nova/tests/xenapi/stubs.py b/nova/tests/xenapi/stubs.py index 0c707e14e..2dfece00f 100644 --- a/nova/tests/xenapi/stubs.py +++ b/nova/tests/xenapi/stubs.py @@ -32,7 +32,6 @@ def stubout_firewall_driver(stubs, conn): return vmops = conn._vmops - stubs.Set(vmops.firewall_driver, 'setup_basic_filtering', fake_none) stubs.Set(vmops.firewall_driver, 'prepare_instance_filter', fake_none) stubs.Set(vmops.firewall_driver, 'instance_filter_exists', fake_none) diff --git a/nova/utils.py b/nova/utils.py index bd68c6966..818dc2b73 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -1075,12 +1075,12 @@ def monkey_patch(): if isinstance(module_data[key], pyclbr.Class): clz = import_class("%s.%s" % (module, key)) for method, func in inspect.getmembers(clz, inspect.ismethod): - setattr(clz, method,\ + setattr(clz, method, decorator("%s.%s.%s" % (module, key, method), func)) # set the decorator for the function if isinstance(module_data[key], pyclbr.Function): func = import_class("%s.%s" % (module, key)) - setattr(sys.modules[module], key,\ + setattr(sys.modules[module], key, decorator("%s.%s" % (module, key), func)) diff --git a/nova/virt/driver.py b/nova/virt/driver.py index 7a9347542..fa40160f6 100644 --- a/nova/virt/driver.py +++ b/nova/virt/driver.py @@ -380,7 +380,7 @@ class ComputeDriver(object): * another host 'H1' runs an instance 'i-1' * instance 'i-1' is a member of security group 'b' - When 'i-1' launches or terminates we will recieve the message + When 'i-1' launches or terminates we will receive the message to update members of group 'b', at which time we will make any changes needed to the rules for instance 'i-0' to allow or deny traffic coming from 'i-1', depending on if it is being @@ -399,7 +399,7 @@ class ComputeDriver(object): # TODO(Vek): Need to pass context in for access to auth_token raise NotImplementedError() - def refresh_provider_fw_rules(self, security_group_id): + def refresh_provider_fw_rules(self): """This triggers a firewall update based on database changes. When this is called, rules have either been added or removed from the diff --git a/nova/virt/firewall.py b/nova/virt/firewall.py index 3426120ac..ed60051d9 100644 --- a/nova/virt/firewall.py +++ b/nova/virt/firewall.py @@ -34,7 +34,7 @@ flags.DEFINE_bool('allow_same_net_traffic', class FirewallDriver(object): """ Firewall Driver base class. - Defines methos that any driver providing security groups + Defines methods that any driver providing security groups and provider fireall functionality should implement. """ def prepare_instance_filter(self, instance, network_info): @@ -129,12 +129,18 @@ class IptablesFirewallDriver(FirewallDriver): self.instances[instance['id']] = instance self.network_infos[instance['id']] = network_info self.add_filters_for_instance(instance) + LOG.debug(_('Filters added to the instance: %r'), instance) + self.refresh_provider_fw_rules() + LOG.debug(_('Provider Firewall Rules refreshed')) self.iptables.apply() def _create_filter(self, ips, chain_name): return ['-d %s -j $%s' % (ip, chain_name) for ip in ips] def _filters_for_instance(self, chain_name, network_info): + """Creates a rule corresponding to each ip that defines a + jump to the corresponding instance - chain for all the traffic + destined to that ip""" ips_v4 = [ip['ip'] for (_n, mapping) in network_info for ip in mapping['ips']] ipv4_rules = self._create_filter(ips_v4, chain_name) @@ -190,6 +196,10 @@ class IptablesFirewallDriver(FirewallDriver): ipv4_rules += ['-m state --state ESTABLISHED,RELATED -j ACCEPT'] ipv6_rules += ['-m state --state ESTABLISHED,RELATED -j ACCEPT'] + # Pass through provider-wide drops + ipv4_rules += ['-j $provider'] + ipv6_rules += ['-j $provider'] + def _do_dhcp_rules(self, ipv4_rules, network_info): dhcp_servers = [info['dhcp_server'] for (_n, info) in network_info] @@ -345,3 +355,38 @@ class IptablesFirewallDriver(FirewallDriver): for instance in self.instances.values(): self.remove_filters_for_instance(instance) self.add_filters_for_instance(instance) + + def refresh_provider_fw_rules(self): + """See class:FirewallDriver: docs.""" + self._do_refresh_provider_fw_rules() + self.iptables.apply() + + @utils.synchronized('iptables', external=True) + def _do_refresh_provider_fw_rules(self): + """Internal, synchronized version of refresh_provider_fw_rules.""" + self._purge_provider_fw_rules() + self._build_provider_fw_rules() + + def _purge_provider_fw_rules(self): + """Remove all rules from the provider chains.""" + self.iptables.ipv4['filter'].empty_chain('provider') + if FLAGS.use_ipv6: + self.iptables.ipv6['filter'].empty_chain('provider') + + def _build_provider_fw_rules(self): + """Create all rules for the provider IP DROPs.""" + self.iptables.ipv4['filter'].add_chain('provider') + if FLAGS.use_ipv6: + self.iptables.ipv6['filter'].add_chain('provider') + ipv4_rules, ipv6_rules = self._provider_rules() + for rule in ipv4_rules: + self.iptables.ipv4['filter'].add_rule('provider', rule) + + if FLAGS.use_ipv6: + for rule in ipv6_rules: + self.iptables.ipv6['filter'].add_rule('provider', rule) + + @staticmethod + def _provider_rules(): + """Generate a list of rules from provider for IP4 & IP6.""" + raise NotImplementedError() diff --git a/nova/virt/libvirt/firewall.py b/nova/virt/libvirt/firewall.py index 9b9e3540e..3e299b932 100644 --- a/nova/virt/libvirt/firewall.py +++ b/nova/virt/libvirt/firewall.py @@ -259,7 +259,7 @@ class NWFilterFirewall(base_firewall.FirewallDriver): LOG.debug(_('The nwfilter(%(instance_filter_name)s) ' 'for %(instance_name)s is not found.') % locals()) - instance_secgroup_filter_name =\ + instance_secgroup_filter_name = \ '%s-secgroup' % (self._instance_filter_name(instance)) try: @@ -486,53 +486,10 @@ class IptablesFirewallDriver(base_firewall.IptablesFirewallDriver): LOG.info(_('Attempted to unfilter instance %s which is not ' 'filtered'), instance['id']) - def _do_basic_rules(self, ipv4_rules, ipv6_rules, network_info): - # Always drop invalid packets - ipv4_rules += ['-m state --state ' 'INVALID -j DROP'] - ipv6_rules += ['-m state --state ' 'INVALID -j DROP'] - - # Allow established connections - ipv4_rules += ['-m state --state ESTABLISHED,RELATED -j ACCEPT'] - ipv6_rules += ['-m state --state ESTABLISHED,RELATED -j ACCEPT'] - - # Pass through provider-wide drops - ipv4_rules += ['-j $provider'] - ipv6_rules += ['-j $provider'] - def instance_filter_exists(self, instance, network_info): """Check nova-instance-instance-xxx exists""" return self.nwfilter.instance_filter_exists(instance, network_info) - def refresh_provider_fw_rules(self): - """See class:FirewallDriver: docs.""" - self._do_refresh_provider_fw_rules() - self.iptables.apply() - - @utils.synchronized('iptables', external=True) - def _do_refresh_provider_fw_rules(self): - """Internal, synchronized version of refresh_provider_fw_rules.""" - self._purge_provider_fw_rules() - self._build_provider_fw_rules() - - def _purge_provider_fw_rules(self): - """Remove all rules from the provider chains.""" - self.iptables.ipv4['filter'].empty_chain('provider') - if FLAGS.use_ipv6: - self.iptables.ipv6['filter'].empty_chain('provider') - - def _build_provider_fw_rules(self): - """Create all rules for the provider IP DROPs.""" - self.iptables.ipv4['filter'].add_chain('provider') - if FLAGS.use_ipv6: - self.iptables.ipv6['filter'].add_chain('provider') - ipv4_rules, ipv6_rules = self._provider_rules() - for rule in ipv4_rules: - self.iptables.ipv4['filter'].add_rule('provider', rule) - - if FLAGS.use_ipv6: - for rule in ipv6_rules: - self.iptables.ipv6['filter'].add_rule('provider', rule) - @staticmethod def _provider_rules(): """Generate a list of rules from provider for IP4 & IP6.""" diff --git a/nova/virt/xenapi/firewall.py b/nova/virt/xenapi/firewall.py index 8f6f17de3..41d67de5c 100644 --- a/nova/virt/xenapi/firewall.py +++ b/nova/virt/xenapi/firewall.py @@ -19,8 +19,12 @@ import json + +from nova import context from nova import flags from nova import log as logging +from nova.db import api as db +from nova.virt import netutils from nova.virt.firewall import IptablesFirewallDriver @@ -65,3 +69,55 @@ class Dom0IptablesFirewallDriver(IptablesFirewallDriver): # No multiport needed for XS! return ['--dport', '%s:%s' % (rule.from_port, rule.to_port)] + + @staticmethod + def _provider_rules(): + """Generate a list of rules from provider for IP4 & IP6. + Note: We could not use the common code from virt.firewall because + XS doesn't accept the '-m multiport' option""" + + ctxt = context.get_admin_context() + ipv4_rules = [] + ipv6_rules = [] + rules = db.provider_fw_rule_get_all(ctxt) + for rule in rules: + LOG.debug(_('Adding provider rule: %s'), rule['cidr']) + version = netutils.get_ip_version(rule['cidr']) + if version == 4: + fw_rules = ipv4_rules + else: + fw_rules = ipv6_rules + + protocol = rule['protocol'] + if version == 6 and protocol == 'icmp': + protocol = 'icmpv6' + + args = ['-p', protocol, '-s', rule['cidr']] + + if protocol in ['udp', 'tcp']: + if rule['from_port'] == rule['to_port']: + args += ['--dport', '%s' % (rule['from_port'],)] + else: + args += ['--dport', '%s:%s' % (rule['from_port'], + rule['to_port'])] + elif protocol == 'icmp': + icmp_type = rule['from_port'] + icmp_code = rule['to_port'] + + if icmp_type == -1: + icmp_type_arg = None + else: + icmp_type_arg = '%s' % icmp_type + if not icmp_code == -1: + icmp_type_arg += '/%s' % icmp_code + + if icmp_type_arg: + if version == 4: + args += ['-m', 'icmp', '--icmp-type', + icmp_type_arg] + elif version == 6: + args += ['-m', 'icmp6', '--icmpv6-type', + icmp_type_arg] + args += ['-j DROP'] + fw_rules += [' '.join(args)] + return ipv4_rules, ipv6_rules diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 1309879b5..f681aceef 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -1744,6 +1744,9 @@ class VMOps(object): """ recreates security group rules for every instance """ self.firewall_driver.refresh_security_group_members(security_group_id) + def refresh_provider_fw_rules(self): + self.firewall_driver.refresh_provider_fw_rules() + def unfilter_instance(self, instance_ref, network_info): """Removes filters for each VIF of the specified instance.""" self.firewall_driver.unfilter_instance(instance_ref, diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py index 1bd0b52a5..42f035217 100644 --- a/nova/virt/xenapi_conn.py +++ b/nova/virt/xenapi_conn.py @@ -443,6 +443,9 @@ class XenAPIConnection(driver.ComputeDriver): """ return self._vmops.refresh_security_group_members(security_group_id) + def refresh_provider_fw_rules(self): + return self._vmops.refresh_provider_fw_rules() + def update_host_status(self): """Update the status info of the host, and return those values to the calling program.""" |
