From 8f28b588618fc1ac24a84a86d8d485f8875d3709 Mon Sep 17 00:00:00 2001 From: Gary Kotton Date: Sun, 13 Jan 2013 09:16:29 +0000 Subject: [PATCH] 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 --- quantum/agent/rpc.py | 6 + .../agent/linuxbridge_quantum_agent.py | 136 ++++++++---------- .../plugins/linuxbridge/lb_quantum_plugin.py | 26 +++- .../unit/linuxbridge/test_lb_quantum_agent.py | 2 +- quantum/tests/unit/linuxbridge/test_rpcapi.py | 7 + 5 files changed, 97 insertions(+), 80 deletions(-) diff --git a/quantum/agent/rpc.py b/quantum/agent/rpc.py index 984f43ddb..4fb925672 100644 --- a/quantum/agent/rpc.py +++ b/quantum/agent/rpc.py @@ -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), diff --git a/quantum/plugins/linuxbridge/agent/linuxbridge_quantum_agent.py b/quantum/plugins/linuxbridge/agent/linuxbridge_quantum_agent.py index 153312985..56d11ccfd 100755 --- a/quantum/plugins/linuxbridge/agent/linuxbridge_quantum_agent.py +++ b/quantum/plugins/linuxbridge/agent/linuxbridge_quantum_agent.py @@ -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: diff --git a/quantum/plugins/linuxbridge/lb_quantum_plugin.py b/quantum/plugins/linuxbridge/lb_quantum_plugin.py index 2355cf2bc..976178d0d 100644 --- a/quantum/plugins/linuxbridge/lb_quantum_plugin.py +++ b/quantum/plugins/linuxbridge/lb_quantum_plugin.py @@ -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): diff --git a/quantum/tests/unit/linuxbridge/test_lb_quantum_agent.py b/quantum/tests/unit/linuxbridge/test_lb_quantum_agent.py index 8ebbcb641..be394f13f 100644 --- a/quantum/tests/unit/linuxbridge/test_lb_quantum_agent.py +++ b/quantum/tests/unit/linuxbridge/test_lb_quantum_agent.py @@ -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): diff --git a/quantum/tests/unit/linuxbridge/test_rpcapi.py b/quantum/tests/unit/linuxbridge/test_rpcapi.py index 04ed559f0..bfdfdd402 100644 --- a/quantum/tests/unit/linuxbridge/test_rpcapi.py +++ b/quantum/tests/unit/linuxbridge/test_rpcapi.py @@ -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') -- 2.45.2