1 Star 0 Fork 28

武积超/syscontainer-tools_1

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
0006-support-ipv6.patch 51.49 KB
一键复制 编辑 原始数据 按行查看 历史
vegbir 提交于 2023-12-25 11:10 . hide error when isula info is abnormal
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085
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 := &ethDriver{
+ 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 := &ethDriver{
+ 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
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/wu-jichao123/syscontainer-tools_1.git
git@gitee.com:wu-jichao123/syscontainer-tools_1.git
wu-jichao123
syscontainer-tools_1
syscontainer-tools_1
master

搜索帮助

D67c1975 1850385 1daf7b77 1850385