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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>