Skip to content

Commit

Permalink
Implement binding strategy in creating and binding lport
Browse files Browse the repository at this point in the history
- see the guide: ansible/doc/binding-strategy.rst

Signed-off-by: Hui Kang <kangh@us.ibm.com>
  • Loading branch information
Hui Kang committed Aug 27, 2016
1 parent 6b1bcd0 commit 703f276
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 3 deletions.
51 changes: 51 additions & 0 deletions ansible/doc/binding-strategy.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
======================
Binding Strategy Guide
======================

Overview
========

In OVN, a logical port can be bind to a local OVS port on any
chassis/hypervisor, depending on the VM scheduler (e.g., ``nova-scheduler``).
The binding strategy potentially impacts the network performance. That is
binding all logical ports from a logical network on a single hypervisor performs
differently than distributing the ports on multiple hypervisors.

The container-based ovn-scale-test deployment allows to configure the binding
strategy in creating and binding port rally task.


Binding Configuration
=====================

Use ``networks_per_sandbox`` to control how logical networks and the logical
ports are bind to chassis.

For example, given ``ovn_number_chassis: 10`` (4 emulated chassis) and
``ovn_number_chassis: 10`` (10 logical networks), the binding varies depending
on the value of ``networks_per_sandbox``.

- ``networks_per_sandbox: "10"``: this is the default case. All networks will
be evenly distributed to all chassis.

- ``networks_per_sandbox: "2"``: each chassis has ports belong to two logical
networks. In this case, the 10 logical networks are divided into 5 groups, say
[n0, n1], [n2, n3], [n4, n5], [n6, n7], [n8, n9]. Then ports in [n0, n1] are
bind to chassis 0 and 1, [n2, n3] to chassis 2 and 3, and so forth. As a
result, each chassis has two logical network as configured.

- ``networks_per_sandbox: "1"``: each chassis has ports belong to only one
logical network. In this case, the 10 logical network will have a one-to-one
mapping to the 10 chassis. Note that this is the extreme case as opposite to
``networks_per_sandbox: "10"``.


Constraint
~~~~~~~~~

TBD

Implementation Detail
=====================

TBD
3 changes: 3 additions & 0 deletions ansible/etc/variables.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ network_start_cidr: "172.16.201.0/24"
network_number: "5"
ports_per_network: "5"

# from 0 to network_number, 0 means even distribution (default)
networks_per_sandbox: "0"

acls_per_port: "1"

########################
Expand Down
3 changes: 3 additions & 0 deletions ansible/group_vars/all.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ ports_per_network: "1"
ports_created_batch_size: "1"
networks_created_batch_size: "1"

# from 0 to network_number, 0 means even distribution (default)
networks_per_sandbox: "0"

acls_per_port: "1"

########################
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"start_cidr": "{{ network_start_cidr }}",
"physical_network": "providernet"
},
"networks_per_sandbox": {{ networks_per_sandbox }},
"port_create_args" : {
"batch": {{ ports_created_batch_size }}
},
Expand Down
3 changes: 3 additions & 0 deletions ci/ansible/all.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ ports_created_batch_size: "1"
networks_created_batch_size: "1"
acls_per_port: "5"

# from 0 to network_number, 0 means even distribution (default)
networks_per_sandbox: "0"

################
# OVS Repository
################
Expand Down
106 changes: 103 additions & 3 deletions rally_ovs/plugins/ovs/scenarios/ovn_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,105 @@
from rally.common import logging
from rally_ovs.plugins.ovs.scenarios import ovn

from rally import exceptions
from rally.task import scenario
from rally.task import validation

LOG = logging.getLogger(__name__)

class LogicalNetwork():
def __init__(self):
self.sandboxes = []
self.ports_per_network = 0

def set_lswitch(self, lswitch):
self.lswitch = lswitch

def add_sandbox(self, sandbox):
self.sandboxes.append(sandbox)

def get_lswitch(self):
return self.lswitch

