Diff for /embedaddon/bird/sysdep/linux/netlink.c between versions 1.1 and 1.1.1.2

version 1.1, 2017/08/22 12:33:54 version 1.1.1.2, 2021/03/17 19:50:23
Line 59 Line 59
 /*  /*
  * Structure nl_parse_state keeps state of received route processing. Ideally,   * Structure nl_parse_state keeps state of received route processing. Ideally,
  * we could just independently parse received Netlink messages and immediately   * we could just independently parse received Netlink messages and immediately
 * propagate received routes to the rest of BIRD, but Linux kernel represents * propagate received routes to the rest of BIRD, but older Linux kernel (before
 * and announces IPv6 ECMP routes not as one route with multiple next hops (like * version 4.11) represents and announces IPv6 ECMP routes not as one route with
 * RTA_MULTIPATH in IPv4 ECMP), but as a set of routes with the same prefix. * multiple next hops (like RTA_MULTIPATH in IPv4 ECMP), but as a sequence of
  * routes with the same prefix. More recent kernels work as with IPv4.
  *   *
  * Therefore, BIRD keeps currently processed route in nl_parse_state structure   * Therefore, BIRD keeps currently processed route in nl_parse_state structure
  * and postpones its propagation until we expect it to be final; i.e., when   * and postpones its propagation until we expect it to be final; i.e., when
  * non-matching route is received or when the scan ends. When another matching   * non-matching route is received or when the scan ends. When another matching
  * route is received, it is merged with the already processed route to form an   * route is received, it is merged with the already processed route to form an
  * ECMP route. Note that merging is done only for IPv6 (merge == 1), but the   * ECMP route. Note that merging is done only for IPv6 (merge == 1), but the
 * postponing is done in both cases (for simplicity). All IPv4 routes are just * postponing is done in both cases (for simplicity). All IPv4 routes or IPv6
 * considered non-matching. * routes with RTA_MULTIPATH set are just considered non-matching.
  *   *
  * This is ignored for asynchronous notifications (every notification is handled   * This is ignored for asynchronous notifications (every notification is handled
  * as a separate route). It is not an issue for our routes, as we ignore such   * as a separate route). It is not an issue for our routes, as we ignore such
  * notifications anyways. But importing alien IPv6 ECMP routes does not work   * notifications anyways. But importing alien IPv6 ECMP routes does not work
 * properly. * properly with older kernels.
  *
  * Whatever the kernel version is, IPv6 ECMP routes are sent as multiple routes
  * for the same prefix.
  */   */
   
 struct nl_parse_state  struct nl_parse_state
