Skip to content

Commit

Permalink
Check openflow(OF) rules on each hyperviors after binding lports
Browse files Browse the repository at this point in the history
- use ovs-appctl to trace flow matches in the tables

Signed-off-by: Hui Kang <kangh@us.ibm.com>
  • Loading branch information
Hui Kang committed Aug 14, 2016
1 parent b8aee2f commit 279f152
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 8 deletions.
12 changes: 12 additions & 0 deletions rally_ovs/plugins/ovs/ovsclients.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,18 @@ def get_lswitch_info(info):
return lswitches


def get_of_in_port(of_port_list_raw, port_name_full):
# NOTE (huikang): the max length of portname shown in ovs-ofctl show is 15
port_name = port_name_full[0:15]
lines = of_port_list_raw.splitlines()
line = ""
for line in lines:
if (line.find(port_name) >= 0):
break
position = line.find("(")
return line[:position]


def set_colval_args(*col_values):
args = []
for entry in col_values:
Expand Down
42 changes: 34 additions & 8 deletions rally_ovs/plugins/ovs/ovsclients_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@
import pipes
import sys
import itertools
import pipes
import StringIO
from rally.common import logging
from rally_ovs.plugins.ovs.ovsclients import *
from rally_ovs.plugins.ovs.utils import get_ssh_from_credential

LOG = logging.getLogger(__name__)

@configure("ssh")
class SshClient(OvsClient):
Expand Down Expand Up @@ -167,7 +169,7 @@ def acl_del(self, lswitch):

def show(self, lswitch=None):
params = [lswitch] if lswitch else []
stdout = StringIO()
stdout = StringIO.StringIO()
self.run("show", args=params, stdout=stdout)
output = stdout.getvalue()

Expand Down Expand Up @@ -203,7 +205,7 @@ def set_sandbox(self, sandbox, install_method="sandbox"):
self.sandbox = sandbox
self.install_method = install_method

def run(self, cmd, opts=[], args=[]):
def run(self, ovs_cmd, cmd, opts=[], args=[], stdout=sys.stdout):
self.cmds = self.cmds or []

# TODO: tested with non batch_mode only for docker
Expand All @@ -213,16 +215,17 @@ def run(self, cmd, opts=[], args=[]):
if self.sandbox and self.batch_mode == False:
if self.install_method == "sandbox":
self.cmds.append(". %s/sandbox.rc" % self.sandbox)
cmd = itertools.chain(["ovs-vsctl"], opts, [cmd], args)
cmd = itertools.chain([ovs_cmd], opts, [cmd], args)
self.cmds.append(" ".join(cmd))
elif self.install_method == "docker":
self.cmds.append("sudo docker exec %s ovs-vsctl " % self.sandbox + cmd + " " + " ".join(args))
self.cmds.append("sudo docker exec %s " % self.sandbox + " "
+ ovs_cmd + " " + cmd + " " + " ".join(args))

if self.batch_mode:
return

self.ssh.run("\n".join(self.cmds),
stdout=sys.stdout, stderr=sys.stderr)
stdout=stdout, stderr=sys.stderr)

self.cmds = None

Expand All @@ -242,13 +245,36 @@ def flush(self):

def add_port(self, bridge, port, may_exist=True):
opts = ['--may-exist'] if may_exist else None
self.run('add-port', opts, [bridge, port])
self.run("ovs-vsctl", 'add-port', opts, [bridge, port])


def db_set(self, table, record, *col_values):
args = [table, record]
args += set_colval_args(*col_values)
self.run("set", args=args)
self.run("ovs-vsctl", "set", args=args)

def of_check(self, bridge, port, mac_addr, may_exist=True):
in_port = ""
stdout = StringIO.StringIO()
self.run("ovs-ofctl", "show br-int", stdout=stdout)
show_br_int_output = stdout.getvalue()
in_port = get_of_in_port(show_br_int_output, port)
LOG.info("Check port: in_port: %s; mac: %s" % (in_port.strip(), mac_addr))
appctl_cmd = " ofproto/trace br-int in_port=" + in_port.strip()
appctl_cmd += ",dl_src=" + mac_addr
appctl_cmd += ",dl_dst=00:00:00:00:00:03 -generate "
self.run("ovs-appctl", appctl_cmd, stdout=stdout)
of_trace_output = stdout.getvalue()

