]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
LinuxBridge: update status according to admin_state_up
authorGary Kotton <gkotton@redhat.com>
Sun, 13 Jan 2013 09:16:29 +0000 (09:16 +0000)
committerGary Kotton <gkotton@redhat.com>
Wed, 23 Jan 2013 16:39:13 +0000 (16:39 +0000)
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
quantum/plugins/linuxbridge/agent/linuxbridge_quantum_agent.py
quantum/plugins/linuxbridge/lb_quantum_plugin.py
quantum/tests/unit/linuxbridge/test_lb_quantum_agent.py
quantum/tests/unit/linuxbridge/test_rpcapi.py

index 984f43ddbec35f6cd8cb3b446253080b342dcb1d..4fb92567295177bedc85e2af4ad27311f44dff18 100644 (file)
@@ -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),
index 1533129859d20b6ce300d8f2d358930cc6fa471b..56d11ccfd2af2ce56554912daf6edb42dc28402b 100755 (executable)
@@ -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:
index 2355cf2bc2b715213cfa821ffe41e8523feb6db8..976178d0dcb6a7ba46f9f8b6640ad736e24b9ed0 100644 (file)
@@ -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):
index 8ebbcb64199f9c18607c12cdc52eb804bb2438e9..be394f13f47b178d6905ec5577ba9e7c7da624cb 100644 (file)
@@ -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):
index 04ed559f02dd924b969e7ac0b5e9d22ea756be47..bfdfdd402cac6ed798f7681e392bd6135d948bca 100644 (file)
@@ -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')