]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Adds support for several Linux kernel route attributes.
authorOndrej Zajicek <santiago@crfreenet.org>
Wed, 13 Apr 2011 10:32:27 +0000 (12:32 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Wed, 13 Apr 2011 10:32:27 +0000 (12:32 +0200)
doc/bird.sgml
nest/route.h
sysdep/linux/netlink/netlink.Y
sysdep/linux/netlink/netlink.c
sysdep/unix/krt.c
sysdep/unix/krt.h

index 5859c77b2fbe9f08168c551c042b284eadaeb8d0..86f4c5077cdfa853d52accff76baa561e0b835fe 100644 (file)
@@ -1420,12 +1420,20 @@ device routes from BIRD tables to kernel routing tables is restricted
 to prevent accidental interference. This restriction can be disabled using
 <cf/device routes/ switch.
 
-<p>If your OS supports only a single routing table, you can configure only one
-instance of the Kernel protocol. If it supports multiple tables (in order to
-allow policy routing; such an OS is for example Linux 2.2), you can run as many instances as you want, but each of
-them must be connected to a different BIRD routing table and to a different
+<p>If your OS supports only a single routing table, you can configure
+only one instance of the Kernel protocol. If it supports multiple
+tables (in order to allow policy routing; such an OS is for example
+Linux), you can run as many instances as you want, but each of them
+must be connected to a different BIRD routing table and to a different
 kernel table.
 
+<p>Because the kernel protocol is partially integrated with the
+connected routing table, there are two limitations - it is not
+possible to connect more kernel protocols to the same routing table
+and changing route attributes (even the kernel ones) in an export
+filter of a kernel protocol does not work. Both limitations can be
+overcome using another routing table and the pipe protocol.
+
 <sect1>Configuration
 
 <p><descrip>
@@ -1450,12 +1458,27 @@ kernel table.
        only on systems supporting multiple routing tables.
 </descrip>
 
-<p>The Kernel protocol doesn't define any route attributes.
+<sect1>Attributes
+
+<p>The Kernel protocol defines several attributes. These attributes
+are translated to appropriate system (and OS-specific) route attributes.
+We support these attributes:
+
+<descrip>
+       <tag>ip <cf/krt_prefsrc/</tag> (Linux) The preferred source address.
+       Used in source address selection for outgoing packets. Have to
+       be one of IP addresses of the router.
+
+       <tag>int <cf/krt_realm/</tag> (Linux) The realm of the route. Can be
+       used for traffic classification.
+</descrip>
+
+<sect1>Example
+
 <p>A simple configuration can look this way:
 
 <p><code>
 protocol kernel {
-       import all;
        export all;
 }
 </code>
index 8f9dff9a6e85de4d5a89ea0bfd6ddb69747adb3b..236882ece3bd4c66e61a301d603431424b67331a 100644 (file)
@@ -344,7 +344,8 @@ typedef struct eattr {
 #define EAP_BGP 1                      /* BGP attributes */
 #define EAP_RIP 2                      /* RIP */
 #define EAP_OSPF 3                     /* OSPF */
-#define EAP_MAX 4
+#define EAP_KRT 4                      /* Kernel route attributes */
+#define EAP_MAX 5
 
 #define EA_CODE(proto,id) (((proto) << 8) | (id))
 #define EA_PROTO(ea) ((ea) >> 8)
index c5dcf6204f45575a83c24eaea240e09b4f5438ff..b00b0eee4918b6803ccbece441f4fc33937eebe5 100644 (file)
@@ -10,7 +10,7 @@ CF_HDR
 
 CF_DECLS
 
-CF_KEYWORDS(ASYNC, KERNEL, TABLE)
+CF_KEYWORDS(ASYNC, KERNEL, TABLE, KRT_PREFSRC, KRT_REALM)
 
 CF_GRAMMAR
 
@@ -24,6 +24,9 @@ nl_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_CODE
 
 CF_END
index 6cb3c800c4fd5bf340f67384d8d1b8b6f025b4aa..0830097a10e0ba01acc3e5544cc8e04d6abbfabb 100644 (file)
@@ -18,6 +18,7 @@
 #include "nest/route.h"
 #include "nest/protocol.h"
 #include "nest/iface.h"
+#include "lib/alloca.h"
 #include "lib/timer.h"
 #include "lib/unix.h"
 #include "lib/krt.h"
@@ -618,6 +619,7 @@ nh_bufsize(struct mpnh *nh)
 static void
 nl_send_route(struct krt_proto *p, rte *e, int new)
 {
+  eattr *ea;
   net *net = e->net;
   rta *a = e->attrs;
   struct {
@@ -641,6 +643,13 @@ nl_send_route(struct krt_proto *p, rte *e, int new)
   r.r.rtm_protocol = RTPROT_BIRD;
   r.r.rtm_scope = RT_SCOPE_UNIVERSE;
   nl_add_attr_ipa(&r.h, sizeof(r), RTA_DST, net->n.prefix);
+
+  if (ea = ea_find(a->eattrs, EA_KRT_PREFSRC))
+    nl_add_attr_ipa(&r.h, sizeof(r), RTA_PREFSRC, *(ip_addr *)ea->u.ptr->data);
+
+  if (ea = ea_find(a->eattrs, EA_KRT_REALM))
+    nl_add_attr_u32(&r.h, sizeof(r), RTA_FLOW, ea->u.data);
+
   switch (a->dest)
     {
     case RTD_ROUTER:
@@ -698,10 +707,9 @@ nl_parse_route(struct nlmsghdr *h, int scan)
   struct rtmsg *i;
   struct rtattr *a[RTA_CACHEINFO+1];
   int new = h->nlmsg_type == RTM_NEWROUTE;
-  ip_addr dst;
-  rte *e;
-  net *net;
-  u32 oif;
+
+  ip_addr dst = IPA_NONE;
+  u32 oif = ~0;
   int src;
 
   if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(RTM_RTA(i), a, sizeof(a)))
@@ -709,12 +717,14 @@ nl_parse_route(struct nlmsghdr *h, int scan)
   if (i->rtm_family != BIRD_AF)
     return;
   if ((a[RTA_DST] && RTA_PAYLOAD(a[RTA_DST]) != sizeof(ip_addr)) ||
-      (a[RTA_OIF] && RTA_PAYLOAD(a[RTA_OIF]) != 4) ||
-      (a[RTA_PRIORITY] && RTA_PAYLOAD(a[RTA_PRIORITY]) != 4) ||
 #ifdef IPV6
       (a[RTA_IIF] && RTA_PAYLOAD(a[RTA_IIF]) != 4) ||
 #endif
-      (a[RTA_GATEWAY] && RTA_PAYLOAD(a[RTA_GATEWAY]) != sizeof(ip_addr)))
+      (a[RTA_OIF] && RTA_PAYLOAD(a[RTA_OIF]) != 4) ||
+      (a[RTA_GATEWAY] && RTA_PAYLOAD(a[RTA_GATEWAY]) != sizeof(ip_addr)) ||
+      (a[RTA_PRIORITY] && RTA_PAYLOAD(a[RTA_PRIORITY]) != 4) ||
+      (a[RTA_PREFSRC] && RTA_PAYLOAD(a[RTA_PREFSRC]) != sizeof(ip_addr)) ||
+      (a[RTA_FLOW] && RTA_PAYLOAD(a[RTA_OIF]) != 4))
     {
       log(L_ERR "KRT: Malformed message received");
       return;
@@ -725,13 +735,9 @@ nl_parse_route(struct nlmsghdr *h, int scan)
       memcpy(&dst, RTA_DATA(a[RTA_DST]), sizeof(dst));
       ipa_ntoh(dst);
     }
-  else
-    dst = IPA_NONE;
 
   if (a[RTA_OIF])
     memcpy(&oif, RTA_DATA(a[RTA_OIF]), sizeof(oif));
-  else
-    oif = ~0;
 
   DBG("KRT: Got %I/%d, type=%d, oif=%d, table=%d, prid=%d, proto=%s\n", dst, i->rtm_dst_len, i->rtm_type, oif, i->rtm_table, i->rtm_protocol, p->p.name);
 
@@ -782,7 +788,7 @@ nl_parse_route(struct nlmsghdr *h, int scan)
       src = KRT_SRC_ALIEN;
     }
 
-  net = net_get(p->p.table, dst, i->rtm_dst_len);
+  net *net = net_get(p->p.table, dst, i->rtm_dst_len);
 
   rta ra = {
     .proto = &p->p,
@@ -871,15 +877,49 @@ nl_parse_route(struct nlmsghdr *h, int scan)
       return;
     }
 
-  e = rte_get_temp(&ra);
+  rte *e = rte_get_temp(&ra);
   e->net = net;
   e->u.krt.src = src;
   e->u.krt.proto = i->rtm_protocol;
   e->u.krt.type = i->rtm_type;
+
   if (a[RTA_PRIORITY])
     memcpy(&e->u.krt.metric, RTA_DATA(a[RTA_PRIORITY]), sizeof(e->u.krt.metric));
   else
     e->u.krt.metric = 0;
+
+  if (a[RTA_PREFSRC])
+    {
+      ip_addr ps;
+      memcpy(&ps, RTA_DATA(a[RTA_PREFSRC]), sizeof(ps));
+      ipa_ntoh(ps);
+
+      ea_list *ea = alloca(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_PREFSRC;
+      ea->attrs[0].flags = 0;
+      ea->attrs[0].type = EAF_TYPE_IP_ADDRESS;
+      ea->attrs[0].u.ptr = alloca(sizeof(struct adata) + sizeof(ps));
+      ea->attrs[0].u.ptr->length = sizeof(ps);
+      memcpy(ea->attrs[0].u.ptr->data, &ps, sizeof(ps));
+    }
+
+  if (a[RTA_FLOW])
+    {
+      ea_list *ea = alloca(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_REALM;
+      ea->attrs[0].flags = 0;
+      ea->attrs[0].type = EAF_TYPE_INT;
+      memcpy(&ea->attrs[0].u.data, RTA_DATA(a[RTA_FLOW]), 4);
+    }
+
   if (scan)
     krt_got_route(p, e);
   else
index 562dc71742ccde01f2f17c3988620f648ccca1e9..7057070385b261c452f517eca985091100927272 100644 (file)
@@ -890,6 +890,7 @@ krt_init(struct proto_config *c)
   p->p.accept_ra_types = RA_OPTIMAL;
   p->p.import_control = krt_import_control;
   p->p.rt_notify = krt_notify;
+
   return &p->p;
 }
 
@@ -907,15 +908,35 @@ krt_reconfigure(struct proto *p, struct proto_config *new)
     ;
 }
 
+
+static int
+krt_get_attr(eattr * a, byte * buf, int buflen UNUSED)
+{
+  switch (a->id)
+  {
+  case EA_KRT_PREFSRC:
+    bsprintf(buf, "prefsrc");
+    return GA_NAME;
+  case EA_KRT_REALM:
+    bsprintf(buf, "realm");
+    return GA_NAME;
+  default:
+    return GA_UNKNOWN;
+  }
+}
+
+
 struct protocol proto_unix_kernel = {
   name:                "Kernel",
   template:    "kernel%d",
+  attr_class:  EAP_KRT,
   preconfig:   krt_preconfig,
   postconfig:  krt_postconfig,
   init:                krt_init,
   start:       krt_start,
   shutdown:    krt_shutdown,
   reconfigure: krt_reconfigure,
+  get_attr:    krt_get_attr,
 #ifdef KRT_ALLOW_LEARN
   dump:                krt_dump,
   dump_attrs:  krt_dump_attrs,
index ed61621fe3099dbfcf0414c1b72dff476ec40c44..c88bc4848fde8552a22ade1ad8ac0812da0153fa 100644 (file)
@@ -30,6 +30,10 @@ struct kif_proto;
 
 #define KRF_INSTALLED 0x80             /* This route should be installed in the kernel */
 
+
+#define EA_KRT_PREFSRC EA_CODE(EAP_KRT, 0)
+#define EA_KRT_REALM EA_CODE(EAP_KRT, 1)
+
 /* Whenever we recognize our own routes, we allow learing of foreign routes */
 
 #ifdef CONFIG_SELF_CONSCIOUS