Add ovs_options and ovs_extra parameters to VLAN object

This patch adds the ovs_options and ovs_extra parameters to the
VLAN object, and OVS_OPTIONS/OVS_EXTRA to the OVS VLAN ifcfg.
An OVS VLAN is an internal port on the bridge, and when ifup
is run the ovs-vsctl command will be called with the commands
in OVS_OPTIONS and the list of commands in OVS_EXTRA. This
makes OVS VLANs work the same as other OVS object types.
These settings are ignored for VLANs not on an OVS bridge.

Change-Id: Ie1db61eea48e3426a59ae02b13dd8ab8ef85e851
Closes-bug: 1821816
This commit is contained in:
Dan Sneddon 2019-03-27 14:57:09 -07:00
parent 97679372dd
commit dd1906f61f
7 changed files with 47 additions and 3 deletions

View File

@ -11,6 +11,10 @@
{
"type": "vlan",
"vlan_id": 16,
"ovs_options": "mac=00:11:22:33:44:55",
"ovs_extra": [
"foo=bar"
],
"addresses": [{
"ip_netmask": "192.0.2.1/24"
}]

View File

@ -10,6 +10,9 @@ network_config:
-
type: vlan
vlan_id: 16
ovs_options: "mac=00:11:22:33:44:55"
ovs_extra:
- "foo=bar"
addresses:
-
ip_netmask: 192.0.2.1/24

View File

@ -364,6 +364,10 @@ class IfcfgNetConfig(os_net_config.NetConfig):
data += "PHYSDEV=%s\n" % base_opt.device
elif base_opt.linux_bond_name:
data += "PHYSDEV=%s\n" % base_opt.linux_bond_name
else:
if base_opt.ovs_options:
data += "OVS_OPTIONS=\"%s\"\n" % base_opt.ovs_options
ovs_extra.extend(base_opt.ovs_extra)
elif isinstance(base_opt, objects.IvsInterface):
data += "TYPE=IVSIntPort\n"
elif isinstance(base_opt, objects.NfvswitchInternal):

View File

@ -492,7 +492,8 @@ class Vlan(_BaseOpts):
addresses=None, routes=None, rules=None, mtu=None,
primary=False, nic_mapping=None, persist_mapping=False,
defroute=True, dhclient_args=None, dns_servers=None,
nm_controlled=False, onboot=True, domain=None):
nm_controlled=False, onboot=True, domain=None,
ovs_options=None, ovs_extra=None):
addresses = addresses or []
routes = routes or []
rules = rules or []
@ -503,6 +504,9 @@ class Vlan(_BaseOpts):
persist_mapping, defroute, dhclient_args,
dns_servers, nm_controlled, onboot, domain)
self.vlan_id = int(vlan_id)
self.ovs_options = ovs_options
ovs_extra = ovs_extra or []
self.ovs_extra = format_ovs_extra(self, ovs_extra)
mapped_nic_names = mapped_nics(nic_mapping)
if device in mapped_nic_names:
self.device = mapped_nic_names[device]
@ -515,7 +519,12 @@ class Vlan(_BaseOpts):
device = json.get('device')
vlan_id = _get_required_field(json, 'vlan_id', 'Vlan')
opts = _BaseOpts.base_opts_from_json(json)
return Vlan(device, vlan_id, *opts)
ovs_options = json.get('ovs_options')
ovs_extra = json.get('ovs_extra', [])
if not isinstance(ovs_extra, list):
ovs_extra = [ovs_extra]
return Vlan(device, vlan_id, *opts, ovs_options=ovs_options,
ovs_extra=ovs_extra)
class IvsInterface(_BaseOpts):

View File

@ -197,7 +197,7 @@ definitions:
ovs_options_string:
type: string
pattern: "^((?:[a-zA-Z][a-zA-Z0-9: _-]*)=(?:[a-zA-Z0-9._-]+)[ ]*)+$"
pattern: "^((?:[a-zA-Z][a-zA-Z0-9: _-]*)=(?:[a-zA-Z0-9:._-]+)[ ]*)+$"
ovs_options_string_or_param:
oneOf:
- $ref: "#/definitions/ovs_options_string"
@ -459,6 +459,10 @@ definitions:
$ref: "#/definitions/bool_or_param"
domain:
$ref: "#/definitions/domain_name_string"
ovs_options:
$ref: "#/definitions/ovs_options_string_or_param"
ovs_extra:
$ref: "#/definitions/ovs_extra_or_param"
required:
- type
- vlan_id

View File

@ -335,6 +335,10 @@ _VLAN_NO_IP = _BASE_VLAN + "BOOTPROTO=none\n"
_VLAN_OVS = _BASE_VLAN_OVS + "DEVICETYPE=ovs\nBOOTPROTO=none\n"
_VLAN_OVS_EXTRA = _BASE_VLAN_OVS + "OVS_OPTIONS=\"foo\"\nDEVICETYPE=ovs\n" + \
"BOOTPROTO=none\nOVS_EXTRA=\"bar -- baz\"\n"
_VLAN_OVS_BRIDGE = _BASE_VLAN_OVS + """DEVICETYPE=ovs
TYPE=OVSIntPort
OVS_BRIDGE=br-ctlplane
@ -1055,6 +1059,14 @@ class TestIfcfgNetConfig(base.TestCase):
self.provider.add_vlan(vlan)
self.assertEqual(_VLAN_OVS, self.get_vlan_config('vlan5'))
def test_add_vlan_ovs_options(self):
vlan = objects.Vlan('em1', 5)
vlan.ovs_port = True
vlan.ovs_options = 'foo'
vlan.ovs_extra = ['bar', 'baz']
self.provider.add_vlan(vlan)
self.assertEqual(_VLAN_OVS_EXTRA, self.get_vlan_config('vlan5'))
def test_add_vlan_mtu_1500(self):
vlan = objects.Vlan('em1', 5, mtu=1500)
self.provider.add_vlan(vlan)

View File

@ -381,6 +381,14 @@ class TestVlan(base.TestCase):
self.assertEqual(16, vlan.vlan_id)
self.assertTrue(vlan.use_dhcp)
def test_from_json_ovs_options_extra(self):
data = '{"type": "vlan", "device": "em1", "vlan_id": 16,' \
'"use_dhcp": true, "ovs_options": "foo",' \
'"ovs_extra": ["bar","baz"]}'
vlan = objects.object_from_json(json.loads(data))
self.assertEqual("foo", vlan.ovs_options)
self.assertEqual(["bar", "baz"], vlan.ovs_extra)
class TestBridge(base.TestCase):