LinuxBridge: update status according to admin_state_up
Fixes bug 1099065 In addition to this the agent will only treat ports that exist on the agent. Change-Id: I927649a45a860421ef0d825015516000475ad08d
This commit is contained in:
parent
6f6499700a
commit
8f28b58861
@ -75,6 +75,12 @@ class PluginApi(proxy.RpcProxy):
|
||||
agent_id=agent_id),
|
||||
topic=self.topic)
|
||||
|
||||
def update_device_up(self, context, device, agent_id):
|
||||
return self.call(context,
|
||||
self.make_msg('update_device_up', device=device,
|
||||
agent_id=agent_id),
|
||||
topic=self.topic)
|
||||
|
||||
def tunnel_sync(self, context, tunnel_ip):
|
||||
return self.call(context,
|
||||
self.make_msg('tunnel_sync', tunnel_ip=tunnel_ip),
|
||||
|
@ -56,12 +56,16 @@ DEVICE_NAME_PLACEHOLDER = "device_name"
|
||||
BRIDGE_PORT_FS_FOR_DEVICE = BRIDGE_FS + DEVICE_NAME_PLACEHOLDER + "/brport"
|
||||
|
||||
|
||||
class LinuxBridge:
|
||||
class LinuxBridgeManager:
|
||||
def __init__(self, interface_mappings, root_helper):
|
||||
self.interface_mappings = interface_mappings
|
||||
self.root_helper = root_helper
|
||||
self.ip = ip_lib.IPWrapper(self.root_helper)
|
||||
|
||||
self.udev = pyudev.Context()
|
||||
monitor = pyudev.Monitor.from_netlink(self.udev)
|
||||
monitor.filter_by('net')
|
||||
|
||||
def device_exists(self, device):
|
||||
"""Check if ethernet device exists."""
|
||||
try:
|
||||
@ -113,34 +117,6 @@ class LinuxBridge:
|
||||
BRIDGE_NAME_PLACEHOLDER, bridge_name)
|
||||
return os.listdir(bridge_interface_path)
|
||||
|
||||
def _get_prefixed_ip_link_devices(self, prefix):
|
||||
prefixed_devices = []
|
||||
retval = utils.execute(['ip', 'link'], root_helper=self.root_helper)
|
||||
rows = retval.split('\n')
|
||||
for row in rows:
|
||||
values = row.split(':')
|
||||
if (len(values) > 2):
|
||||
value = values[1].strip(' ')
|
||||
if (value.startswith(prefix)):
|
||||
prefixed_devices.append(value)
|
||||
return prefixed_devices
|
||||
|
||||
def _get_prefixed_tap_devices(self, prefix):
|
||||
prefixed_devices = []
|
||||
retval = utils.execute(['ip', 'tuntap'], root_helper=self.root_helper)
|
||||
rows = retval.split('\n')
|
||||
for row in rows:
|
||||
split_row = row.split(':')
|
||||
if split_row[0].startswith(prefix):
|
||||
prefixed_devices.append(split_row[0])
|
||||
return prefixed_devices
|
||||
|
||||
def get_all_tap_devices(self):
|
||||
try:
|
||||
return self._get_prefixed_tap_devices(TAP_INTERFACE_PREFIX)
|
||||
except RuntimeError:
|
||||
return self._get_prefixed_ip_link_devices(TAP_INTERFACE_PREFIX)
|
||||
|
||||
def get_bridge_for_tap_device(self, tap_device_name):
|
||||
bridges = self.get_all_quantum_bridges()
|
||||
for bridge in bridges:
|
||||
@ -389,6 +365,30 @@ class LinuxBridge:
|
||||
return
|
||||
LOG.debug(_("Done deleting subinterface %s"), interface)
|
||||
|
||||
def update_devices(self, registered_devices):
|
||||
devices = self.udev_get_tap_devices()
|
||||
if devices == registered_devices:
|
||||
return
|
||||
added = devices - registered_devices
|
||||
removed = registered_devices - devices
|
||||
return {'current': devices,
|
||||
'added': added,
|
||||
'removed': removed}
|
||||
|
||||
def udev_get_tap_devices(self):
|
||||
devices = set()
|
||||
for device in self.udev.list_devices(subsystem='net'):
|
||||
name = self.udev_get_name(device)
|
||||
if self.is_tap_device(name):
|
||||
devices.add(name)
|
||||
return devices
|
||||
|
||||
def is_tap_device(self, name):
|
||||
return name.startswith(TAP_INTERFACE_PREFIX)
|
||||
|
||||
def udev_get_name(self, device):
|
||||
return device.sys_name
|
||||
|
||||
|
||||
class LinuxBridgeRpcCallbacks(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
|
||||
|
||||
@ -400,18 +400,23 @@ class LinuxBridgeRpcCallbacks(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
|
||||
def __init__(self, context, agent):
|
||||
self.context = context
|
||||
self.agent = agent
|
||||
self.linux_br = agent.linux_br
|
||||
|
||||
def network_delete(self, context, **kwargs):
|
||||
LOG.debug(_("network_delete received"))
|
||||
network_id = kwargs.get('network_id')
|
||||
bridge_name = self.linux_br.get_bridge_name(network_id)
|
||||
bridge_name = self.agent.br_mgr.get_bridge_name(network_id)
|
||||
LOG.debug(_("Delete %s"), bridge_name)
|
||||
self.linux_br.delete_vlan_bridge(bridge_name)
|
||||
self.agent.br_mgr.delete_vlan_bridge(bridge_name)
|
||||
|
||||
def port_update(self, context, **kwargs):
|
||||
LOG.debug(_("port_update received"))
|
||||
# Check port exists on node
|
||||
port = kwargs.get('port')
|
||||
tap_device_name = self.agent.br_mgr.get_tap_device_name(port['id'])
|
||||
devices = self.agent.br_mgr.udev_get_tap_devices()
|
||||
if not tap_device_name in devices:
|
||||
return
|
||||
|
||||
if 'security_groups' in port:
|
||||
self.agent.refresh_firewall()
|
||||
|
||||
@ -419,14 +424,22 @@ class LinuxBridgeRpcCallbacks(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
|
||||
vlan_id = kwargs.get('vlan_id')
|
||||
physical_network = kwargs.get('physical_network')
|
||||
# create the networking for the port
|
||||
self.linux_br.add_interface(port['network_id'],
|
||||
physical_network,
|
||||
vlan_id,
|
||||
port['id'])
|
||||
self.agent.br_mgr.add_interface(port['network_id'],
|
||||
physical_network,
|
||||
vlan_id,
|
||||
port['id'])
|
||||
# update plugin about port status
|
||||
self.agent.plugin_rpc.update_device_up(self.context,
|
||||
tap_device_name,
|
||||
self.agent.agent_id)
|
||||
else:
|
||||
bridge_name = self.linux_br.get_bridge_name(port['network_id'])
|
||||
tap_device_name = self.linux_br.get_tap_device_name(port['id'])
|
||||
self.linux_br.remove_interface(bridge_name, tap_device_name)
|
||||
bridge_name = self.agent.br_mgr.get_bridge_name(
|
||||
port['network_id'])
|
||||
self.agent.br_mgr.remove_interface(bridge_name, tap_device_name)
|
||||
# update plugin about port status
|
||||
self.agent.plugin_rpc.update_device_down(self.context,
|
||||
tap_device_name,
|
||||
self.agent.agent_id)
|
||||
|
||||
def create_rpc_dispatcher(self):
|
||||
'''Get the rpc dispatcher for this manager.
|
||||
@ -482,41 +495,14 @@ class LinuxBridgeQuantumAgentRPC(sg_rpc.SecurityGroupAgentRpcMixin):
|
||||
self.connection = agent_rpc.create_consumers(self.dispatcher,
|
||||
self.topic,
|
||||
consumers)
|
||||
self.udev = pyudev.Context()
|
||||
monitor = pyudev.Monitor.from_netlink(self.udev)
|
||||
monitor.filter_by('net')
|
||||
|
||||
def setup_linux_bridge(self, interface_mappings):
|
||||
self.linux_br = LinuxBridge(interface_mappings, self.root_helper)
|
||||
self.br_mgr = LinuxBridgeManager(interface_mappings, self.root_helper)
|
||||
|
||||
def remove_port_binding(self, network_id, interface_id):
|
||||
bridge_name = self.linux_br.get_bridge_name(network_id)
|
||||
tap_device_name = self.linux_br.get_tap_device_name(interface_id)
|
||||
return self.linux_br.remove_interface(bridge_name, tap_device_name)
|
||||
|
||||
def update_devices(self, registered_devices):
|
||||
devices = self.udev_get_all_tap_devices()
|
||||
if devices == registered_devices:
|
||||
return
|
||||
added = devices - registered_devices
|
||||
removed = registered_devices - devices
|
||||
return {'current': devices,
|
||||
'added': added,
|
||||
'removed': removed}
|
||||
|
||||
def udev_get_all_tap_devices(self):
|
||||
devices = set()
|
||||
for device in self.udev.list_devices(subsystem='net'):
|
||||
name = self.udev_get_name(device)
|
||||
if self.is_tap_device(name):
|
||||
devices.add(name)
|
||||
return devices
|
||||
|
||||
def is_tap_device(self, name):
|
||||
return name.startswith(TAP_INTERFACE_PREFIX)
|
||||
|
||||
def udev_get_name(self, device):
|
||||
return device.sys_name
|
||||
bridge_name = self.br_mgr.get_bridge_name(network_id)
|
||||
tap_device_name = self.br_mgr.get_tap_device_name(interface_id)
|
||||
return self.br_mgr.remove_interface(bridge_name, tap_device_name)
|
||||
|
||||
def process_network_devices(self, device_info):
|
||||
resync_a = False
|
||||
@ -547,10 +533,10 @@ class LinuxBridgeQuantumAgentRPC(sg_rpc.SecurityGroupAgentRpcMixin):
|
||||
locals())
|
||||
if details['admin_state_up']:
|
||||
# create the networking for the port
|
||||
self.linux_br.add_interface(details['network_id'],
|
||||
details['physical_network'],
|
||||
details['vlan_id'],
|
||||
details['port_id'])
|
||||
self.br_mgr.add_interface(details['network_id'],
|
||||
details['physical_network'],
|
||||
details['vlan_id'],
|
||||
details['port_id'])
|
||||
else:
|
||||
self.remove_port_binding(details['network_id'],
|
||||
details['port_id'])
|
||||
@ -591,7 +577,7 @@ class LinuxBridgeQuantumAgentRPC(sg_rpc.SecurityGroupAgentRpcMixin):
|
||||
devices.clear()
|
||||
sync = False
|
||||
|
||||
device_info = self.update_devices(devices)
|
||||
device_info = self.br_mgr.update_devices(devices)
|
||||
|
||||
# notify plugin about device deltas
|
||||
if device_info:
|
||||
|
@ -86,8 +86,10 @@ class LinuxBridgeRpcCallbacks(dhcp_rpc_base.DhcpRpcCallbackMixin,
|
||||
'network_id': port['network_id'],
|
||||
'port_id': port['id'],
|
||||
'admin_state_up': port['admin_state_up']}
|
||||
# Set the port status to UP
|
||||
db.set_port_status(port['id'], q_const.PORT_STATUS_ACTIVE)
|
||||
new_status = (q_const.PORT_STATUS_ACTIVE if port['admin_state_up']
|
||||
else q_const.PORT_STATUS_DOWN)
|
||||
if port['status'] != new_status:
|
||||
db.set_port_status(port['id'], new_status)
|
||||
else:
|
||||
entry = {'device': device}
|
||||
LOG.debug(_("%s can not be found in database"), device)
|
||||
@ -104,14 +106,29 @@ class LinuxBridgeRpcCallbacks(dhcp_rpc_base.DhcpRpcCallbackMixin,
|
||||
if port:
|
||||
entry = {'device': device,
|
||||
'exists': True}
|
||||
# Set port status to DOWN
|
||||
db.set_port_status(port['id'], q_const.PORT_STATUS_DOWN)
|
||||
if port['status'] != q_const.PORT_STATUS_DOWN:
|
||||
# Set port status to DOWN
|
||||
db.set_port_status(port['id'], q_const.PORT_STATUS_DOWN)
|
||||
else:
|
||||
entry = {'device': device,
|
||||
'exists': False}
|
||||
LOG.debug(_("%s can not be found in database"), device)
|
||||
return entry
|
||||
|
||||
def update_device_up(self, rpc_context, **kwargs):
|
||||
"""Device is up on agent"""
|
||||
agent_id = kwargs.get('agent_id')
|
||||
device = kwargs.get('device')
|
||||
LOG.debug(_("Device %(device)s up %(agent_id)s"),
|
||||
locals())
|
||||
port = self.get_port_from_device(device)
|
||||
if port:
|
||||
if port['status'] != q_const.PORT_STATUS_ACTIVE:
|
||||
# Set port status to ACTIVE
|
||||
db.set_port_status(port['id'], q_const.PORT_STATUS_ACTIVE)
|
||||
else:
|
||||
LOG.debug(_("%s can not be found in database"), device)
|
||||
|
||||
|
||||
class AgentNotifierApi(proxy.RpcProxy,
|
||||
sg_rpc.SecurityGroupAgentRpcApiMixin):
|
||||
@ -508,6 +525,7 @@ class LinuxBridgePluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||
|
||||
if port_updated:
|
||||
self._notify_port_updated(context, port)
|
||||
|
||||
return self._extend_port_dict_binding(context, port)
|
||||
|
||||
def delete_port(self, context, id, l3_port_check=True):
|
||||
|
@ -29,7 +29,7 @@ class TestLinuxBridge(unittest.TestCase):
|
||||
interface_mappings = {'physnet1': 'eth1'}
|
||||
root_helper = cfg.CONF.AGENT.root_helper
|
||||
|
||||
self.linux_bridge = linuxbridge_quantum_agent.LinuxBridge(
|
||||
self.linux_bridge = linuxbridge_quantum_agent.LinuxBridgeManager(
|
||||
interface_mappings, root_helper)
|
||||
|
||||
def test_ensure_physical_in_bridge_invalid(self):
|
||||
|
@ -91,3 +91,10 @@ class rpcApiTestCase(unittest2.TestCase):
|
||||
'update_device_down', rpc_method='call',
|
||||
device='fake_device',
|
||||
agent_id='fake_agent_id')
|
||||
|
||||
def test_update_device_up(self):
|
||||
rpcapi = agent_rpc.PluginApi(topics.PLUGIN)
|
||||
self._test_lb_api(rpcapi, topics.PLUGIN,
|
||||
'update_device_up', rpc_method='call',
|
||||
device='fake_device',
|
||||
agent_id='fake_agent_id')
|
||||
|
Loading…
Reference in New Issue
Block a user