Annotation of embedaddon/bird/proto/rip/rip.c, revision 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>