Annotation of embedaddon/bird2/proto/pipe/pipe.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  *     BIRD -- Table-to-Table Routing Protocol a.k.a Pipe
                      3:  *
                      4:  *     (c) 1999--2000 Martin Mares <mj@ucw.cz>
                      5:  *
                      6:  *     Can be freely distributed and used under the terms of the GNU GPL.
                      7:  */
                      8: 
                      9: /**
                     10:  * DOC: Pipe
                     11:  *
                     12:  * The Pipe protocol is very simple. It just connects to two routing tables
                     13:  * using proto_add_announce_hook() and whenever it receives a rt_notify()
                     14:  * about a change in one of the tables, it converts it to a rte_update()
                     15:  * in the other one.
                     16:  *
                     17:  * To avoid pipe loops, Pipe keeps a `being updated' flag in each routing
                     18:  * table.
                     19:  *
                     20:  * A pipe has two announce hooks, the first connected to the main
                     21:  * table, the second connected to the peer table. When a new route is
                     22:  * announced on the main table, it gets checked by an export filter in
                     23:  * ahook 1, and, after that, it is announced to the peer table via
                     24:  * rte_update(), an import filter in ahook 2 is called. When a new
                     25:  * route is announced in the peer table, an export filter in ahook2
                     26:  * and an import filter in ahook 1 are used. Oviously, there is no
                     27:  * need in filtering the same route twice, so both import filters are
                     28:  * set to accept, while user configured 'import' and 'export' filters
                     29:  * are used as export filters in ahooks 2 and 1. Route limits are
                     30:  * handled similarly, but on the import side of ahooks.
                     31:  */
                     32: 
                     33: #undef LOCAL_DEBUG
                     34: 
                     35: #include "nest/bird.h"
                     36: #include "nest/iface.h"
                     37: #include "nest/protocol.h"
                     38: #include "nest/route.h"
                     39: #include "nest/cli.h"
                     40: #include "conf/conf.h"
                     41: #include "filter/filter.h"
                     42: #include "lib/string.h"
                     43: 
                     44: #include "pipe.h"
                     45: 
                     46: static void
                     47: pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *old)
                     48: {
                     49:   struct pipe_proto *p = (void *) P;
                     50:   struct channel *dst = (src_ch == p->pri) ? p->sec : p->pri;
                     51:   struct rte_src *src;
                     52: 
                     53:   rte *e;
                     54:   rta *a;
                     55: 
                     56:   if (!new && !old)
                     57:     return;
                     58: 
                     59:   if (dst->table->pipe_busy)
                     60:     {
                     61:       log(L_ERR "Pipe loop detected when sending %N to table %s",
                     62:          n->n.addr, dst->table->name);
                     63:       return;
                     64:     }
                     65: 
                     66:   if (new)
                     67:     {
                     68:       a = alloca(rta_size(new->attrs));
                     69:       memcpy(a, new->attrs, rta_size(new->attrs));
                     70: 
                     71:       a->aflags = 0;
                     72:       a->hostentry = NULL;
                     73:       e = rte_get_temp(a);
                     74:       e->pflags = 0;
                     75: 
                     76:       /* Copy protocol specific embedded attributes. */
                     77:       memcpy(&(e->u), &(new->u), sizeof(e->u));
                     78:       e->pref = new->pref;
                     79:       e->pflags = new->pflags;
                     80: 
                     81: #ifdef CONFIG_BGP
                     82:       /* Hack to cleanup cached value */
                     83:       if (e->attrs->src->proto->proto == &proto_bgp)
                     84:        e->u.bgp.stale = -1;
                     85: #endif
                     86: 
                     87:       src = a->src;
                     88:     }
                     89:   else
                     90:     {
                     91:       e = NULL;
                     92:       src = old->attrs->src;
                     93:     }
                     94: 
                     95:   src_ch->table->pipe_busy = 1;
                     96:   rte_update2(dst, n->n.addr, e, src);
                     97:   src_ch->table->pipe_busy = 0;
                     98: }
                     99: 
                    100: static int
                    101: pipe_preexport(struct proto *P, rte **ee, struct linpool *p UNUSED)
                    102: {
                    103:   struct proto *pp = (*ee)->sender->proto;
                    104: 
                    105:   if (pp == P)
                    106:     return -1; /* Avoid local loops automatically */
                    107: 
                    108:   return 0;
                    109: }
                    110: 
                    111: static void
                    112: pipe_reload_routes(struct channel *C)
                    113: {
                    114:   struct pipe_proto *p = (void *) C->proto;
                    115: 
                    116:   /* Route reload on one channel is just refeed on the other */
                    117:   channel_request_feeding((C == p->pri) ? p->sec : p->pri);
                    118: }
                    119: 
                    120: 
                    121: static void
                    122: pipe_postconfig(struct proto_config *CF)
                    123: {
                    124:   struct pipe_config *cf = (void *) CF;
                    125:   struct channel_config *cc = proto_cf_main_channel(CF);
                    126: 
                    127:   if (!cc->table)
                    128:     cf_error("Primary routing table not specified");
                    129: 
                    130:   if (!cf->peer)
                    131:     cf_error("Secondary routing table not specified");
                    132: 
                    133:   if (cc->table == cf->peer)
                    134:     cf_error("Primary table and peer table must be different");
                    135: 
                    136:   if (cc->table->addr_type != cf->peer->addr_type)
                    137:     cf_error("Primary table and peer table must have the same type");
                    138: 
                    139:   if (cc->rx_limit.action)
                    140:     cf_error("Pipe protocol does not support receive limits");
                    141: 
                    142:   if (cc->in_keep_filtered)
                    143:     cf_error("Pipe protocol prohibits keeping filtered routes");
                    144: }
                    145: 
                    146: static int
                    147: pipe_configure_channels(struct pipe_proto *p, struct pipe_config *cf)
                    148: {
                    149:   struct channel_config *cc = proto_cf_main_channel(&cf->c);
                    150: 
                    151:   struct channel_config pri_cf = {
                    152:     .name = "pri",
                    153:     .channel = cc->channel,
                    154:     .table = cc->table,
                    155:     .out_filter = cc->out_filter,
                    156:     .in_limit = cc->in_limit,
                    157:     .ra_mode = RA_ANY
                    158:   };
                    159: 
                    160:   struct channel_config sec_cf = {
                    161:     .name = "sec",
                    162:     .channel = cc->channel,
                    163:     .table = cf->peer,
                    164:     .out_filter = cc->in_filter,
                    165:     .in_limit = cc->out_limit,
                    166:     .ra_mode = RA_ANY
                    167:   };
                    168: 
                    169:   return
                    170:     proto_configure_channel(&p->p, &p->pri, &pri_cf) &&
                    171:     proto_configure_channel(&p->p, &p->sec, &sec_cf);
                    172: }
                    173: 
                    174: static struct proto *
                    175: pipe_init(struct proto_config *CF)
                    176: {
                    177:   struct proto *P = proto_new(CF);
                    178:   struct pipe_proto *p = (void *) P;
                    179:   struct pipe_config *cf = (void *) CF;
                    180: 
                    181:   P->rt_notify = pipe_rt_notify;
                    182:   P->preexport = pipe_preexport;
                    183:   P->reload_routes = pipe_reload_routes;
                    184: 
                    185:   pipe_configure_channels(p, cf);
                    186: 
                    187:   return P;
                    188: }
                    189: 
                    190: static int
                    191: pipe_reconfigure(struct proto *P, struct proto_config *CF)
                    192: {
                    193:   struct pipe_proto *p = (void *) P;
                    194:   struct pipe_config *cf = (void *) CF;
                    195: 
                    196:   return pipe_configure_channels(p, cf);
                    197: }
                    198: 
                    199: static void
                    200: pipe_copy_config(struct proto_config *dest UNUSED, struct proto_config *src UNUSED)
                    201: {
                    202:   /* Just a shallow copy, not many items here */
                    203: }
                    204: 
                    205: static void
                    206: pipe_get_status(struct proto *P, byte *buf)
                    207: {
                    208:   struct pipe_proto *p = (void *) P;
                    209: 
                    210:   bsprintf(buf, "%s <=> %s", p->pri->table->name, p->sec->table->name);
                    211: }
                    212: 
                    213: static void
                    214: pipe_show_stats(struct pipe_proto *p)
                    215: {
                    216:   struct proto_stats *s1 = &p->pri->stats;
                    217:   struct proto_stats *s2 = &p->sec->stats;
                    218: 
                    219:   /*
                    220:    * Pipe stats (as anything related to pipes) are a bit tricky. There
                    221:    * are two sets of stats - s1 for ahook to the primary routing and
                    222:    * s2 for the ahook to the secondary routing table. The user point
                    223:    * of view is that routes going from the primary routing table to
                    224:    * the secondary routing table are 'exported', while routes going in
                    225:    * the other direction are 'imported'.
                    226:    *
                    227:    * Each route going through a pipe is, technically, first exported
                    228:    * to the pipe and then imported from that pipe and such operations
                    229:    * are counted in one set of stats according to the direction of the
                    230:    * route propagation. Filtering is done just in the first part
                    231:    * (export). Therefore, we compose stats for one directon for one
                    232:    * user direction from both import and export stats, skipping
                    233:    * immediate and irrelevant steps (exp_updates_accepted,
                    234:    * imp_updates_received, imp_updates_filtered, ...).
                    235:    *
                    236:    * Rule of thumb is that stats s1 have the correct 'polarity'
                    237:    * (imp/exp), while stats s2 have switched 'polarity'.
                    238:    */
                    239: 
                    240:   cli_msg(-1006, "  Routes:         %u imported, %u exported",
                    241:          s1->imp_routes, s2->imp_routes);
                    242:   cli_msg(-1006, "  Route change stats:     received   rejected   filtered    ignored   accepted");
                    243:   cli_msg(-1006, "    Import updates:     %10u %10u %10u %10u %10u",
                    244:          s2->exp_updates_received, s2->exp_updates_rejected + s1->imp_updates_invalid,
                    245:          s2->exp_updates_filtered, s1->imp_updates_ignored, s1->imp_updates_accepted);
                    246:   cli_msg(-1006, "    Import withdraws:   %10u %10u        --- %10u %10u",
                    247:          s2->exp_withdraws_received, s1->imp_withdraws_invalid,
                    248:          s1->imp_withdraws_ignored, s1->imp_withdraws_accepted);
                    249:   cli_msg(-1006, "    Export updates:     %10u %10u %10u %10u %10u",
                    250:          s1->exp_updates_received, s1->exp_updates_rejected + s2->imp_updates_invalid,
                    251:          s1->exp_updates_filtered, s2->imp_updates_ignored, s2->imp_updates_accepted);
                    252:   cli_msg(-1006, "    Export withdraws:   %10u %10u        --- %10u %10u",
                    253:          s1->exp_withdraws_received, s2->imp_withdraws_invalid,
                    254:          s2->imp_withdraws_ignored, s2->imp_withdraws_accepted);
                    255: }
                    256: 
                    257: static const char *pipe_feed_state[] = { [ES_DOWN] = "down", [ES_FEEDING] = "feed", [ES_READY] = "up" };
                    258: 
                    259: static void
                    260: pipe_show_proto_info(struct proto *P)
                    261: {
                    262:   struct pipe_proto *p = (void *) P;
                    263: 
                    264:   cli_msg(-1006, "  Channel %s", "main");
                    265:   cli_msg(-1006, "    Table:          %s", p->pri->table->name);
                    266:   cli_msg(-1006, "    Peer table:     %s", p->sec->table->name);
                    267:   cli_msg(-1006, "    Import state:   %s", pipe_feed_state[p->sec->export_state]);
                    268:   cli_msg(-1006, "    Export state:   %s", pipe_feed_state[p->pri->export_state]);
                    269:   cli_msg(-1006, "    Import filter:  %s", filter_name(p->sec->out_filter));
                    270:   cli_msg(-1006, "    Export filter:  %s", filter_name(p->pri->out_filter));
                    271: 
                    272:   channel_show_limit(&p->pri->in_limit, "Import limit:");
                    273:   channel_show_limit(&p->sec->in_limit, "Export limit:");
                    274: 
                    275:   if (P->proto_state != PS_DOWN)
                    276:     pipe_show_stats(p);
                    277: }
                    278: 
                    279: 
                    280: struct protocol proto_pipe = {
                    281:   .name =              "Pipe",
                    282:   .template =          "pipe%d",
                    283:   .class =             PROTOCOL_PIPE,
                    284:   .proto_size =                sizeof(struct pipe_proto),
                    285:   .config_size =       sizeof(struct pipe_config),
                    286:   .postconfig =                pipe_postconfig,
                    287:   .init =              pipe_init,
                    288:   .reconfigure =       pipe_reconfigure,
                    289:   .copy_config =       pipe_copy_config,
                    290:   .get_status =        pipe_get_status,
                    291:   .show_proto_info =   pipe_show_proto_info
                    292: };

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