Annotation of embedaddon/bird/sysdep/linux/netlink.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  *     BIRD -- Linux Netlink Interface
        !             3:  *
        !             4:  *     (c) 1999--2000 Martin Mares <mj@ucw.cz>
        !             5:  *
        !             6:  *     Can be freely distributed and used under the terms of the GNU GPL.
        !             7:  */
        !             8: 
        !             9: #include <stdio.h>
        !            10: #include <unistd.h>
        !            11: #include <fcntl.h>
        !            12: #include <sys/socket.h>
        !            13: #include <sys/uio.h>
        !            14: #include <errno.h>
        !            15: 
        !            16: #undef LOCAL_DEBUG
        !            17: 
        !            18: #include "nest/bird.h"
        !            19: #include "nest/route.h"
        !            20: #include "nest/protocol.h"
        !            21: #include "nest/iface.h"
        !            22: #include "lib/timer.h"
        !            23: #include "lib/unix.h"
        !            24: #include "lib/krt.h"
        !            25: #include "lib/socket.h"
        !            26: #include "lib/string.h"
        !            27: #include "lib/hash.h"
        !            28: #include "conf/conf.h"
        !            29: 
        !            30: #include <asm/types.h>
        !            31: #include <linux/if.h>
        !            32: #include <linux/netlink.h>
        !            33: #include <linux/rtnetlink.h>
        !            34: 
        !            35: 
        !            36: #ifndef MSG_TRUNC                      /* Hack: Several versions of glibc miss this one :( */
        !            37: #define MSG_TRUNC 0x20
        !            38: #endif
        !            39: 
        !            40: #ifndef IFA_FLAGS
        !            41: #define IFA_FLAGS 8
        !            42: #endif
        !            43: 
        !            44: #ifndef IFF_LOWER_UP
        !            45: #define IFF_LOWER_UP 0x10000
        !            46: #endif
        !            47: 
        !            48: #ifndef RTA_TABLE
        !            49: #define RTA_TABLE  15
        !            50: #endif
        !            51: 
        !            52: 
        !            53: #ifdef IPV6
        !            54: #define krt_ecmp6(X) 1
        !            55: #else
        !            56: #define krt_ecmp6(X) 0
        !            57: #endif
        !            58: 
        !            59: /*
        !            60:  * Structure nl_parse_state keeps state of received route processing. Ideally,
        !            61:  * we could just independently parse received Netlink messages and immediately
        !            62:  * propagate received routes to the rest of BIRD, but Linux kernel represents
        !            63:  * and announces IPv6 ECMP routes not as one route with multiple next hops (like
        !            64:  * RTA_MULTIPATH in IPv4 ECMP), but as a set of routes with the same prefix.
        !            65:  *
        !            66:  * Therefore, BIRD keeps currently processed route in nl_parse_state structure
        !            67:  * and postpones its propagation until we expect it to be final; i.e., when
        !            68:  * non-matching route is received or when the scan ends. When another matching
        !            69:  * route is received, it is merged with the already processed route to form an
        !            70:  * ECMP route. Note that merging is done only for IPv6 (merge == 1), but the
        !            71:  * postponing is done in both cases (for simplicity). All IPv4 routes are just
        !            72:  * considered non-matching.
        !            73:  *
        !            74:  * This is ignored for asynchronous notifications (every notification is handled
        !            75:  * as a separate route). It is not an issue for our routes, as we ignore such
        !            76:  * notifications anyways. But importing alien IPv6 ECMP routes does not work
        !            77:  * properly.
        !            78:  */
        !            79: 
        !            80: struct nl_parse_state
        !            81: {
        !            82:   struct linpool *pool;
        !            83:   int scan;
        !            84:   int merge;
        !            85: 
        !            86:   net *net;
        !            87:   rta *attrs;
        !            88:   struct krt_proto *proto;
        !            89:   s8 new;
        !            90:   s8 krt_src;
        !            91:   u8 krt_type;
        !            92:   u8 krt_proto;
        !            93:   u32 krt_metric;
        !            94: };
        !            95: 
        !            96: /*
        !            97:  *     Synchronous Netlink interface
        !            98:  */
        !            99: 
        !           100: struct nl_sock
        !           101: {
        !           102:   int fd;
        !           103:   u32 seq;
        !           104:   byte *rx_buffer;                     /* Receive buffer */
        !           105:   struct nlmsghdr *last_hdr;           /* Recently received packet */
        !           106:   uint last_size;
        !           107: };
        !           108: 
        !           109: #define NL_RX_SIZE 8192
        !           110: 
        !           111: #define NL_OP_DELETE   0
        !           112: #define NL_OP_ADD      (NLM_F_CREATE|NLM_F_EXCL)
        !           113: #define NL_OP_REPLACE  (NLM_F_CREATE|NLM_F_REPLACE)
        !           114: #define NL_OP_APPEND   (NLM_F_CREATE|NLM_F_APPEND)
        !           115: 
        !           116: static linpool *nl_linpool;
        !           117: 
        !           118: static struct nl_sock nl_scan = {.fd = -1};    /* Netlink socket for synchronous scan */
        !           119: static struct nl_sock nl_req  = {.fd = -1};    /* Netlink socket for requests */
        !           120: 
        !           121: static void
        !           122: nl_open_sock(struct nl_sock *nl)
        !           123: {
        !           124:   if (nl->fd < 0)
        !           125:     {
        !           126:       nl->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
        !           127:       if (nl->fd < 0)
        !           128:        die("Unable to open rtnetlink socket: %m");
        !           129:       nl->seq = now;
        !           130:       nl->rx_buffer = xmalloc(NL_RX_SIZE);
        !           131:       nl->last_hdr = NULL;
        !           132:       nl->last_size = 0;
        !           133:     }
        !           134: }
        !           135: 
        !           136: static void
        !           137: nl_open(void)
        !           138: {
        !           139:   nl_open_sock(&nl_scan);
        !           140:   nl_open_sock(&nl_req);
        !           141: }
        !           142: 
        !           143: static void
        !           144: nl_send(struct nl_sock *nl, struct nlmsghdr *nh)
        !           145: {
        !           146:   struct sockaddr_nl sa;
        !           147: 
        !           148:   memset(&sa, 0, sizeof(sa));
        !           149:   sa.nl_family = AF_NETLINK;
        !           150:   nh->nlmsg_pid = 0;
        !           151:   nh->nlmsg_seq = ++(nl->seq);
        !           152:   if (sendto(nl->fd, nh, nh->nlmsg_len, 0, (struct sockaddr *)&sa, sizeof(sa)) < 0)
        !           153:     die("rtnetlink sendto: %m");
        !           154:   nl->last_hdr = NULL;
        !           155: }
        !           156: 
        !           157: static void
        !           158: nl_request_dump(int af, int cmd)
        !           159: {
        !           160:   struct {
        !           161:     struct nlmsghdr nh;
        !           162:     struct rtgenmsg g;
        !           163:   } req = {
        !           164:     .nh.nlmsg_type = cmd,
        !           165:     .nh.nlmsg_len = sizeof(req),
        !           166:     .nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
        !           167:     .g.rtgen_family = af
        !           168:   };
        !           169:   nl_send(&nl_scan, &req.nh);
        !           170: }
        !           171: 
        !           172: static struct nlmsghdr *
        !           173: nl_get_reply(struct nl_sock *nl)
        !           174: {
        !           175:   for(;;)
        !           176:     {
        !           177:       if (!nl->last_hdr)
        !           178:        {
        !           179:          struct iovec iov = { nl->rx_buffer, NL_RX_SIZE };
        !           180:          struct sockaddr_nl sa;
        !           181:          struct msghdr m = {
        !           182:            .msg_name = &sa,
        !           183:            .msg_namelen = sizeof(sa),
        !           184:            .msg_iov = &iov,
        !           185:            .msg_iovlen = 1,
        !           186:          };
        !           187:          int x = recvmsg(nl->fd, &m, 0);
        !           188:          if (x < 0)
        !           189:            die("nl_get_reply: %m");
        !           190:          if (sa.nl_pid)                /* It isn't from the kernel */
        !           191:            {
        !           192:              DBG("Non-kernel packet\n");
        !           193:              continue;
        !           194:            }
        !           195:          nl->last_size = x;
        !           196:          nl->last_hdr = (void *) nl->rx_buffer;
        !           197:          if (m.msg_flags & MSG_TRUNC)
        !           198:            bug("nl_get_reply: got truncated reply which should be impossible");
        !           199:        }
        !           200:       if (NLMSG_OK(nl->last_hdr, nl->last_size))
        !           201:        {
        !           202:          struct nlmsghdr *h = nl->last_hdr;
        !           203:          nl->last_hdr = NLMSG_NEXT(h, nl->last_size);
        !           204:          if (h->nlmsg_seq != nl->seq)
        !           205:            {
        !           206:              log(L_WARN "nl_get_reply: Ignoring out of sequence netlink packet (%x != %x)",
        !           207:                  h->nlmsg_seq, nl->seq);
        !           208:              continue;
        !           209:            }
        !           210:          return h;
        !           211:        }
        !           212:       if (nl->last_size)
        !           213:        log(L_WARN "nl_get_reply: Found packet remnant of size %d", nl->last_size);
        !           214:       nl->last_hdr = NULL;
        !           215:     }
        !           216: }
        !           217: 
        !           218: static struct tbf rl_netlink_err = TBF_DEFAULT_LOG_LIMITS;
        !           219: 
        !           220: static int
        !           221: nl_error(struct nlmsghdr *h, int ignore_esrch)
        !           222: {
        !           223:   struct nlmsgerr *e;
        !           224:   int ec;
        !           225: 
        !           226:   if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
        !           227:     {
        !           228:       log(L_WARN "Netlink: Truncated error message received");
        !           229:       return ENOBUFS;
        !           230:     }
        !           231:   e = (struct nlmsgerr *) NLMSG_DATA(h);
        !           232:   ec = -e->error;
        !           233:   if (ec && !(ignore_esrch && (ec == ESRCH)))
        !           234:     log_rl(&rl_netlink_err, L_WARN "Netlink: %s", strerror(ec));
        !           235:   return ec;
        !           236: }
        !           237: 
        !           238: static struct nlmsghdr *
        !           239: nl_get_scan(void)
        !           240: {
        !           241:   struct nlmsghdr *h = nl_get_reply(&nl_scan);
        !           242: 
        !           243:   if (h->nlmsg_type == NLMSG_DONE)
        !           244:     return NULL;
        !           245:   if (h->nlmsg_type == NLMSG_ERROR)
        !           246:     {
        !           247:       nl_error(h, 0);
        !           248:       return NULL;
        !           249:     }
        !           250:   return h;
        !           251: }
        !           252: 
        !           253: static int
        !           254: nl_exchange(struct nlmsghdr *pkt, int ignore_esrch)
        !           255: {
        !           256:   struct nlmsghdr *h;
        !           257: 
        !           258:   nl_send(&nl_req, pkt);
        !           259:   for(;;)
        !           260:     {
        !           261:       h = nl_get_reply(&nl_req);
        !           262:       if (h->nlmsg_type == NLMSG_ERROR)
        !           263:        break;
        !           264:       log(L_WARN "nl_exchange: Unexpected reply received");
        !           265:     }
        !           266:   return nl_error(h, ignore_esrch) ? -1 : 0;
        !           267: }
        !           268: 
        !           269: /*
        !           270:  *     Netlink attributes
        !           271:  */
        !           272: 
        !           273: static int nl_attr_len;
        !           274: 
        !           275: static void *
        !           276: nl_checkin(struct nlmsghdr *h, int lsize)
        !           277: {
        !           278:   nl_attr_len = h->nlmsg_len - NLMSG_LENGTH(lsize);
        !           279:   if (nl_attr_len < 0)
        !           280:     {
        !           281:       log(L_ERR "nl_checkin: underrun by %d bytes", -nl_attr_len);
        !           282:       return NULL;
        !           283:     }
        !           284:   return NLMSG_DATA(h);
        !           285: }
        !           286: 
        !           287: struct nl_want_attrs {
        !           288:   u8 defined:1;
        !           289:   u8 checksize:1;
        !           290:   u8 size;
        !           291: };
        !           292: 
        !           293: 
        !           294: #define BIRD_IFLA_MAX (IFLA_WIRELESS+1)
        !           295: 
        !           296: static struct nl_want_attrs ifla_attr_want[BIRD_IFLA_MAX] = {
        !           297:   [IFLA_IFNAME]          = { 1, 0, 0 },
        !           298:   [IFLA_MTU]     = { 1, 1, sizeof(u32) },
        !           299:   [IFLA_WIRELESS] = { 1, 0, 0 },
        !           300: };
        !           301: 
        !           302: 
        !           303: #define BIRD_IFA_MAX  (IFA_FLAGS+1)
        !           304: 
        !           305: #ifndef IPV6
        !           306: static struct nl_want_attrs ifa_attr_want4[BIRD_IFA_MAX] = {
        !           307:   [IFA_ADDRESS]          = { 1, 1, sizeof(ip4_addr) },
        !           308:   [IFA_LOCAL]    = { 1, 1, sizeof(ip4_addr) },
        !           309:   [IFA_BROADCAST] = { 1, 1, sizeof(ip4_addr) },
        !           310:   [IFA_FLAGS]    = { 1, 1, sizeof(u32) },
        !           311: };
        !           312: #else
        !           313: static struct nl_want_attrs ifa_attr_want6[BIRD_IFA_MAX] = {
        !           314:   [IFA_ADDRESS]          = { 1, 1, sizeof(ip6_addr) },
        !           315:   [IFA_LOCAL]    = { 1, 1, sizeof(ip6_addr) },
        !           316:   [IFA_FLAGS]    = { 1, 1, sizeof(u32) },
        !           317: };
        !           318: #endif
        !           319: 
        !           320: 
        !           321: #define BIRD_RTA_MAX  (RTA_TABLE+1)
        !           322: 
        !           323: static struct nl_want_attrs mpnh_attr_want4[BIRD_RTA_MAX] = {
        !           324:   [RTA_GATEWAY]          = { 1, 1, sizeof(ip4_addr) },
        !           325: };
        !           326: 
        !           327: #ifndef IPV6
        !           328: static struct nl_want_attrs rtm_attr_want4[BIRD_RTA_MAX] = {
        !           329:   [RTA_DST]      = { 1, 1, sizeof(ip4_addr) },
        !           330:   [RTA_OIF]      = { 1, 1, sizeof(u32) },
        !           331:   [RTA_GATEWAY]          = { 1, 1, sizeof(ip4_addr) },
        !           332:   [RTA_PRIORITY]  = { 1, 1, sizeof(u32) },
        !           333:   [RTA_PREFSRC]          = { 1, 1, sizeof(ip4_addr) },
        !           334:   [RTA_METRICS]          = { 1, 0, 0 },
        !           335:   [RTA_MULTIPATH] = { 1, 0, 0 },
        !           336:   [RTA_FLOW]     = { 1, 1, sizeof(u32) },
        !           337:   [RTA_TABLE]    = { 1, 1, sizeof(u32) },
        !           338: };
        !           339: #else
        !           340: static struct nl_want_attrs rtm_attr_want6[BIRD_RTA_MAX] = {
        !           341:   [RTA_DST]      = { 1, 1, sizeof(ip6_addr) },
        !           342:   [RTA_IIF]      = { 1, 1, sizeof(u32) },
        !           343:   [RTA_OIF]      = { 1, 1, sizeof(u32) },
        !           344:   [RTA_GATEWAY]          = { 1, 1, sizeof(ip6_addr) },
        !           345:   [RTA_PRIORITY]  = { 1, 1, sizeof(u32) },
        !           346:   [RTA_PREFSRC]          = { 1, 1, sizeof(ip6_addr) },
        !           347:   [RTA_METRICS]          = { 1, 0, 0 },
        !           348:   [RTA_FLOW]     = { 1, 1, sizeof(u32) },
        !           349:   [RTA_TABLE]    = { 1, 1, sizeof(u32) },
        !           350: };
        !           351: #endif
        !           352: 
        !           353: 
        !           354: static int
        !           355: nl_parse_attrs(struct rtattr *a, struct nl_want_attrs *want, struct rtattr **k, int ksize)
        !           356: {
        !           357:   int max = ksize / sizeof(struct rtattr *);
        !           358:   bzero(k, ksize);
        !           359: 
        !           360:   for ( ; RTA_OK(a, nl_attr_len); a = RTA_NEXT(a, nl_attr_len))
        !           361:     {
        !           362:       if ((a->rta_type >= max) || !want[a->rta_type].defined)
        !           363:        continue;
        !           364: 
        !           365:       if (want[a->rta_type].checksize && (RTA_PAYLOAD(a) != want[a->rta_type].size))
        !           366:        {
        !           367:          log(L_ERR "nl_parse_attrs: Malformed message received");
        !           368:          return 0;
        !           369:        }
        !           370: 
        !           371:       k[a->rta_type] = a;
        !           372:     }
        !           373: 
        !           374:   if (nl_attr_len)
        !           375:     {
        !           376:       log(L_ERR "nl_parse_attrs: remnant of size %d", nl_attr_len);
        !           377:       return 0;
        !           378:     }
        !           379: 
        !           380:   return 1;
        !           381: }
        !           382: 
        !           383: static inline u32 rta_get_u32(struct rtattr *a)
        !           384: { return *(u32 *) RTA_DATA(a); }
        !           385: 
        !           386: static inline ip4_addr rta_get_ip4(struct rtattr *a)
        !           387: { return ip4_ntoh(*(ip4_addr *) RTA_DATA(a)); }
        !           388: 
        !           389: static inline ip6_addr rta_get_ip6(struct rtattr *a)
        !           390: { return ip6_ntoh(*(ip6_addr *) RTA_DATA(a)); }
        !           391: 
        !           392: 
        !           393: struct rtattr *
        !           394: nl_add_attr(struct nlmsghdr *h, uint bufsize, uint code, const void *data, uint dlen)
        !           395: {
        !           396:   uint pos = NLMSG_ALIGN(h->nlmsg_len);
        !           397:   uint len = RTA_LENGTH(dlen);
        !           398: 
        !           399:   if (pos + len > bufsize)
        !           400:     bug("nl_add_attr: packet buffer overflow");
        !           401: 
        !           402:   struct rtattr *a = (struct rtattr *)((char *)h + pos);
        !           403:   a->rta_type = code;
        !           404:   a->rta_len = len;
        !           405:   h->nlmsg_len = pos + len;
        !           406: 
        !           407:   if (dlen > 0)
        !           408:     memcpy(RTA_DATA(a), data, dlen);
        !           409: 
        !           410:   return a;
        !           411: }
        !           412: 
        !           413: static inline void
        !           414: nl_add_attr_u32(struct nlmsghdr *h, unsigned bufsize, int code, u32 data)
        !           415: {
        !           416:   nl_add_attr(h, bufsize, code, &data, 4);
        !           417: }
        !           418: 
        !           419: static inline void
        !           420: nl_add_attr_ipa(struct nlmsghdr *h, unsigned bufsize, int code, ip_addr ipa)
        !           421: {
        !           422:   ipa_hton(ipa);
        !           423:   nl_add_attr(h, bufsize, code, &ipa, sizeof(ipa));
        !           424: }
        !           425: 
        !           426: static inline struct rtattr *
        !           427: nl_open_attr(struct nlmsghdr *h, uint bufsize, uint code)
        !           428: {
        !           429:   return nl_add_attr(h, bufsize, code, NULL, 0);
        !           430: }
        !           431: 
        !           432: static inline void
        !           433: nl_close_attr(struct nlmsghdr *h, struct rtattr *a)
        !           434: {
        !           435:   a->rta_len = (void *)h + NLMSG_ALIGN(h->nlmsg_len) - (void *)a;
        !           436: }
        !           437: 
        !           438: static inline struct rtnexthop *
        !           439: nl_open_nexthop(struct nlmsghdr *h, uint bufsize)
        !           440: {
        !           441:   uint pos = NLMSG_ALIGN(h->nlmsg_len);
        !           442:   uint len = RTNH_LENGTH(0);
        !           443: 
        !           444:   if (pos + len > bufsize)
        !           445:     bug("nl_open_nexthop: packet buffer overflow");
        !           446: 
        !           447:   h->nlmsg_len = pos + len;
        !           448: 
        !           449:   return (void *)h + pos;
        !           450: }
        !           451: 
        !           452: static inline void
        !           453: nl_close_nexthop(struct nlmsghdr *h, struct rtnexthop *nh)
        !           454: {
        !           455:   nh->rtnh_len = (void *)h + NLMSG_ALIGN(h->nlmsg_len) - (void *)nh;
        !           456: }
        !           457: 
        !           458: static void
        !           459: nl_add_multipath(struct nlmsghdr *h, unsigned bufsize, struct mpnh *nh)
        !           460: {
        !           461:   struct rtattr *a = nl_open_attr(h, bufsize, RTA_MULTIPATH);
        !           462: 
        !           463:   for (; nh; nh = nh->next)
        !           464:   {
        !           465:     struct rtnexthop *rtnh = nl_open_nexthop(h, bufsize);
        !           466: 
        !           467:     rtnh->rtnh_flags = 0;
        !           468:     rtnh->rtnh_hops = nh->weight;
        !           469:     rtnh->rtnh_ifindex = nh->iface->index;
        !           470: 
        !           471:     nl_add_attr_ipa(h, bufsize, RTA_GATEWAY, nh->gw);
        !           472: 
        !           473:     nl_close_nexthop(h, rtnh);
        !           474:   }
        !           475: 
        !           476:   nl_close_attr(h, a);
        !           477: }
        !           478: 
        !           479: static struct mpnh *
        !           480: nl_parse_multipath(struct krt_proto *p, struct rtattr *ra)
        !           481: {
        !           482:   /* Temporary buffer for multicast nexthops */
        !           483:   static struct mpnh *nh_buffer;
        !           484:   static int nh_buf_size;      /* in number of structures */
        !           485:   static int nh_buf_used;
        !           486: 
        !           487:   struct rtattr *a[BIRD_RTA_MAX];
        !           488:   struct rtnexthop *nh = RTA_DATA(ra);
        !           489:   struct mpnh *rv, *first, **last;
        !           490:   unsigned len = RTA_PAYLOAD(ra);
        !           491: 
        !           492:   first = NULL;
        !           493:   last = &first;
        !           494:   nh_buf_used = 0;
        !           495: 
        !           496:   while (len)
        !           497:     {
        !           498:       /* Use RTNH_OK(nh,len) ?? */
        !           499:       if ((len < sizeof(*nh)) || (len < nh->rtnh_len))
        !           500:        return NULL;
        !           501: 
        !           502:       if (nh_buf_used == nh_buf_size)
        !           503:       {
        !           504:        nh_buf_size = nh_buf_size ? (nh_buf_size * 2) : 4;
        !           505:        nh_buffer = xrealloc(nh_buffer, nh_buf_size * sizeof(struct mpnh));
        !           506:       }
        !           507:       *last = rv = nh_buffer + nh_buf_used++;
        !           508:       rv->next = NULL;
        !           509:       last = &(rv->next);
        !           510: 
        !           511:       rv->weight = nh->rtnh_hops;
        !           512:       rv->iface = if_find_by_index(nh->rtnh_ifindex);
        !           513:       if (!rv->iface)
        !           514:        return NULL;
        !           515: 
        !           516:       /* Nonexistent RTNH_PAYLOAD ?? */
        !           517:       nl_attr_len = nh->rtnh_len - RTNH_LENGTH(0);
        !           518:       nl_parse_attrs(RTNH_DATA(nh), mpnh_attr_want4, a, sizeof(a));
        !           519:       if (a[RTA_GATEWAY])
        !           520:        {
        !           521:          memcpy(&rv->gw, RTA_DATA(a[RTA_GATEWAY]), sizeof(ip_addr));
        !           522:          ipa_ntoh(rv->gw);
        !           523: 
        !           524:          neighbor *ng = neigh_find2(&p->p, &rv->gw, rv->iface,
        !           525:                                     (nh->rtnh_flags & RTNH_F_ONLINK) ? NEF_ONLINK : 0);
        !           526:          if (!ng || (ng->scope == SCOPE_HOST))
        !           527:            return NULL;
        !           528:        }
        !           529:       else
        !           530:        return NULL;
        !           531: 
        !           532:       len -= NLMSG_ALIGN(nh->rtnh_len);
        !           533:       nh = RTNH_NEXT(nh);
        !           534:     }
        !           535: 
        !           536:   return first;
        !           537: }
        !           538: 
        !           539: static void
        !           540: nl_add_metrics(struct nlmsghdr *h, uint bufsize, u32 *metrics, int max)
        !           541: {
        !           542:   struct rtattr *a = nl_open_attr(h, bufsize, RTA_METRICS);
        !           543:   int t;
        !           544: 
        !           545:   for (t = 1; t < max; t++)
        !           546:     if (metrics[0] & (1 << t))
        !           547:       nl_add_attr_u32(h, bufsize, t, metrics[t]);
        !           548: 
        !           549:   nl_close_attr(h, a);
        !           550: }
        !           551: 
        !           552: static int
        !           553: nl_parse_metrics(struct rtattr *hdr, u32 *metrics, int max)
        !           554: {
        !           555:   struct rtattr *a = RTA_DATA(hdr);
        !           556:   int len = RTA_PAYLOAD(hdr);
        !           557: 
        !           558:   metrics[0] = 0;
        !           559:   for (; RTA_OK(a, len); a = RTA_NEXT(a, len))
        !           560:   {
        !           561:     if (a->rta_type == RTA_UNSPEC)
        !           562:       continue;
        !           563: 
        !           564:     if (a->rta_type >= max)
        !           565:       continue;
        !           566: 
        !           567:     if (RTA_PAYLOAD(a) != 4)
        !           568:       return -1;
        !           569: 
        !           570:     metrics[0] |= 1 << a->rta_type;
        !           571:     metrics[a->rta_type] = rta_get_u32(a);
        !           572:   }
        !           573: 
        !           574:   if (len > 0)
        !           575:     return -1;
        !           576: 
        !           577:   return 0;
        !           578: }
        !           579: 
        !           580: 
        !           581: /*
        !           582:  *     Scanning of interfaces
        !           583:  */
        !           584: 
        !           585: static void
        !           586: nl_parse_link(struct nlmsghdr *h, int scan)
        !           587: {
        !           588:   struct ifinfomsg *i;
        !           589:   struct rtattr *a[BIRD_IFLA_MAX];
        !           590:   int new = h->nlmsg_type == RTM_NEWLINK;
        !           591:   struct iface f = {};
        !           592:   struct iface *ifi;
        !           593:   char *name;
        !           594:   u32 mtu;
        !           595:   uint fl;
        !           596: 
        !           597:   if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(IFLA_RTA(i), ifla_attr_want, a, sizeof(a)))
        !           598:     return;
        !           599:   if (!a[IFLA_IFNAME] || (RTA_PAYLOAD(a[IFLA_IFNAME]) < 2) || !a[IFLA_MTU])
        !           600:     {
        !           601:       /*
        !           602:        * IFLA_IFNAME and IFLA_MTU are required, in fact, but there may also come
        !           603:        * a message with IFLA_WIRELESS set, where (e.g.) no IFLA_IFNAME exists.
        !           604:        * We simply ignore all such messages with IFLA_WIRELESS without notice.
        !           605:        */
        !           606: 
        !           607:       if (a[IFLA_WIRELESS])
        !           608:        return;
        !           609: 
        !           610:       log(L_ERR "KIF: Malformed message received");
        !           611:       return;
        !           612:     }
        !           613: 
        !           614:   name = RTA_DATA(a[IFLA_IFNAME]);
        !           615:   mtu = rta_get_u32(a[IFLA_MTU]);
        !           616: 
        !           617:   ifi = if_find_by_index(i->ifi_index);
        !           618:   if (!new)
        !           619:     {
        !           620:       DBG("KIF: IF%d(%s) goes down\n", i->ifi_index, name);
        !           621:       if (!ifi)
        !           622:        return;
        !           623: 
        !           624:       if_delete(ifi);
        !           625:     }
        !           626:   else
        !           627:     {
        !           628:       DBG("KIF: IF%d(%s) goes up (mtu=%d,flg=%x)\n", i->ifi_index, name, mtu, i->ifi_flags);
        !           629:       if (ifi && strncmp(ifi->name, name, sizeof(ifi->name)-1))
        !           630:        if_delete(ifi);
        !           631: 
        !           632:       strncpy(f.name, name, sizeof(f.name)-1);
        !           633:       f.index = i->ifi_index;
        !           634:       f.mtu = mtu;
        !           635: 
        !           636:       fl = i->ifi_flags;
        !           637:       if (fl & IFF_UP)
        !           638:        f.flags |= IF_ADMIN_UP;
        !           639:       if (fl & IFF_LOWER_UP)
        !           640:        f.flags |= IF_LINK_UP;
        !           641:       if (fl & IFF_LOOPBACK)           /* Loopback */
        !           642:        f.flags |= IF_MULTIACCESS | IF_LOOPBACK | IF_IGNORE;
        !           643:       else if (fl & IFF_POINTOPOINT)   /* PtP */
        !           644:        f.flags |= IF_MULTICAST;
        !           645:       else if (fl & IFF_BROADCAST)     /* Broadcast */
        !           646:        f.flags |= IF_MULTIACCESS | IF_BROADCAST | IF_MULTICAST;
        !           647:       else
        !           648:        f.flags |= IF_MULTIACCESS;      /* NBMA */
        !           649: 
        !           650:       if (fl & IFF_MULTICAST)
        !           651:        f.flags |= IF_MULTICAST;
        !           652: 
        !           653:       ifi = if_update(&f);
        !           654: 
        !           655:       if (!scan)
        !           656:        if_end_partial_update(ifi);
        !           657:     }
        !           658: }
        !           659: 
        !           660: static void
        !           661: nl_parse_addr(struct nlmsghdr *h, int scan)
        !           662: {
        !           663:   struct ifaddrmsg *i;
        !           664:   struct rtattr *a[BIRD_IFA_MAX];
        !           665:   int new = h->nlmsg_type == RTM_NEWADDR;
        !           666:   struct ifa ifa;
        !           667:   struct iface *ifi;
        !           668:   int scope;
        !           669:   u32 ifa_flags;
        !           670: 
        !           671:   if (!(i = nl_checkin(h, sizeof(*i))))
        !           672:     return;
        !           673: 
        !           674:   switch (i->ifa_family)
        !           675:     {
        !           676: #ifndef IPV6
        !           677:       case AF_INET:
        !           678:        if (!nl_parse_attrs(IFA_RTA(i), ifa_attr_want4, a, sizeof(a)))
        !           679:          return;
        !           680:        if (!a[IFA_LOCAL])
        !           681:          {
        !           682:            log(L_ERR "KIF: Malformed message received (missing IFA_LOCAL)");
        !           683:            return;
        !           684:          }
        !           685:        break;
        !           686: #else
        !           687:       case AF_INET6:
        !           688:        if (!nl_parse_attrs(IFA_RTA(i), ifa_attr_want6, a, sizeof(a)))
        !           689:          return;
        !           690:        break;
        !           691: #endif
        !           692:       default:
        !           693:        return;
        !           694:     }
        !           695: 
        !           696:   if (!a[IFA_ADDRESS])
        !           697:     {
        !           698:       log(L_ERR "KIF: Malformed message received (missing IFA_ADDRESS)");
        !           699:       return;
        !           700:     }
        !           701: 
        !           702:   if (a[IFA_FLAGS])
        !           703:     ifa_flags = rta_get_u32(a[IFA_FLAGS]);
        !           704:   else
        !           705:     ifa_flags = i->ifa_flags;
        !           706: 
        !           707:   ifi = if_find_by_index(i->ifa_index);
        !           708:   if (!ifi)
        !           709:     {
        !           710:       log(L_ERR "KIF: Received address message for unknown interface %d", i->ifa_index);
        !           711:       return;
        !           712:     }
        !           713: 
        !           714:   bzero(&ifa, sizeof(ifa));
        !           715:   ifa.iface = ifi;
        !           716:   if (ifa_flags & IFA_F_SECONDARY)
        !           717:     ifa.flags |= IA_SECONDARY;
        !           718: 
        !           719: #ifdef IPV6
        !           720:   /* Ignore tentative addresses silently */
        !           721:   if (ifa_flags & IFA_F_TENTATIVE)
        !           722:     return;
        !           723: #endif
        !           724: 
        !           725:   /* IFA_LOCAL can be unset for IPv6 interfaces */
        !           726:   memcpy(&ifa.ip, RTA_DATA(a[IFA_LOCAL] ? : a[IFA_ADDRESS]), sizeof(ifa.ip));
        !           727:   ipa_ntoh(ifa.ip);
        !           728:   ifa.pxlen = i->ifa_prefixlen;
        !           729:   if (i->ifa_prefixlen > BITS_PER_IP_ADDRESS)
        !           730:     {
        !           731:       log(L_ERR "KIF: Invalid prefix length for interface %s: %d", ifi->name, i->ifa_prefixlen);
        !           732:       new = 0;
        !           733:     }
        !           734:   if (i->ifa_prefixlen == BITS_PER_IP_ADDRESS)
        !           735:     {
        !           736:       ip_addr addr;
        !           737:       memcpy(&addr, RTA_DATA(a[IFA_ADDRESS]), sizeof(addr));
        !           738:       ipa_ntoh(addr);
        !           739:       ifa.prefix = ifa.brd = addr;
        !           740: 
        !           741:       /* It is either a host address or a peer address */
        !           742:       if (ipa_equal(ifa.ip, addr))
        !           743:        ifa.flags |= IA_HOST;
        !           744:       else
        !           745:        {
        !           746:          ifa.flags |= IA_PEER;
        !           747:          ifa.opposite = addr;
        !           748:        }
        !           749:     }
        !           750:   else
        !           751:     {
        !           752:       ip_addr netmask = ipa_mkmask(ifa.pxlen);
        !           753:       ifa.prefix = ipa_and(ifa.ip, netmask);
        !           754:       ifa.brd = ipa_or(ifa.ip, ipa_not(netmask));
        !           755:       if (i->ifa_prefixlen == BITS_PER_IP_ADDRESS - 1)
        !           756:        ifa.opposite = ipa_opposite_m1(ifa.ip);
        !           757: 
        !           758: #ifndef IPV6
        !           759:       if (i->ifa_prefixlen == BITS_PER_IP_ADDRESS - 2)
        !           760:        ifa.opposite = ipa_opposite_m2(ifa.ip);
        !           761: 
        !           762:       if ((ifi->flags & IF_BROADCAST) && a[IFA_BROADCAST])
        !           763:        {
        !           764:          ip_addr xbrd;
        !           765:          memcpy(&xbrd, RTA_DATA(a[IFA_BROADCAST]), sizeof(xbrd));
        !           766:          ipa_ntoh(xbrd);
        !           767:          if (ipa_equal(xbrd, ifa.prefix) || ipa_equal(xbrd, ifa.brd))
        !           768:            ifa.brd = xbrd;
        !           769:          else if (ifi->flags & IF_TMP_DOWN) /* Complain only during the first scan */
        !           770:            log(L_ERR "KIF: Invalid broadcast address %I for %s", xbrd, ifi->name);
        !           771:        }
        !           772: #endif
        !           773:     }
        !           774: 
        !           775:   scope = ipa_classify(ifa.ip);
        !           776:   if (scope < 0)
        !           777:     {
        !           778:       log(L_ERR "KIF: Invalid interface address %I for %s", ifa.ip, ifi->name);
        !           779:       return;
        !           780:     }
        !           781:   ifa.scope = scope & IADDR_SCOPE_MASK;
        !           782: 
        !           783:   DBG("KIF: IF%d(%s): %s IPA %I, flg %x, net %I/%d, brd %I, opp %I\n",
        !           784:       ifi->index, ifi->name,
        !           785:       new ? "added" : "removed",
        !           786:       ifa.ip, ifa.flags, ifa.prefix, ifa.pxlen, ifa.brd, ifa.opposite);
        !           787: 
        !           788:   if (new)
        !           789:     ifa_update(&ifa);
        !           790:   else
        !           791:     ifa_delete(&ifa);
        !           792: 
        !           793:   if (!scan)
        !           794:     if_end_partial_update(ifi);
        !           795: }
        !           796: 
        !           797: void
        !           798: kif_do_scan(struct kif_proto *p UNUSED)
        !           799: {
        !           800:   struct nlmsghdr *h;
        !           801: 
        !           802:   if_start_update();
        !           803: 
        !           804:   nl_request_dump(AF_UNSPEC, RTM_GETLINK);
        !           805:   while (h = nl_get_scan())
        !           806:     if (h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)
        !           807:       nl_parse_link(h, 1);
        !           808:     else
        !           809:       log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type);
        !           810: 
        !           811:   nl_request_dump(BIRD_AF, RTM_GETADDR);
        !           812:   while (h = nl_get_scan())
        !           813:     if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
        !           814:       nl_parse_addr(h, 1);
        !           815:     else
        !           816:       log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type);
        !           817: 
        !           818:   if_end_update();
        !           819: }
        !           820: 
        !           821: /*
        !           822:  *     Routes
        !           823:  */
        !           824: 
        !           825: static inline u32
        !           826: krt_table_id(struct krt_proto *p)
        !           827: {
        !           828:   return KRT_CF->sys.table_id;
        !           829: }
        !           830: 
        !           831: static HASH(struct krt_proto) nl_table_map;
        !           832: 
        !           833: #define RTH_FN(k)      u32_hash(k)
        !           834: #define RTH_EQ(k1,k2)  k1 == k2
        !           835: #define RTH_KEY(p)     krt_table_id(p)
        !           836: #define RTH_NEXT(p)    p->sys.hash_next
        !           837: 
        !           838: #define RTH_REHASH             rth_rehash
        !           839: #define RTH_PARAMS             /8, *2, 2, 2, 6, 20
        !           840: 
        !           841: HASH_DEFINE_REHASH_FN(RTH, struct krt_proto)
        !           842: 
        !           843: int
        !           844: krt_capable(rte *e)
        !           845: {
        !           846:   rta *a = e->attrs;
        !           847: 
        !           848:   if (a->cast != RTC_UNICAST)
        !           849:     return 0;
        !           850: 
        !           851:   switch (a->dest)
        !           852:     {
        !           853:     case RTD_ROUTER:
        !           854:     case RTD_DEVICE:
        !           855:       if (a->iface == NULL)
        !           856:        return 0;
        !           857:     case RTD_BLACKHOLE:
        !           858:     case RTD_UNREACHABLE:
        !           859:     case RTD_PROHIBIT:
        !           860:     case RTD_MULTIPATH:
        !           861:       break;
        !           862:     default:
        !           863:       return 0;
        !           864:     }
        !           865:   return 1;
        !           866: }
        !           867: 
        !           868: static inline int
        !           869: nh_bufsize(struct mpnh *nh)
        !           870: {
        !           871:   int rv = 0;
        !           872:   for (; nh != NULL; nh = nh->next)
        !           873:     rv += RTNH_LENGTH(RTA_LENGTH(sizeof(ip_addr)));
        !           874:   return rv;
        !           875: }
        !           876: 
        !           877: static int
        !           878: nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int op, int dest, ip_addr gw, struct iface *iface)
        !           879: {
        !           880:   eattr *ea;
        !           881:   net *net = e->net;
        !           882:   rta *a = e->attrs;
        !           883:   u32 priority = 0;
        !           884: 
        !           885:   struct {
        !           886:     struct nlmsghdr h;
        !           887:     struct rtmsg r;
        !           888:     char buf[128 + KRT_METRICS_MAX*8 + nh_bufsize(a->nexthops)];
        !           889:   } r;
        !           890: 
        !           891:   DBG("nl_send_route(%I/%d,op=%x)\n", net->n.prefix, net->n.pxlen, op);
        !           892: 
        !           893:   bzero(&r.h, sizeof(r.h));
        !           894:   bzero(&r.r, sizeof(r.r));
        !           895:   r.h.nlmsg_type = op ? RTM_NEWROUTE : RTM_DELROUTE;
        !           896:   r.h.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
        !           897:   r.h.nlmsg_flags = op | NLM_F_REQUEST | NLM_F_ACK;
        !           898: 
        !           899:   r.r.rtm_family = BIRD_AF;
        !           900:   r.r.rtm_dst_len = net->n.pxlen;
        !           901:   r.r.rtm_protocol = RTPROT_BIRD;
        !           902:   r.r.rtm_scope = RT_SCOPE_NOWHERE;
        !           903:   nl_add_attr_ipa(&r.h, sizeof(r), RTA_DST, net->n.prefix);
        !           904: 
        !           905:   /*
        !           906:    * Strange behavior for RTM_DELROUTE:
        !           907:    * 1) rtm_family is ignored in IPv6, works for IPv4
        !           908:    * 2) not setting RTA_PRIORITY is different from setting default value (on IPv6)
        !           909:    * 3) not setting RTA_PRIORITY is equivalent to setting 0, which is wildcard
        !           910:    */
        !           911: 
        !           912:   if (krt_table_id(p) < 256)
        !           913:     r.r.rtm_table = krt_table_id(p);
        !           914:   else
        !           915:     nl_add_attr_u32(&r.h, sizeof(r), RTA_TABLE, krt_table_id(p));
        !           916: 
        !           917:   if (a->source == RTS_DUMMY)
        !           918:     priority = e->u.krt.metric;
        !           919:   else if (KRT_CF->sys.metric)
        !           920:     priority = KRT_CF->sys.metric;
        !           921:   else if ((op != NL_OP_DELETE) && (ea = ea_find(eattrs, EA_KRT_METRIC)))
        !           922:     priority = ea->u.data;
        !           923: 
        !           924:   if (priority)
        !           925:     nl_add_attr_u32(&r.h, sizeof(r), RTA_PRIORITY, priority);
        !           926: 
        !           927:   /* For route delete, we do not specify remaining route attributes */
        !           928:   if (op == NL_OP_DELETE)
        !           929:     goto dest;
        !           930: 
        !           931:   /* Default scope is LINK for device routes, UNIVERSE otherwise */
        !           932:   if (ea = ea_find(eattrs, EA_KRT_SCOPE))
        !           933:     r.r.rtm_scope = ea->u.data;
        !           934:   else
        !           935:     r.r.rtm_scope = (dest == RTD_DEVICE) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE;
        !           936: 
        !           937:   if (ea = ea_find(eattrs, EA_KRT_PREFSRC))
        !           938:     nl_add_attr_ipa(&r.h, sizeof(r), RTA_PREFSRC, *(ip_addr *)ea->u.ptr->data);
        !           939: 
        !           940:   if (ea = ea_find(eattrs, EA_KRT_REALM))
        !           941:     nl_add_attr_u32(&r.h, sizeof(r), RTA_FLOW, ea->u.data);
        !           942: 
        !           943: 
        !           944:   u32 metrics[KRT_METRICS_MAX];
        !           945:   metrics[0] = 0;
        !           946: 
        !           947:   struct ea_walk_state ews = { .eattrs = eattrs };
        !           948:   while (ea = ea_walk(&ews, EA_KRT_METRICS, KRT_METRICS_MAX))
        !           949:   {
        !           950:     int id = ea->id - EA_KRT_METRICS;
        !           951:     metrics[0] |= 1 << id;
        !           952:     metrics[id] = ea->u.data;
        !           953:   }
        !           954: 
        !           955:   if (metrics[0])
        !           956:     nl_add_metrics(&r.h, sizeof(r), metrics, KRT_METRICS_MAX);
        !           957: 
        !           958: 
        !           959: dest:
        !           960:   /* a->iface != NULL checked in krt_capable() for router and device routes */
        !           961:   switch (dest)
        !           962:     {
        !           963:     case RTD_ROUTER:
        !           964:       r.r.rtm_type = RTN_UNICAST;
        !           965:       nl_add_attr_u32(&r.h, sizeof(r), RTA_OIF, iface->index);
        !           966:       nl_add_attr_ipa(&r.h, sizeof(r), RTA_GATEWAY, gw);
        !           967:       break;
        !           968:     case RTD_DEVICE:
        !           969:       r.r.rtm_type = RTN_UNICAST;
        !           970:       nl_add_attr_u32(&r.h, sizeof(r), RTA_OIF, iface->index);
        !           971:       break;
        !           972:     case RTD_BLACKHOLE:
        !           973:       r.r.rtm_type = RTN_BLACKHOLE;
        !           974:       break;
        !           975:     case RTD_UNREACHABLE:
        !           976:       r.r.rtm_type = RTN_UNREACHABLE;
        !           977:       break;
        !           978:     case RTD_PROHIBIT:
        !           979:       r.r.rtm_type = RTN_PROHIBIT;
        !           980:       break;
        !           981:     case RTD_MULTIPATH:
        !           982:       r.r.rtm_type = RTN_UNICAST;
        !           983:       nl_add_multipath(&r.h, sizeof(r), a->nexthops);
        !           984:       break;
        !           985:     case RTD_NONE:
        !           986:       break;
        !           987:     default:
        !           988:       bug("krt_capable inconsistent with nl_send_route");
        !           989:     }
        !           990: 
        !           991:   /* Ignore missing for DELETE */
        !           992:   return nl_exchange(&r.h, (op == NL_OP_DELETE));
        !           993: }
        !           994: 
        !           995: static inline int
        !           996: nl_add_rte(struct krt_proto *p, rte *e, struct ea_list *eattrs)
        !           997: {
        !           998:   rta *a = e->attrs;
        !           999:   int err = 0;
        !          1000: 
        !          1001:   if (krt_ecmp6(p) && (a->dest == RTD_MULTIPATH))
        !          1002:   {
        !          1003:     struct mpnh *nh = a->nexthops;
        !          1004: 
        !          1005:     err = nl_send_route(p, e, eattrs, NL_OP_ADD, RTD_ROUTER, nh->gw, nh->iface);
        !          1006:     if (err < 0)
        !          1007:       return err;
        !          1008: 
        !          1009:     for (nh = nh->next; nh; nh = nh->next)
        !          1010:       err += nl_send_route(p, e, eattrs, NL_OP_APPEND, RTD_ROUTER, nh->gw, nh->iface);
        !          1011: 
        !          1012:     return err;
        !          1013:   }
        !          1014: 
        !          1015:   return nl_send_route(p, e, eattrs, NL_OP_ADD, a->dest, a->gw, a->iface);
        !          1016: }
        !          1017: 
        !          1018: static inline int
        !          1019: nl_delete_rte(struct krt_proto *p, rte *e, struct ea_list *eattrs)
        !          1020: {
        !          1021:   int err = 0;
        !          1022: 
        !          1023:   /* For IPv6, we just repeatedly request DELETE until we get error */
        !          1024:   do
        !          1025:     err = nl_send_route(p, e, eattrs, NL_OP_DELETE, RTD_NONE, IPA_NONE, NULL);
        !          1026:   while (krt_ecmp6(p) && !err);
        !          1027: 
        !          1028:   return err;
        !          1029: }
        !          1030: 
        !          1031: void
        !          1032: krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old, struct ea_list *eattrs)
        !          1033: {
        !          1034:   int err = 0;
        !          1035: 
        !          1036:   /*
        !          1037:    * We could use NL_OP_REPLACE, but route replace on Linux has some problems:
        !          1038:    *
        !          1039:    * 1) Does not check for matching rtm_protocol
        !          1040:    * 2) Has broken semantics for IPv6 ECMP
        !          1041:    * 3) Crashes some kernel version when used for IPv6 ECMP
        !          1042:    *
        !          1043:    * So we use NL_OP_DELETE and then NL_OP_ADD. We also do not trust the old
        !          1044:    * route value, so we do not try to optimize IPv6 ECMP reconfigurations.
        !          1045:    */
        !          1046: 
        !          1047:   if (old)
        !          1048:     nl_delete_rte(p, old, eattrs);
        !          1049: 
        !          1050:   if (new)
        !          1051:     err = nl_add_rte(p, new, eattrs);
        !          1052: 
        !          1053:   if (err < 0)
        !          1054:     n->n.flags |= KRF_SYNC_ERROR;
        !          1055:   else
        !          1056:     n->n.flags &= ~KRF_SYNC_ERROR;
        !          1057: }
        !          1058: 
        !          1059: 
        !          1060: static inline struct mpnh *
        !          1061: nl_alloc_mpnh(struct nl_parse_state *s, ip_addr gw, struct iface *iface, byte weight)
        !          1062: {
        !          1063:   struct mpnh *nh = lp_alloc(s->pool, sizeof(struct mpnh));
        !          1064: 
        !          1065:   nh->gw = gw;
        !          1066:   nh->iface = iface;
        !          1067:   nh->next = NULL;
        !          1068:   nh->weight = weight;
        !          1069: 
        !          1070:   return nh;
        !          1071: }
        !          1072: 
        !          1073: static int
        !          1074: nl_mergable_route(struct nl_parse_state *s, net *net, struct krt_proto *p, uint priority, uint krt_type)
        !          1075: {
        !          1076:   /* Route merging must be active */
        !          1077:   if (!s->merge)
        !          1078:     return 0;
        !          1079: 
        !          1080:   /* Saved and new route must have same network, proto/table, and priority */
        !          1081:   if ((s->net != net) || (s->proto != p) || (s->krt_metric != priority))
        !          1082:     return 0;
        !          1083: 
        !          1084:   /* Both must be regular unicast routes */
        !          1085:   if ((s->krt_type != RTN_UNICAST) || (krt_type != RTN_UNICAST))
        !          1086:     return 0;
        !          1087: 
        !          1088:   return 1;
        !          1089: }
        !          1090: 
        !          1091: static void
        !          1092: nl_announce_route(struct nl_parse_state *s)
        !          1093: {
        !          1094:   rte *e = rte_get_temp(s->attrs);
        !          1095:   e->net = s->net;
        !          1096:   e->u.krt.src = s->krt_src;
        !          1097:   e->u.krt.proto = s->krt_proto;
        !          1098:   e->u.krt.seen = 0;
        !          1099:   e->u.krt.best = 0;
        !          1100:   e->u.krt.metric = s->krt_metric;
        !          1101: 
        !          1102:   if (s->scan)
        !          1103:     krt_got_route(s->proto, e);
        !          1104:   else
        !          1105:     krt_got_route_async(s->proto, e, s->new);
        !          1106: 
        !          1107:   s->net = NULL;
        !          1108:   s->attrs = NULL;
        !          1109:   s->proto = NULL;
        !          1110:   lp_flush(s->pool);
        !          1111: }
        !          1112: 
        !          1113: static inline void
        !          1114: nl_parse_begin(struct nl_parse_state *s, int scan, int merge)
        !          1115: {
        !          1116:   memset(s, 0, sizeof (struct nl_parse_state));
        !          1117:   s->pool = nl_linpool;
        !          1118:   s->scan = scan;
        !          1119:   s->merge = merge;
        !          1120: }
        !          1121: 
        !          1122: static inline void
        !          1123: nl_parse_end(struct nl_parse_state *s)
        !          1124: {
        !          1125:   if (s->net)
        !          1126:     nl_announce_route(s);
        !          1127: }
        !          1128: 
        !          1129: 
        !          1130: #define SKIP(ARG...) do { DBG("KRT: Ignoring route - " ARG); return; } while(0)
        !          1131: 
        !          1132: static void
        !          1133: nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
        !          1134: {
        !          1135:   struct krt_proto *p;
        !          1136:   struct rtmsg *i;
        !          1137:   struct rtattr *a[BIRD_RTA_MAX];
        !          1138:   int new = h->nlmsg_type == RTM_NEWROUTE;
        !          1139: 
        !          1140:   ip_addr dst = IPA_NONE;
        !          1141:   u32 oif = ~0;
        !          1142:   u32 table;
        !          1143:   u32 priority = 0;
        !          1144:   u32 def_scope = RT_SCOPE_UNIVERSE;
        !          1145:   int src;
        !          1146: 
        !          1147:   if (!(i = nl_checkin(h, sizeof(*i))))
        !          1148:     return;
        !          1149: 
        !          1150:   switch (i->rtm_family)
        !          1151:     {
        !          1152: #ifndef IPV6
        !          1153:       case AF_INET:
        !          1154:        if (!nl_parse_attrs(RTM_RTA(i), rtm_attr_want4, a, sizeof(a)))
        !          1155:          return;
        !          1156:        break;
        !          1157: #else
        !          1158:       case AF_INET6:
        !          1159:        if (!nl_parse_attrs(RTM_RTA(i), rtm_attr_want6, a, sizeof(a)))
        !          1160:          return;
        !          1161:        break;
        !          1162: #endif
        !          1163:       default:
        !          1164:        return;
        !          1165:     }
        !          1166: 
        !          1167:   if (a[RTA_DST])
        !          1168:     {
        !          1169:       memcpy(&dst, RTA_DATA(a[RTA_DST]), sizeof(dst));
        !          1170:       ipa_ntoh(dst);
        !          1171:     }
        !          1172: 
        !          1173:   if (a[RTA_OIF])
        !          1174:     oif = rta_get_u32(a[RTA_OIF]);
        !          1175: 
        !          1176:   if (a[RTA_TABLE])
        !          1177:     table = rta_get_u32(a[RTA_TABLE]);
        !          1178:   else
        !          1179:     table = i->rtm_table;
        !          1180: 
        !          1181:   p = HASH_FIND(nl_table_map, RTH, table); /* Do we know this table? */
        !          1182:   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, table, i->rtm_protocol, p ? p->p.name : "(none)");
        !          1183:   if (!p)
        !          1184:     SKIP("unknown table %d\n", table);
        !          1185: 
        !          1186: #ifdef IPV6
        !          1187:   if (a[RTA_IIF])
        !          1188:     SKIP("IIF set\n");
        !          1189: #else
        !          1190:   if (i->rtm_tos != 0)                 /* We don't support TOS */
        !          1191:     SKIP("TOS %02x\n", i->rtm_tos);
        !          1192: #endif
        !          1193: 
        !          1194:   if (s->scan && !new)
        !          1195:     SKIP("RTM_DELROUTE in scan\n");
        !          1196: 
        !          1197:   if (a[RTA_PRIORITY])
        !          1198:     priority = rta_get_u32(a[RTA_PRIORITY]);
        !          1199: 
        !          1200:   int c = ipa_classify_net(dst);
        !          1201:   if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
        !          1202:     SKIP("strange class/scope\n");
        !          1203: 
        !          1204:   switch (i->rtm_protocol)
        !          1205:     {
        !          1206:     case RTPROT_UNSPEC:
        !          1207:       SKIP("proto unspec\n");
        !          1208: 
        !          1209:     case RTPROT_REDIRECT:
        !          1210:       src = KRT_SRC_REDIRECT;
        !          1211:       break;
        !          1212: 
        !          1213:     case RTPROT_KERNEL:
        !          1214:       src = KRT_SRC_KERNEL;
        !          1215:       return;
        !          1216: 
        !          1217:     case RTPROT_BIRD:
        !          1218:       if (!s->scan)
        !          1219:        SKIP("echo\n");
        !          1220:       src = KRT_SRC_BIRD;
        !          1221:       break;
        !          1222: 
        !          1223:     case RTPROT_BOOT:
        !          1224:     default:
        !          1225:       src = KRT_SRC_ALIEN;
        !          1226:     }
        !          1227: 
        !          1228:   net *net = net_get(p->p.table, dst, i->rtm_dst_len);
        !          1229: 
        !          1230:   if (s->net && !nl_mergable_route(s, net, p, priority, i->rtm_type))
        !          1231:     nl_announce_route(s);
        !          1232: 
        !          1233:   rta *ra = lp_allocz(s->pool, sizeof(rta));
        !          1234:   ra->src = p->p.main_source;
        !          1235:   ra->source = RTS_INHERIT;
        !          1236:   ra->scope = SCOPE_UNIVERSE;
        !          1237:   ra->cast = RTC_UNICAST;
        !          1238: 
        !          1239:   switch (i->rtm_type)
        !          1240:     {
        !          1241:     case RTN_UNICAST:
        !          1242: 
        !          1243:       if (a[RTA_MULTIPATH] && (i->rtm_family == AF_INET))
        !          1244:        {
        !          1245:          ra->dest = RTD_MULTIPATH;
        !          1246:          ra->nexthops = nl_parse_multipath(p, a[RTA_MULTIPATH]);
        !          1247:          if (!ra->nexthops)
        !          1248:            {
        !          1249:              log(L_ERR "KRT: Received strange multipath route %I/%d",
        !          1250:                  net->n.prefix, net->n.pxlen);
        !          1251:              return;
        !          1252:            }
        !          1253: 
        !          1254:          break;
        !          1255:        }
        !          1256: 
        !          1257:       ra->iface = if_find_by_index(oif);
        !          1258:       if (!ra->iface)
        !          1259:        {
        !          1260:          log(L_ERR "KRT: Received route %I/%d with unknown ifindex %u",
        !          1261:              net->n.prefix, net->n.pxlen, oif);
        !          1262:          return;
        !          1263:        }
        !          1264: 
        !          1265:       if (a[RTA_GATEWAY])
        !          1266:        {
        !          1267:          neighbor *ng;
        !          1268:          ra->dest = RTD_ROUTER;
        !          1269:          memcpy(&ra->gw, RTA_DATA(a[RTA_GATEWAY]), sizeof(ra->gw));
        !          1270:          ipa_ntoh(ra->gw);
        !          1271: 
        !          1272: #ifdef IPV6
        !          1273:          /* Silently skip strange 6to4 routes */
        !          1274:          if (ipa_in_net(ra->gw, IPA_NONE, 96))
        !          1275:            return;
        !          1276: #endif
        !          1277: 
        !          1278:          ng = neigh_find2(&p->p, &ra->gw, ra->iface,
        !          1279:                           (i->rtm_flags & RTNH_F_ONLINK) ? NEF_ONLINK : 0);
        !          1280:          if (!ng || (ng->scope == SCOPE_HOST))
        !          1281:            {
        !          1282:              log(L_ERR "KRT: Received route %I/%d with strange next-hop %I",
        !          1283:                  net->n.prefix, net->n.pxlen, ra->gw);
        !          1284:              return;
        !          1285:            }
        !          1286:        }
        !          1287:       else
        !          1288:        {
        !          1289:          ra->dest = RTD_DEVICE;
        !          1290:          def_scope = RT_SCOPE_LINK;
        !          1291:        }
        !          1292: 
        !          1293:       break;
        !          1294:     case RTN_BLACKHOLE:
        !          1295:       ra->dest = RTD_BLACKHOLE;
        !          1296:       break;
        !          1297:     case RTN_UNREACHABLE:
        !          1298:       ra->dest = RTD_UNREACHABLE;
        !          1299:       break;
        !          1300:     case RTN_PROHIBIT:
        !          1301:       ra->dest = RTD_PROHIBIT;
        !          1302:       break;
        !          1303:     /* FIXME: What about RTN_THROW? */
        !          1304:     default:
        !          1305:       SKIP("type %d\n", i->rtm_type);
        !          1306:       return;
        !          1307:     }
        !          1308: 
        !          1309:   if (i->rtm_scope != def_scope)
        !          1310:     {
        !          1311:       ea_list *ea = lp_alloc(s->pool, sizeof(ea_list) + sizeof(eattr));
        !          1312:       ea->next = ra->eattrs;
        !          1313:       ra->eattrs = ea;
        !          1314:       ea->flags = EALF_SORTED;
        !          1315:       ea->count = 1;
        !          1316:       ea->attrs[0].id = EA_KRT_SCOPE;
        !          1317:       ea->attrs[0].flags = 0;
        !          1318:       ea->attrs[0].type = EAF_TYPE_INT;
        !          1319:       ea->attrs[0].u.data = i->rtm_scope;
        !          1320:     }
        !          1321: 
        !          1322:   if (a[RTA_PREFSRC])
        !          1323:     {
        !          1324:       ip_addr ps;
        !          1325:       memcpy(&ps, RTA_DATA(a[RTA_PREFSRC]), sizeof(ps));
        !          1326:       ipa_ntoh(ps);
        !          1327: 
        !          1328:       ea_list *ea = lp_alloc(s->pool, sizeof(ea_list) + sizeof(eattr));
        !          1329:       ea->next = ra->eattrs;
        !          1330:       ra->eattrs = ea;
        !          1331:       ea->flags = EALF_SORTED;
        !          1332:       ea->count = 1;
        !          1333:       ea->attrs[0].id = EA_KRT_PREFSRC;
        !          1334:       ea->attrs[0].flags = 0;
        !          1335:       ea->attrs[0].type = EAF_TYPE_IP_ADDRESS;
        !          1336:       ea->attrs[0].u.ptr = lp_alloc(s->pool, sizeof(struct adata) + sizeof(ps));
        !          1337:       ea->attrs[0].u.ptr->length = sizeof(ps);
        !          1338:       memcpy(ea->attrs[0].u.ptr->data, &ps, sizeof(ps));
        !          1339:     }
        !          1340: 
        !          1341:   if (a[RTA_FLOW])
        !          1342:     {
        !          1343:       ea_list *ea = lp_alloc(s->pool, sizeof(ea_list) + sizeof(eattr));
        !          1344:       ea->next = ra->eattrs;
        !          1345:       ra->eattrs = ea;
        !          1346:       ea->flags = EALF_SORTED;
        !          1347:       ea->count = 1;
        !          1348:       ea->attrs[0].id = EA_KRT_REALM;
        !          1349:       ea->attrs[0].flags = 0;
        !          1350:       ea->attrs[0].type = EAF_TYPE_INT;
        !          1351:       ea->attrs[0].u.data = rta_get_u32(a[RTA_FLOW]);
        !          1352:     }
        !          1353: 
        !          1354:   if (a[RTA_METRICS])
        !          1355:     {
        !          1356:       u32 metrics[KRT_METRICS_MAX];
        !          1357:       ea_list *ea = lp_alloc(s->pool, sizeof(ea_list) + KRT_METRICS_MAX * sizeof(eattr));
        !          1358:       int t, n = 0;
        !          1359: 
        !          1360:       if (nl_parse_metrics(a[RTA_METRICS], metrics, ARRAY_SIZE(metrics)) < 0)
        !          1361:         {
        !          1362:          log(L_ERR "KRT: Received route %I/%d with strange RTA_METRICS attribute",
        !          1363:              net->n.prefix, net->n.pxlen);
        !          1364:          return;
        !          1365:        }
        !          1366: 
        !          1367:       for (t = 1; t < KRT_METRICS_MAX; t++)
        !          1368:        if (metrics[0] & (1 << t))
        !          1369:          {
        !          1370:            ea->attrs[n].id = EA_CODE(EAP_KRT, KRT_METRICS_OFFSET + t);
        !          1371:            ea->attrs[n].flags = 0;
        !          1372:            ea->attrs[n].type = EAF_TYPE_INT; /* FIXME: Some are EAF_TYPE_BITFIELD */
        !          1373:            ea->attrs[n].u.data = metrics[t];
        !          1374:            n++;
        !          1375:          }
        !          1376: 
        !          1377:       if (n > 0)
        !          1378:         {
        !          1379:          ea->next = ra->eattrs;
        !          1380:          ea->flags = EALF_SORTED;
        !          1381:          ea->count = n;
        !          1382:          ra->eattrs = ea;
        !          1383:        }
        !          1384:     }
        !          1385: 
        !          1386:   /*
        !          1387:    * Ideally, now we would send the received route to the rest of kernel code.
        !          1388:    * But IPv6 ECMP routes are sent as a sequence of routes, so we postpone it
        !          1389:    * and merge next hops until the end of the sequence.
        !          1390:    */
        !          1391: 
        !          1392:   if (!s->net)
        !          1393:   {
        !          1394:     /* Store the new route */
        !          1395:     s->net = net;
        !          1396:     s->attrs = ra;
        !          1397:     s->proto = p;
        !          1398:     s->new = new;
        !          1399:     s->krt_src = src;
        !          1400:     s->krt_type = i->rtm_type;
        !          1401:     s->krt_proto = i->rtm_protocol;
        !          1402:     s->krt_metric = priority;
        !          1403:   }
        !          1404:   else
        !          1405:   {
        !          1406:     /* Merge next hops with the stored route */
        !          1407:     rta *a = s->attrs;
        !          1408: 
        !          1409:     if (a->dest != RTD_MULTIPATH)
        !          1410:     {
        !          1411:       a->dest = RTD_MULTIPATH;
        !          1412:       a->nexthops = nl_alloc_mpnh(s, a->gw, a->iface, 0);
        !          1413:     }
        !          1414: 
        !          1415:     mpnh_insert(&a->nexthops, nl_alloc_mpnh(s, ra->gw, ra->iface, 0));
        !          1416:   }
        !          1417: }
        !          1418: 
        !          1419: void
        !          1420: krt_do_scan(struct krt_proto *p UNUSED)        /* CONFIG_ALL_TABLES_AT_ONCE => p is NULL */
        !          1421: {
        !          1422:   struct nlmsghdr *h;
        !          1423:   struct nl_parse_state s;
        !          1424: 
        !          1425:   nl_parse_begin(&s, 1, krt_ecmp6(p));
        !          1426: 
        !          1427:   nl_request_dump(BIRD_AF, RTM_GETROUTE);
        !          1428:   while (h = nl_get_scan())
        !          1429:     if (h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)
        !          1430:       nl_parse_route(&s, h);
        !          1431:     else
        !          1432:       log(L_DEBUG "nl_scan_fire: Unknown packet received (type=%d)", h->nlmsg_type);
        !          1433: 
        !          1434:   nl_parse_end(&s);
        !          1435: }
        !          1436: 
        !          1437: /*
        !          1438:  *     Asynchronous Netlink interface
        !          1439:  */
        !          1440: 
        !          1441: static sock *nl_async_sk;              /* BIRD socket for asynchronous notifications */
        !          1442: static byte *nl_async_rx_buffer;       /* Receive buffer */
        !          1443: 
        !          1444: static void
        !          1445: nl_async_msg(struct nlmsghdr *h)
        !          1446: {
        !          1447:   struct nl_parse_state s;
        !          1448: 
        !          1449:   switch (h->nlmsg_type)
        !          1450:     {
        !          1451:     case RTM_NEWROUTE:
        !          1452:     case RTM_DELROUTE:
        !          1453:       DBG("KRT: Received async route notification (%d)\n", h->nlmsg_type);
        !          1454:       nl_parse_begin(&s, 0, 0);
        !          1455:       nl_parse_route(&s, h);
        !          1456:       nl_parse_end(&s);
        !          1457:       break;
        !          1458:     case RTM_NEWLINK:
        !          1459:     case RTM_DELLINK:
        !          1460:       DBG("KRT: Received async link notification (%d)\n", h->nlmsg_type);
        !          1461:       if (kif_proto)
        !          1462:        nl_parse_link(h, 0);
        !          1463:       break;
        !          1464:     case RTM_NEWADDR:
        !          1465:     case RTM_DELADDR:
        !          1466:       DBG("KRT: Received async address notification (%d)\n", h->nlmsg_type);
        !          1467:       if (kif_proto)
        !          1468:        nl_parse_addr(h, 0);
        !          1469:       break;
        !          1470:     default:
        !          1471:       DBG("KRT: Received unknown async notification (%d)\n", h->nlmsg_type);
        !          1472:     }
        !          1473: }
        !          1474: 
        !          1475: static int
        !          1476: nl_async_hook(sock *sk, uint size UNUSED)
        !          1477: {
        !          1478:   struct iovec iov = { nl_async_rx_buffer, NL_RX_SIZE };
        !          1479:   struct sockaddr_nl sa;
        !          1480:   struct msghdr m = {
        !          1481:     .msg_name = &sa,
        !          1482:     .msg_namelen = sizeof(sa),
        !          1483:     .msg_iov = &iov,
        !          1484:     .msg_iovlen = 1,
        !          1485:   };
        !          1486:   struct nlmsghdr *h;
        !          1487:   int x;
        !          1488:   uint len;
        !          1489: 
        !          1490:   x = recvmsg(sk->fd, &m, 0);
        !          1491:   if (x < 0)
        !          1492:     {
        !          1493:       if (errno == ENOBUFS)
        !          1494:        {
        !          1495:          /*
        !          1496:           *  Netlink reports some packets have been thrown away.
        !          1497:           *  One day we might react to it by asking for route table
        !          1498:           *  scan in near future.
        !          1499:           */
        !          1500:          log(L_WARN "Kernel dropped some netlink messages, will resync on next scan.");
        !          1501:          return 1;     /* More data are likely to be ready */
        !          1502:        }
        !          1503:       else if (errno != EWOULDBLOCK)
        !          1504:        log(L_ERR "Netlink recvmsg: %m");
        !          1505:       return 0;
        !          1506:     }
        !          1507:   if (sa.nl_pid)               /* It isn't from the kernel */
        !          1508:     {
        !          1509:       DBG("Non-kernel packet\n");
        !          1510:       return 1;
        !          1511:     }
        !          1512:   h = (void *) nl_async_rx_buffer;
        !          1513:   len = x;
        !          1514:   if (m.msg_flags & MSG_TRUNC)
        !          1515:     {
        !          1516:       log(L_WARN "Netlink got truncated asynchronous message");
        !          1517:       return 1;
        !          1518:     }
        !          1519:   while (NLMSG_OK(h, len))
        !          1520:     {
        !          1521:       nl_async_msg(h);
        !          1522:       h = NLMSG_NEXT(h, len);
        !          1523:     }
        !          1524:   if (len)
        !          1525:     log(L_WARN "nl_async_hook: Found packet remnant of size %d", len);
        !          1526:   return 1;
        !          1527: }
        !          1528: 
        !          1529: static void
        !          1530: nl_async_err_hook(sock *sk, int e UNUSED)
        !          1531: {
        !          1532:   nl_async_hook(sk, 0);
        !          1533: }
        !          1534: 
        !          1535: static void
        !          1536: nl_open_async(void)
        !          1537: {
        !          1538:   sock *sk;
        !          1539:   struct sockaddr_nl sa;
        !          1540:   int fd;
        !          1541: 
        !          1542:   if (nl_async_sk)
        !          1543:     return;
        !          1544: 
        !          1545:   DBG("KRT: Opening async netlink socket\n");
        !          1546: 
        !          1547:   fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
        !          1548:   if (fd < 0)
        !          1549:     {
        !          1550:       log(L_ERR "Unable to open asynchronous rtnetlink socket: %m");
        !          1551:       return;
        !          1552:     }
        !          1553: 
        !          1554:   bzero(&sa, sizeof(sa));
        !          1555:   sa.nl_family = AF_NETLINK;
        !          1556: #ifdef IPV6
        !          1557:   sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE;
        !          1558: #else
        !          1559:   sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;
        !          1560: #endif
        !          1561:   if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0)
        !          1562:     {
        !          1563:       log(L_ERR "Unable to bind asynchronous rtnetlink socket: %m");
        !          1564:       close(fd);
        !          1565:       return;
        !          1566:     }
        !          1567: 
        !          1568:   nl_async_rx_buffer = xmalloc(NL_RX_SIZE);
        !          1569: 
        !          1570:   sk = nl_async_sk = sk_new(krt_pool);
        !          1571:   sk->type = SK_MAGIC;
        !          1572:   sk->rx_hook = nl_async_hook;
        !          1573:   sk->err_hook = nl_async_err_hook;
        !          1574:   sk->fd = fd;
        !          1575:   if (sk_open(sk) < 0)
        !          1576:     bug("Netlink: sk_open failed");
        !          1577: }
        !          1578: 
        !          1579: 
        !          1580: /*
        !          1581:  *     Interface to the UNIX krt module
        !          1582:  */
        !          1583: 
        !          1584: void
        !          1585: krt_sys_io_init(void)
        !          1586: {
        !          1587:   nl_linpool = lp_new(krt_pool, 4080);
        !          1588:   HASH_INIT(nl_table_map, krt_pool, 6);
        !          1589: }
        !          1590: 
        !          1591: int
        !          1592: krt_sys_start(struct krt_proto *p)
        !          1593: {
        !          1594:   struct krt_proto *old = HASH_FIND(nl_table_map, RTH, krt_table_id(p));
        !          1595: 
        !          1596:   if (old)
        !          1597:     {
        !          1598:       log(L_ERR "%s: Kernel table %u already registered by %s",
        !          1599:          p->p.name, krt_table_id(p), old->p.name);
        !          1600:       return 0;
        !          1601:     }
        !          1602: 
        !          1603:   HASH_INSERT2(nl_table_map, RTH, krt_pool, p);
        !          1604: 
        !          1605:   nl_open();
        !          1606:   nl_open_async();
        !          1607: 
        !          1608:   return 1;
        !          1609: }
        !          1610: 
        !          1611: void
        !          1612: krt_sys_shutdown(struct krt_proto *p)
        !          1613: {
        !          1614:   HASH_REMOVE2(nl_table_map, RTH, krt_pool, p);
        !          1615: }
        !          1616: 
        !          1617: int
        !          1618: krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n, struct krt_config *o)
        !          1619: {
        !          1620:   return (n->sys.table_id == o->sys.table_id) && (n->sys.metric == o->sys.metric);
        !          1621: }
        !          1622: 
        !          1623: void
        !          1624: krt_sys_init_config(struct krt_config *cf)
        !          1625: {
        !          1626:   cf->sys.table_id = RT_TABLE_MAIN;
        !          1627:   cf->sys.metric = 0;
        !          1628: }
        !          1629: 
        !          1630: void
        !          1631: krt_sys_copy_config(struct krt_config *d, struct krt_config *s)
        !          1632: {
        !          1633:   d->sys.table_id = s->sys.table_id;
        !          1634:   d->sys.metric = s->sys.metric;
        !          1635: }
        !          1636: 
        !          1637: static const char *krt_metrics_names[KRT_METRICS_MAX] = {
        !          1638:   NULL, "lock", "mtu", "window", "rtt", "rttvar", "sstresh", "cwnd", "advmss",
        !          1639:   "reordering", "hoplimit", "initcwnd", "features", "rto_min", "initrwnd", "quickack"
        !          1640: };
        !          1641: 
        !          1642: static const char *krt_features_names[KRT_FEATURES_MAX] = {
        !          1643:   "ecn", NULL, NULL, "allfrag"
        !          1644: };
        !          1645: 
        !          1646: int
        !          1647: krt_sys_get_attr(eattr *a, byte *buf, int buflen UNUSED)
        !          1648: {
        !          1649:   switch (a->id)
        !          1650:   {
        !          1651:   case EA_KRT_PREFSRC:
        !          1652:     bsprintf(buf, "prefsrc");
        !          1653:     return GA_NAME;
        !          1654: 
        !          1655:   case EA_KRT_REALM:
        !          1656:     bsprintf(buf, "realm");
        !          1657:     return GA_NAME;
        !          1658: 
        !          1659:   case EA_KRT_SCOPE:
        !          1660:     bsprintf(buf, "scope");
        !          1661:     return GA_NAME;
        !          1662: 
        !          1663:   case EA_KRT_LOCK:
        !          1664:     buf += bsprintf(buf, "lock:");
        !          1665:     ea_format_bitfield(a, buf, buflen, krt_metrics_names, 2, KRT_METRICS_MAX);
        !          1666:     return GA_FULL;
        !          1667: 
        !          1668:   case EA_KRT_FEATURES:
        !          1669:     buf += bsprintf(buf, "features:");
        !          1670:     ea_format_bitfield(a, buf, buflen, krt_features_names, 0, KRT_FEATURES_MAX);
        !          1671:     return GA_FULL;
        !          1672: 
        !          1673:   default:;
        !          1674:     int id = (int)EA_ID(a->id) - KRT_METRICS_OFFSET;
        !          1675:     if (id > 0 && id < KRT_METRICS_MAX)
        !          1676:     {
        !          1677:       bsprintf(buf, "%s", krt_metrics_names[id]);
        !          1678:       return GA_NAME;
        !          1679:     }
        !          1680: 
        !          1681:     return GA_UNKNOWN;
        !          1682:   }
        !          1683: }
        !          1684: 
        !          1685: 
        !          1686: 
        !          1687: void
        !          1688: kif_sys_start(struct kif_proto *p UNUSED)
        !          1689: {
        !          1690:   nl_open();
        !          1691:   nl_open_async();
        !          1692: }
        !          1693: 
        !          1694: void
        !          1695: kif_sys_shutdown(struct kif_proto *p UNUSED)
        !          1696: {
        !          1697: }

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