Annotation of embedaddon/bird/nest/proto.c, revision 1.1.1.1
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;
389:
390: add_tail(&initial_proto_list, &q->n);
391:
392: if (p == &proto_unix_iface)
393: initial_device_proto = q;
394:
395: add_tail(&proto_list, &q->glob_node);
396: PD(q, "Initializing%s", q->disabled ? " [disabled]" : "");
397: return q;
398: }
399:
400: int proto_reconfig_type; /* Hack to propagate type info to pipe reconfigure hook */
401:
402: static int
403: proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config *nc, int type)
404: {
405: /* If the protocol is DOWN, we just restart it */
406: if (p->proto_state == PS_DOWN)
407: return 0;
408:
409: /* If there is a too big change in core attributes, ... */
410: if ((nc->protocol != oc->protocol) ||
411: (nc->disabled != p->disabled) ||
412: (nc->table->table != oc->table->table))
413: return 0;
414:
415: p->debug = nc->debug;
416: p->mrtdump = nc->mrtdump;
417: proto_reconfig_type = type;
418:
419: /* Execute protocol specific reconfigure hook */
420: if (! (p->proto->reconfigure && p->proto->reconfigure(p, nc)))
421: return 0;
422:
423: DBG("\t%s: same\n", oc->name);
424: PD(p, "Reconfigured");
425: p->cf = nc;
426: p->name = nc->name;
427: p->preference = nc->preference;
428:
429:
430: /* Multitable protocols handle rest in their reconfigure hooks */
431: if (p->proto->multitable)
432: return 1;
433:
434: /* Update filters and limits in the main announce hook
435: Note that this also resets limit state */
436: if (p->main_ahook)
437: {
438: struct announce_hook *ah = p->main_ahook;
439: ah->in_filter = nc->in_filter;
440: ah->out_filter = nc->out_filter;
441: ah->rx_limit = nc->rx_limit;
442: ah->in_limit = nc->in_limit;
443: ah->out_limit = nc->out_limit;
444: ah->in_keep_filtered = nc->in_keep_filtered;
445: proto_verify_limits(ah);
446: }
447:
448: /* Update routes when filters changed. If the protocol in not UP,
449: it has no routes and we can ignore such changes */
450: if ((p->proto_state != PS_UP) || (type == RECONFIG_SOFT))
451: return 1;
452:
453: int import_changed = ! filter_same(nc->in_filter, oc->in_filter);
454: int export_changed = ! filter_same(nc->out_filter, oc->out_filter);
455:
456: /* We treat a change in preferences by reimporting routes */
457: if (nc->preference != oc->preference)
458: import_changed = 1;
459:
460: if (import_changed || export_changed)
461: log(L_INFO "Reloading protocol %s", p->name);
462:
463: /* If import filter changed, call reload hook */
464: if (import_changed && ! (p->reload_routes && p->reload_routes(p)))
465: {
466: /* Now, the protocol is reconfigured. But route reload failed
467: and we have to do regular protocol restart. */
468: log(L_INFO "Restarting protocol %s", p->name);
469: p->disabled = 1;
470: p->down_code = PDC_CF_RESTART;
471: proto_rethink_goal(p);
472: p->disabled = 0;
473: proto_rethink_goal(p);
474: return 1;
475: }
476:
477: if (export_changed)
478: proto_request_feeding(p);
479:
480: return 1;
481: }
482:
483: /**
484: * protos_commit - commit new protocol configuration
485: * @new: new configuration
486: * @old: old configuration or %NULL if it's boot time config
487: * @force_reconfig: force restart of all protocols (used for example
488: * when the router ID changes)
489: * @type: type of reconfiguration (RECONFIG_SOFT or RECONFIG_HARD)
490: *
491: * Scan differences between @old and @new configuration and adjust all
492: * protocol instances to conform to the new configuration.
493: *
494: * When a protocol exists in the new configuration, but it doesn't in the
495: * original one, it's immediately started. When a collision with the other
496: * running protocol would arise, the new protocol will be temporarily stopped
497: * by the locking mechanism.
498: *
499: * When a protocol exists in the old configuration, but it doesn't in the
500: * new one, it's shut down and deleted after the shutdown completes.
501: *
502: * When a protocol exists in both configurations, the core decides
503: * whether it's possible to reconfigure it dynamically - it checks all
504: * the core properties of the protocol (changes in filters are ignored
505: * if type is RECONFIG_SOFT) and if they match, it asks the
506: * reconfigure() hook of the protocol to see if the protocol is able
507: * to switch to the new configuration. If it isn't possible, the
508: * protocol is shut down and a new instance is started with the new
509: * configuration after the shutdown is completed.
510: */
511: void
512: protos_commit(struct config *new, struct config *old, int force_reconfig, int type)
513: {
514: struct proto_config *oc, *nc;
515: struct proto *p, *n;
516: struct symbol *sym;
517:
518: DBG("protos_commit:\n");
519: if (old)
520: {
521: WALK_LIST(oc, old->protos)
522: {
523: p = oc->proto;
524: sym = cf_find_symbol(new, oc->name);
525: if (sym && sym->class == SYM_PROTO && !new->shutdown)
526: {
527: /* Found match, let's check if we can smoothly switch to new configuration */
528: /* No need to check description */
529: nc = sym->def;
530: nc->proto = p;
531:
532: /* We will try to reconfigure protocol p */
533: if (! force_reconfig && proto_reconfigure(p, oc, nc, type))
534: continue;
535:
536: /* Unsuccessful, we will restart it */
537: if (!p->disabled && !nc->disabled)
538: log(L_INFO "Restarting protocol %s", p->name);
539: else if (p->disabled && !nc->disabled)
540: log(L_INFO "Enabling protocol %s", p->name);
541: else if (!p->disabled && nc->disabled)
542: log(L_INFO "Disabling protocol %s", p->name);
543:
544: p->down_code = nc->disabled ? PDC_CF_DISABLE : PDC_CF_RESTART;
545: p->cf_new = nc;
546: }
547: else if (!new->shutdown)
548: {
549: log(L_INFO "Removing protocol %s", p->name);
550: p->down_code = PDC_CF_REMOVE;
551: p->cf_new = NULL;
552: }
553: else /* global shutdown */
554: {
555: p->down_code = PDC_CMD_SHUTDOWN;
556: p->cf_new = NULL;
557: }
558:
559: p->reconfiguring = 1;
560: config_add_obstacle(old);
561: proto_rethink_goal(p);
562: }
563: }
564:
565: WALK_LIST(nc, new->protos)
566: if (!nc->proto)
567: {
568: if (old) /* Not a first-time configuration */
569: log(L_INFO "Adding protocol %s", nc->name);
570: proto_init(nc);
571: }
572: DBG("\tdone\n");
573:
574: DBG("Protocol start\n");
575:
576: /* Start device protocol first */
577: if (initial_device_proto)
578: {
579: proto_rethink_goal(initial_device_proto);
580: initial_device_proto = NULL;
581: }
582:
583: /* Determine router ID for the first time - it has to be here and not in
584: global_commit() because it is postponed after start of device protocol */
585: if (!config->router_id)
586: {
587: config->router_id = if_choose_router_id(config->router_id_from, 0);
588: if (!config->router_id)
589: die("Cannot determine router ID, please configure it manually");
590: }
591:
592: /* Start all other protocols */
593: WALK_LIST_DELSAFE(p, n, initial_proto_list)
594: proto_rethink_goal(p);
595: }
596:
597: static void
598: proto_rethink_goal(struct proto *p)
599: {
600: struct protocol *q;
601: byte goal;
602:
603: if (p->reconfiguring && p->core_state == FS_HUNGRY && p->proto_state == PS_DOWN)
604: {
605: struct proto_config *nc = p->cf_new;
606: DBG("%s has shut down for reconfiguration\n", p->name);
607: p->cf->proto = NULL;
608: config_del_obstacle(p->cf->global);
609: rem_node(&p->n);
610: rem_node(&p->glob_node);
611: mb_free(p);
612: if (!nc)
613: return;
614: p = proto_init(nc);
615: }
616:
617: /* Determine what state we want to reach */
618: if (p->disabled || p->reconfiguring)
619: goal = PS_DOWN;
620: else
621: goal = PS_UP;
622:
623: q = p->proto;
624: if (goal == PS_UP) /* Going up */
625: {
626: if (p->proto_state == PS_DOWN && p->core_state == FS_HUNGRY)
627: {
628: DBG("Kicking %s up\n", p->name);
629: PD(p, "Starting");
630: proto_init_instance(p);
631: proto_notify_state(p, (q->start ? q->start(p) : PS_UP));
632: }
633: }
634: else /* Going down */
635: {
636: if (p->proto_state == PS_START || p->proto_state == PS_UP)
637: {
638: DBG("Kicking %s down\n", p->name);
639: PD(p, "Shutting down");
640: proto_notify_state(p, (q->shutdown ? q->shutdown(p) : PS_DOWN));
641: }
642: }
643: }
644:
645:
646: /**
647: * DOC: Graceful restart recovery
648: *
649: * Graceful restart of a router is a process when the routing plane (e.g. BIRD)
650: * restarts but both the forwarding plane (e.g kernel routing table) and routing
651: * neighbors keep proper routes, and therefore uninterrupted packet forwarding
652: * is maintained.
653: *
654: * BIRD implements graceful restart recovery by deferring export of routes to
655: * protocols until routing tables are refilled with the expected content. After
656: * start, protocols generate routes as usual, but routes are not propagated to
657: * them, until protocols report that they generated all routes. After that,
658: * graceful restart recovery is finished and the export (and the initial feed)
659: * to protocols is enabled.
660: *
661: * When graceful restart recovery need is detected during initialization, then
662: * enabled protocols are marked with @gr_recovery flag before start. Such
663: * protocols then decide how to proceed with graceful restart, participation is
664: * voluntary. Protocols could lock the recovery by proto_graceful_restart_lock()
665: * (stored in @gr_lock flag), which means that they want to postpone the end of
666: * the recovery until they converge and then unlock it. They also could set
667: * @gr_wait before advancing to %PS_UP, which means that the core should defer
668: * route export to that protocol until the end of the recovery. This should be
669: * done by protocols that expect their neigbors to keep the proper routes
670: * (kernel table, BGP sessions with BGP graceful restart capability).
671: *
672: * The graceful restart recovery is finished when either all graceful restart
673: * locks are unlocked or when graceful restart wait timer fires.
674: *
675: */
676:
677: static void graceful_restart_done(struct timer *t);
678:
679: /**
680: * graceful_restart_recovery - request initial graceful restart recovery
681: *
682: * Called by the platform initialization code if the need for recovery
683: * after graceful restart is detected during boot. Have to be called
684: * before protos_commit().
685: */
686: void
687: graceful_restart_recovery(void)
688: {
689: graceful_restart_state = GRS_INIT;
690: }
691:
692: /**
693: * graceful_restart_init - initialize graceful restart
694: *
695: * When graceful restart recovery was requested, the function starts an active
696: * phase of the recovery and initializes graceful restart wait timer. The
697: * function have to be called after protos_commit().
698: */
699: void
700: graceful_restart_init(void)
701: {
702: if (!graceful_restart_state)
703: return;
704:
705: log(L_INFO "Graceful restart started");
706:
707: if (!graceful_restart_locks)
708: {
709: graceful_restart_done(NULL);
710: return;
711: }
712:
713: graceful_restart_state = GRS_ACTIVE;
714: gr_wait_timer = tm_new(proto_pool);
715: gr_wait_timer->hook = graceful_restart_done;
716: tm_start(gr_wait_timer, config->gr_wait);
717: }
718:
719: /**
720: * graceful_restart_done - finalize graceful restart
721: * @t: unused
722: *
723: * When there are no locks on graceful restart, the functions finalizes the
724: * graceful restart recovery. Protocols postponing route export until the end of
725: * the recovery are awakened and the export to them is enabled. All other
726: * related state is cleared. The function is also called when the graceful
727: * restart wait timer fires (but there are still some locks).
728: */
729: static void
730: graceful_restart_done(struct timer *t UNUSED)
731: {
732: struct proto *p;
733: node *n;
734:
735: log(L_INFO "Graceful restart done");
736: graceful_restart_state = GRS_DONE;
737:
738: WALK_LIST2(p, n, proto_list, glob_node)
739: {
740: if (!p->gr_recovery)
741: continue;
742:
743: /* Resume postponed export of routes */
744: if ((p->proto_state == PS_UP) && p->gr_wait)
745: {
746: proto_want_export_up(p);
747: proto_log_state_change(p);
748: }
749:
750: /* Cleanup */
751: p->gr_recovery = 0;
752: p->gr_wait = 0;
753: p->gr_lock = 0;
754: }
755:
756: graceful_restart_locks = 0;
757: }
758:
759: void
760: graceful_restart_show_status(void)
761: {
762: if (graceful_restart_state != GRS_ACTIVE)
763: return;
764:
765: cli_msg(-24, "Graceful restart recovery in progress");
766: cli_msg(-24, " Waiting for %d protocols to recover", graceful_restart_locks);
767: cli_msg(-24, " Wait timer is %d/%d", tm_remains(gr_wait_timer), config->gr_wait);
768: }
769:
770: /**
771: * proto_graceful_restart_lock - lock graceful restart by protocol
772: * @p: protocol instance
773: *
774: * This function allows a protocol to postpone the end of graceful restart
775: * recovery until it converges. The lock is removed when the protocol calls
776: * proto_graceful_restart_unlock() or when the protocol is stopped.
777: *
778: * The function have to be called during the initial phase of graceful restart
779: * recovery and only for protocols that are part of graceful restart (i.e. their
780: * @gr_recovery is set), which means it should be called from protocol start
781: * hooks.
782: */
783: void
784: proto_graceful_restart_lock(struct proto *p)
785: {
786: ASSERT(graceful_restart_state == GRS_INIT);
787: ASSERT(p->gr_recovery);
788:
789: if (p->gr_lock)
790: return;
791:
792: p->gr_lock = 1;
793: graceful_restart_locks++;
794: }
795:
796: /**
797: * proto_graceful_restart_unlock - unlock graceful restart by protocol
798: * @p: protocol instance
799: *
800: * This function unlocks a lock from proto_graceful_restart_lock(). It is also
801: * automatically called when the lock holding protocol went down.
802: */
803: void
804: proto_graceful_restart_unlock(struct proto *p)
805: {
806: if (!p->gr_lock)
807: return;
808:
809: p->gr_lock = 0;
810: graceful_restart_locks--;
811:
812: if ((graceful_restart_state == GRS_ACTIVE) && !graceful_restart_locks)
813: tm_start(gr_wait_timer, 0);
814: }
815:
816:
817:
818: /**
819: * protos_dump_all - dump status of all protocols
820: *
821: * This function dumps status of all existing protocol instances to the
822: * debug output. It involves printing of general status information
823: * such as protocol states, its position on the protocol lists
824: * and also calling of a dump() hook of the protocol to print
825: * the internals.
826: */
827: void
828: protos_dump_all(void)
829: {
830: struct proto *p;
831: struct announce_hook *a;
832:
833: debug("Protocols:\n");
834:
835: WALK_LIST(p, active_proto_list)
836: {
837: debug(" protocol %s state %s/%s\n", p->name,
838: p_states[p->proto_state], c_states[p->core_state]);
839: for (a = p->ahooks; a; a = a->next)
840: {
841: debug("\tTABLE %s\n", a->table->name);
842: if (a->in_filter)
843: debug("\tInput filter: %s\n", filter_name(a->in_filter));
844: if (a->out_filter != FILTER_REJECT)
845: debug("\tOutput filter: %s\n", filter_name(a->out_filter));
846: }
847: if (p->disabled)
848: debug("\tDISABLED\n");
849: else if (p->proto->dump)
850: p->proto->dump(p);
851: }
852: WALK_LIST(p, inactive_proto_list)
853: debug(" inactive %s: state %s/%s\n", p->name, p_states[p->proto_state], c_states[p->core_state]);
854: WALK_LIST(p, initial_proto_list)
855: debug(" initial %s\n", p->name);
856: WALK_LIST(p, flush_proto_list)
857: debug(" flushing %s\n", p->name);
858: }
859:
860: /**
861: * proto_build - make a single protocol available
862: * @p: the protocol
863: *
864: * After the platform specific initialization code uses protos_build()
865: * to add all the standard protocols, it should call proto_build() for
866: * all platform specific protocols to inform the core that they exist.
867: */
868: void
869: proto_build(struct protocol *p)
870: {
871: add_tail(&protocol_list, &p->n);
872: if (p->attr_class)
873: {
874: ASSERT(!attr_class_to_protocol[p->attr_class]);
875: attr_class_to_protocol[p->attr_class] = p;
876: }
877: }
878:
879: /* FIXME: convert this call to some protocol hook */
880: extern void bfd_init_all(void);
881:
882: /**
883: * protos_build - build a protocol list
884: *
885: * This function is called during BIRD startup to insert
886: * all standard protocols to the global protocol list. Insertion
887: * of platform specific protocols (such as the kernel syncer)
888: * is in the domain of competence of the platform dependent
889: * startup code.
890: */
891: void
892: protos_build(void)
893: {
894: init_list(&protocol_list);
895: init_list(&proto_list);
896: init_list(&active_proto_list);
897: init_list(&inactive_proto_list);
898: init_list(&initial_proto_list);
899: init_list(&flush_proto_list);
900: proto_build(&proto_device);
901: #ifdef CONFIG_RADV
902: proto_build(&proto_radv);
903: #endif
904: #ifdef CONFIG_RIP
905: proto_build(&proto_rip);
906: #endif
907: #ifdef CONFIG_STATIC
908: proto_build(&proto_static);
909: #endif
910: #ifdef CONFIG_OSPF
911: proto_build(&proto_ospf);
912: #endif
913: #ifdef CONFIG_PIPE
914: proto_build(&proto_pipe);
915: #endif
916: #ifdef CONFIG_BGP
917: proto_build(&proto_bgp);
918: #endif
919: #ifdef CONFIG_BFD
920: proto_build(&proto_bfd);
921: bfd_init_all();
922: #endif
923: #ifdef CONFIG_BABEL
924: proto_build(&proto_babel);
925: #endif
926:
927: proto_pool = rp_new(&root_pool, "Protocols");
928: proto_flush_event = ev_new(proto_pool);
929: proto_flush_event->hook = proto_flush_loop;
930: proto_shutdown_timer = tm_new(proto_pool);
931: proto_shutdown_timer->hook = proto_shutdown_loop;
932: }
933:
934: static void
935: proto_feed_more(void *P)
936: {
937: struct proto *p = P;
938:
939: if (p->export_state != ES_FEEDING)
940: return;
941:
942: DBG("Feeding protocol %s continued\n", p->name);
943: if (rt_feed_baby(p))
944: {
945: DBG("Feeding protocol %s finished\n", p->name);
946: p->export_state = ES_READY;
947: proto_log_state_change(p);
948:
949: if (p->feed_end)
950: p->feed_end(p);
951: }
952: else
953: {
954: p->attn->hook = proto_feed_more;
955: ev_schedule(p->attn); /* Will continue later... */
956: }
957: }
958:
959: static void
960: proto_feed_initial(void *P)
961: {
962: struct proto *p = P;
963:
964: if (p->export_state != ES_FEEDING)
965: return;
966:
967: DBG("Feeding protocol %s\n", p->name);
968:
969: if_feed_baby(p);
970: proto_feed_more(P);
971: }
972:
973: static void
974: proto_schedule_feed(struct proto *p, int initial)
975: {
976: DBG("%s: Scheduling meal\n", p->name);
977:
978: p->export_state = ES_FEEDING;
979: p->refeeding = !initial;
980:
981: p->attn->hook = initial ? proto_feed_initial : proto_feed_more;
982: ev_schedule(p->attn);
983:
984: if (p->feed_begin)
985: p->feed_begin(p, initial);
986: }
987:
988: /*
989: * Flushing loop is responsible for flushing routes and protocols
990: * after they went down. It runs in proto_flush_event. At the start of
991: * one round, protocols waiting to flush are marked in
992: * proto_schedule_flush_loop(). At the end of the round (when routing
993: * table flush is complete), marked protocols are flushed and a next
994: * round may start.
995: */
996:
997: static int flush_loop_state; /* 1 -> running */
998:
999: static void
1000: proto_schedule_flush_loop(void)
1001: {
1002: struct proto *p;
1003: struct announce_hook *h;
1004:
1005: if (flush_loop_state)
1006: return;
1007: flush_loop_state = 1;
1008:
1009: WALK_LIST(p, flush_proto_list)
1010: {
1011: p->flushing = 1;
1012: for (h=p->ahooks; h; h=h->next)
1013: rt_mark_for_prune(h->table);
1014: }
1015:
1016: ev_schedule(proto_flush_event);
1017: }
1018:
1019: static void
1020: proto_flush_loop(void *unused UNUSED)
1021: {
1022: struct proto *p;
1023:
1024: if (! rt_prune_loop())
1025: {
1026: /* Rtable pruning is not finished */
1027: ev_schedule(proto_flush_event);
1028: return;
1029: }
1030:
1031: rt_prune_sources();
1032:
1033: again:
1034: WALK_LIST(p, flush_proto_list)
1035: if (p->flushing)
1036: {
1037: /* This will flush interfaces in the same manner
1038: like rt_prune_all() flushes routes */
1039: if (p->proto == &proto_unix_iface)
1040: if_flush_ifaces(p);
1041:
1042: DBG("Flushing protocol %s\n", p->name);
1043: p->flushing = 0;
1044: p->core_state = FS_HUNGRY;
1045: proto_relink(p);
1046: proto_log_state_change(p);
1047: if (p->proto_state == PS_DOWN)
1048: proto_fell_down(p);
1049: goto again;
1050: }
1051:
1052: /* This round finished, perhaps there will be another one */
1053: flush_loop_state = 0;
1054: if (!EMPTY_LIST(flush_proto_list))
1055: proto_schedule_flush_loop();
1056: }
1057:
1058:
1059: /* Temporary hack to propagate restart to BGP */
1060: int proto_restart;
1061:
1062: static void
1063: proto_shutdown_loop(struct timer *t UNUSED)
1064: {
1065: struct proto *p, *p_next;
1066:
1067: WALK_LIST_DELSAFE(p, p_next, active_proto_list)
1068: if (p->down_sched)
1069: {
1070: proto_restart = (p->down_sched == PDS_RESTART);
1071:
1072: p->disabled = 1;
1073: proto_rethink_goal(p);
1074: if (proto_restart)
1075: {
1076: p->disabled = 0;
1077: proto_rethink_goal(p);
1078: }
1079: }
1080: }
1081:
1082: static inline void
1083: proto_schedule_down(struct proto *p, byte restart, byte code)
1084: {
1085: /* Does not work for other states (even PS_START) */
1086: ASSERT(p->proto_state == PS_UP);
1087:
1088: /* Scheduled restart may change to shutdown, but not otherwise */
1089: if (p->down_sched == PDS_DISABLE)
1090: return;
1091:
1092: p->down_sched = restart ? PDS_RESTART : PDS_DISABLE;
1093: p->down_code = code;
1094: tm_start_max(proto_shutdown_timer, restart ? 2 : 0);
1095: }
1096:
1097:
1098: /**
1099: * proto_request_feeding - request feeding routes to the protocol
1100: * @p: given protocol
1101: *
1102: * Sometimes it is needed to send again all routes to the
1103: * protocol. This is called feeding and can be requested by this
1104: * function. This would cause protocol export state transition
1105: * to ES_FEEDING (during feeding) and when completed, it will
1106: * switch back to ES_READY. This function can be called even
1107: * when feeding is already running, in that case it is restarted.
1108: */
1109: void
1110: proto_request_feeding(struct proto *p)
1111: {
1112: ASSERT(p->proto_state == PS_UP);
1113:
1114: /* Do nothing if we are still waiting for feeding */
1115: if (p->export_state == ES_DOWN)
1116: return;
1117:
1118: /* If we are already feeding, we want to restart it */
1119: if (p->export_state == ES_FEEDING)
1120: {
1121: /* Unless feeding is in initial state */
1122: if (p->attn->hook == proto_feed_initial)
1123: return;
1124:
1125: rt_feed_baby_abort(p);
1126: }
1127:
1128: /* FIXME: This should be changed for better support of multitable protos */
1129: struct announce_hook *ah;
1130: for (ah = p->ahooks; ah; ah = ah->next)
1131: proto_reset_limit(ah->out_limit);
1132:
1133: /* Hack: reset exp_routes during refeed, and do not decrease it later */
1134: p->stats.exp_routes = 0;
1135:
1136: proto_schedule_feed(p, 0);
1137: proto_log_state_change(p);
1138: }
1139:
1140: static const char *
1141: proto_limit_name(struct proto_limit *l)
1142: {
1143: const char *actions[] = {
1144: [PLA_WARN] = "warn",
1145: [PLA_BLOCK] = "block",
1146: [PLA_RESTART] = "restart",
1147: [PLA_DISABLE] = "disable",
1148: };
1149:
1150: return actions[l->action];
1151: }
1152:
1153: /**
1154: * proto_notify_limit: notify about limit hit and take appropriate action
1155: * @ah: announce hook
1156: * @l: limit being hit
1157: * @dir: limit direction (PLD_*)
1158: * @rt_count: the number of routes
1159: *
1160: * The function is called by the route processing core when limit @l
1161: * is breached. It activates the limit and tooks appropriate action
1162: * according to @l->action.
1163: */
1164: void
1165: proto_notify_limit(struct announce_hook *ah, struct proto_limit *l, int dir, u32 rt_count)
1166: {
1167: const char *dir_name[PLD_MAX] = { "receive", "import" , "export" };
1168: const byte dir_down[PLD_MAX] = { PDC_RX_LIMIT_HIT, PDC_IN_LIMIT_HIT, PDC_OUT_LIMIT_HIT };
1169: struct proto *p = ah->proto;
1170:
1171: if (l->state == PLS_BLOCKED)
1172: return;
1173:
1174: /* For warning action, we want the log message every time we hit the limit */
1175: if (!l->state || ((l->action == PLA_WARN) && (rt_count == l->limit)))
1176: log(L_WARN "Protocol %s hits route %s limit (%d), action: %s",
1177: p->name, dir_name[dir], l->limit, proto_limit_name(l));
1178:
1179: switch (l->action)
1180: {
1181: case PLA_WARN:
1182: l->state = PLS_ACTIVE;
1183: break;
1184:
1185: case PLA_BLOCK:
1186: l->state = PLS_BLOCKED;
1187: break;
1188:
1189: case PLA_RESTART:
1190: case PLA_DISABLE:
1191: l->state = PLS_BLOCKED;
1192: if (p->proto_state == PS_UP)
1193: proto_schedule_down(p, l->action == PLA_RESTART, dir_down[dir]);
1194: break;
1195: }
1196: }
1197:
1198: void
1199: proto_verify_limits(struct announce_hook *ah)
1200: {
1201: struct proto_limit *l;
1202: struct proto_stats *stats = ah->stats;
1203: u32 all_routes = stats->imp_routes + stats->filt_routes;
1204:
1205: l = ah->rx_limit;
1206: if (l && (all_routes > l->limit))
1207: proto_notify_limit(ah, l, PLD_RX, all_routes);
1208:
1209: l = ah->in_limit;
1210: if (l && (stats->imp_routes > l->limit))
1211: proto_notify_limit(ah, l, PLD_IN, stats->imp_routes);
1212:
1213: l = ah->out_limit;
1214: if (l && (stats->exp_routes > l->limit))
1215: proto_notify_limit(ah, l, PLD_OUT, stats->exp_routes);
1216: }
1217:
1218:
1219: static void
1220: proto_want_core_up(struct proto *p)
1221: {
1222: ASSERT(p->core_state == FS_HUNGRY);
1223:
1224: if (!p->proto->multitable)
1225: {
1226: p->main_source = rt_get_source(p, 0);
1227: rt_lock_source(p->main_source);
1228:
1229: /* Connect protocol to routing table */
1230: p->main_ahook = proto_add_announce_hook(p, p->table, &p->stats);
1231: p->main_ahook->in_filter = p->cf->in_filter;
1232: p->main_ahook->out_filter = p->cf->out_filter;
1233: p->main_ahook->rx_limit = p->cf->rx_limit;
1234: p->main_ahook->in_limit = p->cf->in_limit;
1235: p->main_ahook->out_limit = p->cf->out_limit;
1236: p->main_ahook->in_keep_filtered = p->cf->in_keep_filtered;
1237:
1238: proto_reset_limit(p->main_ahook->rx_limit);
1239: proto_reset_limit(p->main_ahook->in_limit);
1240: proto_reset_limit(p->main_ahook->out_limit);
1241: }
1242:
1243: p->core_state = FS_HAPPY;
1244: proto_relink(p);
1245: }
1246:
1247: static void
1248: proto_want_export_up(struct proto *p)
1249: {
1250: ASSERT(p->core_state == FS_HAPPY);
1251: ASSERT(p->export_state == ES_DOWN);
1252:
1253: proto_link_ahooks(p);
1254: proto_schedule_feed(p, 1); /* Sets ES_FEEDING */
1255: }
1256:
1257: static void
1258: proto_want_export_down(struct proto *p)
1259: {
1260: ASSERT(p->export_state != ES_DOWN);
1261:
1262: /* Need to abort feeding */
1263: if (p->export_state == ES_FEEDING)
1264: rt_feed_baby_abort(p);
1265:
1266: p->export_state = ES_DOWN;
1267: p->stats.exp_routes = 0;
1268: proto_unlink_ahooks(p);
1269: }
1270:
1271: static void
1272: proto_want_core_down(struct proto *p)
1273: {
1274: ASSERT(p->core_state == FS_HAPPY);
1275: ASSERT(p->export_state == ES_DOWN);
1276:
1277: p->core_state = FS_FLUSHING;
1278: proto_relink(p);
1279: proto_schedule_flush_loop();
1280:
1281: if (!p->proto->multitable)
1282: {
1283: rt_unlock_source(p->main_source);
1284: p->main_source = NULL;
1285: }
1286: }
1287:
1288: static void
1289: proto_falling_down(struct proto *p)
1290: {
1291: p->gr_recovery = 0;
1292: p->gr_wait = 0;
1293: if (p->gr_lock)
1294: proto_graceful_restart_unlock(p);
1295: }
1296:
1297: static void
1298: proto_fell_down(struct proto *p)
1299: {
1300: DBG("Protocol %s down\n", p->name);
1301:
1302: u32 all_routes = p->stats.imp_routes + p->stats.filt_routes;
1303: if (all_routes != 0)
1304: log(L_ERR "Protocol %s is down but still has %d routes", p->name, all_routes);
1305:
1306: bzero(&p->stats, sizeof(struct proto_stats));
1307: proto_free_ahooks(p);
1308:
1309: if (! p->proto->multitable)
1310: rt_unlock_table(p->table);
1311:
1312: if (p->proto->cleanup)
1313: p->proto->cleanup(p);
1314:
1315: proto_rethink_goal(p);
1316: }
1317:
1318:
1319: /**
1320: * proto_notify_state - notify core about protocol state change
1321: * @p: protocol the state of which has changed
1322: * @ps: the new status
1323: *
1324: * Whenever a state of a protocol changes due to some event internal
1325: * to the protocol (i.e., not inside a start() or shutdown() hook),
1326: * it should immediately notify the core about the change by calling
1327: * proto_notify_state() which will write the new state to the &proto
1328: * structure and take all the actions necessary to adapt to the new
1329: * state. State change to PS_DOWN immediately frees resources of protocol
1330: * and might execute start callback of protocol; therefore,
1331: * it should be used at tail positions of protocol callbacks.
1332: */
1333: void
1334: proto_notify_state(struct proto *p, unsigned ps)
1335: {
1336: unsigned ops = p->proto_state;
1337: unsigned cs = p->core_state;
1338: unsigned es = p->export_state;
1339:
1340: DBG("%s reporting state transition %s/%s -> */%s\n", p->name, c_states[cs], p_states[ops], p_states[ps]);
1341: if (ops == ps)
1342: return;
1343:
1344: p->proto_state = ps;
1345: p->last_state_change = now;
1346:
1347: switch (ps)
1348: {
1349: case PS_START:
1350: ASSERT(ops == PS_DOWN || ops == PS_UP);
1351: ASSERT(cs == FS_HUNGRY || cs == FS_HAPPY);
1352:
1353: if (es != ES_DOWN)
1354: proto_want_export_down(p);
1355: break;
1356:
1357: case PS_UP:
1358: ASSERT(ops == PS_DOWN || ops == PS_START);
1359: ASSERT(cs == FS_HUNGRY || cs == FS_HAPPY);
1360: ASSERT(es == ES_DOWN);
1361:
1362: if (cs == FS_HUNGRY)
1363: proto_want_core_up(p);
1364: if (!p->gr_wait)
1365: proto_want_export_up(p);
1366: break;
1367:
1368: case PS_STOP:
1369: ASSERT(ops == PS_START || ops == PS_UP);
1370:
1371: p->down_sched = 0;
1372:
1373: if (es != ES_DOWN)
1374: proto_want_export_down(p);
1375: if (cs == FS_HAPPY)
1376: proto_want_core_down(p);
1377: proto_falling_down(p);
1378: break;
1379:
1380: case PS_DOWN:
1381: p->down_code = 0;
1382: p->down_sched = 0;
1383:
1384: if (es != ES_DOWN)
1385: proto_want_export_down(p);
1386: if (cs == FS_HAPPY)
1387: proto_want_core_down(p);
1388: if (ops != PS_STOP)
1389: proto_falling_down(p);
1390:
1391: neigh_prune(); // FIXME convert neighbors to resource?
1392: rfree(p->pool);
1393: p->pool = NULL;
1394:
1395: if (cs == FS_HUNGRY) /* Shutdown finished */
1396: {
1397: proto_log_state_change(p);
1398: proto_fell_down(p);
1399: return; /* The protocol might have ceased to exist */
1400: }
1401: break;
1402:
1403: default:
1404: bug("%s: Invalid state %d", p->name, ps);
1405: }
1406:
1407: proto_log_state_change(p);
1408: }
1409:
1410: /*
1411: * CLI Commands
1412: */
1413:
1414: static char *
1415: proto_state_name(struct proto *p)
1416: {
1417: #define P(x,y) ((x << 4) | y)
1418: switch (P(p->proto_state, p->core_state))
1419: {
1420: case P(PS_DOWN, FS_HUNGRY): return "down";
1421: case P(PS_START, FS_HUNGRY):
1422: case P(PS_START, FS_HAPPY): return "start";
1423: case P(PS_UP, FS_HAPPY):
1424: switch (p->export_state)
1425: {
1426: case ES_DOWN: return "wait";
1427: case ES_FEEDING: return "feed";
1428: case ES_READY: return "up";
1429: default: return "???";
1430: }
1431: case P(PS_STOP, FS_HUNGRY):
1432: case P(PS_STOP, FS_FLUSHING): return "stop";
1433: case P(PS_DOWN, FS_FLUSHING): return "flush";
1434: default: return "???";
1435: }
1436: #undef P
1437: }
1438:
1439: static void
1440: proto_show_stats(struct proto_stats *s, int in_keep_filtered)
1441: {
1442: if (in_keep_filtered)
1443: cli_msg(-1006, " Routes: %u imported, %u filtered, %u exported, %u preferred",
1444: s->imp_routes, s->filt_routes, s->exp_routes, s->pref_routes);
1445: else
1446: cli_msg(-1006, " Routes: %u imported, %u exported, %u preferred",
1447: s->imp_routes, s->exp_routes, s->pref_routes);
1448:
1449: cli_msg(-1006, " Route change stats: received rejected filtered ignored accepted");
1450: cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u",
1451: s->imp_updates_received, s->imp_updates_invalid,
1452: s->imp_updates_filtered, s->imp_updates_ignored,
1453: s->imp_updates_accepted);
1454: cli_msg(-1006, " Import withdraws: %10u %10u --- %10u %10u",
1455: s->imp_withdraws_received, s->imp_withdraws_invalid,
1456: s->imp_withdraws_ignored, s->imp_withdraws_accepted);
1457: cli_msg(-1006, " Export updates: %10u %10u %10u --- %10u",
1458: s->exp_updates_received, s->exp_updates_rejected,
1459: s->exp_updates_filtered, s->exp_updates_accepted);
1460: cli_msg(-1006, " Export withdraws: %10u --- --- --- %10u",
1461: s->exp_withdraws_received, s->exp_withdraws_accepted);
1462: }
1463:
1464: void
1465: proto_show_limit(struct proto_limit *l, const char *dsc)
1466: {
1467: if (!l)
1468: return;
1469:
1470: cli_msg(-1006, " %-16s%d%s", dsc, l->limit, l->state ? " [HIT]" : "");
1471: cli_msg(-1006, " Action: %s", proto_limit_name(l));
1472: }
1473:
1474: void
1475: proto_show_basic_info(struct proto *p)
1476: {
1477: // cli_msg(-1006, " Table: %s", p->table->name);
1478: cli_msg(-1006, " Preference: %d", p->preference);
1479: cli_msg(-1006, " Input filter: %s", filter_name(p->cf->in_filter));
1480: cli_msg(-1006, " Output filter: %s", filter_name(p->cf->out_filter));
1481:
1482: if (graceful_restart_state == GRS_ACTIVE)
1483: cli_msg(-1006, " GR recovery: %s%s",
1484: p->gr_lock ? " pending" : "",
1485: p->gr_wait ? " waiting" : "");
1486:
1487: proto_show_limit(p->cf->rx_limit, "Receive limit:");
1488: proto_show_limit(p->cf->in_limit, "Import limit:");
1489: proto_show_limit(p->cf->out_limit, "Export limit:");
1490:
1491: if (p->proto_state != PS_DOWN)
1492: proto_show_stats(&p->stats, p->cf->in_keep_filtered);
1493: }
1494:
1495: void
1496: proto_cmd_show(struct proto *p, uint verbose, int cnt)
1497: {
1498: byte buf[256], tbuf[TM_DATETIME_BUFFER_SIZE];
1499:
1500: /* First protocol - show header */
1501: if (!cnt)
1502: cli_msg(-2002, "name proto table state since info");
1503:
1504: buf[0] = 0;
1505: if (p->proto->get_status)
1506: p->proto->get_status(p, buf);
1507: tm_format_datetime(tbuf, &config->tf_proto, p->last_state_change);
1508: cli_msg(-1002, "%-8s %-8s %-8s %-5s %-10s %s",
1509: p->name,
1510: p->proto->name,
1511: p->table->name,
1512: proto_state_name(p),
1513: tbuf,
1514: buf);
1515: if (verbose)
1516: {
1517: if (p->cf->dsc)
1518: cli_msg(-1006, " Description: %s", p->cf->dsc);
1519: if (p->cf->router_id)
1520: cli_msg(-1006, " Router ID: %R", p->cf->router_id);
1521:
1522: if (p->proto->show_proto_info)
1523: p->proto->show_proto_info(p);
1524: else
1525: proto_show_basic_info(p);
1526:
1527: cli_msg(-1006, "");
1528: }
1529: }
1530:
1531: void
1532: proto_cmd_disable(struct proto *p, uint arg UNUSED, int cnt UNUSED)
1533: {
1534: if (p->disabled)
1535: {
1536: cli_msg(-8, "%s: already disabled", p->name);
1537: return;
1538: }
1539:
1540: log(L_INFO "Disabling protocol %s", p->name);
1541: p->disabled = 1;
1542: p->down_code = PDC_CMD_DISABLE;
1543: proto_rethink_goal(p);
1544: cli_msg(-9, "%s: disabled", p->name);
1545: }
1546:
1547: void
1548: proto_cmd_enable(struct proto *p, uint arg UNUSED, int cnt UNUSED)
1549: {
1550: if (!p->disabled)
1551: {
1552: cli_msg(-10, "%s: already enabled", p->name);
1553: return;
1554: }
1555:
1556: log(L_INFO "Enabling protocol %s", p->name);
1557: p->disabled = 0;
1558: proto_rethink_goal(p);
1559: cli_msg(-11, "%s: enabled", p->name);
1560: }
1561:
1562: void
1563: proto_cmd_restart(struct proto *p, uint arg UNUSED, int cnt UNUSED)
1564: {
1565: if (p->disabled)
1566: {
1567: cli_msg(-8, "%s: already disabled", p->name);
1568: return;
1569: }
1570:
1571: log(L_INFO "Restarting protocol %s", p->name);
1572: p->disabled = 1;
1573: p->down_code = PDC_CMD_RESTART;
1574: proto_rethink_goal(p);
1575: p->disabled = 0;
1576: proto_rethink_goal(p);
1577: cli_msg(-12, "%s: restarted", p->name);
1578: }
1579:
1580: void
1581: proto_cmd_reload(struct proto *p, uint dir, int cnt UNUSED)
1582: {
1583: if (p->disabled)
1584: {
1585: cli_msg(-8, "%s: already disabled", p->name);
1586: return;
1587: }
1588:
1589: /* If the protocol in not UP, it has no routes */
1590: if (p->proto_state != PS_UP)
1591: return;
1592:
1593: log(L_INFO "Reloading protocol %s", p->name);
1594:
1595: /* re-importing routes */
1596: if (dir != CMD_RELOAD_OUT)
1597: {
1598: if (! (p->reload_routes && p->reload_routes(p)))
1599: {
1600: cli_msg(-8006, "%s: reload failed", p->name);
1601: return;
1602: }
1603:
1604: /*
1605: * Should be done before reload_routes() hook?
1606: * Perhaps, but these hooks work asynchronously.
1607: */
1608: if (!p->proto->multitable)
1609: {
1610: proto_reset_limit(p->main_ahook->rx_limit);
1611: proto_reset_limit(p->main_ahook->in_limit);
1612: }
1613: }
1614:
1615: /* re-exporting routes */
1616: if (dir != CMD_RELOAD_IN)
1617: proto_request_feeding(p);
1618:
1619: cli_msg(-15, "%s: reloading", p->name);
1620: }
1621:
1622: void
1623: proto_cmd_debug(struct proto *p, uint mask, int cnt UNUSED)
1624: {
1625: p->debug = mask;
1626: }
1627:
1628: void
1629: proto_cmd_mrtdump(struct proto *p, uint mask, int cnt UNUSED)
1630: {
1631: p->mrtdump = mask;
1632: }
1633:
1634: static void
1635: proto_apply_cmd_symbol(struct symbol *s, void (* cmd)(struct proto *, uint, int), uint arg)
1636: {
1637: if (s->class != SYM_PROTO)
1638: {
1639: cli_msg(9002, "%s is not a protocol", s->name);
1640: return;
1641: }
1642:
1643: cmd(((struct proto_config *)s->def)->proto, arg, 0);
1644: cli_msg(0, "");
1645: }
1646:
1647: static void
1648: proto_apply_cmd_patt(char *patt, void (* cmd)(struct proto *, uint, int), uint arg)
1649: {
1650: int cnt = 0;
1651:
1652: node *nn;
1653: WALK_LIST(nn, proto_list)
1654: {
1655: struct proto *p = SKIP_BACK(struct proto, glob_node, nn);
1656:
1657: if (!patt || patmatch(patt, p->name))
1658: cmd(p, arg, cnt++);
1659: }
1660:
1661: if (!cnt)
1662: cli_msg(8003, "No protocols match");
1663: else
1664: cli_msg(0, "");
1665: }
1666:
1667: void
1668: proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, uint, int),
1669: int restricted, uint arg)
1670: {
1671: if (restricted && cli_access_restricted())
1672: return;
1673:
1674: if (ps.patt)
1675: proto_apply_cmd_patt(ps.ptr, cmd, arg);
1676: else
1677: proto_apply_cmd_symbol(ps.ptr, cmd, arg);
1678: }
1679:
1680: struct proto *
1681: proto_get_named(struct symbol *sym, struct protocol *pr)
1682: {
1683: struct proto *p, *q;
1684:
1685: if (sym)
1686: {
1687: if (sym->class != SYM_PROTO)
1688: cf_error("%s: Not a protocol", sym->name);
1689: p = ((struct proto_config *)sym->def)->proto;
1690: if (!p || p->proto != pr)
1691: cf_error("%s: Not a %s protocol", sym->name, pr->name);
1692: }
1693: else
1694: {
1695: p = NULL;
1696: WALK_LIST(q, active_proto_list)
1697: if (q->proto == pr)
1698: {
1699: if (p)
1700: cf_error("There are multiple %s protocols running", pr->name);
1701: p = q;
1702: }
1703: if (!p)
1704: cf_error("There is no %s protocol running", pr->name);
1705: }
1706: return p;
1707: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>