Annotation of embedaddon/bird/proto/pipe/pipe.c, revision 1.1.1.2
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, rtable *src_table, net *n, rte *new, rte *old, ea_list *attrs)
48: {
49: struct pipe_proto *p = (struct pipe_proto *) P;
50: struct announce_hook *ah = (src_table == P->table) ? p->peer_ahook : P->main_ahook;
51: rtable *dst_table = ah->table;
52: struct rte_src *src;
53:
54: net *nn;
55: rte *e;
56: rta a;
57:
58: if (!new && !old)
59: return;
60:
61: if (dst_table->pipe_busy)
62: {
63: log(L_ERR "Pipe loop detected when sending %I/%d to table %s",
64: n->n.prefix, n->n.pxlen, dst_table->name);
65: return;
66: }
67:
68: nn = net_get(dst_table, n->n.prefix, n->n.pxlen);
69: if (new)
70: {
71: memcpy(&a, new->attrs, sizeof(rta));
72:
73: if (p->mode == PIPE_OPAQUE)
74: {
75: a.src = P->main_source;
76: a.source = RTS_PIPE;
77: }
78:
79: a.aflags = 0;
80: a.eattrs = attrs;
81: a.hostentry = NULL;
82: e = rte_get_temp(&a);
83: e->net = nn;
84: e->pflags = 0;
85:
86: if (p->mode == PIPE_TRANSPARENT)
87: {
88: /* Copy protocol specific embedded attributes. */
89: memcpy(&(e->u), &(new->u), sizeof(e->u));
90: e->pref = new->pref;
91: e->pflags = new->pflags;
1.1.1.2 ! misho 92:
! 93: #ifdef CONFIG_BGP
! 94: /* Hack to cleanup cached value */
! 95: if (e->attrs->src->proto->proto == &proto_bgp)
! 96: e->u.bgp.stale = -1;
! 97: #endif
1.1 misho 98: }
99:
100: src = a.src;
101: }
102: else
103: {
104: e = NULL;
105: src = old->attrs->src;
106: }
107:
108: src_table->pipe_busy = 1;
109: rte_update2(ah, nn, e, src);
110: src_table->pipe_busy = 0;
111: }
112:
113: static int
114: pipe_import_control(struct proto *P, rte **ee, ea_list **ea UNUSED, struct linpool *p UNUSED)
115: {
116: struct proto *pp = (*ee)->sender->proto;
117:
118: if (pp == P)
119: return -1; /* Avoid local loops automatically */
120: return 0;
121: }
122:
123: static int
124: pipe_reload_routes(struct proto *P)
125: {
126: struct pipe_proto *p = (struct pipe_proto *) P;
127:
128: /*
129: * Because the pipe protocol feeds routes from both routing tables
130: * together, both directions are reloaded during refeed and 'reload
131: * out' command works like 'reload' command. For symmetry, we also
132: * request refeed when 'reload in' command is used.
133: */
134: proto_request_feeding(P);
135:
136: proto_reset_limit(P->main_ahook->in_limit);
137: proto_reset_limit(p->peer_ahook->in_limit);
138:
139: return 1;
140: }
141:
142: static struct proto *
143: pipe_init(struct proto_config *C)
144: {
145: struct pipe_config *c = (struct pipe_config *) C;
146: struct proto *P = proto_new(C, sizeof(struct pipe_proto));
147: struct pipe_proto *p = (struct pipe_proto *) P;
148:
149: p->mode = c->mode;
150: p->peer_table = c->peer->table;
151: P->accept_ra_types = (p->mode == PIPE_OPAQUE) ? RA_OPTIMAL : RA_ANY;
152: P->rt_notify = pipe_rt_notify;
153: P->import_control = pipe_import_control;
154: P->reload_routes = pipe_reload_routes;
155:
156: return P;
157: }
158:
159: static int
160: pipe_start(struct proto *P)
161: {
162: struct pipe_config *cf = (struct pipe_config *) P->cf;
163: struct pipe_proto *p = (struct pipe_proto *) P;
164:
165: /* Lock both tables, unlock is handled in pipe_cleanup() */
166: rt_lock_table(P->table);
167: rt_lock_table(p->peer_table);
168:
169: /* Going directly to PS_UP - prepare for feeding,
170: connect the protocol to both routing tables */
171:
172: P->main_ahook = proto_add_announce_hook(P, P->table, &P->stats);
173: P->main_ahook->out_filter = cf->c.out_filter;
174: P->main_ahook->in_limit = cf->c.in_limit;
175: proto_reset_limit(P->main_ahook->in_limit);
176:
177: p->peer_ahook = proto_add_announce_hook(P, p->peer_table, &p->peer_stats);
178: p->peer_ahook->out_filter = cf->c.in_filter;
179: p->peer_ahook->in_limit = cf->c.out_limit;
180: proto_reset_limit(p->peer_ahook->in_limit);
181:
182: if (p->mode == PIPE_OPAQUE)
183: {
184: P->main_source = rt_get_source(P, 0);
185: rt_lock_source(P->main_source);
186: }
187:
188: return PS_UP;
189: }
190:
191: static void
192: pipe_cleanup(struct proto *P)
193: {
194: struct pipe_proto *p = (struct pipe_proto *) P;
195:
196: bzero(&P->stats, sizeof(struct proto_stats));
197: bzero(&p->peer_stats, sizeof(struct proto_stats));
198:
199: P->main_ahook = NULL;
200: p->peer_ahook = NULL;
201:
202: if (p->mode == PIPE_OPAQUE)
203: rt_unlock_source(P->main_source);
204: P->main_source = NULL;
205:
206: rt_unlock_table(P->table);
207: rt_unlock_table(p->peer_table);
208: }
209:
210: static void
211: pipe_postconfig(struct proto_config *C)
212: {
213: struct pipe_config *c = (struct pipe_config *) C;
214:
215: if (!c->peer)
216: cf_error("Name of peer routing table not specified");
217: if (c->peer == C->table)
218: cf_error("Primary table and peer table must be different");
219:
220: if (C->in_keep_filtered)
221: cf_error("Pipe protocol prohibits keeping filtered routes");
222: if (C->rx_limit)
223: cf_error("Pipe protocol does not support receive limits");
224: }
225:
226: extern int proto_reconfig_type;
227:
228: static int
229: pipe_reconfigure(struct proto *P, struct proto_config *new)
230: {
231: struct pipe_proto *p = (struct pipe_proto *)P;
232: struct proto_config *old = P->cf;
233: struct pipe_config *oc = (struct pipe_config *) old;
234: struct pipe_config *nc = (struct pipe_config *) new;
235:
236: if ((oc->peer->table != nc->peer->table) || (oc->mode != nc->mode))
237: return 0;
238:
1.1.1.2 ! misho 239: int import_changed = ! filter_same(new->in_filter, old->in_filter);
! 240: int export_changed = ! filter_same(new->out_filter, old->out_filter);
! 241:
1.1 misho 242: /* Update output filters in ahooks */
243: if (P->main_ahook)
244: {
245: P->main_ahook->out_filter = new->out_filter;
246: P->main_ahook->in_limit = new->in_limit;
247: proto_verify_limits(P->main_ahook);
1.1.1.2 ! misho 248:
! 249: if (export_changed)
! 250: P->main_ahook->last_out_filter_change = now;
1.1 misho 251: }
252:
253: if (p->peer_ahook)
254: {
255: p->peer_ahook->out_filter = new->in_filter;
256: p->peer_ahook->in_limit = new->out_limit;
257: proto_verify_limits(p->peer_ahook);
1.1.1.2 ! misho 258:
! 259: if (import_changed)
! 260: p->peer_ahook->last_out_filter_change = now;
1.1 misho 261: }
262:
263: if ((P->proto_state != PS_UP) || (proto_reconfig_type == RECONFIG_SOFT))
264: return 1;
265:
1.1.1.2 ! misho 266: if (import_changed || export_changed || (new->preference != old->preference))
1.1 misho 267: proto_request_feeding(P);
268:
269: return 1;
270: }
271:
272: static void
273: pipe_copy_config(struct proto_config *dest, struct proto_config *src)
274: {
275: /* Just a shallow copy, not many items here */
276: proto_copy_rest(dest, src, sizeof(struct pipe_config));
277: }
278:
279: static void
280: pipe_get_status(struct proto *P, byte *buf)
281: {
282: struct pipe_proto *p = (struct pipe_proto *) P;
283:
284: bsprintf(buf, "%c> %s", (p->mode == PIPE_OPAQUE) ? '-' : '=', p->peer_table->name);
285: }
286:
287: static void
288: pipe_show_stats(struct pipe_proto *p)
289: {
290: struct proto_stats *s1 = &p->p.stats;
291: struct proto_stats *s2 = &p->peer_stats;
292:
293: /*
294: * Pipe stats (as anything related to pipes) are a bit tricky. There
295: * are two sets of stats - s1 for ahook to the primary routing and
296: * s2 for the ahook to the secondary routing table. The user point
297: * of view is that routes going from the primary routing table to
298: * the secondary routing table are 'exported', while routes going in
299: * the other direction are 'imported'.
300: *
301: * Each route going through a pipe is, technically, first exported
302: * to the pipe and then imported from that pipe and such operations
303: * are counted in one set of stats according to the direction of the
304: * route propagation. Filtering is done just in the first part
305: * (export). Therefore, we compose stats for one directon for one
306: * user direction from both import and export stats, skipping
307: * immediate and irrelevant steps (exp_updates_accepted,
308: * imp_updates_received, imp_updates_filtered, ...).
309: *
310: * Rule of thumb is that stats s1 have the correct 'polarity'
311: * (imp/exp), while stats s2 have switched 'polarity'.
312: */
313:
314: cli_msg(-1006, " Routes: %u imported, %u exported",
315: s1->imp_routes, s2->imp_routes);
316: cli_msg(-1006, " Route change stats: received rejected filtered ignored accepted");
317: cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u",
318: s2->exp_updates_received, s2->exp_updates_rejected + s1->imp_updates_invalid,
319: s2->exp_updates_filtered, s1->imp_updates_ignored, s1->imp_updates_accepted);
320: cli_msg(-1006, " Import withdraws: %10u %10u --- %10u %10u",
321: s2->exp_withdraws_received, s1->imp_withdraws_invalid,
322: s1->imp_withdraws_ignored, s1->imp_withdraws_accepted);
323: cli_msg(-1006, " Export updates: %10u %10u %10u %10u %10u",
324: s1->exp_updates_received, s1->exp_updates_rejected + s2->imp_updates_invalid,
325: s1->exp_updates_filtered, s2->imp_updates_ignored, s2->imp_updates_accepted);
326: cli_msg(-1006, " Export withdraws: %10u %10u --- %10u %10u",
327: s1->exp_withdraws_received, s2->imp_withdraws_invalid,
328: s2->imp_withdraws_ignored, s2->imp_withdraws_accepted);
329: }
330:
331: static void
332: pipe_show_proto_info(struct proto *P)
333: {
334: struct pipe_proto *p = (struct pipe_proto *) P;
335: struct pipe_config *cf = (struct pipe_config *) P->cf;
336:
337: // cli_msg(-1006, " Table: %s", P->table->name);
338: // cli_msg(-1006, " Peer table: %s", p->peer_table->name);
339: cli_msg(-1006, " Preference: %d", P->preference);
340: cli_msg(-1006, " Input filter: %s", filter_name(cf->c.in_filter));
341: cli_msg(-1006, " Output filter: %s", filter_name(cf->c.out_filter));
342:
343: proto_show_limit(cf->c.in_limit, "Import limit:");
344: proto_show_limit(cf->c.out_limit, "Export limit:");
345:
346: if (P->proto_state != PS_DOWN)
347: pipe_show_stats(p);
348: }
349:
350:
351: struct protocol proto_pipe = {
352: .name = "Pipe",
353: .template = "pipe%d",
354: .multitable = 1,
355: .preference = DEF_PREF_PIPE,
356: .config_size = sizeof(struct pipe_config),
357: .postconfig = pipe_postconfig,
358: .init = pipe_init,
359: .start = pipe_start,
360: .cleanup = pipe_cleanup,
361: .reconfigure = pipe_reconfigure,
362: .copy_config = pipe_copy_config,
363: .get_status = pipe_get_status,
364: .show_proto_info = pipe_show_proto_info
365: };
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>