# NOTE(HuiKang): if success, the flow goes through table 1 to table
# 32. However, since we use sandbox, table 32 seems not setup
# correctly. Therefore after table 34, the datapath action is
# Datapath actions: 100. If failed, the datapatch action is "drop"
for line in of_trace_output.splitlines():
if (line.find("Datapath actions") >= 0):
if (line.find("drop") >= 0):
return False
return True

def create_client(self):
print "********* call OvnNbctl.create_client"
Expand Down
40 changes: 40 additions & 0 deletions rally_ovs/plugins/ovs/scenarios/ovn.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ def _create_lswitches(self, lswitch_create_args):

print("create lswitch")
self.RESOURCE_NAME_FORMAT = "lswitch_XXXXXX_XXXXXX"
self.port_mac = dict()

amount = lswitch_create_args.get("amount", 1)
batch = lswitch_create_args.get("batch", amount)
Expand Down Expand Up @@ -124,6 +125,7 @@ def _create_lports(self, lswitch, lport_create_args = [], lport_amount=1):
ovn_nbctl.enable_batch_mode()

base_mac = [i[:2] for i in self.task["uuid"].split('-')]
base_mac[0] = str(hex(int(base_mac[0], 16) & 254))
base_mac[3:] = ['00']*3


Expand All @@ -138,6 +140,7 @@ def _create_lports(self, lswitch, lport_create_args = [], lport_amount=1):

ovn_nbctl.lport_set_addresses(name, [mac, ip])
ovn_nbctl.lport_set_port_security(name, mac)
self.port_mac[name] = mac

lports.append(lport)

Expand Down Expand Up @@ -251,6 +254,43 @@ def _create_networks(self, network_create_args):
return lswitches


@atomic.action_timer("ovn_network.of_check_port")
def _of_check_ports(self, lports, sandboxes, port_bind_args):
port_bind_args = port_bind_args or {}
wait_up = port_bind_args.get("wait_up", False)

sandbox_num = len(sandboxes)
lport_num = len(lports)
lport_per_sandbox = (lport_num + sandbox_num - 1) / sandbox_num

LOG.info("Checking OF lports method: %s" % self.install_method)
install_method = self.install_method

j = 0
for i in range(0, len(lports), lport_per_sandbox):
lport_slice = lports[i:i+lport_per_sandbox]

sandbox = sandboxes[j]["name"]
farm = sandboxes[j]["farm"]
ovs_vsctl = self.farm_clients(farm, "ovs-vsctl")
ovs_vsctl.set_sandbox(sandbox, install_method)
ovs_vsctl.enable_batch_mode()

for lport in lport_slice:
port_name = lport["name"]

LOG.info("of check %s to %s on %s" % (port_name, sandbox, farm))

# check if OF rules installed correctly
mac_addr = self.port_mac[port_name]
of_check = ovs_vsctl.of_check('br-int', port_name, mac_addr)
if of_check is False:
LOG.info("Return false" )
raise exceptions.NotFoundException(message="openflow rule")

ovs_vsctl.flush()
j += 1


@atomic.action_timer("ovn_network.bind_port")
def _bind_ports(self, lports, sandboxes, port_bind_args):
Expand Down
1 change: 1 addition & 0 deletions rally_ovs/plugins/ovs/scenarios/ovn_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ def create_and_bind_ports(self,
for lswitch in lswitches:
lports = self._create_lports(lswitch, port_create_args, ports_per_network)
self._bind_ports(lports, sandboxes, port_bind_args)
self._of_check_ports(lports, sandboxes, port_bind_args)


def bind_ports(self):
Expand Down

0 comments on commit 279f152

Please sign in to comment.