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