summaryrefslogtreecommitdiff
path: root/vendor/github.com/vishvananda/netlink/addr_linux.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/vishvananda/netlink/addr_linux.go')
-rw-r--r--vendor/github.com/vishvananda/netlink/addr_linux.go126
1 files changed, 96 insertions, 30 deletions
diff --git a/vendor/github.com/vishvananda/netlink/addr_linux.go b/vendor/github.com/vishvananda/netlink/addr_linux.go
index f33242a7c..d59c3281e 100644
--- a/vendor/github.com/vishvananda/netlink/addr_linux.go
+++ b/vendor/github.com/vishvananda/netlink/addr_linux.go
@@ -2,13 +2,13 @@ package netlink
import (
"fmt"
- "log"
"net"
"strings"
"syscall"
"github.com/vishvananda/netlink/nl"
"github.com/vishvananda/netns"
+ "golang.org/x/sys/unix"
)
// IFA_FLAGS is a u32 attribute.
@@ -23,7 +23,7 @@ func AddrAdd(link Link, addr *Addr) error {
// AddrAdd will add an IP address to a link device.
// Equivalent to: `ip addr add $addr dev $link`
func (h *Handle) AddrAdd(link Link, addr *Addr) error {
- req := h.newNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
+ req := h.newNetlinkRequest(unix.RTM_NEWADDR, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
return h.addrHandle(link, addr, req)
}
@@ -36,7 +36,7 @@ func AddrReplace(link Link, addr *Addr) error {
// AddrReplace will replace (or, if not present, add) an IP address on a link device.
// Equivalent to: `ip addr replace $addr dev $link`
func (h *Handle) AddrReplace(link Link, addr *Addr) error {
- req := h.newNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_REPLACE|syscall.NLM_F_ACK)
+ req := h.newNetlinkRequest(unix.RTM_NEWADDR, unix.NLM_F_CREATE|unix.NLM_F_REPLACE|unix.NLM_F_ACK)
return h.addrHandle(link, addr, req)
}
@@ -49,7 +49,7 @@ func AddrDel(link Link, addr *Addr) error {
// AddrDel will delete an IP address from a link device.
// Equivalent to: `ip addr del $addr dev $link`
func (h *Handle) AddrDel(link Link, addr *Addr) error {
- req := h.newNetlinkRequest(syscall.RTM_DELADDR, syscall.NLM_F_ACK)
+ req := h.newNetlinkRequest(unix.RTM_DELADDR, unix.NLM_F_ACK)
return h.addrHandle(link, addr, req)
}
@@ -65,7 +65,7 @@ func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error
msg := nl.NewIfAddrmsg(family)
msg.Index = uint32(base.Index)
msg.Scope = uint8(addr.Scope)
- prefixlen, _ := addr.Mask.Size()
+ prefixlen, masklen := addr.Mask.Size()
msg.Prefixlen = uint8(prefixlen)
req.AddData(msg)
@@ -76,7 +76,7 @@ func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error
localAddrData = addr.IP.To16()
}
- localData := nl.NewRtAttr(syscall.IFA_LOCAL, localAddrData)
+ localData := nl.NewRtAttr(unix.IFA_LOCAL, localAddrData)
req.AddData(localData)
var peerAddrData []byte
if addr.Peer != nil {
@@ -89,7 +89,7 @@ func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error
peerAddrData = localAddrData
}
- addressData := nl.NewRtAttr(syscall.IFA_ADDRESS, peerAddrData)
+ addressData := nl.NewRtAttr(unix.IFA_ADDRESS, peerAddrData)
req.AddData(addressData)
if addr.Flags != 0 {
@@ -103,16 +103,34 @@ func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error
}
}
- if addr.Broadcast != nil {
- req.AddData(nl.NewRtAttr(syscall.IFA_BROADCAST, addr.Broadcast))
+ if family == FAMILY_V4 {
+ if addr.Broadcast == nil {
+ calcBroadcast := make(net.IP, masklen/8)
+ for i := range localAddrData {
+ calcBroadcast[i] = localAddrData[i] | ^addr.Mask[i]
+ }
+ addr.Broadcast = calcBroadcast
+ }
+ req.AddData(nl.NewRtAttr(unix.IFA_BROADCAST, addr.Broadcast))
+
+ if addr.Label != "" {
+ labelData := nl.NewRtAttr(unix.IFA_LABEL, nl.ZeroTerminated(addr.Label))
+ req.AddData(labelData)
+ }
}
- if addr.Label != "" {
- labelData := nl.NewRtAttr(syscall.IFA_LABEL, nl.ZeroTerminated(addr.Label))
- req.AddData(labelData)
+ // 0 is the default value for these attributes. However, 0 means "expired", while the least-surprising default
+ // value should be "forever". To compensate for that, only add the attributes if at least one of the values is
+ // non-zero, which means the caller has explicitly set them
+ if addr.ValidLft > 0 || addr.PreferedLft > 0 {
+ cachedata := nl.IfaCacheInfo{
+ IfaValid: uint32(addr.ValidLft),
+ IfaPrefered: uint32(addr.PreferedLft),
+ }
+ req.AddData(nl.NewRtAttr(unix.IFA_CACHEINFO, cachedata.Serialize()))
}
- _, err := req.Execute(syscall.NETLINK_ROUTE, 0)
+ _, err := req.Execute(unix.NETLINK_ROUTE, 0)
return err
}
@@ -127,11 +145,11 @@ func AddrList(link Link, family int) ([]Addr, error) {
// Equivalent to: `ip addr show`.
// The list can be filtered by link and ip family.
func (h *Handle) AddrList(link Link, family int) ([]Addr, error) {
- req := h.newNetlinkRequest(syscall.RTM_GETADDR, syscall.NLM_F_DUMP)
+ req := h.newNetlinkRequest(unix.RTM_GETADDR, unix.NLM_F_DUMP)
msg := nl.NewIfInfomsg(family)
req.AddData(msg)
- msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWADDR)
+ msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWADDR)
if err != nil {
return nil, err
}
@@ -183,21 +201,21 @@ func parseAddr(m []byte) (addr Addr, family, index int, err error) {
var local, dst *net.IPNet
for _, attr := range attrs {
switch attr.Attr.Type {
- case syscall.IFA_ADDRESS:
+ case unix.IFA_ADDRESS:
dst = &net.IPNet{
IP: attr.Value,
Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
}
addr.Peer = dst
- case syscall.IFA_LOCAL:
+ case unix.IFA_LOCAL:
local = &net.IPNet{
IP: attr.Value,
Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
}
addr.IPNet = local
- case syscall.IFA_BROADCAST:
+ case unix.IFA_BROADCAST:
addr.Broadcast = attr.Value
- case syscall.IFA_LABEL:
+ case unix.IFA_LABEL:
addr.Label = string(attr.Value[:len(attr.Value)-1])
case IFA_FLAGS:
addr.Flags = int(native.Uint32(attr.Value[0:4]))
@@ -232,17 +250,36 @@ type AddrUpdate struct {
// AddrSubscribe takes a chan down which notifications will be sent
// when addresses change. Close the 'done' chan to stop subscription.
func AddrSubscribe(ch chan<- AddrUpdate, done <-chan struct{}) error {
- return addrSubscribe(netns.None(), netns.None(), ch, done)
+ return addrSubscribeAt(netns.None(), netns.None(), ch, done, nil, false)
}
// AddrSubscribeAt works like AddrSubscribe plus it allows the caller
// to choose the network namespace in which to subscribe (ns).
func AddrSubscribeAt(ns netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}) error {
- return addrSubscribe(ns, netns.None(), ch, done)
+ return addrSubscribeAt(ns, netns.None(), ch, done, nil, false)
+}
+
+// AddrSubscribeOptions contains a set of options to use with
+// AddrSubscribeWithOptions.
+type AddrSubscribeOptions struct {
+ Namespace *netns.NsHandle
+ ErrorCallback func(error)
+ ListExisting bool
}
-func addrSubscribe(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}) error {
- s, err := nl.SubscribeAt(newNs, curNs, syscall.NETLINK_ROUTE, syscall.RTNLGRP_IPV4_IFADDR, syscall.RTNLGRP_IPV6_IFADDR)
+// AddrSubscribeWithOptions work like AddrSubscribe but enable to
+// provide additional options to modify the behavior. Currently, the
+// namespace can be provided as well as an error callback.
+func AddrSubscribeWithOptions(ch chan<- AddrUpdate, done <-chan struct{}, options AddrSubscribeOptions) error {
+ if options.Namespace == nil {
+ none := netns.None()
+ options.Namespace = &none
+ }
+ return addrSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting)
+}
+
+func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}, cberr func(error), listExisting bool) error {
+ s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_IPV4_IFADDR, unix.RTNLGRP_IPV6_IFADDR)
if err != nil {
return err
}
@@ -252,30 +289,59 @@ func addrSubscribe(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-cha
s.Close()
}()
}
+ if listExisting {
+ req := pkgHandle.newNetlinkRequest(unix.RTM_GETADDR,
+ unix.NLM_F_DUMP)
+ infmsg := nl.NewIfInfomsg(unix.AF_UNSPEC)
+ req.AddData(infmsg)
+ if err := s.Send(req); err != nil {
+ return err
+ }
+ }
go func() {
defer close(ch)
for {
msgs, err := s.Receive()
if err != nil {
- log.Printf("netlink.AddrSubscribe: Receive() error: %v", err)
+ if cberr != nil {
+ cberr(err)
+ }
return
}
for _, m := range msgs {
- msgType := m.Header.Type
- if msgType != syscall.RTM_NEWADDR && msgType != syscall.RTM_DELADDR {
- log.Printf("netlink.AddrSubscribe: bad message type: %d", msgType)
+ if m.Header.Type == unix.NLMSG_DONE {
continue
}
+ if m.Header.Type == unix.NLMSG_ERROR {
+ native := nl.NativeEndian()
+ error := int32(native.Uint32(m.Data[0:4]))
+ if error == 0 {
+ continue
+ }
+ if cberr != nil {
+ cberr(syscall.Errno(-error))
+ }
+ return
+ }
+ msgType := m.Header.Type
+ if msgType != unix.RTM_NEWADDR && msgType != unix.RTM_DELADDR {
+ if cberr != nil {
+ cberr(fmt.Errorf("bad message type: %d", msgType))
+ }
+ return
+ }
addr, _, ifindex, err := parseAddr(m.Data)
if err != nil {
- log.Printf("netlink.AddrSubscribe: could not parse address: %v", err)
- continue
+ if cberr != nil {
+ cberr(fmt.Errorf("could not parse address: %v", err))
+ }
+ return
}
ch <- AddrUpdate{LinkAddress: *addr.IPNet,
LinkIndex: ifindex,
- NewAddr: msgType == syscall.RTM_NEWADDR,
+ NewAddr: msgType == unix.RTM_NEWADDR,
Flags: addr.Flags,
Scope: addr.Scope,
PreferedLft: addr.PreferedLft,