Annotation of embedaddon/bird/proto/rip/rip.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  *     BIRD -- Routing Information Protocol (RIP)
                      3:  *
                      4:  *     (c) 1998--1999 Pavel Machek <pavel@ucw.cz>
                      5:  *     (c) 2004--2013 Ondrej Filip <feela@network.cz>
                      6:  *     (c) 2009--2015 Ondrej Zajicek <santiago@crfreenet.org>
                      7:  *     (c) 2009--2015 CZ.NIC z.s.p.o.
                      8:  *
                      9:  *     Can be freely distributed and used under the terms of the GNU GPL.
                     10:  */
                     11: 
                     12: /**
                     13:  * DOC: Routing Information Protocol (RIP)
                     14:  *
                     15:  * The RIP protocol is implemented in two files: |rip.c| containing the protocol
                     16:  * logic, route management and the protocol glue with BIRD core, and |packets.c|
                     17:  * handling RIP packet processing, RX, TX and protocol sockets.
                     18:  *
                     19:  * Each instance of RIP is described by a structure &rip_proto, which contains
                     20:  * an internal RIP routing table, a list of protocol interfaces and the main
                     21:  * timer responsible for RIP routing table cleanup.
                     22:  *
                     23:  * RIP internal routing table contains incoming and outgoing routes. For each
                     24:  * network (represented by structure &rip_entry) there is one outgoing route
                     25:  * stored directly in &rip_entry and an one-way linked list of incoming routes
                     26:  * (structures &rip_rte). The list contains incoming routes from different RIP
                     27:  * neighbors, but only routes with the lowest metric are stored (i.e., all
                     28:  * stored incoming routes have the same metric).
                     29:  *
                     30:  * Note that RIP itself does not select outgoing route, that is done by the core
                     31:  * routing table. When a new incoming route is received, it is propagated to the
                     32:  * RIP table by rip_update_rte() and possibly stored in the list of incoming
                     33:  * routes. Then the change may be propagated to the core by rip_announce_rte().
                     34:  * The core selects the best route and propagate it to RIP by rip_rt_notify(),
                     35:  * which updates outgoing route part of &rip_entry and possibly triggers route
                     36:  * propagation by rip_trigger_update().
                     37:  *
                     38:  * RIP interfaces are represented by structures &rip_iface. A RIP interface
                     39:  * contains a per-interface socket, a list of associated neighbors, interface
                     40:  * configuration, and state information related to scheduled interface events
                     41:  * and running update sessions. RIP interfaces are added and removed based on
                     42:  * core interface notifications.
                     43:  *
                     44:  * There are two RIP interface events - regular updates and triggered updates.
                     45:  * Both are managed from the RIP interface timer (rip_iface_timer()). Regular
                     46:  * updates are called at fixed interval and propagate the whole routing table,
                     47:  * while triggered updates are scheduled by rip_trigger_update() due to some
                     48:  * routing table change and propagate only the routes modified since the time
                     49:  * they were scheduled. There are also unicast-destined requested updates, but
                     50:  * these are sent directly as a reaction to received RIP request message. The
                     51:  * update session is started by rip_send_table(). There may be at most one
                     52:  * active update session per interface, as the associated state (including the
                     53:  * fib iterator) is stored directly in &rip_iface structure.
                     54:  *
                     55:  * RIP neighbors are represented by structures &rip_neighbor. Compared to
                     56:  * neighbor handling in other routing protocols, RIP does not have explicit
                     57:  * neighbor discovery and adjacency maintenance, which makes the &rip_neighbor
                     58:  * related code a bit peculiar. RIP neighbors are interlinked with core neighbor
                     59:  * structures (&neighbor) and use core neighbor notifications to ensure that RIP
                     60:  * neighbors are timely removed. RIP neighbors are added based on received route
                     61:  * notifications and removed based on core neighbor and RIP interface events.
                     62:  *
                     63:  * RIP neighbors are linked by RIP routes and use counter to track the number of
                     64:  * associated routes, but when these RIP routes timeout, associated RIP neighbor
                     65:  * is still alive (with zero counter). When RIP neighbor is removed but still
                     66:  * has some associated routes, it is not freed, just changed to detached state
                     67:  * (core neighbors and RIP ifaces are unlinked), then during the main timer
                     68:  * cleanup phase the associated routes are removed and the &rip_neighbor
                     69:  * structure is finally freed.
                     70:  *
                     71:  * Supported standards:
                     72:  * - RFC 1058 - RIPv1
                     73:  * - RFC 2453 - RIPv2
                     74:  * - RFC 2080 - RIPng
                     75:  * - RFC 4822 - RIP cryptographic authentication
                     76:  */
                     77: 
                     78: #include <stdlib.h>
                     79: #include "rip.h"
                     80: 
                     81: 
                     82: static inline void rip_lock_neighbor(struct rip_neighbor *n);
                     83: static inline void rip_unlock_neighbor(struct rip_neighbor *n);
                     84: static inline int rip_iface_link_up(struct rip_iface *ifa);
                     85: static inline void rip_kick_timer(struct rip_proto *p);
                     86: static inline void rip_iface_kick_timer(struct rip_iface *ifa);
                     87: static void rip_iface_timer(timer *timer);
                     88: static void rip_trigger_update(struct rip_proto *p);
                     89: 
                     90: 
                     91: /*
                     92:  *     RIP routes
                     93:  */
                     94: 
                     95: static void
                     96: rip_init_entry(struct fib_node *fn)
                     97: {
                     98:   // struct rip_entry *en = (void) *fn;
                     99: 
                    100:   const uint offset = OFFSETOF(struct rip_entry, routes);
                    101:   memset((byte *)fn + offset, 0, sizeof(struct rip_entry) - offset);
                    102: }
                    103: 
                    104: static struct rip_rte *
                    105: rip_add_rte(struct rip_proto *p, struct rip_rte **rp, struct rip_rte *src)
                    106: {
                    107:   struct rip_rte *rt = sl_alloc(p->rte_slab);
                    108: 
                    109:   memcpy(rt, src, sizeof(struct rip_rte));
                    110:   rt->next = *rp;
                    111:   *rp = rt;
                    112: 
                    113:   rip_lock_neighbor(rt->from);
                    114: 
                    115:   return rt;
                    116: }
                    117: 
                    118: static inline void
                    119: rip_remove_rte(struct rip_proto *p, struct rip_rte **rp)
                    120: {
                    121:   struct rip_rte *rt = *rp;
                    122: 
                    123:   rip_unlock_neighbor(rt->from);
                    124: 
                    125:   *rp = rt->next;
                    126:   sl_free(p->rte_slab, rt);
                    127: }
                    128: 
                    129: static inline int rip_same_rte(struct rip_rte *a, struct rip_rte *b)
                    130: { return a->metric == b->metric && a->tag == b->tag && ipa_equal(a->next_hop, b->next_hop); }
                    131: 
                    132: static inline int rip_valid_rte(struct rip_rte *rt)
                    133: { return rt->from->ifa != NULL; }
                    134: 
                    135: /**
                    136:  * rip_announce_rte - announce route from RIP routing table to the core
                    137:  * @p: RIP instance
                    138:  * @en: related network
                    139:  *
                    140:  * The function takes a list of incoming routes from @en, prepare appropriate
                    141:  * &rte for the core and propagate it by rte_update().
                    142:  */
                    143: static void
                    144: rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
                    145: {
                    146:   struct rip_rte *rt = en->routes;
                    147: 
                    148:   /* Find first valid rte */
                    149:   while (rt && !rip_valid_rte(rt))
                    150:     rt = rt->next;
                    151: 
                    152:   if (rt)
                    153:   {
                    154:     /* Update */
                    155:     net *n = net_get(p->p.table, en->n.prefix, en->n.pxlen);
                    156: 
                    157:     rta a0 = {
                    158:       .src = p->p.main_source,
                    159:       .source = RTS_RIP,
                    160:       .scope = SCOPE_UNIVERSE,
                    161:       .cast = RTC_UNICAST
                    162:     };
                    163: 
                    164:     u8 rt_metric = rt->metric;
                    165:     u16 rt_tag = rt->tag;
                    166:     struct rip_rte *rt2 = rt->next;
                    167: 
                    168:     /* Find second valid rte */
                    169:     while (rt2 && !rip_valid_rte(rt2))
                    170:       rt2 = rt2->next;
                    171: 
                    172:     if (p->ecmp && rt2)
                    173:     {
                    174:       /* ECMP route */
                    175:       struct mpnh *nhs = NULL;
                    176:       int num = 0;
                    177: 
                    178:       for (rt = en->routes; rt && (num < p->ecmp); rt = rt->next)
                    179:       {
                    180:        if (!rip_valid_rte(rt))
                    181:            continue;
                    182: 
                    183:        struct mpnh *nh = alloca(sizeof(struct mpnh));
                    184:        nh->gw = rt->next_hop;
                    185:        nh->iface = rt->from->nbr->iface;
                    186:        nh->weight = rt->from->ifa->cf->ecmp_weight;
                    187:        mpnh_insert(&nhs, nh);
                    188:        num++;
                    189: 
                    190:        if (rt->tag != rt_tag)
                    191:          rt_tag = 0;
                    192:       }
                    193: 
                    194:       a0.dest = RTD_MULTIPATH;
                    195:       a0.nexthops = nhs;
                    196:     }
                    197:     else
                    198:     {
                    199:       /* Unipath route */
                    200:       a0.dest = RTD_ROUTER;
                    201:       a0.gw = rt->next_hop;
                    202:       a0.iface = rt->from->nbr->iface;
                    203:       a0.from = rt->from->nbr->addr;
                    204:     }
                    205: 
                    206:     rta *a = rta_lookup(&a0);
                    207:     rte *e = rte_get_temp(a);
                    208: 
                    209:     e->u.rip.from = a0.iface;
                    210:     e->u.rip.metric = rt_metric;
                    211:     e->u.rip.tag = rt_tag;
                    212: 
                    213:     e->net = n;
                    214:     e->pflags = 0;
                    215: 
                    216:     rte_update(&p->p, n, e);
                    217:   }
                    218:   else
                    219:   {
                    220:     /* Withdraw */
                    221:     net *n = net_find(p->p.table, en->n.prefix, en->n.pxlen);
                    222:     rte_update(&p->p, n, NULL);
                    223:   }
                    224: }
                    225: 
                    226: /**
                    227:  * rip_update_rte - enter a route update to RIP routing table
                    228:  * @p: RIP instance
                    229:  * @prefix: network prefix
                    230:  * @pxlen: network prefix length
                    231:  * @new: a &rip_rte representing the new route
                    232:  *
                    233:  * The function is called by the RIP packet processing code whenever it receives
                    234:  * a reachable route. The appropriate routing table entry is found and the list
                    235:  * of incoming routes is updated. Eventually, the change is also propagated to
                    236:  * the core by rip_announce_rte(). Note that for unreachable routes,
                    237:  * rip_withdraw_rte() should be called instead of rip_update_rte().
                    238:  */
                    239: void
                    240: rip_update_rte(struct rip_proto *p, ip_addr *prefix, int pxlen, struct rip_rte *new)
                    241: {
                    242:   struct rip_entry *en = fib_get(&p->rtable, prefix, pxlen);
                    243:   struct rip_rte *rt, **rp;
                    244:   int changed = 0;
                    245: 
                    246:   /* If the new route is better, remove all current routes */
                    247:   if (en->routes && new->metric < en->routes->metric)
                    248:     while (en->routes)
                    249:       rip_remove_rte(p, &en->routes);
                    250: 
                    251:   /* Find the old route (also set rp for later) */
                    252:   for (rp = &en->routes; rt = *rp; rp = &rt->next)
                    253:     if (rt->from == new->from)
                    254:     {
                    255:       if (rip_same_rte(rt, new))
                    256:       {
                    257:        rt->expires = new->expires;
                    258:        return;
                    259:       }
                    260: 
                    261:       /* Remove the old route */
                    262:       rip_remove_rte(p, rp);
                    263:       changed = 1;
                    264:       break;
                    265:     }
                    266: 
                    267:   /* If the new route is optimal, add it to the list */
                    268:   if (!en->routes || new->metric == en->routes->metric)
                    269:   {
                    270:     rt = rip_add_rte(p, rp, new);
                    271:     changed = 1;
                    272:   }
                    273: 
                    274:   /* Announce change if on relevant position (the first or any for ECMP) */
                    275:   if (changed && (rp == &en->routes || p->ecmp))
                    276:     rip_announce_rte(p, en);
                    277: }
                    278: 
                    279: /**
                    280:  * rip_withdraw_rte - enter a route withdraw to RIP routing table
                    281:  * @p: RIP instance
                    282:  * @prefix: network prefix
                    283:  * @pxlen: network prefix length
                    284:  * @from: a &rip_neighbor propagating the withdraw
                    285:  *
                    286:  * The function is called by the RIP packet processing code whenever it receives
                    287:  * an unreachable route. The incoming route for given network from nbr @from is
                    288:  * removed. Eventually, the change is also propagated by rip_announce_rte().
                    289:  */
                    290: void
                    291: rip_withdraw_rte(struct rip_proto *p, ip_addr *prefix, int pxlen, struct rip_neighbor *from)
                    292: {
                    293:   struct rip_entry *en = fib_find(&p->rtable, prefix, pxlen);
                    294:   struct rip_rte *rt, **rp;
                    295: 
                    296:   if (!en)
                    297:     return;
                    298: 
                    299:   /* Find the old route */
                    300:   for (rp = &en->routes; rt = *rp; rp = &rt->next)
                    301:     if (rt->from == from)
                    302:       break;
                    303: 
                    304:   if (!rt)
                    305:     return;
                    306: 
                    307:   /* Remove the old route */
                    308:   rip_remove_rte(p, rp);
                    309: 
                    310:   /* Announce change if on relevant position */
                    311:   if (rp == &en->routes || p->ecmp)
                    312:     rip_announce_rte(p, en);
                    313: }
                    314: 
                    315: /*
                    316:  * rip_rt_notify - core tells us about new route, so store
                    317:  * it into our data structures.
                    318:  */
                    319: static void
                    320: rip_rt_notify(struct proto *P, struct rtable *table UNUSED, struct network *net, struct rte *new,
                    321:              struct rte *old UNUSED, struct ea_list *attrs)
                    322: {
                    323:   struct rip_proto *p = (struct rip_proto *) P;
                    324:   struct rip_entry *en;
                    325:   int old_metric;
                    326: 
                    327:   if (new)
                    328:   {
                    329:     /* Update */
                    330:     u32 rt_metric = ea_get_int(attrs, EA_RIP_METRIC, 1);
                    331:     u32 rt_tag = ea_get_int(attrs, EA_RIP_TAG, 0);
                    332: 
                    333:     if (rt_metric > p->infinity)
                    334:     {
                    335:       log(L_WARN "%s: Invalid rip_metric value %u for route %I/%d",
                    336:          p->p.name, rt_metric, net->n.prefix, net->n.pxlen);
                    337:       rt_metric = p->infinity;
                    338:     }
                    339: 
                    340:     if (rt_tag > 0xffff)
                    341:     {
                    342:       log(L_WARN "%s: Invalid rip_tag value %u for route %I/%d",
                    343:          p->p.name, rt_tag, net->n.prefix, net->n.pxlen);
                    344:       rt_metric = p->infinity;
                    345:       rt_tag = 0;
                    346:     }
                    347: 
                    348:     /*
                    349:      * Note that we accept exported routes with infinity metric (this could
                    350:      * happen if rip_metric is modified in filters). Such entry has infinity
                    351:      * metric but is RIP_ENTRY_VALID and therefore is not subject to garbage
                    352:      * collection.
                    353:      */
                    354: 
                    355:     en = fib_get(&p->rtable, &net->n.prefix, net->n.pxlen);
                    356: 
                    357:     old_metric = en->valid ? en->metric : -1;
                    358: 
                    359:     en->valid = RIP_ENTRY_VALID;
                    360:     en->metric = rt_metric;
                    361:     en->tag = rt_tag;
                    362:     en->from = (new->attrs->src->proto == P) ? new->u.rip.from : NULL;
                    363:     en->iface = new->attrs->iface;
                    364:     en->next_hop = new->attrs->gw;
                    365:   }
                    366:   else
                    367:   {
                    368:     /* Withdraw */
                    369:     en = fib_find(&p->rtable, &net->n.prefix, net->n.pxlen);
                    370: 
                    371:     if (!en || en->valid != RIP_ENTRY_VALID)
                    372:       return;
                    373: 
                    374:     old_metric = en->metric;
                    375: 
                    376:     en->valid = RIP_ENTRY_STALE;
                    377:     en->metric = p->infinity;
                    378:     en->tag = 0;
                    379:     en->from = NULL;
                    380:     en->iface = NULL;
                    381:     en->next_hop = IPA_NONE;
                    382:   }
                    383: 
                    384:   /* Activate triggered updates */
                    385:   if (en->metric != old_metric)
                    386:   {
                    387:     en->changed = now;
                    388:     rip_trigger_update(p);
                    389:   }
                    390: }
                    391: 
                    392: 
                    393: /*
                    394:  *     RIP neighbors
                    395:  */
                    396: 
                    397: struct rip_neighbor *
                    398: rip_get_neighbor(struct rip_proto *p, ip_addr *a, struct rip_iface *ifa)
                    399: {
                    400:   neighbor *nbr = neigh_find2(&p->p, a, ifa->iface, 0);
                    401: 
                    402:   if (!nbr || (nbr->scope == SCOPE_HOST) || !rip_iface_link_up(ifa))
                    403:     return NULL;
                    404: 
                    405:   if (nbr->data)
                    406:     return nbr->data;
                    407: 
                    408:   TRACE(D_EVENTS, "New neighbor %I on %s", *a, ifa->iface->name);
                    409: 
                    410:   struct rip_neighbor *n = mb_allocz(p->p.pool, sizeof(struct rip_neighbor));
                    411:   n->ifa = ifa;
                    412:   n->nbr = nbr;
                    413:   nbr->data = n;
                    414:   n->csn = nbr->aux;
                    415: 
                    416:   add_tail(&ifa->neigh_list, NODE n);
                    417: 
                    418:   return n;
                    419: }
                    420: 
                    421: static void
                    422: rip_remove_neighbor(struct rip_proto *p, struct rip_neighbor *n)
                    423: {
                    424:   neighbor *nbr = n->nbr;
                    425: 
                    426:   TRACE(D_EVENTS, "Removing neighbor %I on %s", nbr->addr, nbr->iface->name);
                    427: 
                    428:   rem_node(NODE n);
                    429:   n->ifa = NULL;
                    430:   n->nbr = NULL;
                    431:   nbr->data = NULL;
                    432:   nbr->aux = n->csn;
                    433: 
                    434:   rfree(n->bfd_req);
                    435:   n->bfd_req = NULL;
                    436:   n->last_seen = 0;
                    437: 
                    438:   if (!n->uc)
                    439:     mb_free(n);
                    440: 
                    441:   /* Related routes are removed in rip_timer() */
                    442:   rip_kick_timer(p);
                    443: }
                    444: 
                    445: static inline void
                    446: rip_lock_neighbor(struct rip_neighbor *n)
                    447: {
                    448:   n->uc++;
                    449: }
                    450: 
                    451: static inline void
                    452: rip_unlock_neighbor(struct rip_neighbor *n)
                    453: {
                    454:   n->uc--;
                    455: 
                    456:   if (!n->nbr && !n->uc)
                    457:     mb_free(n);
                    458: }
                    459: 
                    460: static void
                    461: rip_neigh_notify(struct neighbor *nbr)
                    462: {
                    463:   struct rip_proto *p = (struct rip_proto *) nbr->proto;
                    464:   struct rip_neighbor *n = nbr->data;
                    465: 
                    466:   if (!n)
                    467:     return;
                    468: 
                    469:   /*
                    470:    * We assume that rip_neigh_notify() is called before rip_if_notify() for
                    471:    * IF_CHANGE_DOWN and therefore n->ifa is still valid. We have no such
                    472:    * ordering assumption for IF_CHANGE_LINK, so we test link state of the
                    473:    * underlying iface instead of just rip_iface state.
                    474:    */
                    475:   if ((nbr->scope <= 0) || !rip_iface_link_up(n->ifa))
                    476:     rip_remove_neighbor(p, n);
                    477: }
                    478: 
                    479: static void
                    480: rip_bfd_notify(struct bfd_request *req)
                    481: {
                    482:   struct rip_neighbor *n = req->data;
                    483:   struct rip_proto *p = n->ifa->rip;
                    484: 
                    485:   if (req->down)
                    486:   {
                    487:     TRACE(D_EVENTS, "BFD session down for nbr %I on %s",
                    488:          n->nbr->addr, n->ifa->iface->name);
                    489:     rip_remove_neighbor(p, n);
                    490:   }
                    491: }
                    492: 
                    493: void
                    494: rip_update_bfd(struct rip_proto *p, struct rip_neighbor *n)
                    495: {
                    496:   int use_bfd = n->ifa->cf->bfd && n->last_seen;
                    497: 
                    498:   if (use_bfd && !n->bfd_req)
                    499:   {
                    500:     /*
                    501:      * For RIPv2, use the same address as rip_open_socket(). For RIPng, neighbor
                    502:      * should contain an address from the same prefix, thus also link-local. It
                    503:      * may cause problems if two link-local addresses are assigned to one iface.
                    504:      */
                    505:     ip_addr saddr = rip_is_v2(p) ? n->ifa->sk->saddr : n->nbr->ifa->ip;
                    506:     n->bfd_req = bfd_request_session(p->p.pool, n->nbr->addr, saddr,
                    507:                                     n->nbr->iface, rip_bfd_notify, n);
                    508:   }
                    509: 
                    510:   if (!use_bfd && n->bfd_req)
                    511:   {
                    512:     rfree(n->bfd_req);
                    513:     n->bfd_req = NULL;
                    514:   }
                    515: }
                    516: 
                    517: 
                    518: /*
                    519:  *     RIP interfaces
                    520:  */
                    521: 
                    522: static void
                    523: rip_iface_start(struct rip_iface *ifa)
                    524: {
                    525:   struct rip_proto *p = ifa->rip;
                    526: 
                    527:   TRACE(D_EVENTS, "Starting interface %s", ifa->iface->name);
                    528: 
                    529:   ifa->next_regular = now + (random() % ifa->cf->update_time) + 1;
                    530:   ifa->next_triggered = now;   /* Available immediately */
                    531:   ifa->want_triggered = 1;     /* All routes in triggered update */
                    532:   tm_start(ifa->timer, 1);     /* Or 100 ms */
                    533:   ifa->up = 1;
                    534: 
                    535:   if (!ifa->cf->passive)
                    536:     rip_send_request(ifa->rip, ifa);
                    537: }
                    538: 
                    539: static void
                    540: rip_iface_stop(struct rip_iface *ifa)
                    541: {
                    542:   struct rip_proto *p = ifa->rip;
                    543:   struct rip_neighbor *n;
                    544: 
                    545:   TRACE(D_EVENTS, "Stopping interface %s", ifa->iface->name);
                    546: 
                    547:   rip_reset_tx_session(p, ifa);
                    548: 
                    549:   WALK_LIST_FIRST(n, ifa->neigh_list)
                    550:     rip_remove_neighbor(p, n);
                    551: 
                    552:   tm_stop(ifa->timer);
                    553:   ifa->up = 0;
                    554: }
                    555: 
                    556: static inline int
                    557: rip_iface_link_up(struct rip_iface *ifa)
                    558: {
                    559:   return !ifa->cf->check_link || (ifa->iface->flags & IF_LINK_UP);
                    560: }
                    561: 
                    562: static void
                    563: rip_iface_update_state(struct rip_iface *ifa)
                    564: {
                    565:   int up = ifa->sk && rip_iface_link_up(ifa);
                    566: 
                    567:   if (up == ifa->up)
                    568:     return;
                    569: 
                    570:   if (up)
                    571:     rip_iface_start(ifa);
                    572:   else
                    573:     rip_iface_stop(ifa);
                    574: }
                    575: 
                    576: static void
                    577: rip_iface_update_buffers(struct rip_iface *ifa)
                    578: {
                    579:   if (!ifa->sk)
                    580:     return;
                    581: 
                    582:   uint rbsize = ifa->cf->rx_buffer ?: ifa->iface->mtu;
                    583:   uint tbsize = ifa->cf->tx_length ?: ifa->iface->mtu;
                    584:   rbsize = MAX(rbsize, tbsize);
                    585: 
                    586:   sk_set_rbsize(ifa->sk, rbsize);
                    587:   sk_set_tbsize(ifa->sk, tbsize);
                    588: 
                    589:   uint headers = (rip_is_v2(ifa->rip) ? IP4_HEADER_LENGTH : IP6_HEADER_LENGTH) + UDP_HEADER_LENGTH;
                    590:   ifa->tx_plen = tbsize - headers;
                    591: 
                    592:   if (ifa->cf->auth_type == RIP_AUTH_CRYPTO)
                    593:     ifa->tx_plen -= RIP_AUTH_TAIL_LENGTH + max_mac_length(ifa->cf->passwords);
                    594: }
                    595: 
                    596: static inline void
                    597: rip_iface_update_bfd(struct rip_iface *ifa)
                    598: {
                    599:   struct rip_proto *p = ifa->rip;
                    600:   struct rip_neighbor *n;
                    601: 
                    602:   WALK_LIST(n, ifa->neigh_list)
                    603:     rip_update_bfd(p, n);
                    604: }
                    605: 
                    606: 
                    607: static void
                    608: rip_iface_locked(struct object_lock *lock)
                    609: {
                    610:   struct rip_iface *ifa = lock->data;
                    611:   struct rip_proto *p = ifa->rip;
                    612: 
                    613:   if (!rip_open_socket(ifa))
                    614:   {
                    615:     log(L_ERR "%s: Cannot open socket for %s", p->p.name, ifa->iface->name);
                    616:     return;
                    617:   }
                    618: 
                    619:   rip_iface_update_buffers(ifa);
                    620:   rip_iface_update_state(ifa);
                    621: }
                    622: 
                    623: 
                    624: static struct rip_iface *
                    625: rip_find_iface(struct rip_proto *p, struct iface *what)
                    626: {
                    627:   struct rip_iface *ifa;
                    628: 
                    629:   WALK_LIST(ifa, p->iface_list)
                    630:     if (ifa->iface == what)
                    631:       return ifa;
                    632: 
                    633:   return NULL;
                    634: }
                    635: 
                    636: static void
                    637: rip_add_iface(struct rip_proto *p, struct iface *iface, struct rip_iface_config *ic)
                    638: {
                    639:   struct rip_iface *ifa;
                    640: 
                    641:   TRACE(D_EVENTS, "Adding interface %s", iface->name);
                    642: 
                    643:   ifa = mb_allocz(p->p.pool, sizeof(struct rip_iface));
                    644:   ifa->rip = p;
                    645:   ifa->iface = iface;
                    646:   ifa->cf = ic;
                    647: 
                    648:   if (ipa_nonzero(ic->address))
                    649:     ifa->addr = ic->address;
                    650:   else if (ic->mode == RIP_IM_MULTICAST)
                    651:     ifa->addr = rip_is_v2(p) ? IP4_RIP_ROUTERS : IP6_RIP_ROUTERS;
                    652:   else /* Broadcast */
                    653:     ifa->addr = iface->addr->brd;
                    654: 
                    655:   init_list(&ifa->neigh_list);
                    656: 
                    657:   add_tail(&p->iface_list, NODE ifa);
                    658: 
                    659:   ifa->timer = tm_new_set(p->p.pool, rip_iface_timer, ifa, 0, 0);
                    660: 
                    661:   struct object_lock *lock = olock_new(p->p.pool);
                    662:   lock->type = OBJLOCK_UDP;
                    663:   lock->port = ic->port;
                    664:   lock->iface = iface;
                    665:   lock->data = ifa;
                    666:   lock->hook = rip_iface_locked;
                    667:   ifa->lock = lock;
                    668: 
                    669:   olock_acquire(lock);
                    670: }
                    671: 
                    672: static void
                    673: rip_remove_iface(struct rip_proto *p, struct rip_iface *ifa)
                    674: {
                    675:   rip_iface_stop(ifa);
                    676: 
                    677:   TRACE(D_EVENTS, "Removing interface %s", ifa->iface->name);
                    678: 
                    679:   rem_node(NODE ifa);
                    680: 
                    681:   rfree(ifa->sk);
                    682:   rfree(ifa->lock);
                    683:   rfree(ifa->timer);
                    684: 
                    685:   mb_free(ifa);
                    686: }
                    687: 
                    688: static int
                    689: rip_reconfigure_iface(struct rip_proto *p, struct rip_iface *ifa, struct rip_iface_config *new)
                    690: {
                    691:   struct rip_iface_config *old = ifa->cf;
                    692: 
                    693:   /* Change of these options would require to reset the iface socket */
                    694:   if ((new->mode != old->mode) ||
                    695:       (new->port != old->port) ||
                    696:       (new->tx_tos != old->tx_tos) ||
                    697:       (new->tx_priority != old->tx_priority) ||
                    698:       (new->ttl_security != old->ttl_security))
                    699:     return 0;
                    700: 
                    701:   TRACE(D_EVENTS, "Reconfiguring interface %s", ifa->iface->name);
                    702: 
                    703:   ifa->cf = new;
                    704: 
                    705:   rip_iface_update_buffers(ifa);
                    706: 
                    707:   if (ifa->next_regular > (now + new->update_time))
                    708:     ifa->next_regular = now + (random() % new->update_time) + 1;
                    709: 
                    710:   if (new->check_link != old->check_link)
                    711:     rip_iface_update_state(ifa);
                    712: 
                    713:   if (new->bfd != old->bfd)
                    714:     rip_iface_update_bfd(ifa);
                    715: 
                    716:   if (ifa->up)
                    717:     rip_iface_kick_timer(ifa);
                    718: 
                    719:   return 1;
                    720: }
                    721: 
                    722: static void
                    723: rip_reconfigure_ifaces(struct rip_proto *p, struct rip_config *cf)
                    724: {
                    725:   struct iface *iface;
                    726: 
                    727:   WALK_LIST(iface, iface_list)
                    728:   {
                    729:     if (! (iface->flags & IF_UP))
                    730:       continue;
                    731: 
                    732:     struct rip_iface *ifa = rip_find_iface(p, iface);
                    733:     struct rip_iface_config *ic = (void *) iface_patt_find(&cf->patt_list, iface, NULL);
                    734: 
                    735:     if (ifa && ic)
                    736:     {
                    737:       if (rip_reconfigure_iface(p, ifa, ic))
                    738:        continue;
                    739: 
                    740:       /* Hard restart */
                    741:       log(L_INFO "%s: Restarting interface %s", p->p.name, ifa->iface->name);
                    742:       rip_remove_iface(p, ifa);
                    743:       rip_add_iface(p, iface, ic);
                    744:     }
                    745: 
                    746:     if (ifa && !ic)
                    747:       rip_remove_iface(p, ifa);
                    748: 
                    749:     if (!ifa && ic)
                    750:       rip_add_iface(p, iface, ic);
                    751:   }
                    752: }
                    753: 
                    754: static void
                    755: rip_if_notify(struct proto *P, unsigned flags, struct iface *iface)
                    756: {
                    757:   struct rip_proto *p = (void *) P;
                    758:   struct rip_config *cf = (void *) P->cf;
                    759: 
                    760:   if (iface->flags & IF_IGNORE)
                    761:     return;
                    762: 
                    763:   if (flags & IF_CHANGE_UP)
                    764:   {
                    765:     struct rip_iface_config *ic = (void *) iface_patt_find(&cf->patt_list, iface, NULL);
                    766: 
                    767:     if (ic)
                    768:       rip_add_iface(p, iface, ic);
                    769: 
                    770:     return;
                    771:   }
                    772: 
                    773:   struct rip_iface *ifa = rip_find_iface(p, iface);
                    774: 
                    775:   if (!ifa)
                    776:     return;
                    777: 
                    778:   if (flags & IF_CHANGE_DOWN)
                    779:   {
                    780:     rip_remove_iface(p, ifa);
                    781:     return;
                    782:   }
                    783: 
                    784:   if (flags & IF_CHANGE_MTU)
                    785:     rip_iface_update_buffers(ifa);
                    786: 
                    787:   if (flags & IF_CHANGE_LINK)
                    788:     rip_iface_update_state(ifa);
                    789: }
                    790: 
                    791: 
                    792: /*
                    793:  *     RIP timer events
                    794:  */
                    795: 
                    796: /**
                    797:  * rip_timer - RIP main timer hook
                    798:  * @t: timer
                    799:  *
                    800:  * The RIP main timer is responsible for routing table maintenance. Invalid or
                    801:  * expired routes (&rip_rte) are removed and garbage collection of stale routing
                    802:  * table entries (&rip_entry) is done. Changes are propagated to core tables,
                    803:  * route reload is also done here. Note that garbage collection uses a maximal
                    804:  * GC time, while interfaces maintain an illusion of per-interface GC times in
                    805:  * rip_send_response().
                    806:  *
                    807:  * Keeping incoming routes and the selected outgoing route are two independent
                    808:  * functions, therefore after garbage collection some entries now considered
                    809:  * invalid (RIP_ENTRY_DUMMY) still may have non-empty list of incoming routes,
                    810:  * while some valid entries (representing an outgoing route) may have that list
                    811:  * empty.
                    812:  *
                    813:  * The main timer is not scheduled periodically but it uses the time of the
                    814:  * current next event and the minimal interval of any possible event to compute
                    815:  * the time of the next run.
                    816:  */
                    817: static void
                    818: rip_timer(timer *t)
                    819: {
                    820:   struct rip_proto *p = t->data;
                    821:   struct rip_config *cf = (void *) (p->p.cf);
                    822:   struct rip_iface *ifa;
                    823:   struct rip_neighbor *n, *nn;
                    824:   struct fib_iterator fit;
                    825:   bird_clock_t next = now + MIN(cf->min_timeout_time, cf->max_garbage_time);
                    826:   bird_clock_t expires = 0;
                    827: 
                    828:   TRACE(D_EVENTS, "Main timer fired");
                    829: 
                    830:   FIB_ITERATE_INIT(&fit, &p->rtable);
                    831: 
                    832:   loop:
                    833:   FIB_ITERATE_START(&p->rtable, &fit, node)
                    834:   {
                    835:     struct rip_entry *en = (struct rip_entry *) node;
                    836:     struct rip_rte *rt, **rp;
                    837:     int changed = 0;
                    838: 
                    839:     /* Checking received routes for timeout and for dead neighbors */
                    840:     for (rp = &en->routes; rt = *rp; /* rp = &rt->next */)
                    841:     {
                    842:       if (!rip_valid_rte(rt) || (rt->expires <= now))
                    843:       {
                    844:        rip_remove_rte(p, rp);
                    845:        changed = 1;
                    846:        continue;
                    847:       }
                    848: 
                    849:       next = MIN(next, rt->expires);
                    850:       rp = &rt->next;
                    851:     }
                    852: 
                    853:     /* Propagating eventual change */
                    854:     if (changed || p->rt_reload)
                    855:     {
                    856:       /*
                    857:        * We have to restart the iteration because there may be a cascade of
                    858:        * synchronous events rip_announce_rte() -> nest table change ->
                    859:        * rip_rt_notify() -> p->rtable change, invalidating hidden variables.
                    860:        */
                    861: 
                    862:       FIB_ITERATE_PUT_NEXT(&fit, &p->rtable, node);
                    863:       rip_announce_rte(p, en);
                    864:       goto loop;
                    865:     }
                    866: 
                    867:     /* Checking stale entries for garbage collection timeout */
                    868:     if (en->valid == RIP_ENTRY_STALE)
                    869:     {
                    870:       expires = en->changed + cf->max_garbage_time;
                    871: 
                    872:       if (expires <= now)
                    873:       {
                    874:        // TRACE(D_EVENTS, "entry is too old: %I/%d", en->n.prefix, en->n.pxlen);
                    875:        en->valid = 0;
                    876:       }
                    877:       else
                    878:        next = MIN(next, expires);
                    879:     }
                    880: 
                    881:     /* Remove empty nodes */
                    882:     if (!en->valid && !en->routes)
                    883:     {
                    884:       FIB_ITERATE_PUT(&fit, node);
                    885:       fib_delete(&p->rtable, node);
                    886:       goto loop;
                    887:     }
                    888:   }
                    889:   FIB_ITERATE_END(node);
                    890: 
                    891:   p->rt_reload = 0;
                    892: 
                    893:   /* Handling neighbor expiration */
                    894:   WALK_LIST(ifa, p->iface_list)
                    895:     WALK_LIST_DELSAFE(n, nn, ifa->neigh_list)
                    896:       if (n->last_seen)
                    897:       {
                    898:        expires = n->last_seen + n->ifa->cf->timeout_time;
                    899: 
                    900:        if (expires <= now)
                    901:          rip_remove_neighbor(p, n);
                    902:        else
                    903:          next = MIN(next, expires);
                    904:       }
                    905: 
                    906:   tm_start(p->timer, MAX(next - now, 1));
                    907: }
                    908: 
                    909: static inline void
                    910: rip_kick_timer(struct rip_proto *p)
                    911: {
                    912:   if (p->timer->expires > (now + 1))
                    913:     tm_start(p->timer, 1);     /* Or 100 ms */
                    914: }
                    915: 
                    916: /**
                    917:  * rip_iface_timer - RIP interface timer hook
                    918:  * @t: timer
                    919:  *
                    920:  * RIP interface timers are responsible for scheduling both regular and
                    921:  * triggered updates. Fixed, delay-independent period is used for regular
                    922:  * updates, while minimal separating interval is enforced for triggered updates.
                    923:  * The function also ensures that a new update is not started when the old one
                    924:  * is still running.
                    925:  */
                    926: static void
                    927: rip_iface_timer(timer *t)
                    928: {
                    929:   struct rip_iface *ifa = t->data;
                    930:   struct rip_proto *p = ifa->rip;
                    931:   bird_clock_t period = ifa->cf->update_time;
                    932: 
                    933:   if (ifa->cf->passive)
                    934:     return;
                    935: 
                    936:   TRACE(D_EVENTS, "Interface timer fired for %s", ifa->iface->name);
                    937: 
                    938:   if (ifa->tx_active)
                    939:   {
                    940:     if (now < (ifa->next_regular + period))
                    941:       { tm_start(ifa->timer, 1); return; }
                    942: 
                    943:     /* We are too late, reset is done by rip_send_table() */
                    944:     log(L_WARN "%s: Too slow update on %s, resetting", p->p.name, ifa->iface->name);
                    945:   }
                    946: 
                    947:   if (now >= ifa->next_regular)
                    948:   {
                    949:     /* Send regular update, set timer for next period (or following one if necessay) */
                    950:     TRACE(D_EVENTS, "Sending regular updates for %s", ifa->iface->name);
                    951:     rip_send_table(p, ifa, ifa->addr, 0);
                    952:     ifa->next_regular += period * (1 + ((now - ifa->next_regular) / period));
                    953:     ifa->want_triggered = 0;
                    954:     p->triggered = 0;
                    955:   }
                    956:   else if (ifa->want_triggered && (now >= ifa->next_triggered))
                    957:   {
                    958:     /* Send triggered update, enforce interval between triggered updates */
                    959:     TRACE(D_EVENTS, "Sending triggered updates for %s", ifa->iface->name);
                    960:     rip_send_table(p, ifa, ifa->addr, ifa->want_triggered);
                    961:     ifa->next_triggered = now + MIN(5, period / 2 + 1);
                    962:     ifa->want_triggered = 0;
                    963:     p->triggered = 0;
                    964:   }
                    965: 
                    966:   tm_start(ifa->timer, ifa->want_triggered ? 1 : (ifa->next_regular - now));
                    967: }
                    968: 
                    969: static inline void
                    970: rip_iface_kick_timer(struct rip_iface *ifa)
                    971: {
                    972:   if (ifa->timer->expires > (now + 1))
                    973:     tm_start(ifa->timer, 1);   /* Or 100 ms */
                    974: }
                    975: 
                    976: static void
                    977: rip_trigger_update(struct rip_proto *p)
                    978: {
                    979:   if (p->triggered)
                    980:     return;
                    981: 
                    982:   struct rip_iface *ifa;
                    983:   WALK_LIST(ifa, p->iface_list)
                    984:   {
                    985:     /* Interface not active */
                    986:     if (! ifa->up)
                    987:       continue;
                    988: 
                    989:     /* Already scheduled */
                    990:     if (ifa->want_triggered)
                    991:       continue;
                    992: 
                    993:     TRACE(D_EVENTS, "Scheduling triggered updates for %s", ifa->iface->name);
                    994:     ifa->want_triggered = now;
                    995:     rip_iface_kick_timer(ifa);
                    996:   }
                    997: 
                    998:   p->triggered = 1;
                    999: }
                   1000: 
                   1001: 
                   1002: /*
                   1003:  *     RIP protocol glue
                   1004:  */
                   1005: 
                   1006: static struct ea_list *
                   1007: rip_prepare_attrs(struct linpool *pool, ea_list *next, u8 metric, u16 tag)
                   1008: {
                   1009:   struct ea_list *l = lp_alloc(pool, sizeof(struct ea_list) + 2 * sizeof(eattr));
                   1010: 
                   1011:   l->next = next;
                   1012:   l->flags = EALF_SORTED;
                   1013:   l->count = 2;
                   1014: 
                   1015:   l->attrs[0].id = EA_RIP_METRIC;
                   1016:   l->attrs[0].flags = 0;
                   1017:   l->attrs[0].type = EAF_TYPE_INT | EAF_TEMP;
                   1018:   l->attrs[0].u.data = metric;
                   1019: 
                   1020:   l->attrs[1].id = EA_RIP_TAG;
                   1021:   l->attrs[1].flags = 0;
                   1022:   l->attrs[1].type = EAF_TYPE_INT | EAF_TEMP;
                   1023:   l->attrs[1].u.data = tag;
                   1024: 
                   1025:   return l;
                   1026: }
                   1027: 
                   1028: static int
                   1029: rip_import_control(struct proto *P UNUSED, struct rte **rt, struct ea_list **attrs, struct linpool *pool)
                   1030: {
                   1031:   /* Prepare attributes with initial values */
                   1032:   if ((*rt)->attrs->source != RTS_RIP)
                   1033:     *attrs = rip_prepare_attrs(pool, *attrs, 1, 0);
                   1034: 
                   1035:   return 0;
                   1036: }
                   1037: 
                   1038: static int
                   1039: rip_reload_routes(struct proto *P)
                   1040: {
                   1041:   struct rip_proto *p = (struct rip_proto *) P;
                   1042: 
                   1043:   if (p->rt_reload)
                   1044:     return 1;
                   1045: 
                   1046:   TRACE(D_EVENTS, "Scheduling route reload");
                   1047:   p->rt_reload = 1;
                   1048:   rip_kick_timer(p);
                   1049: 
                   1050:   return 1;
                   1051: }
                   1052: 
                   1053: static struct ea_list *
                   1054: rip_make_tmp_attrs(struct rte *rt, struct linpool *pool)
                   1055: {
                   1056:   return rip_prepare_attrs(pool, NULL, rt->u.rip.metric, rt->u.rip.tag);
                   1057: }
                   1058: 
                   1059: static void
                   1060: rip_store_tmp_attrs(struct rte *rt, struct ea_list *attrs)
                   1061: {
                   1062:   rt->u.rip.metric = ea_get_int(attrs, EA_RIP_METRIC, 1);
                   1063:   rt->u.rip.tag = ea_get_int(attrs, EA_RIP_TAG, 0);
                   1064: }
                   1065: 
                   1066: static int
                   1067: rip_rte_better(struct rte *new, struct rte *old)
                   1068: {
                   1069:   return new->u.rip.metric < old->u.rip.metric;
                   1070: }
                   1071: 
                   1072: static int
                   1073: rip_rte_same(struct rte *new, struct rte *old)
                   1074: {
                   1075:   return ((new->u.rip.metric == old->u.rip.metric) &&
                   1076:          (new->u.rip.tag == old->u.rip.tag) &&
                   1077:          (new->u.rip.from == old->u.rip.from));
                   1078: }
                   1079: 
                   1080: 
                   1081: static struct proto *
                   1082: rip_init(struct proto_config *cfg)
                   1083: {
                   1084:   struct proto *P = proto_new(cfg, sizeof(struct rip_proto));
                   1085: 
                   1086:   P->accept_ra_types = RA_OPTIMAL;
                   1087:   P->if_notify = rip_if_notify;
                   1088:   P->rt_notify = rip_rt_notify;
                   1089:   P->neigh_notify = rip_neigh_notify;
                   1090:   P->import_control = rip_import_control;
                   1091:   P->reload_routes = rip_reload_routes;
                   1092:   P->make_tmp_attrs = rip_make_tmp_attrs;
                   1093:   P->store_tmp_attrs = rip_store_tmp_attrs;
                   1094:   P->rte_better = rip_rte_better;
                   1095:   P->rte_same = rip_rte_same;
                   1096: 
                   1097:   return P;
                   1098: }
                   1099: 
                   1100: static int
                   1101: rip_start(struct proto *P)
                   1102: {
                   1103:   struct rip_proto *p = (void *) P;
                   1104:   struct rip_config *cf = (void *) (P->cf);
                   1105: 
                   1106:   init_list(&p->iface_list);
                   1107:   fib_init(&p->rtable, P->pool, sizeof(struct rip_entry), 0, rip_init_entry);
                   1108:   p->rte_slab = sl_new(P->pool, sizeof(struct rip_rte));
                   1109:   p->timer = tm_new_set(P->pool, rip_timer, p, 0, 0);
                   1110: 
                   1111:   p->ecmp = cf->ecmp;
                   1112:   p->infinity = cf->infinity;
                   1113:   p->triggered = 0;
                   1114: 
                   1115:   p->log_pkt_tbf = (struct tbf){ .rate = 1, .burst = 5 };
                   1116:   p->log_rte_tbf = (struct tbf){ .rate = 4, .burst = 20 };
                   1117: 
                   1118:   tm_start(p->timer, MIN(cf->min_timeout_time, cf->max_garbage_time));
                   1119: 
                   1120:   return PS_UP;
                   1121: }
                   1122: 
                   1123: static int
                   1124: rip_reconfigure(struct proto *P, struct proto_config *c)
                   1125: {
                   1126:   struct rip_proto *p = (void *) P;
                   1127:   struct rip_config *new = (void *) c;
                   1128:   // struct rip_config *old = (void *) (P->cf);
                   1129: 
                   1130:   if (new->infinity != p->infinity)
                   1131:     return 0;
                   1132: 
                   1133:   TRACE(D_EVENTS, "Reconfiguring");
                   1134: 
                   1135:   p->p.cf = c;
                   1136:   p->ecmp = new->ecmp;
                   1137:   rip_reconfigure_ifaces(p, new);
                   1138: 
                   1139:   p->rt_reload = 1;
                   1140:   rip_kick_timer(p);
                   1141: 
                   1142:   return 1;
                   1143: }
                   1144: 
                   1145: static void
                   1146: rip_get_route_info(rte *rte, byte *buf, ea_list *attrs UNUSED)
                   1147: {
                   1148:   buf += bsprintf(buf, " (%d/%d)", rte->pref, rte->u.rip.metric);
                   1149: 
                   1150:   if (rte->u.rip.tag)
                   1151:     bsprintf(buf, " [%04x]", rte->u.rip.tag);
                   1152: }
                   1153: 
                   1154: static int
                   1155: rip_get_attr(eattr *a, byte *buf, int buflen UNUSED)
                   1156: {
                   1157:   switch (a->id)
                   1158:   {
                   1159:   case EA_RIP_METRIC:
                   1160:     bsprintf(buf, "metric: %d", a->u.data);
                   1161:     return GA_FULL;
                   1162: 
                   1163:   case EA_RIP_TAG:
                   1164:     bsprintf(buf, "tag: %04x", a->u.data);
                   1165:     return GA_FULL;
                   1166: 
                   1167:   default:
                   1168:     return GA_UNKNOWN;
                   1169:   }
                   1170: }
                   1171: 
                   1172: void
                   1173: rip_show_interfaces(struct proto *P, char *iff)
                   1174: {
                   1175:   struct rip_proto *p = (void *) P;
                   1176:   struct rip_iface *ifa = NULL;
                   1177:   struct rip_neighbor *n = NULL;
                   1178: 
                   1179:   if (p->p.proto_state != PS_UP)
                   1180:   {
                   1181:     cli_msg(-1021, "%s: is not up", p->p.name);
                   1182:     cli_msg(0, "");
                   1183:     return;
                   1184:   }
                   1185: 
                   1186:   cli_msg(-1021, "%s:", p->p.name);
                   1187:   cli_msg(-1021, "%-10s %-6s %6s %6s %6s",
                   1188:          "Interface", "State", "Metric", "Nbrs", "Timer");
                   1189: 
                   1190:   WALK_LIST(ifa, p->iface_list)
                   1191:   {
                   1192:     if (iff && !patmatch(iff, ifa->iface->name))
                   1193:       continue;
                   1194: 
                   1195:     int nbrs = 0;
                   1196:     WALK_LIST(n, ifa->neigh_list)
                   1197:       if (n->last_seen)
                   1198:        nbrs++;
                   1199: 
                   1200:     int timer = MAX(ifa->next_regular - now, 0);
                   1201:     cli_msg(-1021, "%-10s %-6s %6u %6u %6u",
                   1202:            ifa->iface->name, (ifa->up ? "Up" : "Down"), ifa->cf->metric, nbrs, timer);
                   1203:   }
                   1204: 
                   1205:   cli_msg(0, "");
                   1206: }
                   1207: 
                   1208: void
                   1209: rip_show_neighbors(struct proto *P, char *iff)
                   1210: {
                   1211:   struct rip_proto *p = (void *) P;
                   1212:   struct rip_iface *ifa = NULL;
                   1213:   struct rip_neighbor *n = NULL;
                   1214: 
                   1215:   if (p->p.proto_state != PS_UP)
                   1216:   {
                   1217:     cli_msg(-1022, "%s: is not up", p->p.name);
                   1218:     cli_msg(0, "");
                   1219:     return;
                   1220:   }
                   1221: 
                   1222:   cli_msg(-1022, "%s:", p->p.name);
                   1223:   cli_msg(-1022, "%-25s %-10s %6s %6s %6s",
                   1224:          "IP address", "Interface", "Metric", "Routes", "Seen");
                   1225: 
                   1226:   WALK_LIST(ifa, p->iface_list)
                   1227:   {
                   1228:     if (iff && !patmatch(iff, ifa->iface->name))
                   1229:       continue;
                   1230: 
                   1231:     WALK_LIST(n, ifa->neigh_list)
                   1232:     {
                   1233:       if (!n->last_seen)
                   1234:        continue;
                   1235: 
                   1236:       int timer = now - n->last_seen;
                   1237:       cli_msg(-1022, "%-25I %-10s %6u %6u %6u",
                   1238:              n->nbr->addr, ifa->iface->name, ifa->cf->metric, n->uc, timer);
                   1239:     }
                   1240:   }
                   1241: 
                   1242:   cli_msg(0, "");
                   1243: }
                   1244: 
                   1245: static void
                   1246: rip_dump(struct proto *P)
                   1247: {
                   1248:   struct rip_proto *p = (struct rip_proto *) P;
                   1249:   struct rip_iface *ifa;
                   1250:   int i;
                   1251: 
                   1252:   i = 0;
                   1253:   FIB_WALK(&p->rtable, e)
                   1254:   {
                   1255:     struct rip_entry *en = (struct rip_entry *) e;
                   1256:     debug("RIP: entry #%d: %I/%d via %I dev %s valid %d metric %d age %d s\n",
                   1257:          i++, en->n.prefix, en->n.pxlen, en->next_hop, en->iface->name,
                   1258:          en->valid, en->metric, now - en->changed);
                   1259:   }
                   1260:   FIB_WALK_END;
                   1261: 
                   1262:   i = 0;
                   1263:   WALK_LIST(ifa, p->iface_list)
                   1264:   {
                   1265:     debug("RIP: interface #%d: %s, %I, up = %d, busy = %d\n",
                   1266:          i++, ifa->iface->name, ifa->sk ? ifa->sk->daddr : IPA_NONE,
                   1267:          ifa->up, ifa->tx_active);
                   1268:   }
                   1269: }
                   1270: 
                   1271: 
                   1272: struct protocol proto_rip = {
                   1273:   .name =              "RIP",
                   1274:   .template =          "rip%d",
                   1275:   .attr_class =                EAP_RIP,
                   1276:   .preference =                DEF_PREF_RIP,
                   1277:   .config_size =       sizeof(struct rip_config),
                   1278:   .init =              rip_init,
                   1279:   .dump =              rip_dump,
                   1280:   .start =             rip_start,
                   1281:   .reconfigure =       rip_reconfigure,
                   1282:   .get_route_info =    rip_get_route_info,
                   1283:   .get_attr =          rip_get_attr
                   1284: };

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