Statistics
| Branch: | Revision:

iof-bird-daemon / nest / rt-roa.c @ 9b9a7143

History | View | Annotate | Download (9.88 KB)

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;
309
  struct roa_table *t;
310

    
311
  if (old)
312
    WALK_LIST(t, roa_table_list)
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
}