Annotation of embedaddon/bird/nest/rt-roa.c, revision 1.1.1.2
1.1 misho 1: /*
2: * BIRD -- Route Origin Authorization
3: *
4: *
5: * Can be freely distributed and used under the terms of the GNU GPL.
6: */
7:
8: #undef LOCAL_DEBUG
9:
10: #include "nest/bird.h"
11: #include "nest/route.h"
12: #include "nest/cli.h"
13: #include "lib/lists.h"
14: #include "lib/resource.h"
15: #include "lib/event.h"
16: #include "lib/string.h"
17: #include "conf/conf.h"
18:
19:
20: pool *roa_pool;
21: static slab *roa_slab; /* Slab of struct roa_item */
22: static list roa_table_list; /* List of struct roa_table */
23: struct roa_table *roa_table_default; /* The first ROA table in the config */
24:
25: static inline int
26: src_match(struct roa_item *it, byte src)
27: { return !src || it->src == src; }
28:
29: /**
30: * roa_add_item - add a ROA entry
31: * @t: ROA table
32: * @prefix: prefix of the ROA entry
33: * @pxlen: prefix length of the ROA entry
34: * @maxlen: max length field of the ROA entry
35: * @asn: AS number field of the ROA entry
36: * @src: source of the ROA entry (ROA_SRC_*)
37: *
38: * The function adds a new ROA entry to the ROA table. If the same ROA
39: * is already in the table, nothing is added. @src field is used to
40: * distinguish different sources of ROAs.
41: */
42: void
43: roa_add_item(struct roa_table *t, ip_addr prefix, byte pxlen, byte maxlen, u32 asn, byte src)
44: {
45: struct roa_node *n = fib_get(&t->fib, &prefix, pxlen);
46:
47: // if ((n->items == NULL) && (n->n.x0 != ROA_INVALID))
48: // t->cached_items--;
49:
50: struct roa_item *it;
51: for (it = n->items; it; it = it->next)
52: if ((it->maxlen == maxlen) && (it->asn == asn) && src_match(it, src))
53: return;
54:
55: it = sl_alloc(roa_slab);
56: it->asn = asn;
57: it->maxlen = maxlen;
58: it->src = src;
59: it->next = n->items;
60: n->items = it;
61: }
62:
63: /**
64: * roa_delete_item - delete a ROA entry
65: * @t: ROA table
66: * @prefix: prefix of the ROA entry
67: * @pxlen: prefix length of the ROA entry
68: * @maxlen: max length field of the ROA entry
69: * @asn: AS number field of the ROA entry
70: * @src: source of the ROA entry (ROA_SRC_*)
71: *
72: * The function removes a specified ROA entry from the ROA table and
73: * frees it. If @src field is not ROA_SRC_ANY, only entries from
74: * that source are considered.
75: */
76: void
77: roa_delete_item(struct roa_table *t, ip_addr prefix, byte pxlen, byte maxlen, u32 asn, byte src)
78: {
79: struct roa_node *n = fib_find(&t->fib, &prefix, pxlen);
80:
81: if (!n)
82: return;
83:
84: struct roa_item *it, **itp;
85: for (itp = &n->items; it = *itp; itp = &it->next)
86: if ((it->maxlen == maxlen) && (it->asn == asn) && src_match(it, src))
87: break;
88:
89: if (!it)
90: return;
91:
92: *itp = it->next;
93: sl_free(roa_slab, it);
94:
95: // if ((n->items == NULL) && (n->n.x0 != ROA_INVALID))
96: // t->cached_items++;
97: }
98:
99:
100: /**
101: * roa_flush - flush a ROA table
102: * @t: ROA table
103: * @src: source of ROA entries (ROA_SRC_*)
104: *
105: * The function removes and frees ROA entries from the ROA table. If
106: * @src is ROA_SRC_ANY, all entries in the table are removed,
107: * otherwise only all entries from that source are removed.
108: */
109: void
110: roa_flush(struct roa_table *t, byte src)
111: {
112: struct roa_item *it, **itp;
113: struct roa_node *n;
114:
115: FIB_WALK(&t->fib, fn)
116: {
117: n = (struct roa_node *) fn;
118:
119: itp = &n->items;
120: while (it = *itp)
121: if (src_match(it, src))
122: {
123: *itp = it->next;
124: sl_free(roa_slab, it);
125: }
126: else
127: itp = &it->next;
128: }
129: FIB_WALK_END;
130:
131: // TODO add cleanup of roa_nodes
132: }
133:
134:
135:
136: /*
137: byte
138: roa_check(struct roa_table *t, ip_addr prefix, byte pxlen, u32 asn)
139: {
140: struct roa_node *n = fib_find(&t->fib, &prefix, pxlen);
141:
142: if (n && n->n.x0 == ROA_UNKNOWN)
143: return ROA_UNKNOWN;
144:
145: if (n && n->n.x0 == ROA_VALID && asn == n->cached_asn)
146: return ROA_VALID;
147:
148: byte rv = roa_match(t, n, prefix, pxlen, asn);
149:
150: if (rv != ROA_INVALID)
151: {
152: if (!n)
153: {
154: if (t->cached_items >= t->cached_items_max)
155: n = fib_get(&t->fib, &prefix, pxlen);
156: t->cached_items++;
157: }
158:
159: n->cached_asn = asn;
160: n->n.x0 = rv;
161: }
162:
163: return rv;
164: }
165: */
166:
167: /**
168: * roa_check - check validity of route origination in a ROA table
169: * @t: ROA table
170: * @prefix: network prefix to check
171: * @pxlen: length of network prefix
172: * @asn: AS number of network prefix
173: *
174: * Implements RFC 6483 route validation for the given network
175: * prefix. The procedure is to find all candidate ROAs - ROAs whose
176: * prefixes cover the give network prefix. If there is no candidate
177: * ROA, return ROA_UNKNOWN. If there is a candidate ROA with matching
178: * ASN and maxlen field greater than or equal to the given prefix
179: * length, return ROA_VALID. Otherwise return ROA_INVALID. If caller
180: * cannot determine origin AS, 0 could be used (in that case ROA_VALID
181: * cannot happen).
182: */
183: byte
184: roa_check(struct roa_table *t, ip_addr prefix, byte pxlen, u32 asn)
185: {
186: struct roa_node *n;
187: ip_addr px;
188: byte anything = 0;
189:
190: int len;
191: for (len = pxlen; len >= 0; len--)
192: {
193: px = ipa_and(prefix, ipa_mkmask(len));
194: n = fib_find(&t->fib, &px, len);
195:
196: if (!n)
197: continue;
198:
199: struct roa_item *it;
200: for (it = n->items; it; it = it->next)
201: {
202: anything = 1;
203: if ((it->maxlen >= pxlen) && (it->asn == asn) && asn)
204: return ROA_VALID;
205: }
206: }
207:
208: return anything ? ROA_INVALID : ROA_UNKNOWN;
209: }
210:
211: static void
212: roa_node_init(struct fib_node *fn)
213: {
214: struct roa_node *n = (struct roa_node *) fn;
215: n->items = NULL;
216: }
217:
218: static inline void
219: roa_populate(struct roa_table *t)
220: {
221: struct roa_item_config *ric;
222: for (ric = t->cf->roa_items; ric; ric = ric->next)
223: roa_add_item(t, ric->prefix, ric->pxlen, ric->maxlen, ric->asn, ROA_SRC_CONFIG);
224: }
225:
226: static void
227: roa_new_table(struct roa_table_config *cf)
228: {
229: struct roa_table *t;
230:
231: t = mb_allocz(roa_pool, sizeof(struct roa_table));
232: fib_init(&t->fib, roa_pool, sizeof(struct roa_node), 0, roa_node_init);
233: t->name = cf->name;
234: t->cf = cf;
235:
236: cf->table = t;
237: add_tail(&roa_table_list, &t->n);
238:
239: roa_populate(t);
240: }
241:
242: struct roa_table_config *
243: roa_new_table_config(struct symbol *s)
244: {
245: struct roa_table_config *rtc = cfg_allocz(sizeof(struct roa_table_config));
246:
247: cf_define_symbol(s, SYM_ROA, rtc);
248: rtc->name = s->name;
249: add_tail(&new_config->roa_tables, &rtc->n);
250: return rtc;
251: }
252:
253: /**
254: * roa_add_item_config - add a static ROA entry to a ROA table configuration
255: *
256: * Arguments are self-explanatory. The first is the ROA table config, rest
257: * are specifying the ROA entry.
258: */
259: void
260: roa_add_item_config(struct roa_table_config *rtc, ip_addr prefix, byte pxlen, byte maxlen, u32 asn)
261: {
262: struct roa_item_config *ric = cfg_allocz(sizeof(struct roa_item_config));
263:
264: ric->prefix = prefix;
265: ric->pxlen = pxlen;
266: ric->maxlen = maxlen;
267: ric->asn = asn;
268: ric->next = rtc->roa_items;
269: rtc->roa_items = ric;
270: }
271:
272: /**
273: * roa_init - initialize ROA tables
274: *
275: * This function is called during BIRD startup. It initializes
276: * the ROA table module.
277: */
278: void
279: roa_init(void)
280: {
281: roa_pool = rp_new(&root_pool, "ROA tables");
282: roa_slab = sl_new(roa_pool, sizeof(struct roa_item));
283: init_list(&roa_table_list);
284: }
285:
286: void
287: roa_preconfig(struct config *c)
288: {
289: init_list(&c->roa_tables);
290: }
291:
292:
293: /**
294: * roa_commit - commit new ROA table configuration
295: * @new: new configuration
296: * @old: original configuration or %NULL if it's boot time config
297: *
298: * Scan differences between @old and @new configuration and modify the
299: * ROA tables according to these changes. If @new defines a previously
300: * unknown table, create it, if it omits a table existing in @old,
301: * delete it (there are no references, only indirect through struct
302: * roa_table_config). If it exists in both configurations, update the
303: * configured ROA entries.
304: */
305: void
306: roa_commit(struct config *new, struct config *old)
307: {
308: struct roa_table_config *cf;
1.1.1.2 ! misho 309: struct roa_table *t, *tx;
1.1 misho 310:
311: if (old)
1.1.1.2 ! misho 312: WALK_LIST_DELSAFE(t, tx, roa_table_list)
1.1 misho 313: {
314: struct symbol *sym = cf_find_symbol(new, t->name);
315: if (sym && sym->class == SYM_ROA)
316: {
317: /* Found old table in new config */
318: cf = sym->def;
319: cf->table = t;
320: t->name = cf->name;
321: t->cf = cf;
322:
323: /* Reconfigure it */
324: roa_flush(t, ROA_SRC_CONFIG);
325: roa_populate(t);
326: }
327: else
328: {
329: t->cf->table = NULL;
330:
331: /* Free it now */
332: roa_flush(t, ROA_SRC_ANY);
333: rem_node(&t->n);
334: fib_free(&t->fib);
335: mb_free(t);
336: }
337: }
338:
339: /* Add new tables */
340: WALK_LIST(cf, new->roa_tables)
341: if (! cf->table)
342: roa_new_table(cf);
343:
344: roa_table_default = EMPTY_LIST(new->roa_tables) ? NULL :
345: ((struct roa_table_config *) HEAD(new->roa_tables))->table;
346: }
347:
348:
349:
350: static void
351: roa_show_node(struct cli *c, struct roa_node *rn, int len, u32 asn)
352: {
353: struct roa_item *ri;
354:
355: for (ri = rn->items; ri; ri = ri->next)
356: if ((ri->maxlen >= len) && (!asn || (ri->asn == asn)))
357: cli_printf(c, -1019, "%I/%d max %d as %u", rn->n.prefix, rn->n.pxlen, ri->maxlen, ri->asn);
358: }
359:
360: static void
361: roa_show_cont(struct cli *c)
362: {
363: struct roa_show_data *d = c->rover;
364: struct fib *fib = &d->table->fib;
365: struct fib_iterator *it = &d->fit;
366: struct roa_node *rn;
367: unsigned max = 32;
368:
369: FIB_ITERATE_START(fib, it, f)
370: {
371: rn = (struct roa_node *) f;
372:
373: if (!max--)
374: {
375: FIB_ITERATE_PUT(it, f);
376: return;
377: }
378:
379: if ((d->mode == ROA_SHOW_ALL) ||
380: net_in_net(rn->n.prefix, rn->n.pxlen, d->prefix, d->pxlen))
381: roa_show_node(c, rn, 0, d->asn);
382: }
383: FIB_ITERATE_END(f);
384:
385: cli_printf(c, 0, "");
386: c->cont = c->cleanup = NULL;
387: }
388:
389: static void
390: roa_show_cleanup(struct cli *c)
391: {
392: struct roa_show_data *d = c->rover;
393:
394: /* Unlink the iterator */
395: fit_get(&d->table->fib, &d->fit);
396: }
397:
398: void
399: roa_show(struct roa_show_data *d)
400: {
401: struct roa_node *rn;
402: ip_addr px;
403: int len;
404:
405: switch (d->mode)
406: {
407: case ROA_SHOW_ALL:
408: case ROA_SHOW_IN:
409: FIB_ITERATE_INIT(&d->fit, &d->table->fib);
410: this_cli->cont = roa_show_cont;
411: this_cli->cleanup = roa_show_cleanup;
412: this_cli->rover = d;
413: break;
414:
415: case ROA_SHOW_PX:
416: rn = fib_find(&d->table->fib, &d->prefix, d->pxlen);
417: if (rn)
418: {
419: roa_show_node(this_cli, rn, 0, d->asn);
420: cli_msg(0, "");
421: }
422: else
423: cli_msg(-8001, "Network not in table");
424: break;
425:
426: case ROA_SHOW_FOR:
427: for (len = d->pxlen; len >= 0; len--)
428: {
429: px = ipa_and(d->prefix, ipa_mkmask(len));
430: rn = fib_find(&d->table->fib, &px, len);
431:
432: if (!rn)
433: continue;
434:
435: roa_show_node(this_cli, rn, 0, d->asn);
436: }
437: cli_msg(0, "");
438: break;
439: }
440: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>