Skip to content

Commit

Permalink
NFV OVN DPDK Configuration Changes
Browse files Browse the repository at this point in the history
This change is used to have custom ansible edpm
variables for OVN DPDK configurations.
  • Loading branch information
Jaganathancse authored and Jaganathan Palanisamy committed Nov 8, 2023
1 parent f143cb5 commit 28617d1
Show file tree
Hide file tree
Showing 14 changed files with 851 additions and 1 deletion.
30 changes: 30 additions & 0 deletions docs/source/roles/role-edpm_ovn_dpdk.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
========================
Role - edpm_ovn_dpdk
========================

Usage
~~~~~

This Ansible role allows to do the following tasks:

* Configure the required eVN DPDK configuration
based on the OVN DPDK edpm ansible variables.

* Remove any existing OVN DPDK configuration based
on the OVN DPDK edpm ansible variables.

Here is an example of a playbook:

.. code-block:: YAML
- name: "Configure OVN DPDK Configs"
include_role:
name: "osp.edpm.edpm_ovn_dpdk"
vars:
edpm_ovn_dpdk_enabled: true
edpm_ovn_dpdk_pmd_core_list: "1,13,3,15"
edpm_ovn_dpdk_lcore_list: "0,12"
edpm_ovn_dpdk_socket_memory: "4096"
edpm_ovn_dpdk_memory_channels: 4
edpm_ovn_dpdk_vhost_postcopy_support: tru
edpm_nova_libvirt_vhostuser_socket_group: 'hugetlbfs'
12 changes: 12 additions & 0 deletions playbooks/configure_ovn_dpdk.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---

- name: Configure OVN DPDK
hosts: all
strategy: linear
become: true
tasks:
- name: Configure OVN DPDK configs
ansible.builtin.import_role:
name: osp.edpm.edpm_ovn_dpdk
tags:
- edpm_ovn_dpdk
14 changes: 14 additions & 0 deletions plugins/filter/cpu_mask.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
DOCUMENTATION:
name: cpu_mask
author: "EDPM team"
version_added: 2.9
short_description: Calculates cpu mask for the list of CPus.
description: |
This filter will take the list of CPUs and will convert
that to a cpu mask value.
EXAMPLES: |
"{{ cpu_list | osp.edpm.cpu_mask }}"
RETURN:
_value:
description:
type: string
31 changes: 30 additions & 1 deletion plugins/filter/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# under the License.

import ast
import binascii
import json
import re

Expand All @@ -25,7 +26,8 @@ def filters(self):
'needs_delete': self.needs_delete,
'haskey': self.haskey,
'dict_to_list': self.dict_to_list,
'jump_chain_targets': self.jump_chain_targets
'jump_chain_targets': self.jump_chain_targets,
'cpu_mask': self.cpu_mask
}

def needs_delete(self, container_infos, config, config_id,
Expand Down Expand Up @@ -190,3 +192,30 @@ def _filter(item):
if 'target' in target.get('jump', {}).keys():
targets.append(target['jump']['target'])
return targets

def cpu_mask(self, cpu_list):
"""Return a cpu mask for the list of CPUs.
Example - for input of 1,13 the mask would be 2002
:param cpu_list: list
:returns: cpu mask
"""
mask = 0
cpus = []
for cpu in cpu_list.split(','):
if '-' in cpu:
rng = cpu.split('-')
cpus.extend(range(int(rng[0]), int(rng[1]) + 1))
else:
cpus.append(int(cpu))
cpus.sort()
max_val = int(cpus[-1])
byte_arr = bytearray(int(max_val / 8) + 1)

for item in cpus:
pos = int(int(item) / 8)
bit = int(item) % 8
byte_arr[pos] |= 2**bit

byte_arr.reverse()
mask = binascii.hexlify(byte_arr)
return mask.decode("utf-8").lstrip("0")
238 changes: 238 additions & 0 deletions plugins/modules/openvswitch_db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
#!/usr/bin/python
# coding: utf-8 -*-

#
# (c) 2015, Mark Hamilton <[email protected]>
# Portions copyright @ 2015 VMware, Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
__metaclass__ = type

import re

from ansible.module_utils.basic import AnsibleModule

ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'network'}


DOCUMENTATION = """
---
module: openvswitch_db
author: "Mark Hamilton (@markleehamilton) <[email protected]>"
version_added: 2.0
short_description: Configure open vswitch database.
requirements: [ "ovs-vsctl >= 2.3.3" ]
description:
- Set column values in record in database table.
options:
state:
required: false
description:
- Configures the state of the key. When set
to I(present), the I(key) and I(value) pair will be set
on the I(record) and when set to I(absent) the I(key)
will not be set.
default: present
choices: ['present', 'absent']
version_added: "2.4"
table:
required: true
description:
- Identifies the table in the database.
record:
required: true
description:
- Identifies the record in the table.
col:
required: true
description:
- Identifies the column in the record.
key:
required: false
description:
- Identifies the key in the record column, when the column is a map
type.
value:
required: false
description:
- Expected value for the table, record, column and key.
- Required when I(state) is I(present)
timeout:
required: false
default: 5
description:
- How long to wait for ovs-vswitchd to respond
"""

EXAMPLES = '''
# Increase the maximum idle time to 50 seconds before pruning unused kernel
# rules.
- openvswitch_db:
table: open_vswitch
record: .
col: other_config
key: max-idle
value: 50000
# Disable in band copy
- openvswitch_db:
table: Bridge
record: br-int
col: other_config
key: disable-in-band
value: true
# Remove in band key
- openvswitch_db:
state: absent
table: Bridge
record: br-int
col: other_config
key: disable-in-band
# Mark port with tag 10
- openvswitch_db:
table: Port
record: port0
col: tag
value: 10
'''

