Add support for the expires option of ip route

This commit is contained in:
Albert Jin
2025-05-10 17:00:23 +08:00
committed by Alessandro Boch
parent cf66e1d224
commit b032ea08ec
3 changed files with 67 additions and 1 deletions

View File

@@ -45,6 +45,17 @@ type Encap interface {
Equal(Encap) bool
}
type RouteCacheInfo struct {
Users uint32
Age uint32
Expires int32
Error uint32
Used uint32
Id uint32
Ts uint32
Tsage uint32
}
// Protocol describe what was the originator of the route
type RouteProtocol int
@@ -87,6 +98,8 @@ type Route struct {
QuickACK int
Congctl string
FastOpenNoCookie int
Expires int
CacheInfo *RouteCacheInfo
}
func (r Route) String() string {
@@ -117,6 +130,9 @@ func (r Route) String() string {
elems = append(elems, fmt.Sprintf("Flags: %s", r.ListFlags()))
elems = append(elems, fmt.Sprintf("Table: %d", r.Table))
elems = append(elems, fmt.Sprintf("Realm: %d", r.Realm))
if r.Expires != 0 {
elems = append(elems, fmt.Sprintf("Expires: %dsec", r.Expires))
}
return fmt.Sprintf("{%s}", strings.Join(elems, " "))
}

View File

@@ -1086,6 +1086,12 @@ func (h *Handle) prepareRouteReq(route *Route, req *nl.NetlinkRequest, msg *nl.R
msg.Type = uint8(route.Type)
}
if route.Expires > 0 {
b := make([]byte, 4)
native.PutUint32(b, uint32(route.Expires))
rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_EXPIRES, b))
}
var metrics []*nl.RtAttr
if route.MTU > 0 {
b := nl.Uint32Attr(uint32(route.MTU))
@@ -1320,6 +1326,25 @@ func (h *Handle) RouteListFilteredIter(family int, filter *Route, filterMask uin
return executeErr
}
// deserializeRouteCacheInfo decodes a RTA_CACHEINFO attribute into a RouteCacheInfo struct
func deserializeRouteCacheInfo(b []byte) (*RouteCacheInfo, error) {
if len(b) != 32 {
return nil, unix.EINVAL
}
e := nl.NativeEndian()
return &RouteCacheInfo{
e.Uint32(b),
e.Uint32(b[4:]),
int32(e.Uint32(b[8:])),
e.Uint32(b[12:]),
e.Uint32(b[16:]),
e.Uint32(b[20:]),
e.Uint32(b[24:]),
e.Uint32(b[28:]),
}, nil
}
// deserializeRoute decodes a binary netlink message into a Route struct
func deserializeRoute(m []byte) (Route, error) {
msg := nl.DeserializeRtMsg(m)
@@ -1363,6 +1388,12 @@ func deserializeRoute(m []byte) (Route, error) {
route.ILinkIndex = int(native.Uint32(attr.Value[0:4]))
case unix.RTA_PRIORITY:
route.Priority = int(native.Uint32(attr.Value[0:4]))
case unix.RTA_CACHEINFO:
route.CacheInfo, err = deserializeRouteCacheInfo(attr.Value)
if err != nil {
return route, err
}
route.Expires = int(route.CacheInfo.Expires) / 100
case unix.RTA_FLOW:
route.Realm = int(native.Uint32(attr.Value[0:4]))
case unix.RTA_TABLE:

View File

@@ -190,7 +190,7 @@ func TestRoute6AddDel(t *testing.T) {
IP: net.ParseIP("2001:db8::0"),
Mask: net.CIDRMask(64, 128),
}
route := Route{LinkIndex: link.Attrs().Index, Dst: dst}
route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Expires: 10}
if err := RouteAdd(&route); err != nil {
t.Fatal(err)
}
@@ -202,6 +202,25 @@ func TestRoute6AddDel(t *testing.T) {
t.Fatal("Route not added properly")
}
// route expiry is supported by kernel 4.4+
k, m, err := KernelVersion()
if err != nil {
t.Fatal(err)
}
if k > 4 || (k == 4 && m > 4) {
foundExpires := false
for _, route := range routes {
if route.Dst.IP.Equal(dst.IP) {
if route.Expires > 0 && route.Expires <= 10 {
foundExpires = true
}
}
}
if !foundExpires {
t.Fatal("Route 'expires' not set")
}
}
dstIP := net.ParseIP("2001:db8::1")
routeToDstIP, err := RouteGet(dstIP)
if err != nil {