Skip to content

Commit 1e6be0f

Browse files
committed
Add support for the expires option of ip route
1 parent 17daef6 commit 1e6be0f

File tree

3 files changed

+67
-1
lines changed

3 files changed

+67
-1
lines changed

route.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,17 @@ type Encap interface {
4545
Equal(Encap) bool
4646
}
4747

48+
type RouteCacheInfo struct {
49+
Users uint32
50+
Age uint32
51+
Expires int32
52+
Error uint32
53+
Used uint32
54+
Id uint32
55+
Ts uint32
56+
Tsage uint32
57+
}
58+
4859
// Protocol describe what was the originator of the route
4960
type RouteProtocol int
5061

@@ -87,6 +98,8 @@ type Route struct {
8798
QuickACK int
8899
Congctl string
89100
FastOpenNoCookie int
101+
Expires int
102+
CacheInfo *RouteCacheInfo
90103
}
91104

92105
func (r Route) String() string {
@@ -117,6 +130,9 @@ func (r Route) String() string {
117130
elems = append(elems, fmt.Sprintf("Flags: %s", r.ListFlags()))
118131
elems = append(elems, fmt.Sprintf("Table: %d", r.Table))
119132
elems = append(elems, fmt.Sprintf("Realm: %d", r.Realm))
133+
if r.Expires != 0 {
134+
elems = append(elems, fmt.Sprintf("Expires: %dsec", r.Expires))
135+
}
120136
return fmt.Sprintf("{%s}", strings.Join(elems, " "))
121137
}
122138

route_linux.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,6 +1086,12 @@ func (h *Handle) prepareRouteReq(route *Route, req *nl.NetlinkRequest, msg *nl.R
10861086
msg.Type = uint8(route.Type)
10871087
}
10881088

1089+
if route.Expires > 0 {
1090+
b := make([]byte, 4)
1091+
native.PutUint32(b, uint32(route.Expires))
1092+
rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_EXPIRES, b))
1093+
}
1094+
10891095
var metrics []*nl.RtAttr
10901096
if route.MTU > 0 {
10911097
b := nl.Uint32Attr(uint32(route.MTU))
@@ -1320,6 +1326,25 @@ func (h *Handle) RouteListFilteredIter(family int, filter *Route, filterMask uin
13201326
return executeErr
13211327
}
13221328

1329+
// deserializeRouteCacheInfo decodes a RTA_CACHEINFO attribute into a RouteCacheInfo struct
1330+
func deserializeRouteCacheInfo(b []byte) (*RouteCacheInfo, error) {
1331+
if len(b) != 32 {
1332+
return nil, unix.EINVAL
1333+
}
1334+
1335+
e := nl.NativeEndian()
1336+
return &RouteCacheInfo{
1337+
e.Uint32(b),
1338+
e.Uint32(b[4:]),
1339+
int32(e.Uint32(b[8:])),
1340+
e.Uint32(b[12:]),
1341+
e.Uint32(b[16:]),
1342+
e.Uint32(b[20:]),
1343+
e.Uint32(b[24:]),
1344+
e.Uint32(b[28:]),
1345+
}, nil
1346+
}
1347+
13231348
// deserializeRoute decodes a binary netlink message into a Route struct
13241349
func deserializeRoute(m []byte) (Route, error) {
13251350
msg := nl.DeserializeRtMsg(m)
@@ -1363,6 +1388,12 @@ func deserializeRoute(m []byte) (Route, error) {
13631388
route.ILinkIndex = int(native.Uint32(attr.Value[0:4]))
13641389
case unix.RTA_PRIORITY:
13651390
route.Priority = int(native.Uint32(attr.Value[0:4]))
1391+
case unix.RTA_CACHEINFO:
1392+
route.CacheInfo, err = deserializeRouteCacheInfo(attr.Value)
1393+
if err != nil {
1394+
return route, err
1395+
}
1396+
route.Expires = int(route.CacheInfo.Expires) / 100
13661397
case unix.RTA_FLOW:
13671398
route.Realm = int(native.Uint32(attr.Value[0:4]))
13681399
case unix.RTA_TABLE:

route_test.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ func TestRoute6AddDel(t *testing.T) {
192192
IP: net.ParseIP("2001:db8::0"),
193193
Mask: net.CIDRMask(64, 128),
194194
}
195-
route := Route{LinkIndex: link.Attrs().Index, Dst: dst}
195+
route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Expires: 10}
196196
if err := RouteAdd(&route); err != nil {
197197
t.Fatal(err)
198198
}
@@ -204,6 +204,25 @@ func TestRoute6AddDel(t *testing.T) {
204204
t.Fatal("Route not added properly")
205205
}
206206

207+
// route expiry is supported by kernel 4.4+
208+
k, m, err := KernelVersion()
209+
if err != nil {
210+
t.Fatal(err)
211+
}
212+
if k > 4 || (k == 4 && m > 4) {
213+
foundExpires := false
214+
for _, route := range routes {
215+
if route.Dst.IP.Equal(dst.IP) {
216+
if route.Expires > 0 && route.Expires <= 10 {
217+
foundExpires = true
218+
}
219+
}
220+
}
221+
if !foundExpires {
222+
t.Fatal("Route 'expires' not set")
223+
}
224+
}
225+
207226
dstIP := net.ParseIP("2001:db8::1")
208227
routeToDstIP, err := RouteGet(dstIP)
209228
if err != nil {

0 commit comments

Comments
 (0)