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

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,
1.1.1.2 ! misho     507:                                     n->nbr->iface, p->p.vrf,
        !           508:                                     rip_bfd_notify, n);
1.1       misho     509:   }
                    510: 
                    511:   if (!use_bfd && n->bfd_req)
                    512:   {
                    513:     rfree(n->bfd_req);
                    514:     n->bfd_req = NULL;
                    515:   }
                    516: }
                    517: 
                    518: 
                    519: /*
                    520:  *     RIP interfaces
                    521:  */
                    522: 
                    523: static void
                    524: rip_iface_start(struct rip_iface *ifa)
                    525: {
                    526:   struct rip_proto *p = ifa->rip;
                    527: 
                    528:   TRACE(D_EVENTS, "Starting interface %s", ifa->iface->name);
                    529: 
                    530:   ifa->next_regular = now + (random() % ifa->cf->update_time) + 1;
                    531:   ifa->next_triggered = now;   /* Available immediately */
                    532:   ifa->want_triggered = 1;     /* All routes in triggered update */
                    533:   tm_start(ifa->timer, 1);     /* Or 100 ms */
                    534:   ifa->up = 1;
                    535: 
                    536:   if (!ifa->cf->passive)
                    537:     rip_send_request(ifa->rip, ifa);
                    538: }
                    539: 
                    540: static void
                    541: rip_iface_stop(struct rip_iface *ifa)
                    542: {
                    543:   struct rip_proto *p = ifa->rip;
                    544:   struct rip_neighbor *n;
                    545: 
                    546:   TRACE(D_EVENTS, "Stopping interface %s", ifa->iface->name);
                    547: 
                    548:   rip_reset_tx_session(p, ifa);
                    549: 
                    550:   WALK_LIST_FIRST(n, ifa->neigh_list)
                    551:     rip_remove_neighbor(p, n);
                    552: 
                    553:   tm_stop(ifa->timer);
                    554:   ifa->up = 0;
                    555: }
                    556: 
                    557: static inline int
                    558: rip_iface_link_up(struct rip_iface *ifa)
                    559: {
                    560:   return !ifa->cf->check_link || (ifa->iface->flags & IF_LINK_UP);
                    561: }
                    562: 
                    563: static void
                    564: rip_iface_update_state(struct rip_iface *ifa)
                    565: {
                    566:   int up = ifa->sk && rip_iface_link_up(ifa);
                    567: 
                    568:   if (up == ifa->up)
                    569:     return;
                    570: 
                    571:   if (up)
                    572:     rip_iface_start(ifa);
                    573:   else
                    574:     rip_iface_stop(ifa);
                    575: }
                    576: 
                    577: static void
                    578: rip_iface_update_buffers(struct rip_iface *ifa)
                    579: {
                    580:   if (!ifa->sk)
                    581:     return;
                    582: 
                    583:   uint rbsize = ifa->cf->rx_buffer ?: ifa->iface->mtu;
                    584:   uint tbsize = ifa->cf->tx_length ?: ifa->iface->mtu;
                    585:   rbsize = MAX(rbsize, tbsize);
                    586: 
                    587:   sk_set_rbsize(ifa->sk, rbsize);
                    588:   sk_set_tbsize(ifa->sk, tbsize);
                    589: 
                    590:   uint headers = (rip_is_v2(ifa->rip) ? IP4_HEADER_LENGTH : IP6_HEADER_LENGTH) + UDP_HEADER_LENGTH;
                    591:   ifa->tx_plen = tbsize - headers;
                    592: 
                    593:   if (ifa->cf->auth_type == RIP_AUTH_CRYPTO)
                    594:     ifa->tx_plen -= RIP_AUTH_TAIL_LENGTH + max_mac_length(ifa->cf->passwords);
                    595: }
                    596: 
                    597: static inline void
                    598: rip_iface_update_bfd(struct rip_iface *ifa)
                    599: {
                    600:   struct rip_proto *p = ifa->rip;
                    601:   struct rip_neighbor *n;
                    602: 
                    603:   WALK_LIST(n, ifa->neigh_list)
                    604:     rip_update_bfd(p, n);
                    605: }
                    606: 
                    607: 
                    608: static void
                    609: rip_iface_locked(struct object_lock *lock)
                    610: {
                    611:   struct rip_iface *ifa = lock->data;
                    612:   struct rip_proto *p = ifa->rip;
                    613: 
                    614:   if (!rip_open_socket(ifa))
                    615:   {
                    616:     log(L_ERR "%s: Cannot open socket for %s", p->p.name, ifa->iface->name);
                    617:     return;
                    618:   }
                    619: 
                    620:   rip_iface_update_buffers(ifa);
                    621:   rip_iface_update_state(ifa);
                    622: }
                    623: 
                    624: 
                    625: static struct rip_iface *
                    626: rip_find_iface(struct rip_proto *p, struct iface *what)
                    627: {
                    628:   struct rip_iface *ifa;
                    629: 
                    630:   WALK_LIST(ifa, p->iface_list)
                    631:     if (ifa->iface == what)
                    632:       return ifa;
                    633: 
                    634:   return NULL;
                    635: }
                    636: 
                    637: static void
                    638: rip_add_iface(struct rip_proto *p, struct iface *iface, struct rip_iface_config *ic)
                    639: {
                    640:   struct rip_iface *ifa;
                    641: 
                    642:   TRACE(D_EVENTS, "Adding interface %s", iface->name);
                    643: 
                    644:   ifa = mb_allocz(p->p.pool, sizeof(struct rip_iface));
                    645:   ifa->rip = p;
                    646:   ifa->iface = iface;
                    647:   ifa->cf = ic;
                    648: 
                    649:   if (ipa_nonzero(ic->address))
                    650:     ifa->addr = ic->address;
                    651:   else if (ic->mode == RIP_IM_MULTICAST)
                    652:     ifa->addr = rip_is_v2(p) ? IP4_RIP_ROUTERS : IP6_RIP_ROUTERS;
                    653:   else /* Broadcast */
                    654:     ifa->addr = iface->addr->brd;
                    655: 
                    656:   init_list(&ifa->neigh_list);
                    657: 
                    658:   add_tail(&p->iface_list, NODE ifa);
                    659: 
                    660:   ifa->timer = tm_new_set(p->p.pool, rip_iface_timer, ifa, 0, 0);
                    661: 
                    662:   struct object_lock *lock = olock_new(p->p.pool);
                    663:   lock->type = OBJLOCK_UDP;
                    664:   lock->port = ic->port;
                    665:   lock->iface = iface;
                    666:   lock->data = ifa;
                    667:   lock->hook = rip_iface_locked;
                    668:   ifa->lock = lock;
                    669: 
                    670:   olock_acquire(lock);
                    671: }
                    672: 
                    673: static void
                    674: rip_remove_iface(struct rip_proto *p, struct rip_iface *ifa)
                    675: {
                    676:   rip_iface_stop(ifa);
                    677: 
                    678:   TRACE(D_EVENTS, "Removing interface %s", ifa->iface->name);
                    679: 
                    680:   rem_node(NODE ifa);
                    681: 
                    682:   rfree(ifa->sk);
                    683:   rfree(ifa->lock);
                    684:   rfree(ifa->timer);
                    685: 
                    686:   mb_free(ifa);
                    687: }
                    688: 
                    689: static int
                    690: rip_reconfigure_iface(struct rip_proto *p, struct rip_iface *ifa, struct rip_iface_config *new)
                    691: {
                    692:   struct rip_iface_config *old = ifa->cf;
                    693: 
                    694:   /* Change of these options would require to reset the iface socket */
                    695:   if ((new->mode != old->mode) ||
                    696:       (new->port != old->port) ||
                    697:       (new->tx_tos != old->tx_tos) ||
                    698:       (new->tx_priority != old->tx_priority) ||
                    699:       (new->ttl_security != old->ttl_security))
                    700:     return 0;
                    701: 
                    702:   TRACE(D_EVENTS, "Reconfiguring interface %s", ifa->iface->name);
                    703: 
                    704:   ifa->cf = new;
                    705: 
                    706:   rip_iface_update_buffers(ifa);
                    707: 
                    708:   if (ifa->next_regular > (now + new->update_time))
                    709:     ifa->next_regular = now + (random() % new->update_time) + 1;
                    710: 
                    711:   if (new->check_link != old->check_link)
                    712:     rip_iface_update_state(ifa);
                    713: 
                    714:   if (new->bfd != old->bfd)
                    715:     rip_iface_update_bfd(ifa);
                    716: 
                    717:   if (ifa->up)
                    718:     rip_iface_kick_timer(ifa);
                    719: 
                    720:   return 1;
                    721: }
                    722: 
                    723: static void
                    724: rip_reconfigure_ifaces(struct rip_proto *p, struct rip_config *cf)
                    725: {
                    726:   struct iface *iface;
                    727: 
                    728:   WALK_LIST(iface, iface_list)
                    729:   {
                    730:     if (! (iface->flags & IF_UP))
                    731:       continue;
                    732: 
                    733:     struct rip_iface *ifa = rip_find_iface(p, iface);
                    734:     struct rip_iface_config *ic = (void *) iface_patt_find(&cf->patt_list, iface, NULL);
                    735: 
                    736:     if (ifa && ic)
                    737:     {
                    738:       if (rip_reconfigure_iface(p, ifa, ic))
                    739:        continue;
                    740: 
                    741:       /* Hard restart */
                    742:       log(L_INFO "%s: Restarting interface %s", p->p.name, ifa->iface->name);
                    743:       rip_remove_iface(p, ifa);
                    744:       rip_add_iface(p, iface, ic);
                    745:     }
                    746: 
                    747:     if (ifa && !ic)
                    748:       rip_remove_iface(p, ifa);
                    749: 
                    750:     if (!ifa && ic)
                    751:       rip_add_iface(p, iface, ic);
                    752:   }
                    753: }
                    754: 
                    755: static void
                    756: rip_if_notify(struct proto *P, unsigned flags, struct iface *iface)
                    757: {
                    758:   struct rip_proto *p = (void *) P;
                    759:   struct rip_config *cf = (void *) P->cf;
                    760: 
                    761:   if (iface->flags & IF_IGNORE)
                    762:     return;
                    763: 
                    764:   if (flags & IF_CHANGE_UP)
                    765:   {
                    766:     struct rip_iface_config *ic = (void *) iface_patt_find(&cf->patt_list, iface, NULL);
                    767: 
1.1.1.2 ! misho     768:     /* For RIPng, ignore ifaces without link-local address */
        !           769:     if (rip_is_ng(p) && !ifa_llv6(iface))
        !           770:       return;
        !           771: 
1.1       misho     772:     if (ic)
                    773:       rip_add_iface(p, iface, ic);
                    774: 
                    775:     return;
                    776:   }
                    777: 
                    778:   struct rip_iface *ifa = rip_find_iface(p, iface);
                    779: 
                    780:   if (!ifa)
                    781:     return;
                    782: 
                    783:   if (flags & IF_CHANGE_DOWN)
                    784:   {
                    785:     rip_remove_iface(p, ifa);
                    786:     return;
                    787:   }
                    788: 
                    789:   if (flags & IF_CHANGE_MTU)
                    790:     rip_iface_update_buffers(ifa);
                    791: 
                    792:   if (flags & IF_CHANGE_LINK)
                    793:     rip_iface_update_state(ifa);
                    794: }
                    795: 
                    796: 
                    797: /*
                    798:  *     RIP timer events
                    799:  */
                    800: 
                    801: /**
                    802:  * rip_timer - RIP main timer hook
                    803:  * @t: timer
                    804:  *
                    805:  * The RIP main timer is responsible for routing table maintenance. Invalid or
                    806:  * expired routes (&rip_rte) are removed and garbage collection of stale routing
                    807:  * table entries (&rip_entry) is done. Changes are propagated to core tables,
                    808:  * route reload is also done here. Note that garbage collection uses a maximal
                    809:  * GC time, while interfaces maintain an illusion of per-interface GC times in
                    810:  * rip_send_response().
                    811:  *
                    812:  * Keeping incoming routes and the selected outgoing route are two independent
                    813:  * functions, therefore after garbage collection some entries now considered
                    814:  * invalid (RIP_ENTRY_DUMMY) still may have non-empty list of incoming routes,
                    815:  * while some valid entries (representing an outgoing route) may have that list
                    816:  * empty.
                    817:  *
                    818:  * The main timer is not scheduled periodically but it uses the time of the
                    819:  * current next event and the minimal interval of any possible event to compute
                    820:  * the time of the next run.
                    821:  */
                    822: static void
                    823: rip_timer(timer *t)
                    824: {
                    825:   struct rip_proto *p = t->data;
                    826:   struct rip_config *cf = (void *) (p->p.cf);
                    827:   struct rip_iface *ifa;
                    828:   struct rip_neighbor *n, *nn;
                    829:   struct fib_iterator fit;
                    830:   bird_clock_t next = now + MIN(cf->min_timeout_time, cf->max_garbage_time);
                    831:   bird_clock_t expires = 0;
                    832: 
                    833:   TRACE(D_EVENTS, "Main timer fired");
                    834: 
                    835:   FIB_ITERATE_INIT(&fit, &p->rtable);
                    836: 
                    837:   loop:
                    838:   FIB_ITERATE_START(&p->rtable, &fit, node)
                    839:   {
                    840:     struct rip_entry *en = (struct rip_entry *) node;
                    841:     struct rip_rte *rt, **rp;
                    842:     int changed = 0;
                    843: 
                    844:     /* Checking received routes for timeout and for dead neighbors */
                    845:     for (rp = &en->routes; rt = *rp; /* rp = &rt->next */)
                    846:     {
                    847:       if (!rip_valid_rte(rt) || (rt->expires <= now))
                    848:       {
                    849:        rip_remove_rte(p, rp);
                    850:        changed = 1;
                    851:        continue;
                    852:       }
                    853: 
                    854:       next = MIN(next, rt->expires);
                    855:       rp = &rt->next;
                    856:     }
                    857: 
                    858:     /* Propagating eventual change */
                    859:     if (changed || p->rt_reload)
                    860:     {
                    861:       /*
                    862:        * We have to restart the iteration because there may be a cascade of
                    863:        * synchronous events rip_announce_rte() -> nest table change ->
                    864:        * rip_rt_notify() -> p->rtable change, invalidating hidden variables.
                    865:        */
                    866: 
                    867:       FIB_ITERATE_PUT_NEXT(&fit, &p->rtable, node);
                    868:       rip_announce_rte(p, en);
                    869:       goto loop;
                    870:     }
                    871: 
                    872:     /* Checking stale entries for garbage collection timeout */
                    873:     if (en->valid == RIP_ENTRY_STALE)
                    874:     {
                    875:       expires = en->changed + cf->max_garbage_time;
                    876: 
                    877:       if (expires <= now)
                    878:       {
                    879:        // TRACE(D_EVENTS, "entry is too old: %I/%d", en->n.prefix, en->n.pxlen);
                    880:        en->valid = 0;
                    881:       }
                    882:       else
                    883:        next = MIN(next, expires);
                    884:     }
                    885: 
                    886:     /* Remove empty nodes */
                    887:     if (!en->valid && !en->routes)
                    888:     {
                    889:       FIB_ITERATE_PUT(&fit, node);
                    890:       fib_delete(&p->rtable, node);
                    891:       goto loop;
                    892:     }
                    893:   }
                    894:   FIB_ITERATE_END(node);
                    895: 
                    896:   p->rt_reload = 0;
                    897: 
                    898:   /* Handling neighbor expiration */
                    899:   WALK_LIST(ifa, p->iface_list)
                    900:     WALK_LIST_DELSAFE(n, nn, ifa->neigh_list)
                    901:       if (n->last_seen)
                    902:       {
                    903:        expires = n->last_seen + n->ifa->cf->timeout_time;
                    904: 
                    905:        if (expires <= now)
                    906:          rip_remove_neighbor(p, n);
                    907:        else
                    908:          next = MIN(next, expires);
                    909:       }
                    910: 
                    911:   tm_start(p->timer, MAX(next - now, 1));
                    912: }
                    913: 
                    914: static inline void
                    915: rip_kick_timer(struct rip_proto *p)
                    916: {
                    917:   if (p->timer->expires > (now + 1))
                    918:     tm_start(p->timer, 1);     /* Or 100 ms */
                    919: }
                    920: 
                    921: /**
                    922:  * rip_iface_timer - RIP interface timer hook
                    923:  * @t: timer
                    924:  *
                    925:  * RIP interface timers are responsible for scheduling both regular and
                    926:  * triggered updates. Fixed, delay-independent period is used for regular
                    927:  * updates, while minimal separating interval is enforced for triggered updates.
                    928:  * The function also ensures that a new update is not started when the old one
                    929:  * is still running.
                    930:  */
                    931: static void
                    932: rip_iface_timer(timer *t)
                    933: {
                    934:   struct rip_iface *ifa = t->data;
                    935:   struct rip_proto *p = ifa->rip;
                    936:   bird_clock_t period = ifa->cf->update_time;
                    937: 
                    938:   if (ifa->cf->passive)
                    939:     return;
                    940: 
                    941:   TRACE(D_EVENTS, "Interface timer fired for %s", ifa->iface->name);
                    942: 
                    943:   if (ifa->tx_active)
                    944:   {
                    945:     if (now < (ifa->next_regular + period))
                    946:       { tm_start(ifa->timer, 1); return; }
                    947: 
                    948:     /* We are too late, reset is done by rip_send_table() */
                    949:     log(L_WARN "%s: Too slow update on %s, resetting", p->p.name, ifa->iface->name);
                    950:   }
                    951: 
                    952:   if (now >= ifa->next_regular)
                    953:   {
                    954:     /* Send regular update, set timer for next period (or following one if necessay) */
                    955:     TRACE(D_EVENTS, "Sending regular updates for %s", ifa->iface->name);
                    956:     rip_send_table(p, ifa, ifa->addr, 0);
                    957:     ifa->next_regular += period * (1 + ((now - ifa->next_regular) / period));
                    958:     ifa->want_triggered = 0;
                    959:     p->triggered = 0;
                    960:   }
                    961:   else if (ifa->want_triggered && (now >= ifa->next_triggered))
                    962:   {
                    963:     /* Send triggered update, enforce interval between triggered updates */
                    964:     TRACE(D_EVENTS, "Sending triggered updates for %s", ifa->iface->name);
                    965:     rip_send_table(p, ifa, ifa->addr, ifa->want_triggered);
                    966:     ifa->next_triggered = now + MIN(5, period / 2 + 1);
                    967:     ifa->want_triggered = 0;
                    968:     p->triggered = 0;
                    969:   }
                    970: 
                    971:   tm_start(ifa->timer, ifa->want_triggered ? 1 : (ifa->next_regular - now));
                    972: }
                    973: 
                    974: static inline void
                    975: rip_iface_kick_timer(struct rip_iface *ifa)
                    976: {
                    977:   if (ifa->timer->expires > (now + 1))
                    978:     tm_start(ifa->timer, 1);   /* Or 100 ms */
                    979: }
                    980: 
                    981: static void
                    982: rip_trigger_update(struct rip_proto *p)
                    983: {
                    984:   if (p->triggered)
                    985:     return;
                    986: 
                    987:   struct rip_iface *ifa;
                    988:   WALK_LIST(ifa, p->iface_list)
                    989:   {
                    990:     /* Interface not active */
                    991:     if (! ifa->up)
                    992:       continue;
                    993: 
                    994:     /* Already scheduled */
                    995:     if (ifa->want_triggered)
                    996:       continue;
                    997: 
                    998:     TRACE(D_EVENTS, "Scheduling triggered updates for %s", ifa->iface->name);
                    999:     ifa->want_triggered = now;
                   1000:     rip_iface_kick_timer(ifa);
                   1001:   }
                   1002: 
                   1003:   p->triggered = 1;
                   1004: }
                   1005: 
                   1006: 
                   1007: /*
                   1008:  *     RIP protocol glue
                   1009:  */
                   1010: 
                   1011: static struct ea_list *
                   1012: rip_prepare_attrs(struct linpool *pool, ea_list *next, u8 metric, u16 tag)
                   1013: {
                   1014:   struct ea_list *l = lp_alloc(pool, sizeof(struct ea_list) + 2 * sizeof(eattr));
                   1015: 
                   1016:   l->next = next;
                   1017:   l->flags = EALF_SORTED;
                   1018:   l->count = 2;
                   1019: 
                   1020:   l->attrs[0].id = EA_RIP_METRIC;
                   1021:   l->attrs[0].flags = 0;
                   1022:   l->attrs[0].type = EAF_TYPE_INT | EAF_TEMP;
                   1023:   l->attrs[0].u.data = metric;
                   1024: 
                   1025:   l->attrs[1].id = EA_RIP_TAG;
                   1026:   l->attrs[1].flags = 0;
                   1027:   l->attrs[1].type = EAF_TYPE_INT | EAF_TEMP;
                   1028:   l->attrs[1].u.data = tag;
                   1029: 
                   1030:   return l;
                   1031: }
                   1032: 
                   1033: static int
                   1034: rip_import_control(struct proto *P UNUSED, struct rte **rt, struct ea_list **attrs, struct linpool *pool)
                   1035: {
                   1036:   /* Prepare attributes with initial values */
                   1037:   if ((*rt)->attrs->source != RTS_RIP)
                   1038:     *attrs = rip_prepare_attrs(pool, *attrs, 1, 0);
                   1039: 
                   1040:   return 0;
                   1041: }
                   1042: 
                   1043: static int
                   1044: rip_reload_routes(struct proto *P)
                   1045: {
                   1046:   struct rip_proto *p = (struct rip_proto *) P;
                   1047: 
                   1048:   if (p->rt_reload)
                   1049:     return 1;
                   1050: 
                   1051:   TRACE(D_EVENTS, "Scheduling route reload");
                   1052:   p->rt_reload = 1;
                   1053:   rip_kick_timer(p);
                   1054: 
                   1055:   return 1;
                   1056: }
                   1057: 
                   1058: static struct ea_list *
                   1059: rip_make_tmp_attrs(struct rte *rt, struct linpool *pool)
                   1060: {
                   1061:   return rip_prepare_attrs(pool, NULL, rt->u.rip.metric, rt->u.rip.tag);
                   1062: }
                   1063: 
                   1064: static void
                   1065: rip_store_tmp_attrs(struct rte *rt, struct ea_list *attrs)
                   1066: {
                   1067:   rt->u.rip.metric = ea_get_int(attrs, EA_RIP_METRIC, 1);
                   1068:   rt->u.rip.tag = ea_get_int(attrs, EA_RIP_TAG, 0);
                   1069: }
                   1070: 
                   1071: static int
                   1072: rip_rte_better(struct rte *new, struct rte *old)
                   1073: {
                   1074:   return new->u.rip.metric < old->u.rip.metric;
                   1075: }
                   1076: 
                   1077: static int
                   1078: rip_rte_same(struct rte *new, struct rte *old)
                   1079: {
                   1080:   return ((new->u.rip.metric == old->u.rip.metric) &&
                   1081:          (new->u.rip.tag == old->u.rip.tag) &&
                   1082:          (new->u.rip.from == old->u.rip.from));
                   1083: }
                   1084: 
                   1085: 
                   1086: static struct proto *
                   1087: rip_init(struct proto_config *cfg)
                   1088: {
                   1089:   struct proto *P = proto_new(cfg, sizeof(struct rip_proto));
                   1090: 
                   1091:   P->accept_ra_types = RA_OPTIMAL;
                   1092:   P->if_notify = rip_if_notify;
                   1093:   P->rt_notify = rip_rt_notify;
                   1094:   P->neigh_notify = rip_neigh_notify;
                   1095:   P->import_control = rip_import_control;
                   1096:   P->reload_routes = rip_reload_routes;
                   1097:   P->make_tmp_attrs = rip_make_tmp_attrs;
                   1098:   P->store_tmp_attrs = rip_store_tmp_attrs;
                   1099:   P->rte_better = rip_rte_better;
                   1100:   P->rte_same = rip_rte_same;
                   1101: 
                   1102:   return P;
                   1103: }
                   1104: 
                   1105: static int
                   1106: rip_start(struct proto *P)
                   1107: {
                   1108:   struct rip_proto *p = (void *) P;
                   1109:   struct rip_config *cf = (void *) (P->cf);
                   1110: 
                   1111:   init_list(&p->iface_list);
                   1112:   fib_init(&p->rtable, P->pool, sizeof(struct rip_entry), 0, rip_init_entry);
                   1113:   p->rte_slab = sl_new(P->pool, sizeof(struct rip_rte));
                   1114:   p->timer = tm_new_set(P->pool, rip_timer, p, 0, 0);
                   1115: 
                   1116:   p->ecmp = cf->ecmp;
                   1117:   p->infinity = cf->infinity;
                   1118:   p->triggered = 0;
                   1119: 
                   1120:   p->log_pkt_tbf = (struct tbf){ .rate = 1, .burst = 5 };
                   1121:   p->log_rte_tbf = (struct tbf){ .rate = 4, .burst = 20 };
                   1122: 
                   1123:   tm_start(p->timer, MIN(cf->min_timeout_time, cf->max_garbage_time));
                   1124: 
                   1125:   return PS_UP;
                   1126: }
                   1127: 
                   1128: static int
                   1129: rip_reconfigure(struct proto *P, struct proto_config *c)
                   1130: {
                   1131:   struct rip_proto *p = (void *) P;
                   1132:   struct rip_config *new = (void *) c;
                   1133:   // struct rip_config *old = (void *) (P->cf);
                   1134: 
                   1135:   if (new->infinity != p->infinity)
                   1136:     return 0;
                   1137: 
                   1138:   TRACE(D_EVENTS, "Reconfiguring");
                   1139: 
                   1140:   p->p.cf = c;
                   1141:   p->ecmp = new->ecmp;
                   1142:   rip_reconfigure_ifaces(p, new);
                   1143: 
                   1144:   p->rt_reload = 1;
                   1145:   rip_kick_timer(p);
                   1146: 
                   1147:   return 1;
                   1148: }
                   1149: 
                   1150: static void
                   1151: rip_get_route_info(rte *rte, byte *buf, ea_list *attrs UNUSED)
                   1152: {
                   1153:   buf += bsprintf(buf, " (%d/%d)", rte->pref, rte->u.rip.metric);
                   1154: 
                   1155:   if (rte->u.rip.tag)
                   1156:     bsprintf(buf, " [%04x]", rte->u.rip.tag);
                   1157: }
                   1158: 
                   1159: static int
                   1160: rip_get_attr(eattr *a, byte *buf, int buflen UNUSED)
                   1161: {
                   1162:   switch (a->id)
                   1163:   {
                   1164:   case EA_RIP_METRIC:
                   1165:     bsprintf(buf, "metric: %d", a->u.data);
                   1166:     return GA_FULL;
                   1167: 
                   1168:   case EA_RIP_TAG:
                   1169:     bsprintf(buf, "tag: %04x", a->u.data);
                   1170:     return GA_FULL;
                   1171: 
                   1172:   default:
                   1173:     return GA_UNKNOWN;
                   1174:   }
                   1175: }
                   1176: 
                   1177: void
                   1178: rip_show_interfaces(struct proto *P, char *iff)
                   1179: {
                   1180:   struct rip_proto *p = (void *) P;
                   1181:   struct rip_iface *ifa = NULL;
                   1182:   struct rip_neighbor *n = NULL;
                   1183: 
                   1184:   if (p->p.proto_state != PS_UP)
                   1185:   {
                   1186:     cli_msg(-1021, "%s: is not up", p->p.name);
                   1187:     cli_msg(0, "");
                   1188:     return;
                   1189:   }
                   1190: 
                   1191:   cli_msg(-1021, "%s:", p->p.name);
                   1192:   cli_msg(-1021, "%-10s %-6s %6s %6s %6s",
                   1193:          "Interface", "State", "Metric", "Nbrs", "Timer");
                   1194: 
                   1195:   WALK_LIST(ifa, p->iface_list)
                   1196:   {
                   1197:     if (iff && !patmatch(iff, ifa->iface->name))
                   1198:       continue;
                   1199: 
                   1200:     int nbrs = 0;
                   1201:     WALK_LIST(n, ifa->neigh_list)
                   1202:       if (n->last_seen)
                   1203:        nbrs++;
                   1204: 
                   1205:     int timer = MAX(ifa->next_regular - now, 0);
                   1206:     cli_msg(-1021, "%-10s %-6s %6u %6u %6u",
                   1207:            ifa->iface->name, (ifa->up ? "Up" : "Down"), ifa->cf->metric, nbrs, timer);
                   1208:   }
                   1209: 
                   1210:   cli_msg(0, "");
                   1211: }
                   1212: 
                   1213: void
                   1214: rip_show_neighbors(struct proto *P, char *iff)
                   1215: {
                   1216:   struct rip_proto *p = (void *) P;
                   1217:   struct rip_iface *ifa = NULL;
                   1218:   struct rip_neighbor *n = NULL;
                   1219: 
                   1220:   if (p->p.proto_state != PS_UP)
                   1221:   {
                   1222:     cli_msg(-1022, "%s: is not up", p->p.name);
                   1223:     cli_msg(0, "");
                   1224:     return;
                   1225:   }
                   1226: 
                   1227:   cli_msg(-1022, "%s:", p->p.name);
                   1228:   cli_msg(-1022, "%-25s %-10s %6s %6s %6s",
                   1229:          "IP address", "Interface", "Metric", "Routes", "Seen");
                   1230: 
                   1231:   WALK_LIST(ifa, p->iface_list)
                   1232:   {
                   1233:     if (iff && !patmatch(iff, ifa->iface->name))
                   1234:       continue;
                   1235: 
                   1236:     WALK_LIST(n, ifa->neigh_list)
                   1237:     {
                   1238:       if (!n->last_seen)
                   1239:        continue;
                   1240: 
                   1241:       int timer = now - n->last_seen;
                   1242:       cli_msg(-1022, "%-25I %-10s %6u %6u %6u",
                   1243:              n->nbr->addr, ifa->iface->name, ifa->cf->metric, n->uc, timer);
                   1244:     }
                   1245:   }
                   1246: 
                   1247:   cli_msg(0, "");
                   1248: }
                   1249: 
                   1250: static void
                   1251: rip_dump(struct proto *P)
                   1252: {
                   1253:   struct rip_proto *p = (struct rip_proto *) P;
                   1254:   struct rip_iface *ifa;
                   1255:   int i;
                   1256: 
                   1257:   i = 0;
                   1258:   FIB_WALK(&p->rtable, e)
                   1259:   {
                   1260:     struct rip_entry *en = (struct rip_entry *) e;
                   1261:     debug("RIP: entry #%d: %I/%d via %I dev %s valid %d metric %d age %d s\n",
                   1262:          i++, en->n.prefix, en->n.pxlen, en->next_hop, en->iface->name,
                   1263:          en->valid, en->metric, now - en->changed);
                   1264:   }
                   1265:   FIB_WALK_END;
                   1266: 
                   1267:   i = 0;
                   1268:   WALK_LIST(ifa, p->iface_list)
                   1269:   {
                   1270:     debug("RIP: interface #%d: %s, %I, up = %d, busy = %d\n",
                   1271:          i++, ifa->iface->name, ifa->sk ? ifa->sk->daddr : IPA_NONE,
                   1272:          ifa->up, ifa->tx_active);
                   1273:   }
                   1274: }
                   1275: 
                   1276: 
                   1277: struct protocol proto_rip = {
                   1278:   .name =              "RIP",
                   1279:   .template =          "rip%d",
                   1280:   .attr_class =                EAP_RIP,
                   1281:   .preference =                DEF_PREF_RIP,
                   1282:   .config_size =       sizeof(struct rip_config),
                   1283:   .init =              rip_init,
                   1284:   .dump =              rip_dump,
                   1285:   .start =             rip_start,
                   1286:   .reconfigure =       rip_reconfigure,
                   1287:   .get_route_info =    rip_get_route_info,
                   1288:   .get_attr =          rip_get_attr
                   1289: };

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