iproute2: initial version

This commit is contained in:
Yousong Zhou
2020-01-14 18:41:04 +08:00
parent 358ce8e6e6
commit fc4189694b
5 changed files with 335 additions and 0 deletions
+122
View File
@@ -0,0 +1,122 @@
package iproute2
import (
"net"
"github.com/vishvananda/netlink"
)
type Address struct {
*Link
addrBad bool
addrs []*netlink.Addr
}
func NewAddress(ifname string, addresses ...string) *Address {
l := NewLink(ifname)
r := &Address{
Link: l,
}
addrs := make([]*netlink.Addr, len(addresses))
for i, address := range addresses {
addr, err := netlink.ParseAddr(address)
if err != nil {
r.addrBad = true
r.addErr(err, "parse addr")
}
addrs[i] = addr
}
r.addrs = addrs
return r
}
func (address *Address) link() (link netlink.Link, ok bool) {
if address.addrBad {
return
}
link = address.Link.link
if link != nil {
ok = true
}
return
}
func (address *Address) Exact() *Address {
link, ok := address.link()
if !ok {
return address
}
for _, addr := range address.addrs {
err := netlink.AddrReplace(link, addr)
if err != nil {
address.addErr(err, "Exact: AddrReplace %s", addr)
}
}
oldAddrs, err := netlink.AddrList(link, netlink.FAMILY_ALL)
if err != nil {
address.addErr(err, "Exact: AddrList")
}
for _, oldAddr := range oldAddrs {
del := true
for _, addr := range address.addrs {
if oldAddr.Equal(*addr) {
del = false
break
}
}
if del {
err := netlink.AddrDel(link, &oldAddr)
if err != nil {
address.addErr(err, "Exact: AddrDel %s", oldAddr)
}
}
}
return address
}
func (address *Address) Add() *Address {
link, ok := address.link()
if !ok {
return address
}
for _, addr := range address.addrs {
err := netlink.AddrReplace(link, addr)
if err != nil {
address.addErr(err, "Add: AddrReplace %s ", addr)
}
}
return address
}
func (address *Address) Del() *Address {
link, ok := address.link()
if !ok {
return address
}
for _, addr := range address.addrs {
err := netlink.AddrDel(link, addr)
if err != nil {
address.addErr(err, "Del: AddrDel %s ", addr)
}
}
return address
}
func (address *Address) List4() ([]net.IPNet, error) {
link, ok := address.link()
if !ok {
return nil, address.Err()
}
oldAddrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
if err != nil {
return nil, err
}
r := make([]net.IPNet, len(oldAddrs))
for i, oldAddr := range oldAddrs {
r[i] = *oldAddr.IPNet
}
return r, nil
}
+70
View File
@@ -0,0 +1,70 @@
package iproute2
import (
"testing"
)
func TestAddress(t *testing.T) {
ifname := genDummyName(t)
dum := addDummy(t, ifname)
defer delDummy(t, dum)
emptyT := func(t *testing.T) {
l := NewAddress(ifname)
l.Exact()
if err := l.Err(); err != nil {
t.Fatalf("got err: %v", err)
}
if ipnets, err := l.List4(); err != nil {
t.Fatalf("list4 err: %v", err)
} else if len(ipnets) > 0 {
t.Fatalf("want empty, got %#v", ipnets)
}
}
t.Run("exact some", func(t *testing.T) {
want := "10.168.222.236/24"
l := NewAddress(ifname, want, "fe80::222:d5ff:fe9e:28d1/64")
l.Exact()
if err := l.Err(); err != nil {
t.Fatalf("got err: %v", err)
}
if ipnets, err := l.List4(); err != nil {
t.Fatalf("list4 err: %v", err)
} else if len(ipnets) != 1 {
t.Fatalf("want 1, got %#v", ipnets)
} else if got := ipnets[0]; got.String() != want {
t.Fatalf("want %s, got %s", want, got.String())
}
t.Run("empty", emptyT)
t.Run("empty empty", emptyT)
})
}
func TestAddress_nopriv(t *testing.T) {
t.Run("bad address", func(t *testing.T) {
addresses := []string{
"192.168.2.1.1",
"192.168.2.1/33",
"192.168.2.1",
"0.0.0.0",
}
address := NewAddress("lo", addresses...)
address.Exact().Add().Del().List4()
if nerr := len(address.errs); nerr != len(addresses) {
t.Errorf("want %d err, got %d: %v ", len(addresses), nerr, address.Err())
}
})
t.Run("good address", func(t *testing.T) {
address := NewAddress("lo",
"192.168.2.1/0",
"192.168.2.1/1",
"0.0.0.0/0",
)
address.List4()
if err := address.Err(); err != nil {
t.Errorf("got err: %v", err)
}
})
}
+1
View File
@@ -0,0 +1 @@
package iproute2 // import "yunion.io/x/onecloud/pkg/util/iproute2"
+88
View File
@@ -0,0 +1,88 @@
package iproute2
import (
"net"
"github.com/vishvananda/netlink"
"yunion.io/x/pkg/errors"
)
type Link struct {
ifname string
link netlink.Link
errs []error
}
func NewLink(ifname string) *Link {
l := &Link{
ifname: ifname,
}
{
link, err := netlink.LinkByName(l.ifname)
if err != nil {
l.addErr(err, "LinkByName %s", ifname)
return l
}
l.link = link
}
return l
}
func (l *Link) addErr(err error, fmtStr string, vals ...interface{}) {
l.errs = append(l.errs, errors.Wrapf(err, fmtStr, vals...))
}
func (l *Link) Err() error {
err := errors.NewAggregate(l.errs)
if err != nil {
return errors.Wrapf(err, "Link %s", l.ifname)
}
return nil
}
func (l *Link) ResetErr() {
l.errs = nil
}
func (l *Link) Up() *Link {
if l.link != nil {
if err := netlink.LinkSetUp(l.link); err != nil {
l.addErr(err, "LinkSetUp")
}
}
return l
}
func (l *Link) Down() *Link {
if l.link != nil {
if err := netlink.LinkSetDown(l.link); err != nil {
l.addErr(err, "LinkSetDown")
}
}
return l
}
func (l *Link) MTU(mtu int) *Link {
if l.link != nil {
if err := netlink.LinkSetMTU(l.link, mtu); err != nil {
l.addErr(err, "LinkSetMTU")
}
}
return l
}
func (l *Link) Address(address string) *Link {
if l.link != nil {
hwaddr, err := net.ParseMAC(address)
if err != nil {
l.addErr(err, "bad hwaddr: %s", address)
return l
}
if err := netlink.LinkSetHardwareAddr(l.link, hwaddr); err != nil {
l.addErr(err, "LinkSetHardwareAddr")
}
}
return l
}
+54
View File
@@ -0,0 +1,54 @@
package iproute2
import (
"fmt"
"testing"
"github.com/vishvananda/netlink"
)
func genDummyName(t *testing.T) string {
for i := 0; i < 100; i++ {
name := fmt.Sprintf("dummy%d", i)
if _, err := netlink.LinkByName(name); err != nil {
return name
}
}
t.Fatalf("can't even find a dummy name")
return ""
}
func addDummy(t *testing.T, name string) *netlink.Dummy {
attrs := netlink.NewLinkAttrs()
attrs.Name = name
dum := &netlink.Dummy{
LinkAttrs: attrs,
}
if err := netlink.LinkAdd(dum); err != nil {
t.Skipf("add %s: %v", name, err)
}
return dum
}
func delDummy(t *testing.T, dum *netlink.Dummy) {
if err := netlink.LinkDel(dum); err != nil {
t.Errorf("del %s: %v", dum.Name, err)
}
}
func TestLink(t *testing.T) {
ifname := genDummyName(t)
dum := addDummy(t, ifname)
defer delDummy(t, dum)
l := NewLink(ifname)
l.Up().MTU(100).Address("00:11:22:33:44:55")
if err := l.Err(); err != nil {
t.Fatalf("got error: %v", err)
}
l.Down().MTU(120).Address("00:11:22:33:44:88")
if err := l.Err(); err != nil {
t.Fatalf("got error: %v", err)
}
}