The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/7678

This e-mail was sent by the LXC bot, direct replies will not reach the author
unless they happen to be subscribed to this list.

=== Description (from pull-request) ===
This PR allows one to use a sriov managed network for adding sriov NICs, e.g.

```
lxc network create test --type=sriov parent=enp4s0f0
lxc config device add c1 eth0 nic network=test
```
From 9e6fa4e9098cb344e2964350daad251863621262 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 21 Jul 2020 16:14:38 +0100
Subject: [PATCH 1/7] lxd: Adds NetworkTypeSriov constant and conversion
 handling

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/db/networks.go | 3 +++
 lxd/networks.go    | 2 ++
 2 files changed, 5 insertions(+)

diff --git a/lxd/db/networks.go b/lxd/db/networks.go
index af26843557..bcd6812145 100644
--- a/lxd/db/networks.go
+++ b/lxd/db/networks.go
@@ -309,6 +309,7 @@ type NetworkType int
 const (
        NetworkTypeBridge  NetworkType = iota // Network type bridge.
        NetworkTypeMacvlan                    // Network type macvlan.
+       NetworkTypeSriov                      // Network type sriov.
 )
 
 // GetNetworkInAnyState returns the network with the given name.
@@ -370,6 +371,8 @@ func (c *Cluster) getNetwork(name string, onlyCreated bool) 
(int64, *api.Network
                network.Type = "bridge"
        case NetworkTypeMacvlan:
                network.Type = "macvlan"
+       case NetworkTypeSriov:
+               network.Type = "sriov"
        default:
                network.Type = "" // Unknown
        }
