]>
git.ipfire.org Git - thirdparty/bird.git/blob - proto/pipe/pipe.c
2 * BIRD -- Table-to-Table Routing Protocol a.k.a Pipe
4 * (c) 1999--2000 Martin Mares <mj@ucw.cz>
6 * Can be freely distributed and used under the terms of the GNU GPL.
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()
17 * To avoid pipe loops, Pipe keeps a `being updated' flag in each routing
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.
35 #include "nest/bird.h"
36 #include "nest/iface.h"
37 #include "nest/protocol.h"
38 #include "nest/route.h"
40 #include "conf/conf.h"
41 #include "filter/filter.h"
42 #include "lib/string.h"
47 pipe_rt_notify(struct proto
*P
, rtable
*src_table
, net
*n
, rte
*new, rte
*old
, ea_list
*attrs
)
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
;
61 if (dst_table
->pipe_busy
)
63 log(L_ERR
"Pipe loop detected when sending %I/%d to table %s",
64 n
->n
.prefix
, n
->n
.pxlen
, dst_table
->name
);
68 nn
= net_get(dst_table
, n
->n
.prefix
, n
->n
.pxlen
);
71 memcpy(&a
, new->attrs
, sizeof(rta
));
73 if (p
->mode
== PIPE_OPAQUE
)
75 a
.src
= P
->main_source
;
86 if (p
->mode
== PIPE_TRANSPARENT
)
88 /* Copy protocol specific embedded attributes. */
89 memcpy(&(e
->u
), &(new->u
), sizeof(e
->u
));
91 e
->pflags
= new->pflags
;
99 src
= old
->attrs
->src
;
102 src_table
->pipe_busy
= 1;
103 rte_update2(ah
, nn
, e
, src
);
104 src_table
->pipe_busy
= 0;
108 pipe_import_control(struct proto
*P
, rte
**ee
, ea_list
**ea UNUSED
, struct linpool
*p UNUSED
)
110 struct proto
*pp
= (*ee
)->sender
->proto
;
113 return -1; /* Avoid local loops automatically */
118 pipe_reload_routes(struct proto
*P
)
120 struct pipe_proto
*p
= (struct pipe_proto
*) P
;
123 * Because the pipe protocol feeds routes from both routing tables
124 * together, both directions are reloaded during refeed and 'reload
125 * out' command works like 'reload' command. For symmetry, we also
126 * request refeed when 'reload in' command is used.
128 proto_request_feeding(P
);
130 proto_reset_limit(P
->main_ahook
->in_limit
);
131 proto_reset_limit(p
->peer_ahook
->in_limit
);
136 static struct proto
*
137 pipe_init(struct proto_config
*C
)
139 struct pipe_config
*c
= (struct pipe_config
*) C
;
140 struct proto
*P
= proto_new(C
, sizeof(struct pipe_proto
));
141 struct pipe_proto
*p
= (struct pipe_proto
*) P
;
144 p
->peer_table
= c
->peer
->table
;
145 P
->accept_ra_types
= (p
->mode
== PIPE_OPAQUE
) ? RA_OPTIMAL
: RA_ANY
;
146 P
->rt_notify
= pipe_rt_notify
;
147 P
->import_control
= pipe_import_control
;
148 P
->reload_routes
= pipe_reload_routes
;
154 pipe_start(struct proto
*P
)
156 struct pipe_config
*cf
= (struct pipe_config
*) P
->cf
;
157 struct pipe_proto
*p
= (struct pipe_proto
*) P
;
159 /* Lock both tables, unlock is handled in pipe_cleanup() */
160 rt_lock_table(P
->table
);
161 rt_lock_table(p
->peer_table
);
163 /* Going directly to PS_UP - prepare for feeding,
164 connect the protocol to both routing tables */
166 P
->main_ahook
= proto_add_announce_hook(P
, P
->table
, &P
->stats
);
167 P
->main_ahook
->out_filter
= cf
->c
.out_filter
;
168 P
->main_ahook
->in_limit
= cf
->c
.in_limit
;
169 proto_reset_limit(P
->main_ahook
->in_limit
);
171 p
->peer_ahook
= proto_add_announce_hook(P
, p
->peer_table
, &p
->peer_stats
);
172 p
->peer_ahook
->out_filter
= cf
->c
.in_filter
;
173 p
->peer_ahook
->in_limit
= cf
->c
.out_limit
;
174 proto_reset_limit(p
->peer_ahook
->in_limit
);
176 if (p
->mode
== PIPE_OPAQUE
)
178 P
->main_source
= rt_get_source(P
, 0);
179 rt_lock_source(P
->main_source
);
186 pipe_cleanup(struct proto
*P
)
188 struct pipe_proto
*p
= (struct pipe_proto
*) P
;
190 bzero(&P
->stats
, sizeof(struct proto_stats
));
191 bzero(&p
->peer_stats
, sizeof(struct proto_stats
));
193 P
->main_ahook
= NULL
;
194 p
->peer_ahook
= NULL
;
196 if (p
->mode
== PIPE_OPAQUE
)
197 rt_unlock_source(P
->main_source
);
198 P
->main_source
= NULL
;
200 rt_unlock_table(P
->table
);
201 rt_unlock_table(p
->peer_table
);
205 pipe_postconfig(struct proto_config
*C
)
207 struct pipe_config
*c
= (struct pipe_config
*) C
;
210 cf_error("Name of peer routing table not specified");
211 if (c
->peer
== C
->table
)
212 cf_error("Primary table and peer table must be different");
214 if (C
->in_keep_filtered
)
215 cf_error("Pipe protocol prohibits keeping filtered routes");
217 cf_error("Pipe protocol does not support receive limits");
220 extern int proto_reconfig_type
;
223 pipe_reconfigure(struct proto
*P
, struct proto_config
*new)
225 struct pipe_proto
*p
= (struct pipe_proto
*)P
;
226 struct proto_config
*old
= P
->cf
;
227 struct pipe_config
*oc
= (struct pipe_config
*) old
;
228 struct pipe_config
*nc
= (struct pipe_config
*) new;
230 if ((oc
->peer
->table
!= nc
->peer
->table
) || (oc
->mode
!= nc
->mode
))
233 int import_changed
= ! filter_same(new->in_filter
, old
->in_filter
);
234 int export_changed
= ! filter_same(new->out_filter
, old
->out_filter
);
236 /* Update output filters in ahooks */
239 P
->main_ahook
->out_filter
= new->out_filter
;
240 P
->main_ahook
->in_limit
= new->in_limit
;
241 proto_verify_limits(P
->main_ahook
);
244 P
->main_ahook
->last_out_filter_change
= now
;
249 p
->peer_ahook
->out_filter
= new->in_filter
;
250 p
->peer_ahook
->in_limit
= new->out_limit
;
251 proto_verify_limits(p
->peer_ahook
);
254 p
->peer_ahook
->last_out_filter_change
= now
;
257 if ((P
->proto_state
!= PS_UP
) || (proto_reconfig_type
== RECONFIG_SOFT
))
260 if (import_changed
|| export_changed
|| (new->preference
!= old
->preference
))
261 proto_request_feeding(P
);
267 pipe_copy_config(struct proto_config
*dest
, struct proto_config
*src
)
269 /* Just a shallow copy, not many items here */
270 proto_copy_rest(dest
, src
, sizeof(struct pipe_config
));
274 pipe_get_status(struct proto
*P
, byte
*buf
)
276 struct pipe_proto
*p
= (struct pipe_proto
*) P
;
278 bsprintf(buf
, "%c> %s", (p
->mode
== PIPE_OPAQUE
) ? '-' : '=', p
->peer_table
->name
);
282 pipe_show_stats(struct pipe_proto
*p
)
284 struct proto_stats
*s1
= &p
->p
.stats
;
285 struct proto_stats
*s2
= &p
->peer_stats
;
288 * Pipe stats (as anything related to pipes) are a bit tricky. There
289 * are two sets of stats - s1 for ahook to the primary routing and
290 * s2 for the ahook to the secondary routing table. The user point
291 * of view is that routes going from the primary routing table to
292 * the secondary routing table are 'exported', while routes going in
293 * the other direction are 'imported'.
295 * Each route going through a pipe is, technically, first exported
296 * to the pipe and then imported from that pipe and such operations
297 * are counted in one set of stats according to the direction of the
298 * route propagation. Filtering is done just in the first part
299 * (export). Therefore, we compose stats for one directon for one
300 * user direction from both import and export stats, skipping
301 * immediate and irrelevant steps (exp_updates_accepted,
302 * imp_updates_received, imp_updates_filtered, ...).
304 * Rule of thumb is that stats s1 have the correct 'polarity'
305 * (imp/exp), while stats s2 have switched 'polarity'.
308 cli_msg(-1006, " Routes: %u imported, %u exported",
309 s1
->imp_routes
, s2
->imp_routes
);
310 cli_msg(-1006, " Route change stats: received rejected filtered ignored accepted");
311 cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u",
312 s2
->exp_updates_received
, s2
->exp_updates_rejected
+ s1
->imp_updates_invalid
,
313 s2
->exp_updates_filtered
, s1
->imp_updates_ignored
, s1
->imp_updates_accepted
);
314 cli_msg(-1006, " Import withdraws: %10u %10u --- %10u %10u",
315 s2
->exp_withdraws_received
, s1
->imp_withdraws_invalid
,
316 s1
->imp_withdraws_ignored
, s1
->imp_withdraws_accepted
);
317 cli_msg(-1006, " Export updates: %10u %10u %10u %10u %10u",
318 s1
->exp_updates_received
, s1
->exp_updates_rejected
+ s2
->imp_updates_invalid
,
319 s1
->exp_updates_filtered
, s2
->imp_updates_ignored
, s2
->imp_updates_accepted
);
320 cli_msg(-1006, " Export withdraws: %10u %10u --- %10u %10u",
321 s1
->exp_withdraws_received
, s2
->imp_withdraws_invalid
,
322 s2
->imp_withdraws_ignored
, s2
->imp_withdraws_accepted
);
326 pipe_show_proto_info(struct proto
*P
)
328 struct pipe_proto
*p
= (struct pipe_proto
*) P
;
329 struct pipe_config
*cf
= (struct pipe_config
*) P
->cf
;
331 // cli_msg(-1006, " Table: %s", P->table->name);
332 // cli_msg(-1006, " Peer table: %s", p->peer_table->name);
333 cli_msg(-1006, " Preference: %d", P
->preference
);
334 cli_msg(-1006, " Input filter: %s", filter_name(cf
->c
.in_filter
));
335 cli_msg(-1006, " Output filter: %s", filter_name(cf
->c
.out_filter
));
337 proto_show_limit(cf
->c
.in_limit
, "Import limit:");
338 proto_show_limit(cf
->c
.out_limit
, "Export limit:");
340 if (P
->proto_state
!= PS_DOWN
)
345 struct protocol proto_pipe
= {
347 .template = "pipe%d",
349 .preference
= DEF_PREF_PIPE
,
350 .config_size
= sizeof(struct pipe_config
),
351 .postconfig
= pipe_postconfig
,
354 .cleanup
= pipe_cleanup
,
355 .reconfigure
= pipe_reconfigure
,
356 .copy_config
= pipe_copy_config
,
357 .get_status
= pipe_get_status
,
358 .show_proto_info
= pipe_show_proto_info