mirror of https://github.com/vishvananda/netlink
149 lines
3.4 KiB
Go
149 lines
3.4 KiB
Go
|
package netlink
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"net"
|
||
|
"strings"
|
||
|
"syscall"
|
||
|
"unsafe"
|
||
|
)
|
||
|
|
||
|
type IfAddrmsg struct {
|
||
|
syscall.IfAddrmsg
|
||
|
}
|
||
|
|
||
|
func newIfAddrmsg(family int) *IfAddrmsg {
|
||
|
return &IfAddrmsg{
|
||
|
IfAddrmsg: syscall.IfAddrmsg{
|
||
|
Family: uint8(family),
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// struct ifaddrmsg {
|
||
|
// __u8 ifa_family;
|
||
|
// __u8 ifa_prefixlen; /* The prefix length */
|
||
|
// __u8 ifa_flags; /* Flags */
|
||
|
// __u8 ifa_scope; /* Address scope */
|
||
|
// __u32 ifa_index; /* Link index */
|
||
|
// };
|
||
|
|
||
|
// type IfAddrmsg struct {
|
||
|
// Family uint8
|
||
|
// Prefixlen uint8
|
||
|
// Flags uint8
|
||
|
// Scope uint8
|
||
|
// Index uint32
|
||
|
// }
|
||
|
// SizeofIfAddrmsg = 0x8
|
||
|
|
||
|
func DeserializeIfAddrmsg(b []byte) *IfAddrmsg {
|
||
|
return (*IfAddrmsg)(unsafe.Pointer(&b[0:syscall.SizeofIfAddrmsg][0]))
|
||
|
}
|
||
|
|
||
|
func (msg *IfAddrmsg) Serialize() []byte {
|
||
|
return (*(*[syscall.SizeofIfAddrmsg]byte)(unsafe.Pointer(msg)))[:]
|
||
|
}
|
||
|
|
||
|
func (msg *IfAddrmsg) Len() int {
|
||
|
return syscall.SizeofIfAddrmsg
|
||
|
}
|
||
|
|
||
|
// AddrAdd will add an IP address to a link device.
|
||
|
// Equivalent to: `ip addr del $addr dev $link`
|
||
|
func AddrAdd(link *Link, addr *Addr) error {
|
||
|
|
||
|
req := newNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
|
||
|
return addrHandle(link, addr, req)
|
||
|
}
|
||
|
|
||
|
// AddrDel will delete an IP address from a link device.
|
||
|
// Equivalent to: `ip addr del $addr dev $link`
|
||
|
func AddrDel(link *Link, addr *Addr) error {
|
||
|
req := newNetlinkRequest(syscall.RTM_DELADDR, syscall.NLM_F_ACK)
|
||
|
return addrHandle(link, addr, req)
|
||
|
}
|
||
|
|
||
|
func addrHandle(link *Link, addr *Addr, req *NetlinkRequest) error {
|
||
|
if addr.Label != "" && !strings.HasPrefix(addr.Label, link.Name) {
|
||
|
return fmt.Errorf("label must begin with interface name")
|
||
|
}
|
||
|
ensureIndex(link)
|
||
|
|
||
|
family := GetIPFamily(addr.IP)
|
||
|
|
||
|
msg := newIfAddrmsg(family)
|
||
|
msg.Index = uint32(link.Index)
|
||
|
prefixlen, _ := addr.Mask.Size()
|
||
|
msg.Prefixlen = uint8(prefixlen)
|
||
|
req.AddData(msg)
|
||
|
|
||
|
var addrData []byte
|
||
|
if family == FAMILY_V4 {
|
||
|
addrData = addr.IP.To4()
|
||
|
} else {
|
||
|
addrData = addr.IP.To16()
|
||
|
}
|
||
|
|
||
|
localData := newRtAttr(syscall.IFA_LOCAL, addrData)
|
||
|
req.AddData(localData)
|
||
|
|
||
|
addressData := newRtAttr(syscall.IFA_ADDRESS, addrData)
|
||
|
req.AddData(addressData)
|
||
|
|
||
|
if addr.Label != "" {
|
||
|
labelData := newRtAttr(syscall.IFA_LABEL, zeroTerminated(addr.Label))
|
||
|
req.AddData(labelData)
|
||
|
}
|
||
|
|
||
|
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// AddrList gets a list of IP addresses in the system.
|
||
|
// Equivalent to: `ip addr show`.
|
||
|
// The list can be filtered by link and ip family.
|
||
|
func AddrList(link *Link, family int) ([]Addr, error) {
|
||
|
req := newNetlinkRequest(syscall.RTM_GETADDR, syscall.NLM_F_DUMP)
|
||
|
msg := newIfInfomsg(family)
|
||
|
req.AddData(msg)
|
||
|
|
||
|
msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWADDR)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
ensureIndex(link)
|
||
|
|
||
|
res := make([]Addr, 0)
|
||
|
for _, m := range msgs {
|
||
|
msg := DeserializeIfAddrmsg(m)
|
||
|
|
||
|
if link != nil && msg.Index != uint32(link.Index) {
|
||
|
// Ignore messages from other interfaces
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
attrs, err := parseRouteAttr(m[msg.Len():])
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
var addr Addr
|
||
|
for _, attr := range attrs {
|
||
|
switch attr.Attr.Type {
|
||
|
case syscall.IFA_ADDRESS:
|
||
|
addr.IPNet = net.IPNet{
|
||
|
IP: attr.Value,
|
||
|
Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
|
||
|
}
|
||
|
case syscall.IFA_LABEL:
|
||
|
addr.Label = string(attr.Value[:len(attr.Value)-1])
|
||
|
}
|
||
|
}
|
||
|
res = append(res, addr)
|
||
|
}
|
||
|
|
||
|
return res, nil
|
||
|
}
|