Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement binding strategy in creating and binding lport #111

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better to add 'self.lswitch = None' in init(), otherwise get_lswitch() before set_lswitch() may raise a exception

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got you. Thanks.

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())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'idx0' is a typo?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a debug message. I will remove it. Thanks.


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