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
pipe_rt_notify(struct proto * P,struct channel * src_ch,net * n,rte * new,rte * old)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
pipe_preexport(struct proto * P,rte ** ee,struct linpool * p UNUSED)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
pipe_reload_routes(struct channel * C)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
pipe_postconfig(struct proto_config * CF)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   cc->debug = cf->c.debug;
146 }
147 
148 static int
pipe_configure_channels(struct pipe_proto * p,struct pipe_config * cf)149 pipe_configure_channels(struct pipe_proto *p, struct pipe_config *cf)
150 {
151   struct channel_config *cc = proto_cf_main_channel(&cf->c);
152 
153   struct channel_config pri_cf = {
154     .name = "pri",
155     .channel = cc->channel,
156     .table = cc->table,
157     .out_filter = cc->out_filter,
158     .in_limit = cc->in_limit,
159     .ra_mode = RA_ANY,
160     .debug = cc->debug,
161     .rpki_reload = cc->rpki_reload,
162   };
163 
164   struct channel_config sec_cf = {
165     .name = "sec",
166     .channel = cc->channel,
167     .table = cf->peer,
168     .out_filter = cc->in_filter,
169     .in_limit = cc->out_limit,
170     .ra_mode = RA_ANY,
171     .debug = cc->debug,
172     .rpki_reload = cc->rpki_reload,
173   };
174 
175   return
176     proto_configure_channel(&p->p, &p->pri, &pri_cf) &&
177     proto_configure_channel(&p->p, &p->sec, &sec_cf);
178 }
179 
180 static struct proto *
pipe_init(struct proto_config * CF)181 pipe_init(struct proto_config *CF)
182 {
183   struct proto *P = proto_new(CF);
184   struct pipe_proto *p = (void *) P;
185   struct pipe_config *cf = (void *) CF;
186 
187   P->rt_notify = pipe_rt_notify;
188   P->preexport = pipe_preexport;
189   P->reload_routes = pipe_reload_routes;
190 
191   pipe_configure_channels(p, cf);
192 
193   return P;
194 }
195 
196 static int
pipe_reconfigure(struct proto * P,struct proto_config * CF)197 pipe_reconfigure(struct proto *P, struct proto_config *CF)
198 {
199   struct pipe_proto *p = (void *) P;
200   struct pipe_config *cf = (void *) CF;
201 
202   return pipe_configure_channels(p, cf);
203 }
204 
205 static void
pipe_copy_config(struct proto_config * dest UNUSED,struct proto_config * src UNUSED)206 pipe_copy_config(struct proto_config *dest UNUSED, struct proto_config *src UNUSED)
207 {
208   /* Just a shallow copy, not many items here */
209 }
210 
211 static void
pipe_get_status(struct proto * P,byte * buf)212 pipe_get_status(struct proto *P, byte *buf)
213 {
214   struct pipe_proto *p = (void *) P;
215 
216   bsprintf(buf, "%s <=> %s", p->pri->table->name, p->sec->table->name);
217 }
218 
219 static void
pipe_show_stats(struct pipe_proto * p)220 pipe_show_stats(struct pipe_proto *p)
221 {
222   struct proto_stats *s1 = &p->pri->stats;
223   struct proto_stats *s2 = &p->sec->stats;
224 
225   /*
226    * Pipe stats (as anything related to pipes) are a bit tricky. There
227    * are two sets of stats - s1 for ahook to the primary routing and
228    * s2 for the ahook to the secondary routing table. The user point
229    * of view is that routes going from the primary routing table to
230    * the secondary routing table are 'exported', while routes going in
231    * the other direction are 'imported'.
232    *
233    * Each route going through a pipe is, technically, first exported
234    * to the pipe and then imported from that pipe and such operations
235    * are counted in one set of stats according to the direction of the
236    * route propagation. Filtering is done just in the first part
237    * (export). Therefore, we compose stats for one directon for one
238    * user direction from both import and export stats, skipping
239    * immediate and irrelevant steps (exp_updates_accepted,
240    * imp_updates_received, imp_updates_filtered, ...).
241    *
242    * Rule of thumb is that stats s1 have the correct 'polarity'
243    * (imp/exp), while stats s2 have switched 'polarity'.
244    */
245 
246   cli_msg(-1006, "  Routes:         %u imported, %u exported",
247 	  s1->imp_routes, s2->imp_routes);
248   cli_msg(-1006, "  Route change stats:     received   rejected   filtered    ignored   accepted");
249   cli_msg(-1006, "    Import updates:     %10u %10u %10u %10u %10u",
250 	  s2->exp_updates_received, s2->exp_updates_rejected + s1->imp_updates_invalid,
251 	  s2->exp_updates_filtered, s1->imp_updates_ignored, s1->imp_updates_accepted);
252   cli_msg(-1006, "    Import withdraws:   %10u %10u        --- %10u %10u",
253 	  s2->exp_withdraws_received, s1->imp_withdraws_invalid,
254 	  s1->imp_withdraws_ignored, s1->imp_withdraws_accepted);
255   cli_msg(-1006, "    Export updates:     %10u %10u %10u %10u %10u",
256 	  s1->exp_updates_received, s1->exp_updates_rejected + s2->imp_updates_invalid,
257 	  s1->exp_updates_filtered, s2->imp_updates_ignored, s2->imp_updates_accepted);
258   cli_msg(-1006, "    Export withdraws:   %10u %10u        --- %10u %10u",
259 	  s1->exp_withdraws_received, s2->imp_withdraws_invalid,
260 	  s2->imp_withdraws_ignored, s2->imp_withdraws_accepted);
261 }
262 
263 static const char *pipe_feed_state[] = { [ES_DOWN] = "down", [ES_FEEDING] = "feed", [ES_READY] = "up" };
264 
265 static void
pipe_show_proto_info(struct proto * P)266 pipe_show_proto_info(struct proto *P)
267 {
268   struct pipe_proto *p = (void *) P;
269 
270   cli_msg(-1006, "  Channel %s", "main");
271   cli_msg(-1006, "    Table:          %s", p->pri->table->name);
272   cli_msg(-1006, "    Peer table:     %s", p->sec->table->name);
273   cli_msg(-1006, "    Import state:   %s", pipe_feed_state[p->sec->export_state]);
274   cli_msg(-1006, "    Export state:   %s", pipe_feed_state[p->pri->export_state]);
275   cli_msg(-1006, "    Import filter:  %s", filter_name(p->sec->out_filter));
276   cli_msg(-1006, "    Export filter:  %s", filter_name(p->pri->out_filter));
277 
278   channel_show_limit(&p->pri->in_limit, "Import limit:");
279   channel_show_limit(&p->sec->in_limit, "Export limit:");
280 
281   if (P->proto_state != PS_DOWN)
282     pipe_show_stats(p);
283 }
284 
285 void
pipe_update_debug(struct proto * P)286 pipe_update_debug(struct proto *P)
287 {
288   struct pipe_proto *p = (void *) P;
289 
290   p->pri->debug = p->sec->debug = p->p.debug;
291 }
292 
293 
294 struct protocol proto_pipe = {
295   .name =		"Pipe",
296   .template =		"pipe%d",
297   .class =		PROTOCOL_PIPE,
298   .proto_size =		sizeof(struct pipe_proto),
299   .config_size =	sizeof(struct pipe_config),
300   .postconfig =		pipe_postconfig,
301   .init =		pipe_init,
302   .reconfigure =	pipe_reconfigure,
303   .copy_config = 	pipe_copy_config,
304   .get_status = 	pipe_get_status,
305   .show_proto_info = 	pipe_show_proto_info
306 };
307