Skip to content

Commit

Permalink
LinuxBridge: update status according to admin_state_up
Browse files Browse the repository at this point in the history
Fixes bug 1099065

In addition to this the agent will only treat ports that exist on the agent.

Change-Id: I927649a45a860421ef0d825015516000475ad08d
  • Loading branch information
Gary Kotton committed Jan 29, 2013
1 parent fe0ae7a commit b56c2c9
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 86 deletions.
6 changes: 6 additions & 0 deletions quantum/agent/rpc.py
Expand Up @@ -74,6 +74,12 @@ def update_device_down(self, context, device, agent_id):
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),
Expand Down
162 changes: 81 additions & 81 deletions quantum/plugins/linuxbridge/agent/linuxbridge_quantum_agent.py
Expand Up @@ -62,12 +62,16 @@
PORT_BINDINGS = "port_bindings"


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:
Expand Down Expand Up @@ -391,38 +395,76 @@ def delete_vlan(self, interface):
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():

# Set RPC API version to 1.0 by default.
RPC_API_VERSION = '1.0'

def __init__(self, context, linux_br):
def __init__(self, context, agent):
self.context = context
self.linux_br = linux_br
self.agent = agent

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.get_bridge_name(network_id)
LOG.debug("Delete %s", bridge_name)
self.linux_br.delete_vlan_bridge(bridge_name)
self.agent.delete_vlan_bridge(bridge_name)

def port_update(self, context, **kwargs):
LOG.debug("port_update received")
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 port['admin_state_up']:
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.
Expand All @@ -445,18 +487,18 @@ def __init__(self, interface_mappings, polling_interval,
self.db_connection_url = db_connection_url

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 process_port_binding(self, network_id, interface_id,
physical_network, vlan_id):
return self.linux_br.add_interface(network_id,
physical_network, vlan_id,
interface_id)
return self.br_mgr.add_interface(network_id,
physical_network, vlan_id,
interface_id)

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)
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_unplugged_interfaces(self, plugged_interfaces):
"""
Expand All @@ -468,44 +510,29 @@ def process_unplugged_interfaces(self, plugged_interfaces):
plugged_tap_device_names = []
plugged_gateway_device_names = []
for interface in plugged_interfaces:
if interface.startswith(GATEWAY_INTERFACE_PREFIX):
"""
The name for the gateway devices is set by the linux net
driver, hence we use the name as is
"""
plugged_gateway_device_names.append(interface)
else:
tap_device_name = self.linux_br.get_tap_device_name(interface)
plugged_tap_device_names.append(tap_device_name)
tap_device_name = self.br_mgr.get_tap_device_name(interface)
plugged_tap_device_names.append(tap_device_name)

LOG.debug("plugged tap device names %s" % plugged_tap_device_names)
for tap_device in self.linux_br.get_all_tap_devices():
for tap_device in self.br_mgr.get_all_tap_devices():
if tap_device not in plugged_tap_device_names:
current_bridge_name = (
self.linux_br.get_bridge_for_tap_device(tap_device))
self.br_mgr.get_bridge_for_tap_device(tap_device))
if current_bridge_name:
self.linux_br.remove_interface(current_bridge_name,
tap_device)

for gw_device in self.linux_br.get_all_gateway_devices():
if gw_device not in plugged_gateway_device_names:
current_bridge_name = (
self.linux_br.get_bridge_for_tap_device(gw_device))
if current_bridge_name:
self.linux_br.remove_interface(current_bridge_name,
gw_device)
self.br_mgr.remove_interface(current_bridge_name,
tap_device)

def process_deleted_networks(self, vlan_bindings):
current_quantum_networks = vlan_bindings.keys()
current_quantum_bridge_names = []
for network in current_quantum_networks:
bridge_name = self.linux_br.get_bridge_name(network)
bridge_name = self.br_mgr.get_bridge_name(network)
current_quantum_bridge_names.append(bridge_name)

quantum_bridges_on_this_host = self.linux_br.get_all_quantum_bridges()
quantum_bridges_on_this_host = self.br_mgr.get_all_quantum_bridges()
for bridge in quantum_bridges_on_this_host:
if bridge not in current_quantum_bridge_names:
self.linux_br.delete_vlan_bridge(bridge)
self.br_mgr.delete_vlan_bridge(bridge)

def manage_networks_on_host(self, db,
old_vlan_bindings,
Expand Down Expand Up @@ -638,49 +665,22 @@ def setup_rpc(self, physical_interfaces):
is_admin=False)
# Handle updates from service
self.callbacks = LinuxBridgeRpcCallbacks(self.context,
self.linux_br)
self.br_mgr)
self.dispatcher = self.callbacks.create_rpc_dispatcher()
# Define the listening consumers for the agent
consumers = [[topics.PORT, topics.UPDATE],
[topics.NETWORK, topics.DELETE]]
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
Expand Down Expand Up @@ -708,10 +708,10 @@ def treat_devices_added(self, devices):
LOG.info("Port %s updated. Details: %s", device, details)
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'])
Expand Down Expand Up @@ -750,7 +750,7 @@ def daemon_loop(self):
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:
Expand Down
25 changes: 21 additions & 4 deletions quantum/plugins/linuxbridge/lb_quantum_plugin.py
Expand Up @@ -72,8 +72,10 @@ def get_device_details(self, rpc_context, **kwargs):
'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)
Expand All @@ -89,14 +91,29 @@ def update_device_down(self, rpc_context, **kwargs):
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):
'''Agent side of the linux bridge rpc API.
Expand Down
2 changes: 1 addition & 1 deletion quantum/tests/unit/linuxbridge/test_lb_quantum_agent.py
Expand Up @@ -30,7 +30,7 @@ def setUp(self):
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):
Expand Down
7 changes: 7 additions & 0 deletions quantum/tests/unit/linuxbridge/test_rpcapi.py
Expand Up @@ -91,3 +91,10 @@ def test_update_device_down(self):
'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')

0 comments on commit b56c2c9

Please sign in to comment.