diff --git a/lxd/networks.go b/lxd/networks.go
index d31c0cf802..76baa06e07 100644
--- a/lxd/networks.go
+++ b/lxd/networks.go
@@ -130,6 +130,8 @@ func networksPost(d *Daemon, r *http.Request) 
response.Response {
                dbNetType = db.NetworkTypeBridge
        case "macvlan":
                dbNetType = db.NetworkTypeMacvlan
+       case "sriov":
+               dbNetType = db.NetworkTypeSriov
        default:
                return response.BadRequest(fmt.Errorf("Unrecognised network 
type"))
        }

From b5b7234688b366a7f1f29c9761af5a1c0babe571 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 21 Jul 2020 16:17:38 +0100
Subject: [PATCH 2/7] lxd/network: Adds sriov driver

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/network/driver_sriov.go | 115 ++++++++++++++++++++++++++++++++++++
 lxd/network/network_load.go |   1 +
 2 files changed, 116 insertions(+)
 create mode 100644 lxd/network/driver_sriov.go

diff --git a/lxd/network/driver_sriov.go b/lxd/network/driver_sriov.go
new file mode 100644
index 0000000000..3b8260609d
--- /dev/null
+++ b/lxd/network/driver_sriov.go
@@ -0,0 +1,115 @@
+package network
+
+import (
+       "fmt"
+
+       "github.com/pkg/errors"
+
+       "github.com/lxc/lxd/lxd/revert"
+       "github.com/lxc/lxd/shared"
+       "github.com/lxc/lxd/shared/api"
+       log "github.com/lxc/lxd/shared/log15"
+)
+
+// sriov represents a LXD sriov network.
+type sriov struct {
+       common
+}
+
+// Validate network config.
+func (n *sriov) Validate(config map[string]string) error {
+       rules := map[string]func(value string) error{
+               "parent": func(value string) error {
+                       if err := ValidNetworkName(value); err != nil {
+                               return errors.Wrapf(err, "Invalid interface 
name %q", value)
+                       }
+
+                       return nil
+               },
+               "maas.subnet.ipv4": shared.IsAny,
+               "maas.subnet.ipv6": shared.IsAny,
+       }
+
+       err := n.validate(config, rules)
+       if err != nil {
+               return err
+       }
+
+       return nil
+}
+
+// Delete deletes a network.
+func (n *sriov) Delete(clusterNotification bool) error {
+       n.logger.Debug("Delete", log.Ctx{"clusterNotification": 
clusterNotification})
+       return n.common.delete(clusterNotification)
+}
+
+// Rename renames a network.
+func (n *sriov) Rename(newName string) error {
+       n.logger.Debug("Rename", log.Ctx{"newName": newName})
+
+       // Sanity checks.
+       inUse, err := n.IsUsed()
+       if err != nil {
+               return err
+       }
+
+       if inUse {
+               return fmt.Errorf("The network is currently in use")
+       }
+
+       // Rename common steps.
+       err = n.common.rename(newName)
+       if err != nil {
+               return err
+       }
+
+       return nil
+}
+
+// Start starts is a no-op.
+func (n *sriov) Start() error {
+       if n.status == api.NetworkStatusPending {
+               return fmt.Errorf("Cannot start pending network")
+       }
+
+       return nil
+}
+
+// Stop stops is a no-op.
+func (n *sriov) Stop() error {
+       return nil
+}
+
+// Update updates the network. Accepts notification boolean indicating if this 
update request is coming from a
+// cluster notification, in which case do not update the database, just apply 
local changes needed.
+func (n *sriov) Update(newNetwork api.NetworkPut, targetNode string, 
clusterNotification bool) error {
+       n.logger.Debug("Update", log.Ctx{"clusterNotification": 
clusterNotification, "newNetwork": newNetwork})
+
+       dbUpdateNeeeded, _, oldNetwork, err := 
n.common.configChanged(newNetwork)
+       if err != nil {
+               return err
+       }
+
+       if !dbUpdateNeeeded {
+               return nil // Nothing changed.
+       }
+
+       revert := revert.New()
+       defer revert.Fail()
+
+       // Define a function which reverts everything.
+       revert.Add(func() {
+               // Reset changes to all nodes and database.
+               n.common.update(oldNetwork, targetNode, clusterNotification)
+       })
+
+       // Apply changes to database.
+       err = n.common.update(newNetwork, targetNode, clusterNotification)
+       if err != nil {
+               return err
+       }
+
+       revert.Success()
+       return nil
+}
diff --git a/lxd/network/network_load.go b/lxd/network/network_load.go
index a515779fb3..8638987cfd 100644
--- a/lxd/network/network_load.go
+++ b/lxd/network/network_load.go
@@ -8,6 +8,7 @@ import (
 var drivers = map[string]func() Network{
        "bridge":  func() Network { return &bridge{} },
        "macvlan": func() Network { return &macvlan{} },
+       "sriov":   func() Network { return &sriov{} },
 }
 
 // LoadByName loads the network info from the database by name.

From 4085f133ee537f2691e5068d0d06509f83198b8f Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 21 Jul 2020 16:29:32 +0100
Subject: [PATCH 3/7] lxd/networks: Remove database record on error in
 networksPost

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/networks.go | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/lxd/networks.go b/lxd/networks.go
index 76baa06e07..94771ec9a7 100644
--- a/lxd/networks.go
+++ b/lxd/networks.go
@@ -201,18 +201,26 @@ func networksPost(d *Daemon, r *http.Request) 
response.Response {
                return response.BadRequest(fmt.Errorf("The network already 
exists"))
        }
 
+       revert := revert.New()
+       defer revert.Fail()
+
        // Create the database entry.
        _, err = d.cluster.CreateNetwork(req.Name, req.Description, dbNetType, 
req.Config)
        if err != nil {
                return response.SmartError(errors.Wrapf(err, "Error inserting 
%q into database", req.Name))
        }
 
+       revert.Add(func() {
+               d.cluster.DeleteNetwork(req.Name)
+       })
+
        // Create network and pass false to clusterNotification so the database 
record is removed on error.
        err = doNetworksCreate(d, req, false)
        if err != nil {
                return response.SmartError(err)
        }
 
+       revert.Success()
        return resp
 }
 

From 3f9271e1da1ec944577c256eace56091b45bc0b2 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 21 Jul 2020 16:31:43 +0100
Subject: [PATCH 4/7] lxd/device/nic/sriov: Adds network key support

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/device/nic_sriov.go | 48 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 47 insertions(+), 1 deletion(-)

diff --git a/lxd/device/nic_sriov.go b/lxd/device/nic_sriov.go
index 724d432e71..83f7294254 100644
--- a/lxd/device/nic_sriov.go
+++ b/lxd/device/nic_sriov.go
@@ -17,9 +17,11 @@ import (
        deviceConfig "github.com/lxc/lxd/lxd/device/config"
        "github.com/lxc/lxd/lxd/instance"
        "github.com/lxc/lxd/lxd/instance/instancetype"
+       "github.com/lxc/lxd/lxd/network"
        "github.com/lxc/lxd/lxd/revert"
        "github.com/lxc/lxd/lxd/util"
        "github.com/lxc/lxd/shared"
+       "github.com/lxc/lxd/shared/api"
 )
 
 type nicSRIOV struct {
@@ -32,9 +34,11 @@ func (d *nicSRIOV) validateConfig(instConf 
instance.ConfigReader) error {
                return ErrUnsupportedDevType
        }
 
-       requiredFields := []string{"parent"}
+       var requiredFields []string
        optionalFields := []string{
                "name",
+               "network",
+               "parent",
                "hwaddr",
                "vlan",
                "security.mac_filtering",
@@ -43,6 +47,48 @@ func (d *nicSRIOV) validateConfig(instConf 
instance.ConfigReader) error {
                "boot.priority",
        }
 
+       // Check that if network proeperty is set that conflicting keys are not 
present.
+       if d.config["network"] != "" {
+               requiredFields = append(requiredFields, "network")
+
+               bannedKeys := []string{"nictype", "parent", "mtu", 
"maas.subnet.ipv4", "maas.subnet.ipv6"}
+               for _, bannedKey := range bannedKeys {
+                       if d.config[bannedKey] != "" {
+                               return fmt.Errorf("Cannot use %q property in 
conjunction with %q property", bannedKey, "network")
+                       }
+               }
+
+               // If network property is specified, lookup network settings 
and apply them to the device's config.
+               n, err := network.LoadByName(d.state, d.config["network"])
+               if err != nil {
+                       return errors.Wrapf(err, "Error loading network config 
for %q", d.config["network"])
+               }
+
+               if n.Status() == api.NetworkStatusPending {
+                       return fmt.Errorf("Specified network is not fully 
created")
+               }
+
+               if n.Type() != "sriov" {
+                       return fmt.Errorf("Specified network must be of type 
macvlan")
+               }
+
+               netConfig := n.Config()
+
+               // Get actual parent device from network's parent setting.
+               d.config["parent"] = netConfig["parent"]
+
+               // Copy certain keys verbatim from the network's settings.
+               inheritKeys := []string{"maas.subnet.ipv4", "maas.subnet.ipv6"}
+               for _, inheritKey := range inheritKeys {
+                       if _, found := netConfig[inheritKey]; found {
+                               d.config[inheritKey] = netConfig[inheritKey]
+                       }
+               }
+       } else {
+               // If no network property supplied, then parent property is 
required.
+               requiredFields = append(requiredFields, "parent")
+       }
+
        // For VMs only NIC properties that can be specified on the parent's VF 
settings are controllable.
        if instConf.Type() == instancetype.Container {
                optionalFields = append(optionalFields, "mtu")

From 7abacec2487d4c06b8af8635be36d5126c39b5db Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 21 Jul 2020 16:31:58 +0100
Subject: [PATCH 5/7] lxd/device/nictype: Adds sriov support

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/device/nictype/nictype.go | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lxd/device/nictype/nictype.go b/lxd/device/nictype/nictype.go
index fb8e02530d..c3ad6811ab 100644
--- a/lxd/device/nictype/nictype.go
+++ b/lxd/device/nictype/nictype.go
@@ -30,6 +30,8 @@ func NICType(s *state.State, d deviceConfig.Device) (string, 
error) {
                                nicType = "bridged"
                        case "macvlan":
                                nicType = "macvlan"
+                       case "sriov":
+                               nicType = "sriov"
                        default:
                                return "", fmt.Errorf("Unrecognised NIC network 
type for network %q", d["network"])
                        }

From 77d2fafebb0bcae4f5748d02ec0b38bb080f08d6 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Wed, 22 Jul 2020 08:52:19 +0100
Subject: [PATCH 6/7] test: sriov NIC comment ending consistency

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 test/suites/container_devices_nic_sriov.sh | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/test/suites/container_devices_nic_sriov.sh 
b/test/suites/container_devices_nic_sriov.sh
index 062818d084..7a03f0d3af 100644
--- a/test/suites/container_devices_nic_sriov.sh
+++ b/test/suites/container_devices_nic_sriov.sh
@@ -38,7 +38,7 @@ test_container_devices_nic_sriov() {
     parent="${parent}"
   lxc start "${ctName}"
 
-  # Check spoof checking has been disabled (the default)
+  # Check spoof checking has been disabled (the default).
   vfID=$(lxc config get "${ctName}" volatile.eth0.last_state.vf.id)
   if ip link show "${parent}" | grep "vf ${vfID}" | grep "spoof checking on"; 
then
     echo "spoof checking is still enabled"
@@ -47,7 +47,7 @@ test_container_devices_nic_sriov() {
 
   lxc config device set "${ctName}" eth0 vlan 1234
 
-  # Check custom vlan has been enabled
+  # Check custom vlan has been enabled.
   vfID=$(lxc config get "${ctName}" volatile.eth0.last_state.vf.id)
   if ! ip link show "${parent}" | grep "vf ${vfID}" | grep "vlan 1234"; then
     echo "vlan not set"
@@ -65,7 +65,7 @@ test_container_devices_nic_sriov() {
 
   lxc config device set "${ctName}" eth0 vlan 0
 
-  # Check custom vlan has been disabled
+  # Check custom vlan has been disabled.
   vfID=$(lxc config get "${ctName}" volatile.eth0.last_state.vf.id)
   if ip link show "${parent}" | grep "vf ${vfID}" | grep "vlan"; then
     # Mellanox cards display vlan 0 as vlan 4095!
@@ -89,7 +89,7 @@ test_container_devices_nic_sriov() {
   lxc config device set "${ctName}" eth0 hwaddr "${ctMAC1}"
   lxc start "${ctName}"
 
-  # Check custom MAC is applied
+  # Check custom MAC is applied.
   vfID=$(lxc config get "${ctName}" volatile.eth0.last_state.vf.id)
   if ! ip link show "${parent}" | grep "vf ${vfID}" | grep "${ctMAC1}"; then
     echo "eth0 MAC not set"
@@ -98,24 +98,24 @@ test_container_devices_nic_sriov() {
 
   lxc stop -f "${ctName}"
 
-  # Disable mac filtering and try fresh boot
+  # Disable mac filtering and try fresh boot.
   lxc config device set "${ctName}" eth0 security.mac_filtering false
   lxc start "${ctName}"
 
-  # Check spoof checking has been disabled (the default)
+  # Check spoof checking has been disabled (the default).
   vfID=$(lxc config get "${ctName}" volatile.eth0.last_state.vf.id)
   if ! ip link show "${parent}" | grep "vf ${vfID}" | grep "spoof checking 
off"; then
     echo "spoof checking is still enabled"
     false
   fi
 
-  # Hot plug fresh device
+  # Hot plug fresh device.
   lxc config device add "${ctName}" eth1 nic \
     nictype=sriov \
     parent="${parent}" \
     security.mac_filtering=true
 
-  # Check spoof checking has been enabled
+  # Check spoof checking has been enabled.
   vfID=$(lxc config get "${ctName}" volatile.eth1.last_state.vf.id)
   if ! ip link show "${parent}" | grep "vf ${vfID}" | grep "spoof checking 
on"; then
     echo "spoof checking is still disabled"
@@ -124,11 +124,11 @@ test_container_devices_nic_sriov() {
 
   lxc stop -f "${ctName}"
 
-  # Test setting MAC offline
+  # Test setting MAC offline.
   lxc config device set "${ctName}" eth1 hwaddr "${ctMAC2}"
   lxc start "${ctName}"
 
-  # Check custom MAC is applied
+  # Check custom MAC is applied.
   vfID=$(lxc config get "${ctName}" volatile.eth1.last_state.vf.id)
   if ! ip link show "${parent}" | grep "vf ${vfID}" | grep "${ctMAC2}"; then
     echo "eth1 MAC not set"

From 5846bd8ea334c5d1ddd87f7844b035b2b34993a4 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Wed, 22 Jul 2020 08:52:56 +0100
Subject: [PATCH 7/7] test: sriov network test

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 test/suites/container_devices_nic_sriov.sh | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/test/suites/container_devices_nic_sriov.sh 
b/test/suites/container_devices_nic_sriov.sh
index 7a03f0d3af..a128404f0a 100644
--- a/test/suites/container_devices_nic_sriov.sh
+++ b/test/suites/container_devices_nic_sriov.sh
@@ -135,6 +135,28 @@ test_container_devices_nic_sriov() {
     false
   fi
 
+  lxc stop -f "${ctName}"
+  lxc config device remove "${ctName}" eth0
+  lxc config device remove "${ctName}" eth1
+
+  # Create sriov network and add NIC device using that network.
+  lxc network create "${ctName}net" --type=sriov parent="${parent}"
+  lxc config device add "${ctName}" eth0 nic \
+    network="${ctName}net" \
+    name=eth0 \
+    hwaddr="${ctMAC1}"
+  lxc start "${ctName}"
+
+  # Check custom MAC is applied.
+  vfID=$(lxc config get "${ctName}" volatile.eth0.last_state.vf.id)
+  if ! ip link show "${parent}" | grep "vf ${vfID}" | grep "${ctMAC1}"; then
+    echo "eth0 MAC not set"
+    false
+  fi
+
+  lxc config device remove "${ctName}" eth0
+  lxc network delete "${ctName}net"
+
   lxc delete -f "${ctName}"
 
   # Check we haven't left any NICS lying around.
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to