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