Annotation of embedaddon/bird/nest/proto.c, revision 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>