| 
									
										
										
										
											1998-05-20 11:54:33 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  *	BIRD -- Protocols | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2000-01-16 16:44:50 +00:00
										 |  |  |  *	(c) 1998--2000 Martin Mares <mj@ucw.cz> | 
					
						
							| 
									
										
										
										
											1998-05-20 11:54:33 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  *	Can be freely distributed and used under the terms of the GNU GPL. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-12 21:01:38 +00:00
										 |  |  | #undef LOCAL_DEBUG
 | 
					
						
							| 
									
										
										
										
											1998-06-03 08:38:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-05-20 11:54:33 +00:00
										 |  |  | #include "nest/bird.h"
 | 
					
						
							|  |  |  | #include "nest/protocol.h"
 | 
					
						
							|  |  |  | #include "lib/resource.h"
 | 
					
						
							|  |  |  | #include "lib/lists.h"
 | 
					
						
							| 
									
										
										
										
											1999-02-11 22:59:06 +00:00
										 |  |  | #include "lib/event.h"
 | 
					
						
							| 
									
										
										
										
											2000-01-16 23:30:06 +00:00
										 |  |  | #include "lib/string.h"
 | 
					
						
							| 
									
										
										
										
											1998-11-27 19:35:10 +00:00
										 |  |  | #include "conf/conf.h"
 | 
					
						
							| 
									
										
										
										
											1998-10-17 11:05:18 +00:00
										 |  |  | #include "nest/route.h"
 | 
					
						
							|  |  |  | #include "nest/iface.h"
 | 
					
						
							| 
									
										
										
										
											1999-11-25 15:35:30 +00:00
										 |  |  | #include "nest/cli.h"
 | 
					
						
							| 
									
										
										
										
											1999-03-17 14:31:26 +00:00
										 |  |  | #include "filter/filter.h"
 | 
					
						
							| 
									
										
										
										
											1998-05-20 11:54:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-02-11 22:59:06 +00:00
										 |  |  | static pool *proto_pool; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-04-01 10:19:47 +00:00
										 |  |  | static list protocol_list; | 
					
						
							| 
									
										
										
										
											2000-01-16 23:30:06 +00:00
										 |  |  | static list proto_list; | 
					
						
							| 
									
										
										
										
											1999-02-11 22:59:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-01-16 23:30:06 +00:00
										 |  |  | #define WALK_PROTO_LIST(p) do {							\
 | 
					
						
							|  |  |  | 	node *nn;								\ | 
					
						
							|  |  |  | 	WALK_LIST(nn, proto_list) {						\ | 
					
						
							|  |  |  | 		struct proto *p = SKIP_BACK(struct proto, glob_node, nn); | 
					
						
							|  |  |  | #define WALK_PROTO_LIST_END } } while(0)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-07 21:50:21 +00:00
										 |  |  | #define PD(pr, msg, args...) do { if (pr->debug & D_STATES) { log(L_TRACE "%s: " msg, pr->name , ## args); } } while(0)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-01-16 23:30:06 +00:00
										 |  |  | list active_proto_list; | 
					
						
							| 
									
										
										
										
											1999-02-11 22:59:06 +00:00
										 |  |  | static list inactive_proto_list; | 
					
						
							|  |  |  | static list initial_proto_list; | 
					
						
							| 
									
										
										
										
											1999-02-13 19:15:28 +00:00
										 |  |  | static list flush_proto_list; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static event *proto_flush_event; | 
					
						
							| 
									
										
										
										
											1999-02-11 22:59:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | static char *p_states[] = { "DOWN", "START", "UP", "STOP" }; | 
					
						
							|  |  |  | static char *c_states[] = { "HUNGRY", "FEEDING", "HAPPY", "FLUSHING" }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-04-27 22:28:49 +00:00
										 |  |  | static void proto_flush_all(void *); | 
					
						
							| 
									
										
										
										
											2000-01-16 16:44:50 +00:00
										 |  |  | static void proto_rethink_goal(struct proto *p); | 
					
						
							| 
									
										
										
										
											2000-03-07 21:50:21 +00:00
										 |  |  | static char *proto_state_name(struct proto *p); | 
					
						
							| 
									
										
										
										
											1999-02-13 19:15:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-03-03 19:33:54 +00:00
										 |  |  | static void | 
					
						
							|  |  |  | proto_enqueue(list *l, struct proto *p) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2000-01-18 11:01:03 +00:00
										 |  |  |   add_tail(l, &p->n); | 
					
						
							| 
									
										
										
										
											1999-12-01 12:00:15 +00:00
										 |  |  |   p->last_state_change = now; | 
					
						
							| 
									
										
										
										
											1999-03-03 19:33:54 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-02-11 22:59:06 +00:00
										 |  |  | static void | 
					
						
							|  |  |  | proto_relink(struct proto *p) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											1999-02-13 19:15:28 +00:00
										 |  |  |   list *l; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-05-16 13:43:26 +00:00
										 |  |  |   if (p->debug & D_STATES) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       char *name = proto_state_name(p); | 
					
						
							|  |  |  |       if (name != p->last_state_name_announced) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  p->last_state_name_announced = name; | 
					
						
							|  |  |  | 	  PD(p, "State changed to %s", proto_state_name(p)); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     p->last_state_name_announced = NULL; | 
					
						
							| 
									
										
										
										
											1999-02-11 22:59:06 +00:00
										 |  |  |   rem_node(&p->n); | 
					
						
							| 
									
										
										
										
											1999-02-13 19:15:28 +00:00
										 |  |  |   switch (p->core_state) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case FS_HAPPY: | 
					
						
							| 
									
										
										
										
											2000-01-16 23:30:06 +00:00
										 |  |  |       l = &active_proto_list; | 
					
						
							| 
									
										
										
										
											1999-02-13 19:15:28 +00:00
										 |  |  |       break; | 
					
						
							|  |  |  |     case FS_FLUSHING: | 
					
						
							|  |  |  |       l = &flush_proto_list; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       l = &inactive_proto_list; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											1999-03-03 19:33:54 +00:00
										 |  |  |   proto_enqueue(l, p); | 
					
						
							| 
									
										
										
										
											1999-02-11 22:59:06 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											1998-05-20 11:54:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-06-02 13:42:36 +00:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * proto_new - create a new protocol instance | 
					
						
							|  |  |  |  * @c: protocol configuration | 
					
						
							|  |  |  |  * @size: size of protocol data structure (each protocol instance is represented by | 
					
						
							|  |  |  |  * a structure starting with generic part [struct &proto] and continued | 
					
						
							|  |  |  |  * with data specific to the protocol) | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * When a new configuration has been read in, the core code starts | 
					
						
							| 
									
										
										
										
											2000-06-07 12:29:08 +00:00
										 |  |  |  * initializing all the protocol instances configured by calling their | 
					
						
							| 
									
										
										
										
											2000-06-02 13:42:36 +00:00
										 |  |  |  * init() hooks with the corresponding instance configuration. The initialization | 
					
						
							|  |  |  |  * code of the protocol is expected to create a new instance according to the | 
					
						
							|  |  |  |  * configuration by calling this function and then modifying the default settings | 
					
						
							|  |  |  |  * to values wanted by the protocol. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											1998-06-03 08:38:53 +00:00
										 |  |  | void * | 
					
						
							| 
									
										
										
										
											1999-02-05 21:37:34 +00:00
										 |  |  | proto_new(struct proto_config *c, unsigned size) | 
					
						
							| 
									
										
										
										
											1998-06-03 08:38:53 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											1999-11-30 14:04:09 +00:00
										 |  |  |   struct protocol *pr = c->protocol; | 
					
						
							| 
									
										
										
										
											1999-03-04 11:39:24 +00:00
										 |  |  |   struct proto *p = mb_allocz(proto_pool, size); | 
					
						
							| 
									
										
										
										
											1998-06-03 08:38:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-02-05 21:37:34 +00:00
										 |  |  |   p->cf = c; | 
					
						
							|  |  |  |   p->debug = c->debug; | 
					
						
							| 
									
										
										
										
											1999-02-11 22:59:06 +00:00
										 |  |  |   p->name = c->name; | 
					
						
							| 
									
										
										
										
											1999-02-05 21:37:34 +00:00
										 |  |  |   p->preference = c->preference; | 
					
						
							|  |  |  |   p->disabled = c->disabled; | 
					
						
							| 
									
										
										
										
											1998-06-03 08:38:53 +00:00
										 |  |  |   p->proto = pr; | 
					
						
							| 
									
										
										
										
											1999-08-03 19:31:54 +00:00
										 |  |  |   p->table = c->table->table; | 
					
						
							| 
									
										
										
										
											1999-03-17 14:31:26 +00:00
										 |  |  |   p->in_filter = c->in_filter; | 
					
						
							|  |  |  |   p->out_filter = c->out_filter; | 
					
						
							| 
									
										
										
										
											1999-12-08 14:16:13 +00:00
										 |  |  |   p->min_scope = SCOPE_SITE; | 
					
						
							| 
									
										
										
										
											2000-03-01 14:49:07 +00:00
										 |  |  |   p->hash_key = random_u32(); | 
					
						
							| 
									
										
										
										
											1999-11-30 14:04:09 +00:00
										 |  |  |   c->proto = p; | 
					
						
							| 
									
										
										
										
											1998-06-03 08:38:53 +00:00
										 |  |  |   return p; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-02-13 19:15:28 +00:00
										 |  |  | static void | 
					
						
							|  |  |  | proto_init_instance(struct proto *p) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											1999-03-29 20:14:33 +00:00
										 |  |  |   /* Here we cannot use p->cf->name since it won't survive reconfiguration */ | 
					
						
							|  |  |  |   p->pool = rp_new(proto_pool, p->proto->name); | 
					
						
							| 
									
										
										
										
											1999-02-13 19:15:28 +00:00
										 |  |  |   p->attn = ev_new(p->pool); | 
					
						
							|  |  |  |   p->attn->data = p; | 
					
						
							| 
									
										
										
										
											2000-01-16 16:44:50 +00:00
										 |  |  |   rt_lock_table(p->table); | 
					
						
							| 
									
										
										
										
											1999-02-13 19:15:28 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-06-02 13:42:36 +00:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * proto_add_announce_hook - connect protocol to a routing table | 
					
						
							|  |  |  |  * @p: protocol instance | 
					
						
							|  |  |  |  * @t: routing table to connect to | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This function creates a connection between the protocol instance @p | 
					
						
							|  |  |  |  * and the routing table @t, making the protocol hear all changes in | 
					
						
							|  |  |  |  * the table. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Unless you want to listen to multiple routing tables (as the Pipe | 
					
						
							|  |  |  |  * protocol does), you needn't to worry about this function since the | 
					
						
							|  |  |  |  * connection to the protocol's primary routing table is initialized | 
					
						
							|  |  |  |  * automatically by the core code. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											1999-05-17 20:14:52 +00:00
										 |  |  | struct announce_hook * | 
					
						
							|  |  |  | proto_add_announce_hook(struct proto *p, struct rtable *t) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   struct announce_hook *h; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!p->rt_notify) | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  |   DBG("Connecting protocol %s to table %s\n", p->name, t->name); | 
					
						
							| 
									
										
										
										
											2000-03-07 21:50:21 +00:00
										 |  |  |   PD(p, "Connected to table %s", t->name); | 
					
						
							| 
									
										
										
										
											1999-05-17 20:14:52 +00:00
										 |  |  |   h = mb_alloc(p->pool, sizeof(struct announce_hook)); | 
					
						
							|  |  |  |   h->table = t; | 
					
						
							|  |  |  |   h->proto = p; | 
					
						
							|  |  |  |   h->next = p->ahooks; | 
					
						
							|  |  |  |   p->ahooks = h; | 
					
						
							|  |  |  |   add_tail(&t->hooks, &h->n); | 
					
						
							|  |  |  |   return h; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | proto_flush_hooks(struct proto *p) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   struct announce_hook *h; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for(h=p->ahooks; h; h=h->next) | 
					
						
							|  |  |  |     rem_node(&h->n); | 
					
						
							|  |  |  |   p->ahooks = NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-06-02 13:42:36 +00:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * proto_config_new - create a new protocol configuration | 
					
						
							|  |  |  |  * @pr: protocol the configuration will belong to | 
					
						
							|  |  |  |  * @size: size of the structure including generic data | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Whenever the configuration file says that a new instance | 
					
						
							|  |  |  |  * of a routing protocol should be created, the parser calls | 
					
						
							|  |  |  |  * proto_config_new() to create a configuration entry for this | 
					
						
							|  |  |  |  * instance (a structure staring with the &proto_config header | 
					
						
							|  |  |  |  * containing all the generic items followed by protocol-specific | 
					
						
							|  |  |  |  * ones). Also, the configuration entry gets added to the list | 
					
						
							|  |  |  |  * of protocol instances kept in the configuration. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											1999-02-05 21:37:34 +00:00
										 |  |  | void * | 
					
						
							|  |  |  | proto_config_new(struct protocol *pr, unsigned size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   struct proto_config *c = cfg_allocz(size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   add_tail(&new_config->protos, &c->n); | 
					
						
							|  |  |  |   c->global = new_config; | 
					
						
							| 
									
										
										
										
											1999-11-30 14:04:09 +00:00
										 |  |  |   c->protocol = pr; | 
					
						
							| 
									
										
										
										
											1999-02-05 21:37:34 +00:00
										 |  |  |   c->name = pr->name; | 
					
						
							| 
									
										
										
										
											1999-04-05 20:15:31 +00:00
										 |  |  |   c->out_filter = FILTER_REJECT; | 
					
						
							| 
									
										
										
										
											1999-08-03 19:31:54 +00:00
										 |  |  |   c->table = c->global->master_rtc; | 
					
						
							| 
									
										
										
										
											2000-03-07 21:50:21 +00:00
										 |  |  |   c->debug = new_config->proto_default_debug; | 
					
						
							| 
									
										
										
										
											1999-02-05 21:37:34 +00:00
										 |  |  |   return c; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-06-02 13:42:36 +00:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * protos_preconfig - pre-configuration processing | 
					
						
							|  |  |  |  * @c: new configuration | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This function calls the preconfig() hooks of all routing | 
					
						
							|  |  |  |  * protocols available to prepare them for reading of the new | 
					
						
							|  |  |  |  * configuration. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											1998-05-20 11:54:33 +00:00
										 |  |  | void | 
					
						
							| 
									
										
										
										
											1999-02-05 21:37:34 +00:00
										 |  |  | protos_preconfig(struct config *c) | 
					
						
							| 
									
										
										
										
											1998-05-20 11:54:33 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											1998-06-03 08:38:53 +00:00
										 |  |  |   struct protocol *p; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-12-06 13:44:45 +00:00
										 |  |  |   init_list(&c->protos); | 
					
						
							| 
									
										
										
										
											2000-03-12 21:01:38 +00:00
										 |  |  |   DBG("Protocol preconfig:"); | 
					
						
							| 
									
										
										
										
											1998-06-03 08:38:53 +00:00
										 |  |  |   WALK_LIST(p, protocol_list) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2000-03-12 21:01:38 +00:00
										 |  |  |       DBG(" %s", p->name); | 
					
						
							| 
									
										
										
										
											1999-03-26 21:37:29 +00:00
										 |  |  |       p->name_counter = 0; | 
					
						
							| 
									
										
										
										
											1998-10-18 12:26:02 +00:00
										 |  |  |       if (p->preconfig) | 
					
						
							| 
									
										
										
										
											1999-02-05 21:37:34 +00:00
										 |  |  | 	p->preconfig(p, c); | 
					
						
							| 
									
										
										
										
											1998-06-03 08:38:53 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2000-03-12 21:01:38 +00:00
										 |  |  |   DBG("\n"); | 
					
						
							| 
									
										
										
										
											1998-06-03 08:38:53 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-06-02 13:42:36 +00:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * protos_postconfig - post-configuration processing | 
					
						
							|  |  |  |  * @c: new configuration | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This function calls the postconfig() hooks of all protocol | 
					
						
							|  |  |  |  * instances specified in configuration @c. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											1998-06-03 08:38:53 +00:00
										 |  |  | void | 
					
						
							| 
									
										
										
										
											1999-02-05 21:37:34 +00:00
										 |  |  | protos_postconfig(struct config *c) | 
					
						
							| 
									
										
										
										
											1998-06-03 08:38:53 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											1999-02-05 21:37:34 +00:00
										 |  |  |   struct proto_config *x; | 
					
						
							| 
									
										
										
										
											1998-06-03 08:38:53 +00:00
										 |  |  |   struct protocol *p; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-12 21:01:38 +00:00
										 |  |  |   DBG("Protocol postconfig:"); | 
					
						
							| 
									
										
										
										
											1999-02-05 21:37:34 +00:00
										 |  |  |   WALK_LIST(x, c->protos) | 
					
						
							| 
									
										
										
										
											1998-06-03 08:38:53 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2000-03-12 21:01:38 +00:00
										 |  |  |       DBG(" %s", x->name); | 
					
						
							| 
									
										
										
										
											1999-11-30 14:04:09 +00:00
										 |  |  |       p = x->protocol; | 
					
						
							| 
									
										
										
										
											1998-10-18 12:26:02 +00:00
										 |  |  |       if (p->postconfig) | 
					
						
							| 
									
										
										
										
											1999-02-05 21:37:34 +00:00
										 |  |  | 	p->postconfig(x); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2000-03-12 21:01:38 +00:00
										 |  |  |   DBG("\n"); | 
					
						
							| 
									
										
										
										
											1999-02-05 21:37:34 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-01-16 16:44:50 +00:00
										 |  |  | static struct proto * | 
					
						
							|  |  |  | proto_init(struct proto_config *c) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   struct protocol *p = c->protocol; | 
					
						
							|  |  |  |   struct proto *q = p->init(c); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   q->proto_state = PS_DOWN; | 
					
						
							|  |  |  |   q->core_state = FS_HUNGRY; | 
					
						
							|  |  |  |   proto_enqueue(&initial_proto_list, q); | 
					
						
							| 
									
										
										
										
											2000-01-16 23:30:06 +00:00
										 |  |  |   add_tail(&proto_list, &q->glob_node); | 
					
						
							| 
									
										
										
										
											2000-05-06 21:42:19 +00:00
										 |  |  |   PD(q, "Initializing%s", q->disabled ? " [disabled]" : ""); | 
					
						
							| 
									
										
										
										
											2000-01-16 16:44:50 +00:00
										 |  |  |   return q; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-06-02 13:42:36 +00:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * protos_commit - commit new protocol configuration | 
					
						
							|  |  |  |  * @new: new configuration | 
					
						
							|  |  |  |  * @old: old configuration or %NULL if it's boot time config | 
					
						
							|  |  |  |  * @force_reconfig: force restart of all protocols (used for example | 
					
						
							|  |  |  |  * when the router ID changes) | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Scan differences between @old and @new configuration and adjust all | 
					
						
							|  |  |  |  * protocol instances to conform to the new configuration. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * When a protocol exists in the new configuration, but it doesn't in the | 
					
						
							|  |  |  |  * original one, it's immediately started. When a collision with the other | 
					
						
							|  |  |  |  * running protocol would arise, the new protocol will be temporarily stopped | 
					
						
							|  |  |  |  * by the locking mechanism. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * When a protocol exists in the old configuration, but it doesn't in the | 
					
						
							|  |  |  |  * new one, it's shut down and deleted after the shutdown completes. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * When a protocol exists in both configurations, the core decides whether | 
					
						
							|  |  |  |  * it's possible to reconfigure it dynamically (it checks all the core properties | 
					
						
							|  |  |  |  * of the protocol and if they match, it asks the reconfigure() hook of the | 
					
						
							|  |  |  |  * protocol to see if the protocol is able to switch to the new configuration). | 
					
						
							|  |  |  |  * If it isn't possible, the protocol is shut down and a new instance is started | 
					
						
							|  |  |  |  * with the new configuration after the shutdown is completed. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											1999-02-05 21:37:34 +00:00
										 |  |  | void | 
					
						
							| 
									
										
										
										
											2000-01-16 16:44:50 +00:00
										 |  |  | protos_commit(struct config *new, struct config *old, int force_reconfig) | 
					
						
							| 
									
										
										
										
											1999-02-05 21:37:34 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2000-01-16 16:44:50 +00:00
										 |  |  |   struct proto_config *oc, *nc; | 
					
						
							|  |  |  |   struct proto *p, *n; | 
					
						
							| 
									
										
										
										
											1999-02-05 21:37:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-01-16 16:44:50 +00:00
										 |  |  |   DBG("protos_commit:\n"); | 
					
						
							|  |  |  |   if (old) | 
					
						
							| 
									
										
										
										
											1999-02-05 21:37:34 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2000-01-16 16:44:50 +00:00
										 |  |  |       WALK_LIST(oc, old->protos) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  struct proto *p = oc->proto; | 
					
						
							|  |  |  | 	  struct symbol *sym = cf_find_symbol(oc->name); | 
					
						
							| 
									
										
										
										
											2000-01-16 17:40:26 +00:00
										 |  |  | 	  if (sym && sym->class == SYM_PROTO && !new->shutdown) | 
					
						
							| 
									
										
										
										
											2000-01-16 16:44:50 +00:00
										 |  |  | 	    { | 
					
						
							|  |  |  | 	      /* Found match, let's check if we can smoothly switch to new configuration */ | 
					
						
							|  |  |  | 	      nc = sym->def; | 
					
						
							|  |  |  | 	      if (!force_reconfig | 
					
						
							|  |  |  | 		  && nc->protocol == oc->protocol | 
					
						
							|  |  |  | 		  && nc->preference == oc->preference | 
					
						
							|  |  |  | 		  && nc->disabled == oc->disabled | 
					
						
							|  |  |  | 		  && nc->table->table == oc->table->table | 
					
						
							| 
									
										
										
										
											2000-01-16 17:49:32 +00:00
										 |  |  | 		  && filter_same(nc->in_filter, oc->in_filter) | 
					
						
							|  |  |  | 		  && filter_same(nc->out_filter, oc->out_filter) | 
					
						
							| 
									
										
										
										
											2000-01-16 16:44:50 +00:00
										 |  |  | 		  && p->proto_state != PS_DOWN) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 		  /* Generic attributes match, try converting them and then ask the protocol */ | 
					
						
							|  |  |  | 		  p->debug = nc->debug; | 
					
						
							| 
									
										
										
										
											2000-01-16 17:40:26 +00:00
										 |  |  | 		  if (p->proto->reconfigure && p->proto->reconfigure(p, nc)) | 
					
						
							| 
									
										
										
										
											2000-01-16 16:44:50 +00:00
										 |  |  | 		    { | 
					
						
							|  |  |  | 		      DBG("\t%s: same\n", oc->name); | 
					
						
							| 
									
										
										
										
											2000-03-07 21:50:21 +00:00
										 |  |  | 		      PD(p, "Reconfigured"); | 
					
						
							| 
									
										
										
										
											2000-01-16 16:44:50 +00:00
										 |  |  | 		      p->cf = nc; | 
					
						
							| 
									
										
										
										
											2000-01-17 00:19:58 +00:00
										 |  |  | 		      p->name = nc->name; | 
					
						
							| 
									
										
										
										
											2000-04-25 21:56:46 +00:00
										 |  |  | 		      p->in_filter = nc->in_filter; | 
					
						
							|  |  |  | 		      p->out_filter = nc->out_filter; | 
					
						
							| 
									
										
										
										
											2000-01-16 16:44:50 +00:00
										 |  |  | 		      nc->proto = p; | 
					
						
							|  |  |  | 		      continue; | 
					
						
							|  |  |  | 		    } | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	      /* Unsuccessful, force reconfig */ | 
					
						
							|  |  |  | 	      DBG("\t%s: power cycling\n", oc->name); | 
					
						
							| 
									
										
										
										
											2000-03-07 21:50:21 +00:00
										 |  |  | 	      PD(p, "Reconfiguration failed, restarting"); | 
					
						
							| 
									
										
										
										
											2000-01-16 16:44:50 +00:00
										 |  |  | 	      p->cf_new = nc; | 
					
						
							| 
									
										
										
										
											2000-01-16 17:40:26 +00:00
										 |  |  | 	      nc->proto = p; | 
					
						
							| 
									
										
										
										
											2000-01-16 16:44:50 +00:00
										 |  |  | 	    } | 
					
						
							|  |  |  | 	  else | 
					
						
							|  |  |  | 	    { | 
					
						
							|  |  |  | 	      DBG("\t%s: deleting\n", oc->name); | 
					
						
							| 
									
										
										
										
											2000-03-07 21:50:21 +00:00
										 |  |  | 	      PD(p, "Unconfigured"); | 
					
						
							| 
									
										
										
										
											2000-01-16 16:44:50 +00:00
										 |  |  | 	      p->cf_new = NULL; | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 	  p->reconfiguring = 1; | 
					
						
							|  |  |  | 	  config_add_obstacle(old); | 
					
						
							|  |  |  | 	  proto_rethink_goal(p); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1998-06-03 08:38:53 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2000-01-16 16:44:50 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   WALK_LIST(nc, new->protos) | 
					
						
							|  |  |  |     if (!nc->proto) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  | 	DBG("\t%s: adding\n", nc->name); | 
					
						
							|  |  |  | 	proto_init(nc); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |   DBG("\tdone\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   DBG("Protocol start\n"); | 
					
						
							|  |  |  |   WALK_LIST_DELSAFE(p, n, initial_proto_list) | 
					
						
							|  |  |  |     proto_rethink_goal(p); | 
					
						
							| 
									
										
										
										
											1998-06-03 08:38:53 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-10-17 11:05:18 +00:00
										 |  |  | static void | 
					
						
							| 
									
										
										
										
											1999-02-11 22:59:06 +00:00
										 |  |  | proto_rethink_goal(struct proto *p) | 
					
						
							| 
									
										
										
										
											1998-10-17 11:05:18 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2000-01-16 16:44:50 +00:00
										 |  |  |   struct protocol *q; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (p->reconfiguring && p->core_state == FS_HUNGRY && p->proto_state == PS_DOWN) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       struct proto_config *nc = p->cf_new; | 
					
						
							|  |  |  |       DBG("%s has shut down for reconfiguration\n", p->name); | 
					
						
							|  |  |  |       config_del_obstacle(p->cf->global); | 
					
						
							|  |  |  |       rem_node(&p->n); | 
					
						
							| 
									
										
										
										
											2000-01-16 23:30:06 +00:00
										 |  |  |       rem_node(&p->glob_node); | 
					
						
							| 
									
										
										
										
											2000-01-16 16:44:50 +00:00
										 |  |  |       mb_free(p); | 
					
						
							|  |  |  |       if (!nc) | 
					
						
							|  |  |  | 	return; | 
					
						
							| 
									
										
										
										
											2000-03-12 22:53:05 +00:00
										 |  |  |       p = proto_init(nc); | 
					
						
							| 
									
										
										
										
											2000-01-16 16:44:50 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Determine what state we want to reach */ | 
					
						
							| 
									
										
										
										
											2000-01-16 17:40:26 +00:00
										 |  |  |   if (p->disabled || p->reconfiguring) | 
					
						
							| 
									
										
										
										
											2000-04-26 12:30:41 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |       p->core_goal = FS_HUNGRY; | 
					
						
							|  |  |  |       if (p->core_state == FS_HUNGRY && p->proto_state == PS_DOWN) | 
					
						
							|  |  |  | 	return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2000-01-16 16:44:50 +00:00
										 |  |  |   else | 
					
						
							| 
									
										
										
										
											2000-04-26 12:30:41 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |       p->core_goal = FS_HAPPY; | 
					
						
							|  |  |  |       if (p->core_state == FS_HAPPY && p->proto_state == PS_UP) | 
					
						
							|  |  |  | 	return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2000-01-16 16:44:50 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   q = p->proto; | 
					
						
							| 
									
										
										
										
											1999-02-11 22:59:06 +00:00
										 |  |  |   if (p->core_goal == FS_HAPPY)		/* Going up */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (p->core_state == FS_HUNGRY && p->proto_state == PS_DOWN) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  DBG("Kicking %s up\n", p->name); | 
					
						
							| 
									
										
										
										
											2000-03-07 21:50:21 +00:00
										 |  |  | 	  PD(p, "Starting"); | 
					
						
							| 
									
										
										
										
											1999-02-13 19:15:28 +00:00
										 |  |  | 	  proto_init_instance(p); | 
					
						
							| 
									
										
										
										
											1999-02-11 22:59:06 +00:00
										 |  |  | 	  proto_notify_state(p, (q->start ? q->start(p) : PS_UP)); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   else 					/* Going down */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (p->proto_state == PS_START || p->proto_state == PS_UP) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  DBG("Kicking %s down\n", p->name); | 
					
						
							| 
									
										
										
										
											2000-03-07 21:50:21 +00:00
										 |  |  | 	  PD(p, "Shutting down"); | 
					
						
							| 
									
										
										
										
											1999-02-11 22:59:06 +00:00
										 |  |  | 	  proto_notify_state(p, (q->shutdown ? q->shutdown(p) : PS_DOWN)); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-06-02 13:42:36 +00:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * protos_dump_all - dump status of all protocols | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This function dumps status of all existing protocol instances to the | 
					
						
							|  |  |  |  * debug output. It involves printing of general status information | 
					
						
							|  |  |  |  * such as protocol states, its position on the protocol lists | 
					
						
							|  |  |  |  * and also calling of a dump() hook of the protocol to print | 
					
						
							|  |  |  |  * the internals. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											1998-07-09 19:36:52 +00:00
										 |  |  | void | 
					
						
							|  |  |  | protos_dump_all(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   struct proto *p; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   debug("Protocols:\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-01-16 23:30:06 +00:00
										 |  |  |   WALK_LIST(p, active_proto_list) | 
					
						
							| 
									
										
										
										
											1998-07-09 19:36:52 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2000-01-18 11:01:03 +00:00
										 |  |  |       debug("  protocol %s state %s/%s\n", p->name, | 
					
						
							| 
									
										
										
										
											1999-03-03 19:33:54 +00:00
										 |  |  | 	    p_states[p->proto_state], c_states[p->core_state]); | 
					
						
							| 
									
										
										
										
											1999-03-17 14:31:26 +00:00
										 |  |  |       if (p->in_filter) | 
					
						
							| 
									
										
										
										
											1999-04-05 20:15:31 +00:00
										 |  |  | 	debug("\tInput filter: %s\n", filter_name(p->in_filter)); | 
					
						
							|  |  |  |       if (p->out_filter != FILTER_REJECT) | 
					
						
							|  |  |  | 	debug("\tOutput filter: %s\n", filter_name(p->out_filter)); | 
					
						
							| 
									
										
										
										
											1998-11-29 22:01:33 +00:00
										 |  |  |       if (p->disabled) | 
					
						
							|  |  |  | 	debug("\tDISABLED\n"); | 
					
						
							| 
									
										
										
										
											1999-02-05 21:37:34 +00:00
										 |  |  |       else if (p->proto->dump) | 
					
						
							|  |  |  | 	p->proto->dump(p); | 
					
						
							| 
									
										
										
										
											1998-07-09 19:36:52 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											1998-10-17 11:05:18 +00:00
										 |  |  |   WALK_LIST(p, inactive_proto_list) | 
					
						
							| 
									
										
										
										
											1999-02-11 22:59:06 +00:00
										 |  |  |     debug("  inactive %s: state %s/%s\n", p->name, p_states[p->proto_state], c_states[p->core_state]); | 
					
						
							|  |  |  |   WALK_LIST(p, initial_proto_list) | 
					
						
							|  |  |  |     debug("  initial %s\n", p->name); | 
					
						
							| 
									
										
										
										
											2000-01-16 23:30:06 +00:00
										 |  |  |   WALK_LIST(p, flush_proto_list) | 
					
						
							|  |  |  |     debug("  flushing %s\n", p->name); | 
					
						
							| 
									
										
										
										
											1998-07-09 19:36:52 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-06-02 13:42:36 +00:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * proto_build - make a single protocol available | 
					
						
							|  |  |  |  * @p: the protocol | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * After the platform specific initialization code uses protos_build() | 
					
						
							|  |  |  |  * to add all the standard protocols, it should call proto_build() for | 
					
						
							| 
									
										
										
										
											2000-06-07 12:29:08 +00:00
										 |  |  |  * all platform specific protocols to inform the core that they exist. | 
					
						
							| 
									
										
										
										
											2000-06-02 13:42:36 +00:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2000-04-01 10:19:47 +00:00
										 |  |  | void | 
					
						
							|  |  |  | proto_build(struct protocol *p) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   add_tail(&protocol_list, &p->n); | 
					
						
							|  |  |  |   if (p->attr_class) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       ASSERT(!attr_class_to_protocol[p->attr_class]); | 
					
						
							|  |  |  |       attr_class_to_protocol[p->attr_class] = p; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-06-02 13:42:36 +00:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * protos_build - build a protocol list | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This function is called during BIRD startup to insert | 
					
						
							|  |  |  |  * all standard protocols to the global protocol list. Insertion | 
					
						
							|  |  |  |  * of platform specific protocols (such as the kernel syncer) | 
					
						
							|  |  |  |  * is in the domain of competence of the platform dependent | 
					
						
							|  |  |  |  * startup code. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											1998-10-18 11:53:21 +00:00
										 |  |  | void | 
					
						
							|  |  |  | protos_build(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   init_list(&protocol_list); | 
					
						
							| 
									
										
										
										
											2000-01-17 12:38:07 +00:00
										 |  |  |   init_list(&proto_list); | 
					
						
							|  |  |  |   init_list(&active_proto_list); | 
					
						
							|  |  |  |   init_list(&inactive_proto_list); | 
					
						
							|  |  |  |   init_list(&initial_proto_list); | 
					
						
							|  |  |  |   init_list(&flush_proto_list); | 
					
						
							| 
									
										
										
										
											2000-04-01 10:19:47 +00:00
										 |  |  |   proto_build(&proto_device); | 
					
						
							| 
									
										
										
										
											1999-01-10 00:26:11 +00:00
										 |  |  | #ifdef CONFIG_RIP
 | 
					
						
							| 
									
										
										
										
											2000-04-01 10:19:47 +00:00
										 |  |  |   proto_build(&proto_rip); | 
					
						
							| 
									
										
										
										
											1999-01-10 00:26:11 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | #ifdef CONFIG_STATIC
 | 
					
						
							| 
									
										
										
										
											2000-04-01 10:19:47 +00:00
										 |  |  |   proto_build(&proto_static); | 
					
						
							| 
									
										
										
										
											1999-03-09 22:27:43 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | #ifdef CONFIG_OSPF
 | 
					
						
							| 
									
										
										
										
											2000-04-01 10:19:47 +00:00
										 |  |  |   proto_build(&proto_ospf); | 
					
						
							| 
									
										
										
										
											2000-01-17 00:19:58 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | #ifdef CONFIG_PIPE
 | 
					
						
							| 
									
										
										
										
											2000-04-01 10:19:47 +00:00
										 |  |  |   proto_build(&proto_pipe); | 
					
						
							| 
									
										
										
										
											2000-03-19 22:09:07 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | #ifdef CONFIG_BGP
 | 
					
						
							| 
									
										
										
										
											2000-04-01 10:19:47 +00:00
										 |  |  |   proto_build(&proto_bgp); | 
					
						
							| 
									
										
										
										
											1999-01-10 00:26:11 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											1999-02-11 22:59:06 +00:00
										 |  |  |   proto_pool = rp_new(&root_pool, "Protocols"); | 
					
						
							| 
									
										
										
										
											1999-02-13 19:15:28 +00:00
										 |  |  |   proto_flush_event = ev_new(proto_pool); | 
					
						
							|  |  |  |   proto_flush_event->hook = proto_flush_all; | 
					
						
							| 
									
										
										
										
											1999-02-11 22:59:06 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | proto_fell_down(struct proto *p) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   DBG("Protocol %s down\n", p->name); | 
					
						
							| 
									
										
										
										
											2000-01-16 16:44:50 +00:00
										 |  |  |   rt_unlock_table(p->table); | 
					
						
							| 
									
										
										
										
											1999-02-11 22:59:06 +00:00
										 |  |  |   proto_rethink_goal(p); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-05-19 10:46:26 +00:00
										 |  |  | static void | 
					
						
							|  |  |  | proto_feed_more(void *P) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   struct proto *p = P; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   DBG("Feeding protocol %s continued\n", p->name); | 
					
						
							| 
									
										
										
										
											2000-05-19 18:03:53 +00:00
										 |  |  |   if (p->core_state != FS_FEEDING) | 
					
						
							|  |  |  |     return; | 
					
						
							| 
									
										
										
										
											2000-05-19 10:46:26 +00:00
										 |  |  |   if (rt_feed_baby(p)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       p->core_state = FS_HAPPY; | 
					
						
							|  |  |  |       proto_relink(p); | 
					
						
							|  |  |  |       DBG("Protocol %s up and running\n", p->name); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       p->attn->hook = proto_feed_more; | 
					
						
							|  |  |  |       ev_schedule(p->attn);		/* Will continue later... */ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-04-27 22:28:49 +00:00
										 |  |  | static void | 
					
						
							| 
									
										
										
										
											1999-02-11 22:59:06 +00:00
										 |  |  | proto_feed(void *P) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   struct proto *p = P; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   DBG("Feeding protocol %s\n", p->name); | 
					
						
							| 
									
										
										
										
											1999-05-17 20:14:52 +00:00
										 |  |  |   proto_add_announce_hook(p, p->table); | 
					
						
							| 
									
										
										
										
											1999-02-11 22:59:06 +00:00
										 |  |  |   if_feed_baby(p); | 
					
						
							| 
									
										
										
										
											2000-05-19 10:46:26 +00:00
										 |  |  |   proto_feed_more(P); | 
					
						
							| 
									
										
										
										
											1999-02-11 22:59:06 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-06-02 13:42:36 +00:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * proto_notify_state - notify core about protocol state change | 
					
						
							|  |  |  |  * @p: protocol the state of which has changed | 
					
						
							|  |  |  |  * @ps: the new status | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Whenever a state of a protocol changes due to some event internal | 
					
						
							|  |  |  |  * to the protocol (i.e., not inside a start() or shutdown() hook), | 
					
						
							|  |  |  |  * it should immediately notify the core about the change by calling | 
					
						
							|  |  |  |  * proto_notify_state() which will write the new state to the &proto | 
					
						
							|  |  |  |  * structure and take all the actions necessary to adapt to the new | 
					
						
							|  |  |  |  * state. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											1999-02-11 22:59:06 +00:00
										 |  |  | void | 
					
						
							|  |  |  | proto_notify_state(struct proto *p, unsigned ps) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   unsigned ops = p->proto_state; | 
					
						
							|  |  |  |   unsigned cs = p->core_state; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   DBG("%s reporting state transition %s/%s -> */%s\n", p->name, c_states[cs], p_states[ops], p_states[ps]); | 
					
						
							|  |  |  |   if (ops == ps) | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   switch (ps) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case PS_DOWN: | 
					
						
							|  |  |  |       if (cs == FS_HUNGRY)		/* Shutdown finished */ | 
					
						
							| 
									
										
										
										
											2000-01-16 16:44:50 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2000-04-26 12:30:41 +00:00
										 |  |  | 	  p->proto_state = ps; | 
					
						
							| 
									
										
										
										
											2000-01-16 16:44:50 +00:00
										 |  |  | 	  proto_fell_down(p); | 
					
						
							|  |  |  | 	  return;			/* The protocol might have ceased to exist */ | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1999-02-11 22:59:06 +00:00
										 |  |  |       else if (cs == FS_FLUSHING)	/* Still flushing... */ | 
					
						
							|  |  |  | 	; | 
					
						
							| 
									
										
										
										
											2000-05-19 10:46:26 +00:00
										 |  |  |       else | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  if (cs == FS_FEEDING)		/* Need to abort feeding */ | 
					
						
							|  |  |  | 	    rt_feed_baby_abort(p); | 
					
						
							|  |  |  | 	  goto schedule_flush;		/* Need to start flushing */ | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1999-02-11 22:59:06 +00:00
										 |  |  |       break; | 
					
						
							|  |  |  |     case PS_START: | 
					
						
							|  |  |  |       ASSERT(ops == PS_DOWN); | 
					
						
							|  |  |  |       ASSERT(cs == FS_HUNGRY); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case PS_UP: | 
					
						
							|  |  |  |       ASSERT(ops == PS_DOWN || ops == PS_START); | 
					
						
							|  |  |  |       ASSERT(cs == FS_HUNGRY); | 
					
						
							|  |  |  |       DBG("%s: Scheduling meal\n", p->name); | 
					
						
							|  |  |  |       cs = FS_FEEDING; | 
					
						
							|  |  |  |       p->attn->hook = proto_feed; | 
					
						
							|  |  |  |       ev_schedule(p->attn); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case PS_STOP: | 
					
						
							| 
									
										
										
										
											2000-04-26 12:30:41 +00:00
										 |  |  |       if (ops != PS_DOWN) | 
					
						
							| 
									
										
										
										
											1999-02-11 22:59:06 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 	schedule_flush: | 
					
						
							|  |  |  | 	  DBG("%s: Scheduling flush\n", p->name); | 
					
						
							| 
									
										
										
										
											1999-08-03 19:31:54 +00:00
										 |  |  | 	  proto_flush_hooks(p); | 
					
						
							| 
									
										
										
										
											1999-02-11 22:59:06 +00:00
										 |  |  | 	  cs = FS_FLUSHING; | 
					
						
							| 
									
										
										
										
											1999-02-13 19:15:28 +00:00
										 |  |  | 	  ev_schedule(proto_flush_event); | 
					
						
							| 
									
										
										
										
											1999-02-11 22:59:06 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											1999-02-13 20:15:36 +00:00
										 |  |  |       break; | 
					
						
							| 
									
										
										
										
											1999-02-11 22:59:06 +00:00
										 |  |  |     default: | 
					
						
							|  |  |  |       bug("Invalid state transition for %s from %s/%s to */%s", p->name, c_states[cs], p_states[ops], p_states[ps]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   p->proto_state = ps; | 
					
						
							|  |  |  |   p->core_state = cs; | 
					
						
							|  |  |  |   proto_relink(p); | 
					
						
							| 
									
										
										
										
											1998-10-18 11:53:21 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											1999-02-13 19:15:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-04-27 22:28:49 +00:00
										 |  |  | static void | 
					
						
							| 
									
										
										
										
											1999-02-13 19:15:28 +00:00
										 |  |  | proto_flush_all(void *unused) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   struct proto *p; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-05-17 20:14:52 +00:00
										 |  |  |   rt_prune_all(); | 
					
						
							| 
									
										
										
										
											1999-02-13 20:55:08 +00:00
										 |  |  |   neigh_prune(); | 
					
						
							| 
									
										
										
										
											1999-02-13 19:15:28 +00:00
										 |  |  |   while ((p = HEAD(flush_proto_list))->n.next) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       DBG("Flushing protocol %s\n", p->name); | 
					
						
							|  |  |  |       rfree(p->pool); | 
					
						
							|  |  |  |       p->pool = NULL; | 
					
						
							|  |  |  |       p->core_state = FS_HUNGRY; | 
					
						
							|  |  |  |       proto_relink(p); | 
					
						
							| 
									
										
										
										
											1999-02-13 20:15:36 +00:00
										 |  |  |       proto_fell_down(p); | 
					
						
							| 
									
										
										
										
											1999-02-13 19:15:28 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											1999-11-25 15:35:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-11-30 12:57:14 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  *  CLI Commands | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static char * | 
					
						
							|  |  |  | proto_state_name(struct proto *p) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #define P(x,y) ((x << 4) | y)
 | 
					
						
							|  |  |  |   switch (P(p->proto_state, p->core_state)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case P(PS_DOWN, FS_HUNGRY):		return "down"; | 
					
						
							|  |  |  |     case P(PS_START, FS_HUNGRY):	return "start"; | 
					
						
							|  |  |  |     case P(PS_UP, FS_HUNGRY): | 
					
						
							|  |  |  |     case P(PS_UP, FS_FEEDING):		return "feed"; | 
					
						
							|  |  |  |     case P(PS_STOP, FS_HUNGRY):		return "stop"; | 
					
						
							|  |  |  |     case P(PS_UP, FS_HAPPY):		return "up"; | 
					
						
							|  |  |  |     case P(PS_STOP, FS_FLUSHING): | 
					
						
							|  |  |  |     case P(PS_DOWN, FS_FLUSHING):	return "flush"; | 
					
						
							|  |  |  |     default:      			return "???"; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | #undef P
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											1999-11-30 14:04:09 +00:00
										 |  |  | proto_do_show(struct proto *p, int verbose) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											1999-12-01 12:00:15 +00:00
										 |  |  |   byte buf[256], reltime[TM_RELTIME_BUFFER_SIZE]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   buf[0] = 0; | 
					
						
							|  |  |  |   if (p->proto->get_status) | 
					
						
							|  |  |  |     p->proto->get_status(p, buf); | 
					
						
							|  |  |  |   tm_format_reltime(reltime, p->last_state_change); | 
					
						
							| 
									
										
										
										
											2000-05-30 21:23:49 +00:00
										 |  |  |   cli_msg(-1002, "%-8s %-8s %-8s %-5s %-5s  %s", | 
					
						
							| 
									
										
										
										
											1999-11-30 14:04:09 +00:00
										 |  |  | 	  p->name, | 
					
						
							|  |  |  | 	  p->proto->name, | 
					
						
							|  |  |  | 	  p->table->name, | 
					
						
							|  |  |  | 	  proto_state_name(p), | 
					
						
							| 
									
										
										
										
											1999-12-01 12:00:15 +00:00
										 |  |  | 	  reltime, | 
					
						
							|  |  |  | 	  buf); | 
					
						
							| 
									
										
										
										
											1999-11-30 14:04:09 +00:00
										 |  |  |   if (verbose) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       cli_msg(-1006, "\tPreference: %d", p->preference); | 
					
						
							|  |  |  |       cli_msg(-1006, "\tInput filter: %s", filter_name(p->in_filter)); | 
					
						
							|  |  |  |       cli_msg(-1006, "\tOutput filter: %s", filter_name(p->out_filter)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-11-25 15:35:30 +00:00
										 |  |  | void | 
					
						
							| 
									
										
										
										
											1999-11-30 12:57:14 +00:00
										 |  |  | proto_show(struct symbol *s, int verbose) | 
					
						
							| 
									
										
										
										
											1999-11-25 15:35:30 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											1999-11-30 14:04:09 +00:00
										 |  |  |   if (s && s->class != SYM_PROTO) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       cli_msg(9002, "%s is not a protocol", s->name); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2000-05-30 21:23:49 +00:00
										 |  |  |   cli_msg(-2002, "name     proto    table    state since  info"); | 
					
						
							| 
									
										
										
										
											1999-11-30 14:04:09 +00:00
										 |  |  |   if (s) | 
					
						
							|  |  |  |     proto_do_show(((struct proto_config *)s->def)->proto, verbose); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2000-01-16 23:30:06 +00:00
										 |  |  |       WALK_PROTO_LIST(p) | 
					
						
							|  |  |  | 	proto_do_show(p, verbose); | 
					
						
							|  |  |  |       WALK_PROTO_LIST_END; | 
					
						
							| 
									
										
										
										
											1999-11-30 14:04:09 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											1999-11-25 15:35:30 +00:00
										 |  |  |   cli_msg(0, ""); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											1999-12-03 11:40:45 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | struct proto * | 
					
						
							|  |  |  | proto_get_named(struct symbol *sym, struct protocol *pr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   struct proto *p, *q; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (sym) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (sym->class != SYM_PROTO) | 
					
						
							|  |  |  | 	cf_error("%s: Not a protocol", sym->name); | 
					
						
							|  |  |  |       p = ((struct proto_config *)sym->def)->proto; | 
					
						
							|  |  |  |       if (!p || p->proto != pr) | 
					
						
							|  |  |  | 	cf_error("%s: Not a %s protocol", sym->name, pr->name); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       p = NULL; | 
					
						
							| 
									
										
										
										
											2000-01-16 23:30:06 +00:00
										 |  |  |       WALK_LIST(q, active_proto_list) | 
					
						
							| 
									
										
										
										
											1999-12-03 11:40:45 +00:00
										 |  |  | 	if (q->proto == pr) | 
					
						
							|  |  |  | 	  { | 
					
						
							|  |  |  | 	    if (p) | 
					
						
							|  |  |  | 	      cf_error("There are multiple %s protocols running", pr->name); | 
					
						
							|  |  |  | 	    p = q; | 
					
						
							|  |  |  | 	  } | 
					
						
							|  |  |  |       if (!p) | 
					
						
							|  |  |  | 	cf_error("There is no %s protocol running", pr->name); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   return p; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2000-01-16 23:30:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | proto_xxable(char *pattern, int xx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   int cnt = 0; | 
					
						
							|  |  |  |   WALK_PROTO_LIST(p) | 
					
						
							|  |  |  |     if (patmatch(pattern, p->name)) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  | 	cnt++; | 
					
						
							|  |  |  | 	switch (xx) | 
					
						
							|  |  |  | 	  { | 
					
						
							|  |  |  | 	  case 0: | 
					
						
							|  |  |  | 	    if (p->disabled) | 
					
						
							|  |  |  | 	      cli_msg(-8, "%s: already disabled", p->name); | 
					
						
							|  |  |  | 	    else | 
					
						
							|  |  |  | 	      { | 
					
						
							|  |  |  | 		cli_msg(-9, "%s: disabled", p->name); | 
					
						
							|  |  |  | 		p->disabled = 1; | 
					
						
							|  |  |  | 	      } | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  case 1: | 
					
						
							|  |  |  | 	    if (!p->disabled) | 
					
						
							|  |  |  | 	      cli_msg(-10, "%s: already enabled", p->name); | 
					
						
							|  |  |  | 	    else | 
					
						
							|  |  |  | 	      { | 
					
						
							|  |  |  | 		cli_msg(-11, "%s: enabled", p->name); | 
					
						
							|  |  |  | 		p->disabled = 0; | 
					
						
							|  |  |  | 	      } | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  case 2: | 
					
						
							|  |  |  | 	    if (p->disabled) | 
					
						
							|  |  |  | 	      cli_msg(-8, "%s: already disabled", p->name); | 
					
						
							|  |  |  | 	    else | 
					
						
							|  |  |  | 	      { | 
					
						
							|  |  |  | 		p->disabled = 1; | 
					
						
							|  |  |  | 		proto_rethink_goal(p); | 
					
						
							|  |  |  | 		p->disabled = 0; | 
					
						
							|  |  |  | 		cli_msg(-12, "%s: restarted", p->name); | 
					
						
							|  |  |  | 	      } | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  default: | 
					
						
							|  |  |  | 	    ASSERT(0); | 
					
						
							|  |  |  | 	  } | 
					
						
							|  |  |  | 	proto_rethink_goal(p); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |   WALK_PROTO_LIST_END; | 
					
						
							|  |  |  |   if (!cnt) | 
					
						
							|  |  |  |     cli_msg(8003, "No protocols match"); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     cli_msg(0, ""); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2000-03-07 20:49:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | proto_debug(char *pattern, unsigned int mask) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   int cnt = 0; | 
					
						
							|  |  |  |   WALK_PROTO_LIST(p) | 
					
						
							|  |  |  |     if (patmatch(pattern, p->name)) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  | 	cnt++; | 
					
						
							|  |  |  | 	p->debug = mask; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |   WALK_PROTO_LIST_END; | 
					
						
							|  |  |  |   if (!cnt) | 
					
						
							|  |  |  |     cli_msg(8003, "No protocols match"); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     cli_msg(0, ""); | 
					
						
							|  |  |  | } |