2086 lines
52 KiB
Diff
2086 lines
52 KiB
Diff
From 9acfe3e5c2889c511d28447f1660911c4ce17cc5 Mon Sep 17 00:00:00 2001
|
|
From: vegbir <yangjiaqi16@huawei.com>
|
|
Date: Thu, 10 Aug 2023 02:44:07 +0000
|
|
Subject: [PATCH] support ipv6
|
|
|
|
Signed-off-by: vegbir <yangjiaqi16@huawei.com>
|
|
---
|
|
Makefile | 2 +-
|
|
config/config_network.go | 3 +-
|
|
libnetwork/drivers/common/driver.go | 11 +
|
|
libnetwork/drivers/common/driver_test.go | 68 +++
|
|
libnetwork/drivers/driver.go | 30 ++
|
|
libnetwork/drivers/driver_test.go | 147 +++++++
|
|
libnetwork/drivers/eth/driver.go | 59 ++-
|
|
libnetwork/drivers/eth/driver_test.go | 397 +++++++++++++++++
|
|
libnetwork/interfaces.go | 37 +-
|
|
libnetwork/interfaces_test.go | 255 +++++++++++
|
|
libnetwork/route.go | 12 -
|
|
libnetwork/route_test.go | 143 +++++++
|
|
network.go | 14 +-
|
|
types/network.go | 49 ++-
|
|
types/network_test.go | 514 +++++++++++++++++++++++
|
|
15 files changed, 1699 insertions(+), 42 deletions(-)
|
|
create mode 100644 libnetwork/drivers/common/driver_test.go
|
|
create mode 100644 libnetwork/drivers/driver_test.go
|
|
create mode 100644 libnetwork/drivers/eth/driver_test.go
|
|
create mode 100644 libnetwork/interfaces_test.go
|
|
create mode 100644 libnetwork/route_test.go
|
|
create mode 100644 types/network_test.go
|
|
|
|
diff --git a/Makefile b/Makefile
|
|
index 556382c..ede386b 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -48,7 +48,7 @@ syscontainer-hooks: $(SOURCES) | $(DEPS_LINK)
|
|
@echo "Done!"
|
|
|
|
localtest:
|
|
- ${ENV} go test -mod=vendor -tags ${TAGS} -ldflags ${GO_LDFLAGS} -v ./...
|
|
+ go test -mod=vendor -v ./...
|
|
|
|
clean:
|
|
rm -rf build
|
|
diff --git a/config/config_network.go b/config/config_network.go
|
|
index 4e0da46..1bb9c7f 100644
|
|
--- a/config/config_network.go
|
|
+++ b/config/config_network.go
|
|
@@ -15,8 +15,9 @@ package config
|
|
|
|
import (
|
|
"fmt"
|
|
- "isula.org/syscontainer-tools/types"
|
|
"path/filepath"
|
|
+
|
|
+ "isula.org/syscontainer-tools/types"
|
|
)
|
|
|
|
var (
|
|
diff --git a/libnetwork/drivers/common/driver.go b/libnetwork/drivers/common/driver.go
|
|
index c2dadd7..a2158a1 100644
|
|
--- a/libnetwork/drivers/common/driver.go
|
|
+++ b/libnetwork/drivers/common/driver.go
|
|
@@ -27,6 +27,7 @@ type Driver struct {
|
|
hostName string
|
|
mac *net.HardwareAddr
|
|
ip *net.IPNet
|
|
+ ip6 *net.IPNet
|
|
bridge string
|
|
bridgeDriver api.BridgeDriver
|
|
mtu int
|
|
@@ -73,6 +74,16 @@ func (d *Driver) GetIP() *net.IPNet {
|
|
return d.ip
|
|
}
|
|
|
|
+// SetIP6 will set the network interface ip6
|
|
+func (d *Driver) SetIP6(addr *net.IPNet) {
|
|
+ d.ip6 = addr
|
|
+}
|
|
+
|
|
+// GetIP6 will get the network interface ip6
|
|
+func (d *Driver) GetIP6() *net.IPNet {
|
|
+ return d.ip6
|
|
+}
|
|
+
|
|
// SetMac will set the network interface mac
|
|
func (d *Driver) SetMac(mac *net.HardwareAddr) {
|
|
d.mac = mac
|
|
diff --git a/libnetwork/drivers/common/driver_test.go b/libnetwork/drivers/common/driver_test.go
|
|
new file mode 100644
|
|
index 0000000..7247232
|
|
--- /dev/null
|
|
+++ b/libnetwork/drivers/common/driver_test.go
|
|
@@ -0,0 +1,68 @@
|
|
+// Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
|
|
+// syscontainer-tools licensed under the Mulan PSL v2.
|
|
+// You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
+// You may obtain a copy of Mulan PSL v2 at:
|
|
+// http://license.coscl.org.cn/MulanPSL2
|
|
+// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
|
|
+// IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
|
|
+// PURPOSE.
|
|
+// See the Mulan PSL v2 for more details.
|
|
+// Author: Jiaqi Yang
|
|
+// Date: 2023-05-03
|
|
+// Description: This file is used for test common.driver package
|
|
+
|
|
+// package common is common network driver implementation
|
|
+package common
|
|
+
|
|
+import (
|
|
+ "net"
|
|
+ "testing"
|
|
+)
|
|
+
|
|
+// TestDriver_GetAndSet tests setter & getter methods
|
|
+func TestDriver_GetAndSet(t *testing.T) {
|
|
+ type fields struct {
|
|
+ nsPath string
|
|
+ ctrName string
|
|
+ hostName string
|
|
+ mac *net.HardwareAddr
|
|
+ ip *net.IPNet
|
|
+ ip6 *net.IPNet
|
|
+ bridge string
|
|
+ mtu int
|
|
+ qlen int
|
|
+ }
|
|
+ tests := []struct {
|
|
+ name string
|
|
+ fields fields
|
|
+ }{
|
|
+ {
|
|
+ name: "TC1-sety & get sucessfully",
|
|
+ },
|
|
+ }
|
|
+ for _, tt := range tests {
|
|
+ t.Run(tt.name, func(t *testing.T) {
|
|
+ d := &Driver{}
|
|
+ d.SetIP6(tt.fields.ip6)
|
|
+ d.SetIP(tt.fields.ip)
|
|
+ d.SetBridge(tt.fields.bridge)
|
|
+ d.SetCtrNicName(tt.fields.ctrName)
|
|
+ d.SetHostNicName(tt.fields.hostName)
|
|
+ d.SetMac(tt.fields.mac)
|
|
+ d.SetMtu(tt.fields.mtu)
|
|
+ d.SetQlen(tt.fields.qlen)
|
|
+ d.SetNsPath(tt.fields.nsPath)
|
|
+
|
|
+ d.GetBridge()
|
|
+ d.GetCtrNicName()
|
|
+ d.GetHostNicName()
|
|
+ d.GetIP()
|
|
+ d.GetIP6()
|
|
+ d.GetMac()
|
|
+ d.GetMtu()
|
|
+ d.GetQlen()
|
|
+ d.GetNsPath()
|
|
+ d.GetBridgeDriver()
|
|
+ })
|
|
+ }
|
|
+}
|
|
diff --git a/libnetwork/drivers/driver.go b/libnetwork/drivers/driver.go
|
|
index a87831d..86cac7a 100644
|
|
--- a/libnetwork/drivers/driver.go
|
|
+++ b/libnetwork/drivers/driver.go
|
|
@@ -111,16 +111,46 @@ func NicOptionHostNicName(name string) DriverOptions {
|
|
func NicOptionIP(ip string) DriverOptions {
|
|
return func(d *common.Driver) error {
|
|
ip = strings.TrimSpace(ip)
|
|
+ if len(ip) == 0 {
|
|
+ return nil
|
|
+ }
|
|
+
|
|
ipnet, err := netlink.ParseIPNet(ip)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
+ if ipnet.IP.To4() == nil {
|
|
+ // fail to get ip4
|
|
+ return fmt.Errorf("ip only accepts CIDR data in ipv4 format, not %v", ipnet.String())
|
|
+ }
|
|
|
|
d.SetIP(ipnet)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
+// NicOptionIP6 handles network interface ip6 option
|
|
+func NicOptionIP6(ip6 string) DriverOptions {
|
|
+ return func(d *common.Driver) error {
|
|
+ ip6 = strings.TrimSpace(ip6)
|
|
+ if len(ip6) == 0 {
|
|
+ return nil
|
|
+ }
|
|
+
|
|
+ ipnet6, err := netlink.ParseIPNet(ip6)
|
|
+ if err != nil {
|
|
+ return err
|
|
+ }
|
|
+ if ipnet6.IP.To4() != nil {
|
|
+ // can get ip4
|
|
+ return fmt.Errorf("ip6 only accepts CIDR data in ipv6 format, not %v", ipnet6.String())
|
|
+ }
|
|
+
|
|
+ d.SetIP6(ipnet6)
|
|
+ return nil
|
|
+ }
|
|
+}
|
|
+
|
|
// NicOptionMac handles network interface mac option
|
|
func NicOptionMac(mac string) DriverOptions {
|
|
return func(d *common.Driver) error {
|
|
diff --git a/libnetwork/drivers/driver_test.go b/libnetwork/drivers/driver_test.go
|
|
new file mode 100644
|
|
index 0000000..5640130
|
|
--- /dev/null
|
|
+++ b/libnetwork/drivers/driver_test.go
|
|
@@ -0,0 +1,147 @@
|
|
+// Copyright (c) Huawei Technologies Co., Ltd. 2018-2023. All rights reserved.
|
|
+// syscontainer-tools is licensed under the Mulan PSL v2.
|
|
+// You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
+// You may obtain a copy of Mulan PSL v2 at:
|
|
+// http://license.coscl.org.cn/MulanPSL2
|
|
+// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
|
|
+// IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
|
|
+// PURPOSE.
|
|
+// See the Mulan PSL v2 for more details.
|
|
+// Description: network interface driver
|
|
+// Author: Jiaqi Yang
|
|
+// Create: 2023-04-04
|
|
+
|
|
+package drivers
|
|
+
|
|
+import (
|
|
+ "fmt"
|
|
+ "testing"
|
|
+
|
|
+ "isula.org/syscontainer-tools/types"
|
|
+)
|
|
+
|
|
+// TestNew tests New
|
|
+func TestNew(t *testing.T) {
|
|
+ const (
|
|
+ ctrNicName = "eth0"
|
|
+ hostNicName = "eth0"
|
|
+ nsPath = "/proc/1/ns/net"
|
|
+ ip = types.CIDRIpExample1
|
|
+ ip6 = types.CIDRIp6Example1
|
|
+ mac = "aa:bb:cc:dd:ee:aa"
|
|
+ mtu = 1500
|
|
+ qlen = 1000
|
|
+ bridge = ""
|
|
+ )
|
|
+ type args struct {
|
|
+ driverType string
|
|
+ options []DriverOptions
|
|
+ }
|
|
+ tests := []struct {
|
|
+ name string
|
|
+ args args
|
|
+ want Driver
|
|
+ wantErr bool
|
|
+ }{
|
|
+ {
|
|
+ name: "TC1-new eth driver success",
|
|
+ args: args{
|
|
+ driverType: "eth",
|
|
+ options: []DriverOptions{
|
|
+ NicOptionCtrNicName(ctrNicName),
|
|
+ NicOptionHostNicName(hostNicName),
|
|
+ NicOptionNsPath(nsPath),
|
|
+ NicOptionIP(ip),
|
|
+ NicOptionIP6(ip6),
|
|
+ NicOptionMac(mac),
|
|
+ NicOptionMtu(mtu),
|
|
+ NicOptionQlen(qlen),
|
|
+ NicOptionBridge(bridge),
|
|
+ },
|
|
+ },
|
|
+ wantErr: false,
|
|
+ },
|
|
+ {
|
|
+ name: "TC2-ip6 is not CIDR address",
|
|
+ args: args{
|
|
+ driverType: "eth",
|
|
+ options: []DriverOptions{
|
|
+ NicOptionCtrNicName(ctrNicName),
|
|
+ NicOptionHostNicName(hostNicName),
|
|
+ NicOptionNsPath(nsPath),
|
|
+ NicOptionIP6(mac),
|
|
+ },
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC3-ip6 is empty",
|
|
+ args: args{
|
|
+ driverType: "eth",
|
|
+ options: []DriverOptions{
|
|
+ NicOptionCtrNicName(ctrNicName),
|
|
+ NicOptionHostNicName(hostNicName),
|
|
+ NicOptionNsPath(nsPath),
|
|
+ NicOptionIP6(bridge),
|
|
+ },
|
|
+ },
|
|
+ wantErr: false,
|
|
+ },
|
|
+ {
|
|
+ name: "TC4-ip is not CIDR address",
|
|
+ args: args{
|
|
+ driverType: "eth",
|
|
+ options: []DriverOptions{
|
|
+ NicOptionCtrNicName(ctrNicName),
|
|
+ NicOptionHostNicName(hostNicName),
|
|
+ NicOptionNsPath(nsPath),
|
|
+ NicOptionIP(mac),
|
|
+ },
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC5-ip is empty",
|
|
+ args: args{
|
|
+ driverType: "eth",
|
|
+ options: []DriverOptions{
|
|
+ NicOptionCtrNicName(ctrNicName),
|
|
+ NicOptionHostNicName(hostNicName),
|
|
+ NicOptionNsPath(nsPath),
|
|
+ NicOptionIP(bridge),
|
|
+ },
|
|
+ },
|
|
+ wantErr: false,
|
|
+ },
|
|
+ {
|
|
+ name: "TC6.1-set ip6 to ip",
|
|
+ args: args{
|
|
+ driverType: "eth",
|
|
+ options: []DriverOptions{
|
|
+ NicOptionIP(ip6),
|
|
+ },
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC6.2-set ip to ip6",
|
|
+ args: args{
|
|
+ driverType: "eth",
|
|
+ options: []DriverOptions{
|
|
+ NicOptionIP6(ip),
|
|
+ },
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ }
|
|
+ for _, tt := range tests {
|
|
+ t.Run(tt.name, func(t *testing.T) {
|
|
+ _, err := New(tt.args.driverType, tt.args.options...)
|
|
+ fmt.Printf("%v\n", err)
|
|
+ if (err != nil) != tt.wantErr {
|
|
+ t.Errorf("New() error = %v, wantErr %v", err, tt.wantErr)
|
|
+ return
|
|
+ }
|
|
+ })
|
|
+ }
|
|
+}
|
|
diff --git a/libnetwork/drivers/eth/driver.go b/libnetwork/drivers/eth/driver.go
|
|
index cd70ddf..901ec9c 100644
|
|
--- a/libnetwork/drivers/eth/driver.go
|
|
+++ b/libnetwork/drivers/eth/driver.go
|
|
@@ -15,6 +15,7 @@ package eth
|
|
|
|
import (
|
|
"fmt"
|
|
+ "net"
|
|
"os"
|
|
"strings"
|
|
|
|
@@ -178,6 +179,44 @@ func (d *ethDriver) DeleteIf() (rErr error) {
|
|
return err
|
|
}
|
|
|
|
+func (d *ethDriver) setNicIP(nic netlink.Link, ipType int) error {
|
|
+ if nic == nil {
|
|
+ return fmt.Errorf("nic is nil")
|
|
+ }
|
|
+ var (
|
|
+ ipNet *net.IPNet
|
|
+ typ string
|
|
+ )
|
|
+ switch ipType {
|
|
+ case netlink.FAMILY_V4:
|
|
+ ipNet = d.GetIP()
|
|
+ typ = "ip"
|
|
+ case netlink.FAMILY_V6:
|
|
+ ipNet = d.GetIP6()
|
|
+ typ = "ip6"
|
|
+ default:
|
|
+ return fmt.Errorf("unsupported IP type")
|
|
+ }
|
|
+
|
|
+ // delete original ip/ip6 address
|
|
+ oldAddr, err := netlink.AddrList(nic, ipType)
|
|
+ if err != nil {
|
|
+ logrus.Infof("Fail to get origin %v addr: %v", typ, err)
|
|
+ }
|
|
+ if len(oldAddr) > 0 {
|
|
+ // we only have an IP set for the interface
|
|
+ if err := netlink.AddrDel(nic, &oldAddr[0]); err != nil {
|
|
+ return fmt.Errorf("failed to delete old %v address %v: %v", typ, oldAddr[0].IP, err)
|
|
+ }
|
|
+ }
|
|
+ // set new ipv4/ipv6 address
|
|
+ ipAddr := &netlink.Addr{IPNet: ipNet, Label: ""}
|
|
+ if err := netlink.AddrAdd(nic, ipAddr); err != nil {
|
|
+ return fmt.Errorf("failed to configure %v address %v: %v", typ, ipAddr, err)
|
|
+ }
|
|
+ return nil
|
|
+}
|
|
+
|
|
func (d *ethDriver) setNicConfigure(nic netlink.Link) (rErr error) {
|
|
// set MAC
|
|
if d.GetMac() != nil {
|
|
@@ -197,18 +236,18 @@ func (d *ethDriver) setNicConfigure(nic netlink.Link) (rErr error) {
|
|
return fmt.Errorf("failed to set qlen(%d) for nic(%s)", d.GetQlen(), d.GetCtrNicName())
|
|
}
|
|
|
|
- // set ipv4 address (TODO: ipv6 support?)
|
|
- oldAddr, _ := netlink.AddrList(nic, netlink.FAMILY_V4)
|
|
- if oldAddr != nil {
|
|
- // we only have on IP set for the interface
|
|
- if err := netlink.AddrDel(nic, &oldAddr[0]); err != nil {
|
|
- return fmt.Errorf("failed to delete old ip address: %v", err)
|
|
+ // set ipv4
|
|
+ if d.GetIP() != nil {
|
|
+ if err := d.setNicIP(nic, netlink.FAMILY_V4); err != nil {
|
|
+ return err
|
|
}
|
|
}
|
|
- // set ipv4 address (TODO: ipv6 support?)
|
|
- ipAddr := &netlink.Addr{IPNet: d.GetIP(), Label: ""}
|
|
- if err := netlink.AddrAdd(nic, ipAddr); err != nil {
|
|
- return fmt.Errorf("failed to configure ip address: %v", err)
|
|
+
|
|
+ // set ipv6
|
|
+ if d.GetIP6() != nil {
|
|
+ if err := d.setNicIP(nic, netlink.FAMILY_V6); err != nil {
|
|
+ return err
|
|
+ }
|
|
}
|
|
|
|
return nil
|
|
diff --git a/libnetwork/drivers/eth/driver_test.go b/libnetwork/drivers/eth/driver_test.go
|
|
new file mode 100644
|
|
index 0000000..9596a9a
|
|
--- /dev/null
|
|
+++ b/libnetwork/drivers/eth/driver_test.go
|
|
@@ -0,0 +1,397 @@
|
|
+// Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
|
|
+// syscontainer-tools is licensed under the Mulan PSL v2.
|
|
+// You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
+// You may obtain a copy of Mulan PSL v2 at:
|
|
+// http://license.coscl.org.cn/MulanPSL2
|
|
+// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
|
|
+// IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
|
|
+// PURPOSE.
|
|
+// See the Mulan PSL v2 for more details.
|
|
+// Description: ethetic network driver
|
|
+// Author: Jiaqi Yang
|
|
+// Create: 2023-05-03
|
|
+
|
|
+package eth
|
|
+
|
|
+import (
|
|
+ "fmt"
|
|
+ "io/ioutil"
|
|
+ "net"
|
|
+ "os"
|
|
+ "testing"
|
|
+
|
|
+ "github.com/vishvananda/netlink"
|
|
+
|
|
+ "isula.org/syscontainer-tools/libnetwork/drivers/common"
|
|
+ "isula.org/syscontainer-tools/types"
|
|
+)
|
|
+
|
|
+func getPhysicalNics() (map[string]struct{}, error) {
|
|
+ const (
|
|
+ allNicDir = "/sys/class/net"
|
|
+ virtualNicDir = "/sys/devices/virtual/net"
|
|
+ )
|
|
+ getFileName := func(dirName string) (map[string]struct{}, error) {
|
|
+ fis, err := ioutil.ReadDir(dirName)
|
|
+ if err != nil {
|
|
+ return nil, err
|
|
+ }
|
|
+ var fileNames = make(map[string]struct{})
|
|
+ for _, fi := range fis {
|
|
+ fileNames[fi.Name()] = struct{}{}
|
|
+ }
|
|
+ return fileNames, nil
|
|
+ }
|
|
+ allNics, err := getFileName(allNicDir)
|
|
+ if err != nil {
|
|
+ return nil, err
|
|
+ }
|
|
+ virtualNics, err := getFileName(virtualNicDir)
|
|
+ if err != nil {
|
|
+ return nil, err
|
|
+ }
|
|
+ var res = make(map[string]struct{})
|
|
+ for name := range allNics {
|
|
+ if _, ok := virtualNics[name]; !ok {
|
|
+ res[name] = struct{}{}
|
|
+ }
|
|
+ }
|
|
+ return res, nil
|
|
+}
|
|
+
|
|
+func getUnusedNic() (string, error) {
|
|
+ nicNames, err := getPhysicalNics()
|
|
+ if err != nil {
|
|
+ return "", err
|
|
+ }
|
|
+ inters, err := net.Interfaces()
|
|
+ if err != nil {
|
|
+ return "", err
|
|
+ }
|
|
+ for _, i := range inters {
|
|
+ if _, ok := nicNames[i.Name]; !ok {
|
|
+ continue
|
|
+ }
|
|
+ addrs, err := i.Addrs()
|
|
+ if err != nil {
|
|
+ fmt.Printf("%v can not get its addr: %v\n", i.Name, err)
|
|
+ continue
|
|
+ }
|
|
+ if len(addrs) > 0 {
|
|
+ continue
|
|
+ }
|
|
+ return i.Name, nil
|
|
+ }
|
|
+ return "", fmt.Errorf("can not find any unused card")
|
|
+}
|
|
+
|
|
+func getIPAddr(l netlink.Link, t int) (string, error) {
|
|
+ var typ string = "ip4"
|
|
+ if t == netlink.FAMILY_V6 {
|
|
+ typ = "ip6"
|
|
+ }
|
|
+ addrs, err := netlink.AddrList(l, t)
|
|
+ if err != nil {
|
|
+ return "", fmt.Errorf("fail to get %v: %v", typ, err)
|
|
+ }
|
|
+ if len(addrs) > 0 {
|
|
+ if typ == "ip6" {
|
|
+ return addrs[0].IP.To16().String(), nil
|
|
+ }
|
|
+ return addrs[0].IP.To4().String(), nil
|
|
+ }
|
|
+ return "", fmt.Errorf("empty %v", typ)
|
|
+}
|
|
+
|
|
+func getIp6(l netlink.Link) (string, error) {
|
|
+ return getIPAddr(l, netlink.FAMILY_V6)
|
|
+}
|
|
+
|
|
+func getIp(l netlink.Link) (string, error) {
|
|
+ return getIPAddr(l, netlink.FAMILY_V4)
|
|
+}
|
|
+
|
|
+func removeAllAddrOfNic(nicName string) {
|
|
+ rmNic := func(ip string, nic netlink.Link) {
|
|
+ ipNet, err := netlink.ParseIPNet(ip)
|
|
+ if err != nil {
|
|
+ fmt.Printf("fail to create ip: %v\n", err)
|
|
+ return
|
|
+ }
|
|
+ ipaddr := &netlink.Addr{IPNet: ipNet}
|
|
+ err = netlink.AddrDel(nic, ipaddr)
|
|
+ if err != nil {
|
|
+ fmt.Printf("fail to del ip: %v\n", err)
|
|
+ }
|
|
+ }
|
|
+
|
|
+ nic, err := netlink.LinkByName(nicName)
|
|
+ if err != nil {
|
|
+ fmt.Printf("should find nic: %v", err)
|
|
+ return
|
|
+ }
|
|
+ ip, _ := getIp(nic)
|
|
+ if ip != "" {
|
|
+ rmNic(ip+"/16", nic)
|
|
+ }
|
|
+ ip6, _ := getIp6(nic)
|
|
+ if ip6 != "" {
|
|
+ rmNic(ip6+"/64", nic)
|
|
+ }
|
|
+}
|
|
+
|
|
+func hasPerm() error {
|
|
+ filePath := "/proc/1/ns/net"
|
|
+
|
|
+ // is existed
|
|
+ fileInfo, err := os.Stat(filePath)
|
|
+ if err != nil {
|
|
+ return err
|
|
+ }
|
|
+
|
|
+ // get file info
|
|
+ fileMode := fileInfo.Mode()
|
|
+
|
|
+ // Check if the current user has permission to access the file
|
|
+ if fileMode.Perm()&(1<<(uint(7))) == 0 {
|
|
+ return fmt.Errorf("no permission to access the file")
|
|
+ }
|
|
+ return nil
|
|
+}
|
|
+
|
|
+// Test_ethDriver_setNicConfigure tests setNicConfigure of ethDriver
|
|
+func Test_ethDriver_setNicConfigure(t *testing.T) {
|
|
+ const (
|
|
+ expIP = types.CIDRIpExample1
|
|
+ expIP6 = types.CIDRIp6Example1
|
|
+ expMTU = 1500
|
|
+ expQlen = 1000
|
|
+ invalidMtu = -1
|
|
+ invalidMtu2 = 65536
|
|
+ invalidIP = "xxx"
|
|
+ )
|
|
+
|
|
+ var (
|
|
+ invalidBytes = []byte("ABCDEFG")
|
|
+ invalidMac = net.HardwareAddr(invalidBytes)
|
|
+ expIPNet, _ = netlink.ParseIPNet(expIP)
|
|
+ expIP6Net, _ = netlink.ParseIPNet(expIP6)
|
|
+ invalidIPNet = net.IPNet{IP: invalidBytes}
|
|
+ )
|
|
+ if hasPerm() != nil {
|
|
+ return
|
|
+ }
|
|
+
|
|
+ nicName, err := getUnusedNic()
|
|
+ if err != nil {
|
|
+ fmt.Printf("skip this tests: %v\n", err)
|
|
+ return
|
|
+ }
|
|
+ fmt.Printf("use nics: %v\n", nicName)
|
|
+
|
|
+ type fields struct {
|
|
+ ip *net.IPNet
|
|
+ ip6 *net.IPNet
|
|
+ mtu int
|
|
+ qlen int
|
|
+ mac *net.HardwareAddr
|
|
+ }
|
|
+ tests := []struct {
|
|
+ name string
|
|
+ fields fields
|
|
+ wantErr bool
|
|
+ post func(t *testing.T, nic netlink.Link)
|
|
+ }{
|
|
+ {
|
|
+ name: "TC1-success",
|
|
+ fields: fields{
|
|
+ ip: expIPNet,
|
|
+ ip6: expIP6Net,
|
|
+ mtu: expMTU,
|
|
+ qlen: expQlen,
|
|
+ },
|
|
+ post: func(t *testing.T, nic netlink.Link) {
|
|
+ ip, err := getIp(nic)
|
|
+ if err != nil {
|
|
+ t.Errorf("fail to get ip: %v", err)
|
|
+ }
|
|
+ ip6, err := getIp6(nic)
|
|
+ if err != nil {
|
|
+ t.Errorf("fail to get ip6: %v", err)
|
|
+ }
|
|
+ if ip+"/24" != expIP && ip6+"/64" != expIP6 {
|
|
+ t.Errorf("not same")
|
|
+ }
|
|
+ },
|
|
+ wantErr: false,
|
|
+ },
|
|
+ {
|
|
+ name: "TC2-invalid mac addr",
|
|
+ fields: fields{
|
|
+ mac: &invalidMac,
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC3-invalid MTU",
|
|
+ fields: fields{
|
|
+ mtu: invalidMtu,
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC3.1-invalid MTU",
|
|
+ fields: fields{
|
|
+ mtu: invalidMtu2,
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC4-invalid IP",
|
|
+ fields: fields{
|
|
+ mtu: expMTU,
|
|
+ qlen: expQlen,
|
|
+ ip: &invalidIPNet,
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC5-invalid IP6",
|
|
+ fields: fields{
|
|
+ mtu: expMTU,
|
|
+ qlen: expQlen,
|
|
+ ip6: &invalidIPNet,
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ }
|
|
+ for _, tt := range tests {
|
|
+ t.Run(tt.name, func(t *testing.T) {
|
|
+ d := ðDriver{
|
|
+ Driver: &common.Driver{},
|
|
+ }
|
|
+ if tt.fields.ip != nil {
|
|
+ d.SetIP(tt.fields.ip)
|
|
+ fmt.Printf("ip %v\n", tt.fields.ip)
|
|
+ }
|
|
+ if tt.fields.ip6 != nil {
|
|
+ d.SetIP6(tt.fields.ip6)
|
|
+ fmt.Printf("ip6 %v\n", tt.fields.ip6)
|
|
+ }
|
|
+
|
|
+ d.SetMtu(tt.fields.mtu)
|
|
+ d.SetQlen(tt.fields.qlen)
|
|
+ d.SetMac(tt.fields.mac)
|
|
+
|
|
+ nic, err := netlink.LinkByName(nicName)
|
|
+ if err != nil {
|
|
+ t.Errorf("should find nic: %v", err)
|
|
+ return
|
|
+ }
|
|
+ defer removeAllAddrOfNic(nicName)
|
|
+
|
|
+ if err := d.setNicConfigure(nic); (err != nil) != tt.wantErr {
|
|
+ t.Errorf("ethDriver.setNicConfigure() error = %v, wantErr %v", err, tt.wantErr)
|
|
+ }
|
|
+ if tt.post != nil {
|
|
+ tt.post(t, nic)
|
|
+ }
|
|
+ })
|
|
+ }
|
|
+}
|
|
+
|
|
+// Test_ethDriver_setNicIP tests setNicIP
|
|
+func Test_ethDriver_setNicIP(t *testing.T) {
|
|
+ const (
|
|
+ originIP = types.CIDRIpExample1
|
|
+ curIP = types.CIDRIpExample2
|
|
+ invalidTyp = 111111
|
|
+ )
|
|
+ var (
|
|
+ originIPNet, _ = netlink.ParseIPNet(originIP)
|
|
+ curIPNet, _ = netlink.ParseIPNet(curIP)
|
|
+ )
|
|
+
|
|
+ if hasPerm() != nil {
|
|
+ return
|
|
+ }
|
|
+
|
|
+ type fields struct {
|
|
+ ip *net.IPNet
|
|
+ }
|
|
+ type args struct {
|
|
+ nic netlink.Link
|
|
+ ipType int
|
|
+ }
|
|
+
|
|
+ nicName, err := getUnusedNic()
|
|
+ if err != nil {
|
|
+ fmt.Printf("skip this tests: %v\n", err)
|
|
+ return
|
|
+ }
|
|
+ fmt.Printf("use nics: %v\n", nicName)
|
|
+ nic, err := netlink.LinkByName(nicName)
|
|
+ if err != nil {
|
|
+ t.Errorf("should find nic: %v", err)
|
|
+ return
|
|
+ }
|
|
+ defer removeAllAddrOfNic(nicName)
|
|
+
|
|
+ tests := []struct {
|
|
+ name string
|
|
+ args args
|
|
+ fields fields
|
|
+ pre func(t *testing.T)
|
|
+ wantErr bool
|
|
+ }{
|
|
+ {
|
|
+ name: "TC1-invalid IPType",
|
|
+ args: args{
|
|
+ ipType: invalidTyp,
|
|
+ nic: nic,
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC2-invalid nic",
|
|
+ args: args{
|
|
+ ipType: netlink.FAMILY_V4,
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC3-delete origin ip",
|
|
+ fields: fields{
|
|
+ ip: curIPNet,
|
|
+ },
|
|
+ args: args{
|
|
+ ipType: netlink.FAMILY_V4,
|
|
+ nic: nic,
|
|
+ },
|
|
+ pre: func(t *testing.T) {
|
|
+ ipAddr := &netlink.Addr{IPNet: originIPNet, Label: ""}
|
|
+ if err := netlink.AddrAdd(nic, ipAddr); err != nil {
|
|
+ t.Errorf("failed to configure ip4 address %v: %v", ipAddr, err)
|
|
+ }
|
|
+ },
|
|
+ wantErr: false,
|
|
+ },
|
|
+ }
|
|
+
|
|
+ for _, tt := range tests {
|
|
+ t.Run(tt.name, func(t *testing.T) {
|
|
+ d := ðDriver{
|
|
+ Driver: &common.Driver{},
|
|
+ }
|
|
+ if tt.fields.ip != nil {
|
|
+ d.SetIP(tt.fields.ip)
|
|
+ }
|
|
+ if tt.pre != nil {
|
|
+ tt.pre(t)
|
|
+ }
|
|
+ if err := d.setNicIP(tt.args.nic, tt.args.ipType); (err != nil) != tt.wantErr {
|
|
+ t.Errorf("ethDriver.setNicIP() error = %v, wantErr %v", err, tt.wantErr)
|
|
+ }
|
|
+ })
|
|
+ }
|
|
+}
|
|
diff --git a/libnetwork/interfaces.go b/libnetwork/interfaces.go
|
|
index 46a51aa..121243a 100644
|
|
--- a/libnetwork/interfaces.go
|
|
+++ b/libnetwork/interfaces.go
|
|
@@ -71,6 +71,7 @@ func AddNicToContainer(nsPath string, config *types.InterfaceConf) (rErr error)
|
|
drivers.NicOptionHostNicName(config.HostNicName),
|
|
drivers.NicOptionNsPath(nsPath),
|
|
drivers.NicOptionIP(config.IP),
|
|
+ drivers.NicOptionIP6(config.IP6),
|
|
drivers.NicOptionMac(config.Mac),
|
|
drivers.NicOptionMtu(config.Mtu),
|
|
drivers.NicOptionQlen(config.Qlen),
|
|
@@ -94,6 +95,7 @@ func UpdateNicInContainer(nsPath string, config *types.InterfaceConf) (rErr erro
|
|
drivers.NicOptionHostNicName(config.HostNicName),
|
|
drivers.NicOptionNsPath(nsPath),
|
|
drivers.NicOptionIP(config.IP),
|
|
+ drivers.NicOptionIP6(config.IP6),
|
|
drivers.NicOptionMac(config.Mac),
|
|
drivers.NicOptionMtu(config.Mtu),
|
|
drivers.NicOptionQlen(config.Qlen),
|
|
@@ -151,6 +153,7 @@ func DelNicFromContainer(nsPath string, config *types.InterfaceConf) error {
|
|
drivers.NicOptionHostNicName(config.HostNicName),
|
|
drivers.NicOptionNsPath(nsPath),
|
|
drivers.NicOptionIP(config.IP),
|
|
+ drivers.NicOptionIP6(config.IP6),
|
|
drivers.NicOptionMac(config.Mac),
|
|
drivers.NicOptionMtu(config.Mtu),
|
|
drivers.NicOptionBridge(config.Bridge))
|
|
@@ -176,21 +179,29 @@ func UpdateNic(ctr *container.Container, config *types.InterfaceConf, updateConf
|
|
var tmpConfig = new(types.InterfaceConf)
|
|
tmpConfig.CtrNicName = config.CtrNicName
|
|
|
|
- var newConfig *types.InterfaceConf
|
|
- if newConfig = hConfig.FindInterfaceByName(tmpConfig); newConfig == nil {
|
|
+ var oldConfig *types.InterfaceConf
|
|
+ if oldConfig = hConfig.FindInterfaceByName(tmpConfig); oldConfig == nil {
|
|
return fmt.Errorf("Network interface %s,%s with type %s not exist in container %s", config.HostNicName, config.CtrNicName, config.Type, ctr.Name())
|
|
}
|
|
|
|
if config.IP == "" {
|
|
- tmpConfig.IP = newConfig.IP
|
|
+ tmpConfig.IP = oldConfig.IP
|
|
} else {
|
|
tmpConfig.IP = config.IP
|
|
msg := fmt.Sprintf("Update IP address for network interface (%s,%v) done", config.CtrNicName, config.IP)
|
|
fmt.Fprintln(os.Stdout, msg)
|
|
logrus.Info(msg)
|
|
}
|
|
+ if config.IP6 == "" {
|
|
+ tmpConfig.IP6 = oldConfig.IP6
|
|
+ } else {
|
|
+ tmpConfig.IP6 = config.IP6
|
|
+ msg := fmt.Sprintf("Update IP6 address for network interface (%s,%v) done", config.CtrNicName, config.IP6)
|
|
+ fmt.Fprintln(os.Stdout, msg)
|
|
+ logrus.Info(msg)
|
|
+ }
|
|
if config.Mac == "" {
|
|
- tmpConfig.Mac = newConfig.Mac
|
|
+ tmpConfig.Mac = oldConfig.Mac
|
|
} else {
|
|
tmpConfig.Mac = config.Mac
|
|
msg := fmt.Sprintf("Update MAC address for network interface (%s,%v) done", config.CtrNicName, config.Mac)
|
|
@@ -199,7 +210,7 @@ func UpdateNic(ctr *container.Container, config *types.InterfaceConf, updateConf
|
|
|
|
}
|
|
if config.Bridge == "" {
|
|
- tmpConfig.Bridge = newConfig.Bridge
|
|
+ tmpConfig.Bridge = oldConfig.Bridge
|
|
} else {
|
|
tmpConfig.Bridge = config.Bridge
|
|
msg := fmt.Sprintf("Update Bridge for network interface (%s,%v) done", config.CtrNicName, config.Bridge)
|
|
@@ -208,7 +219,7 @@ func UpdateNic(ctr *container.Container, config *types.InterfaceConf, updateConf
|
|
|
|
}
|
|
if config.Mtu == 0 {
|
|
- tmpConfig.Mtu = newConfig.Mtu
|
|
+ tmpConfig.Mtu = oldConfig.Mtu
|
|
} else {
|
|
tmpConfig.Mtu = config.Mtu
|
|
msg := fmt.Sprintf("Update Mtu for network interface (%s,%v) done", config.CtrNicName, config.Mtu)
|
|
@@ -218,26 +229,28 @@ func UpdateNic(ctr *container.Container, config *types.InterfaceConf, updateConf
|
|
}
|
|
// we use qlen < 0 to check if the user has set parameter qlen or not
|
|
if config.Qlen < 0 {
|
|
- tmpConfig.Qlen = newConfig.Qlen
|
|
+ tmpConfig.Qlen = oldConfig.Qlen
|
|
} else {
|
|
tmpConfig.Qlen = config.Qlen
|
|
msg := fmt.Sprintf("Update Qlen for network interface (%s,%v)", config.CtrNicName, config.Qlen)
|
|
fmt.Fprintln(os.Stdout, msg)
|
|
logrus.Info(msg)
|
|
}
|
|
- tmpConfig.Type = newConfig.Type
|
|
- tmpConfig.HostNicName = newConfig.HostNicName
|
|
+ tmpConfig.Type = oldConfig.Type
|
|
+ tmpConfig.HostNicName = oldConfig.HostNicName
|
|
|
|
if hConfig.IsSameInterface(tmpConfig) {
|
|
logrus.Infof("Network interface in container (%s, %s): Identical setting, nothing to change",
|
|
config.CtrNicName, ctr.Name())
|
|
return nil
|
|
}
|
|
- if err := hConfig.UpdateNetworkInterface(newConfig, false); err != nil {
|
|
+
|
|
+ if err := hConfig.UpdateNetworkInterface(oldConfig, false); err != nil {
|
|
return err
|
|
}
|
|
+
|
|
if err := hConfig.IsConflictInterface(tmpConfig); err != nil {
|
|
- if err := hConfig.UpdateNetworkInterface(newConfig, true); err != nil {
|
|
+ if err := hConfig.UpdateNetworkInterface(oldConfig, true); err != nil {
|
|
return err
|
|
}
|
|
return err
|
|
@@ -245,7 +258,7 @@ func UpdateNic(ctr *container.Container, config *types.InterfaceConf, updateConf
|
|
|
|
if !updateConfigOnly && ctr.Pid() > 0 && ctr.CheckPidExist() {
|
|
if err := UpdateNicInContainer(ctr.NetNsPath(), tmpConfig); err != nil {
|
|
- if err := hConfig.UpdateNetworkInterface(newConfig, true); err != nil {
|
|
+ if err := hConfig.UpdateNetworkInterface(oldConfig, true); err != nil {
|
|
return err
|
|
}
|
|
return err
|
|
diff --git a/libnetwork/interfaces_test.go b/libnetwork/interfaces_test.go
|
|
new file mode 100644
|
|
index 0000000..88b8e68
|
|
--- /dev/null
|
|
+++ b/libnetwork/interfaces_test.go
|
|
@@ -0,0 +1,255 @@
|
|
+// Copyright (c) Huawei Technologies Co., Ltd. 2018-2023. All rights reserved.
|
|
+// syscontainer-tools is licensed under the Mulan PSL v2.
|
|
+// You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
+// You may obtain a copy of Mulan PSL v2 at:
|
|
+// http://license.coscl.org.cn/MulanPSL2
|
|
+// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
|
|
+// IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
|
|
+// PURPOSE.
|
|
+// See the Mulan PSL v2 for more details.
|
|
+// Description: network interface operation
|
|
+// Author: Jiaqi Yang
|
|
+// Create: 2023-05-03
|
|
+
|
|
+// package libnetwork is network library
|
|
+package libnetwork
|
|
+
|
|
+import (
|
|
+ "fmt"
|
|
+ "os"
|
|
+ "os/exec"
|
|
+ "path/filepath"
|
|
+ "testing"
|
|
+
|
|
+ "isula.org/syscontainer-tools/container"
|
|
+ "isula.org/syscontainer-tools/types"
|
|
+)
|
|
+
|
|
+const (
|
|
+ ctrNicName = "ctr"
|
|
+ hostNicName = "host"
|
|
+ ip6 = types.CIDRIp6Example1
|
|
+ mtu = 1500
|
|
+ procOneNsPath = "/proc/1/ns/net"
|
|
+ nonExistBridge = "test"
|
|
+)
|
|
+
|
|
+// TestAddNicToContainer tests AddNicToContainer
|
|
+func TestAddNicToContainer(t *testing.T) {
|
|
+ type args struct {
|
|
+ nsPath string
|
|
+ config *types.InterfaceConf
|
|
+ }
|
|
+ tests := []struct {
|
|
+ name string
|
|
+ args args
|
|
+ wantErr bool
|
|
+ }{
|
|
+ {
|
|
+ name: "TC1-fail to add nic",
|
|
+ args: args{
|
|
+ nsPath: procOneNsPath,
|
|
+ config: &types.InterfaceConf{
|
|
+ CtrNicName: ctrNicName,
|
|
+ HostNicName: hostNicName,
|
|
+ IP6: ip6,
|
|
+ Mtu: mtu,
|
|
+ Bridge: nonExistBridge,
|
|
+ },
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC2-invalid IP",
|
|
+ args: args{
|
|
+ nsPath: procOneNsPath,
|
|
+ config: &types.InterfaceConf{
|
|
+ CtrNicName: ctrNicName,
|
|
+ HostNicName: hostNicName,
|
|
+ },
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ }
|
|
+ for _, tt := range tests {
|
|
+ t.Run(tt.name, func(t *testing.T) {
|
|
+ if err := AddNicToContainer(tt.args.nsPath, tt.args.config); (err != nil) != tt.wantErr {
|
|
+ t.Errorf("AddNicToContainer() error = %v, wantErr %v", err, tt.wantErr)
|
|
+ }
|
|
+ })
|
|
+ }
|
|
+}
|
|
+
|
|
+// TestUpdateNicInContainer test UpdateNicInContainer
|
|
+func TestUpdateNicInContainer(t *testing.T) {
|
|
+ type args struct {
|
|
+ nsPath string
|
|
+ config *types.InterfaceConf
|
|
+ }
|
|
+ tests := []struct {
|
|
+ name string
|
|
+ args args
|
|
+ wantErr bool
|
|
+ }{
|
|
+ {
|
|
+ name: "TC1-fail to update nic",
|
|
+ args: args{
|
|
+ nsPath: procOneNsPath,
|
|
+ config: &types.InterfaceConf{
|
|
+ CtrNicName: ctrNicName,
|
|
+ HostNicName: hostNicName,
|
|
+ IP6: ip6,
|
|
+ Mtu: mtu,
|
|
+ Bridge: nonExistBridge,
|
|
+ },
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ }
|
|
+ for _, tt := range tests {
|
|
+ t.Run(tt.name, func(t *testing.T) {
|
|
+ if err := UpdateNicInContainer(tt.args.nsPath, tt.args.config); (err != nil) != tt.wantErr {
|
|
+ t.Errorf("UpdateNicInContainer() error = %v, wantErr %v", err, tt.wantErr)
|
|
+ }
|
|
+ })
|
|
+ }
|
|
+}
|
|
+
|
|
+// TestDelNicFromContainer tests DelNicFromContainer
|
|
+func TestDelNicFromContainer(t *testing.T) {
|
|
+ type args struct {
|
|
+ nsPath string
|
|
+ config *types.InterfaceConf
|
|
+ }
|
|
+ tests := []struct {
|
|
+ name string
|
|
+ args args
|
|
+ wantErr bool
|
|
+ }{
|
|
+ {
|
|
+ name: "TC1-delete non-existed nic",
|
|
+ args: args{
|
|
+ nsPath: procOneNsPath,
|
|
+ config: &types.InterfaceConf{
|
|
+ CtrNicName: ctrNicName,
|
|
+ HostNicName: hostNicName,
|
|
+ IP6: ip6,
|
|
+ Mtu: mtu,
|
|
+ Bridge: nonExistBridge,
|
|
+ },
|
|
+ },
|
|
+ wantErr: false,
|
|
+ },
|
|
+ }
|
|
+ for _, tt := range tests {
|
|
+ t.Run(tt.name, func(t *testing.T) {
|
|
+ if err := DelNicFromContainer(tt.args.nsPath, tt.args.config); (err != nil) != tt.wantErr {
|
|
+ t.Errorf("DelNicFromContainer() error = %v, wantErr %v", err, tt.wantErr)
|
|
+ }
|
|
+ })
|
|
+ }
|
|
+}
|
|
+
|
|
+const ctrName = "ctrName"
|
|
+
|
|
+func createContainer() error {
|
|
+ const (
|
|
+ imageName = "rnd-dockerhub.huawei.com/official/ubuntu"
|
|
+ ctrCmd = "bash"
|
|
+ )
|
|
+ // cmdValue := "isula run -tid -name " + ctrName + " " + imageName + " "
|
|
+ cmd := exec.Command("isula", "run", "-tid", "--name", "ctrName", imageName, ctrCmd)
|
|
+ out, err := cmd.CombinedOutput()
|
|
+ if err != nil {
|
|
+ return fmt.Errorf("%s: %v", string(out), err)
|
|
+ }
|
|
+ return nil
|
|
+}
|
|
+
|
|
+func removeContainer() {
|
|
+ cmd := exec.Command("bash", "-c", "isula rm -f `isula ps -aq`")
|
|
+ out, err := cmd.CombinedOutput()
|
|
+ if err != nil {
|
|
+ fmt.Printf("%s: %v\n", string(out), err)
|
|
+ }
|
|
+}
|
|
+
|
|
+// TestUpdateNic tests UpdateNic
|
|
+func TestUpdateNic(t *testing.T) {
|
|
+ type args struct {
|
|
+ ctr *container.Container
|
|
+ config *types.InterfaceConf
|
|
+ updateConfigOnly bool
|
|
+ data string
|
|
+ }
|
|
+ if err := createContainer(); err != nil {
|
|
+ fmt.Printf("skip this usecase: %v\n", err)
|
|
+ return
|
|
+ }
|
|
+ ctr, err := container.New(ctrName)
|
|
+ if err != nil {
|
|
+ return
|
|
+ }
|
|
+ defer removeContainer()
|
|
+
|
|
+ const (
|
|
+ defaultConfigFile = "device_hook.json"
|
|
+ isuladPath = "/var/lib/isulad/engines/lcr"
|
|
+ filePerm = 0750
|
|
+ invalidQlen = -1
|
|
+ ip6 = "abc"
|
|
+ )
|
|
+ var (
|
|
+ data1 = "{\"networkInterfaces\":[{\"Ip\":\"\",\"Ip6\":\"\",\"Mac\":\"\",\"Mtu\":1,\"Qlen\":1," +
|
|
+ "\"Type\":\"eth\",\"Bridge\":\"\",\"HostNicName\":\"host\",\"CtrNicName\":\"ctr\"}]}"
|
|
+ )
|
|
+ ctrID := ctr.ContainerID()
|
|
+
|
|
+ if err := os.WriteFile(filepath.Join(isuladPath, ctrID, defaultConfigFile), []byte(data1), filePerm); err != nil {
|
|
+ fmt.Printf("write fail: %v\n", err)
|
|
+ return
|
|
+ }
|
|
+ tests := []struct {
|
|
+ name string
|
|
+ args args
|
|
+ wantErr bool
|
|
+ }{
|
|
+ {
|
|
+ name: "TC1-same config",
|
|
+ args: args{
|
|
+ ctr: ctr,
|
|
+ config: &types.InterfaceConf{
|
|
+ CtrNicName: ctrNicName,
|
|
+ HostNicName: hostNicName,
|
|
+ Qlen: invalidQlen,
|
|
+ },
|
|
+ data: data1,
|
|
+ },
|
|
+ wantErr: false,
|
|
+ },
|
|
+ {
|
|
+ name: "TC2-ip6 changed",
|
|
+ args: args{
|
|
+ ctr: ctr,
|
|
+ config: &types.InterfaceConf{
|
|
+ CtrNicName: ctrNicName,
|
|
+ HostNicName: hostNicName,
|
|
+ IP6: ip6,
|
|
+ },
|
|
+ data: data1,
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ }
|
|
+ for _, tt := range tests {
|
|
+ t.Run(tt.name, func(t *testing.T) {
|
|
+ if err := os.WriteFile(filepath.Join(isuladPath, ctrID, defaultConfigFile), []byte(tt.args.data), filePerm); err != nil {
|
|
+ fmt.Printf("write fail: %v\n", err)
|
|
+ return
|
|
+ }
|
|
+ if err := UpdateNic(tt.args.ctr, tt.args.config, tt.args.updateConfigOnly); (err != nil) != tt.wantErr {
|
|
+ t.Errorf("UpdateNic() error = %v, wantErr %v", err, tt.wantErr)
|
|
+ }
|
|
+ })
|
|
+ }
|
|
+}
|
|
diff --git a/libnetwork/route.go b/libnetwork/route.go
|
|
index 0be5a76..2b72c3e 100644
|
|
--- a/libnetwork/route.go
|
|
+++ b/libnetwork/route.go
|
|
@@ -92,16 +92,10 @@ func AddRouteToContainer(nsPath string, route *types.Route) error {
|
|
|
|
if len(src) != 0 {
|
|
rule.Src = net.ParseIP(src)
|
|
- if err != nil {
|
|
- return fmt.Errorf("failed to parse src ip")
|
|
- }
|
|
}
|
|
|
|
if len(gw) != 0 {
|
|
rule.Gw = net.ParseIP(gw)
|
|
- if err != nil {
|
|
- return fmt.Errorf("failed to parse gw ip")
|
|
- }
|
|
}
|
|
|
|
return nsutils.NsInvoke(nsPath,
|
|
@@ -195,16 +189,10 @@ func DelRouteFromContainer(nsPath string, route *types.Route) error {
|
|
|
|
if len(src) != 0 {
|
|
rule.Src = net.ParseIP(src)
|
|
- if err != nil {
|
|
- return fmt.Errorf("failed to parse src ip")
|
|
- }
|
|
}
|
|
|
|
if len(gw) != 0 {
|
|
rule.Gw = net.ParseIP(gw)
|
|
- if err != nil {
|
|
- return fmt.Errorf("failed to parse gw ip")
|
|
- }
|
|
}
|
|
|
|
return nsutils.NsInvoke(nsPath,
|
|
diff --git a/libnetwork/route_test.go b/libnetwork/route_test.go
|
|
new file mode 100644
|
|
index 0000000..2f8ab38
|
|
--- /dev/null
|
|
+++ b/libnetwork/route_test.go
|
|
@@ -0,0 +1,143 @@
|
|
+// Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. All rights reserved.
|
|
+// syscontainer-tools is licensed under the Mulan PSL v2.
|
|
+// You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
+// You may obtain a copy of Mulan PSL v2 at:
|
|
+// http://license.coscl.org.cn/MulanPSL2
|
|
+// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
|
|
+// IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
|
|
+// PURPOSE.
|
|
+// See the Mulan PSL v2 for more details.
|
|
+// Description: network routes operation
|
|
+// Author: zhangwei
|
|
+// Create: 2018-01-18
|
|
+
|
|
+// package libnetwork is network library
|
|
+package libnetwork
|
|
+
|
|
+import (
|
|
+ "fmt"
|
|
+ "os"
|
|
+ "testing"
|
|
+
|
|
+ "isula.org/syscontainer-tools/types"
|
|
+)
|
|
+
|
|
+func hasPerm() error {
|
|
+ filePath := "/proc/1/ns/net"
|
|
+
|
|
+ // is existed
|
|
+ fileInfo, err := os.Stat(filePath)
|
|
+ if err != nil {
|
|
+ return err
|
|
+ }
|
|
+
|
|
+ // get file info
|
|
+ fileMode := fileInfo.Mode()
|
|
+
|
|
+ // Check if the current user has permission to access the file
|
|
+ if fileMode.Perm()&(1<<(uint(7))) == 0 {
|
|
+ return fmt.Errorf("no permission to access the file")
|
|
+ }
|
|
+ return nil
|
|
+}
|
|
+
|
|
+// TestAddRouteToContainer tests AddRouteToContainer and DelRouteToContainer
|
|
+func TestAddDelRouteToContainer(t *testing.T) {
|
|
+ const (
|
|
+ normalIP = types.IPExample1
|
|
+ cidrIP = normalIP + "/16"
|
|
+ dev = "netDev"
|
|
+ )
|
|
+
|
|
+ if hasPerm() != nil {
|
|
+ return
|
|
+ }
|
|
+
|
|
+ type args struct {
|
|
+ nsPath string
|
|
+ route *types.Route
|
|
+ }
|
|
+ tests := []struct {
|
|
+ name string
|
|
+ args args
|
|
+ addWantErr bool
|
|
+ delWantErr bool
|
|
+ }{
|
|
+ {
|
|
+ name: "TC1.1-fail to parse invalaid src",
|
|
+ args: args{
|
|
+ nsPath: procOneNsPath,
|
|
+ route: &types.Route{
|
|
+ Src: cidrIP,
|
|
+ },
|
|
+ },
|
|
+ addWantErr: true,
|
|
+ delWantErr: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC1.2-fail to parse invalaid gw",
|
|
+ args: args{
|
|
+ nsPath: procOneNsPath,
|
|
+ route: &types.Route{
|
|
+ Gw: cidrIP,
|
|
+ },
|
|
+ },
|
|
+ addWantErr: true,
|
|
+ delWantErr: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC1.3-fail to parse invalid dest",
|
|
+ args: args{
|
|
+ nsPath: procOneNsPath,
|
|
+ route: &types.Route{
|
|
+ Dest: normalIP,
|
|
+ Dev: dev,
|
|
+ },
|
|
+ },
|
|
+ addWantErr: true,
|
|
+ delWantErr: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC1.4-lack of dev, gw & src",
|
|
+ args: args{
|
|
+ nsPath: procOneNsPath,
|
|
+ route: &types.Route{},
|
|
+ },
|
|
+ addWantErr: true,
|
|
+ delWantErr: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC1.5-non existed dev",
|
|
+ args: args{
|
|
+ nsPath: procOneNsPath,
|
|
+ route: &types.Route{
|
|
+ Dev: dev,
|
|
+ },
|
|
+ },
|
|
+ addWantErr: true,
|
|
+ delWantErr: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC2-default dest",
|
|
+ args: args{
|
|
+ nsPath: procOneNsPath,
|
|
+ route: &types.Route{
|
|
+ Dest: "default",
|
|
+ Gw: normalIP,
|
|
+ },
|
|
+ },
|
|
+ addWantErr: false,
|
|
+ delWantErr: false,
|
|
+ },
|
|
+ }
|
|
+ for _, tt := range tests {
|
|
+ t.Run(tt.name, func(t *testing.T) {
|
|
+ if err := AddRouteToContainer(tt.args.nsPath, tt.args.route); (err != nil) != tt.addWantErr {
|
|
+ t.Errorf("AddRouteToContainer() error = %v, wantErr %v", err, tt.addWantErr)
|
|
+ }
|
|
+ if err := DelRouteFromContainer(tt.args.nsPath, tt.args.route); (err != nil) != tt.delWantErr {
|
|
+ t.Errorf("DelRouteFromContainer() error = %v, wantErr %v", err, tt.addWantErr)
|
|
+ }
|
|
+ })
|
|
+ }
|
|
+}
|
|
diff --git a/network.go b/network.go
|
|
index e8eaa68..6e32dc4 100644
|
|
--- a/network.go
|
|
+++ b/network.go
|
|
@@ -47,7 +47,11 @@ and configure it as you wanted, then attach to specified bridge.
|
|
},
|
|
cli.StringFlag{
|
|
Name: "ip",
|
|
- Usage: "set ip address. E.g. 172.17.28.2/24",
|
|
+ Usage: "set ip address. E.g. " + types.CIDRIpExample1,
|
|
+ },
|
|
+ cli.StringFlag{
|
|
+ Name: "ip6",
|
|
+ Usage: "set ipv6 address. E.g. " + types.CIDRIp6Example1,
|
|
},
|
|
cli.StringFlag{
|
|
Name: "mac",
|
|
@@ -101,6 +105,7 @@ and configure it as you wanted, then attach to specified bridge.
|
|
|
|
nicConf := &types.InterfaceConf{
|
|
IP: context.String("ip"),
|
|
+ IP6: context.String("ip6"),
|
|
Mac: context.String("mac"),
|
|
Mtu: context.Int("mtu"),
|
|
Type: context.String("type"),
|
|
@@ -207,7 +212,11 @@ var updateNicCommand = cli.Command{
|
|
},
|
|
cli.StringFlag{
|
|
Name: "ip",
|
|
- Usage: "set ip address. E.g. 172.17.28.2/24",
|
|
+ Usage: "set ip address. E.g. " + types.CIDRIpExample1,
|
|
+ },
|
|
+ cli.StringFlag{
|
|
+ Name: "ip6",
|
|
+ Usage: "set ipv6 address. E.g. " + types.CIDRIp6Example1,
|
|
},
|
|
cli.StringFlag{
|
|
Name: "mac",
|
|
@@ -264,6 +273,7 @@ var updateNicCommand = cli.Command{
|
|
|
|
nicConf := &types.InterfaceConf{
|
|
IP: context.String("ip"),
|
|
+ IP6: context.String("ip6"),
|
|
Mac: context.String("mac"),
|
|
Mtu: context.Int("mtu"),
|
|
Bridge: context.String("bridge"),
|
|
diff --git a/types/network.go b/types/network.go
|
|
index 74231f9..524e1d5 100644
|
|
--- a/types/network.go
|
|
+++ b/types/network.go
|
|
@@ -21,6 +21,26 @@ import (
|
|
"github.com/vishvananda/netlink"
|
|
)
|
|
|
|
+const (
|
|
+ // example1 of ip address
|
|
+ IPExample1 = "172.17.28.2"
|
|
+ // example2 of ip address
|
|
+ IPExample2 = "172.17.28.3"
|
|
+ // example1 of cidr format ip address (with mask)
|
|
+ CIDRIpExample1 = IPExample1 + "/24"
|
|
+ // example2 of cidr format ip address (with mask)
|
|
+ CIDRIpExample2 = IPExample2 + "/16"
|
|
+
|
|
+ // example1 of ip6 address
|
|
+ IP6Example1 = "2001:0db8:0:f101::1"
|
|
+ // example2 of ip6 address
|
|
+ IP6Example2 = "fe80::2aee:d4ef:fe:b890"
|
|
+ // example1 of cidr format ip6 address (with mask)
|
|
+ CIDRIp6Example1 = IP6Example1 + "/64"
|
|
+ // example2 of cidr format ip6 address (with mask)
|
|
+ CIDRIp6Example2 = IP6Example2 + "/64"
|
|
+)
|
|
+
|
|
// NamespacePath namespace paths
|
|
type NamespacePath struct {
|
|
Pid string `json:"pid,omitempty"`
|
|
@@ -34,6 +54,7 @@ type NamespacePath struct {
|
|
// InterfaceConf is the network interface config
|
|
type InterfaceConf struct {
|
|
IP string `json:"Ip"`
|
|
+ IP6 string `json:"Ip6"`
|
|
Mac string `json:"Mac"`
|
|
Mtu int `json:"Mtu"`
|
|
Qlen int `json:"Qlen"`
|
|
@@ -72,9 +93,12 @@ func IsConflictNic(nic1, nic2 *InterfaceConf) error {
|
|
if nic1.Mac != "" && (nic1.Mac == nic2.Mac) {
|
|
return fmt.Errorf("interface mac conflict: %s", nic1.Mac)
|
|
}
|
|
- if nic1.IP == nic2.IP {
|
|
+ if nic1.IP != "" && nic1.IP == nic2.IP {
|
|
return fmt.Errorf("interface ip conflict: %s", nic1.IP)
|
|
}
|
|
+ if nic1.IP6 != "" && nic1.IP6 == nic2.IP6 {
|
|
+ return fmt.Errorf("interface ip6 conflict: %s", nic1.IP6)
|
|
+ }
|
|
return nil
|
|
}
|
|
|
|
@@ -83,6 +107,9 @@ func IsSameNic(obj, src *InterfaceConf) bool {
|
|
if obj.IP != src.IP && obj.IP != "" {
|
|
return false
|
|
}
|
|
+ if obj.IP6 != src.IP6 && obj.IP6 != "" {
|
|
+ return false
|
|
+ }
|
|
if obj.Mac != src.Mac && obj.Mac != "" {
|
|
return false
|
|
}
|
|
@@ -134,10 +161,24 @@ func IsSameRoute(obj, src *Route) bool {
|
|
|
|
// ValidNetworkConfig validate network config
|
|
func ValidNetworkConfig(conf *InterfaceConf) error {
|
|
- // check IP here
|
|
conf.IP = strings.TrimSpace(conf.IP)
|
|
- if _, err := netlink.ParseIPNet(conf.IP); err != nil {
|
|
- return err
|
|
+ conf.IP6 = strings.TrimSpace(conf.IP6)
|
|
+ if len(conf.IP) == 0 && len(conf.IP6) == 0 {
|
|
+ return fmt.Errorf("either ip or ipv6 must be specified")
|
|
+ }
|
|
+
|
|
+ // check IP here
|
|
+ if len(conf.IP) != 0 {
|
|
+ if _, err := netlink.ParseIPNet(conf.IP); err != nil {
|
|
+ return err
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // check IP6 here
|
|
+ if len(conf.IP6) != 0 {
|
|
+ if _, err := netlink.ParseIPNet(conf.IP6); err != nil {
|
|
+ return err
|
|
+ }
|
|
}
|
|
|
|
// Check mac here
|
|
diff --git a/types/network_test.go b/types/network_test.go
|
|
new file mode 100644
|
|
index 0000000..fecf8b6
|
|
--- /dev/null
|
|
+++ b/types/network_test.go
|
|
@@ -0,0 +1,514 @@
|
|
+// Copyright (c) Huawei Technologies Co., Ltd. 2018-2023. All rights reserved.
|
|
+// syscontainer-tools is licensed under the Mulan PSL v2.
|
|
+// You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
+// You may obtain a copy of Mulan PSL v2 at:
|
|
+// http://license.coscl.org.cn/MulanPSL2
|
|
+// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
|
|
+// IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
|
|
+// PURPOSE.
|
|
+// See the Mulan PSL v2 for more details.
|
|
+// Description: network interface type
|
|
+// Author: Jiaqi Yang
|
|
+// Create: 2023-05-03
|
|
+
|
|
+// package types defines type used by libnetwork
|
|
+package types
|
|
+
|
|
+import (
|
|
+ "testing"
|
|
+)
|
|
+
|
|
+// TestIsConflictNic tests IsConflictNic
|
|
+func TestIsConflictNic(t *testing.T) {
|
|
+ const (
|
|
+ testCtrNicName1 = "ctr1"
|
|
+ testCtrNicName2 = "ctr2"
|
|
+ testHostNicName1 = "host1"
|
|
+ testHostNicName2 = "host2"
|
|
+ testMac1 = "aa:bb:cc:dd:ee:ff"
|
|
+ testIP41 = CIDRIpExample1
|
|
+ testIP42 = CIDRIpExample2
|
|
+ testIP61 = CIDRIp6Example1
|
|
+ testIP62 = CIDRIp6Example2
|
|
+ testMTU = 1500
|
|
+ )
|
|
+ type args struct {
|
|
+ nic1 *InterfaceConf
|
|
+ nic2 *InterfaceConf
|
|
+ }
|
|
+ tests := []struct {
|
|
+ name string
|
|
+ args args
|
|
+ wantErr bool
|
|
+ }{
|
|
+ {
|
|
+ name: "TC1-same ctrName(ctrName can not be empty)",
|
|
+ args: args{
|
|
+ nic1: &InterfaceConf{
|
|
+ CtrNicName: testCtrNicName1,
|
|
+ },
|
|
+ nic2: &InterfaceConf{
|
|
+ CtrNicName: testCtrNicName1,
|
|
+ },
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC2-same hostName(hostName can not be empty)",
|
|
+ args: args{
|
|
+ nic1: &InterfaceConf{
|
|
+ CtrNicName: testCtrNicName1,
|
|
+ HostNicName: testHostNicName1,
|
|
+ },
|
|
+ nic2: &InterfaceConf{
|
|
+ CtrNicName: testCtrNicName2,
|
|
+ HostNicName: testHostNicName1,
|
|
+ },
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC3.1-same mac",
|
|
+ args: args{
|
|
+ nic1: &InterfaceConf{
|
|
+ CtrNicName: testCtrNicName1,
|
|
+ HostNicName: testHostNicName1,
|
|
+ Mac: testMac1,
|
|
+ },
|
|
+ nic2: &InterfaceConf{
|
|
+ CtrNicName: testCtrNicName2,
|
|
+ HostNicName: testHostNicName2,
|
|
+ Mac: testMac1,
|
|
+ },
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC3.2-diffrent mac address",
|
|
+ args: args{
|
|
+ nic1: &InterfaceConf{
|
|
+ CtrNicName: testCtrNicName1,
|
|
+ HostNicName: testHostNicName1,
|
|
+ Mac: testMac1,
|
|
+ },
|
|
+ nic2: &InterfaceConf{
|
|
+ CtrNicName: testCtrNicName2,
|
|
+ HostNicName: testHostNicName2,
|
|
+ },
|
|
+ },
|
|
+ wantErr: false,
|
|
+ },
|
|
+ {
|
|
+ name: "TC3.3-both not have a mac address",
|
|
+ args: args{
|
|
+ nic1: &InterfaceConf{
|
|
+ CtrNicName: testCtrNicName1,
|
|
+ HostNicName: testHostNicName1,
|
|
+ },
|
|
+ nic2: &InterfaceConf{
|
|
+ CtrNicName: testCtrNicName2,
|
|
+ HostNicName: testHostNicName2,
|
|
+ },
|
|
+ },
|
|
+ wantErr: false,
|
|
+ },
|
|
+ {
|
|
+ name: "TC4.1-smae IP4",
|
|
+ args: args{
|
|
+ nic1: &InterfaceConf{
|
|
+ CtrNicName: testCtrNicName1,
|
|
+ HostNicName: testHostNicName1,
|
|
+ IP: testIP41,
|
|
+ },
|
|
+ nic2: &InterfaceConf{
|
|
+ CtrNicName: testCtrNicName2,
|
|
+ HostNicName: testHostNicName2,
|
|
+ IP: testIP41,
|
|
+ },
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC4.2-different IP4 & not set IP6",
|
|
+ args: args{
|
|
+ nic1: &InterfaceConf{
|
|
+ CtrNicName: testCtrNicName1,
|
|
+ HostNicName: testHostNicName1,
|
|
+ IP: testIP41,
|
|
+ },
|
|
+ nic2: &InterfaceConf{
|
|
+ CtrNicName: testCtrNicName2,
|
|
+ HostNicName: testHostNicName2,
|
|
+ IP: testIP42,
|
|
+ },
|
|
+ },
|
|
+ wantErr: false,
|
|
+ },
|
|
+ {
|
|
+ name: "TC4.3-both not have a IP4 address",
|
|
+ args: args{
|
|
+ nic1: &InterfaceConf{
|
|
+ CtrNicName: testCtrNicName1,
|
|
+ HostNicName: testHostNicName1,
|
|
+ },
|
|
+ nic2: &InterfaceConf{
|
|
+ CtrNicName: testCtrNicName2,
|
|
+ HostNicName: testHostNicName2,
|
|
+ },
|
|
+ },
|
|
+ wantErr: false,
|
|
+ },
|
|
+ {
|
|
+ name: "TC5.1-smae IP6",
|
|
+ args: args{
|
|
+ nic1: &InterfaceConf{
|
|
+ CtrNicName: testCtrNicName1,
|
|
+ HostNicName: testHostNicName1,
|
|
+ IP6: testIP61,
|
|
+ },
|
|
+ nic2: &InterfaceConf{
|
|
+ CtrNicName: testCtrNicName2,
|
|
+ HostNicName: testHostNicName2,
|
|
+ IP6: testIP61,
|
|
+ },
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC5.2-different IP6",
|
|
+ args: args{
|
|
+ nic1: &InterfaceConf{
|
|
+ CtrNicName: testCtrNicName1,
|
|
+ HostNicName: testHostNicName1,
|
|
+ IP6: testIP61,
|
|
+ },
|
|
+ nic2: &InterfaceConf{
|
|
+ CtrNicName: testCtrNicName2,
|
|
+ HostNicName: testHostNicName2,
|
|
+ IP6: testIP62,
|
|
+ },
|
|
+ },
|
|
+ wantErr: false,
|
|
+ },
|
|
+ {
|
|
+ name: "TC5.3-both not have a IP6 address",
|
|
+ args: args{
|
|
+ nic1: &InterfaceConf{
|
|
+ CtrNicName: testCtrNicName1,
|
|
+ HostNicName: testHostNicName1,
|
|
+ },
|
|
+ nic2: &InterfaceConf{
|
|
+ CtrNicName: testCtrNicName2,
|
|
+ HostNicName: testHostNicName2,
|
|
+ },
|
|
+ },
|
|
+ wantErr: false,
|
|
+ },
|
|
+ }
|
|
+ for _, tt := range tests {
|
|
+ t.Run(tt.name, func(t *testing.T) {
|
|
+ if err := IsConflictNic(tt.args.nic1, tt.args.nic2); (err != nil) != tt.wantErr {
|
|
+ t.Errorf("IsConflictNic() error = %v, wantErr %v", err, tt.wantErr)
|
|
+ }
|
|
+ })
|
|
+ }
|
|
+}
|
|
+
|
|
+// TestIsSameNic tests IsSameNic
|
|
+func TestIsSameNic(t *testing.T) {
|
|
+ const (
|
|
+ testCtrNicName1 = "ctr1"
|
|
+ testCtrNicName2 = "ctr2"
|
|
+ testHostNicName1 = "host1"
|
|
+ testHostNicName2 = "host2"
|
|
+ testMac1 = "aa:bb:cc:dd:ee:ff"
|
|
+ testMac2 = "ff:ee:dd:cc:bb:aa"
|
|
+ testIP41 = CIDRIpExample1
|
|
+ testIP42 = CIDRIpExample2
|
|
+ testIP61 = CIDRIp6Example1
|
|
+ testIP62 = CIDRIp6Example2
|
|
+ testMTU1 = 1500
|
|
+ testMTU2 = 1200
|
|
+ testQlen1 = 500
|
|
+ testQlen2 = 1000
|
|
+ testBridge1 = "test1"
|
|
+ testBridge2 = "test2"
|
|
+ testType1 = "eth"
|
|
+ testType2 = "veth"
|
|
+ )
|
|
+ type args struct {
|
|
+ obj *InterfaceConf
|
|
+ src *InterfaceConf
|
|
+ }
|
|
+ tests := []struct {
|
|
+ name string
|
|
+ args args
|
|
+ want bool
|
|
+ }{
|
|
+ {
|
|
+ name: "TC1-all data is empty",
|
|
+ args: args{
|
|
+ obj: &InterfaceConf{},
|
|
+ src: &InterfaceConf{},
|
|
+ },
|
|
+ want: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC2-different IP",
|
|
+ args: args{
|
|
+ obj: &InterfaceConf{
|
|
+ IP: testIP41,
|
|
+ },
|
|
+ src: &InterfaceConf{
|
|
+ IP: testIP42,
|
|
+ },
|
|
+ },
|
|
+ want: false,
|
|
+ },
|
|
+ {
|
|
+ name: "TC3-different IP6",
|
|
+ args: args{
|
|
+ obj: &InterfaceConf{
|
|
+ IP6: testIP61,
|
|
+ },
|
|
+ src: &InterfaceConf{
|
|
+ IP6: testIP62,
|
|
+ },
|
|
+ },
|
|
+ want: false,
|
|
+ },
|
|
+ {
|
|
+ name: "TC4-different Mac",
|
|
+ args: args{
|
|
+ obj: &InterfaceConf{
|
|
+ Mac: testMac1,
|
|
+ },
|
|
+ src: &InterfaceConf{
|
|
+ Mac: testMac2,
|
|
+ },
|
|
+ },
|
|
+ want: false,
|
|
+ },
|
|
+ {
|
|
+ name: "TC5-different Mtu",
|
|
+ args: args{
|
|
+ obj: &InterfaceConf{
|
|
+ Mtu: testMTU1,
|
|
+ },
|
|
+ src: &InterfaceConf{
|
|
+ Mtu: testMTU2,
|
|
+ },
|
|
+ },
|
|
+ want: false,
|
|
+ },
|
|
+ {
|
|
+ name: "TC6-different Qlen",
|
|
+ args: args{
|
|
+ obj: &InterfaceConf{
|
|
+ Qlen: testQlen1,
|
|
+ },
|
|
+ src: &InterfaceConf{
|
|
+ Qlen: testQlen2,
|
|
+ },
|
|
+ },
|
|
+ want: false,
|
|
+ },
|
|
+ {
|
|
+ name: "TC7-different Type",
|
|
+ args: args{
|
|
+ obj: &InterfaceConf{
|
|
+ Type: testType1,
|
|
+ },
|
|
+ src: &InterfaceConf{
|
|
+ Type: testType2,
|
|
+ },
|
|
+ },
|
|
+ want: false,
|
|
+ },
|
|
+ {
|
|
+ name: "TC8-different Bridge",
|
|
+ args: args{
|
|
+ obj: &InterfaceConf{
|
|
+ Bridge: testBridge1,
|
|
+ },
|
|
+ src: &InterfaceConf{
|
|
+ Bridge: testBridge2,
|
|
+ },
|
|
+ },
|
|
+ want: false,
|
|
+ },
|
|
+ {
|
|
+ name: "TC9-different host Name",
|
|
+ args: args{
|
|
+ obj: &InterfaceConf{
|
|
+ HostNicName: testHostNicName1,
|
|
+ },
|
|
+ src: &InterfaceConf{
|
|
+ HostNicName: testHostNicName2,
|
|
+ },
|
|
+ },
|
|
+ want: false,
|
|
+ },
|
|
+ {
|
|
+ name: "TC10-different Ctr Name",
|
|
+ args: args{
|
|
+ obj: &InterfaceConf{
|
|
+ CtrNicName: testCtrNicName1,
|
|
+ },
|
|
+ src: &InterfaceConf{
|
|
+ CtrNicName: testCtrNicName2,
|
|
+ },
|
|
+ },
|
|
+ want: false,
|
|
+ },
|
|
+ }
|
|
+ for _, tt := range tests {
|
|
+ t.Run(tt.name, func(t *testing.T) {
|
|
+ if got := IsSameNic(tt.args.obj, tt.args.src); got != tt.want {
|
|
+ t.Errorf("IsSameNic() = %v, want %v", got, tt.want)
|
|
+ }
|
|
+ })
|
|
+ }
|
|
+}
|
|
+
|
|
+// TestValidNetworkConfig tests ValidNetworkConfig
|
|
+func TestValidNetworkConfig(t *testing.T) {
|
|
+ const (
|
|
+ testCtrNicName = "ctr1"
|
|
+ testHostNicName = "host1"
|
|
+ testMac1 = "aa:bb:cc:dd:ee:ff"
|
|
+ invalidMac = "ABCDEFG"
|
|
+ testIP41 = CIDRIpExample1
|
|
+ testIP42 = CIDRIpExample2
|
|
+ testIP61 = CIDRIp6Example1
|
|
+ testIP62 = CIDRIp6Example2
|
|
+ testIP4 = CIDRIpExample1
|
|
+ invalidIP4 = IPExample1
|
|
+ testIP6 = CIDRIp6Example1
|
|
+ invalidIP6 = IP6Example1
|
|
+ testBridge = "test1"
|
|
+ ethType = "eth"
|
|
+ vethType = "veth"
|
|
+ invalidType = "fake"
|
|
+ )
|
|
+ type args struct {
|
|
+ conf *InterfaceConf
|
|
+ }
|
|
+ tests := []struct {
|
|
+ name string
|
|
+ args args
|
|
+ wantErr bool
|
|
+ }{
|
|
+ {
|
|
+ name: "TC1-No IP & IP6",
|
|
+ args: args{
|
|
+ conf: &InterfaceConf{},
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC2-invalid ip",
|
|
+ args: args{
|
|
+ conf: &InterfaceConf{
|
|
+ IP: invalidIP4,
|
|
+ },
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC3-invalid ip6",
|
|
+ args: args{
|
|
+ conf: &InterfaceConf{
|
|
+ IP6: invalidIP6,
|
|
+ },
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC4-invalid Mac",
|
|
+ args: args{
|
|
+ conf: &InterfaceConf{
|
|
+ IP: testIP4,
|
|
+ Mac: invalidMac,
|
|
+ },
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC5-No such eth nic",
|
|
+ args: args{
|
|
+ conf: &InterfaceConf{
|
|
+ IP: testIP4,
|
|
+ IP6: testIP6,
|
|
+ HostNicName: testHostNicName,
|
|
+ },
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC6-veth:No host nic name is not existed",
|
|
+ args: args{
|
|
+ conf: &InterfaceConf{
|
|
+ IP: testIP4,
|
|
+ IP6: testIP6,
|
|
+ HostNicName: testHostNicName,
|
|
+ Type: vethType,
|
|
+ },
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC7-eth:empty host nic name",
|
|
+ args: args{
|
|
+ conf: &InterfaceConf{
|
|
+ IP: testIP4,
|
|
+ IP6: testIP6,
|
|
+ Type: ethType,
|
|
+ },
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC7.1-eth:empty bridge",
|
|
+ args: args{
|
|
+ conf: &InterfaceConf{
|
|
+ IP: testIP4,
|
|
+ IP6: testIP6,
|
|
+ HostNicName: testHostNicName,
|
|
+ Type: ethType,
|
|
+ },
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC7.2-eth can not find eth",
|
|
+ args: args{
|
|
+ conf: &InterfaceConf{
|
|
+ IP: testIP4,
|
|
+ IP6: testIP6,
|
|
+ HostNicName: testHostNicName,
|
|
+ Bridge: testBridge,
|
|
+ Type: ethType,
|
|
+ },
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ {
|
|
+ name: "TC8-invalid type",
|
|
+ args: args{
|
|
+ conf: &InterfaceConf{
|
|
+ IP: testIP4,
|
|
+ Type: invalidType,
|
|
+ },
|
|
+ },
|
|
+ wantErr: true,
|
|
+ },
|
|
+ }
|
|
+ for _, tt := range tests {
|
|
+ t.Run(tt.name, func(t *testing.T) {
|
|
+ if err := ValidNetworkConfig(tt.args.conf); (err != nil) != tt.wantErr {
|
|
+ t.Errorf("ValidNetworkConfig() error = %v, wantErr %v", err, tt.wantErr)
|
|
+ }
|
|
+ })
|
|
+ }
|
|
+}
|
|
--
|
|
2.41.0
|
|
|