def get_sandboxes(self):
return self.sandboxes

def get_ports_per_network(self):
return self.ports_per_network


def initialize_logical_networks(lswitches):
LOG.info("Initialize logical lswitches with %s" % lswitches)
logical_networks = []

for lswitch in lswitches:
logical_network = LogicalNetwork()
logical_network.set_lswitch(lswitch)
LOG.info("Logical network: %s" % logical_network.get_lswitch())
logical_networks.append(logical_network)

return logical_networks


def allocate_networks_on_sandboxes(logical_networks, sandboxes, networks_per_sandbox=0):
if networks_per_sandbox == 0:
for logical_network in logical_networks:
for sandbox in sandboxes:
logical_network.add_sandbox(sandbox)
else:
# Sanity check
num_networks = len(logical_networks)

if (num_networks % networks_per_sandbox) != 0 :
message = ("Number of network %s is not divisible by network per sandbox %s")
raise exceptions.InvalidConfigException(
message % (str(num_networks), str(networks_per_sandbox)))

LOG.info("Number of networks: %s" % str(num_networks))
num_network_groups = num_networks / networks_per_sandbox
LOG.info("Number of network group: %s" % str(num_network_groups))

if len(sandboxes) < num_network_groups :
message = ("Number of sandbox %d is less than number of network groups %d")
raise exceptions.InvalidConfigException(
message % (len(sandboxes), num_network_groups))
elif (len(sandboxes) % num_network_groups) != 0 :
message = ("Number of sandbox %d is not divisible by network groups %d")
raise exceptions.InvalidConfigException(
message % (len(sandboxes), num_network_groups))


group_spread_sandboxes = len(sandboxes) / num_network_groups
LOG.info("Number of group spread sandboxes: %s" % str(group_spread_sandboxes))

network_groups = []
networks_per_group = num_networks / num_network_groups
base = 0
for i in range(0, num_network_groups):
LOG.info("Group %d" % i)
network_group = []

for j in range(base, base + networks_per_group):
network_group.append(logical_networks[j])
LOG.info("\t%d, add logical network: %s" % (j, logical_networks[j].get_lswitch()))

LOG.info("network group idx0: %s" % network_group[0].get_lswitch())

network_groups.append(network_group)
base += networks_per_group

LOG.info("Allocating sandboxes...")
sandbox_idx = 0
base = 0
for group in network_groups:
for network in group:
LOG.info("network switch name: %s" % network.get_lswitch())
for sandbox_idx in range(base, base + group_spread_sandboxes):
network.add_sandbox(sandboxes[sandbox_idx])
LOG.info("\tAdd sandbox %s" % sandboxes[sandbox_idx])
base += group_spread_sandboxes

return logical_networks

class OvnNetwork(ovn.OvnScenario):
"""scenarios for OVN network."""
Expand All @@ -35,16 +128,23 @@ def create_networks(self, network_create_args):
@scenario.configure(context={})
def create_and_bind_ports(self,
network_create_args=None,
networks_per_sandbox=None,
port_create_args=None,
ports_per_network=None,
port_bind_args=None):

sandboxes = self.context["sandboxes"]

lswitches = self._create_networks(network_create_args)
for lswitch in lswitches:
lports = self._create_lports(lswitch, port_create_args, ports_per_network)
self._bind_ports(lports, sandboxes, port_bind_args)
logical_networks = []
logical_networks = initialize_logical_networks(lswitches)
if networks_per_sandbox == None:
networks_per_sandbox = 0
logical_networks = allocate_networks_on_sandboxes(logical_networks, sandboxes, networks_per_sandbox)

for logical_network in logical_networks:
lports = self._create_lports(logical_network.get_lswitch(), port_create_args, ports_per_network)
self._bind_ports(lports, logical_network.get_sandboxes(), port_bind_args)


def bind_ports(self):
Expand Down

0 comments on commit 703f276

Please sign in to comment.