[PATCH v4] [Kimchi 0/8] Network API change + VEPA network support

From: Daniel Henrique Barboza <dhbarboza82@gmail.com> v4: - added one interface only restriction to macvtap and bridge networks v3: - Lucio suggestions made: docs/API.md and 'bridge' connection in test_template.py v2: - changes on the existing network backend This patch set implements two major changes in the network backend and API of Kimchi: - first 4 patches: changed the API to allow networks to be created with more than one interface Changing 'interface' to 'interfaces' in the network backend to allow more than one interface to be added to a network. Existing networks that use only one interface were adapted to use interfaces[0] instead. UI changes were made to comply with this change. - last 4 patches: second version of the VEPA network patch set. VEPA networks are somewhat similar to macvtap networks that tunnels traffic between VMs by using an external VEPA-enabled switch that will process and forward the frames faster than the host CPU/OS can do. The UI support is similar to what we already have for the macvtap network. ATM the UI doesn't support multiple physical devices being assigned to a single VEPA network but the backend does. This can be enhanced in the future with an UI patch. The idea was to have some UI support to get the feature alive ASAP. To create a VEPA network the process is similar to the bridge network, allowing more interfaces to be declared in the new 'interfaces' parameter of the networks backend. This is the XML created when adding a VEPA network using one interface: <network> <name>vepa_net</name> <uuid>d6a3c86b-0592-4ccf-abf0-0abb353870b3</uuid> <forward dev='enp0s25' mode='vepa'> <interface dev='enp0s25'/> </forward> </network> This is how a VM can declare a interface that belongs to this network: <interface type='network'> <mac address='52:54:00:9c:be:bd'/> <source network='vepa_net'/> <model type='virtio'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> </interface> This is how the XML looks like when turning on the VM. Libvirt will take care of the creation of the VEPA tunnel by using the assigned physical interface in the network. If more interfaces were added to the network, libvirt will do a load balance between them and the VMs: <interface type='direct'> <mac address='52:54:00:9c:be:bd'/> <source network='vepa_net' dev='enp0s25' mode='vepa'/> <target dev='macvtap0'/> <model type='virtio'/> <alias name='net0'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> </interface> Daniel Henrique Barboza (8): Changing network API 'interface' to array: docs and API Changing network API: control and model changes Changing network API: unit test changes Changing network API: UI changes VEPA network support: API and i18n changes VEPA network support - models and xmlutils changes VEPA network support: additional backend unit tests VEPA network support: UI changes API.json | 8 ++--- control/networks.py | 4 +-- docs/API.md | 14 ++++---- i18n.py | 8 +++-- model/networks.py | 65 ++++++++++++++++++++++++------------ tests/test_mock_network.py | 11 ++---- tests/test_model_network.py | 38 ++++++++++++++++++--- tests/test_networkxml.py | 44 +++++++++++++++++++++++- tests/test_template.py | 12 ++++--- ui/js/src/kimchi.network.js | 5 +-- ui/js/src/kimchi.network_add_main.js | 12 +++---- ui/pages/network-add.html.tmpl | 5 +-- xmlutils/network.py | 10 +++++- 13 files changed, 169 insertions(+), 67 deletions(-) -- 2.5.0

