mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-19 02:37:24 +08:00
iproute2: initial version
This commit is contained in:
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package iproute2 // import "yunion.io/x/onecloud/pkg/util/iproute2"
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user