The fixes enable the OVS and linuxbridge agenets to "keep alive" when the host running the server/plugin is down.
bugs 985470 and 985646 Change-Id: Ia7174c80a0760d27fe36fb6e7764e3abe32ae8a6
This commit is contained in:
parent
b226e0c7e9
commit
ba72f9c735
@ -16,12 +16,14 @@ host = <hostname_or_IP_address_of_Quantum_server>
|
||||
port = 3306
|
||||
|
||||
[LINUX_BRIDGE]
|
||||
#this is the interface connected to the switch on your Quantum network
|
||||
# This is the interface connected to the switch on your Quantum network
|
||||
physical_interface = eth1
|
||||
|
||||
[AGENT]
|
||||
#agent's polling interval in seconds
|
||||
# Agent's polling interval in seconds
|
||||
polling_interval = 2
|
||||
# Agent's database reconnection interval in seconds - in event connectivity is lost
|
||||
reconnect_interval = 2
|
||||
# Change to "sudo quantum-rootwrap" to limit commands that can be run
|
||||
# as root.
|
||||
root_helper = sudo
|
||||
|
@ -32,6 +32,10 @@ integration-bridge = br-int
|
||||
# local-ip = 10.0.0.3
|
||||
|
||||
[AGENT]
|
||||
# Agent's polling interval in seconds
|
||||
polling_interval = 2
|
||||
# Agent's database reconnection interval in seconds - in event connectivity is lost
|
||||
reconnect_interval = 2
|
||||
# Change to "sudo quantum-rootwrap" to limit commands that can be run
|
||||
# as root.
|
||||
root_helper = sudo
|
||||
|
@ -21,21 +21,22 @@
|
||||
# Based on the structure of the OpenVSwitch agent in the
|
||||
# Quantum OpenVSwitch Plugin.
|
||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
||||
#
|
||||
|
||||
from optparse import OptionParser
|
||||
from subprocess import *
|
||||
|
||||
import ConfigParser
|
||||
import logging as LOG
|
||||
import MySQLdb
|
||||
import logging
|
||||
from optparse import OptionParser
|
||||
import os
|
||||
import shlex
|
||||
import signal
|
||||
import sqlite3
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
from sqlalchemy.ext.sqlsoup import SqlSoup
|
||||
|
||||
logging.basicConfig()
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
BRIDGE_NAME_PREFIX = "brq"
|
||||
GATEWAY_INTERFACE_PREFIX = "gw-"
|
||||
@ -50,7 +51,9 @@ VLAN_BINDINGS = "vlan_bindings"
|
||||
PORT_BINDINGS = "port_bindings"
|
||||
OP_STATUS_UP = "UP"
|
||||
OP_STATUS_DOWN = "DOWN"
|
||||
DB_CONNECTION = None
|
||||
# Default inteval values
|
||||
DEFAULT_POLLING_INTERVAL = 2
|
||||
DEFAULT_RECONNECT_INTERVAL = 2
|
||||
|
||||
|
||||
class LinuxBridge:
|
||||
@ -62,7 +65,7 @@ class LinuxBridge:
|
||||
def run_cmd(self, args):
|
||||
cmd = shlex.split(self.root_helper) + args
|
||||
LOG.debug("Running command: " + " ".join(cmd))
|
||||
p = Popen(cmd, stdout=PIPE)
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
||||
retval = p.communicate()[0]
|
||||
if p.returncode == -(signal.SIGALRM):
|
||||
LOG.debug("Timeout running command: " + " ".join(cmd))
|
||||
@ -81,7 +84,7 @@ class LinuxBridge:
|
||||
def get_bridge_name(self, network_id):
|
||||
if not network_id:
|
||||
LOG.warning("Invalid Network ID, will lead to incorrect bridge" \
|
||||
"name")
|
||||
"name")
|
||||
bridge_name = self.br_name_prefix + network_id[0:11]
|
||||
return bridge_name
|
||||
|
||||
@ -95,7 +98,7 @@ class LinuxBridge:
|
||||
def get_tap_device_name(self, interface_id):
|
||||
if not interface_id:
|
||||
LOG.warning("Invalid Interface ID, will lead to incorrect " \
|
||||
"tap device name")
|
||||
"tap device name")
|
||||
tap_device_name = TAP_INTERFACE_PREFIX + interface_id[0:11]
|
||||
return tap_device_name
|
||||
|
||||
@ -109,9 +112,8 @@ class LinuxBridge:
|
||||
|
||||
def get_interfaces_on_bridge(self, bridge_name):
|
||||
if self.device_exists(bridge_name):
|
||||
bridge_interface_path = \
|
||||
BRIDGE_INTERFACES_FS.replace(BRIDGE_NAME_PLACEHOLDER,
|
||||
bridge_name)
|
||||
bridge_interface_path = BRIDGE_INTERFACES_FS.replace(
|
||||
BRIDGE_NAME_PLACEHOLDER, bridge_name)
|
||||
return os.listdir(bridge_interface_path)
|
||||
|
||||
def get_all_tap_devices(self):
|
||||
@ -149,9 +151,8 @@ class LinuxBridge:
|
||||
if not device_name:
|
||||
return False
|
||||
else:
|
||||
bridge_port_path = \
|
||||
BRIDGE_PORT_FS_FOR_DEVICE.replace(DEVICE_NAME_PLACEHOLDER,
|
||||
device_name)
|
||||
bridge_port_path = BRIDGE_PORT_FS_FOR_DEVICE.replace(
|
||||
DEVICE_NAME_PLACEHOLDER, device_name)
|
||||
return os.path.exists(bridge_port_path)
|
||||
|
||||
def ensure_vlan_bridge(self, network_id, vlan_id):
|
||||
@ -183,7 +184,7 @@ class LinuxBridge:
|
||||
"""
|
||||
if not self.device_exists(bridge_name):
|
||||
LOG.debug("Starting bridge %s for subinterface %s" % (bridge_name,
|
||||
interface))
|
||||
interface))
|
||||
if self.run_cmd(['brctl', 'addbr', bridge_name]):
|
||||
return
|
||||
if self.run_cmd(['brctl', 'setfd', bridge_name, str(0)]):
|
||||
@ -210,8 +211,7 @@ class LinuxBridge:
|
||||
tap_device_name)
|
||||
return False
|
||||
|
||||
current_bridge_name = \
|
||||
self.get_bridge_for_tap_device(tap_device_name)
|
||||
current_bridge_name = self.get_bridge_for_tap_device(tap_device_name)
|
||||
bridge_name = self.get_bridge_name(network_id)
|
||||
if bridge_name == current_bridge_name:
|
||||
return False
|
||||
@ -237,12 +237,10 @@ class LinuxBridge:
|
||||
"""
|
||||
return False
|
||||
if interface_id.startswith(GATEWAY_INTERFACE_PREFIX):
|
||||
return self.add_tap_interface(network_id, vlan_id,
|
||||
interface_id)
|
||||
return self.add_tap_interface(network_id, vlan_id, interface_id)
|
||||
else:
|
||||
tap_device_name = self.get_tap_device_name(interface_id)
|
||||
return self.add_tap_interface(network_id, vlan_id,
|
||||
tap_device_name)
|
||||
return self.add_tap_interface(network_id, vlan_id, tap_device_name)
|
||||
|
||||
def delete_vlan_bridge(self, bridge_name):
|
||||
if self.device_exists(bridge_name):
|
||||
@ -266,15 +264,15 @@ class LinuxBridge:
|
||||
if self.device_exists(bridge_name):
|
||||
if not self.is_device_on_bridge(interface_name):
|
||||
return True
|
||||
LOG.debug("Removing device %s from bridge %s" % \
|
||||
LOG.debug("Removing device %s from bridge %s" %
|
||||
(interface_name, bridge_name))
|
||||
if self.run_cmd(['brctl', 'delif', bridge_name, interface_name]):
|
||||
return False
|
||||
LOG.debug("Done removing device %s from bridge %s" % \
|
||||
LOG.debug("Done removing device %s from bridge %s" %
|
||||
(interface_name, bridge_name))
|
||||
return True
|
||||
else:
|
||||
LOG.debug("Cannot remove device %s, bridge %s does not exist" % \
|
||||
LOG.debug("Cannot remove device %s, bridge %s does not exist" %
|
||||
(interface_name, bridge_name))
|
||||
return False
|
||||
|
||||
@ -291,10 +289,12 @@ class LinuxBridge:
|
||||
class LinuxBridgeQuantumAgent:
|
||||
|
||||
def __init__(self, br_name_prefix, physical_interface, polling_interval,
|
||||
root_helper):
|
||||
self.polling_interval = int(polling_interval)
|
||||
reconnect_interval, root_helper):
|
||||
self.polling_interval = polling_interval
|
||||
self.reconnect_interval = reconnect_interval
|
||||
self.root_helper = root_helper
|
||||
self.setup_linux_bridge(br_name_prefix, physical_interface)
|
||||
self.db_connected = False
|
||||
|
||||
def setup_linux_bridge(self, br_name_prefix, physical_interface):
|
||||
self.linux_br = LinuxBridge(br_name_prefix, physical_interface,
|
||||
@ -327,16 +327,16 @@ class LinuxBridgeQuantumAgent:
|
||||
LOG.debug("plugged tap device names %s" % plugged_tap_device_names)
|
||||
for tap_device in self.linux_br.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)
|
||||
current_bridge_name = (
|
||||
self.linux_br.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)
|
||||
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)
|
||||
@ -353,42 +353,53 @@ class LinuxBridgeQuantumAgent:
|
||||
if bridge not in current_quantum_bridge_names:
|
||||
self.linux_br.delete_vlan_bridge(bridge)
|
||||
|
||||
def manage_networks_on_host(self, conn, old_vlan_bindings,
|
||||
def manage_networks_on_host(self, db,
|
||||
old_vlan_bindings,
|
||||
old_port_bindings):
|
||||
if DB_CONNECTION != 'sqlite':
|
||||
cursor = MySQLdb.cursors.DictCursor(conn)
|
||||
else:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("SELECT * FROM vlan_bindings")
|
||||
rows = cursor.fetchall()
|
||||
cursor.close()
|
||||
vlan_bindings = {}
|
||||
try:
|
||||
vlan_binds = db.vlan_bindings.all()
|
||||
except Exception as e:
|
||||
LOG.info("Unable to get vlan bindings! Exception: %s" % e)
|
||||
self.db_connected = False
|
||||
return {VLAN_BINDINGS: {},
|
||||
PORT_BINDINGS: []}
|
||||
|
||||
vlans_string = ""
|
||||
for row in rows:
|
||||
vlan_bindings[row['network_id']] = row
|
||||
vlans_string = "%s %s" % (vlans_string, row)
|
||||
for bind in vlan_binds:
|
||||
entry = {'network_id': bind.network_id, 'vlan_id': bind.vlan_id}
|
||||
vlan_bindings[bind.network_id] = entry
|
||||
vlans_string = "%s %s" % (vlans_string, entry)
|
||||
|
||||
port_bindings = []
|
||||
try:
|
||||
port_binds = db.ports.all()
|
||||
except Exception as e:
|
||||
LOG.info("Unable to get port bindings! Exception: %s" % e)
|
||||
self.db_connected = False
|
||||
return {VLAN_BINDINGS: {},
|
||||
PORT_BINDINGS: []}
|
||||
|
||||
all_bindings = {}
|
||||
for bind in port_binds:
|
||||
all_bindings[bind.uuid] = bind
|
||||
entry = {'network_id': bind.network_id, 'state': bind.state,
|
||||
'op_status': bind.op_status, 'uuid': bind.uuid,
|
||||
'interface_id': bind.interface_id}
|
||||
if bind.state == 'ACTIVE':
|
||||
port_bindings.append(entry)
|
||||
|
||||
plugged_interfaces = []
|
||||
cursor = MySQLdb.cursors.DictCursor(conn)
|
||||
cursor.execute("SELECT * FROM ports where state = 'ACTIVE'")
|
||||
port_bindings = cursor.fetchall()
|
||||
cursor.close()
|
||||
|
||||
ports_string = ""
|
||||
for pb in port_bindings:
|
||||
ports_string = "%s %s" % (ports_string, pb)
|
||||
if pb['interface_id']:
|
||||
vlan_id = \
|
||||
str(vlan_bindings[pb['network_id']]['vlan_id'])
|
||||
vlan_id = str(vlan_bindings[pb['network_id']]['vlan_id'])
|
||||
if self.process_port_binding(pb['uuid'],
|
||||
pb['network_id'],
|
||||
pb['interface_id'],
|
||||
vlan_id):
|
||||
cursor = MySQLdb.cursors.DictCursor(conn)
|
||||
sql = PORT_OPSTATUS_UPDATESQL % (pb['uuid'],
|
||||
OP_STATUS_UP)
|
||||
cursor.execute(sql)
|
||||
cursor.close()
|
||||
all_bindings[pb['uuid']].op_status = OP_STATUS_UP
|
||||
plugged_interfaces.append(pb['interface_id'])
|
||||
|
||||
if old_port_bindings != port_bindings:
|
||||
@ -401,16 +412,30 @@ class LinuxBridgeQuantumAgent:
|
||||
|
||||
self.process_deleted_networks(vlan_bindings)
|
||||
|
||||
conn.commit()
|
||||
try:
|
||||
db.commit()
|
||||
except Exception as e:
|
||||
LOG.info("Unable to update database! Exception: %s" % e)
|
||||
db.rollback()
|
||||
vlan_bindings = {}
|
||||
port_bindings = []
|
||||
|
||||
return {VLAN_BINDINGS: vlan_bindings,
|
||||
PORT_BINDINGS: port_bindings}
|
||||
|
||||
def daemon_loop(self, conn):
|
||||
def daemon_loop(self, db_connection_url):
|
||||
old_vlan_bindings = {}
|
||||
old_port_bindings = {}
|
||||
old_port_bindings = []
|
||||
self.db_connected = False
|
||||
|
||||
while True:
|
||||
bindings = self.manage_networks_on_host(conn,
|
||||
if not self.db_connected:
|
||||
time.sleep(self.reconnect_interval)
|
||||
db = SqlSoup(db_connection_url)
|
||||
self.db_connected = True
|
||||
LOG.info("Connecting to database \"%s\" on %s" %
|
||||
(db.engine.url.database, db.engine.url.host))
|
||||
bindings = self.manage_networks_on_host(db,
|
||||
old_vlan_bindings,
|
||||
old_port_bindings)
|
||||
old_vlan_bindings = bindings[VLAN_BINDINGS]
|
||||
@ -427,9 +452,9 @@ def main():
|
||||
options, args = parser.parse_args()
|
||||
|
||||
if options.verbose:
|
||||
LOG.basicConfig(level=LOG.DEBUG)
|
||||
LOG.setLevel(logging.DEBUG)
|
||||
else:
|
||||
LOG.basicConfig(level=LOG.WARN)
|
||||
LOG.setLevel(logging.WARNING)
|
||||
|
||||
if len(args) != 1:
|
||||
parser.print_help()
|
||||
@ -437,22 +462,28 @@ def main():
|
||||
|
||||
config_file = args[0]
|
||||
config = ConfigParser.ConfigParser()
|
||||
conn = None
|
||||
try:
|
||||
fh = open(config_file)
|
||||
fh.close()
|
||||
config.read(config_file)
|
||||
br_name_prefix = BRIDGE_NAME_PREFIX
|
||||
physical_interface = config.get("LINUX_BRIDGE", "physical_interface")
|
||||
polling_interval = config.get("AGENT", "polling_interval")
|
||||
if config.has_option("AGENT", "polling_interval"):
|
||||
polling_interval = config.getint("AGENT", "polling_interval")
|
||||
else:
|
||||
polling_interval = DEFAULT_POLLING_INTERVAL
|
||||
LOG.info("Polling interval not defined. Using default.")
|
||||
if config.has_option("AGENT", "reconnect_interval"):
|
||||
reconnect_interval = config.getint("AGENT", "reconnect_interval")
|
||||
else:
|
||||
reconnect_interval = DEFAULT_RECONNECT_INTERVAL
|
||||
LOG.info("Reconnect interval not defined. Using default.")
|
||||
root_helper = config.get("AGENT", "root_helper")
|
||||
'Establish database connection and load models'
|
||||
global DB_CONNECTION
|
||||
DB_CONNECTION = config.get("DATABASE", "connection")
|
||||
if DB_CONNECTION == 'sqlite':
|
||||
connection = config.get("DATABASE", "connection")
|
||||
if connection == 'sqlite':
|
||||
LOG.info("Connecting to sqlite DB")
|
||||
conn = sqlite3.connect(":memory:")
|
||||
conn.row_factory = sqlite3.Row
|
||||
db_connection_url = "sqlite:///:memory:"
|
||||
else:
|
||||
db_name = config.get("DATABASE", "name")
|
||||
db_user = config.get("DATABASE", "user")
|
||||
@ -460,21 +491,18 @@ def main():
|
||||
db_host = config.get("DATABASE", "host")
|
||||
db_port = int(config.get("DATABASE", "port"))
|
||||
LOG.info("Connecting to database %s on %s" % (db_name, db_host))
|
||||
conn = MySQLdb.connect(host=db_host, user=db_user, port=db_port,
|
||||
passwd=db_pass, db=db_name)
|
||||
except Exception, e:
|
||||
LOG.error("Unable to parse config file \"%s\": \nException%s"
|
||||
% (config_file, str(e)))
|
||||
db_connection_url = ("%s://%s:%s@%s:%d/%s" %
|
||||
(connection, db_user, db_pass, db_host, db_port, db_name))
|
||||
except Exception as e:
|
||||
LOG.error("Unable to parse config file \"%s\": \nException %s" %
|
||||
(config_file, str(e)))
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
plugin = LinuxBridgeQuantumAgent(br_name_prefix, physical_interface,
|
||||
polling_interval, root_helper)
|
||||
LOG.info("Agent initialized successfully, now running...")
|
||||
plugin.daemon_loop(conn)
|
||||
finally:
|
||||
if conn:
|
||||
conn.close()
|
||||
plugin = LinuxBridgeQuantumAgent(br_name_prefix, physical_interface,
|
||||
polling_interval, reconnect_interval,
|
||||
root_helper)
|
||||
LOG.info("Agent initialized successfully, now running... ")
|
||||
plugin.daemon_loop(db_connection_url)
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
|
@ -15,43 +15,43 @@
|
||||
# under the License.
|
||||
#
|
||||
# @author: Shweta Padubidri, Cisco Systems, Inc.
|
||||
#
|
||||
|
||||
import ConfigParser
|
||||
import logging as LOG
|
||||
import unittest
|
||||
import sys
|
||||
import logging
|
||||
import os
|
||||
import shlex
|
||||
import signal
|
||||
from subprocess import *
|
||||
import subprocess
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
import quantum.plugins.linuxbridge.agent.linuxbridge_quantum_agent\
|
||||
as linux_agent
|
||||
from quantum.plugins.linuxbridge.common import constants as lconst
|
||||
from quantum.plugins.linuxbridge import LinuxBridgePlugin
|
||||
from quantum.plugins.linuxbridge.db import l2network_db as cdb
|
||||
import quantum.db.api as db
|
||||
from quantum.plugins.linuxbridge import LinuxBridgePlugin
|
||||
from quantum.plugins.linuxbridge.agent import (
|
||||
linuxbridge_quantum_agent as linux_agent,
|
||||
)
|
||||
from quantum.plugins.linuxbridge.common import constants as lconst
|
||||
from quantum.plugins.linuxbridge.db import l2network_db as cdb
|
||||
|
||||
|
||||
LOG.getLogger(__name__)
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class LinuxBridgeAgentTest(unittest.TestCase):
|
||||
|
||||
def test_add_gateway_interface(
|
||||
self, tenant_id="test_tenant", network_name="test_network",
|
||||
interface_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc',
|
||||
mac_address='fe:16:3e:51:60:dd'):
|
||||
self, tenant_id="test_tenant", network_name="test_network",
|
||||
interface_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc',
|
||||
mac_address='fe:16:3e:51:60:dd'):
|
||||
|
||||
LOG.debug("test_tap_gateway_interface - START")
|
||||
new_network =\
|
||||
self._linuxbridge_plugin.create_network(tenant_id, network_name)
|
||||
new_network = (
|
||||
self._linuxbridge_plugin.create_network(tenant_id, network_name))
|
||||
new_port = self._linuxbridge_plugin.create_port(
|
||||
tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP)
|
||||
tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP)
|
||||
self._linuxbridge_plugin.plug_interface(
|
||||
tenant_id, new_network[lconst.NET_ID],
|
||||
new_port[lconst.PORT_ID], interface_id)
|
||||
tenant_id, new_network[lconst.NET_ID],
|
||||
new_port[lconst.PORT_ID], interface_id)
|
||||
bridge_name = self.br_name_prefix + new_network[lconst.NET_ID][0:11]
|
||||
self.create_bridge(bridge_name)
|
||||
device_name = self.gw_name_prefix + new_network[lconst.NET_ID][0:11]
|
||||
@ -61,15 +61,15 @@ class LinuxBridgeAgentTest(unittest.TestCase):
|
||||
vlan_id = vlan_bind[lconst.VLANID]
|
||||
|
||||
self._linuxbridge_quantum_agent.process_port_binding(
|
||||
new_port[lconst.PORT_ID], new_network[lconst.NET_ID],
|
||||
device_name, str(vlan_id))
|
||||
list_interface = self._linuxbridge_quantum_agent.linux_br.\
|
||||
get_interfaces_on_bridge(bridge_name)
|
||||
new_port[lconst.PORT_ID], new_network[lconst.NET_ID],
|
||||
device_name, str(vlan_id))
|
||||
list_interface = (self._linuxbridge_quantum_agent.linux_br.
|
||||
get_interfaces_on_bridge(bridge_name))
|
||||
|
||||
self.assertTrue(device_name in list_interface)
|
||||
for interface in list_interface:
|
||||
self._linuxbridge_quantum_agent.linux_br.remove_interface(
|
||||
bridge_name, interface)
|
||||
bridge_name, interface)
|
||||
self.delete_device(interface)
|
||||
self.delete_bridge(bridge_name)
|
||||
self.tearDownUnplugInterface(tenant_id, new_network[lconst.NET_ID],
|
||||
@ -78,18 +78,18 @@ class LinuxBridgeAgentTest(unittest.TestCase):
|
||||
LOG.debug("test_add_gateway_interface - END")
|
||||
|
||||
def test_add_tap_interface(
|
||||
self, tenant_id="test_tenant", network_name="test_network",
|
||||
interface_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc',
|
||||
mac_address='fe:16:3e:51:60:dd'):
|
||||
self, tenant_id="test_tenant", network_name="test_network",
|
||||
interface_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc',
|
||||
mac_address='fe:16:3e:51:60:dd'):
|
||||
|
||||
LOG.debug("test_add_tap_interface - START")
|
||||
new_network =\
|
||||
self._linuxbridge_plugin.create_network(tenant_id, network_name)
|
||||
new_network = (
|
||||
self._linuxbridge_plugin.create_network(tenant_id, network_name))
|
||||
new_port = self._linuxbridge_plugin.create_port(
|
||||
tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP)
|
||||
tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP)
|
||||
self._linuxbridge_plugin.plug_interface(
|
||||
tenant_id, new_network[lconst.NET_ID],
|
||||
new_port[lconst.PORT_ID], interface_id)
|
||||
tenant_id, new_network[lconst.NET_ID],
|
||||
new_port[lconst.PORT_ID], interface_id)
|
||||
bridge_name = self.br_name_prefix + new_network[lconst.NET_ID][0:11]
|
||||
self.create_bridge(bridge_name)
|
||||
device_name = self.tap_name_prefix + interface_id[0:11]
|
||||
@ -99,15 +99,15 @@ class LinuxBridgeAgentTest(unittest.TestCase):
|
||||
vlan_id = vlan_bind[lconst.VLANID]
|
||||
|
||||
self._linuxbridge_quantum_agent.process_port_binding(
|
||||
new_port[lconst.PORT_ID], new_network[lconst.NET_ID],
|
||||
interface_id, str(vlan_id))
|
||||
list_interface = self._linuxbridge_quantum_agent.linux_br.\
|
||||
get_interfaces_on_bridge(bridge_name)
|
||||
new_port[lconst.PORT_ID], new_network[lconst.NET_ID],
|
||||
interface_id, str(vlan_id))
|
||||
list_interface = (self._linuxbridge_quantum_agent.linux_br.
|
||||
get_interfaces_on_bridge(bridge_name))
|
||||
|
||||
self.assertTrue(device_name in list_interface)
|
||||
for interface in list_interface:
|
||||
self._linuxbridge_quantum_agent.linux_br.remove_interface(
|
||||
bridge_name, interface)
|
||||
bridge_name, interface)
|
||||
self.delete_device(interface)
|
||||
self.delete_bridge(bridge_name)
|
||||
self.tearDownUnplugInterface(tenant_id, new_network[lconst.NET_ID],
|
||||
@ -121,13 +121,13 @@ class LinuxBridgeAgentTest(unittest.TestCase):
|
||||
mac_address='fe:16:3e:51:60:dd'):
|
||||
|
||||
LOG.debug("test_remove_interface - START")
|
||||
new_network =\
|
||||
self._linuxbridge_plugin.create_network(tenant_id, network_name)
|
||||
new_network = (
|
||||
self._linuxbridge_plugin.create_network(tenant_id, network_name))
|
||||
new_port = self._linuxbridge_plugin.create_port(
|
||||
tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP)
|
||||
tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP)
|
||||
self._linuxbridge_plugin.plug_interface(
|
||||
tenant_id, new_network[lconst.NET_ID],
|
||||
new_port[lconst.PORT_ID], interface_id)
|
||||
tenant_id, new_network[lconst.NET_ID],
|
||||
new_port[lconst.PORT_ID], interface_id)
|
||||
bridge_name = self.br_name_prefix + new_network[lconst.NET_ID][0:11]
|
||||
self.create_bridge(bridge_name)
|
||||
device_name = self.tap_name_prefix + interface_id[0:11]
|
||||
@ -137,19 +137,19 @@ class LinuxBridgeAgentTest(unittest.TestCase):
|
||||
vlan_id = vlan_bind[lconst.VLANID]
|
||||
|
||||
self._linuxbridge_quantum_agent.process_port_binding(
|
||||
new_port[lconst.PORT_ID], new_network[lconst.NET_ID],
|
||||
interface_id, str(vlan_id))
|
||||
list_interface = self._linuxbridge_quantum_agent.linux_br.\
|
||||
get_interfaces_on_bridge(bridge_name)
|
||||
new_port[lconst.PORT_ID], new_network[lconst.NET_ID],
|
||||
interface_id, str(vlan_id))
|
||||
list_interface = (self._linuxbridge_quantum_agent.linux_br.
|
||||
get_interfaces_on_bridge(bridge_name))
|
||||
|
||||
self._linuxbridge_quantum_agent.linux_br.remove_interface(bridge_name,
|
||||
device_name)
|
||||
list_interface = self._linuxbridge_quantum_agent.linux_br.\
|
||||
get_interfaces_on_bridge(bridge_name)
|
||||
device_name)
|
||||
list_interface = (self._linuxbridge_quantum_agent.linux_br.
|
||||
get_interfaces_on_bridge(bridge_name))
|
||||
self.assertFalse(device_name in list_interface)
|
||||
for interface in list_interface:
|
||||
self._linuxbridge_quantum_agent.linux_br.remove_interface(
|
||||
bridge_name, interface)
|
||||
bridge_name, interface)
|
||||
self.delete_device(interface)
|
||||
self.delete_device(device_name)
|
||||
self.delete_bridge(bridge_name)
|
||||
@ -159,34 +159,35 @@ class LinuxBridgeAgentTest(unittest.TestCase):
|
||||
LOG.debug("test_remove_interface -END")
|
||||
|
||||
def test_ensure_vlan_bridge(
|
||||
self, tenant_id="test_tenant", network_name="test_network",
|
||||
interface_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc'):
|
||||
self, tenant_id="test_tenant",
|
||||
network_name="test_network",
|
||||
interface_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc'):
|
||||
|
||||
LOG.debug("test_ensure_vlan_bridge - START")
|
||||
new_network =\
|
||||
self._linuxbridge_plugin.create_network(tenant_id, network_name)
|
||||
new_network = (
|
||||
self._linuxbridge_plugin.create_network(tenant_id, network_name))
|
||||
new_port = self._linuxbridge_plugin.create_port(
|
||||
tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP)
|
||||
tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP)
|
||||
self._linuxbridge_plugin.plug_interface(
|
||||
tenant_id, new_network[lconst.NET_ID],
|
||||
new_port[lconst.PORT_ID], interface_id)
|
||||
tenant_id, new_network[lconst.NET_ID],
|
||||
new_port[lconst.PORT_ID], interface_id)
|
||||
bridge_name = self.br_name_prefix + new_network[lconst.NET_ID][0:11]
|
||||
vlan_bind = cdb.get_vlan_binding(new_network[lconst.NET_ID])
|
||||
vlan_id = vlan_bind[lconst.VLANID]
|
||||
vlan_subinterface = self.physical_interface + '.' + str(vlan_id)
|
||||
|
||||
self._linuxbridge_quantum_agent.linux_br.ensure_vlan_bridge(
|
||||
new_network[lconst.NET_ID], str(vlan_id))
|
||||
list_quantum_bridges = self._linuxbridge_quantum_agent.linux_br.\
|
||||
get_all_quantum_bridges()
|
||||
new_network[lconst.NET_ID], str(vlan_id))
|
||||
list_quantum_bridges = (self._linuxbridge_quantum_agent.linux_br.
|
||||
get_all_quantum_bridges())
|
||||
self.assertTrue(bridge_name in list_quantum_bridges)
|
||||
list_interface = self._linuxbridge_quantum_agent.linux_br.\
|
||||
get_interfaces_on_bridge(bridge_name)
|
||||
list_interface = (self._linuxbridge_quantum_agent.linux_br.
|
||||
get_interfaces_on_bridge(bridge_name))
|
||||
self.assertTrue(vlan_subinterface in list_interface)
|
||||
|
||||
for interface in list_interface:
|
||||
self._linuxbridge_quantum_agent.linux_br.remove_interface(
|
||||
bridge_name, interface)
|
||||
bridge_name, interface)
|
||||
self.delete_device(interface)
|
||||
self.delete_bridge(bridge_name)
|
||||
self.tearDownUnplugInterface(tenant_id, new_network[lconst.NET_ID],
|
||||
@ -195,26 +196,26 @@ class LinuxBridgeAgentTest(unittest.TestCase):
|
||||
LOG.debug("test_ensure_vlan_bridge -END")
|
||||
|
||||
def test_delete_vlan_bridge(
|
||||
self, tenant_id="test_tenant", network_name="test_network",
|
||||
interface_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc'):
|
||||
self, tenant_id="test_tenant", network_name="test_network",
|
||||
interface_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc'):
|
||||
|
||||
LOG.debug("test_delete_vlan_bridge - START")
|
||||
new_network =\
|
||||
self._linuxbridge_plugin.create_network(tenant_id, network_name)
|
||||
new_network = (
|
||||
self._linuxbridge_plugin.create_network(tenant_id, network_name))
|
||||
new_port = self._linuxbridge_plugin.create_port(
|
||||
tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP)
|
||||
tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP)
|
||||
self._linuxbridge_plugin.plug_interface(
|
||||
tenant_id, new_network[lconst.NET_ID],
|
||||
new_port[lconst.PORT_ID], interface_id)
|
||||
tenant_id, new_network[lconst.NET_ID],
|
||||
new_port[lconst.PORT_ID], interface_id)
|
||||
bridge_name = self.br_name_prefix + new_network[lconst.NET_ID][0:11]
|
||||
vlan_bind = cdb.get_vlan_binding(new_network[lconst.NET_ID])
|
||||
vlan_id = vlan_bind[lconst.VLANID]
|
||||
vlan_subinterface = self.physical_interface + '.' + str(vlan_id)
|
||||
|
||||
self._linuxbridge_quantum_agent.linux_br.ensure_vlan_bridge(
|
||||
new_network[lconst.NET_ID], str(vlan_id))
|
||||
new_network[lconst.NET_ID], str(vlan_id))
|
||||
self._linuxbridge_quantum_agent.linux_br.delete_vlan_bridge(
|
||||
bridge_name)
|
||||
bridge_name)
|
||||
|
||||
self.assertEquals(self.device_exists(vlan_subinterface), False)
|
||||
self.assertEquals(self.device_exists(bridge_name), False)
|
||||
@ -224,26 +225,26 @@ class LinuxBridgeAgentTest(unittest.TestCase):
|
||||
LOG.debug("test_delete_vlan_bridge - END")
|
||||
|
||||
def test_process_deleted_networks(
|
||||
self, tenant_id="test_tenant", network_name="test_network",
|
||||
interface_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc'):
|
||||
self, tenant_id="test_tenant", network_name="test_network",
|
||||
interface_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc'):
|
||||
|
||||
LOG.debug("test_delete_vlan_bridge - START")
|
||||
new_network =\
|
||||
self._linuxbridge_plugin.create_network(tenant_id, network_name)
|
||||
new_network = (
|
||||
self._linuxbridge_plugin.create_network(tenant_id, network_name))
|
||||
new_port = self._linuxbridge_plugin.create_port(
|
||||
tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP)
|
||||
tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP)
|
||||
self._linuxbridge_plugin.plug_interface(
|
||||
tenant_id, new_network[lconst.NET_ID],
|
||||
new_port[lconst.PORT_ID], interface_id)
|
||||
tenant_id, new_network[lconst.NET_ID],
|
||||
new_port[lconst.PORT_ID], interface_id)
|
||||
bridge_name = self.br_name_prefix + new_network[lconst.NET_ID][0:11]
|
||||
vlan_bindings = {}
|
||||
vlan_bindings[new_network[lconst.NET_ID]] =\
|
||||
cdb.get_vlan_binding(new_network[lconst.NET_ID])
|
||||
vlan_bindings[new_network[lconst.NET_ID]] = (
|
||||
cdb.get_vlan_binding(new_network[lconst.NET_ID]))
|
||||
vlan_id = vlan_bindings[new_network[lconst.NET_ID]][lconst.VLANID]
|
||||
vlan_subinterface = self.physical_interface + '.' + str(vlan_id)
|
||||
|
||||
self._linuxbridge_quantum_agent.linux_br.ensure_vlan_bridge(
|
||||
new_network[lconst.NET_ID], str(vlan_id))
|
||||
new_network[lconst.NET_ID], str(vlan_id))
|
||||
self.tearDownUnplugInterface(tenant_id, new_network[lconst.NET_ID],
|
||||
new_port[lconst.PORT_ID])
|
||||
vlan_bindings = {}
|
||||
@ -254,18 +255,18 @@ class LinuxBridgeAgentTest(unittest.TestCase):
|
||||
LOG.debug("test_delete_vlan_bridge - END")
|
||||
|
||||
def test_process_unplugged_tap_interface(
|
||||
self, tenant_id="test_tenant", network_name="test_network",
|
||||
interface_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc',
|
||||
mac_address='fe:16:3e:51:60:dd'):
|
||||
self, tenant_id="test_tenant", network_name="test_network",
|
||||
interface_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc',
|
||||
mac_address='fe:16:3e:51:60:dd'):
|
||||
|
||||
LOG.debug("test_process_unplugged_tap_interface - START")
|
||||
new_network =\
|
||||
self._linuxbridge_plugin.create_network(tenant_id, network_name)
|
||||
new_network = (
|
||||
self._linuxbridge_plugin.create_network(tenant_id, network_name))
|
||||
new_port = self._linuxbridge_plugin.create_port(
|
||||
tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP)
|
||||
tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP)
|
||||
self._linuxbridge_plugin.plug_interface(
|
||||
tenant_id, new_network[lconst.NET_ID],
|
||||
new_port[lconst.PORT_ID], interface_id)
|
||||
tenant_id, new_network[lconst.NET_ID],
|
||||
new_port[lconst.PORT_ID], interface_id)
|
||||
bridge_name = self.br_name_prefix + new_network[lconst.NET_ID][0:11]
|
||||
self.create_bridge(bridge_name)
|
||||
device_name = self.tap_name_prefix + interface_id[0:11]
|
||||
@ -275,43 +276,43 @@ class LinuxBridgeAgentTest(unittest.TestCase):
|
||||
vlan_id = vlan_bind[lconst.VLANID]
|
||||
|
||||
self._linuxbridge_quantum_agent.process_port_binding(
|
||||
new_port[lconst.PORT_ID], new_network[lconst.NET_ID],
|
||||
interface_id, str(vlan_id))
|
||||
new_port[lconst.PORT_ID], new_network[lconst.NET_ID],
|
||||
interface_id, str(vlan_id))
|
||||
list_interface = self._linuxbridge_quantum_agent.linux_br.\
|
||||
get_interfaces_on_bridge(bridge_name)
|
||||
get_interfaces_on_bridge(bridge_name)
|
||||
self._linuxbridge_plugin.unplug_interface(tenant_id,
|
||||
new_network[lconst.NET_ID],
|
||||
new_port[lconst.PORT_ID])
|
||||
plugged_interface = []
|
||||
self._linuxbridge_quantum_agent.process_unplugged_interfaces(
|
||||
plugged_interface)
|
||||
list_interface = self._linuxbridge_quantum_agent.linux_br.\
|
||||
get_interfaces_on_bridge(bridge_name)
|
||||
plugged_interface)
|
||||
list_interface = (self._linuxbridge_quantum_agent.linux_br.
|
||||
get_interfaces_on_bridge(bridge_name))
|
||||
self.assertFalse(device_name in list_interface)
|
||||
for interface in list_interface:
|
||||
self._linuxbridge_quantum_agent.linux_br.remove_interface(
|
||||
bridge_name, interface)
|
||||
bridge_name, interface)
|
||||
self.delete_device(interface)
|
||||
self.delete_device(device_name)
|
||||
self.delete_bridge(bridge_name)
|
||||
self.tearDownNetworkPort(tenant_id, new_network[lconst.NET_ID],
|
||||
new_port[lconst.PORT_ID])
|
||||
new_port[lconst.PORT_ID])
|
||||
|
||||
LOG.debug("test_test_process_unplugged_tap_interface -END")
|
||||
|
||||
def test_process_unplugged_gw_interface(
|
||||
self, tenant_id="test_tenant", network_name="test_network",
|
||||
interface_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc',
|
||||
mac_address='fe:16:3e:51:60:dd'):
|
||||
self, tenant_id="test_tenant", network_name="test_network",
|
||||
interface_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc',
|
||||
mac_address='fe:16:3e:51:60:dd'):
|
||||
|
||||
LOG.debug("test_process_unplugged_gw_interface - START")
|
||||
new_network =\
|
||||
self._linuxbridge_plugin.create_network(tenant_id, network_name)
|
||||
new_network = (
|
||||
self._linuxbridge_plugin.create_network(tenant_id, network_name))
|
||||
new_port = self._linuxbridge_plugin.create_port(
|
||||
tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP)
|
||||
tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP)
|
||||
self._linuxbridge_plugin.plug_interface(
|
||||
tenant_id, new_network[lconst.NET_ID],
|
||||
new_port[lconst.PORT_ID], interface_id)
|
||||
tenant_id, new_network[lconst.NET_ID],
|
||||
new_port[lconst.PORT_ID], interface_id)
|
||||
bridge_name = self.br_name_prefix + new_network[lconst.NET_ID][0:11]
|
||||
self.create_bridge(bridge_name)
|
||||
device_name = self.gw_name_prefix + new_network[lconst.NET_ID][0:11]
|
||||
@ -321,27 +322,27 @@ class LinuxBridgeAgentTest(unittest.TestCase):
|
||||
vlan_id = vlan_bind[lconst.VLANID]
|
||||
|
||||
self._linuxbridge_quantum_agent.process_port_binding(
|
||||
new_port[lconst.PORT_ID], new_network[lconst.NET_ID],
|
||||
interface_id, str(vlan_id))
|
||||
list_interface = self._linuxbridge_quantum_agent.linux_br.\
|
||||
get_interfaces_on_bridge(bridge_name)
|
||||
new_port[lconst.PORT_ID], new_network[lconst.NET_ID],
|
||||
interface_id, str(vlan_id))
|
||||
list_interface = (self._linuxbridge_quantum_agent.linux_br.
|
||||
get_interfaces_on_bridge(bridge_name))
|
||||
self._linuxbridge_plugin.unplug_interface(tenant_id,
|
||||
new_network[lconst.NET_ID],
|
||||
new_port[lconst.PORT_ID])
|
||||
plugged_interface = []
|
||||
self._linuxbridge_quantum_agent.process_unplugged_interfaces(
|
||||
plugged_interface)
|
||||
list_interface = self._linuxbridge_quantum_agent.linux_br.\
|
||||
get_interfaces_on_bridge(bridge_name)
|
||||
plugged_interface)
|
||||
list_interface = (self._linuxbridge_quantum_agent.linux_br.
|
||||
get_interfaces_on_bridge(bridge_name))
|
||||
self.assertFalse(device_name in list_interface)
|
||||
for interface in list_interface:
|
||||
self._linuxbridge_quantum_agent.linux_br.remove_interface(
|
||||
bridge_name, interface)
|
||||
bridge_name, interface)
|
||||
self.delete_device(interface)
|
||||
self.delete_device(device_name)
|
||||
self.delete_bridge(bridge_name)
|
||||
self.tearDownNetworkPort(tenant_id, new_network[lconst.NET_ID],
|
||||
new_port[lconst.PORT_ID])
|
||||
new_port[lconst.PORT_ID])
|
||||
|
||||
LOG.debug("test_test_process_unplugged_gw_interface -END")
|
||||
|
||||
@ -402,15 +403,15 @@ class LinuxBridgeAgentTest(unittest.TestCase):
|
||||
self.physical_interface,
|
||||
self.root_helper)
|
||||
self._linuxbridge_quantum_agent = linux_agent.LinuxBridgeQuantumAgent(
|
||||
self.br_name_prefix,
|
||||
self.physical_interface,
|
||||
self.polling_interval,
|
||||
self.root_helper)
|
||||
self.br_name_prefix,
|
||||
self.physical_interface,
|
||||
self.polling_interval,
|
||||
self.root_helper)
|
||||
|
||||
def run_cmd(self, args):
|
||||
cmd = shlex.split(self.root_helper) + args
|
||||
LOG.debug("Running command: " + " ".join(cmd))
|
||||
p = Popen(cmd, stdout=PIPE)
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
||||
retval = p.communicate()[0]
|
||||
if p.returncode == -(signal.SIGALRM):
|
||||
LOG.debug("Timeout running command: " + " ".join(args))
|
||||
|
@ -20,16 +20,18 @@
|
||||
# @author: Dave Lapsley, Nicira Networks, Inc.
|
||||
|
||||
import ConfigParser
|
||||
import logging as LOG
|
||||
import logging
|
||||
from optparse import OptionParser
|
||||
import shlex
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import signal
|
||||
|
||||
from optparse import OptionParser
|
||||
from sqlalchemy.ext.sqlsoup import SqlSoup
|
||||
from subprocess import *
|
||||
|
||||
logging.basicConfig()
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
# Global constants.
|
||||
OP_STATUS_UP = "UP"
|
||||
@ -38,7 +40,9 @@ OP_STATUS_DOWN = "DOWN"
|
||||
# A placeholder for dead vlans.
|
||||
DEAD_VLAN_TAG = "4095"
|
||||
|
||||
REFRESH_INTERVAL = 2
|
||||
# Default interval values
|
||||
DEFAULT_POLLING_INTERVAL = 2
|
||||
DEFAULT_RECONNECT_INTERVAL = 2
|
||||
|
||||
|
||||
# A class to represent a VIF (i.e., a port that has 'iface-id' and 'vif-mac'
|
||||
@ -52,9 +56,10 @@ class VifPort:
|
||||
self.switch = switch
|
||||
|
||||
def __str__(self):
|
||||
return "iface-id=" + self.vif_id + ", vif_mac=" + \
|
||||
self.vif_mac + ", port_name=" + self.port_name + \
|
||||
", ofport=" + self.ofport + ", bridge name = " + self.switch.br_name
|
||||
return ("iface-id=" + self.vif_id + ", vif_mac=" +
|
||||
self.vif_mac + ", port_name=" + self.port_name +
|
||||
", ofport=" + self.ofport + ", bridge name = " +
|
||||
self.switch.br_name)
|
||||
|
||||
|
||||
class OVSBridge:
|
||||
@ -65,7 +70,7 @@ class OVSBridge:
|
||||
def run_cmd(self, args):
|
||||
cmd = shlex.split(self.root_helper) + args
|
||||
LOG.debug("## running command: " + " ".join(cmd))
|
||||
p = Popen(cmd, stdout=PIPE)
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
||||
retval = p.communicate()[0]
|
||||
if p.returncode == -(signal.SIGALRM):
|
||||
LOG.debug("## timeout running command: " + " ".join(cmd))
|
||||
@ -127,17 +132,17 @@ class OVSBridge:
|
||||
def add_tunnel_port(self, port_name, remote_ip):
|
||||
self.run_vsctl(["add-port", self.br_name, port_name])
|
||||
self.set_db_attribute("Interface", port_name, "type", "gre")
|
||||
self.set_db_attribute("Interface", port_name, "options", "remote_ip=" +
|
||||
remote_ip)
|
||||
self.set_db_attribute("Interface", port_name, "options", "in_key=flow")
|
||||
self.set_db_attribute("Interface", port_name, "options",
|
||||
"out_key=flow")
|
||||
self.set_db_attribute("Interface", port_name, "options:remote_ip",
|
||||
remote_ip)
|
||||
self.set_db_attribute("Interface", port_name, "options:in_key", "flow")
|
||||
self.set_db_attribute("Interface", port_name, "options:out_key",
|
||||
"flow")
|
||||
return self.get_port_ofport(port_name)
|
||||
|
||||
def add_patch_port(self, local_name, remote_name):
|
||||
self.run_vsctl(["add-port", self.br_name, local_name])
|
||||
self.set_db_attribute("Interface", local_name, "type", "patch")
|
||||
self.set_db_attribute("Interface", local_name, "options", "peer=" +
|
||||
self.set_db_attribute("Interface", local_name, "options:peer",
|
||||
remote_name)
|
||||
return self.get_port_ofport(local_name)
|
||||
|
||||
@ -166,12 +171,13 @@ class OVSBridge:
|
||||
return self.db_get_map("Interface", port_name, "statistics")
|
||||
|
||||
def get_xapi_iface_id(self, xs_vif_uuid):
|
||||
return self.run_cmd(
|
||||
["xe",
|
||||
"vif-param-get",
|
||||
"param-name=other-config",
|
||||
"param-key=nicira-iface-id",
|
||||
"uuid=%s" % xs_vif_uuid]).strip()
|
||||
return self.run_cmd([
|
||||
"xe",
|
||||
"vif-param-get",
|
||||
"param-name=other-config",
|
||||
"param-key=nicira-iface-id",
|
||||
"uuid=%s" % xs_vif_uuid,
|
||||
]).strip()
|
||||
|
||||
# returns a VIF object for each VIF port
|
||||
def get_vif_ports(self):
|
||||
@ -184,8 +190,8 @@ class OVSBridge:
|
||||
p = VifPort(name, ofport, external_ids["iface-id"],
|
||||
external_ids["attached-mac"], self)
|
||||
edge_ports.append(p)
|
||||
elif "xs-vif-uuid" in external_ids and \
|
||||
"attached-mac" in external_ids:
|
||||
elif ("xs-vif-uuid" in external_ids and
|
||||
"attached-mac" in external_ids):
|
||||
# if this is a xenserver and iface-id is not automatically
|
||||
# synced to OVS from XAPI, we grab it from XAPI directly
|
||||
iface_id = self.get_xapi_iface_id(external_ids["xs-vif-uuid"])
|
||||
@ -210,13 +216,16 @@ class LocalVLANMapping:
|
||||
|
||||
class OVSQuantumAgent(object):
|
||||
|
||||
def __init__(self, integ_br, root_helper):
|
||||
def __init__(self, integ_br, root_helper,
|
||||
polling_interval, reconnect_interval):
|
||||
self.root_helper = root_helper
|
||||
self.setup_integration_br(integ_br)
|
||||
self.polling_interval = polling_interval
|
||||
self.reconnect_interval = reconnect_interval
|
||||
|
||||
def port_bound(self, port, vlan_id):
|
||||
self.int_br.set_db_attribute("Port", port.port_name, "tag",
|
||||
str(vlan_id))
|
||||
self.int_br.set_db_attribute("Port", port.port_name,
|
||||
"tag", str(vlan_id))
|
||||
self.int_br.delete_flows(match="in_port=%s" % port.ofport)
|
||||
|
||||
def port_unbound(self, port, still_exists):
|
||||
@ -229,26 +238,39 @@ class OVSQuantumAgent(object):
|
||||
# switch all traffic using L2 learning
|
||||
self.int_br.add_flow(priority=1, actions="normal")
|
||||
|
||||
def daemon_loop(self, db):
|
||||
def daemon_loop(self, db_connection_url):
|
||||
self.local_vlan_map = {}
|
||||
old_local_bindings = {}
|
||||
old_vif_ports = {}
|
||||
db_connected = False
|
||||
|
||||
while True:
|
||||
if not db_connected:
|
||||
time.sleep(self.reconnect_interval)
|
||||
db = SqlSoup(db_connection_url)
|
||||
db_connected = True
|
||||
LOG.info("Connecting to database \"%s\" on %s" %
|
||||
(db.engine.url.database, db.engine.url.host))
|
||||
|
||||
all_bindings = {}
|
||||
try:
|
||||
ports = db.ports.all()
|
||||
except:
|
||||
ports = []
|
||||
except Exception as e:
|
||||
LOG.info("Unable to get port bindings! Exception: %s" % e)
|
||||
db_connected = False
|
||||
continue
|
||||
|
||||
for port in ports:
|
||||
all_bindings[port.interface_id] = port
|
||||
|
||||
vlan_bindings = {}
|
||||
try:
|
||||
vlan_binds = db.vlan_bindings.all()
|
||||
except:
|
||||
vlan_binds = []
|
||||
except Exception as e:
|
||||
LOG.info("Unable to get vlan bindings! Exception: %s" % e)
|
||||
db_connected = False
|
||||
continue
|
||||
|
||||
for bind in vlan_binds:
|
||||
vlan_bindings[bind.network_id] = bind.vlan_id
|
||||
|
||||
@ -265,7 +287,8 @@ class OVSQuantumAgent(object):
|
||||
self.int_br.set_db_attribute("Port", p.port_name, "tag",
|
||||
DEAD_VLAN_TAG)
|
||||
self.int_br.add_flow(priority=2,
|
||||
match="in_port=%s" % p.ofport, actions="drop")
|
||||
match="in_port=%s" % p.ofport,
|
||||
actions="drop")
|
||||
|
||||
old_b = old_local_bindings.get(p.vif_id, None)
|
||||
new_b = new_local_bindings.get(p.vif_id, None)
|
||||
@ -285,8 +308,9 @@ class OVSQuantumAgent(object):
|
||||
self.port_bound(p, vlan_id)
|
||||
if p.vif_id in all_bindings:
|
||||
all_bindings[p.vif_id].op_status = OP_STATUS_UP
|
||||
LOG.info("Adding binding to net-id = %s " \
|
||||
"for %s on vlan %s" % (new_b, str(p), vlan_id))
|
||||
LOG.info(("Adding binding to net-id = %s "
|
||||
"for %s on vlan %s") %
|
||||
(new_b, str(p), vlan_id))
|
||||
|
||||
for vif_id in old_vif_ports:
|
||||
if vif_id not in new_vif_ports:
|
||||
@ -299,8 +323,15 @@ class OVSQuantumAgent(object):
|
||||
|
||||
old_vif_ports = new_vif_ports
|
||||
old_local_bindings = new_local_bindings
|
||||
db.commit()
|
||||
time.sleep(REFRESH_INTERVAL)
|
||||
try:
|
||||
db.commit()
|
||||
except Exception as e:
|
||||
LOG.info("Unable to commit to database! Exception: %s" % e)
|
||||
db.rollback()
|
||||
old_local_bindings = {}
|
||||
old_vif_ports = {}
|
||||
|
||||
time.sleep(self.polling_interval)
|
||||
|
||||
|
||||
class OVSQuantumTunnelAgent(object):
|
||||
@ -328,7 +359,7 @@ class OVSQuantumTunnelAgent(object):
|
||||
MAX_VLAN_TAG = 4094
|
||||
|
||||
def __init__(self, integ_br, tun_br, remote_ip_file, local_ip,
|
||||
root_helper):
|
||||
root_helper, polling_interval, reconnect_interval):
|
||||
'''Constructor.
|
||||
|
||||
:param integ_br: name of the integration bridge.
|
||||
@ -342,6 +373,9 @@ class OVSQuantumTunnelAgent(object):
|
||||
self.setup_integration_br(integ_br)
|
||||
self.local_vlan_map = {}
|
||||
self.setup_tunnel_br(tun_br, remote_ip_file, local_ip)
|
||||
self.db_connected = False
|
||||
self.polling_interval = polling_interval
|
||||
self.reconnect_interval = reconnect_interval
|
||||
|
||||
def provision_local_vlan(self, net_uuid, lsw_id):
|
||||
'''Provisions a local VLAN.
|
||||
@ -356,13 +390,13 @@ class OVSQuantumTunnelAgent(object):
|
||||
|
||||
# outbound
|
||||
self.tun_br.add_flow(priority=4, match="in_port=%s,dl_vlan=%s" %
|
||||
(self.patch_int_ofport, lvid),
|
||||
(self.patch_int_ofport, lvid),
|
||||
actions="set_tunnel:%s,normal" % (lsw_id))
|
||||
|
||||
# inbound
|
||||
self.tun_br.add_flow(priority=3, match="tun_id=%s" % lsw_id,
|
||||
actions="mod_vlan_vid:%s,output:%s" % (lvid,
|
||||
self.patch_int_ofport))
|
||||
actions="mod_vlan_vid:%s,output:%s" %
|
||||
(lvid, self.patch_int_ofport))
|
||||
|
||||
def reclaim_local_vlan(self, net_uuid, lvm):
|
||||
'''Reclaim a local VLAN.
|
||||
@ -401,8 +435,8 @@ class OVSQuantumTunnelAgent(object):
|
||||
:param port: a VifPort object.
|
||||
:param net_uuid: the net_uuid this port is associated with.'''
|
||||
if net_uuid not in self.local_vlan_map:
|
||||
LOG.info('port_unbound() net_uuid %s not in local_vlan_map'
|
||||
% net_uuid)
|
||||
LOG.info('port_unbound() net_uuid %s not in local_vlan_map' %
|
||||
net_uuid)
|
||||
return
|
||||
lvm = self.local_vlan_map[net_uuid]
|
||||
|
||||
@ -459,9 +493,9 @@ class OVSQuantumTunnelAgent(object):
|
||||
tunnel_ips = (x for x in clean_ips if x != local_ip and x)
|
||||
for i, remote_ip in enumerate(tunnel_ips):
|
||||
self.tun_br.add_tunnel_port("gre-" + str(i), remote_ip)
|
||||
except Exception, e:
|
||||
LOG.error("Error configuring tunnels: '%s' %s"
|
||||
% (remote_ip_file, str(e)))
|
||||
except Exception as e:
|
||||
LOG.error("Error configuring tunnels: '%s' %s" %
|
||||
(remote_ip_file, str(e)))
|
||||
raise
|
||||
|
||||
self.tun_br.remove_all_flows()
|
||||
@ -478,8 +512,10 @@ class OVSQuantumTunnelAgent(object):
|
||||
ports = []
|
||||
try:
|
||||
ports = db.ports.all()
|
||||
except Exception, e:
|
||||
LOG.info("Exception accessing db.ports: %s" % e)
|
||||
except Exceptioni as e:
|
||||
LOG.info("Unable to get port bindings! Exception: %s" % e)
|
||||
self.db_connected = False
|
||||
return {}
|
||||
|
||||
return dict([(port.interface_id, port) for port in ports])
|
||||
|
||||
@ -493,25 +529,39 @@ class OVSQuantumTunnelAgent(object):
|
||||
lsw_id_binds = []
|
||||
try:
|
||||
lsw_id_binds.extend(db.vlan_bindings.all())
|
||||
except Exception, e:
|
||||
LOG.info("Exception accessing db.vlan_bindings: %s" % e)
|
||||
except Exception as e:
|
||||
LOG.info("Unable to get vlan bindings! Exception: %s" % e)
|
||||
self.db_connected = False
|
||||
return {}
|
||||
|
||||
return dict([(bind.network_id, bind.vlan_id)
|
||||
for bind in lsw_id_binds])
|
||||
|
||||
def daemon_loop(self, db):
|
||||
def daemon_loop(self, db_connection_url):
|
||||
'''Main processing loop (not currently used).
|
||||
|
||||
:param db: reference to database layer.
|
||||
:param options: database information - in the event need to reconnect
|
||||
'''
|
||||
old_local_bindings = {}
|
||||
old_vif_ports = {}
|
||||
self.db_connected = False
|
||||
|
||||
while True:
|
||||
if not self.db_connected:
|
||||
time.sleep(self.reconnect_interval)
|
||||
db = SqlSoup(db_connection_url)
|
||||
self.db_connected = True
|
||||
LOG.info("Connecting to database \"%s\" on %s" %
|
||||
(db.engine.url.database, db.engine.url.host))
|
||||
|
||||
# Get bindings from db.
|
||||
all_bindings = self.get_db_port_bindings(db)
|
||||
if not self.db_connected:
|
||||
continue
|
||||
all_bindings_vif_port_ids = set(all_bindings.keys())
|
||||
lsw_id_bindings = self.get_db_vlan_bindings(db)
|
||||
if not self.db_connected:
|
||||
continue
|
||||
|
||||
# Get bindings from OVS bridge.
|
||||
vif_ports = self.int_br.get_vif_ports()
|
||||
@ -525,11 +575,11 @@ class OVSQuantumTunnelAgent(object):
|
||||
new_local_bindings_ids = all_bindings_vif_port_ids.intersection(
|
||||
new_vif_ports_ids)
|
||||
new_local_bindings = dict([(p, all_bindings.get(p))
|
||||
for p in new_vif_ports_ids])
|
||||
new_bindings = set((p, old_local_bindings.get(p),
|
||||
new_local_bindings.get(p)) for p in new_vif_ports_ids)
|
||||
changed_bindings = set([b for b in new_bindings
|
||||
if b[2] != b[1]])
|
||||
for p in new_vif_ports_ids])
|
||||
new_bindings = set(
|
||||
(p, old_local_bindings.get(p),
|
||||
new_local_bindings.get(p)) for p in new_vif_ports_ids)
|
||||
changed_bindings = set([b for b in new_bindings if b[2] != b[1]])
|
||||
|
||||
LOG.debug('all_bindings: %s' % all_bindings)
|
||||
LOG.debug('lsw_id_bindings: %s' % lsw_id_bindings)
|
||||
@ -563,7 +613,7 @@ class OVSQuantumTunnelAgent(object):
|
||||
new_net_uuid = new_port.network_id
|
||||
if new_net_uuid not in lsw_id_bindings:
|
||||
LOG.warn("No ls-id binding found for net-id '%s'" %
|
||||
new_net_uuid)
|
||||
new_net_uuid)
|
||||
continue
|
||||
|
||||
lsw_id = lsw_id_bindings[new_net_uuid]
|
||||
@ -572,10 +622,10 @@ class OVSQuantumTunnelAgent(object):
|
||||
LOG.info("Port " + str(p) + " on net-id = "
|
||||
+ new_net_uuid + " bound to " +
|
||||
str(self.local_vlan_map[new_net_uuid]))
|
||||
except Exception, e:
|
||||
except Exception as e:
|
||||
LOG.info("Unable to bind Port " + str(p) +
|
||||
" on netid = " + new_net_uuid + " to "
|
||||
+ str(self.local_vlan_map[new_net_uuid]))
|
||||
" on netid = " + new_net_uuid + " to "
|
||||
+ str(self.local_vlan_map[new_net_uuid]))
|
||||
|
||||
for vif_id in disappeared_vif_ports_ids:
|
||||
LOG.info("Port Disappeared: " + vif_id)
|
||||
@ -590,7 +640,7 @@ class OVSQuantumTunnelAgent(object):
|
||||
|
||||
old_vif_ports = new_vif_ports
|
||||
old_local_bindings = new_local_bindings
|
||||
time.sleep(REFRESH_INTERVAL)
|
||||
time.sleep(self.polling_interval)
|
||||
|
||||
|
||||
def main():
|
||||
@ -602,9 +652,9 @@ def main():
|
||||
options, args = parser.parse_args()
|
||||
|
||||
if options.verbose:
|
||||
LOG.basicConfig(level=LOG.DEBUG)
|
||||
LOG.setLevel(logging.DEBUG)
|
||||
else:
|
||||
LOG.basicConfig(level=LOG.WARN)
|
||||
LOG.setLevel(logging.WARNING)
|
||||
|
||||
if len(args) != 1:
|
||||
parser.print_help()
|
||||
@ -614,16 +664,16 @@ def main():
|
||||
config = ConfigParser.ConfigParser()
|
||||
try:
|
||||
config.read(config_file)
|
||||
except Exception, e:
|
||||
LOG.error("Unable to parse config file \"%s\": %s"
|
||||
% (config_file, str(e)))
|
||||
except Exception as e:
|
||||
LOG.error("Unable to parse config file \"%s\": %s" %
|
||||
(config_file, str(e)))
|
||||
raise e
|
||||
|
||||
# Determine which agent type to use.
|
||||
enable_tunneling = False
|
||||
try:
|
||||
enable_tunneling = config.getboolean("OVS", "enable-tunneling")
|
||||
except Exception, e:
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
# Get common parameters.
|
||||
@ -636,11 +686,21 @@ def main():
|
||||
if not len(db_connection_url):
|
||||
raise Exception('Empty db_connection_url in configuration file.')
|
||||
|
||||
if config.has_option("AGENT", "polling_interval"):
|
||||
polling_interval = config.getint("AGENT", "polling_interval")
|
||||
else:
|
||||
polling_interval = DEFAULT_POLLING_INTERVAL
|
||||
LOG.info("Polling interval not defined. Using default.")
|
||||
if config.has_option("AGENT", "reconnect_interval"):
|
||||
reconnect_interval = config.getint("AGENT", "reconnect_interval")
|
||||
else:
|
||||
reconnect_interval = DEFAULT_RECONNECT_INTERVAL
|
||||
LOG.info("Reconnect interval not defined. Using default.")
|
||||
root_helper = config.get("AGENT", "root_helper")
|
||||
|
||||
except Exception, e:
|
||||
LOG.error("Error parsing common params in config_file: '%s': %s"
|
||||
% (config_file, str(e)))
|
||||
except Exception as e:
|
||||
LOG.error("Error parsing common params in config_file: '%s': %s" %
|
||||
(config_file, str(e)))
|
||||
sys.exit(1)
|
||||
|
||||
if enable_tunneling:
|
||||
@ -661,24 +721,22 @@ def main():
|
||||
local_ip = config.get("OVS", "local-ip")
|
||||
if not len(local_ip):
|
||||
raise Exception('Empty local-ip in configuration file.')
|
||||
except Exception, e:
|
||||
LOG.error("Error parsing tunnel params in config_file: '%s': %s"
|
||||
% (config_file, str(e)))
|
||||
|
||||
except Exception as e:
|
||||
LOG.error("Error parsing tunnel params in config_file: '%s': %s" %
|
||||
(config_file, str(e)))
|
||||
sys.exit(1)
|
||||
|
||||
plugin = OVSQuantumTunnelAgent(integ_br, tun_br, remote_ip_file,
|
||||
local_ip, root_helper)
|
||||
local_ip, root_helper,
|
||||
polling_interval, reconnect_interval)
|
||||
else:
|
||||
# Get parameters for OVSQuantumAgent.
|
||||
plugin = OVSQuantumAgent(integ_br, root_helper)
|
||||
plugin = OVSQuantumAgent(integ_br, root_helper,
|
||||
polling_interval, reconnect_interval)
|
||||
|
||||
# Start everything.
|
||||
options = {"sql_connection": db_connection_url}
|
||||
db = SqlSoup(options["sql_connection"])
|
||||
LOG.info("Connecting to database \"%s\" on %s" %
|
||||
(db.engine.url.database, db.engine.url.host))
|
||||
|
||||
plugin.daemon_loop(db)
|
||||
plugin.daemon_loop(db_connection_url)
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
|
@ -89,7 +89,7 @@ class TunnelTest(unittest.TestCase):
|
||||
self.TUN_BRIDGE,
|
||||
REMOTE_IP_FILE,
|
||||
'10.0.0.1',
|
||||
'sudo')
|
||||
'sudo', 2, 2)
|
||||
self.mox.VerifyAll()
|
||||
|
||||
def testProvisionLocalVlan(self):
|
||||
@ -109,7 +109,7 @@ class TunnelTest(unittest.TestCase):
|
||||
self.TUN_BRIDGE,
|
||||
REMOTE_IP_FILE,
|
||||
'10.0.0.1',
|
||||
'sudo')
|
||||
'sudo', 2, 2)
|
||||
a.available_local_vlans = set([LV_ID])
|
||||
a.provision_local_vlan(NET_UUID, LS_ID)
|
||||
self.mox.VerifyAll()
|
||||
@ -126,7 +126,7 @@ class TunnelTest(unittest.TestCase):
|
||||
self.TUN_BRIDGE,
|
||||
REMOTE_IP_FILE,
|
||||
'10.0.0.1',
|
||||
'sudo')
|
||||
'sudo', 2, 2)
|
||||
a.available_local_vlans = set()
|
||||
a.local_vlan_map[NET_UUID] = LVM
|
||||
a.reclaim_local_vlan(NET_UUID, LVM)
|
||||
@ -143,7 +143,7 @@ class TunnelTest(unittest.TestCase):
|
||||
self.TUN_BRIDGE,
|
||||
REMOTE_IP_FILE,
|
||||
'10.0.0.1',
|
||||
'sudo')
|
||||
'sudo', 2, 2)
|
||||
a.local_vlan_map[NET_UUID] = LVM
|
||||
a.port_bound(VIF_PORT, NET_UUID, LS_ID)
|
||||
self.mox.VerifyAll()
|
||||
@ -154,7 +154,7 @@ class TunnelTest(unittest.TestCase):
|
||||
self.TUN_BRIDGE,
|
||||
REMOTE_IP_FILE,
|
||||
'10.0.0.1',
|
||||
'sudo')
|
||||
'sudo', 2, 2)
|
||||
a.available_local_vlans = set([LV_ID])
|
||||
a.local_vlan_map[NET_UUID] = LVM
|
||||
a.port_unbound(VIF_PORT, NET_UUID)
|
||||
@ -173,7 +173,7 @@ class TunnelTest(unittest.TestCase):
|
||||
self.TUN_BRIDGE,
|
||||
REMOTE_IP_FILE,
|
||||
'10.0.0.1',
|
||||
'sudo')
|
||||
'sudo', 2, 2)
|
||||
a.available_local_vlans = set([LV_ID])
|
||||
a.local_vlan_map[NET_UUID] = LVM
|
||||
a.port_dead(VIF_PORT)
|
||||
@ -196,7 +196,7 @@ class TunnelTest(unittest.TestCase):
|
||||
self.TUN_BRIDGE,
|
||||
REMOTE_IP_FILE,
|
||||
'10.0.0.1',
|
||||
'sudo')
|
||||
'sudo', 2, 2)
|
||||
|
||||
all_bindings = a.get_db_port_bindings(db)
|
||||
lsw_id_bindings = a.get_db_vlan_bindings(db)
|
||||
|
Loading…
Reference in New Issue
Block a user