Merge "Add common dir for shared agent code, add OVS lib."
This commit is contained in:
commit
03f7735197
16
quantum/agent/__init__.py
Normal file
16
quantum/agent/__init__.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright 2012 OpenStack LLC
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
16
quantum/agent/linux/__init__.py
Normal file
16
quantum/agent/linux/__init__.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright 2012 OpenStack LLC
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
214
quantum/agent/linux/ovs_lib.py
Normal file
214
quantum/agent/linux/ovs_lib.py
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
# Copyright 2011 Nicira Networks, Inc.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
# @author: Somik Behera, Nicira Networks, Inc.
|
||||||
|
# @author: Brad Hall, Nicira Networks, Inc.
|
||||||
|
# @author: Dan Wendlandt, Nicira Networks, Inc.
|
||||||
|
# @author: Dave Lapsley, Nicira Networks, Inc.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import shlex
|
||||||
|
import signal
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class VifPort:
|
||||||
|
def __init__(self, port_name, ofport, vif_id, vif_mac, switch):
|
||||||
|
self.port_name = port_name
|
||||||
|
self.ofport = ofport
|
||||||
|
self.vif_id = vif_id
|
||||||
|
self.vif_mac = vif_mac
|
||||||
|
self.switch = switch
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return ("iface-id=" + self.vif_id + ", vif_mac=" +
|
||||||
|
self.vif_mac + ", port_name=" + self.port_name +
|
||||||
|
", ofport=" + str(self.ofport) + ", bridge_name = " +
|
||||||
|
self.switch.br_name)
|
||||||
|
|
||||||
|
|
||||||
|
class OVSBridge:
|
||||||
|
def __init__(self, br_name, root_helper):
|
||||||
|
self.br_name = br_name
|
||||||
|
self.root_helper = root_helper
|
||||||
|
|
||||||
|
def run_cmd(self, args):
|
||||||
|
cmd = shlex.split(self.root_helper) + args
|
||||||
|
LOG.debug("## running command: " + " ".join(cmd))
|
||||||
|
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
||||||
|
retval = p.communicate()[0]
|
||||||
|
if p.returncode == -(signal.SIGALRM):
|
||||||
|
LOG.debug("## timeout running command: " + " ".join(cmd))
|
||||||
|
return retval
|
||||||
|
|
||||||
|
def run_vsctl(self, args):
|
||||||
|
full_args = ["ovs-vsctl", "--timeout=2"] + args
|
||||||
|
return self.run_cmd(full_args)
|
||||||
|
|
||||||
|
def reset_bridge(self):
|
||||||
|
self.run_vsctl(["--", "--if-exists", "del-br", self.br_name])
|
||||||
|
self.run_vsctl(["add-br", self.br_name])
|
||||||
|
|
||||||
|
def delete_port(self, port_name):
|
||||||
|
self.run_vsctl(["--", "--if-exists", "del-port", self.br_name,
|
||||||
|
port_name])
|
||||||
|
|
||||||
|
def set_db_attribute(self, table_name, record, column, value):
|
||||||
|
args = ["set", table_name, record, "%s=%s" % (column, value)]
|
||||||
|
self.run_vsctl(args)
|
||||||
|
|
||||||
|
def clear_db_attribute(self, table_name, record, column):
|
||||||
|
args = ["clear", table_name, record, column]
|
||||||
|
self.run_vsctl(args)
|
||||||
|
|
||||||
|
def run_ofctl(self, cmd, args):
|
||||||
|
full_args = ["ovs-ofctl", cmd, self.br_name] + args
|
||||||
|
return self.run_cmd(full_args)
|
||||||
|
|
||||||
|
def count_flows(self):
|
||||||
|
flow_list = self.run_ofctl("dump-flows", []).split("\n")[1:]
|
||||||
|
return len(flow_list) - 1
|
||||||
|
|
||||||
|
def remove_all_flows(self):
|
||||||
|
self.run_ofctl("del-flows", [])
|
||||||
|
|
||||||
|
def get_port_ofport(self, port_name):
|
||||||
|
return self.db_get_val("Interface", port_name, "ofport")
|
||||||
|
|
||||||
|
def _build_flow_expr_arr(self, **kwargs):
|
||||||
|
flow_expr_arr = []
|
||||||
|
is_delete_expr = kwargs.get('delete', False)
|
||||||
|
print "kwargs = %s" % kwargs
|
||||||
|
if not is_delete_expr:
|
||||||
|
prefix = ("hard_timeout=%s,idle_timeout=%s,priority=%s"
|
||||||
|
% (kwargs.get('hard_timeout', '0'),
|
||||||
|
kwargs.get('idle_timeout', '0'),
|
||||||
|
kwargs.get('priority', '1')))
|
||||||
|
flow_expr_arr.append(prefix)
|
||||||
|
elif 'priority' in kwargs:
|
||||||
|
raise Exception("Cannot match priority on flow deletion")
|
||||||
|
|
||||||
|
in_port = ('in_port' in kwargs and ",in_port=%s" %
|
||||||
|
kwargs['in_port'] or '')
|
||||||
|
dl_type = ('dl_type' in kwargs and ",dl_type=%s" %
|
||||||
|
kwargs['dl_type'] or '')
|
||||||
|
dl_vlan = ('dl_vlan' in kwargs and ",dl_vlan=%s" %
|
||||||
|
kwargs['dl_vlan'] or '')
|
||||||
|
dl_src = 'dl_src' in kwargs and ",dl_src=%s" % kwargs['dl_src'] or ''
|
||||||
|
dl_dst = 'dl_dst' in kwargs and ",dl_dst=%s" % kwargs['dl_dst'] or ''
|
||||||
|
nw_src = 'nw_src' in kwargs and ",nw_src=%s" % kwargs['nw_src'] or ''
|
||||||
|
nw_dst = 'nw_dst' in kwargs and ",nw_dst=%s" % kwargs['nw_dst'] or ''
|
||||||
|
tun_id = 'tun_id' in kwargs and ",tun_id=%s" % kwargs['tun_id'] or ''
|
||||||
|
proto = 'proto' in kwargs and ",%s" % kwargs['proto'] or ''
|
||||||
|
ip = ('nw_src' in kwargs or 'nw_dst' in kwargs) and ',ip' or ''
|
||||||
|
match = (in_port + dl_type + dl_vlan + dl_src + dl_dst +
|
||||||
|
(ip or proto) + nw_src + nw_dst + tun_id)
|
||||||
|
if match:
|
||||||
|
match = match[1:] # strip leading comma
|
||||||
|
flow_expr_arr.append(match)
|
||||||
|
return flow_expr_arr
|
||||||
|
|
||||||
|
def add_flow(self, **kwargs):
|
||||||
|
if "actions" not in kwargs:
|
||||||
|
raise Exception("must specify one or more actions")
|
||||||
|
if "priority" not in kwargs:
|
||||||
|
kwargs["priority"] = "0"
|
||||||
|
|
||||||
|
flow_expr_arr = self._build_flow_expr_arr(**kwargs)
|
||||||
|
flow_expr_arr.append("actions=%s" % (kwargs["actions"]))
|
||||||
|
flow_str = ",".join(flow_expr_arr)
|
||||||
|
self.run_ofctl("add-flow", [flow_str])
|
||||||
|
|
||||||
|
def delete_flows(self, **kwargs):
|
||||||
|
kwargs['delete'] = True
|
||||||
|
flow_expr_arr = self._build_flow_expr_arr(**kwargs)
|
||||||
|
if "actions" in kwargs:
|
||||||
|
flow_expr_arr.append("actions=%s" % (kwargs["actions"]))
|
||||||
|
flow_str = ",".join(flow_expr_arr)
|
||||||
|
self.run_ofctl("del-flows", [flow_str])
|
||||||
|
|
||||||
|
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")
|
||||||
|
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",
|
||||||
|
remote_name)
|
||||||
|
return self.get_port_ofport(local_name)
|
||||||
|
|
||||||
|
def db_get_map(self, table, record, column):
|
||||||
|
str = self.run_vsctl(["get", table, record, column]).rstrip("\n\r")
|
||||||
|
return self.db_str_to_map(str)
|
||||||
|
|
||||||
|
def db_get_val(self, table, record, column):
|
||||||
|
return self.run_vsctl(["get", table, record, column]).rstrip("\n\r")
|
||||||
|
|
||||||
|
def db_str_to_map(self, full_str):
|
||||||
|
list = full_str.strip("{}").split(", ")
|
||||||
|
ret = {}
|
||||||
|
for e in list:
|
||||||
|
if e.find("=") == -1:
|
||||||
|
continue
|
||||||
|
arr = e.split("=")
|
||||||
|
ret[arr[0]] = arr[1].strip("\"")
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def get_port_name_list(self):
|
||||||
|
res = self.run_vsctl(["list-ports", self.br_name])
|
||||||
|
return res.split("\n")[0:-1]
|
||||||
|
|
||||||
|
def get_port_stats(self, port_name):
|
||||||
|
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()
|
||||||
|
|
||||||
|
# returns a VIF object for each VIF port
|
||||||
|
def get_vif_ports(self):
|
||||||
|
edge_ports = []
|
||||||
|
port_names = self.get_port_name_list()
|
||||||
|
for name in port_names:
|
||||||
|
external_ids = self.db_get_map("Interface", name, "external_ids")
|
||||||
|
ofport = self.db_get_val("Interface", name, "ofport")
|
||||||
|
if "iface-id" in external_ids and "attached-mac" in external_ids:
|
||||||
|
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):
|
||||||
|
# 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"])
|
||||||
|
p = VifPort(name, ofport, iface_id,
|
||||||
|
external_ids["attached-mac"], self)
|
||||||
|
edge_ports.append(p)
|
||||||
|
|
||||||
|
return edge_ports
|
@ -21,18 +21,16 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
from optparse import OptionParser
|
from optparse import OptionParser
|
||||||
import shlex
|
|
||||||
import signal
|
import signal
|
||||||
import subprocess
|
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import sqlalchemy
|
import sqlalchemy
|
||||||
from sqlalchemy.ext import sqlsoup
|
from sqlalchemy.ext import sqlsoup
|
||||||
|
|
||||||
|
from quantum.agent.linux import ovs_lib
|
||||||
from quantum.plugins.openvswitch.common import config
|
from quantum.plugins.openvswitch.common import config
|
||||||
|
|
||||||
|
|
||||||
logging.basicConfig()
|
logging.basicConfig()
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -50,165 +48,6 @@ DEFAULT_RECONNECT_INTERVAL = 2
|
|||||||
|
|
||||||
# A class to represent a VIF (i.e., a port that has 'iface-id' and 'vif-mac'
|
# A class to represent a VIF (i.e., a port that has 'iface-id' and 'vif-mac'
|
||||||
# attributes set).
|
# attributes set).
|
||||||
class VifPort:
|
|
||||||
def __init__(self, port_name, ofport, vif_id, vif_mac, switch):
|
|
||||||
self.port_name = port_name
|
|
||||||
self.ofport = ofport
|
|
||||||
self.vif_id = vif_id
|
|
||||||
self.vif_mac = vif_mac
|
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
class OVSBridge:
|
|
||||||
def __init__(self, br_name, root_helper):
|
|
||||||
self.br_name = br_name
|
|
||||||
self.root_helper = root_helper
|
|
||||||
|
|
||||||
def run_cmd(self, args):
|
|
||||||
cmd = shlex.split(self.root_helper) + args
|
|
||||||
LOG.debug("## running command: " + " ".join(cmd))
|
|
||||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
|
||||||
retval = p.communicate()[0]
|
|
||||||
if p.returncode == -(signal.SIGALRM):
|
|
||||||
LOG.debug("## timeout running command: " + " ".join(cmd))
|
|
||||||
return retval
|
|
||||||
|
|
||||||
def run_vsctl(self, args):
|
|
||||||
full_args = ["ovs-vsctl", "--timeout=2"] + args
|
|
||||||
return self.run_cmd(full_args)
|
|
||||||
|
|
||||||
def reset_bridge(self):
|
|
||||||
self.run_vsctl(["--", "--if-exists", "del-br", self.br_name])
|
|
||||||
self.run_vsctl(["add-br", self.br_name])
|
|
||||||
|
|
||||||
def delete_port(self, port_name):
|
|
||||||
self.run_vsctl(["--", "--if-exists", "del-port", self.br_name,
|
|
||||||
port_name])
|
|
||||||
|
|
||||||
def set_db_attribute(self, table_name, record, column, value):
|
|
||||||
args = ["set", table_name, record, "%s=%s" % (column, value)]
|
|
||||||
self.run_vsctl(args)
|
|
||||||
|
|
||||||
def clear_db_attribute(self, table_name, record, column):
|
|
||||||
args = ["clear", table_name, record, column]
|
|
||||||
self.run_vsctl(args)
|
|
||||||
|
|
||||||
def run_ofctl(self, cmd, args):
|
|
||||||
full_args = ["ovs-ofctl", cmd, self.br_name] + args
|
|
||||||
return self.run_cmd(full_args)
|
|
||||||
|
|
||||||
def count_flows(self):
|
|
||||||
flow_list = self.run_ofctl("dump-flows", []).split("\n")[1:]
|
|
||||||
return len(flow_list) - 1
|
|
||||||
|
|
||||||
def remove_all_flows(self):
|
|
||||||
self.run_ofctl("del-flows", [])
|
|
||||||
|
|
||||||
def get_port_ofport(self, port_name):
|
|
||||||
return self.db_get_val("Interface", port_name, "ofport")
|
|
||||||
|
|
||||||
def add_flow(self, **dict):
|
|
||||||
if "actions" not in dict:
|
|
||||||
raise Exception("must specify one or more actions")
|
|
||||||
if "priority" not in dict:
|
|
||||||
dict["priority"] = "0"
|
|
||||||
|
|
||||||
flow_str = "priority=%s" % dict["priority"]
|
|
||||||
if "match" in dict:
|
|
||||||
flow_str += "," + dict["match"]
|
|
||||||
flow_str += ",actions=%s" % (dict["actions"])
|
|
||||||
self.run_ofctl("add-flow", [flow_str])
|
|
||||||
|
|
||||||
def delete_flows(self, **dict):
|
|
||||||
all_args = []
|
|
||||||
if "priority" in dict:
|
|
||||||
all_args.append("priority=%s" % dict["priority"])
|
|
||||||
if "match" in dict:
|
|
||||||
all_args.append(dict["match"])
|
|
||||||
if "actions" in dict:
|
|
||||||
all_args.append("actions=%s" % (dict["actions"]))
|
|
||||||
flow_str = ",".join(all_args)
|
|
||||||
self.run_ofctl("del-flows", [flow_str])
|
|
||||||
|
|
||||||
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")
|
|
||||||
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",
|
|
||||||
remote_name)
|
|
||||||
return self.get_port_ofport(local_name)
|
|
||||||
|
|
||||||
def db_get_map(self, table, record, column):
|
|
||||||
str = self.run_vsctl(["get", table, record, column]).rstrip("\n\r")
|
|
||||||
return self.db_str_to_map(str)
|
|
||||||
|
|
||||||
def db_get_val(self, table, record, column):
|
|
||||||
return self.run_vsctl(["get", table, record, column]).rstrip("\n\r")
|
|
||||||
|
|
||||||
def db_str_to_map(self, full_str):
|
|
||||||
list = full_str.strip("{}").split(", ")
|
|
||||||
ret = {}
|
|
||||||
for e in list:
|
|
||||||
if e.find("=") == -1:
|
|
||||||
continue
|
|
||||||
arr = e.split("=")
|
|
||||||
ret[arr[0]] = arr[1].strip("\"")
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def get_port_name_list(self):
|
|
||||||
res = self.run_vsctl(["list-ports", self.br_name])
|
|
||||||
return res.split("\n")[0:-1]
|
|
||||||
|
|
||||||
def get_port_stats(self, port_name):
|
|
||||||
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()
|
|
||||||
|
|
||||||
# returns a VIF object for each VIF port
|
|
||||||
def get_vif_ports(self):
|
|
||||||
edge_ports = []
|
|
||||||
port_names = self.get_port_name_list()
|
|
||||||
for name in port_names:
|
|
||||||
external_ids = self.db_get_map("Interface", name, "external_ids")
|
|
||||||
ofport = self.db_get_val("Interface", name, "ofport")
|
|
||||||
if "iface-id" in external_ids and "attached-mac" in external_ids:
|
|
||||||
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):
|
|
||||||
# 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"])
|
|
||||||
p = VifPort(name, ofport, iface_id,
|
|
||||||
external_ids["attached-mac"], self)
|
|
||||||
edge_ports.append(p)
|
|
||||||
|
|
||||||
return edge_ports
|
|
||||||
|
|
||||||
|
|
||||||
class LocalVLANMapping:
|
class LocalVLANMapping:
|
||||||
def __init__(self, vlan, lsw_id, vif_ids=None):
|
def __init__(self, vlan, lsw_id, vif_ids=None):
|
||||||
if vif_ids is None:
|
if vif_ids is None:
|
||||||
@ -263,14 +102,14 @@ class OVSQuantumAgent(object):
|
|||||||
def port_bound(self, port, vlan_id):
|
def port_bound(self, port, vlan_id):
|
||||||
self.int_br.set_db_attribute("Port", port.port_name,
|
self.int_br.set_db_attribute("Port", port.port_name,
|
||||||
"tag", str(vlan_id))
|
"tag", str(vlan_id))
|
||||||
self.int_br.delete_flows(match="in_port=%s" % port.ofport)
|
self.int_br.delete_flows(in_port=port.ofport)
|
||||||
|
|
||||||
def port_unbound(self, port, still_exists):
|
def port_unbound(self, port, still_exists):
|
||||||
if still_exists:
|
if still_exists:
|
||||||
self.int_br.clear_db_attribute("Port", port.port_name, "tag")
|
self.int_br.clear_db_attribute("Port", port.port_name, "tag")
|
||||||
|
|
||||||
def setup_integration_br(self, integ_br):
|
def setup_integration_br(self, integ_br):
|
||||||
self.int_br = OVSBridge(integ_br, self.root_helper)
|
self.int_br = ovs_lib.OVSBridge(integ_br, self.root_helper)
|
||||||
self.int_br.remove_all_flows()
|
self.int_br.remove_all_flows()
|
||||||
# switch all traffic using L2 learning
|
# switch all traffic using L2 learning
|
||||||
self.int_br.add_flow(priority=1, actions="normal")
|
self.int_br.add_flow(priority=1, actions="normal")
|
||||||
@ -328,7 +167,7 @@ class OVSQuantumAgent(object):
|
|||||||
self.int_br.set_db_attribute("Port", p.port_name, "tag",
|
self.int_br.set_db_attribute("Port", p.port_name, "tag",
|
||||||
DEAD_VLAN_TAG)
|
DEAD_VLAN_TAG)
|
||||||
self.int_br.add_flow(priority=2,
|
self.int_br.add_flow(priority=2,
|
||||||
match="in_port=%s" % p.ofport,
|
in_port=p.ofport,
|
||||||
actions="drop")
|
actions="drop")
|
||||||
|
|
||||||
old_b = old_local_bindings.get(p.vif_id, None)
|
old_b = old_local_bindings.get(p.vif_id, None)
|
||||||
@ -435,12 +274,12 @@ class OVSQuantumTunnelAgent(object):
|
|||||||
self.local_vlan_map[net_uuid] = LocalVLANMapping(lvid, lsw_id)
|
self.local_vlan_map[net_uuid] = LocalVLANMapping(lvid, lsw_id)
|
||||||
|
|
||||||
# outbound
|
# outbound
|
||||||
self.tun_br.add_flow(priority=4, match="in_port=%s,dl_vlan=%s" %
|
self.tun_br.add_flow(priority=4, in_port=self.patch_int_ofport,
|
||||||
(self.patch_int_ofport, lvid),
|
dl_vlan=lvid,
|
||||||
actions="strip_vlan,set_tunnel:%s,normal" %
|
actions="strip_vlan,set_tunnel:%s,normal" %
|
||||||
(lsw_id))
|
(lsw_id))
|
||||||
# inbound
|
# inbound
|
||||||
self.tun_br.add_flow(priority=3, match="tun_id=%s" % lsw_id,
|
self.tun_br.add_flow(priority=3, tun_id=lsw_id,
|
||||||
actions="mod_vlan_vid:%s,output:%s" %
|
actions="mod_vlan_vid:%s,output:%s" %
|
||||||
(lvid, self.patch_int_ofport))
|
(lvid, self.patch_int_ofport))
|
||||||
|
|
||||||
@ -451,15 +290,15 @@ class OVSQuantumTunnelAgent(object):
|
|||||||
:param lvm: a LocalVLANMapping object that tracks (vlan, lsw_id,
|
:param lvm: a LocalVLANMapping object that tracks (vlan, lsw_id,
|
||||||
vif_ids) mapping.'''
|
vif_ids) mapping.'''
|
||||||
LOG.info("reclaming vlan = %s from net-id = %s" % (lvm.vlan, net_uuid))
|
LOG.info("reclaming vlan = %s from net-id = %s" % (lvm.vlan, net_uuid))
|
||||||
self.tun_br.delete_flows(match="tun_id=%s" % lvm.lsw_id)
|
self.tun_br.delete_flows(tun_id=lvm.lsw_id)
|
||||||
self.tun_br.delete_flows(match="dl_vlan=%s" % lvm.vlan)
|
self.tun_br.delete_flows(dl_vlan=lvm.vlan)
|
||||||
del self.local_vlan_map[net_uuid]
|
del self.local_vlan_map[net_uuid]
|
||||||
self.available_local_vlans.add(lvm.vlan)
|
self.available_local_vlans.add(lvm.vlan)
|
||||||
|
|
||||||
def port_bound(self, port, net_uuid, lsw_id):
|
def port_bound(self, port, net_uuid, lsw_id):
|
||||||
'''Bind port to net_uuid/lsw_id.
|
'''Bind port to net_uuid/lsw_id.
|
||||||
|
|
||||||
:param port: a VifPort object.
|
:param port: a ovslib.VifPort object.
|
||||||
:param net_uuid: the net_uuid this port is to be associated with.
|
:param net_uuid: the net_uuid this port is to be associated with.
|
||||||
:param lsw_id: the logical switch this port is to be associated with.
|
:param lsw_id: the logical switch this port is to be associated with.
|
||||||
'''
|
'''
|
||||||
@ -470,7 +309,7 @@ class OVSQuantumTunnelAgent(object):
|
|||||||
|
|
||||||
self.int_br.set_db_attribute("Port", port.port_name, "tag",
|
self.int_br.set_db_attribute("Port", port.port_name, "tag",
|
||||||
str(lvm.vlan))
|
str(lvm.vlan))
|
||||||
self.int_br.delete_flows(match="in_port=%s" % port.ofport)
|
self.int_br.delete_flows(in_port=port.ofport)
|
||||||
|
|
||||||
def port_unbound(self, port, net_uuid):
|
def port_unbound(self, port, net_uuid):
|
||||||
'''Unbind port.
|
'''Unbind port.
|
||||||
@ -478,7 +317,7 @@ class OVSQuantumTunnelAgent(object):
|
|||||||
Removes corresponding local vlan mapping object if this is its last
|
Removes corresponding local vlan mapping object if this is its last
|
||||||
VIF.
|
VIF.
|
||||||
|
|
||||||
:param port: a VifPort object.
|
:param port: a ovslib.VifPort object.
|
||||||
:param net_uuid: the net_uuid this port is associated with.'''
|
:param net_uuid: the net_uuid this port is associated with.'''
|
||||||
if net_uuid not in self.local_vlan_map:
|
if net_uuid not in self.local_vlan_map:
|
||||||
LOG.info('port_unbound() net_uuid %s not in local_vlan_map' %
|
LOG.info('port_unbound() net_uuid %s not in local_vlan_map' %
|
||||||
@ -497,11 +336,10 @@ class OVSQuantumTunnelAgent(object):
|
|||||||
def port_dead(self, port):
|
def port_dead(self, port):
|
||||||
'''Once a port has no binding, put it on the "dead vlan".
|
'''Once a port has no binding, put it on the "dead vlan".
|
||||||
|
|
||||||
:param port: a VifPort object.'''
|
:param port: a ovs_lib.VifPort object.'''
|
||||||
self.int_br.set_db_attribute("Port", port.port_name, "tag",
|
self.int_br.set_db_attribute("Port", port.port_name, "tag",
|
||||||
DEAD_VLAN_TAG)
|
DEAD_VLAN_TAG)
|
||||||
self.int_br.add_flow(priority=2,
|
self.int_br.add_flow(priority=2, in_port=port.ofport, actions="drop")
|
||||||
match="in_port=%s" % port.ofport, actions="drop")
|
|
||||||
|
|
||||||
def setup_integration_br(self, integ_br):
|
def setup_integration_br(self, integ_br):
|
||||||
'''Setup the integration bridge.
|
'''Setup the integration bridge.
|
||||||
@ -509,7 +347,7 @@ class OVSQuantumTunnelAgent(object):
|
|||||||
Create patch ports and remove all existing flows.
|
Create patch ports and remove all existing flows.
|
||||||
|
|
||||||
:param integ_br: the name of the integration bridge.'''
|
:param integ_br: the name of the integration bridge.'''
|
||||||
self.int_br = OVSBridge(integ_br, self.root_helper)
|
self.int_br = ovs_lib.OVSBridge(integ_br, self.root_helper)
|
||||||
self.int_br.delete_port("patch-tun")
|
self.int_br.delete_port("patch-tun")
|
||||||
self.patch_tun_ofport = self.int_br.add_patch_port("patch-tun",
|
self.patch_tun_ofport = self.int_br.add_patch_port("patch-tun",
|
||||||
"patch-int")
|
"patch-int")
|
||||||
@ -524,7 +362,7 @@ class OVSQuantumTunnelAgent(object):
|
|||||||
using a patch port.
|
using a patch port.
|
||||||
|
|
||||||
:param tun_br: the name of the tunnel bridge.'''
|
:param tun_br: the name of the tunnel bridge.'''
|
||||||
self.tun_br = OVSBridge(tun_br, self.root_helper)
|
self.tun_br = ovs_lib.OVSBridge(tun_br, self.root_helper)
|
||||||
self.tun_br.reset_bridge()
|
self.tun_br.reset_bridge()
|
||||||
self.patch_int_ofport = self.tun_br.add_patch_port("patch-int",
|
self.patch_int_ofport = self.tun_br.add_patch_port("patch-int",
|
||||||
"patch-tun")
|
"patch-tun")
|
||||||
|
@ -22,7 +22,7 @@ import unittest
|
|||||||
import mox
|
import mox
|
||||||
|
|
||||||
from quantum.plugins.openvswitch.agent import ovs_quantum_agent
|
from quantum.plugins.openvswitch.agent import ovs_quantum_agent
|
||||||
|
from quantum.agent.linux import ovs_lib
|
||||||
|
|
||||||
# Useful global dummy variables.
|
# Useful global dummy variables.
|
||||||
NET_UUID = '3faeebfe-5d37-11e1-a64b-000c29d5f0a7'
|
NET_UUID = '3faeebfe-5d37-11e1-a64b-000c29d5f0a7'
|
||||||
@ -32,7 +32,7 @@ LV_IDS = [42, 43]
|
|||||||
LVM = ovs_quantum_agent.LocalVLANMapping(LV_ID, LS_ID, LV_IDS)
|
LVM = ovs_quantum_agent.LocalVLANMapping(LV_ID, LS_ID, LV_IDS)
|
||||||
VIF_ID = '404deaec-5d37-11e1-a64b-000c29d5f0a8'
|
VIF_ID = '404deaec-5d37-11e1-a64b-000c29d5f0a8'
|
||||||
VIF_MAC = '3c:09:24:1e:78:23'
|
VIF_MAC = '3c:09:24:1e:78:23'
|
||||||
VIF_PORT = ovs_quantum_agent.VifPort('port', 'ofport', VIF_ID, VIF_MAC,
|
VIF_PORT = ovs_lib.VifPort('port', 'ofport', VIF_ID, VIF_MAC,
|
||||||
'switch')
|
'switch')
|
||||||
|
|
||||||
|
|
||||||
@ -57,8 +57,8 @@ class TunnelTest(unittest.TestCase):
|
|||||||
self.INT_OFPORT = 'PATCH_INT_OFPORT'
|
self.INT_OFPORT = 'PATCH_INT_OFPORT'
|
||||||
self.TUN_OFPORT = 'PATCH_TUN_OFPORT'
|
self.TUN_OFPORT = 'PATCH_TUN_OFPORT'
|
||||||
|
|
||||||
self.mox.StubOutClassWithMocks(ovs_quantum_agent, 'OVSBridge')
|
self.mox.StubOutClassWithMocks(ovs_lib, 'OVSBridge')
|
||||||
self.mock_int_bridge = ovs_quantum_agent.OVSBridge(self.INT_BRIDGE,
|
self.mock_int_bridge = ovs_lib.OVSBridge(self.INT_BRIDGE,
|
||||||
'sudo')
|
'sudo')
|
||||||
self.mock_int_bridge.delete_port('patch-tun')
|
self.mock_int_bridge.delete_port('patch-tun')
|
||||||
self.mock_int_bridge.add_patch_port(
|
self.mock_int_bridge.add_patch_port(
|
||||||
@ -66,7 +66,7 @@ class TunnelTest(unittest.TestCase):
|
|||||||
self.mock_int_bridge.remove_all_flows()
|
self.mock_int_bridge.remove_all_flows()
|
||||||
self.mock_int_bridge.add_flow(priority=1, actions='normal')
|
self.mock_int_bridge.add_flow(priority=1, actions='normal')
|
||||||
|
|
||||||
self.mock_tun_bridge = ovs_quantum_agent.OVSBridge(self.TUN_BRIDGE,
|
self.mock_tun_bridge = ovs_lib.OVSBridge(self.TUN_BRIDGE,
|
||||||
'sudo')
|
'sudo')
|
||||||
self.mock_tun_bridge.reset_bridge()
|
self.mock_tun_bridge.reset_bridge()
|
||||||
self.mock_tun_bridge.add_patch_port(
|
self.mock_tun_bridge.add_patch_port(
|
||||||
@ -87,14 +87,12 @@ class TunnelTest(unittest.TestCase):
|
|||||||
self.mox.VerifyAll()
|
self.mox.VerifyAll()
|
||||||
|
|
||||||
def testProvisionLocalVlan(self):
|
def testProvisionLocalVlan(self):
|
||||||
match_string = 'in_port=%s,dl_vlan=%s' % (self.INT_OFPORT, LV_ID)
|
action_string = 'strip_vlan,set_tunnel:%s,normal' % LS_ID
|
||||||
action_string = 'set_tunnel:%s,normal' % LS_ID
|
self.mock_tun_bridge.add_flow(priority=4, in_port=self.INT_OFPORT,
|
||||||
self.mock_tun_bridge.add_flow(priority=4, match=match_string,
|
dl_vlan=LV_ID, actions=action_string)
|
||||||
actions=action_string)
|
|
||||||
|
|
||||||
match_string = 'tun_id=%s' % LS_ID
|
|
||||||
action_string = 'mod_vlan_vid:%s,output:%s' % (LV_ID, self.INT_OFPORT)
|
action_string = 'mod_vlan_vid:%s,output:%s' % (LV_ID, self.INT_OFPORT)
|
||||||
self.mock_tun_bridge.add_flow(priority=3, match=match_string,
|
self.mock_tun_bridge.add_flow(priority=3, tun_id=LS_ID,
|
||||||
actions=action_string)
|
actions=action_string)
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
@ -108,11 +106,9 @@ class TunnelTest(unittest.TestCase):
|
|||||||
self.mox.VerifyAll()
|
self.mox.VerifyAll()
|
||||||
|
|
||||||
def testReclaimLocalVlan(self):
|
def testReclaimLocalVlan(self):
|
||||||
match_string = 'tun_id=%s' % LVM.lsw_id
|
self.mock_tun_bridge.delete_flows(tun_id=LVM.lsw_id)
|
||||||
self.mock_tun_bridge.delete_flows(match=match_string)
|
|
||||||
|
|
||||||
match_string = 'dl_vlan=%s' % LVM.vlan
|
self.mock_tun_bridge.delete_flows(dl_vlan=LVM.vlan)
|
||||||
self.mock_tun_bridge.delete_flows(match=match_string)
|
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
a = ovs_quantum_agent.OVSQuantumTunnelAgent(self.INT_BRIDGE,
|
a = ovs_quantum_agent.OVSQuantumTunnelAgent(self.INT_BRIDGE,
|
||||||
@ -128,7 +124,7 @@ class TunnelTest(unittest.TestCase):
|
|||||||
def testPortBound(self):
|
def testPortBound(self):
|
||||||
self.mock_int_bridge.set_db_attribute('Port', VIF_PORT.port_name,
|
self.mock_int_bridge.set_db_attribute('Port', VIF_PORT.port_name,
|
||||||
'tag', str(LVM.vlan))
|
'tag', str(LVM.vlan))
|
||||||
self.mock_int_bridge.delete_flows(match='in_port=%s' % VIF_PORT.ofport)
|
self.mock_int_bridge.delete_flows(in_port=VIF_PORT.ofport)
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
a = ovs_quantum_agent.OVSQuantumTunnelAgent(self.INT_BRIDGE,
|
a = ovs_quantum_agent.OVSQuantumTunnelAgent(self.INT_BRIDGE,
|
||||||
@ -154,8 +150,7 @@ class TunnelTest(unittest.TestCase):
|
|||||||
self.mock_int_bridge.set_db_attribute(
|
self.mock_int_bridge.set_db_attribute(
|
||||||
'Port', VIF_PORT.port_name, 'tag', ovs_quantum_agent.DEAD_VLAN_TAG)
|
'Port', VIF_PORT.port_name, 'tag', ovs_quantum_agent.DEAD_VLAN_TAG)
|
||||||
|
|
||||||
match_string = 'in_port=%s' % VIF_PORT.ofport
|
self.mock_int_bridge.add_flow(priority=2, in_port=VIF_PORT.ofport,
|
||||||
self.mock_int_bridge.add_flow(priority=2, match=match_string,
|
|
||||||
actions='drop')
|
actions='drop')
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
250
quantum/tests/unit/test_ovs_lib.py
Normal file
250
quantum/tests/unit/test_ovs_lib.py
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright 2012, Nicira, Inc.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
# @author: Dan Wendlandt, Nicira, Inc.
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
import mox
|
||||||
|
|
||||||
|
from quantum.agent.linux import ovs_lib
|
||||||
|
|
||||||
|
|
||||||
|
class OVS_Lib_Test(unittest.TestCase):
|
||||||
|
"""
|
||||||
|
A test suite to excercise the OVS libraries shared by Quantum agents.
|
||||||
|
Note: these tests do not actually execute ovs-* utilities, and thus
|
||||||
|
can run on any system. That does, however, limit their scope.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.BR_NAME = "br-int"
|
||||||
|
self.TO = "--timeout=2"
|
||||||
|
|
||||||
|
self.mox = mox.Mox()
|
||||||
|
self.br = ovs_lib.OVSBridge(self.BR_NAME, 'sudo')
|
||||||
|
self.mox.StubOutWithMock(self.br, "run_cmd")
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.mox.UnsetStubs()
|
||||||
|
|
||||||
|
def test_vifport(self):
|
||||||
|
"""create and stringify vif port, confirm no exceptions"""
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
pname = "vif1.0"
|
||||||
|
ofport = 5
|
||||||
|
vif_id = str(uuid.uuid4())
|
||||||
|
mac = "ca:fe:de:ad:be:ef"
|
||||||
|
|
||||||
|
# test __init__
|
||||||
|
port = ovs_lib.VifPort(pname, ofport, vif_id, mac, self.br)
|
||||||
|
self.assertEqual(port.port_name, pname)
|
||||||
|
self.assertEqual(port.ofport, ofport)
|
||||||
|
self.assertEqual(port.vif_id, vif_id)
|
||||||
|
self.assertEqual(port.vif_mac, mac)
|
||||||
|
self.assertEqual(port.switch.br_name, self.BR_NAME)
|
||||||
|
|
||||||
|
# test __str__
|
||||||
|
foo = str(port)
|
||||||
|
|
||||||
|
self.mox.VerifyAll()
|
||||||
|
|
||||||
|
def test_reset_bridge(self):
|
||||||
|
self.br.run_cmd(["ovs-vsctl", self.TO, "--",
|
||||||
|
"--if-exists", "del-br", self.BR_NAME])
|
||||||
|
self.br.run_cmd(["ovs-vsctl", self.TO, "add-br", self.BR_NAME])
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
self.br.reset_bridge()
|
||||||
|
self.mox.VerifyAll()
|
||||||
|
|
||||||
|
def test_delete_port(self):
|
||||||
|
pname = "tap5"
|
||||||
|
self.br.run_cmd(["ovs-vsctl", self.TO, "--", "--if-exists",
|
||||||
|
"del-port", self.BR_NAME, pname])
|
||||||
|
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
self.br.delete_port(pname)
|
||||||
|
self.mox.VerifyAll()
|
||||||
|
|
||||||
|
def test_add_flow(self):
|
||||||
|
ofport = "99"
|
||||||
|
vid = 4000
|
||||||
|
lsw_id = 18
|
||||||
|
self.br.run_cmd(["ovs-ofctl", "add-flow", self.BR_NAME,
|
||||||
|
"hard_timeout=0,idle_timeout=0,"
|
||||||
|
"priority=2,dl_src=ca:fe:de:ad:be:ef"
|
||||||
|
",actions=strip_vlan,output:0"])
|
||||||
|
self.br.run_cmd(["ovs-ofctl", "add-flow", self.BR_NAME,
|
||||||
|
"hard_timeout=0,idle_timeout=0,"
|
||||||
|
"priority=1,actions=normal"])
|
||||||
|
self.br.run_cmd(["ovs-ofctl", "add-flow", self.BR_NAME,
|
||||||
|
"hard_timeout=0,idle_timeout=0,"
|
||||||
|
"priority=2,actions=drop"])
|
||||||
|
self.br.run_cmd(["ovs-ofctl", "add-flow", self.BR_NAME,
|
||||||
|
"hard_timeout=0,idle_timeout=0,"
|
||||||
|
"priority=2,in_port=%s,actions=drop" % ofport])
|
||||||
|
self.br.run_cmd(["ovs-ofctl", "add-flow", self.BR_NAME,
|
||||||
|
"hard_timeout=0,idle_timeout=0,"
|
||||||
|
"priority=4,in_port=%s,dl_vlan=%s,"
|
||||||
|
"actions=strip_vlan,set_tunnel:%s,normal"
|
||||||
|
% (ofport, vid, lsw_id)])
|
||||||
|
self.br.run_cmd(["ovs-ofctl", "add-flow", self.BR_NAME,
|
||||||
|
"hard_timeout=0,idle_timeout=0,"
|
||||||
|
"priority=3,tun_id=%s,actions="
|
||||||
|
"mod_vlan_vid:%s,output:%s"
|
||||||
|
% (lsw_id, vid, ofport)])
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
self.br.add_flow(priority=2, dl_src="ca:fe:de:ad:be:ef",
|
||||||
|
actions="strip_vlan,output:0")
|
||||||
|
self.br.add_flow(priority=1, actions="normal")
|
||||||
|
self.br.add_flow(priority=2, actions="drop")
|
||||||
|
self.br.add_flow(priority=2, in_port=ofport, actions="drop")
|
||||||
|
|
||||||
|
self.br.add_flow(priority=4, in_port=ofport, dl_vlan=vid,
|
||||||
|
actions="strip_vlan,set_tunnel:%s,normal" %
|
||||||
|
(lsw_id))
|
||||||
|
self.br.add_flow(priority=3, tun_id=lsw_id,
|
||||||
|
actions="mod_vlan_vid:%s,output:%s" %
|
||||||
|
(vid, ofport))
|
||||||
|
self.mox.VerifyAll()
|
||||||
|
|
||||||
|
def test_get_port_ofport(self):
|
||||||
|
pname = "tap99"
|
||||||
|
ofport = "6"
|
||||||
|
self.br.run_cmd(["ovs-vsctl", self.TO, "get", "Interface",
|
||||||
|
pname, "ofport"]).AndReturn(ofport)
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
self.assertEqual(self.br.get_port_ofport(pname), ofport)
|
||||||
|
self.mox.VerifyAll()
|
||||||
|
|
||||||
|
def test_count_flows(self):
|
||||||
|
self.br.run_cmd(["ovs-ofctl", "dump-flows", self.BR_NAME]).\
|
||||||
|
AndReturn("ignore\nflow-1\n")
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
# counts the number of flows as total lines of output - 2
|
||||||
|
self.assertEqual(self.br.count_flows(), 1)
|
||||||
|
self.mox.VerifyAll()
|
||||||
|
|
||||||
|
def test_delete_flow(self):
|
||||||
|
ofport = "5"
|
||||||
|
lsw_id = 40
|
||||||
|
vid = 39
|
||||||
|
self.br.run_cmd(["ovs-ofctl", "del-flows", self.BR_NAME,
|
||||||
|
"in_port=" + ofport])
|
||||||
|
self.br.run_cmd(["ovs-ofctl", "del-flows", self.BR_NAME,
|
||||||
|
"tun_id=%s" % lsw_id])
|
||||||
|
self.br.run_cmd(["ovs-ofctl", "del-flows", self.BR_NAME,
|
||||||
|
"dl_vlan=%s" % vid])
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
self.br.delete_flows(in_port=ofport)
|
||||||
|
self.br.delete_flows(tun_id=lsw_id)
|
||||||
|
self.br.delete_flows(dl_vlan=vid)
|
||||||
|
self.mox.VerifyAll()
|
||||||
|
|
||||||
|
def test_add_tunnel_port(self):
|
||||||
|
pname = "tap99"
|
||||||
|
ip = "9.9.9.9"
|
||||||
|
ofport = "6"
|
||||||
|
|
||||||
|
self.br.run_cmd(["ovs-vsctl", self.TO, "add-port",
|
||||||
|
self.BR_NAME, pname])
|
||||||
|
self.br.run_cmd(["ovs-vsctl", self.TO, "set", "Interface",
|
||||||
|
pname, "type=gre"])
|
||||||
|
self.br.run_cmd(["ovs-vsctl", self.TO, "set", "Interface",
|
||||||
|
pname, "options:remote_ip=" + ip])
|
||||||
|
self.br.run_cmd(["ovs-vsctl", self.TO, "set", "Interface",
|
||||||
|
pname, "options:in_key=flow"])
|
||||||
|
self.br.run_cmd(["ovs-vsctl", self.TO, "set", "Interface",
|
||||||
|
pname, "options:out_key=flow"])
|
||||||
|
self.br.run_cmd(["ovs-vsctl", self.TO, "get", "Interface",
|
||||||
|
pname, "ofport"]).AndReturn(ofport)
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
self.assertEqual(self.br.add_tunnel_port(pname, ip), ofport)
|
||||||
|
self.mox.VerifyAll()
|
||||||
|
|
||||||
|
def test_add_patch_port(self):
|
||||||
|
pname = "tap99"
|
||||||
|
peer = "bar10"
|
||||||
|
ofport = "6"
|
||||||
|
|
||||||
|
self.br.run_cmd(["ovs-vsctl", self.TO, "add-port",
|
||||||
|
self.BR_NAME, pname])
|
||||||
|
self.br.run_cmd(["ovs-vsctl", self.TO, "set", "Interface",
|
||||||
|
pname, "type=patch"])
|
||||||
|
self.br.run_cmd(["ovs-vsctl", self.TO, "set", "Interface",
|
||||||
|
pname, "options:peer=" + peer])
|
||||||
|
self.br.run_cmd(["ovs-vsctl", self.TO, "get", "Interface",
|
||||||
|
pname, "ofport"]).AndReturn(ofport)
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
self.assertEqual(self.br.add_patch_port(pname, peer), ofport)
|
||||||
|
self.mox.VerifyAll()
|
||||||
|
|
||||||
|
def _test_get_vif_ports(self, is_xen=False):
|
||||||
|
pname = "tap99"
|
||||||
|
ofport = "6"
|
||||||
|
vif_id = str(uuid.uuid4())
|
||||||
|
mac = "ca:fe:de:ad:be:ef"
|
||||||
|
|
||||||
|
self.br.run_cmd(["ovs-vsctl", self.TO, "list-ports", self.BR_NAME]).\
|
||||||
|
AndReturn("%s\n" % pname)
|
||||||
|
|
||||||
|
if is_xen:
|
||||||
|
external_ids = ('{xs-vif-uuid="%s", attached-mac="%s"}'
|
||||||
|
% (vif_id, mac))
|
||||||
|
else:
|
||||||
|
external_ids = ('{iface-id="%s", attached-mac="%s"}'
|
||||||
|
% (vif_id, mac))
|
||||||
|
|
||||||
|
self.br.run_cmd(["ovs-vsctl", self.TO, "get", "Interface",
|
||||||
|
pname, "external_ids"]).AndReturn(external_ids)
|
||||||
|
self.br.run_cmd(["ovs-vsctl", self.TO, "get", "Interface",
|
||||||
|
pname, "ofport"]).AndReturn(ofport)
|
||||||
|
if is_xen:
|
||||||
|
self.br.run_cmd(["xe", "vif-param-get", "param-name=other-config",
|
||||||
|
"param-key=nicira-iface-id", "uuid=" + vif_id]).\
|
||||||
|
AndReturn(vif_id)
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
ports = self.br.get_vif_ports()
|
||||||
|
self.assertEqual(1, len(ports))
|
||||||
|
self.assertEqual(ports[0].port_name, pname)
|
||||||
|
self.assertEqual(ports[0].ofport, ofport)
|
||||||
|
self.assertEqual(ports[0].vif_id, vif_id)
|
||||||
|
self.assertEqual(ports[0].vif_mac, mac)
|
||||||
|
self.assertEqual(ports[0].switch.br_name, self.BR_NAME)
|
||||||
|
self.mox.VerifyAll()
|
||||||
|
|
||||||
|
def test_get_vif_ports_nonxen(self):
|
||||||
|
self._test_get_vif_ports(False)
|
||||||
|
|
||||||
|
def test_get_vif_ports_xen(self):
|
||||||
|
self._test_get_vif_ports(True)
|
||||||
|
|
||||||
|
def test_clear_db_attribute(self):
|
||||||
|
pname = "tap77"
|
||||||
|
self.br.run_cmd(["ovs-vsctl", self.TO, "clear", "Port",
|
||||||
|
pname, "tag"])
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
self.br.clear_db_attribute("Port", pname, "tag")
|
||||||
|
self.mox.VerifyAll()
|
Loading…
x
Reference in New Issue
Block a user