# Regular expression for map type, must not be empty
NON_EMPTY_MAP_RE = re.compile(r'{.+}')
# Regular expression for a map column type
MAP_RE = re.compile(r'{.*}')


def map_obj_to_commands(want, have, module):
""" Define ovs-vsctl command to meet desired state """
commands = list()

if module.params['state'] == 'absent':
if 'key' in have.keys():
templatized_command = "%(ovs-vsctl)s -t %(timeout)s remove %(table)s %(record)s " \
"%(col)s %(key)s"
# Append the value only when provided
if 'value' in want.keys():
templatized_command += "=%(value)s"
commands.append(templatized_command % module.params)
elif module.params['key'] is None:
templatized_command = "%(ovs-vsctl)s -t %(timeout)s remove %(table)s %(record)s " \
"%(col)s"
commands.append(templatized_command % module.params)
else:
if want == have:
# Nothing to commit
return commands
if module.params['key'] is None:
templatized_command = "%(ovs-vsctl)s -t %(timeout)s set %(table)s %(record)s " \
"%(col)s=%(value)s"
commands.append(templatized_command % module.params)
else:
templatized_command = "%(ovs-vsctl)s -t %(timeout)s set %(table)s %(record)s " \
"%(col)s:%(key)s=%(value)s"
commands.append(templatized_command % module.params)

return commands


def map_config_to_obj(module):
templatized_command = "%(ovs-vsctl)s -t %(timeout)s list %(table)s %(record)s"
command = templatized_command % module.params
rc, out, err = module.run_command(command, check_rc=True)
if rc != 0:
module.fail_json(msg=err)

match = re.search(r'^' + module.params['col'] + r'(\s+):(\s+)(.*)$', out, re.M)

col_value = match.group(3)

# Map types require key argument
has_key = module.params['key'] is not None
is_map = MAP_RE.match(col_value)
if is_map and not has_key:
module.fail_json(
msg="missing required arguments: key for map type of column")

col_value_to_dict = {}
if NON_EMPTY_MAP_RE.match(col_value):
for kv in col_value[1:-1].split(', '):
k, v = kv.split('=', 1)
col_value_to_dict[k.strip()] = v.strip('\"')

obj = {
'table': module.params['table'],
'record': module.params['record'],
'col': module.params['col'],
}

if has_key and is_map:
if module.params['key'] in col_value_to_dict:
obj['key'] = module.params['key']
obj['value'] = col_value_to_dict[module.params['key']]
else:
obj['value'] = str(col_value.strip())

return obj


def map_params_to_obj(module):
obj = {
'table': module.params['table'],
'record': module.params['record'],
'col': module.params['col'],
}

if module.params['value'] is not None:
if module.params['value'] in ['True', 'False']:
module.params['value'] = module.params['value'].lower()
obj['value'] = module.params['value']

key = module.params['key']
if key is not None:
obj['key'] = key

return obj


def main():
""" Entry point for ansible module. """
argument_spec = {
'state': {'default': 'present', 'choices': ['present', 'absent']},
'table': {'required': True},
'record': {'required': True},
'col': {'required': True},
'key': {'required': False},
'value': {'required': False, 'type': 'str'},
'timeout': {'default': 5, 'type': 'int'},
}

required_if = [('state', 'present', ['value'])]

module = AnsibleModule(argument_spec=argument_spec,
required_if=required_if,
supports_check_mode=True)

result = {'changed': False}

# We add ovs-vsctl to module_params to later build up templatized commands
module.params["ovs-vsctl"] = module.get_bin_path("ovs-vsctl", True)

want = map_params_to_obj(module)
have = map_config_to_obj(module)

commands = map_obj_to_commands(want, have, module)
result['commands'] = commands

if commands:
if not module.check_mode:
for c in commands:
module.run_command(c, check_rc=True)
result['changed'] = True

module.exit_json(**result)


if __name__ == '__main__':
main()
36 changes: 36 additions & 0 deletions roles/edpm_ovn_dpdk/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
# Copyright 2023 Red Hat, 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.


# All variables intended for modification should be placed in this file.

# All variables within this role should have a prefix of "edpm_ovn_dpdk"
edpm_ovn_dpdk_enabled: false
edpm_ovn_dpdk_pmd_core_list: ""
edpm_ovn_dpdk_lcore_list: ""
edpm_ovn_dpdk_memory_channels: 4
edpm_ovn_dpdk_extra: ""
edpm_ovn_dpdk_socket_memory: ""
edpm_ovn_dpdk_revalidator_cores: ""
edpm_ovn_dpdk_handler_cores: ""
edpm_ovn_dpdk_emc_insertion_probablity: ""
edpm_ovn_dpdk_enable_tso: false
edpm_ovn_dpdk_pmd_auto_lb: false
edpm_ovn_dpdk_pmd_load_threshold: ""
edpm_ovn_dpdk_pmd_improvement_threshold: ""
edpm_ovn_dpdk_pmd_rebal_interval: ""
edpm_ovn_dpdk_vhost_postcopy_support: false
edpm_ovn_dpdk_vhost_postcopy_ovs_options: "--mlockall=no"
Loading

0 comments on commit 28617d1

Please sign in to comment.