Merge "misc L3 fixes."
This commit is contained in:
commit
27943f7a67
@ -76,7 +76,7 @@ class L3NATAgent(object):
|
|||||||
cfg.IntOpt('polling_interval',
|
cfg.IntOpt('polling_interval',
|
||||||
default=3,
|
default=3,
|
||||||
help="The time in seconds between state poll requests."),
|
help="The time in seconds between state poll requests."),
|
||||||
cfg.StrOpt('metadata_ip', default='127.0.0.1',
|
cfg.StrOpt('metadata_ip', default='',
|
||||||
help="IP address used by Nova metadata server."),
|
help="IP address used by Nova metadata server."),
|
||||||
cfg.IntOpt('metadata_port',
|
cfg.IntOpt('metadata_port',
|
||||||
default=8775,
|
default=8775,
|
||||||
@ -117,16 +117,8 @@ class L3NATAgent(object):
|
|||||||
auth_region=self.conf.auth_region
|
auth_region=self.conf.auth_region
|
||||||
)
|
)
|
||||||
|
|
||||||
# disable forwarding
|
|
||||||
linux_utils.execute(['sysctl', '-w', 'net.ipv4.ip_forward=0'],
|
|
||||||
self.conf.root_helper, check_exit_code=False)
|
|
||||||
|
|
||||||
self._destroy_all_router_namespaces()
|
self._destroy_all_router_namespaces()
|
||||||
|
|
||||||
# enable forwarding
|
|
||||||
linux_utils.execute(['sysctl', '-w', 'net.ipv4.ip_forward=1'],
|
|
||||||
self.conf.root_helper, check_exit_code=False)
|
|
||||||
|
|
||||||
def _destroy_all_router_namespaces(self):
|
def _destroy_all_router_namespaces(self):
|
||||||
"""Destroy all router namespaces on the host to eliminate
|
"""Destroy all router namespaces on the host to eliminate
|
||||||
all stale linux devices, iptables rules, and namespaces.
|
all stale linux devices, iptables rules, and namespaces.
|
||||||
@ -151,13 +143,18 @@ class L3NATAgent(object):
|
|||||||
bridge=self.conf.external_network_bridge)
|
bridge=self.conf.external_network_bridge)
|
||||||
ns_ip.netns.delete(namespace)
|
ns_ip.netns.delete(namespace)
|
||||||
|
|
||||||
def daemon_loop(self):
|
def _create_router_namespace(self, ri):
|
||||||
|
ip_wrapper_root = ip_lib.IPWrapper(self.conf.root_helper)
|
||||||
|
ip_wrapper_root.netns.add(ri.ns_name())
|
||||||
|
|
||||||
#TODO(danwent): this simple diff logic does not handle if a
|
ip_wrapper = ip_lib.IPWrapper(self.conf.root_helper,
|
||||||
# resource is modified (i.e., ip change on port, or floating ip
|
namespace=ri.ns_name())
|
||||||
# mapped from one IP to another). Will fix this properly with
|
ip_wrapper.netns.execute(['sysctl', '-w', 'net.ipv4.ip_forward=1'])
|
||||||
# update notifications.
|
|
||||||
# Likewise, it does not handle removing routers
|
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:
|
while True:
|
||||||
try:
|
try:
|
||||||
@ -173,10 +170,14 @@ class L3NATAgent(object):
|
|||||||
|
|
||||||
# identify and update new or modified routers
|
# identify and update new or modified routers
|
||||||
for r in self.qclient.list_routers()['routers']:
|
for r in self.qclient.list_routers()['routers']:
|
||||||
|
#FIXME(danwent): handle admin state
|
||||||
|
|
||||||
cur_router_ids.add(r['id'])
|
cur_router_ids.add(r['id'])
|
||||||
if r['id'] not in self.router_info:
|
if r['id'] not in self.router_info:
|
||||||
self.router_info[r['id']] = RouterInfo(r['id'],
|
self.router_info[r['id']] = RouterInfo(r['id'],
|
||||||
self.conf.root_helper)
|
self.conf.root_helper)
|
||||||
|
self._create_router_namespace(self.router_info[r['id']])
|
||||||
|
|
||||||
ri = self.router_info[r['id']]
|
ri = self.router_info[r['id']]
|
||||||
self.process_router(ri)
|
self.process_router(ri)
|
||||||
|
|
||||||
@ -246,6 +247,8 @@ class L3NATAgent(object):
|
|||||||
existing_floating_ip_ids = set([fip['id'] for fip in ri.floating_ips])
|
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])
|
cur_floating_ip_ids = set([fip['id'] for fip in floating_ips])
|
||||||
|
|
||||||
|
id_to_fixed_map = {}
|
||||||
|
|
||||||
for fip in floating_ips:
|
for fip in floating_ips:
|
||||||
if fip['port_id']:
|
if fip['port_id']:
|
||||||
if fip['id'] not in existing_floating_ip_ids:
|
if fip['id'] not in existing_floating_ip_ids:
|
||||||
@ -254,6 +257,9 @@ class L3NATAgent(object):
|
|||||||
fip['floating_ip_address'],
|
fip['floating_ip_address'],
|
||||||
fip['fixed_ip_address'])
|
fip['fixed_ip_address'])
|
||||||
|
|
||||||
|
# store to see if floatingip was remapped
|
||||||
|
id_to_fixed_map[fip['id']] = fip['fixed_ip_address']
|
||||||
|
|
||||||
floating_ip_ids_to_remove = (existing_floating_ip_ids -
|
floating_ip_ids_to_remove = (existing_floating_ip_ids -
|
||||||
cur_floating_ip_ids)
|
cur_floating_ip_ids)
|
||||||
for fip in ri.floating_ips:
|
for fip in ri.floating_ips:
|
||||||
@ -262,6 +268,17 @@ class L3NATAgent(object):
|
|||||||
self.floating_ip_removed(ri, ri.ex_gw_port,
|
self.floating_ip_removed(ri, ri.ex_gw_port,
|
||||||
fip['floating_ip_address'],
|
fip['floating_ip_address'],
|
||||||
fip['fixed_ip_address'])
|
fip['fixed_ip_address'])
|
||||||
|
else:
|
||||||
|
# handle remapping of a floating IP
|
||||||
|
cur_fixed_ip = id_to_fixed_map[fip['id']]
|
||||||
|
existing_fixed_ip = fip['fixed_ip_address']
|
||||||
|
if (cur_fixed_ip and existing_fixed_ip and
|
||||||
|
cur_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, cur_fixed_ip)
|
||||||
|
|
||||||
def _get_ex_gw_port(self, ri):
|
def _get_ex_gw_port(self, ri):
|
||||||
ports = self.qclient.list_ports(
|
ports = self.qclient.list_ports(
|
||||||
@ -306,7 +323,8 @@ class L3NATAgent(object):
|
|||||||
for (c, r) in self.external_gateway_filter_rules():
|
for (c, r) in self.external_gateway_filter_rules():
|
||||||
ri.iptables_manager.ipv4['filter'].add_rule(c, r)
|
ri.iptables_manager.ipv4['filter'].add_rule(c, r)
|
||||||
for (c, r) in self.external_gateway_nat_rules(ex_gw_ip,
|
for (c, r) in self.external_gateway_nat_rules(ex_gw_ip,
|
||||||
internal_cidrs):
|
internal_cidrs,
|
||||||
|
interface_name):
|
||||||
ri.iptables_manager.ipv4['nat'].add_rule(c, r)
|
ri.iptables_manager.ipv4['nat'].add_rule(c, r)
|
||||||
ri.iptables_manager.apply()
|
ri.iptables_manager.apply()
|
||||||
|
|
||||||
@ -321,21 +339,30 @@ class L3NATAgent(object):
|
|||||||
ex_gw_ip = ex_gw_port['fixed_ips'][0]['ip_address']
|
ex_gw_ip = ex_gw_port['fixed_ips'][0]['ip_address']
|
||||||
for c, r in self.external_gateway_filter_rules():
|
for c, r in self.external_gateway_filter_rules():
|
||||||
ri.iptables_manager.ipv4['filter'].remove_rule(c, r)
|
ri.iptables_manager.ipv4['filter'].remove_rule(c, r)
|
||||||
for c, r in self.external_gateway_nat_rules(ex_gw_ip, internal_cidrs):
|
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.ipv4['nat'].remove_rule(c, r)
|
||||||
ri.iptables_manager.apply()
|
ri.iptables_manager.apply()
|
||||||
|
|
||||||
def external_gateway_filter_rules(self):
|
def external_gateway_filter_rules(self):
|
||||||
return [('INPUT', '-s 0.0.0.0/0 -d %s '
|
rules = []
|
||||||
|
if self.conf.metadata_ip:
|
||||||
|
rules.append(('INPUT', '-s 0.0.0.0/0 -d %s '
|
||||||
'-p tcp -m tcp --dport %s '
|
'-p tcp -m tcp --dport %s '
|
||||||
'-j ACCEPT' %
|
'-j ACCEPT' %
|
||||||
(self.conf.metadata_ip, self.conf.metadata_port))]
|
(self.conf.metadata_ip, self.conf.metadata_port)))
|
||||||
|
return rules
|
||||||
|
|
||||||
def external_gateway_nat_rules(self, ex_gw_ip, internal_cidrs):
|
def external_gateway_nat_rules(self, ex_gw_ip, internal_cidrs,
|
||||||
rules = [('PREROUTING', '-s 0.0.0.0/0 -d 169.254.169.254/32 '
|
interface_name):
|
||||||
'-p tcp -m tcp --dport 80 -j DNAT '
|
rules = [('POSTROUTING', '! -i %(interface_name)s '
|
||||||
'--to-destination %s:%s' %
|
'! -o %(interface_name)s -m conntrack ! '
|
||||||
(self.conf.metadata_ip, self.conf.metadata_port))]
|
'--ctstate DNAT -j ACCEPT' % locals())]
|
||||||
|
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))
|
||||||
for cidr in internal_cidrs:
|
for cidr in internal_cidrs:
|
||||||
rules.extend(self.internal_network_nat_rules(ex_gw_ip, cidr))
|
rules.extend(self.internal_network_nat_rules(ex_gw_ip, cidr))
|
||||||
return rules
|
return rules
|
||||||
@ -375,10 +402,12 @@ class L3NATAgent(object):
|
|||||||
ri.iptables_manager.apply()
|
ri.iptables_manager.apply()
|
||||||
|
|
||||||
def internal_network_nat_rules(self, ex_gw_ip, internal_cidr):
|
def internal_network_nat_rules(self, ex_gw_ip, internal_cidr):
|
||||||
return [('snat', '-s %s -j SNAT --to-source %s' %
|
rules = [('snat', '-s %s -j SNAT --to-source %s' %
|
||||||
(internal_cidr, ex_gw_ip)),
|
(internal_cidr, ex_gw_ip))]
|
||||||
('POSTROUTING', '-s %s -d %s/32 -j ACCEPT' %
|
if self.conf.metadata_ip:
|
||||||
(internal_cidr, 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):
|
def floating_ip_added(self, ri, ex_gw_port, floating_ip, fixed_ip):
|
||||||
ip_cidr = str(floating_ip) + '/32'
|
ip_cidr = str(floating_ip) + '/32'
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
import copy
|
||||||
import time
|
import time
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
@ -79,13 +80,6 @@ class TestBasicRouterOperations(unittest.TestCase):
|
|||||||
def testAgentCreate(self):
|
def testAgentCreate(self):
|
||||||
agent = l3_agent.L3NATAgent(self.conf)
|
agent = l3_agent.L3NATAgent(self.conf)
|
||||||
|
|
||||||
# calls to disable/enable routing
|
|
||||||
self.utils_exec.assert_has_calls([
|
|
||||||
mock.call(mock.ANY, self.conf.root_helper,
|
|
||||||
check_exit_code=mock.ANY),
|
|
||||||
mock.call(mock.ANY, self.conf.root_helper,
|
|
||||||
check_exit_code=mock.ANY)])
|
|
||||||
|
|
||||||
self.device_exists.assert_has_calls(
|
self.device_exists.assert_has_calls(
|
||||||
[mock.call(self.conf.external_network_bridge)])
|
[mock.call(self.conf.external_network_bridge)])
|
||||||
|
|
||||||
@ -203,7 +197,7 @@ class TestBasicRouterOperations(unittest.TestCase):
|
|||||||
fake_subnet = {'subnet': {'cidr': '19.4.4.0/24',
|
fake_subnet = {'subnet': {'cidr': '19.4.4.0/24',
|
||||||
'gateway_ip': '19.4.4.1'}}
|
'gateway_ip': '19.4.4.1'}}
|
||||||
|
|
||||||
fake_floatingips = {'floatingips': [
|
fake_floatingips1 = {'floatingips': [
|
||||||
{'id': _uuid(),
|
{'id': _uuid(),
|
||||||
'floating_ip_address': '8.8.8.8',
|
'floating_ip_address': '8.8.8.8',
|
||||||
'fixed_ip_address': '7.7.7.7',
|
'fixed_ip_address': '7.7.7.7',
|
||||||
@ -211,7 +205,13 @@ class TestBasicRouterOperations(unittest.TestCase):
|
|||||||
|
|
||||||
self.client_inst.list_ports.side_effect = fake_list_ports1
|
self.client_inst.list_ports.side_effect = fake_list_ports1
|
||||||
self.client_inst.show_subnet.return_value = fake_subnet
|
self.client_inst.show_subnet.return_value = fake_subnet
|
||||||
self.client_inst.list_floatingips.return_value = fake_floatingips
|
self.client_inst.list_floatingips.return_value = fake_floatingips1
|
||||||
|
agent.process_router(ri)
|
||||||
|
|
||||||
|
# remap floating IP to a new fixed ip
|
||||||
|
fake_floatingips2 = copy.deepcopy(fake_floatingips1)
|
||||||
|
fake_floatingips2['floatingips'][0]['fixed_ip_address'] = '7.7.7.8'
|
||||||
|
self.client_inst.list_floatingips.return_value = fake_floatingips2
|
||||||
agent.process_router(ri)
|
agent.process_router(ri)
|
||||||
|
|
||||||
# remove just the floating ips
|
# remove just the floating ips
|
||||||
|
Loading…
Reference in New Issue
Block a user