|
@@ -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{
|
|
@@ -124,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
|
|
@@ -185,6 +186,79 @@ func (e *MPLSEncap) Equal(x Encap) bool {
|
|
|
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 {
|
|
@@ -194,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())
|
|
|
}
|
|
|
|
|
@@ -208,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())
|
|
|
}
|
|
|
|
|
@@ -222,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())
|
|
|
}
|
|
|
|
|
@@ -245,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 {
|
|
@@ -288,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 {
|
|
@@ -303,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),
|
|
@@ -323,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 {
|
|
@@ -351,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)
|
|
|
}
|
|
@@ -368,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)
|
|
@@ -380,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)
|
|
@@ -394,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
|
|
|
}
|
|
|
|
|
@@ -429,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
|
|
|
}
|
|
@@ -441,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
|
|
@@ -457,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
|
|
@@ -508,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 {
|
|
@@ -525,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
|
|
@@ -611,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]))
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -623,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
|
|
|
}
|
|
@@ -639,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
|
|
@@ -655,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
|
|
|
}
|
|
@@ -678,13 +789,13 @@ 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, nil)
|
|
|
+ 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, nil)
|
|
|
+ return routeSubscribeAt(ns, netns.None(), ch, done, nil, false)
|
|
|
}
|
|
|
|
|
|
// RouteSubscribeOptions contains a set of options to use with
|
|
@@ -692,6 +803,7 @@ func RouteSubscribeAt(ns netns.NsHandle, ch chan<- RouteUpdate, done <-chan stru
|
|
|
type RouteSubscribeOptions struct {
|
|
|
Namespace *netns.NsHandle
|
|
|
ErrorCallback func(error)
|
|
|
+ ListExisting bool
|
|
|
}
|
|
|
|
|
|
// RouteSubscribeWithOptions work like RouteSubscribe but enable to
|
|
@@ -702,11 +814,11 @@ func RouteSubscribeWithOptions(ch chan<- RouteUpdate, done <-chan struct{}, opti
|
|
|
none := netns.None()
|
|
|
options.Namespace = &none
|
|
|
}
|
|
|
- return routeSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback)
|
|
|
+ return routeSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting)
|
|
|
}
|
|
|
|
|
|
-func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <-chan struct{}, cberr func(error)) 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
|
|
|
}
|
|
@@ -716,6 +828,15 @@ 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 {
|
|
@@ -727,6 +848,20 @@ func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <
|
|
|
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 {
|