summaryrefslogtreecommitdiff
path: root/vendor/github.com/vishvananda/netlink/route_linux.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/vishvananda/netlink/route_linux.go')
-rw-r--r--vendor/github.com/vishvananda/netlink/route_linux.go338
1 files changed, 271 insertions, 67 deletions
diff --git a/vendor/github.com/vishvananda/netlink/route_linux.go b/vendor/github.com/vishvananda/netlink/route_linux.go
index cd739e714..3f856711f 100644
--- a/vendor/github.com/vishvananda/netlink/route_linux.go
+++ b/vendor/github.com/vishvananda/netlink/route_linux.go
@@ -8,16 +8,17 @@ import (
"github.com/vishvananda/netlink/nl"
"github.com/vishvananda/netns"
+ "golang.org/x/sys/unix"
)
// RtAttr is shared so it is in netlink_linux.go
const (
- SCOPE_UNIVERSE Scope = syscall.RT_SCOPE_UNIVERSE
- SCOPE_SITE Scope = syscall.RT_SCOPE_SITE
- SCOPE_LINK Scope = syscall.RT_SCOPE_LINK
- SCOPE_HOST Scope = syscall.RT_SCOPE_HOST
- SCOPE_NOWHERE Scope = syscall.RT_SCOPE_NOWHERE
+ SCOPE_UNIVERSE Scope = unix.RT_SCOPE_UNIVERSE
+ SCOPE_SITE Scope = unix.RT_SCOPE_SITE
+ SCOPE_LINK Scope = unix.RT_SCOPE_LINK
+ SCOPE_HOST Scope = unix.RT_SCOPE_HOST
+ SCOPE_NOWHERE Scope = unix.RT_SCOPE_NOWHERE
)
const (
@@ -34,8 +35,8 @@ const (
)
const (
- FLAG_ONLINK NextHopFlag = syscall.RTNH_F_ONLINK
- FLAG_PERVASIVE NextHopFlag = syscall.RTNH_F_PERVASIVE
+ FLAG_ONLINK NextHopFlag = unix.RTNH_F_ONLINK
+ FLAG_PERVASIVE NextHopFlag = unix.RTNH_F_PERVASIVE
)
var testFlags = []flagString{
@@ -86,6 +87,34 @@ func (d *MPLSDestination) String() string {
return strings.Join(s, "/")
}
+func (d *MPLSDestination) Equal(x Destination) bool {
+ o, ok := x.(*MPLSDestination)
+ if !ok {
+ return false
+ }
+ if d == nil && o == nil {
+ return true
+ }
+ if d == nil || o == nil {
+ return false
+ }
+ if d.Labels == nil && o.Labels == nil {
+ return true
+ }
+ if d.Labels == nil || o.Labels == nil {
+ return false
+ }
+ if len(d.Labels) != len(o.Labels) {
+ return false
+ }
+ for i := range d.Labels {
+ if d.Labels[i] != o.Labels[i] {
+ return false
+ }
+ }
+ return true
+}
+
type MPLSEncap struct {
Labels []int
}
@@ -96,17 +125,17 @@ func (e *MPLSEncap) Type() int {
func (e *MPLSEncap) Decode(buf []byte) error {
if len(buf) < 4 {
- return fmt.Errorf("Lack of bytes")
+ return fmt.Errorf("lack of bytes")
}
native := nl.NativeEndian()
l := native.Uint16(buf)
if len(buf) < int(l) {
- return fmt.Errorf("Lack of bytes")
+ return fmt.Errorf("lack of bytes")
}
buf = buf[:l]
typ := native.Uint16(buf[2:])
if typ != nl.MPLS_IPTUNNEL_DST {
- return fmt.Errorf("Unknown MPLS Encap Type: %d", typ)
+ return fmt.Errorf("unknown MPLS Encap Type: %d", typ)
}
e.Labels = nl.DecodeMPLSStack(buf[4:])
return nil
@@ -129,6 +158,107 @@ func (e *MPLSEncap) String() string {
return strings.Join(s, "/")
}
+func (e *MPLSEncap) Equal(x Encap) bool {
+ o, ok := x.(*MPLSEncap)
+ if !ok {
+ return false
+ }
+ if e == nil && o == nil {
+ return true
+ }
+ if e == nil || o == nil {
+ return false
+ }
+ if e.Labels == nil && o.Labels == nil {
+ return true
+ }
+ if e.Labels == nil || o.Labels == nil {
+ return false
+ }
+ if len(e.Labels) != len(o.Labels) {
+ return false
+ }
+ for i := range e.Labels {
+ if e.Labels[i] != o.Labels[i] {
+ return false
+ }
+ }
+ return true
+}
+
+// SEG6 definitions
+type SEG6Encap struct {
+ Mode int
+ Segments []net.IP
+}
+
+func (e *SEG6Encap) Type() int {
+ return nl.LWTUNNEL_ENCAP_SEG6
+}
+func (e *SEG6Encap) Decode(buf []byte) error {
+ if len(buf) < 4 {
+ return fmt.Errorf("lack of bytes")
+ }
+ native := nl.NativeEndian()
+ // Get Length(l) & Type(typ) : 2 + 2 bytes
+ l := native.Uint16(buf)
+ if len(buf) < int(l) {
+ return fmt.Errorf("lack of bytes")
+ }
+ buf = buf[:l] // make sure buf size upper limit is Length
+ typ := native.Uint16(buf[2:])
+ if typ != nl.SEG6_IPTUNNEL_SRH {
+ return fmt.Errorf("unknown SEG6 Type: %d", typ)
+ }
+
+ var err error
+ e.Mode, e.Segments, err = nl.DecodeSEG6Encap(buf[4:])
+
+ return err
+}
+func (e *SEG6Encap) Encode() ([]byte, error) {
+ s, err := nl.EncodeSEG6Encap(e.Mode, e.Segments)
+ native := nl.NativeEndian()
+ hdr := make([]byte, 4)
+ native.PutUint16(hdr, uint16(len(s)+4))
+ native.PutUint16(hdr[2:], nl.SEG6_IPTUNNEL_SRH)
+ return append(hdr, s...), err
+}
+func (e *SEG6Encap) String() string {
+ segs := make([]string, 0, len(e.Segments))
+ // append segment backwards (from n to 0) since seg#0 is the last segment.
+ for i := len(e.Segments); i > 0; i-- {
+ segs = append(segs, fmt.Sprintf("%s", e.Segments[i-1]))
+ }
+ str := fmt.Sprintf("mode %s segs %d [ %s ]", nl.SEG6EncapModeString(e.Mode),
+ len(e.Segments), strings.Join(segs, " "))
+ return str
+}
+func (e *SEG6Encap) Equal(x Encap) bool {
+ o, ok := x.(*SEG6Encap)
+ if !ok {
+ return false
+ }
+ if e == o {
+ return true
+ }
+ if e == nil || o == nil {
+ return false
+ }
+ if e.Mode != o.Mode {
+ return false
+ }
+ if len(e.Segments) != len(o.Segments) {
+ return false
+ }
+ for i := range e.Segments {
+ if !e.Segments[i].Equal(o.Segments[i]) {
+ return false
+ }
+ }
+ return true
+}
+
// RouteAdd will add a route to the system.
// Equivalent to: `ip route add $route`
func RouteAdd(route *Route) error {
@@ -138,8 +268,8 @@ func RouteAdd(route *Route) error {
// RouteAdd will add a route to the system.
// Equivalent to: `ip route add $route`
func (h *Handle) RouteAdd(route *Route) error {
- flags := syscall.NLM_F_CREATE | syscall.NLM_F_EXCL | syscall.NLM_F_ACK
- req := h.newNetlinkRequest(syscall.RTM_NEWROUTE, flags)
+ flags := unix.NLM_F_CREATE | unix.NLM_F_EXCL | unix.NLM_F_ACK
+ req := h.newNetlinkRequest(unix.RTM_NEWROUTE, flags)
return h.routeHandle(route, req, nl.NewRtMsg())
}
@@ -152,8 +282,8 @@ func RouteReplace(route *Route) error {
// RouteReplace will add a route to the system.
// Equivalent to: `ip route replace $route`
func (h *Handle) RouteReplace(route *Route) error {
- flags := syscall.NLM_F_CREATE | syscall.NLM_F_REPLACE | syscall.NLM_F_ACK
- req := h.newNetlinkRequest(syscall.RTM_NEWROUTE, flags)
+ flags := unix.NLM_F_CREATE | unix.NLM_F_REPLACE | unix.NLM_F_ACK
+ req := h.newNetlinkRequest(unix.RTM_NEWROUTE, flags)
return h.routeHandle(route, req, nl.NewRtMsg())
}
@@ -166,7 +296,7 @@ func RouteDel(route *Route) error {
// RouteDel will delete a route from the system.
// Equivalent to: `ip route del $route`
func (h *Handle) RouteDel(route *Route) error {
- req := h.newNetlinkRequest(syscall.RTM_DELROUTE, syscall.NLM_F_ACK)
+ req := h.newNetlinkRequest(unix.RTM_DELROUTE, unix.NLM_F_ACK)
return h.routeHandle(route, req, nl.NewRtDelMsg())
}
@@ -189,12 +319,12 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
} else {
dstData = route.Dst.IP.To16()
}
- rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_DST, dstData))
+ rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_DST, dstData))
} else if route.MPLSDst != nil {
family = nl.FAMILY_MPLS
msg.Dst_len = uint8(20)
- msg.Type = syscall.RTN_UNICAST
- rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_DST, nl.EncodeMPLSStack(*route.MPLSDst)))
+ msg.Type = unix.RTN_UNICAST
+ rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_DST, nl.EncodeMPLSStack(*route.MPLSDst)))
}
if route.NewDst != nil {
@@ -232,7 +362,7 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
srcData = route.Src.To16()
}
// The commonly used src ip for routes is actually PREFSRC
- rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_PREFSRC, srcData))
+ rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_PREFSRC, srcData))
}
if route.Gw != nil {
@@ -247,14 +377,14 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
} else {
gwData = route.Gw.To16()
}
- rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_GATEWAY, gwData))
+ rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_GATEWAY, gwData))
}
if len(route.MultiPath) > 0 {
buf := []byte{}
for _, nh := range route.MultiPath {
rtnh := &nl.RtNexthop{
- RtNexthop: syscall.RtNexthop{
+ RtNexthop: unix.RtNexthop{
Hops: uint8(nh.Hops),
Ifindex: int32(nh.LinkIndex),
Flags: uint8(nh.Flags),
@@ -267,9 +397,9 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
return fmt.Errorf("gateway, source, and destination ip are not the same IP family")
}
if gwFamily == FAMILY_V4 {
- children = append(children, nl.NewRtAttr(syscall.RTA_GATEWAY, []byte(nh.Gw.To4())))
+ children = append(children, nl.NewRtAttr(unix.RTA_GATEWAY, []byte(nh.Gw.To4())))
} else {
- children = append(children, nl.NewRtAttr(syscall.RTA_GATEWAY, []byte(nh.Gw.To16())))
+ children = append(children, nl.NewRtAttr(unix.RTA_GATEWAY, []byte(nh.Gw.To16())))
}
}
if nh.NewDst != nil {
@@ -295,15 +425,15 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
rtnh.Children = children
buf = append(buf, rtnh.Serialize()...)
}
- rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_MULTIPATH, buf))
+ rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_MULTIPATH, buf))
}
if route.Table > 0 {
if route.Table >= 256 {
- msg.Table = syscall.RT_TABLE_UNSPEC
+ msg.Table = unix.RT_TABLE_UNSPEC
b := make([]byte, 4)
native.PutUint32(b, uint32(route.Table))
- rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_TABLE, b))
+ rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_TABLE, b))
} else {
msg.Table = uint8(route.Table)
}
@@ -312,7 +442,7 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
if route.Priority > 0 {
b := make([]byte, 4)
native.PutUint32(b, uint32(route.Priority))
- rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_PRIORITY, b))
+ rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_PRIORITY, b))
}
if route.Tos > 0 {
msg.Tos = uint8(route.Tos)
@@ -324,6 +454,25 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
msg.Type = uint8(route.Type)
}
+ var metrics []*nl.RtAttr
+ // TODO: support other rta_metric values
+ if route.MTU > 0 {
+ b := nl.Uint32Attr(uint32(route.MTU))
+ metrics = append(metrics, nl.NewRtAttr(unix.RTAX_MTU, b))
+ }
+ if route.AdvMSS > 0 {
+ b := nl.Uint32Attr(uint32(route.AdvMSS))
+ metrics = append(metrics, nl.NewRtAttr(unix.RTAX_ADVMSS, b))
+ }
+
+ if metrics != nil {
+ attr := nl.NewRtAttr(unix.RTA_METRICS, nil)
+ for _, metric := range metrics {
+ attr.AddChild(metric)
+ }
+ rtAttrs = append(rtAttrs, attr)
+ }
+
msg.Flags = uint32(route.Flags)
msg.Scope = uint8(route.Scope)
msg.Family = uint8(family)
@@ -338,9 +487,9 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
)
native.PutUint32(b, uint32(route.LinkIndex))
- req.AddData(nl.NewRtAttr(syscall.RTA_OIF, b))
+ req.AddData(nl.NewRtAttr(unix.RTA_OIF, b))
- _, err := req.Execute(syscall.NETLINK_ROUTE, 0)
+ _, err := req.Execute(unix.NETLINK_ROUTE, 0)
return err
}
@@ -373,11 +522,11 @@ func RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, e
// RouteListFiltered gets a list of routes in the system filtered with specified rules.
// All rules must be defined in RouteFilter struct
func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, error) {
- req := h.newNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_DUMP)
+ req := h.newNetlinkRequest(unix.RTM_GETROUTE, unix.NLM_F_DUMP)
infmsg := nl.NewIfInfomsg(family)
req.AddData(infmsg)
- msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWROUTE)
+ msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWROUTE)
if err != nil {
return nil, err
}
@@ -385,11 +534,11 @@ func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64)
var res []Route
for _, m := range msgs {
msg := nl.DeserializeRtMsg(m)
- if msg.Flags&syscall.RTM_F_CLONED != 0 {
+ if msg.Flags&unix.RTM_F_CLONED != 0 {
// Ignore cloned routes
continue
}
- if msg.Table != syscall.RT_TABLE_MAIN {
+ if msg.Table != unix.RT_TABLE_MAIN {
if filter == nil || filter != nil && filterMask&RT_FILTER_TABLE == 0 {
// Ignore non-main tables
continue
@@ -401,7 +550,7 @@ func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64)
}
if filter != nil {
switch {
- case filterMask&RT_FILTER_TABLE != 0 && filter.Table != syscall.RT_TABLE_UNSPEC && route.Table != filter.Table:
+ case filterMask&RT_FILTER_TABLE != 0 && filter.Table != unix.RT_TABLE_UNSPEC && route.Table != filter.Table:
continue
case filterMask&RT_FILTER_PROTOCOL != 0 && route.Protocol != filter.Protocol:
continue
@@ -421,19 +570,8 @@ func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64)
continue
case filterMask&RT_FILTER_DST != 0:
if filter.MPLSDst == nil || route.MPLSDst == nil || (*filter.MPLSDst) != (*route.MPLSDst) {
- if filter.Dst == nil {
- if route.Dst != nil {
- continue
- }
- } else {
- if route.Dst == nil {
- continue
- }
- aMaskLen, aMaskBits := route.Dst.Mask.Size()
- bMaskLen, bMaskBits := filter.Dst.Mask.Size()
- if !(route.Dst.IP.Equal(filter.Dst.IP) && aMaskLen == bMaskLen && aMaskBits == bMaskBits) {
- continue
- }
+ if !ipNetEqual(route.Dst, filter.Dst) {
+ continue
}
}
}
@@ -463,11 +601,11 @@ func deserializeRoute(m []byte) (Route, error) {
var encap, encapType syscall.NetlinkRouteAttr
for _, attr := range attrs {
switch attr.Attr.Type {
- case syscall.RTA_GATEWAY:
+ case unix.RTA_GATEWAY:
route.Gw = net.IP(attr.Value)
- case syscall.RTA_PREFSRC:
+ case unix.RTA_PREFSRC:
route.Src = net.IP(attr.Value)
- case syscall.RTA_DST:
+ case unix.RTA_DST:
if msg.Family == nl.FAMILY_MPLS {
stack := nl.DecodeMPLSStack(attr.Value)
if len(stack) == 0 || len(stack) > 1 {
@@ -480,36 +618,36 @@ func deserializeRoute(m []byte) (Route, error) {
Mask: net.CIDRMask(int(msg.Dst_len), 8*len(attr.Value)),
}
}
- case syscall.RTA_OIF:
+ case unix.RTA_OIF:
route.LinkIndex = int(native.Uint32(attr.Value[0:4]))
- case syscall.RTA_IIF:
+ case unix.RTA_IIF:
route.ILinkIndex = int(native.Uint32(attr.Value[0:4]))
- case syscall.RTA_PRIORITY:
+ case unix.RTA_PRIORITY:
route.Priority = int(native.Uint32(attr.Value[0:4]))
- case syscall.RTA_TABLE:
+ case unix.RTA_TABLE:
route.Table = int(native.Uint32(attr.Value[0:4]))
- case syscall.RTA_MULTIPATH:
+ case unix.RTA_MULTIPATH:
parseRtNexthop := func(value []byte) (*NexthopInfo, []byte, error) {
- if len(value) < syscall.SizeofRtNexthop {
- return nil, nil, fmt.Errorf("Lack of bytes")
+ if len(value) < unix.SizeofRtNexthop {
+ return nil, nil, fmt.Errorf("lack of bytes")
}
nh := nl.DeserializeRtNexthop(value)
if len(value) < int(nh.RtNexthop.Len) {
- return nil, nil, fmt.Errorf("Lack of bytes")
+ return nil, nil, fmt.Errorf("lack of bytes")
}
info := &NexthopInfo{
LinkIndex: int(nh.RtNexthop.Ifindex),
Hops: int(nh.RtNexthop.Hops),
Flags: int(nh.RtNexthop.Flags),
}
- attrs, err := nl.ParseRouteAttr(value[syscall.SizeofRtNexthop:int(nh.RtNexthop.Len)])
+ attrs, err := nl.ParseRouteAttr(value[unix.SizeofRtNexthop:int(nh.RtNexthop.Len)])
if err != nil {
return nil, nil, err
}
var encap, encapType syscall.NetlinkRouteAttr
for _, attr := range attrs {
switch attr.Attr.Type {
- case syscall.RTA_GATEWAY:
+ case unix.RTA_GATEWAY:
info.Gw = net.IP(attr.Value)
case nl.RTA_NEWDST:
var d Destination
@@ -566,6 +704,19 @@ func deserializeRoute(m []byte) (Route, error) {
encapType = attr
case nl.RTA_ENCAP:
encap = attr
+ case unix.RTA_METRICS:
+ metrics, err := nl.ParseRouteAttr(attr.Value)
+ if err != nil {
+ return route, err
+ }
+ for _, metric := range metrics {
+ switch metric.Attr.Type {
+ case unix.RTAX_MTU:
+ route.MTU = int(native.Uint32(metric.Value[0:4]))
+ case unix.RTAX_ADVMSS:
+ route.AdvMSS = int(native.Uint32(metric.Value[0:4]))
+ }
+ }
}
}
@@ -578,6 +729,11 @@ func deserializeRoute(m []byte) (Route, error) {
if err := e.Decode(encap.Value); err != nil {
return route, err
}
+ case nl.LWTUNNEL_ENCAP_SEG6:
+ e = &SEG6Encap{}
+ if err := e.Decode(encap.Value); err != nil {
+ return route, err
+ }
}
route.Encap = e
}
@@ -594,7 +750,7 @@ func RouteGet(destination net.IP) ([]Route, error) {
// RouteGet gets a route to a specific destination from the host system.
// Equivalent to: 'ip route get'.
func (h *Handle) RouteGet(destination net.IP) ([]Route, error) {
- req := h.newNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_REQUEST)
+ req := h.newNetlinkRequest(unix.RTM_GETROUTE, unix.NLM_F_REQUEST)
family := nl.GetIPFamily(destination)
var destinationData []byte
var bitlen uint8
@@ -610,10 +766,10 @@ func (h *Handle) RouteGet(destination net.IP) ([]Route, error) {
msg.Dst_len = bitlen
req.AddData(msg)
- rtaDst := nl.NewRtAttr(syscall.RTA_DST, destinationData)
+ rtaDst := nl.NewRtAttr(unix.RTA_DST, destinationData)
req.AddData(rtaDst)
- msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWROUTE)
+ msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWROUTE)
if err != nil {
return nil, err
}
@@ -633,17 +789,36 @@ func (h *Handle) RouteGet(destination net.IP) ([]Route, error) {
// RouteSubscribe takes a chan down which notifications will be sent
// when routes are added or deleted. Close the 'done' chan to stop subscription.
func RouteSubscribe(ch chan<- RouteUpdate, done <-chan struct{}) error {
- return routeSubscribeAt(netns.None(), netns.None(), ch, done)
+ return routeSubscribeAt(netns.None(), netns.None(), ch, done, nil, false)
}
// RouteSubscribeAt works like RouteSubscribe plus it allows the caller
// to choose the network namespace in which to subscribe (ns).
func RouteSubscribeAt(ns netns.NsHandle, ch chan<- RouteUpdate, done <-chan struct{}) error {
- return routeSubscribeAt(ns, netns.None(), ch, done)
+ return routeSubscribeAt(ns, netns.None(), ch, done, nil, false)
+}
+
+// RouteSubscribeOptions contains a set of options to use with
+// RouteSubscribeWithOptions.
+type RouteSubscribeOptions struct {
+ Namespace *netns.NsHandle
+ ErrorCallback func(error)
+ ListExisting bool
+}
+
+// RouteSubscribeWithOptions work like RouteSubscribe but enable to
+// provide additional options to modify the behavior. Currently, the
+// namespace can be provided as well as an error callback.
+func RouteSubscribeWithOptions(ch chan<- RouteUpdate, done <-chan struct{}, options RouteSubscribeOptions) error {
+ if options.Namespace == nil {
+ none := netns.None()
+ options.Namespace = &none
+ }
+ return routeSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting)
}
-func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <-chan struct{}) error {
- s, err := nl.SubscribeAt(newNs, curNs, syscall.NETLINK_ROUTE, syscall.RTNLGRP_IPV4_ROUTE, syscall.RTNLGRP_IPV6_ROUTE)
+func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <-chan struct{}, cberr func(error), listExisting bool) error {
+ s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_IPV4_ROUTE, unix.RTNLGRP_IPV6_ROUTE)
if err != nil {
return err
}
@@ -653,16 +828,45 @@ func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <
s.Close()
}()
}
+ if listExisting {
+ req := pkgHandle.newNetlinkRequest(unix.RTM_GETROUTE,
+ 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 {
+ if cberr != nil {
+ cberr(err)
+ }
return
}
for _, m := range msgs {
+ 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
+ }
route, err := deserializeRoute(m.Data)
if err != nil {
+ if cberr != nil {
+ cberr(err)
+ }
return
}
ch <- RouteUpdate{Type: m.Header.Type, Route: route}