]>
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 #include "proto/bgp/bgp.h"
51 pipe_rt_notify(struct proto
*P
, struct channel
*src_ch
, net
*n
, rte
*new, rte
*old
)
53 struct pipe_proto
*p
= (void *) P
;
54 struct channel
*dst
= (src_ch
== p
->pri
) ? p
->sec
: p
->pri
;
63 if (dst
->table
->pipe_busy
)
65 log(L_ERR
"Pipe loop detected when sending %N to table %s",
66 n
->n
.addr
, dst
->table
->name
);
74 a
= alloca(rta_size(new->attrs
));
75 memcpy(a
, new->attrs
, rta_size(new->attrs
));
79 e
= rte_get_temp(a
, src
);
80 e
->pflags
= new->pflags
;
83 /* Hack to cleanup cached value */
84 if (e
->src
->proto
->proto
== &proto_bgp
)
85 e
->pflags
&= ~(BGP_REF_STALE
| BGP_REF_NOT_STALE
);
94 src_ch
->table
->pipe_busy
= 1;
95 rte_update2(dst
, n
->n
.addr
, e
, src
);
96 src_ch
->table
->pipe_busy
= 0;
100 pipe_preexport(struct proto
*P
, rte
*e
)
102 struct proto
*pp
= e
->sender
->proto
;
105 return -1; /* Avoid local loops automatically */
111 pipe_reload_routes(struct channel
*C
)
113 struct pipe_proto
*p
= (void *) C
->proto
;
115 /* Route reload on one channel is just refeed on the other */
116 channel_request_feeding((C
== p
->pri
) ? p
->sec
: p
->pri
);
121 pipe_postconfig(struct proto_config
*CF
)
123 struct pipe_config
*cf
= (void *) CF
;
124 struct channel_config
*cc
= proto_cf_main_channel(CF
);
127 cf_error("Primary routing table not specified");
130 cf_error("Secondary routing table not specified");
132 if (cc
->table
== cf
->peer
)
133 cf_error("Primary table and peer table must be different");
135 if (cc
->table
->addr_type
!= cf
->peer
->addr_type
)
136 cf_error("Primary table and peer table must have the same type");
138 if (cc
->rx_limit
.action
)
139 cf_error("Pipe protocol does not support receive limits");
141 if (cc
->in_keep_filtered
)
142 cf_error("Pipe protocol prohibits keeping filtered routes");
144 cc
->debug
= cf
->c
.debug
;
148 pipe_configure_channels(struct pipe_proto
*p
, struct pipe_config
*cf
)
150 struct channel_config
*cc
= proto_cf_main_channel(&cf
->c
);
152 struct channel_config pri_cf
= {
154 .channel
= cc
->channel
,
156 .out_filter
= cc
->out_filter
,
157 .in_limit
= cc
->in_limit
,
160 .rpki_reload
= cc
->rpki_reload
,
163 struct channel_config sec_cf
= {
165 .channel
= cc
->channel
,
167 .out_filter
= cc
->in_filter
,
168 .in_limit
= cc
->out_limit
,
171 .rpki_reload
= cc
->rpki_reload
,
175 proto_configure_channel(&p
->p
, &p
->pri
, &pri_cf
) &&
176 proto_configure_channel(&p
->p
, &p
->sec
, &sec_cf
);
179 static struct proto
*
180 pipe_init(struct proto_config
*CF
)
182 struct proto
*P
= proto_new(CF
);
183 struct pipe_proto
*p
= (void *) P
;
184 struct pipe_config
*cf
= (void *) CF
;
186 P
->rt_notify
= pipe_rt_notify
;
187 P
->preexport
= pipe_preexport
;
188 P
->reload_routes
= pipe_reload_routes
;
190 pipe_configure_channels(p
, cf
);
196 pipe_reconfigure(struct proto
*P
, struct proto_config
*CF
)
198 struct pipe_proto
*p
= (void *) P
;
199 struct pipe_config
*cf
= (void *) CF
;
201 return pipe_configure_channels(p
, cf
);
205 pipe_copy_config(struct proto_config
*dest UNUSED
, struct proto_config
*src UNUSED
)
207 /* Just a shallow copy, not many items here */
211 pipe_get_status(struct proto
*P
, byte
*buf
)
213 struct pipe_proto
*p
= (void *) P
;
215 bsprintf(buf
, "%s <=> %s", p
->pri
->table
->name
, p
->sec
->table
->name
);
219 pipe_show_stats(struct pipe_proto
*p
)
221 struct proto_stats
*s1
= &p
->pri
->stats
;
222 struct proto_stats
*s2
= &p
->sec
->stats
;
225 * Pipe stats (as anything related to pipes) are a bit tricky. There
226 * are two sets of stats - s1 for ahook to the primary routing and
227 * s2 for the ahook to the secondary routing table. The user point
228 * of view is that routes going from the primary routing table to
229 * the secondary routing table are 'exported', while routes going in
230 * the other direction are 'imported'.
232 * Each route going through a pipe is, technically, first exported
233 * to the pipe and then imported from that pipe and such operations
234 * are counted in one set of stats according to the direction of the
235 * route propagation. Filtering is done just in the first part
236 * (export). Therefore, we compose stats for one directon for one
237 * user direction from both import and export stats, skipping
238 * immediate and irrelevant steps (exp_updates_accepted,
239 * imp_updates_received, imp_updates_filtered, ...).
241 * Rule of thumb is that stats s1 have the correct 'polarity'
242 * (imp/exp), while stats s2 have switched 'polarity'.
245 cli_msg(-1006, " Routes: %u imported, %u exported",
246 s1
->imp_routes
, s2
->imp_routes
);
247 cli_msg(-1006, " Route change stats: received rejected filtered ignored accepted");
248 cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u",
249 s2
->exp_updates_received
, s2
->exp_updates_rejected
+ s1
->imp_updates_invalid
,
250 s2
->exp_updates_filtered
, s1
->imp_updates_ignored
, s1
->imp_updates_accepted
);
251 cli_msg(-1006, " Import withdraws: %10u %10u --- %10u %10u",
252 s2
->exp_withdraws_received
, s1
->imp_withdraws_invalid
,
253 s1
->imp_withdraws_ignored
, s1
->imp_withdraws_accepted
);
254 cli_msg(-1006, " Export updates: %10u %10u %10u %10u %10u",
255 s1
->exp_updates_received
, s1
->exp_updates_rejected
+ s2
->imp_updates_invalid
,
256 s1
->exp_updates_filtered
, s2
->imp_updates_ignored
, s2
->imp_updates_accepted
);
257 cli_msg(-1006, " Export withdraws: %10u %10u --- %10u %10u",
258 s1
->exp_withdraws_received
, s2
->imp_withdraws_invalid
,
259 s2
->imp_withdraws_ignored
, s2
->imp_withdraws_accepted
);
262 static const char *pipe_feed_state
[] = { [ES_DOWN
] = "down", [ES_FEEDING
] = "feed", [ES_READY
] = "up" };
265 pipe_show_proto_info(struct proto
*P
)
267 struct pipe_proto
*p
= (void *) P
;
269 cli_msg(-1006, " Channel %s", "main");
270 cli_msg(-1006, " Table: %s", p
->pri
->table
->name
);
271 cli_msg(-1006, " Peer table: %s", p
->sec
->table
->name
);
272 cli_msg(-1006, " Import state: %s", pipe_feed_state
[p
->sec
->export_state
]);
273 cli_msg(-1006, " Export state: %s", pipe_feed_state
[p
->pri
->export_state
]);
274 cli_msg(-1006, " Import filter: %s", filter_name(p
->sec
->out_filter
));
275 cli_msg(-1006, " Export filter: %s", filter_name(p
->pri
->out_filter
));
277 channel_show_limit(&p
->pri
->in_limit
, "Import limit:");
278 channel_show_limit(&p
->sec
->in_limit
, "Export limit:");
280 if (P
->proto_state
!= PS_DOWN
)
285 pipe_update_debug(struct proto
*P
)
287 struct pipe_proto
*p
= (void *) P
;
289 p
->pri
->debug
= p
->sec
->debug
= p
->p
.debug
;
293 struct protocol proto_pipe
= {
295 .template = "pipe%d",
296 .class = PROTOCOL_PIPE
,
297 .proto_size
= sizeof(struct pipe_proto
),
298 .config_size
= sizeof(struct pipe_config
),
299 .postconfig
= pipe_postconfig
,
301 .reconfigure
= pipe_reconfigure
,
302 .copy_config
= pipe_copy_config
,
303 .get_status
= pipe_get_status
,
304 .show_proto_info
= pipe_show_proto_info
310 proto_build(&proto_pipe
);