From: Daniel Henrique Barboza <dhbarboza82@gmail.com> Changed docs/API.md, i18n.py and API.json to reflect the new API. interfaces[0] (the first element of this array) will have the same effect as the former 'interface' parameter. This change is necessary to better adapt the backend to networks that can be created with more than one interface. Signed-off-by: Daniel Henrique Barboza <dhbarboza82@gmail.com> --- API.json | 6 +++--- docs/API.md | 12 ++++++------ i18n.py | 6 ++++-- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/API.json b/API.json index 294be64..bc952b2 100644 --- a/API.json +++ b/API.json @@ -366,9 +366,9 @@ "type": "string", "error": "KCHNET0013E" }, - "interface": { - "description": "The name of a network interface on the host", - "type": "string", + "interfaces": { + "description": "An array of network interfaces of the host", + "type": "array", "error": "KCHNET0014E" }, "vlan_id": { diff --git a/docs/API.md b/docs/API.md index a46e80e..e1433f0 100644 --- a/docs/API.md +++ b/docs/API.md @@ -675,9 +675,9 @@ A interface represents available interface on host. it is not already a Linux bridge. * subnet *(optional)*: Network segment in slash-separated format with ip address and prefix or netmask used to create nat network. - * interface *(optional)*: The name of a network interface on the host. - For "macvtap" and "bridge" connections, the - interface can be a nic, bridge or bonding device. + * interfaces *(optional)*: An array of network interfaces of the host. + For "macvtap" and "bridge" connections, only + one interface will be allowed in this array. * vlan_id *(optional)*: VLAN tagging ID for the macvtap bridge network. ### Resource: Network @@ -710,9 +710,9 @@ A interface represents available interface on host. * bridge: Aggregated Public Network. The VM that joines this network is seen as a peer on this network and it may offer network services such as HTTP or SSH. - * interface: The name of a bridge network interface on the host. All traffic - on this network will be bridged through the indicated interface. - The interface is a bridge or ethernet/bonding device. + * interfaces: An array of bridge network interfaces that belongs to this network + All traffic on this network will be bridged through the first + interface. The interface is a bridge or ethernet/bonding device. * persistent: If 'true', network will persist after a system reboot or be stopped. All networks created by Kimchi are persistent. diff --git a/i18n.py b/i18n.py index 59e75f7..8280fe0 100644 --- a/i18n.py +++ b/i18n.py @@ -1,7 +1,7 @@ # # Project Kimchi # -# Copyright IBM, Corp. 2014-2016 +# Copyright IBM Corp, 2014-2016 # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -262,7 +262,7 @@ messages = { "KCHNET0011E": _("Network name must be a string without slashes (/) or quotes (\")"), "KCHNET0012E": _("Supported network types are isolated, NAT, macvtap and bridge"), "KCHNET0013E": _("Network subnet must be a string with IP address and prefix or netmask"), - "KCHNET0014E": _("Network interface must be a string"), + "KCHNET0014E": _("Network interfaces must be an array."), "KCHNET0015E": _("Network VLAN ID must be an integer between 1 and 4094"), "KCHNET0016E": _("Specify name and type to create a Network"), "KCHNET0017E": _("Unable to delete network %(name)s. There are some virtual machines %(vms)s and/or templates linked to this network."), @@ -275,6 +275,8 @@ messages = { "KCHNET0025E": _("Unable to create bridge %(name)s. Details: %(err)s"), "KCHNET0027E": _("Unable to create bridge with NetworkManager enabled. Disable it and try again."), "KCHNET0028E": _("Interface should be bare NIC or bonding."), + "KCHNET0029E": _("Network interfaces parameter must contain at least one interface."), + "KCHNET0030E": _("Only one interface is allowed for 'bridge' and 'macvtap' networks."), "KCHSR0001E": _("Storage server %(server)s was not used by Kimchi"), -- 2.5.0

From: Daniel Henrique Barboza <dhbarboza82@gmail.com> control/networks.py changes: - changed 'interface' to 'interfaces' in self.info - copyright fix. model/networks.py changes: - changed the param 'interface' to 'interfaces'. All variables that were referencing params['interface'] are now referencing params['interfaces'][0] to retain the same functionality - changed the flow of the create() method by calling the network interface verification for macvtap and bridge connections, removing this call from their specific methods. This will be useful when adding more connection types which will share this same verification - added extra verification in _check_network_interface for the new 'interfaces' parameter, including a verification to assert that 'macvtap' and 'bridge' networks will not be created if more than one interface is passed - moved Network Manager verification up to cover the case where a vlan_tagged_bridge will be created - lookup function of NetworkModel changed to return an array of size 1 with the old 'interface' parameter, renamed it to 'interfaces'. Since no network implemented in the backend supports more than one interface, this change suffices to comply with the new API Signed-off-by: Daniel Henrique Barboza <dhbarboza82@gmail.com> --- control/networks.py | 4 ++-- model/networks.py | 47 ++++++++++++++++++++++++++--------------------- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/control/networks.py b/control/networks.py index fd92111..1431e67 100644 --- a/control/networks.py +++ b/control/networks.py @@ -1,7 +1,7 @@ # # Project Kimchi # -# Copyright IBM, Corp. 2013-2015 +# Copyright IBM Corp, 2013-2016 # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -47,7 +47,7 @@ class Network(Resource): 'in_use': self.info['in_use'], 'autostart': self.info['autostart'], 'connection': self.info['connection'], - 'interface': self.info['interface'], + 'interfaces': self.info['interfaces'], 'subnet': self.info['subnet'], 'dhcp': self.info['dhcp'], 'state': self.info['state'], diff --git a/model/networks.py b/model/networks.py index 81aac3e..15e2d4a 100644 --- a/model/networks.py +++ b/model/networks.py @@ -1,7 +1,7 @@ # # Project Kimchi # -# Copyright IBM, Corp. 2014-2015 +# Copyright IBM Corp, 2014-2016 # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -88,16 +88,18 @@ class NetworksModel(object): # handle connection type connection = params["connection"] - if connection == 'macvtap': - self._set_network_macvtap(params) - elif connection == 'bridge': - self._set_network_bridge(params) - elif connection in ['nat', 'isolated']: + if connection in ['nat', 'isolated']: if connection == 'nat': params['forward'] = {'mode': 'nat'} # set subnet; bridge/macvtap networks do not need subnet self._set_network_subnet(params) + else: + self._check_network_interface(params) + if connection == 'macvtap': + self._set_network_macvtap(params) + elif connection == 'bridge': + self._set_network_bridge(params) # create network XML params['name'] = escape(params['name']) @@ -165,19 +167,23 @@ class NetworksModel(object): raise OperationFailed("KCHNET0021E", {'iface': iface}) def _check_network_interface(self, params): - try: - # fails if host interface is already in use by a libvirt network - iface = params['interface'] + if not params.get('interfaces'): + raise MissingParameter("KCHNET0004E", {'name': params['name']}) + + if len(params['interfaces']) == 0: + raise InvalidParameter("KCHNET0029E") + + conn = params['connection'] + if conn in ['bridge', 'macvtap'] and len(params['interfaces']) > 1: + raise InvalidParameter("KCHNET0030E") + + for iface in params['interfaces']: if iface in self.get_all_networks_interfaces(): msg_args = {'iface': iface, 'network': params['name']} raise InvalidParameter("KCHNET0006E", msg_args) - except KeyError: - raise MissingParameter("KCHNET0004E", {'name': params['name']}) def _set_network_macvtap(self, params): - self._check_network_interface(params) - - iface = params['interface'] + iface = params['interfaces'][0] if ('vlan_id' in params or not (netinfo.is_bare_nic(iface) or netinfo.is_bonding(iface))): raise InvalidParameter('KCHNET0028E', {'name': iface}) @@ -186,11 +192,10 @@ class NetworksModel(object): params['forward'] = {'mode': 'bridge', 'dev': iface} def _set_network_bridge(self, params): - self._check_network_interface(params) params['forward'] = {'mode': 'bridge'} # Bridges cannot be the trunk device of a VLAN - iface = params['interface'] + iface = params['interfaces'][0] if 'vlan_id' in params and netinfo.is_bridge(iface): raise InvalidParameter('KCHNET0019E', {'name': iface}) @@ -205,15 +210,15 @@ class NetworksModel(object): # connection == macvtap and iface is not bridge elif netinfo.is_bare_nic(iface) or netinfo.is_bonding(iface): + # libvirt bridge creation will fail with NetworkManager enabled + if self.caps.nm_running: + raise InvalidParameter('KCHNET0027E') + if 'vlan_id' in params: params['bridge'] = \ self._create_vlan_tagged_bridge(str(iface), str(params['vlan_id'])) else: - # libvirt bridge creation will fail with NetworkManager enabled - if self.caps.nm_running: - raise InvalidParameter('KCHNET0027E') - # create Linux bridge interface and use it as actual iface iface = self._create_linux_bridge(iface) params['bridge'] = iface @@ -353,7 +358,7 @@ class NetworkModel(object): subnet = "%s/%s" % (subnet.network, subnet.prefixlen) return {'connection': connection, - 'interface': interface, + 'interfaces': [interface], 'subnet': subnet, 'dhcp': dhcp, 'vms': self._get_vms_attach_to_a_network(name), -- 2.5.0

From: Daniel Henrique Barboza <dhbarboza82@gmail.com> - test_mock_network: using FeatureTests.is_nm_running() instead of its own function that does the same thing - test_model_network: changed 'interface' to interfaces, added network manager verification on vlan tag - test_template: added network manager verification for macvtap network with vlan tag - fixed copyright dates and format in all those files Signed-off-by: Daniel Henrique Barboza <dhbarboza82@gmail.com> --- tests/test_mock_network.py | 11 ++--------- tests/test_model_network.py | 38 +++++++++++++++++++++++++++++++++----- tests/test_template.py | 12 +++++++----- 3 files changed, 42 insertions(+), 19 deletions(-) diff --git a/tests/test_mock_network.py b/tests/test_mock_network.py index 3a9b7b5..3a2ca64 100644 --- a/tests/test_mock_network.py +++ b/tests/test_mock_network.py @@ -26,7 +26,7 @@ from functools import partial from tests.utils import get_free_port, patch_auth, request, run_server from wok.plugins.kimchi.mockmodel import MockModel -from wok.utils import run_command +from wok.plugins.kimchi.model.featuretests import FeatureTests from test_model_network import _do_network_test @@ -57,19 +57,12 @@ def tearDownModule(): os.unlink('/tmp/obj-store-test') -def is_network_manager_running(): - out, err, rc = run_command(['nmcli', 'dev', 'status']) - if rc != 0: - return False - return True - - class MockNetworkTests(unittest.TestCase): def setUp(self): self.request = partial(request, host, ssl_port) model.reset() - @unittest.skipIf(is_network_manager_running(), + @unittest.skipIf(FeatureTests.is_nm_running(), 'test_vlan_tag_bridge skipped because Network ' 'Manager is running.') def test_vlan_tag_bridge(self): diff --git a/tests/test_model_network.py b/tests/test_model_network.py index 2abdd50..e27036d 100644 --- a/tests/test_model_network.py +++ b/tests/test_model_network.py @@ -2,7 +2,7 @@ # # Project Kimchi # -# Copyright IBM, Corp. 2015 +# Copyright IBM Corp, 2015-2016 # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -29,6 +29,7 @@ from tests.utils import run_server from wok.rollbackcontext import RollbackContext from wok.plugins.kimchi.model.model import Model +from wok.plugins.kimchi.model.featuretests import FeatureTests model = None @@ -124,7 +125,7 @@ class NetworkTests(unittest.TestCase): network = json.loads( self.request('/plugins/kimchi/networks/network-1').read() ) - keys = [u'name', u'connection', u'interface', u'subnet', u'dhcp', + keys = [u'name', u'connection', u'interfaces', u'subnet', u'dhcp', u'vms', u'in_use', u'autostart', u'state', u'persistent'] self.assertEquals(sorted(keys), sorted(network.keys())) @@ -143,9 +144,36 @@ class NetworkTests(unittest.TestCase): if len(interfaces) > 0: iface = interfaces[0]['name'] networks.append({'name': u'macvtap-network', - 'connection': 'macvtap', 'interface': iface}) - networks.append({'name': u'bridge-network', 'connection': 'bridge', - 'interface': iface}) + 'connection': 'macvtap', 'interfaces': [iface]}) + if not FeatureTests.is_nm_running(): + networks.append({'name': u'bridge-network', + 'connection': 'bridge', + 'interfaces': [iface]}) for net in networks: _do_network_test(self, model, net) + + def test_macvtap_network_create_fails_more_than_one_interface(self): + network = { + 'name': u'macvtap-network', + 'connection': 'macvtap', + 'interfaces': ['fake_iface1', 'fake_iface2', 'fake_iface3'] + } + + expected_error_msg = "KCHNET0030E" + req = json.dumps(network) + resp = self.request('/plugins/kimchi/networks', req, 'POST') + self.assertEquals(400, resp.status) + self.assertIn(expected_error_msg, resp.read()) + + def test_bridge_network_create_fails_more_than_one_interface(self): + network = { + 'name': u'bridge-network', + 'connection': 'bridge', + 'interfaces': ['fake_iface1', 'fake_iface2', 'fake_iface3'] + } + expected_error_msg = "KCHNET0030E" + req = json.dumps(network) + resp = self.request('/plugins/kimchi/networks', req, 'POST') + self.assertEquals(400, resp.status) + self.assertIn(expected_error_msg, resp.read()) diff --git a/tests/test_template.py b/tests/test_template.py index da0037e..7e53ae1 100644 --- a/tests/test_template.py +++ b/tests/test_template.py @@ -2,7 +2,7 @@ # # Project Kimchi # -# Copyright IBM, Corp. 2015-2016 +# Copyright IBM Corp, 2015-2016 # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -28,6 +28,7 @@ from tests.utils import get_free_port, patch_auth, request, run_server from wok.plugins.kimchi.config import READONLY_POOL_TYPE from wok.plugins.kimchi.mockmodel import MockModel +from wok.plugins.kimchi.model.featuretests import FeatureTests model = None @@ -320,10 +321,11 @@ class TemplateTests(unittest.TestCase): iface = interfaces[0]['name'] networks.append({'name': u'bridge-network', 'connection': 'macvtap', - 'interface': iface}) - networks.append({'name': u'bridge-network', - 'connection': 'macvtap', - 'interface': iface, 'vlan_id': 987}) + 'interfaces': [iface]}) + if not FeatureTests.is_nm_running(): + networks.append({'name': u'bridge-network-with-vlan', + 'connection': 'bridge', + 'interfaces': [iface], 'vlan_id': 987}) tmpl_nets = [] for net in networks: -- 2.5.0

From: Daniel Henrique Barboza <dhbarboza82@gmail.com> kimchi.network.js and kimchi.network_add_main.js are now considering that the backend is working with an array called 'interfaces'. Same UI behavior is kept by assigning the first element of this array to the existing 'interface' parameter. Copyright format changes were made too. Signed-off-by: Daniel Henrique Barboza <dhbarboza82@gmail.com> --- ui/js/src/kimchi.network.js | 4 ++-- ui/js/src/kimchi.network_add_main.js | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ui/js/src/kimchi.network.js b/ui/js/src/kimchi.network.js index 96c3fea..1e79f8d 100644 --- a/ui/js/src/kimchi.network.js +++ b/ui/js/src/kimchi.network.js @@ -1,7 +1,7 @@ /* * Project Kimchi * - * Copyright IBM, Corp. 2013-2015 + * Copyright IBM Corp, 2013-2016 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,7 +43,7 @@ kimchi.initNetworkListView = function() { } else { network.type = data[i].connection; } - network.interface = data[i].interface ? data[i].interface : null; + network.interface = data[i].interfaces ? data[i].interfaces[0] : null; network.addrSpace = data[i].subnet ? data[i].subnet : null; network.persistent = data[i].persistent; kimchi.addNetworkItem(network); diff --git a/ui/js/src/kimchi.network_add_main.js b/ui/js/src/kimchi.network_add_main.js index 0157df7..6beb115 100644 --- a/ui/js/src/kimchi.network_add_main.js +++ b/ui/js/src/kimchi.network_add_main.js @@ -1,7 +1,7 @@ /* * Project Kimchi * - * Copyright IBM, Corp. 2013-2016 + * Copyright IBM Corp, 2013-2016 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,13 +32,13 @@ kimchi.startNetworkCreation = function() { var data = { name : network.name, connection: network.type, - interface: network.interface, + interfaces: [ network.interface ], vlan_id: network.vlan_id }; kimchi.createNetwork(data, function(result) { network.state = result.state === "active" ? "up" : "down"; - network.interface = result.interface ? result.interface : i18n["KCHNET6001M"]; + network.interface = result.interfaces ? result.interfaces[0] : i18n["KCHNET6001M"]; network.addrSpace = result.subnet ? result.subnet : i18n["KCHNET6001M"]; network.persistent = result.persistent; $('#networkGrid').dataGrid('addRow', kimchi.addNetworkItem(network)); @@ -181,4 +181,4 @@ kimchi.loadInterfaces = function(interfaceFilterArray) { kimchi.setDefaultNetworkType(result.length!==0); kimchi.changeNetworkDestination(); }); -}; \ No newline at end of file +}; -- 2.5.0

From: Daniel Henrique Barboza <dhbarboza82@gmail.com> This patch includes API and message changes to support VEPA networks in Kimchi: - API.json: added 'vepa' as a valid connection in the networks API - docs/API.md: added 'vepa' as a valid connection in the networks API. - i18n.py: changed one message to add 'vepa' reference. Signed-off-by: Daniel Henrique Barboza <dhbarboza82@gmail.com> --- API.json | 2 +- docs/API.md | 2 ++ i18n.py | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/API.json b/API.json index bc952b2..75c8a03 100644 --- a/API.json +++ b/API.json @@ -357,7 +357,7 @@ "connection": { "description": "Specifies how this network should be connected to the other networks", "type": "string", - "pattern": "^isolated|nat|bridge|macvtap$", + "pattern": "^isolated|nat|bridge|macvtap|vepa$", "required": true, "error": "KCHNET0012E" }, diff --git a/docs/API.md b/docs/API.md index e1433f0..c432a5e 100644 --- a/docs/API.md +++ b/docs/API.md @@ -670,6 +670,8 @@ A interface represents available interface on host. * nat: Outgoing traffic will be routed through the host. * macvtap: All traffic on this network will be bridged through the specified interface. + * vepa: All traffic will be forward to one or more physical devices + directly connected to a VEPA-enabled switch. * bridge: All traffic on this network will be bridged through a Linux bridged, which is created upon specified interface in case it is not already a Linux bridge. diff --git a/i18n.py b/i18n.py index 8280fe0..42ee884 100644 --- a/i18n.py +++ b/i18n.py @@ -260,7 +260,7 @@ messages = { "KCHNET0009E": _("Unable to find a free IP address for network '%(name)s'"), "KCHNET0010E": _("The interface %(iface)s already exists."), "KCHNET0011E": _("Network name must be a string without slashes (/) or quotes (\")"), - "KCHNET0012E": _("Supported network types are isolated, NAT, macvtap and bridge"), + "KCHNET0012E": _("Supported network types are isolated, NAT, macvtap, bridge and vepa"), "KCHNET0013E": _("Network subnet must be a string with IP address and prefix or netmask"), "KCHNET0014E": _("Network interfaces must be an array."), "KCHNET0015E": _("Network VLAN ID must be an integer between 1 and 4094"), -- 2.5.0

From: Daniel Henrique Barboza <dhbarboza82@gmail.com> -model/networks.py: added 'vepa' support by creating a new method to verify the availability of all interfaces and preset the parameters for the xml creation. Edited the lookup() method to add the interfaces retrieved by the VEPA xml declaration, keeping the same behavior for the other networks. - xmlutils/network.py: edited the _get_forward_elem() method to add all the interfaces that belongs to a 'vepa' type network. Signed-off-by: Daniel Henrique Barboza <dhbarboza82@gmail.com> --- model/networks.py | 20 +++++++++++++++++++- xmlutils/network.py | 10 +++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/model/networks.py b/model/networks.py index 15e2d4a..ec30458 100644 --- a/model/networks.py +++ b/model/networks.py @@ -100,6 +100,8 @@ class NetworksModel(object): self._set_network_macvtap(params) elif connection == 'bridge': self._set_network_bridge(params) + elif connection == 'vepa': + self._set_network_vepa(params) # create network XML params['name'] = escape(params['name']) @@ -191,6 +193,14 @@ class NetworksModel(object): # set macvtap network params['forward'] = {'mode': 'bridge', 'dev': iface} + def _set_network_vepa(self, params): + for iface in params['interfaces']: + if ('vlan_id' in params or not (netinfo.is_bare_nic(iface) or + netinfo.is_bonding(iface))): + raise InvalidParameter('KCHNET0028E', {'name': iface}) + + params['forward'] = {'mode': 'vepa', 'devs': params['interfaces']} + def _set_network_bridge(self, params): params['forward'] = {'mode': 'bridge'} @@ -357,8 +367,16 @@ class NetworkModel(object): subnet = ipaddr.IPNetwork(subnet) subnet = "%s/%s" % (subnet.network, subnet.prefixlen) + if connection == 'vepa': + interfaces = xpath_get_text( + xml, + "/network/forward/interface/@dev" + ) + else: + interfaces = [interface] + return {'connection': connection, - 'interfaces': [interface], + 'interfaces': interfaces, 'subnet': subnet, 'dhcp': dhcp, 'vms': self._get_vms_attach_to_a_network(name), diff --git a/xmlutils/network.py b/xmlutils/network.py index 6fc3481..01f26f8 100644 --- a/xmlutils/network.py +++ b/xmlutils/network.py @@ -1,7 +1,7 @@ # # Project Kimchi # -# Copyright IBM, Corp. 2014 +# Copyright IBM Corp, 2014-2016 # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -79,6 +79,14 @@ def _get_forward_elem(**kwargs): forward = E.forward() if 'mode' in kwargs.keys(): forward.set('mode', kwargs['mode']) + if kwargs['mode'] == 'vepa': + devs = kwargs['devs'] + forward.set('dev', devs[0]) + + for dev in devs: + interface = E.interface() + interface.set('dev', dev) + forward.append(interface) if 'dev' in kwargs.keys(): forward.set('dev', kwargs['dev']) -- 2.5.0

From: Daniel Henrique Barboza <dhbarboza82@gmail.com> Added extra tests to assert the resulting VEPA network XML. Signed-off-by: Daniel Henrique Barboza <dhbarboza82@gmail.com> --- tests/test_networkxml.py | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/tests/test_networkxml.py b/tests/test_networkxml.py index d4e2c3f..8e83744 100644 --- a/tests/test_networkxml.py +++ b/tests/test_networkxml.py @@ -1,7 +1,7 @@ # # Kimchi # -# Copyright IBM, Corp. 2013-2014 +# Copyright IBM Corp, 2013-2016 # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -153,6 +153,48 @@ class NetworkXmlTests(unittest.TestCase): self.assertEquals(netmask, str(ipaddr.IPNetwork(params["net"]).netmask)) + def test_vepa_network_singledev_xml(self): + expected_xml = """<network>\ +<name>test_vepa</name>\ +<forward mode="vepa" dev="vepa_switch_interface">\ +<interface dev="vepa_switch_interface"/>\ +</forward>\ +</network>""" + + params = { + "name": "test_vepa", + "forward": { + "mode": "vepa", + "devs": ["vepa_switch_interface"] + } + } + xml_str = nxml.to_network_xml(**params) + self.assertEqual(xml_str, expected_xml) + + def test_vepa_network_multipledevs_xml(self): + expected_xml = """<network>\ +<name>test_vepa</name>\ +<forward mode="vepa" dev="vepa_switch_interface1">\ +<interface dev="vepa_switch_interface1"/>\ +<interface dev="vepa_switch_interface2"/>\ +<interface dev="vepa_switch_interface3"/>\ +</forward>\ +</network>""" + + params = { + "name": "test_vepa", + "forward": { + "mode": "vepa", + "devs": [ + "vepa_switch_interface1", + "vepa_switch_interface2", + "vepa_switch_interface3" + ] + } + } + xml_str = nxml.to_network_xml(**params) + self.assertEqual(xml_str, expected_xml) + class InterfaceXmlTests(unittest.TestCase): -- 2.5.0

From: Daniel Henrique Barboza <dhbarboza82@gmail.com> Pinpoint UI changes to add a new network type named 'vepa' with the same capabilites as the macvtap network. At this moment, the UI does not support multiple physical devices to be declared in the VEPA network. This will require additional UI changes in the future (no backend changes needed). Signed-off-by: Daniel Henrique Barboza <dhbarboza82@gmail.com> --- ui/js/src/kimchi.network.js | 1 + ui/js/src/kimchi.network_add_main.js | 4 ++-- ui/pages/network-add.html.tmpl | 5 +++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ui/js/src/kimchi.network.js b/ui/js/src/kimchi.network.js index 1e79f8d..02a37cd 100644 --- a/ui/js/src/kimchi.network.js +++ b/ui/js/src/kimchi.network.js @@ -18,6 +18,7 @@ kimchi.NETWORK_TYPE_MACVTAP = "macvtap"; kimchi.NETWORK_TYPE_BRIDGED = "bridge"; +kimchi.NETWORK_TYPE_VEPA = "vepa"; kimchi.initNetwork = function() { diff --git a/ui/js/src/kimchi.network_add_main.js b/ui/js/src/kimchi.network_add_main.js index 6beb115..8e2665b 100644 --- a/ui/js/src/kimchi.network_add_main.js +++ b/ui/js/src/kimchi.network_add_main.js @@ -82,7 +82,7 @@ kimchi.getNetworkDialogValues = function() { name : $("#networkName").val(), type : $("#networkType").val() }; - if (network.type === kimchi.NETWORK_TYPE_MACVTAP) { + if (network.type === kimchi.NETWORK_TYPE_MACVTAP || network.type === kimchi.NETWORK_TYPE_VEPA) { network.interface = $("#networkDestinationID").val(); } if (network.type === kimchi.NETWORK_TYPE_BRIDGED) { @@ -106,7 +106,7 @@ kimchi.setupNetworkFormEvent = function() { $('#networkType').on('change', function() { var selectedType = $("#networkType").val(); - if(selectedType === kimchi.NETWORK_TYPE_MACVTAP) { + if(selectedType === kimchi.NETWORK_TYPE_MACVTAP || selectedType === kimchi.NETWORK_TYPE_VEPA) { kimchi.loadInterfaces(new Array("nic", "bonding")); } else { kimchi.loadInterfaces(); diff --git a/ui/pages/network-add.html.tmpl b/ui/pages/network-add.html.tmpl index 6bd2acf..3f50ad2 100644 --- a/ui/pages/network-add.html.tmpl +++ b/ui/pages/network-add.html.tmpl @@ -1,7 +1,7 @@ #* * Project Kimchi * - * Copyright IBM, Corp. 2014-2015 + * Copyright IBM Corp, 2014-2016 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,6 +41,7 @@ <option value="isolated">$_("Isolated: no external network connection")</option> <option value="nat">$_("NAT: outbound physical network connection only")</option> <option value="macvtap">$_("Macvtap: Virtual machines are connected to physical network directly")</option> + <option value="vepa">$_("VEPA: special mode where virtual machines are connected to a VEPA-enabled switch")</option> <option value="bridge">$_("Bridged: Virtual machines are connected through a network bridge")</option> </select> </div> @@ -72,4 +73,4 @@ kimchi.network_add_main(); </script> </body> -</html> \ No newline at end of file +</html> -- 2.5.0
participants (2)
-
Aline Manera
-
dhbarboza82@gmail.com