Line 296  struct nl_want_attrs { Line 300  struct nl_want_attrs {
 static struct nl_want_attrs ifla_attr_want[BIRD_IFLA_MAX] = {  static struct nl_want_attrs ifla_attr_want[BIRD_IFLA_MAX] = {
   [IFLA_IFNAME]   = { 1, 0, 0 },    [IFLA_IFNAME]   = { 1, 0, 0 },
   [IFLA_MTU]      = { 1, 1, sizeof(u32) },    [IFLA_MTU]      = { 1, 1, sizeof(u32) },
     [IFLA_MASTER]   = { 1, 1, sizeof(u32) },
   [IFLA_WIRELESS] = { 1, 0, 0 },    [IFLA_WIRELESS] = { 1, 0, 0 },
 };  };
   
Line 320  static struct nl_want_attrs ifa_attr_want6[BIRD_IFA_MA Line 325  static struct nl_want_attrs ifa_attr_want6[BIRD_IFA_MA
   
 #define BIRD_RTA_MAX  (RTA_TABLE+1)  #define BIRD_RTA_MAX  (RTA_TABLE+1)
   
   #ifndef IPV6
 static struct nl_want_attrs mpnh_attr_want4[BIRD_RTA_MAX] = {  static struct nl_want_attrs mpnh_attr_want4[BIRD_RTA_MAX] = {
   [RTA_GATEWAY]   = { 1, 1, sizeof(ip4_addr) },    [RTA_GATEWAY]   = { 1, 1, sizeof(ip4_addr) },
 };  };
   #else
   static struct nl_want_attrs mpnh_attr_want6[BIRD_RTA_MAX] = {
     [RTA_GATEWAY]   = { 1, 1, sizeof(ip6_addr) },
   };
   #endif
   
 #ifndef IPV6  #ifndef IPV6
 static struct nl_want_attrs rtm_attr_want4[BIRD_RTA_MAX] = {  static struct nl_want_attrs rtm_attr_want4[BIRD_RTA_MAX] = {
Line 345  static struct nl_want_attrs rtm_attr_want6[BIRD_RTA_MA Line 356  static struct nl_want_attrs rtm_attr_want6[BIRD_RTA_MA
   [RTA_PRIORITY]  = { 1, 1, sizeof(u32) },    [RTA_PRIORITY]  = { 1, 1, sizeof(u32) },
   [RTA_PREFSRC]   = { 1, 1, sizeof(ip6_addr) },    [RTA_PREFSRC]   = { 1, 1, sizeof(ip6_addr) },
   [RTA_METRICS]   = { 1, 0, 0 },    [RTA_METRICS]   = { 1, 0, 0 },
     [RTA_MULTIPATH] = { 1, 0, 0 },
   [RTA_FLOW]      = { 1, 1, sizeof(u32) },    [RTA_FLOW]      = { 1, 1, sizeof(u32) },
   [RTA_TABLE]     = { 1, 1, sizeof(u32) },    [RTA_TABLE]     = { 1, 1, sizeof(u32) },
 };  };
Line 477  nl_add_multipath(struct nlmsghdr *h, unsigned bufsize, Line 489  nl_add_multipath(struct nlmsghdr *h, unsigned bufsize,
 }  }
   
 static struct mpnh *  static struct mpnh *
nl_parse_multipath(struct krt_proto *p, struct rtattr *ra)nl_parse_multipath(struct krt_proto *p, struct rtattr *ra, int af)
 {  {
   /* Temporary buffer for multicast nexthops */    /* Temporary buffer for multicast nexthops */
   static struct mpnh *nh_buffer;    static struct mpnh *nh_buffer;
Line 515  nl_parse_multipath(struct krt_proto *p, struct rtattr  Line 527  nl_parse_multipath(struct krt_proto *p, struct rtattr 
   
       /* Nonexistent RTNH_PAYLOAD ?? */        /* Nonexistent RTNH_PAYLOAD ?? */
       nl_attr_len = nh->rtnh_len - RTNH_LENGTH(0);        nl_attr_len = nh->rtnh_len - RTNH_LENGTH(0);
      nl_parse_attrs(RTNH_DATA(nh), mpnh_attr_want4, a, sizeof(a));      switch (af)
         {
 #ifndef IPV6
         case AF_INET:
           if (!nl_parse_attrs(RTNH_DATA(nh), mpnh_attr_want4, a, sizeof(a)))
             return NULL;
           break;
 #else
         case AF_INET6:
           if (!nl_parse_attrs(RTNH_DATA(nh), mpnh_attr_want6, a, sizeof(a)))
             return NULL;
           break;
 #endif
         default:
           return NULL;
         }
 
       if (a[RTA_GATEWAY])        if (a[RTA_GATEWAY])
         {          {
          memcpy(&rv->gw, RTA_DATA(a[RTA_GATEWAY]), sizeof(ip_addr));          memcpy(&rv->gw, RTA_DATA(a[RTA_GATEWAY]), sizeof(rv->gw));
           ipa_ntoh(rv->gw);            ipa_ntoh(rv->gw);
   
           neighbor *ng = neigh_find2(&p->p, &rv->gw, rv->iface,            neighbor *ng = neigh_find2(&p->p, &rv->gw, rv->iface,
Line 591  nl_parse_link(struct nlmsghdr *h, int scan) Line 619  nl_parse_link(struct nlmsghdr *h, int scan)
   struct iface f = {};    struct iface f = {};
   struct iface *ifi;    struct iface *ifi;
   char *name;    char *name;
  u32 mtu;  u32 mtu, master = 0;
   uint fl;    uint fl;
   
   if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(IFLA_RTA(i), ifla_attr_want, a, sizeof(a)))    if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(IFLA_RTA(i), ifla_attr_want, a, sizeof(a)))
Line 614  nl_parse_link(struct nlmsghdr *h, int scan) Line 642  nl_parse_link(struct nlmsghdr *h, int scan)
   name = RTA_DATA(a[IFLA_IFNAME]);    name = RTA_DATA(a[IFLA_IFNAME]);
   mtu = rta_get_u32(a[IFLA_MTU]);    mtu = rta_get_u32(a[IFLA_MTU]);
   
     if (a[IFLA_MASTER])
       master = rta_get_u32(a[IFLA_MASTER]);
   
   ifi = if_find_by_index(i->ifi_index);    ifi = if_find_by_index(i->ifi_index);
   if (!new)    if (!new)
     {      {
Line 633  nl_parse_link(struct nlmsghdr *h, int scan) Line 664  nl_parse_link(struct nlmsghdr *h, int scan)
       f.index = i->ifi_index;        f.index = i->ifi_index;
       f.mtu = mtu;        f.mtu = mtu;
   
         f.master_index = master;
         f.master = if_find_by_index(master);
   
       fl = i->ifi_flags;        fl = i->ifi_flags;
       if (fl & IFF_UP)        if (fl & IFF_UP)
         f.flags |= IF_ADMIN_UP;          f.flags |= IF_ADMIN_UP;
Line 808  kif_do_scan(struct kif_proto *p UNUSED) Line 842  kif_do_scan(struct kif_proto *p UNUSED)
     else      else
       log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type);        log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type);
   
     /* Re-resolve master interface for slaves */
     struct iface *i;
     WALK_LIST(i, iface_list)
       if (i->master_index)
       {
         struct iface f = {
           .flags = i->flags,
           .mtu = i->mtu,
           .index = i->index,
           .master_index = i->master_index,
           .master = if_find_by_index(i->master_index)
         };
   
         if (f.master != i->master)
         {
           memcpy(f.name, i->name, sizeof(f.name));
           if_update(&f);
         }
       }
   
   nl_request_dump(BIRD_AF, RTM_GETADDR);    nl_request_dump(BIRD_AF, RTM_GETADDR);
   while (h = nl_get_scan())    while (h = nl_get_scan())
     if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)      if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
Line 885  nl_send_route(struct krt_proto *p, rte *e, struct ea_l Line 939  nl_send_route(struct krt_proto *p, rte *e, struct ea_l
   struct {    struct {
     struct nlmsghdr h;      struct nlmsghdr h;
     struct rtmsg r;      struct rtmsg r;
    char buf[128 + KRT_METRICS_MAX*8 + nh_bufsize(a->nexthops)];    char buf[0];
  } r;  } *r;
   
     uint rsize = sizeof(*r) + 128 + KRT_METRICS_MAX*8 + nh_bufsize(a->nexthops);
     r = alloca(rsize);
   
   DBG("nl_send_route(%I/%d,op=%x)\n", net->n.prefix, net->n.pxlen, op);    DBG("nl_send_route(%I/%d,op=%x)\n", net->n.prefix, net->n.pxlen, op);
   
  bzero(&r.h, sizeof(r.h));  bzero(&r->h, sizeof(r->h));
  bzero(&r.r, sizeof(r.r));  bzero(&r->r, sizeof(r->r));
  r.h.nlmsg_type = op ? RTM_NEWROUTE : RTM_DELROUTE;  r->h.nlmsg_type = op ? RTM_NEWROUTE : RTM_DELROUTE;
  r.h.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));  r->h.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
  r.h.nlmsg_flags = op | NLM_F_REQUEST | NLM_F_ACK;  r->h.nlmsg_flags = op | NLM_F_REQUEST | NLM_F_ACK;
   
  r.r.rtm_family = BIRD_AF;  r->r.rtm_family = BIRD_AF;
  r.r.rtm_dst_len = net->n.pxlen;  r->r.rtm_dst_len = net->n.pxlen;
  r.r.rtm_protocol = RTPROT_BIRD;  r->r.rtm_protocol = RTPROT_BIRD;
  r.r.rtm_scope = RT_SCOPE_NOWHERE;  r->r.rtm_scope = RT_SCOPE_NOWHERE;
  nl_add_attr_ipa(&r.h, sizeof(r), RTA_DST, net->n.prefix);  nl_add_attr_ipa(&r->h, rsize, RTA_DST, net->n.prefix);
   
   /*    /*
    * Strange behavior for RTM_DELROUTE:     * Strange behavior for RTM_DELROUTE:
Line 910  nl_send_route(struct krt_proto *p, rte *e, struct ea_l Line 967  nl_send_route(struct krt_proto *p, rte *e, struct ea_l
    */     */
   
   if (krt_table_id(p) < 256)    if (krt_table_id(p) < 256)
    r.r.rtm_table = krt_table_id(p);    r->r.rtm_table = krt_table_id(p);
   else    else
    nl_add_attr_u32(&r.h, sizeof(r), RTA_TABLE, krt_table_id(p));    nl_add_attr_u32(&r->h, rsize, RTA_TABLE, krt_table_id(p));
   
   if (a->source == RTS_DUMMY)    if (a->source == RTS_DUMMY)
     priority = e->u.krt.metric;      priority = e->u.krt.metric;
Line 922  nl_send_route(struct krt_proto *p, rte *e, struct ea_l Line 979  nl_send_route(struct krt_proto *p, rte *e, struct ea_l
     priority = ea->u.data;      priority = ea->u.data;
   
   if (priority)    if (priority)
    nl_add_attr_u32(&r.h, sizeof(r), RTA_PRIORITY, priority);    nl_add_attr_u32(&r->h, rsize, RTA_PRIORITY, priority);
   
   /* For route delete, we do not specify remaining route attributes */    /* For route delete, we do not specify remaining route attributes */
   if (op == NL_OP_DELETE)    if (op == NL_OP_DELETE)
Line 930  nl_send_route(struct krt_proto *p, rte *e, struct ea_l Line 987  nl_send_route(struct krt_proto *p, rte *e, struct ea_l
   
   /* Default scope is LINK for device routes, UNIVERSE otherwise */    /* Default scope is LINK for device routes, UNIVERSE otherwise */
   if (ea = ea_find(eattrs, EA_KRT_SCOPE))    if (ea = ea_find(eattrs, EA_KRT_SCOPE))
    r.r.rtm_scope = ea->u.data;    r->r.rtm_scope = ea->u.data;
   else    else
    r.r.rtm_scope = (dest == RTD_DEVICE) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE;    r->r.rtm_scope = (dest == RTD_DEVICE) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE;
   
   if (ea = ea_find(eattrs, EA_KRT_PREFSRC))    if (ea = ea_find(eattrs, EA_KRT_PREFSRC))
    nl_add_attr_ipa(&r.h, sizeof(r), RTA_PREFSRC, *(ip_addr *)ea->u.ptr->data);    nl_add_attr_ipa(&r->h, rsize, RTA_PREFSRC, *(ip_addr *)ea->u.ptr->data);
   
   if (ea = ea_find(eattrs, EA_KRT_REALM))    if (ea = ea_find(eattrs, EA_KRT_REALM))
    nl_add_attr_u32(&r.h, sizeof(r), RTA_FLOW, ea->u.data);    nl_add_attr_u32(&r->h, rsize, RTA_FLOW, ea->u.data);
   
   
   u32 metrics[KRT_METRICS_MAX];    u32 metrics[KRT_METRICS_MAX];
Line 953  nl_send_route(struct krt_proto *p, rte *e, struct ea_l Line 1010  nl_send_route(struct krt_proto *p, rte *e, struct ea_l
   }    }
   
   if (metrics[0])    if (metrics[0])
    nl_add_metrics(&r.h, sizeof(r), metrics, KRT_METRICS_MAX);    nl_add_metrics(&r->h, rsize, metrics, KRT_METRICS_MAX);
   
   
 dest:  dest:
Line 961  dest: Line 1018  dest:
   switch (dest)    switch (dest)
     {      {
     case RTD_ROUTER:      case RTD_ROUTER:
      r.r.rtm_type = RTN_UNICAST;      r->r.rtm_type = RTN_UNICAST;
      nl_add_attr_u32(&r.h, sizeof(r), RTA_OIF, iface->index);      nl_add_attr_u32(&r->h, rsize, RTA_OIF, iface->index);
      nl_add_attr_ipa(&r.h, sizeof(r), RTA_GATEWAY, gw);      nl_add_attr_ipa(&r->h, rsize, RTA_GATEWAY, gw);
       break;        break;
     case RTD_DEVICE:      case RTD_DEVICE:
      r.r.rtm_type = RTN_UNICAST;      r->r.rtm_type = RTN_UNICAST;
      nl_add_attr_u32(&r.h, sizeof(r), RTA_OIF, iface->index);      nl_add_attr_u32(&r->h, rsize, RTA_OIF, iface->index);
       break;        break;
     case RTD_BLACKHOLE:      case RTD_BLACKHOLE:
      r.r.rtm_type = RTN_BLACKHOLE;      r->r.rtm_type = RTN_BLACKHOLE;
       break;        break;
     case RTD_UNREACHABLE:      case RTD_UNREACHABLE:
      r.r.rtm_type = RTN_UNREACHABLE;      r->r.rtm_type = RTN_UNREACHABLE;
       break;        break;
     case RTD_PROHIBIT:      case RTD_PROHIBIT:
      r.r.rtm_type = RTN_PROHIBIT;      r->r.rtm_type = RTN_PROHIBIT;
       break;        break;
     case RTD_MULTIPATH:      case RTD_MULTIPATH:
      r.r.rtm_type = RTN_UNICAST;      r->r.rtm_type = RTN_UNICAST;
      nl_add_multipath(&r.h, sizeof(r), a->nexthops);      nl_add_multipath(&r->h, rsize, a->nexthops);
       break;        break;
     case RTD_NONE:      case RTD_NONE:
       break;        break;
Line 989  dest: Line 1046  dest:
     }      }
   
   /* Ignore missing for DELETE */    /* Ignore missing for DELETE */
  return nl_exchange(&r.h, (op == NL_OP_DELETE));  return nl_exchange(&r->h, (op == NL_OP_DELETE));
 }  }
   
 static inline int  static inline int
Line 1240  nl_parse_route(struct nl_parse_state *s, struct nlmsgh Line 1297  nl_parse_route(struct nl_parse_state *s, struct nlmsgh
     {      {
     case RTN_UNICAST:      case RTN_UNICAST:
   
      if (a[RTA_MULTIPATH] && (i->rtm_family == AF_INET))      if (a[RTA_MULTIPATH])
         {          {
           ra->dest = RTD_MULTIPATH;            ra->dest = RTD_MULTIPATH;
          ra->nexthops = nl_parse_multipath(p, a[RTA_MULTIPATH]);          ra->nexthops = nl_parse_multipath(p, a[RTA_MULTIPATH], i->rtm_family);
           if (!ra->nexthops)            if (!ra->nexthops)
             {              {
               log(L_ERR "KRT: Received strange multipath route %I/%d",                log(L_ERR "KRT: Received strange multipath route %I/%d",
Line 1385  nl_parse_route(struct nl_parse_state *s, struct nlmsgh Line 1442  nl_parse_route(struct nl_parse_state *s, struct nlmsgh
   
   /*    /*
    * Ideally, now we would send the received route to the rest of kernel code.     * Ideally, now we would send the received route to the rest of kernel code.
   * But IPv6 ECMP routes are sent as a sequence of routes, so we postpone it   * But IPv6 ECMP routes before 4.11 are sent as a sequence of routes, so we
   * and merge next hops until the end of the sequence.   * postpone it and merge next hops until the end of the sequence. Note that
    * proper multipath updates are rejected by nl_mergable_route(), so it is
    * always the first case for them.
    */     */
   
   if (!s->net)    if (!s->net)
Line 1694  kif_sys_start(struct kif_proto *p UNUSED) Line 1753  kif_sys_start(struct kif_proto *p UNUSED)
 void  void
 kif_sys_shutdown(struct kif_proto *p UNUSED)  kif_sys_shutdown(struct kif_proto *p UNUSED)
 {  {
}}
   

Removed from v.1.1  
changed lines
  Added in v.1.1.1.2


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>