Annotation of embedaddon/bird/nest/proto.c, revision 1.1.1.2
1.1 misho 1: /*
2: * BIRD -- Protocols
3: *
4: * (c) 1998--2000 Martin Mares <mj@ucw.cz>
5: *
6: * Can be freely distributed and used under the terms of the GNU GPL.
7: */
8:
9: #undef LOCAL_DEBUG
10:
11: #include "nest/bird.h"
12: #include "nest/protocol.h"
13: #include "lib/resource.h"
14: #include "lib/lists.h"
15: #include "lib/event.h"
16: #include "lib/string.h"
17: #include "conf/conf.h"
18: #include "nest/route.h"
19: #include "nest/iface.h"
20: #include "nest/cli.h"
21: #include "filter/filter.h"
22:
23: pool *proto_pool;
24:
25: static list protocol_list;
26: static list proto_list;
27:
28: #define PD(pr, msg, args...) do { if (pr->debug & D_STATES) { log(L_TRACE "%s: " msg, pr->name , ## args); } } while(0)
29:
30: list active_proto_list;
31: static list inactive_proto_list;
32: static list initial_proto_list;
33: static list flush_proto_list;
34: static struct proto *initial_device_proto;
35:
36: static event *proto_flush_event;
37: static timer *proto_shutdown_timer;
38: static timer *gr_wait_timer;
39:
40: #define GRS_NONE 0
41: #define GRS_INIT 1
42: #define GRS_ACTIVE 2
43: #define GRS_DONE 3
44:
45: static int graceful_restart_state;
46: static u32 graceful_restart_locks;
47:
48: static char *p_states[] = { "DOWN", "START", "UP", "STOP" };
49: static char *c_states[] = { "HUNGRY", "???", "HAPPY", "FLUSHING" };
50:
51: static void proto_flush_loop(void *);
52: static void proto_shutdown_loop(struct timer *);
53: static void proto_rethink_goal(struct proto *p);
54: static void proto_want_export_up(struct proto *p);
55: static void proto_fell_down(struct proto *p);
56: static char *proto_state_name(struct proto *p);
57:
58: static void
59: proto_relink(struct proto *p)
60: {
61: list *l = NULL;
62:
63: switch (p->core_state)
64: {
65: case FS_HUNGRY:
66: l = &inactive_proto_list;
67: break;
68: case FS_HAPPY:
69: l = &active_proto_list;
70: break;
71: case FS_FLUSHING:
72: l = &flush_proto_list;
73: break;
74: default:
75: ASSERT(0);
76: }
77:
78: rem_node(&p->n);
79: add_tail(l, &p->n);
80: }
81:
82: static void
83: proto_log_state_change(struct proto *p)
84: {
85: if (p->debug & D_STATES)
86: {
87: char *name = proto_state_name(p);
88: if (name != p->last_state_name_announced)
89: {
90: p->last_state_name_announced = name;
91: PD(p, "State changed to %s", proto_state_name(p));
92: }
93: }
94: else
95: p->last_state_name_announced = NULL;
96: }
97:
98:
99: /**
100: * proto_new - create a new protocol instance
101: * @c: protocol configuration
102: * @size: size of protocol data structure (each protocol instance is represented by
103: * a structure starting with generic part [struct &proto] and continued
104: * with data specific to the protocol)
105: *
106: * When a new configuration has been read in, the core code starts
107: * initializing all the protocol instances configured by calling their
108: * init() hooks with the corresponding instance configuration. The initialization
109: * code of the protocol is expected to create a new instance according to the
110: * configuration by calling this function and then modifying the default settings
111: * to values wanted by the protocol.
112: */
113: void *
114: proto_new(struct proto_config *c, unsigned size)
115: {
116: struct protocol *pr = c->protocol;
117: struct proto *p = mb_allocz(proto_pool, size);
118:
119: p->cf = c;
120: p->debug = c->debug;
121: p->mrtdump = c->mrtdump;
122: p->name = c->name;
123: p->preference = c->preference;
124: p->disabled = c->disabled;
125: p->proto = pr;
126: p->table = c->table->table;
127: p->hash_key = random_u32();
128: c->proto = p;
129: return p;
130: }
131:
132: static void
133: proto_init_instance(struct proto *p)
134: {
135: /* Here we cannot use p->cf->name since it won't survive reconfiguration */
136: p->pool = rp_new(proto_pool, p->proto->name);
137: p->attn = ev_new(p->pool);
138: p->attn->data = p;
139:
140: if (graceful_restart_state == GRS_INIT)
141: p->gr_recovery = 1;
142:
143: if (! p->proto->multitable)
144: rt_lock_table(p->table);
145: }
146:
147: extern pool *rt_table_pool;
148: /**
149: * proto_add_announce_hook - connect protocol to a routing table
150: * @p: protocol instance
151: * @t: routing table to connect to
152: * @stats: per-table protocol statistics
153: *
154: * This function creates a connection between the protocol instance @p and the
155: * routing table @t, making the protocol hear all changes in the table.
156: *
157: * The announce hook is linked in the protocol ahook list. Announce hooks are
158: * allocated from the routing table resource pool and when protocol accepts
159: * routes also in the table ahook list. The are linked to the table ahook list
160: * and unlinked from it depending on export_state (in proto_want_export_up() and
161: * proto_want_export_down()) and they are automatically freed after the protocol
162: * is flushed (in proto_fell_down()).
163: *
164: * Unless you want to listen to multiple routing tables (as the Pipe protocol
165: * does), you needn't to worry about this function since the connection to the
166: * protocol's primary routing table is initialized automatically by the core
167: * code.
168: */
169: struct announce_hook *
170: proto_add_announce_hook(struct proto *p, struct rtable *t, struct proto_stats *stats)
171: {
172: struct announce_hook *h;
173:
174: DBG("Connecting protocol %s to table %s\n", p->name, t->name);
175: PD(p, "Connected to table %s", t->name);
176:
177: h = mb_allocz(rt_table_pool, sizeof(struct announce_hook));
178: h->table = t;
179: h->proto = p;
180: h->stats = stats;
181:
182: h->next = p->ahooks;
183: p->ahooks = h;
184:
185: if (p->rt_notify && (p->export_state != ES_DOWN))
186: add_tail(&t->hooks, &h->n);
187: return h;
188: }
189:
190: /**
191: * proto_find_announce_hook - find announce hooks
192: * @p: protocol instance
193: * @t: routing table
194: *
195: * Returns pointer to announce hook or NULL
196: */
197: struct announce_hook *
198: proto_find_announce_hook(struct proto *p, struct rtable *t)
199: {
200: struct announce_hook *a;
201:
202: for (a = p->ahooks; a; a = a->next)
203: if (a->table == t)
204: return a;
205:
206: return NULL;
207: }
208:
209: static void
210: proto_link_ahooks(struct proto *p)
211: {
212: struct announce_hook *h;
213:
214: if (p->rt_notify)
215: for(h=p->ahooks; h; h=h->next)
216: add_tail(&h->table->hooks, &h->n);
217: }
218:
219: static void
220: proto_unlink_ahooks(struct proto *p)
221: {
222: struct announce_hook *h;
223:
224: if (p->rt_notify)
225: for(h=p->ahooks; h; h=h->next)
226: rem_node(&h->n);
227: }
228:
229: static void
230: proto_free_ahooks(struct proto *p)
231: {
232: struct announce_hook *h, *hn;
233:
234: for(h = p->ahooks; h; h = hn)
235: {
236: hn = h->next;
237: mb_free(h);
238: }
239:
240: p->ahooks = NULL;
241: p->main_ahook = NULL;
242: }
243:
244:
245: /**
246: * proto_config_new - create a new protocol configuration
247: * @pr: protocol the configuration will belong to
248: * @class: SYM_PROTO or SYM_TEMPLATE
249: *
250: * Whenever the configuration file says that a new instance
251: * of a routing protocol should be created, the parser calls
252: * proto_config_new() to create a configuration entry for this
253: * instance (a structure staring with the &proto_config header
254: * containing all the generic items followed by protocol-specific
255: * ones). Also, the configuration entry gets added to the list
256: * of protocol instances kept in the configuration.
257: *
258: * The function is also used to create protocol templates (when class
259: * SYM_TEMPLATE is specified), the only difference is that templates
260: * are not added to the list of protocol instances and therefore not
261: * initialized during protos_commit()).
262: */
263: void *
264: proto_config_new(struct protocol *pr, int class)
265: {
266: struct proto_config *c = cfg_allocz(pr->config_size);
267:
268: if (class == SYM_PROTO)
269: add_tail(&new_config->protos, &c->n);
270: c->global = new_config;
271: c->protocol = pr;
272: c->name = pr->name;
273: c->preference = pr->preference;
274: c->class = class;
275: c->out_filter = FILTER_REJECT;
276: c->table = c->global->master_rtc;
277: c->debug = new_config->proto_default_debug;
278: c->mrtdump = new_config->proto_default_mrtdump;
279: return c;
280: }
281:
282: /**
283: * proto_copy_config - copy a protocol configuration
284: * @dest: destination protocol configuration
285: * @src: source protocol configuration
286: *
287: * Whenever a new instance of a routing protocol is created from the
288: * template, proto_copy_config() is called to copy a content of
289: * the source protocol configuration to the new protocol configuration.
290: * Name, class and a node in protos list of @dest are kept intact.
291: * copy_config() protocol hook is used to copy protocol-specific data.
292: */
293: void
294: proto_copy_config(struct proto_config *dest, struct proto_config *src)
295: {
296: node old_node;
297: int old_class;
298: char *old_name;
299:
300: if (dest->protocol != src->protocol)
301: cf_error("Can't copy configuration from a different protocol type");
302:
303: if (dest->protocol->copy_config == NULL)
304: cf_error("Inheriting configuration for %s is not supported", src->protocol->name);
305:
306: DBG("Copying configuration from %s to %s\n", src->name, dest->name);
307:
308: /*
309: * Copy struct proto_config here. Keep original node, class and name.
310: * protocol-specific config copy is handled by protocol copy_config() hook
311: */
312:
313: old_node = dest->n;
314: old_class = dest->class;
315: old_name = dest->name;
316:
317: memcpy(dest, src, sizeof(struct proto_config));
318:
319: dest->n = old_node;
320: dest->class = old_class;
321: dest->name = old_name;
322:
323: dest->protocol->copy_config(dest, src);
324: }
325:
326: /**
327: * protos_preconfig - pre-configuration processing
328: * @c: new configuration
329: *
330: * This function calls the preconfig() hooks of all routing
331: * protocols available to prepare them for reading of the new
332: * configuration.
333: */
334: void
335: protos_preconfig(struct config *c)
336: {
337: struct protocol *p;
338:
339: init_list(&c->protos);
340: DBG("Protocol preconfig:");
341: WALK_LIST(p, protocol_list)
342: {
343: DBG(" %s", p->name);
344: p->name_counter = 0;
345: if (p->preconfig)
346: p->preconfig(p, c);
347: }
348: DBG("\n");
349: }
350:
351: /**
352: * protos_postconfig - post-configuration processing
353: * @c: new configuration
354: *
355: * This function calls the postconfig() hooks of all protocol
356: * instances specified in configuration @c. The hooks are not
357: * called for protocol templates.
358: */
359: void
360: protos_postconfig(struct config *c)
361: {
362: struct proto_config *x;
363: struct protocol *p;
364:
365: DBG("Protocol postconfig:");
366: WALK_LIST(x, c->protos)
367: {
368: DBG(" %s", x->name);
369:
370: p = x->protocol;
371: if (p->postconfig)
372: p->postconfig(x);
373: }
374: DBG("\n");
375: }
376:
377: extern struct protocol proto_unix_iface;
378:
379: static struct proto *
380: proto_init(struct proto_config *c)
381: {
382: struct protocol *p = c->protocol;
383: struct proto *q = p->init(c);
384:
385: q->proto_state = PS_DOWN;
386: q->core_state = FS_HUNGRY;
387: q->export_state = ES_DOWN;
388: q->last_state_change = now;
1.1.1.2 ! misho 389: q->vrf = c->vrf;
! 390: q->vrf_set = c->vrf_set;
1.1 misho 391:
392: add_tail(&initial_proto_list, &q->n);
393:
394: if (p == &proto_unix_iface)
395: initial_device_proto = q;
396:
397: add_tail(&proto_list, &q->glob_node);
398: PD(q, "Initializing%s", q->disabled ? " [disabled]" : "");
399: return q;
400: }
401:
402: int proto_reconfig_type; /* Hack to propagate type info to pipe reconfigure hook */
403:
404: static int
405: proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config *nc, int type)
406: {
407: /* If the protocol is DOWN, we just restart it */
408: if (p->proto_state == PS_DOWN)
409: return 0;
410:
411: /* If there is a too big change in core attributes, ... */
412: if ((nc->protocol != oc->protocol) ||
413: (nc->disabled != p->disabled) ||
1.1.1.2 ! misho 414: (nc->vrf != oc->vrf) ||
! 415: (nc->vrf_set != oc->vrf_set) ||
1.1 misho 416: (nc->table->table != oc->table->table))
417: return 0;
418:
419: p->debug = nc->debug;
420: p->mrtdump = nc->mrtdump;
421: proto_reconfig_type = type;
422:
423: /* Execute protocol specific reconfigure hook */
424: if (! (p->proto->reconfigure && p->proto->reconfigure(p, nc)))
425: return 0;
426:
427: DBG("\t%s: same\n", oc->name);
428: PD(p, "Reconfigured");
429: p->cf = nc;
430: p->name = nc->name;
431: p->preference = nc->preference;
432:
433:
434: /* Multitable protocols handle rest in their reconfigure hooks */
435: if (p->proto->multitable)
436: return 1;
437:
1.1.1.2 ! misho 438: int import_changed = ! filter_same(nc->in_filter, oc->in_filter);
! 439: int export_changed = ! filter_same(nc->out_filter, oc->out_filter);
! 440:
! 441: /* We treat a change in preferences by reimporting routes */
! 442: if (nc->preference != oc->preference)
! 443: import_changed = 1;
! 444:
1.1 misho 445: /* Update filters and limits in the main announce hook
446: Note that this also resets limit state */
447: if (p->main_ahook)
1.1.1.2 ! misho 448: {
1.1 misho 449: struct announce_hook *ah = p->main_ahook;
450: ah->in_filter = nc->in_filter;
451: ah->out_filter = nc->out_filter;
452: ah->rx_limit = nc->rx_limit;
453: ah->in_limit = nc->in_limit;
454: ah->out_limit = nc->out_limit;
455: ah->in_keep_filtered = nc->in_keep_filtered;
456: proto_verify_limits(ah);
1.1.1.2 ! misho 457:
! 458: if (export_changed)
! 459: ah->last_out_filter_change = now;
1.1 misho 460: }
461:
462: /* Update routes when filters changed. If the protocol in not UP,
463: it has no routes and we can ignore such changes */
464: if ((p->proto_state != PS_UP) || (type == RECONFIG_SOFT))
465: return 1;
466:
467: if (import_changed || export_changed)
468: log(L_INFO "Reloading protocol %s", p->name);
469:
470: /* If import filter changed, call reload hook */
471: if (import_changed && ! (p->reload_routes && p->reload_routes(p)))
472: {
473: /* Now, the protocol is reconfigured. But route reload failed
474: and we have to do regular protocol restart. */
475: log(L_INFO "Restarting protocol %s", p->name);
476: p->disabled = 1;
477: p->down_code = PDC_CF_RESTART;
478: proto_rethink_goal(p);
479: p->disabled = 0;
480: proto_rethink_goal(p);
481: return 1;
482: }
483:
484: if (export_changed)
485: proto_request_feeding(p);
486:
487: return 1;
488: }
489:
490: /**
491: * protos_commit - commit new protocol configuration
492: * @new: new configuration
493: * @old: old configuration or %NULL if it's boot time config
494: * @force_reconfig: force restart of all protocols (used for example
495: * when the router ID changes)
496: * @type: type of reconfiguration (RECONFIG_SOFT or RECONFIG_HARD)
497: *
498: * Scan differences between @old and @new configuration and adjust all
499: * protocol instances to conform to the new configuration.
500: *
501: * When a protocol exists in the new configuration, but it doesn't in the
502: * original one, it's immediately started. When a collision with the other
503: * running protocol would arise, the new protocol will be temporarily stopped
504: * by the locking mechanism.
505: *
506: * When a protocol exists in the old configuration, but it doesn't in the
507: * new one, it's shut down and deleted after the shutdown completes.
508: *
509: * When a protocol exists in both configurations, the core decides
510: * whether it's possible to reconfigure it dynamically - it checks all
511: * the core properties of the protocol (changes in filters are ignored
512: * if type is RECONFIG_SOFT) and if they match, it asks the
513: * reconfigure() hook of the protocol to see if the protocol is able
514: * to switch to the new configuration. If it isn't possible, the
515: * protocol is shut down and a new instance is started with the new
516: * configuration after the shutdown is completed.
517: */
518: void
519: protos_commit(struct config *new, struct config *old, int force_reconfig, int type)
520: {
521: struct proto_config *oc, *nc;
522: struct proto *p, *n;
523: struct symbol *sym;
524:
525: DBG("protos_commit:\n");
526: if (old)
527: {
528: WALK_LIST(oc, old->protos)
529: {
530: p = oc->proto;
531: sym = cf_find_symbol(new, oc->name);
532: if (sym && sym->class == SYM_PROTO && !new->shutdown)
533: {
534: /* Found match, let's check if we can smoothly switch to new configuration */
535: /* No need to check description */
536: nc = sym->def;
537: nc->proto = p;
538:
539: /* We will try to reconfigure protocol p */
540: if (! force_reconfig && proto_reconfigure(p, oc, nc, type))
541: continue;
542:
543: /* Unsuccessful, we will restart it */
544: if (!p->disabled && !nc->disabled)
545: log(L_INFO "Restarting protocol %s", p->name);
546: else if (p->disabled && !nc->disabled)
547: log(L_INFO "Enabling protocol %s", p->name);
548: else if (!p->disabled && nc->disabled)
549: log(L_INFO "Disabling protocol %s", p->name);
550:
551: p->down_code = nc->disabled ? PDC_CF_DISABLE : PDC_CF_RESTART;
552: p->cf_new = nc;
553: }
554: else if (!new->shutdown)
555: {
556: log(L_INFO "Removing protocol %s", p->name);
557: p->down_code = PDC_CF_REMOVE;
558: p->cf_new = NULL;
559: }
560: else /* global shutdown */
561: {
562: p->down_code = PDC_CMD_SHUTDOWN;
563: p->cf_new = NULL;
564: }
565:
566: p->reconfiguring = 1;
567: config_add_obstacle(old);
568: proto_rethink_goal(p);
569: }
570: }
571:
572: WALK_LIST(nc, new->protos)
573: if (!nc->proto)
574: {
575: if (old) /* Not a first-time configuration */
576: log(L_INFO "Adding protocol %s", nc->name);
577: proto_init(nc);
578: }
579: DBG("\tdone\n");
580:
581: DBG("Protocol start\n");
582:
583: /* Start device protocol first */
584: if (initial_device_proto)
585: {
586: proto_rethink_goal(initial_device_proto);
587: initial_device_proto = NULL;
588: }
589:
590: /* Determine router ID for the first time - it has to be here and not in
591: global_commit() because it is postponed after start of device protocol */
592: if (!config->router_id)
593: {
594: config->router_id = if_choose_router_id(config->router_id_from, 0);
595: if (!config->router_id)
596: die("Cannot determine router ID, please configure it manually");
597: }
598:
599: /* Start all other protocols */
600: WALK_LIST_DELSAFE(p, n, initial_proto_list)
601: proto_rethink_goal(p);
602: }
603:
604: static void
605: proto_rethink_goal(struct proto *p)
606: {
607: struct protocol *q;
608: byte goal;
609:
610: if (p->reconfiguring && p->core_state == FS_HUNGRY && p->proto_state == PS_DOWN)
611: {
612: struct proto_config *nc = p->cf_new;
613: DBG("%s has shut down for reconfiguration\n", p->name);
614: p->cf->proto = NULL;
615: config_del_obstacle(p->cf->global);
616: rem_node(&p->n);
617: rem_node(&p->glob_node);
1.1.1.2 ! misho 618: mb_free(p->message);
1.1 misho 619: mb_free(p);
620: if (!nc)
621: return;
622: p = proto_init(nc);
623: }
624:
625: /* Determine what state we want to reach */
626: if (p->disabled || p->reconfiguring)
627: goal = PS_DOWN;
628: else
629: goal = PS_UP;
630:
631: q = p->proto;
632: if (goal == PS_UP) /* Going up */
633: {
634: if (p->proto_state == PS_DOWN && p->core_state == FS_HUNGRY)
635: {
636: DBG("Kicking %s up\n", p->name);
637: PD(p, "Starting");
638: proto_init_instance(p);
639: proto_notify_state(p, (q->start ? q->start(p) : PS_UP));
640: }
641: }
642: else /* Going down */
643: {
644: if (p->proto_state == PS_START || p->proto_state == PS_UP)
645: {
646: DBG("Kicking %s down\n", p->name);
647: PD(p, "Shutting down");
648: proto_notify_state(p, (q->shutdown ? q->shutdown(p) : PS_DOWN));
649: }
650: }
651: }
652:
653:
654: /**
655: * DOC: Graceful restart recovery
656: *
657: * Graceful restart of a router is a process when the routing plane (e.g. BIRD)
658: * restarts but both the forwarding plane (e.g kernel routing table) and routing
659: * neighbors keep proper routes, and therefore uninterrupted packet forwarding
660: * is maintained.
661: *
662: * BIRD implements graceful restart recovery by deferring export of routes to
663: * protocols until routing tables are refilled with the expected content. After
664: * start, protocols generate routes as usual, but routes are not propagated to
665: * them, until protocols report that they generated all routes. After that,
666: * graceful restart recovery is finished and the export (and the initial feed)
667: * to protocols is enabled.
668: *
669: * When graceful restart recovery need is detected during initialization, then
670: * enabled protocols are marked with @gr_recovery flag before start. Such
671: * protocols then decide how to proceed with graceful restart, participation is
672: * voluntary. Protocols could lock the recovery by proto_graceful_restart_lock()
673: * (stored in @gr_lock flag), which means that they want to postpone the end of
674: * the recovery until they converge and then unlock it. They also could set
675: * @gr_wait before advancing to %PS_UP, which means that the core should defer
676: * route export to that protocol until the end of the recovery. This should be
677: * done by protocols that expect their neigbors to keep the proper routes
678: * (kernel table, BGP sessions with BGP graceful restart capability).
679: *
680: * The graceful restart recovery is finished when either all graceful restart
681: * locks are unlocked or when graceful restart wait timer fires.
682: *
683: */
684:
685: static void graceful_restart_done(struct timer *t);
686:
687: /**
688: * graceful_restart_recovery - request initial graceful restart recovery
689: *
690: * Called by the platform initialization code if the need for recovery
691: * after graceful restart is detected during boot. Have to be called
692: * before protos_commit().
693: */
694: void
695: graceful_restart_recovery(void)
696: {
697: graceful_restart_state = GRS_INIT;
698: }
699:
700: /**
701: * graceful_restart_init - initialize graceful restart
702: *
703: * When graceful restart recovery was requested, the function starts an active
704: * phase of the recovery and initializes graceful restart wait timer. The
705: * function have to be called after protos_commit().
706: */
707: void
708: graceful_restart_init(void)
709: {
710: if (!graceful_restart_state)
711: return;
712:
713: log(L_INFO "Graceful restart started");
714:
715: if (!graceful_restart_locks)
716: {
717: graceful_restart_done(NULL);
718: return;
719: }
720:
721: graceful_restart_state = GRS_ACTIVE;
722: gr_wait_timer = tm_new(proto_pool);
723: gr_wait_timer->hook = graceful_restart_done;
724: tm_start(gr_wait_timer, config->gr_wait);
725: }
726:
727: /**
728: * graceful_restart_done - finalize graceful restart
729: * @t: unused
730: *
731: * When there are no locks on graceful restart, the functions finalizes the
732: * graceful restart recovery. Protocols postponing route export until the end of
733: * the recovery are awakened and the export to them is enabled. All other
734: * related state is cleared. The function is also called when the graceful
735: * restart wait timer fires (but there are still some locks).
736: */
737: static void
738: graceful_restart_done(struct timer *t UNUSED)
739: {
740: struct proto *p;
741: node *n;
742:
743: log(L_INFO "Graceful restart done");
744: graceful_restart_state = GRS_DONE;
745:
746: WALK_LIST2(p, n, proto_list, glob_node)
747: {
748: if (!p->gr_recovery)
749: continue;
750:
751: /* Resume postponed export of routes */
752: if ((p->proto_state == PS_UP) && p->gr_wait)
753: {
754: proto_want_export_up(p);
755: proto_log_state_change(p);
756: }
757:
758: /* Cleanup */
759: p->gr_recovery = 0;
760: p->gr_wait = 0;
761: p->gr_lock = 0;
762: }
763:
764: graceful_restart_locks = 0;
765: }
766:
767: void
768: graceful_restart_show_status(void)
769: {
770: if (graceful_restart_state != GRS_ACTIVE)
771: return;
772:
773: cli_msg(-24, "Graceful restart recovery in progress");
774: cli_msg(-24, " Waiting for %d protocols to recover", graceful_restart_locks);
775: cli_msg(-24, " Wait timer is %d/%d", tm_remains(gr_wait_timer), config->gr_wait);
776: }
777:
778: /**
779: * proto_graceful_restart_lock - lock graceful restart by protocol
780: * @p: protocol instance
781: *
782: * This function allows a protocol to postpone the end of graceful restart
783: * recovery until it converges. The lock is removed when the protocol calls
784: * proto_graceful_restart_unlock() or when the protocol is stopped.
785: *
786: * The function have to be called during the initial phase of graceful restart
787: * recovery and only for protocols that are part of graceful restart (i.e. their
788: * @gr_recovery is set), which means it should be called from protocol start
789: * hooks.
790: */
791: void
792: proto_graceful_restart_lock(struct proto *p)
793: {
794: ASSERT(graceful_restart_state == GRS_INIT);
795: ASSERT(p->gr_recovery);
796:
797: if (p->gr_lock)
798: return;
799:
800: p->gr_lock = 1;
801: graceful_restart_locks++;
802: }
803:
804: /**
805: * proto_graceful_restart_unlock - unlock graceful restart by protocol
806: * @p: protocol instance
807: *
808: * This function unlocks a lock from proto_graceful_restart_lock(). It is also
809: * automatically called when the lock holding protocol went down.
810: */
811: void
812: proto_graceful_restart_unlock(struct proto *p)
813: {
814: if (!p->gr_lock)
815: return;
816:
817: p->gr_lock = 0;
818: graceful_restart_locks--;
819:
820: if ((graceful_restart_state == GRS_ACTIVE) && !graceful_restart_locks)
821: tm_start(gr_wait_timer, 0);
822: }
823:
824:
825:
826: /**
827: * protos_dump_all - dump status of all protocols
828: *
829: * This function dumps status of all existing protocol instances to the
830: * debug output. It involves printing of general status information
831: * such as protocol states, its position on the protocol lists
832: * and also calling of a dump() hook of the protocol to print
833: * the internals.
834: */
835: void
836: protos_dump_all(void)
837: {
838: struct proto *p;
839: struct announce_hook *a;
840:
841: debug("Protocols:\n");
842:
843: WALK_LIST(p, active_proto_list)
844: {
845: debug(" protocol %s state %s/%s\n", p->name,
846: p_states[p->proto_state], c_states[p->core_state]);
847: for (a = p->ahooks; a; a = a->next)
848: {
849: debug("\tTABLE %s\n", a->table->name);
850: if (a->in_filter)
851: debug("\tInput filter: %s\n", filter_name(a->in_filter));
852: if (a->out_filter != FILTER_REJECT)
853: debug("\tOutput filter: %s\n", filter_name(a->out_filter));
854: }
855: if (p->disabled)
856: debug("\tDISABLED\n");
857: else if (p->proto->dump)
858: p->proto->dump(p);
859: }
860: WALK_LIST(p, inactive_proto_list)
861: debug(" inactive %s: state %s/%s\n", p->name, p_states[p->proto_state], c_states[p->core_state]);
862: WALK_LIST(p, initial_proto_list)
863: debug(" initial %s\n", p->name);
864: WALK_LIST(p, flush_proto_list)
865: debug(" flushing %s\n", p->name);
866: }
867:
868: /**
869: * proto_build - make a single protocol available
870: * @p: the protocol
871: *
872: * After the platform specific initialization code uses protos_build()
873: * to add all the standard protocols, it should call proto_build() for
874: * all platform specific protocols to inform the core that they exist.
875: */
876: void
877: proto_build(struct protocol *p)
878: {
879: add_tail(&protocol_list, &p->n);
880: if (p->attr_class)
881: {
882: ASSERT(!attr_class_to_protocol[p->attr_class]);
883: attr_class_to_protocol[p->attr_class] = p;
884: }
885: }
886:
887: /* FIXME: convert this call to some protocol hook */
888: extern void bfd_init_all(void);
889:
890: /**
891: * protos_build - build a protocol list
892: *
893: * This function is called during BIRD startup to insert
894: * all standard protocols to the global protocol list. Insertion
895: * of platform specific protocols (such as the kernel syncer)
896: * is in the domain of competence of the platform dependent
897: * startup code.
898: */
899: void
900: protos_build(void)
901: {
902: init_list(&protocol_list);
903: init_list(&proto_list);
904: init_list(&active_proto_list);
905: init_list(&inactive_proto_list);
906: init_list(&initial_proto_list);
907: init_list(&flush_proto_list);
908: proto_build(&proto_device);
909: #ifdef CONFIG_RADV
910: proto_build(&proto_radv);
911: #endif
912: #ifdef CONFIG_RIP
913: proto_build(&proto_rip);
914: #endif
915: #ifdef CONFIG_STATIC
916: proto_build(&proto_static);
917: #endif
1.1.1.2 ! misho 918: #ifdef CONFIG_MRT
! 919: proto_build(&proto_mrt);
! 920: #endif
1.1 misho 921: #ifdef CONFIG_OSPF
922: proto_build(&proto_ospf);
923: #endif
924: #ifdef CONFIG_PIPE
925: proto_build(&proto_pipe);
926: #endif
927: #ifdef CONFIG_BGP
928: proto_build(&proto_bgp);
929: #endif
930: #ifdef CONFIG_BFD
931: proto_build(&proto_bfd);
932: bfd_init_all();
933: #endif
934: #ifdef CONFIG_BABEL
935: proto_build(&proto_babel);
936: #endif
937:
938: proto_pool = rp_new(&root_pool, "Protocols");
939: proto_flush_event = ev_new(proto_pool);
940: proto_flush_event->hook = proto_flush_loop;
941: proto_shutdown_timer = tm_new(proto_pool);
942: proto_shutdown_timer->hook = proto_shutdown_loop;
943: }
944:
945: static void
946: proto_feed_more(void *P)
947: {
948: struct proto *p = P;
949:
950: if (p->export_state != ES_FEEDING)
951: return;
952:
953: DBG("Feeding protocol %s continued\n", p->name);
954: if (rt_feed_baby(p))
955: {
956: DBG("Feeding protocol %s finished\n", p->name);
957: p->export_state = ES_READY;
958: proto_log_state_change(p);
959:
960: if (p->feed_end)
961: p->feed_end(p);
962: }
963: else
964: {
965: p->attn->hook = proto_feed_more;
966: ev_schedule(p->attn); /* Will continue later... */
967: }
968: }
969:
970: static void
971: proto_feed_initial(void *P)
972: {
973: struct proto *p = P;
974:
975: if (p->export_state != ES_FEEDING)
976: return;
977:
978: DBG("Feeding protocol %s\n", p->name);
979:
980: if_feed_baby(p);
981: proto_feed_more(P);
982: }
983:
984: static void
985: proto_schedule_feed(struct proto *p, int initial)
986: {
987: DBG("%s: Scheduling meal\n", p->name);
988:
989: p->export_state = ES_FEEDING;
990: p->refeeding = !initial;
991:
992: p->attn->hook = initial ? proto_feed_initial : proto_feed_more;
993: ev_schedule(p->attn);
994:
995: if (p->feed_begin)
996: p->feed_begin(p, initial);
997: }
998:
999: /*
1000: * Flushing loop is responsible for flushing routes and protocols
1001: * after they went down. It runs in proto_flush_event. At the start of
1002: * one round, protocols waiting to flush are marked in
1003: * proto_schedule_flush_loop(). At the end of the round (when routing
1004: * table flush is complete), marked protocols are flushed and a next
1005: * round may start.
1006: */
1007:
1008: static int flush_loop_state; /* 1 -> running */
1009:
1010: static void
1011: proto_schedule_flush_loop(void)
1012: {
1013: struct proto *p;
1014: struct announce_hook *h;
1015:
1016: if (flush_loop_state)
1017: return;
1018: flush_loop_state = 1;
1019:
1020: WALK_LIST(p, flush_proto_list)
1021: {
1022: p->flushing = 1;
1023: for (h=p->ahooks; h; h=h->next)
1024: rt_mark_for_prune(h->table);
1025: }
1026:
1027: ev_schedule(proto_flush_event);
1028: }
1029:
1030: static void
1031: proto_flush_loop(void *unused UNUSED)
1032: {
1033: struct proto *p;
1034:
1035: if (! rt_prune_loop())
1036: {
1037: /* Rtable pruning is not finished */
1038: ev_schedule(proto_flush_event);
1039: return;
1040: }
1041:
1042: rt_prune_sources();
1043:
1044: again:
1045: WALK_LIST(p, flush_proto_list)
1046: if (p->flushing)
1047: {
1048: /* This will flush interfaces in the same manner
1049: like rt_prune_all() flushes routes */
1050: if (p->proto == &proto_unix_iface)
1051: if_flush_ifaces(p);
1052:
1053: DBG("Flushing protocol %s\n", p->name);
1054: p->flushing = 0;
1055: p->core_state = FS_HUNGRY;
1056: proto_relink(p);
1057: proto_log_state_change(p);
1058: if (p->proto_state == PS_DOWN)
1059: proto_fell_down(p);
1060: goto again;
1061: }
1062:
1063: /* This round finished, perhaps there will be another one */
1064: flush_loop_state = 0;
1065: if (!EMPTY_LIST(flush_proto_list))
1066: proto_schedule_flush_loop();
1067: }
1068:
1069:
1070: /* Temporary hack to propagate restart to BGP */
1071: int proto_restart;
1072:
1073: static void
1074: proto_shutdown_loop(struct timer *t UNUSED)
1075: {
1076: struct proto *p, *p_next;
1077:
1078: WALK_LIST_DELSAFE(p, p_next, active_proto_list)
1079: if (p->down_sched)
1080: {
1081: proto_restart = (p->down_sched == PDS_RESTART);
1082:
1083: p->disabled = 1;
1084: proto_rethink_goal(p);
1085: if (proto_restart)
1086: {
1087: p->disabled = 0;
1088: proto_rethink_goal(p);
1089: }
1090: }
1091: }
1092:
1093: static inline void
1094: proto_schedule_down(struct proto *p, byte restart, byte code)
1095: {
1096: /* Does not work for other states (even PS_START) */
1097: ASSERT(p->proto_state == PS_UP);
1098:
1099: /* Scheduled restart may change to shutdown, but not otherwise */
1100: if (p->down_sched == PDS_DISABLE)
1101: return;
1102:
1103: p->down_sched = restart ? PDS_RESTART : PDS_DISABLE;
1104: p->down_code = code;
1105: tm_start_max(proto_shutdown_timer, restart ? 2 : 0);
1106: }
1107:
1.1.1.2 ! misho 1108: /**
! 1109: * proto_set_message - set administrative message to protocol
! 1110: * @p: protocol
! 1111: * @msg: message
! 1112: * @len: message length (-1 for NULL-terminated string)
! 1113: *
! 1114: * The function sets administrative message (string) related to protocol state
! 1115: * change. It is called by the nest code for manual enable/disable/restart
! 1116: * commands all routes to the protocol, and by protocol-specific code when the
! 1117: * protocol state change is initiated by the protocol. Using NULL message clears
! 1118: * the last message. The message string may be either NULL-terminated or with an
! 1119: * explicit length.
! 1120: */
! 1121: void
! 1122: proto_set_message(struct proto *p, char *msg, int len)
! 1123: {
! 1124: mb_free(p->message);
! 1125: p->message = NULL;
! 1126:
! 1127: if (!msg || !len)
! 1128: return;
! 1129:
! 1130: if (len < 0)
! 1131: len = strlen(msg);
! 1132:
! 1133: if (!len)
! 1134: return;
! 1135:
! 1136: p->message = mb_alloc(proto_pool, len + 1);
! 1137: memcpy(p->message, msg, len);
! 1138: p->message[len] = 0;
! 1139: }
! 1140:
1.1 misho 1141:
1142: /**
1143: * proto_request_feeding - request feeding routes to the protocol
1144: * @p: given protocol
1145: *
1146: * Sometimes it is needed to send again all routes to the
1147: * protocol. This is called feeding and can be requested by this
1148: * function. This would cause protocol export state transition
1149: * to ES_FEEDING (during feeding) and when completed, it will
1150: * switch back to ES_READY. This function can be called even
1151: * when feeding is already running, in that case it is restarted.
1152: */
1153: void
1154: proto_request_feeding(struct proto *p)
1155: {
1156: ASSERT(p->proto_state == PS_UP);
1157:
1158: /* Do nothing if we are still waiting for feeding */
1159: if (p->export_state == ES_DOWN)
1160: return;
1161:
1162: /* If we are already feeding, we want to restart it */
1163: if (p->export_state == ES_FEEDING)
1164: {
1165: /* Unless feeding is in initial state */
1166: if (p->attn->hook == proto_feed_initial)
1167: return;
1168:
1169: rt_feed_baby_abort(p);
1170: }
1171:
1172: /* FIXME: This should be changed for better support of multitable protos */
1173: struct announce_hook *ah;
1174: for (ah = p->ahooks; ah; ah = ah->next)
1175: proto_reset_limit(ah->out_limit);
1176:
1177: /* Hack: reset exp_routes during refeed, and do not decrease it later */
1178: p->stats.exp_routes = 0;
1179:
1180: proto_schedule_feed(p, 0);
1181: proto_log_state_change(p);
1182: }
1183:
1184: static const char *
1185: proto_limit_name(struct proto_limit *l)
1186: {
1187: const char *actions[] = {
1188: [PLA_WARN] = "warn",
1189: [PLA_BLOCK] = "block",
1190: [PLA_RESTART] = "restart",
1191: [PLA_DISABLE] = "disable",
1192: };
1193:
1194: return actions[l->action];
1195: }
1196:
1197: /**
1198: * proto_notify_limit: notify about limit hit and take appropriate action
1199: * @ah: announce hook
1200: * @l: limit being hit
1201: * @dir: limit direction (PLD_*)
1202: * @rt_count: the number of routes
1203: *
1204: * The function is called by the route processing core when limit @l
1205: * is breached. It activates the limit and tooks appropriate action
1206: * according to @l->action.
1207: */
1208: void
1209: proto_notify_limit(struct announce_hook *ah, struct proto_limit *l, int dir, u32 rt_count)
1210: {
1211: const char *dir_name[PLD_MAX] = { "receive", "import" , "export" };
1212: const byte dir_down[PLD_MAX] = { PDC_RX_LIMIT_HIT, PDC_IN_LIMIT_HIT, PDC_OUT_LIMIT_HIT };
1213: struct proto *p = ah->proto;
1214:
1215: if (l->state == PLS_BLOCKED)
1216: return;
1217:
1218: /* For warning action, we want the log message every time we hit the limit */
1219: if (!l->state || ((l->action == PLA_WARN) && (rt_count == l->limit)))
1220: log(L_WARN "Protocol %s hits route %s limit (%d), action: %s",
1221: p->name, dir_name[dir], l->limit, proto_limit_name(l));
1222:
1223: switch (l->action)
1224: {
1225: case PLA_WARN:
1226: l->state = PLS_ACTIVE;
1227: break;
1228:
1229: case PLA_BLOCK:
1230: l->state = PLS_BLOCKED;
1231: break;
1232:
1233: case PLA_RESTART:
1234: case PLA_DISABLE:
1235: l->state = PLS_BLOCKED;
1236: if (p->proto_state == PS_UP)
1237: proto_schedule_down(p, l->action == PLA_RESTART, dir_down[dir]);
1238: break;
1239: }
1240: }
1241:
1242: void
1243: proto_verify_limits(struct announce_hook *ah)
1244: {
1245: struct proto_limit *l;
1246: struct proto_stats *stats = ah->stats;
1247: u32 all_routes = stats->imp_routes + stats->filt_routes;
1248:
1249: l = ah->rx_limit;
1250: if (l && (all_routes > l->limit))
1251: proto_notify_limit(ah, l, PLD_RX, all_routes);
1252:
1253: l = ah->in_limit;
1254: if (l && (stats->imp_routes > l->limit))
1255: proto_notify_limit(ah, l, PLD_IN, stats->imp_routes);
1256:
1257: l = ah->out_limit;
1258: if (l && (stats->exp_routes > l->limit))
1259: proto_notify_limit(ah, l, PLD_OUT, stats->exp_routes);
1260: }
1261:
1262:
1263: static void
1264: proto_want_core_up(struct proto *p)
1265: {
1266: ASSERT(p->core_state == FS_HUNGRY);
1267:
1268: if (!p->proto->multitable)
1269: {
1270: p->main_source = rt_get_source(p, 0);
1271: rt_lock_source(p->main_source);
1272:
1273: /* Connect protocol to routing table */
1274: p->main_ahook = proto_add_announce_hook(p, p->table, &p->stats);
1275: p->main_ahook->in_filter = p->cf->in_filter;
1276: p->main_ahook->out_filter = p->cf->out_filter;
1277: p->main_ahook->rx_limit = p->cf->rx_limit;
1278: p->main_ahook->in_limit = p->cf->in_limit;
1279: p->main_ahook->out_limit = p->cf->out_limit;
1280: p->main_ahook->in_keep_filtered = p->cf->in_keep_filtered;
1281:
1282: proto_reset_limit(p->main_ahook->rx_limit);
1283: proto_reset_limit(p->main_ahook->in_limit);
1284: proto_reset_limit(p->main_ahook->out_limit);
1285: }
1286:
1287: p->core_state = FS_HAPPY;
1288: proto_relink(p);
1289: }
1290:
1291: static void
1292: proto_want_export_up(struct proto *p)
1293: {
1294: ASSERT(p->core_state == FS_HAPPY);
1295: ASSERT(p->export_state == ES_DOWN);
1296:
1297: proto_link_ahooks(p);
1298: proto_schedule_feed(p, 1); /* Sets ES_FEEDING */
1299: }
1300:
1301: static void
1302: proto_want_export_down(struct proto *p)
1303: {
1304: ASSERT(p->export_state != ES_DOWN);
1305:
1306: /* Need to abort feeding */
1307: if (p->export_state == ES_FEEDING)
1308: rt_feed_baby_abort(p);
1309:
1310: p->export_state = ES_DOWN;
1311: p->stats.exp_routes = 0;
1312: proto_unlink_ahooks(p);
1313: }
1314:
1315: static void
1316: proto_want_core_down(struct proto *p)
1317: {
1318: ASSERT(p->core_state == FS_HAPPY);
1319: ASSERT(p->export_state == ES_DOWN);
1320:
1321: p->core_state = FS_FLUSHING;
1322: proto_relink(p);
1323: proto_schedule_flush_loop();
1324:
1325: if (!p->proto->multitable)
1326: {
1327: rt_unlock_source(p->main_source);
1328: p->main_source = NULL;
1329: }
1330: }
1331:
1332: static void
1333: proto_falling_down(struct proto *p)
1334: {
1335: p->gr_recovery = 0;
1336: p->gr_wait = 0;
1337: if (p->gr_lock)
1338: proto_graceful_restart_unlock(p);
1339: }
1340:
1341: static void
1342: proto_fell_down(struct proto *p)
1343: {
1344: DBG("Protocol %s down\n", p->name);
1345:
1346: u32 all_routes = p->stats.imp_routes + p->stats.filt_routes;
1347: if (all_routes != 0)
1348: log(L_ERR "Protocol %s is down but still has %d routes", p->name, all_routes);
1349:
1350: bzero(&p->stats, sizeof(struct proto_stats));
1351: proto_free_ahooks(p);
1352:
1353: if (! p->proto->multitable)
1354: rt_unlock_table(p->table);
1355:
1356: if (p->proto->cleanup)
1357: p->proto->cleanup(p);
1358:
1359: proto_rethink_goal(p);
1360: }
1361:
1362:
1363: /**
1364: * proto_notify_state - notify core about protocol state change
1365: * @p: protocol the state of which has changed
1366: * @ps: the new status
1367: *
1368: * Whenever a state of a protocol changes due to some event internal
1369: * to the protocol (i.e., not inside a start() or shutdown() hook),
1370: * it should immediately notify the core about the change by calling
1371: * proto_notify_state() which will write the new state to the &proto
1372: * structure and take all the actions necessary to adapt to the new
1373: * state. State change to PS_DOWN immediately frees resources of protocol
1374: * and might execute start callback of protocol; therefore,
1375: * it should be used at tail positions of protocol callbacks.
1376: */
1377: void
1378: proto_notify_state(struct proto *p, unsigned ps)
1379: {
1380: unsigned ops = p->proto_state;
1381: unsigned cs = p->core_state;
1382: unsigned es = p->export_state;
1383:
1384: DBG("%s reporting state transition %s/%s -> */%s\n", p->name, c_states[cs], p_states[ops], p_states[ps]);
1385: if (ops == ps)
1386: return;
1387:
1388: p->proto_state = ps;
1389: p->last_state_change = now;
1390:
1391: switch (ps)
1392: {
1393: case PS_START:
1394: ASSERT(ops == PS_DOWN || ops == PS_UP);
1395: ASSERT(cs == FS_HUNGRY || cs == FS_HAPPY);
1396:
1397: if (es != ES_DOWN)
1398: proto_want_export_down(p);
1399: break;
1400:
1401: case PS_UP:
1402: ASSERT(ops == PS_DOWN || ops == PS_START);
1403: ASSERT(cs == FS_HUNGRY || cs == FS_HAPPY);
1404: ASSERT(es == ES_DOWN);
1405:
1406: if (cs == FS_HUNGRY)
1407: proto_want_core_up(p);
1408: if (!p->gr_wait)
1409: proto_want_export_up(p);
1410: break;
1411:
1412: case PS_STOP:
1413: ASSERT(ops == PS_START || ops == PS_UP);
1414:
1415: p->down_sched = 0;
1416:
1417: if (es != ES_DOWN)
1418: proto_want_export_down(p);
1419: if (cs == FS_HAPPY)
1420: proto_want_core_down(p);
1421: proto_falling_down(p);
1422: break;
1423:
1424: case PS_DOWN:
1425: p->down_code = 0;
1426: p->down_sched = 0;
1427:
1428: if (es != ES_DOWN)
1429: proto_want_export_down(p);
1430: if (cs == FS_HAPPY)
1431: proto_want_core_down(p);
1432: if (ops != PS_STOP)
1433: proto_falling_down(p);
1434:
1435: neigh_prune(); // FIXME convert neighbors to resource?
1436: rfree(p->pool);
1437: p->pool = NULL;
1438:
1439: if (cs == FS_HUNGRY) /* Shutdown finished */
1440: {
1441: proto_log_state_change(p);
1442: proto_fell_down(p);
1443: return; /* The protocol might have ceased to exist */
1444: }
1445: break;
1446:
1447: default:
1448: bug("%s: Invalid state %d", p->name, ps);
1449: }
1450:
1451: proto_log_state_change(p);
1452: }
1453:
1454: /*
1455: * CLI Commands
1456: */
1457:
1458: static char *
1459: proto_state_name(struct proto *p)
1460: {
1461: #define P(x,y) ((x << 4) | y)
1462: switch (P(p->proto_state, p->core_state))
1463: {
1464: case P(PS_DOWN, FS_HUNGRY): return "down";
1465: case P(PS_START, FS_HUNGRY):
1466: case P(PS_START, FS_HAPPY): return "start";
1467: case P(PS_UP, FS_HAPPY):
1468: switch (p->export_state)
1469: {
1470: case ES_DOWN: return "wait";
1471: case ES_FEEDING: return "feed";
1472: case ES_READY: return "up";
1473: default: return "???";
1474: }
1475: case P(PS_STOP, FS_HUNGRY):
1476: case P(PS_STOP, FS_FLUSHING): return "stop";
1477: case P(PS_DOWN, FS_FLUSHING): return "flush";
1478: default: return "???";
1479: }
1480: #undef P
1481: }
1482:
1483: static void
1484: proto_show_stats(struct proto_stats *s, int in_keep_filtered)
1485: {
1486: if (in_keep_filtered)
1487: cli_msg(-1006, " Routes: %u imported, %u filtered, %u exported, %u preferred",
1488: s->imp_routes, s->filt_routes, s->exp_routes, s->pref_routes);
1489: else
1490: cli_msg(-1006, " Routes: %u imported, %u exported, %u preferred",
1491: s->imp_routes, s->exp_routes, s->pref_routes);
1492:
1493: cli_msg(-1006, " Route change stats: received rejected filtered ignored accepted");
1494: cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u",
1495: s->imp_updates_received, s->imp_updates_invalid,
1496: s->imp_updates_filtered, s->imp_updates_ignored,
1497: s->imp_updates_accepted);
1498: cli_msg(-1006, " Import withdraws: %10u %10u --- %10u %10u",
1499: s->imp_withdraws_received, s->imp_withdraws_invalid,
1500: s->imp_withdraws_ignored, s->imp_withdraws_accepted);
1501: cli_msg(-1006, " Export updates: %10u %10u %10u --- %10u",
1502: s->exp_updates_received, s->exp_updates_rejected,
1503: s->exp_updates_filtered, s->exp_updates_accepted);
1504: cli_msg(-1006, " Export withdraws: %10u --- --- --- %10u",
1505: s->exp_withdraws_received, s->exp_withdraws_accepted);
1506: }
1507:
1508: void
1509: proto_show_limit(struct proto_limit *l, const char *dsc)
1510: {
1511: if (!l)
1512: return;
1513:
1514: cli_msg(-1006, " %-16s%d%s", dsc, l->limit, l->state ? " [HIT]" : "");
1515: cli_msg(-1006, " Action: %s", proto_limit_name(l));
1516: }
1517:
1518: void
1519: proto_show_basic_info(struct proto *p)
1520: {
1.1.1.2 ! misho 1521: if (p->vrf)
! 1522: cli_msg(-1006, " VRF: %s", p->vrf->name);
! 1523:
1.1 misho 1524: cli_msg(-1006, " Preference: %d", p->preference);
1525: cli_msg(-1006, " Input filter: %s", filter_name(p->cf->in_filter));
1526: cli_msg(-1006, " Output filter: %s", filter_name(p->cf->out_filter));
1527:
1528: if (graceful_restart_state == GRS_ACTIVE)
1529: cli_msg(-1006, " GR recovery: %s%s",
1530: p->gr_lock ? " pending" : "",
1531: p->gr_wait ? " waiting" : "");
1532:
1533: proto_show_limit(p->cf->rx_limit, "Receive limit:");
1534: proto_show_limit(p->cf->in_limit, "Import limit:");
1535: proto_show_limit(p->cf->out_limit, "Export limit:");
1536:
1537: if (p->proto_state != PS_DOWN)
1538: proto_show_stats(&p->stats, p->cf->in_keep_filtered);
1539: }
1540:
1541: void
1.1.1.2 ! misho 1542: proto_cmd_show(struct proto *p, uintptr_t verbose, int cnt)
1.1 misho 1543: {
1544: byte buf[256], tbuf[TM_DATETIME_BUFFER_SIZE];
1545:
1546: /* First protocol - show header */
1547: if (!cnt)
1548: cli_msg(-2002, "name proto table state since info");
1549:
1550: buf[0] = 0;
1551: if (p->proto->get_status)
1552: p->proto->get_status(p, buf);
1553: tm_format_datetime(tbuf, &config->tf_proto, p->last_state_change);
1554: cli_msg(-1002, "%-8s %-8s %-8s %-5s %-10s %s",
1555: p->name,
1556: p->proto->name,
1557: p->table->name,
1558: proto_state_name(p),
1559: tbuf,
1560: buf);
1561: if (verbose)
1562: {
1563: if (p->cf->dsc)
1564: cli_msg(-1006, " Description: %s", p->cf->dsc);
1.1.1.2 ! misho 1565:
! 1566: if (p->message)
! 1567: cli_msg(-1006, " Message: %s", p->message);
! 1568:
1.1 misho 1569: if (p->cf->router_id)
1570: cli_msg(-1006, " Router ID: %R", p->cf->router_id);
1571:
1.1.1.2 ! misho 1572: if (p->vrf_set)
! 1573: cli_msg(-1006, " VRF: %s", p->vrf ? p->vrf->name : "default");
! 1574:
1.1 misho 1575: if (p->proto->show_proto_info)
1576: p->proto->show_proto_info(p);
1577: else
1578: proto_show_basic_info(p);
1579:
1580: cli_msg(-1006, "");
1581: }
1582: }
1583:
1584: void
1.1.1.2 ! misho 1585: proto_cmd_disable(struct proto *p, uintptr_t arg, int cnt UNUSED)
1.1 misho 1586: {
1587: if (p->disabled)
1588: {
1589: cli_msg(-8, "%s: already disabled", p->name);
1590: return;
1591: }
1592:
1593: log(L_INFO "Disabling protocol %s", p->name);
1594: p->disabled = 1;
1595: p->down_code = PDC_CMD_DISABLE;
1.1.1.2 ! misho 1596: proto_set_message(p, (char *) arg, -1);
1.1 misho 1597: proto_rethink_goal(p);
1598: cli_msg(-9, "%s: disabled", p->name);
1599: }
1600:
1601: void
1.1.1.2 ! misho 1602: proto_cmd_enable(struct proto *p, uintptr_t arg, int cnt UNUSED)
1.1 misho 1603: {
1604: if (!p->disabled)
1605: {
1606: cli_msg(-10, "%s: already enabled", p->name);
1607: return;
1608: }
1609:
1610: log(L_INFO "Enabling protocol %s", p->name);
1611: p->disabled = 0;
1.1.1.2 ! misho 1612: proto_set_message(p, (char *) arg, -1);
1.1 misho 1613: proto_rethink_goal(p);
1614: cli_msg(-11, "%s: enabled", p->name);
1615: }
1616:
1617: void
1.1.1.2 ! misho 1618: proto_cmd_restart(struct proto *p, uintptr_t arg, int cnt UNUSED)
1.1 misho 1619: {
1620: if (p->disabled)
1621: {
1622: cli_msg(-8, "%s: already disabled", p->name);
1623: return;
1624: }
1625:
1626: log(L_INFO "Restarting protocol %s", p->name);
1627: p->disabled = 1;
1628: p->down_code = PDC_CMD_RESTART;
1.1.1.2 ! misho 1629: proto_set_message(p, (char *) arg, -1);
1.1 misho 1630: proto_rethink_goal(p);
1631: p->disabled = 0;
1632: proto_rethink_goal(p);
1633: cli_msg(-12, "%s: restarted", p->name);
1634: }
1635:
1636: void
1.1.1.2 ! misho 1637: proto_cmd_reload(struct proto *p, uintptr_t dir, int cnt UNUSED)
1.1 misho 1638: {
1639: if (p->disabled)
1640: {
1641: cli_msg(-8, "%s: already disabled", p->name);
1642: return;
1643: }
1644:
1645: /* If the protocol in not UP, it has no routes */
1646: if (p->proto_state != PS_UP)
1647: return;
1648:
1649: log(L_INFO "Reloading protocol %s", p->name);
1650:
1651: /* re-importing routes */
1652: if (dir != CMD_RELOAD_OUT)
1653: {
1654: if (! (p->reload_routes && p->reload_routes(p)))
1655: {
1656: cli_msg(-8006, "%s: reload failed", p->name);
1657: return;
1658: }
1659:
1660: /*
1661: * Should be done before reload_routes() hook?
1662: * Perhaps, but these hooks work asynchronously.
1663: */
1664: if (!p->proto->multitable)
1665: {
1666: proto_reset_limit(p->main_ahook->rx_limit);
1667: proto_reset_limit(p->main_ahook->in_limit);
1668: }
1669: }
1670:
1671: /* re-exporting routes */
1672: if (dir != CMD_RELOAD_IN)
1673: proto_request_feeding(p);
1674:
1675: cli_msg(-15, "%s: reloading", p->name);
1676: }
1677:
1678: void
1.1.1.2 ! misho 1679: proto_cmd_debug(struct proto *p, uintptr_t mask, int cnt UNUSED)
1.1 misho 1680: {
1681: p->debug = mask;
1682: }
1683:
1684: void
1.1.1.2 ! misho 1685: proto_cmd_mrtdump(struct proto *p, uintptr_t mask, int cnt UNUSED)
1.1 misho 1686: {
1687: p->mrtdump = mask;
1688: }
1689:
1690: static void
1.1.1.2 ! misho 1691: proto_apply_cmd_symbol(struct symbol *s, void (* cmd)(struct proto *, uintptr_t, int), uintptr_t arg)
1.1 misho 1692: {
1693: if (s->class != SYM_PROTO)
1694: {
1695: cli_msg(9002, "%s is not a protocol", s->name);
1696: return;
1697: }
1698:
1699: cmd(((struct proto_config *)s->def)->proto, arg, 0);
1700: cli_msg(0, "");
1701: }
1702:
1703: static void
1.1.1.2 ! misho 1704: proto_apply_cmd_patt(char *patt, void (* cmd)(struct proto *, uintptr_t, int), uintptr_t arg)
1.1 misho 1705: {
1706: int cnt = 0;
1707:
1708: node *nn;
1709: WALK_LIST(nn, proto_list)
1710: {
1711: struct proto *p = SKIP_BACK(struct proto, glob_node, nn);
1712:
1713: if (!patt || patmatch(patt, p->name))
1714: cmd(p, arg, cnt++);
1715: }
1716:
1717: if (!cnt)
1718: cli_msg(8003, "No protocols match");
1719: else
1720: cli_msg(0, "");
1721: }
1722:
1723: void
1.1.1.2 ! misho 1724: proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, uintptr_t, int),
! 1725: int restricted, uintptr_t arg)
1.1 misho 1726: {
1727: if (restricted && cli_access_restricted())
1728: return;
1729:
1730: if (ps.patt)
1731: proto_apply_cmd_patt(ps.ptr, cmd, arg);
1732: else
1733: proto_apply_cmd_symbol(ps.ptr, cmd, arg);
1734: }
1735:
1736: struct proto *
1737: proto_get_named(struct symbol *sym, struct protocol *pr)
1738: {
1739: struct proto *p, *q;
1740:
1741: if (sym)
1742: {
1743: if (sym->class != SYM_PROTO)
1744: cf_error("%s: Not a protocol", sym->name);
1745: p = ((struct proto_config *)sym->def)->proto;
1746: if (!p || p->proto != pr)
1747: cf_error("%s: Not a %s protocol", sym->name, pr->name);
1748: }
1749: else
1750: {
1751: p = NULL;
1752: WALK_LIST(q, active_proto_list)
1753: if (q->proto == pr)
1754: {
1755: if (p)
1756: cf_error("There are multiple %s protocols running", pr->name);
1757: p = q;
1758: }
1759: if (!p)
1760: cf_error("There is no %s protocol running", pr->name);
1761: }
1762: return p;
1763: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>