]> git.ipfire.org Git - thirdparty/bird.git/blob - proto/pipe/pipe.c
Protocols have their own explicit init routines
[thirdparty/bird.git] / proto / pipe / pipe.c
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 #ifdef CONFIG_BGP
47 #include "proto/bgp/bgp.h"
48 #endif
49
50 static void
51 pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *old)
52 {
53 struct pipe_proto *p = (void *) P;
54 struct channel *dst = (src_ch == p->pri) ? p->sec : p->pri;
55 struct rte_src *src;
56
57 rte *e;
58 rta *a;
59
60 if (!new && !old)
61 return;
62
63 if (dst->table->pipe_busy)
64 {
65 log(L_ERR "Pipe loop detected when sending %N to table %s",
66 n->n.addr, dst->table->name);
67 return;
68 }
69
70 if (new)
71 {
72 src = new->src;
73
74 a = alloca(rta_size(new->attrs));
75 memcpy(a, new->attrs, rta_size(new->attrs));
76
77 a->cached = 0;
78 a->hostentry = NULL;
79 e = rte_get_temp(a, src);
80 e->pflags = new->pflags;
81
82 #ifdef CONFIG_BGP
83 /* Hack to cleanup cached value */
84 if (e->src->proto->proto == &proto_bgp)
85 e->pflags &= ~(BGP_REF_STALE | BGP_REF_NOT_STALE);
86 #endif
87 }
88 else
89 {
90 e = NULL;
91 src = old->src;
92 }
93
94 src_ch->table->pipe_busy = 1;
95 rte_update2(dst, n->n.addr, e, src);
96 src_ch->table->pipe_busy = 0;
97 }
98
99 static int
100 pipe_preexport(struct proto *P, rte *e)
101 {
102 struct proto *pp = e->sender->proto;
103
104 if (pp == P)
105 return -1; /* Avoid local loops automatically */
106
107 return 0;
108 }
109
110 static void
111 pipe_reload_routes(struct channel *C)
112 {
113 struct pipe_proto *p = (void *) C->proto;
114
115 /* Route reload on one channel is just refeed on the other */
116 channel_request_feeding((C == p->pri) ? p->sec : p->pri);
117 }
118
119
120 static void
121 pipe_postconfig(struct proto_config *CF)
122 {
123 struct pipe_config *cf = (void *) CF;
124 struct channel_config *cc = proto_cf_main_channel(CF);
125
126 if (!cc->table)
127 cf_error("Primary routing table not specified");
128
129 if (!cf->peer)
130 cf_error("Secondary routing table not specified");
131
132 if (cc->table == cf->peer)
133 cf_error("Primary table and peer table must be different");
134
135 if (cc->table->addr_type != cf->peer->addr_type)
136 cf_error("Primary table and peer table must have the same type");
137
138 if (cc->rx_limit.action)
139 cf_error("Pipe protocol does not support receive limits");
140
141 if (cc->in_keep_filtered)
142 cf_error("Pipe protocol prohibits keeping filtered routes");
143
144 cc->debug = cf->c.debug;
145 }
146
147 static int
148 pipe_configure_channels(struct pipe_proto *p, struct pipe_config *cf)
149 {
150 struct channel_config *cc = proto_cf_main_channel(&cf->c);
151
152 struct channel_config pri_cf = {
153 .name = "pri",
154 .channel = cc->channel,
155 .table = cc->table,
156 .out_filter = cc->out_filter,
157 .in_limit = cc->in_limit,
158 .ra_mode = RA_ANY,
159 .debug = cc->debug,
160 .rpki_reload = cc->rpki_reload,
161 };
162
163 struct channel_config sec_cf = {
164 .name = "sec",
165 .channel = cc->channel,
166 .table = cf->peer,
167 .out_filter = cc->in_filter,
168 .in_limit = cc->out_limit,
169 .ra_mode = RA_ANY,
170 .debug = cc->debug,
171 .rpki_reload = cc->rpki_reload,
172 };
173
174 return
175 proto_configure_channel(&p->p, &p->pri, &pri_cf) &&
176 proto_configure_channel(&p->p, &p->sec, &sec_cf);
177 }
178
179 static struct proto *
180 pipe_init(struct proto_config *CF)
181 {
182 struct proto *P = proto_new(CF);
183 struct pipe_proto *p = (void *) P;
184 struct pipe_config *cf = (void *) CF;
185
186 P->rt_notify = pipe_rt_notify;
187 P->preexport = pipe_preexport;
188 P->reload_routes = pipe_reload_routes;
189
190 pipe_configure_channels(p, cf);
191
192 return P;
193 }
194
195 static int
196 pipe_reconfigure(struct proto *P, struct proto_config *CF)
197 {
198 struct pipe_proto *p = (void *) P;
199 struct pipe_config *cf = (void *) CF;
200
201 return pipe_configure_channels(p, cf);
202 }
203
204 static void
205 pipe_copy_config(struct proto_config *dest UNUSED, struct proto_config *src UNUSED)
206 {
207 /* Just a shallow copy, not many items here */
208 }
209
210 static void
211 pipe_get_status(struct proto *P, byte *buf)
212 {
213 struct pipe_proto *p = (void *) P;
214
215 bsprintf(buf, "%s <=> %s", p->pri->table->name, p->sec->table->name);
216 }
217
218 static void
219 pipe_show_stats(struct pipe_proto *p)
220 {
221 struct proto_stats *s1 = &p->pri->stats;
222 struct proto_stats *s2 = &p->sec->stats;
223
224 /*
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'.
231 *
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, ...).
240 *
241 * Rule of thumb is that stats s1 have the correct 'polarity'
242 * (imp/exp), while stats s2 have switched 'polarity'.
243 */
244
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);
260 }
261
262 static const char *pipe_feed_state[] = { [ES_DOWN] = "down", [ES_FEEDING] = "feed", [ES_READY] = "up" };
263
264 static void
265 pipe_show_proto_info(struct proto *P)
266 {
267 struct pipe_proto *p = (void *) P;
268
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));
276
277 channel_show_limit(&p->pri->in_limit, "Import limit:");
278 channel_show_limit(&p->sec->in_limit, "Export limit:");
279
280 if (P->proto_state != PS_DOWN)
281 pipe_show_stats(p);
282 }
283
284 void
285 pipe_update_debug(struct proto *P)
286 {
287 struct pipe_proto *p = (void *) P;
288
289 p->pri->debug = p->sec->debug = p->p.debug;
290 }
291
292
293 struct protocol proto_pipe = {
294 .name = "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,
300 .init = pipe_init,
301 .reconfigure = pipe_reconfigure,
302 .copy_config = pipe_copy_config,
303 .get_status = pipe_get_status,
304 .show_proto_info = pipe_show_proto_info
305 };
306
307 void
308 pipe_build(void)
309 {
310 proto_build(&proto_pipe);
311 }