>From 344b4896bfca25b5b537101f3c084d041df15164 Mon Sep 17 00:00:00 2001
From: Vincent Bernat <vincent@bernat.im>
Date: Thu, 29 Jun 2017 10:44:59 +0200
Subject: [PATCH] Netlink: also store "onlink" attribute

When piping routes from one table to another, this attribute needs to be
copied. We also make it accessible to the user, through `krt_onlink`.
---
 doc/bird.sgml          |  4 ++++
 sysdep/linux/krt-sys.h |  1 +
 sysdep/linux/netlink.Y |  3 ++-
 sysdep/linux/netlink.c | 19 +++++++++++++++++++
 4 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/doc/bird.sgml b/doc/bird.sgml
index 6af0e0f6791b..271f4e08c95f 100644
--- a/doc/bird.sgml
+++ b/doc/bird.sgml
@@ -2562,6 +2562,10 @@ these attributes:
 	kernels anything below <it/link/ (253) is treated as <it/global/ (0).
 	When not present, global scope is implied for all routes except device
 	routes, where link scope is used by default.
+
+	<tag><label id="rta-krt-onlink">int krt_onlink/</tag> (Linux)
+	Whatever the nexthop should be considered as directly attached to
+	the interface.
 </descrip>
 
 <p>In Linux, there is also a plenty of obscure route attributes mostly focused
diff --git a/sysdep/linux/krt-sys.h b/sysdep/linux/krt-sys.h
index 76ae29b716e5..6102dc4f5415 100644
--- a/sysdep/linux/krt-sys.h
+++ b/sysdep/linux/krt-sys.h
@@ -37,6 +37,7 @@ static inline struct ifa * kif_get_primary_ip(struct iface *i UNUSED) { return N
 #define EA_KRT_PREFSRC		EA_CODE(EAP_KRT, 0x10)
 #define EA_KRT_REALM		EA_CODE(EAP_KRT, 0x11)
 #define EA_KRT_SCOPE		EA_CODE(EAP_KRT, 0x12)
+#define EA_KRT_ONLINK		EA_CODE(EAP_KRT, 0x13)
 
 
 #define KRT_METRICS_MAX		0x10	/* RTAX_QUICKACK+1 */
diff --git a/sysdep/linux/netlink.Y b/sysdep/linux/netlink.Y
index f577244de183..a0562e6f4d30 100644
--- a/sysdep/linux/netlink.Y
+++ b/sysdep/linux/netlink.Y
@@ -10,7 +10,7 @@ CF_HDR
 
 CF_DECLS
 
-CF_KEYWORDS(KERNEL, TABLE, METRIC, KRT_PREFSRC, KRT_REALM, KRT_SCOPE, KRT_MTU, KRT_WINDOW,
+CF_KEYWORDS(KERNEL, TABLE, METRIC, KRT_PREFSRC, KRT_REALM, KRT_SCOPE, KRT_ONLINK, KRT_MTU, KRT_WINDOW,
 	    KRT_RTT, KRT_RTTVAR, KRT_SSTRESH, KRT_CWND, KRT_ADVMSS, KRT_REORDERING,
 	    KRT_HOPLIMIT, KRT_INITCWND, KRT_RTO_MIN, KRT_INITRWND, KRT_QUICKACK,
 	    KRT_LOCK_MTU, KRT_LOCK_WINDOW, KRT_LOCK_RTT, KRT_LOCK_RTTVAR,
@@ -29,6 +29,7 @@ kern_sys_item:
 CF_ADDTO(dynamic_attr, KRT_PREFSRC	{ $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, T_IP, EA_KRT_PREFSRC); })
 CF_ADDTO(dynamic_attr, KRT_REALM	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_REALM); })
 CF_ADDTO(dynamic_attr, KRT_SCOPE	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_SCOPE); })
+CF_ADDTO(dynamic_attr, KRT_ONLINK	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_ONLINK); })
 
 CF_ADDTO(dynamic_attr, KRT_MTU		{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_MTU); })
 CF_ADDTO(dynamic_attr, KRT_WINDOW	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_WINDOW); })
diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c
index 22313f439977..479e297ecdb3 100644
--- a/sysdep/linux/netlink.c
+++ b/sysdep/linux/netlink.c
@@ -940,6 +940,8 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int op, int d
   if (ea = ea_find(eattrs, EA_KRT_REALM))
     nl_add_attr_u32(&r.h, sizeof(r), RTA_FLOW, ea->u.data);
 
+  if ((ea = ea_find(eattrs, EA_KRT_ONLINK)) && ea->u.data == 1)
+    r.r.rtm_flags |= RTNH_F_ONLINK;
 
   u32 metrics[KRT_METRICS_MAX];
   metrics[0] = 0;
@@ -1319,6 +1321,19 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
       ea->attrs[0].u.data = i->rtm_scope;
     }
 
+  if (i->rtm_flags & RTNH_F_ONLINK)
+    {
+      ea_list *ea = lp_alloc(s->pool, sizeof(ea_list) + sizeof(eattr));
+      ea->next = ra->eattrs;
+      ra->eattrs = ea;
+      ea->flags = EALF_SORTED;
+      ea->count = 1;
+      ea->attrs[0].id = EA_KRT_ONLINK;
+      ea->attrs[0].flags = 0;
+      ea->attrs[0].type = EAF_TYPE_INT;
+      ea->attrs[0].u.data = 1;
+    }
+
   if (a[RTA_PREFSRC])
     {
       ip_addr ps;
@@ -1660,6 +1675,10 @@ krt_sys_get_attr(eattr *a, byte *buf, int buflen UNUSED)
     bsprintf(buf, "scope");
     return GA_NAME;
 
+  case EA_KRT_ONLINK:
+    bsprintf(buf, "onlink");
+    return GA_NAME;
+
   case EA_KRT_LOCK:
     buf += bsprintf(buf, "lock:");
     ea_format_bitfield(a, buf, buflen, krt_metrics_names, 2, KRT_METRICS_MAX);
-- 
2.13.2

