Statistics
| Branch: | Revision:

iof-bird-daemon / sysdep / linux / krt-scan.c @ 08c69a77

History | View | Annotate | Download (6.69 KB)

1
/*
2
 *        BIRD -- Linux Routing Table Scanning
3
 *
4
 *        (c) 1998 Martin Mares <mj@ucw.cz>
5
 *
6
 *        Can be freely distributed and used under the terms of the GNU GPL.
7
 */
8

    
9
#include <string.h>
10
#include <stdio.h>
11
#include <ctype.h>
12
#include <fcntl.h>
13
#include <unistd.h>
14
#include <net/route.h>
15

    
16
#define LOCAL_DEBUG
17

    
18
#include "nest/bird.h"
19
#include "nest/route.h"
20
#include "nest/protocol.h"
21
#include "nest/iface.h"
22
#include "lib/timer.h"
23
#include "lib/unix.h"
24
#include "lib/krt.h"
25

    
26
#define SCANOPT struct krt_scan_params *p = &x->scanopt
27

    
28
static int krt_scan_fd = -1;
29

    
30
/* FIXME: Filtering */
31

    
32
struct iface *
33
krt_temp_iface(struct krt_proto *x, char *name)
34
{
35
  SCANOPT;
36
  struct iface *i;
37

    
38
  WALK_LIST(i, p->temp_ifs)
39
    if (!strcmp(i->name, name))
40
      return i;
41
  i = mb_alloc(x->p.pool, sizeof(struct iface));
42
  bzero(i, sizeof(*i));
43
  strcpy(i->name, name);
44
  add_tail(&p->temp_ifs, &i->n);
45
  return i;
46
}
47

    
48
static int
49
krt_uptodate(rte *k, rte *e)
50
{
51
  rta *ka = k->attrs, *ea = e->attrs;
52

    
53
  if (ka->dest != ea->dest)
54
    return 0;
55
  switch (ka->dest)
56
    {
57
    case RTD_ROUTER:
58
      return ipa_equal(ka->gw, ea->gw);
59
    case RTD_DEVICE:
60
      return !strcmp(ka->iface->name, ea->iface->name);
61
    default:
62
      return 1;
63
    }
64
}
65

    
66
static void
67
krt_parse_entry(byte *ent, struct krt_proto *p)
68
{
69
  u32 dest0, gw0, mask0;
70
  ip_addr dest, gw, mask;
71
  unsigned int flags, verdict;
72
  int masklen;
73
  net *net;
74
  byte *iface = ent;
75
  rta a;
76
  rte *e, *old;
77

    
78
  if (sscanf(ent, "%*s\t%x\t%x\t%x\t%*d\t%*d\t%*d\t%x\t", &dest0, &gw0, &flags, &mask0) != 4)
79
    {
80
      log(L_ERR "krt read: unable to parse `%s'", ent);
81
      return;
82
    }
83
  while (*ent != '\t')
84
    ent++;
85
  *ent = 0;
86

    
87
  dest = ipa_from_u32(dest0);
88
  ipa_ntoh(dest);
89
  gw = ipa_from_u32(gw0);
90
  ipa_ntoh(gw);
91
  mask = ipa_from_u32(mask0);
92
  ipa_ntoh(mask);
93
  if ((masklen = ipa_mklen(mask)) < 0)
94
    {
95
      log(L_ERR "krt read: invalid netmask %08x", mask0);
96
      return;
97
    }
98
  DBG("Got %I/%d via %I flags %x\n", dest, masklen, gw, flags);
99

    
100
  if (!(flags & RTF_UP))
101
    {
102
      DBG("Down.\n");
103
      return;
104
    }
105
  if (flags & RTF_HOST)
106
    masklen = 32;
107
  if (flags & (RTF_DYNAMIC | RTF_MODIFIED)) /* Redirect route */
108
    {
109
      log(L_WARN "krt: Ignoring redirect to %I/%d via %I", dest, masklen, gw);
110
      return;
111
    }
112

    
113
  net = net_get(&master_table, 0, dest, masklen);
114
  if (net->n.flags)
115
    {
116
      /* Route to this destination was already seen. Strange, but it happens... */
117
      DBG("Already seen.\n");
118
      return;
119
    }
120

    
121
  a.proto = &p->p;
122
  a.source = RTS_INHERIT;
123
  a.scope = SCOPE_UNIVERSE;
124
  a.cast = RTC_UNICAST;
125
  a.tos = a.flags = a.aflags = 0;
126
  a.from = IPA_NONE;
127
  a.iface = NULL;
128
  a.attrs = NULL;
129

    
130
  if (flags & RTF_GATEWAY)
131
    {
132
      neighbor *ng = neigh_find(&p->p, &gw, 0);
133
      if (ng)
134
        a.iface = ng->iface;
135
      else
136
        /* FIXME: Remove this warning? */
137
        log(L_WARN "Kernel told us to use non-neighbor %I for %I/%d", gw, net->n.prefix, net->n.pxlen);
138
      a.dest = RTD_ROUTER;
139
      a.gw = gw;
140
    }
141
  else if (flags & RTF_REJECT)
142
    {
143
      a.dest = RTD_UNREACHABLE;
144
      a.gw = IPA_NONE;
145
    }
146
  else if (isalpha(iface[0]))
147
    {
148
      a.dest = RTD_DEVICE;
149
      a.gw = IPA_NONE;
150
      a.iface = krt_temp_iface(p, iface);
151
    }
152
  else
153
    {
154
      log(L_WARN "Kernel reporting unknown route type to %I/%d", net->n.prefix, net->n.pxlen);
155
      return;
156
    }
157

    
158
  e = rte_get_temp(&a);
159
  e->net = net;
160
  old = net->routes;
161
  if (old && !krt_capable(old))
162
    old = NULL;
163
  if (old)
164
    {
165
      if (krt_uptodate(e, net->routes))
166
        verdict = KRF_SEEN;
167
      else
168
        verdict = KRF_UPDATE;
169
    }
170
  else if (p->scanopt.learn && !net->routes)
171
    verdict = KRF_LEARN;
172
  else
173
    verdict = KRF_DELETE;
174

    
175
  DBG("krt_parse_entry: verdict=%s\n", ((char *[]) { "CREATE", "SEEN", "UPDATE", "DELETE", "LEARN" }) [verdict]);
176

    
177
  net->n.flags = verdict;
178
  if (verdict != KRF_SEEN)
179
    {
180
      /* Get a cached copy of attributes and link the route */
181
      a.source = RTS_DUMMY;
182
      e->attrs = rta_lookup(&a);
183
      e->next = net->routes;
184
      net->routes = e;
185
    }
186
  else
187
    rte_free(e);
188
}
189

    
190
static int
191
krt_scan_proc(struct krt_proto *p)
192
{
193
  byte buf[32768];
194
  int l, seen_hdr;
195

    
196
  DBG("Scanning kernel routing table...\n");
197
  if (krt_scan_fd < 0)
198
    {
199
      krt_scan_fd = open("/proc/net/route", O_RDONLY);
200
      if (krt_scan_fd < 0)
201
        die("/proc/net/route: %m");
202
    }
203
  else if (lseek(krt_scan_fd, 0, SEEK_SET) < 0)
204
    {
205
      log(L_ERR "krt seek: %m");
206
      return 0;
207
    }
208
  seen_hdr = 0;
209
  while ((l = read(krt_scan_fd, buf, sizeof(buf))) > 0)
210
    {
211
      byte *z = buf;
212
      if (l & 127)
213
        {
214
          log(L_ERR "krt read: misaligned entry: l=%d", l);
215
          return 0;
216
        }
217
      while (l >= 128)
218
        {
219
          if (seen_hdr++)
220
            krt_parse_entry(z, p);
221
          z += 128;
222
          l -= 128;
223
        }
224
    }
225
  if (l < 0)
226
    {
227
      log(L_ERR "krt read: %m");
228
      return 0;
229
    }
230
  DBG("KRT scan done, seen %d lines\n", seen_hdr);
231
  return 1;
232
}
233

    
234
static void
235
krt_prune(struct krt_proto *p)
236
{
237
  struct rtable *t = &master_table;
238
  struct fib_node *f;
239

    
240
  DBG("Pruning routes...\n");
241
  while (t && t->tos)
242
    t = t->sibling;
243
  if (!t)
244
    return;
245
  FIB_WALK(&t->fib, f)
246
    {
247
      net *n = (net *) f;
248
      int verdict = f->flags;
249
      rte *new, *old;
250

    
251
      if (verdict != KRF_CREATE && verdict != KRF_SEEN)
252
        {
253
          old = n->routes;
254
          n->routes = old->next;
255
        }
256
      else
257
        old = NULL;
258
      new = n->routes;
259

    
260
      switch (verdict)
261
        {
262
        case KRF_CREATE:
263
          if (new)
264
            {
265
              if (new->attrs->source == RTS_INHERIT)
266
                {
267
                  DBG("krt_prune: removing inherited %I/%d\n", n->n.prefix, n->n.pxlen);
268
                  rte_update(n, &p->p, NULL);
269
                }
270
              else
271
                {
272
                  DBG("krt_prune: reinstalling %I/%d\n", n->n.prefix, n->n.pxlen);
273
                  krt_add_route(new);
274
                }
275
            }
276
          break;
277
        case KRF_SEEN:
278
          /* Nothing happens */
279
          break;
280
        case KRF_UPDATE:
281
          DBG("krt_prune: updating %I/%d\n", n->n.prefix, n->n.pxlen);
282
          krt_remove_route(old);
283
          krt_add_route(new);
284
          break;
285
        case KRF_DELETE:
286
          DBG("krt_prune: deleting %I/%d\n", n->n.prefix, n->n.pxlen);
287
          krt_remove_route(old);
288
          break;
289
        case KRF_LEARN:
290
          DBG("krt_prune: learning %I/%d\n", n->n.prefix, n->n.pxlen);
291
          rte_update(n, &p->p, new);
292
          break;
293
        default:
294
          bug("krt_prune: invalid route status");
295
        }
296

    
297
      if (old)
298
        rte_free(old);
299
      f->flags = 0;
300
    }
301
  FIB_WALK_END;
302
}
303

    
304
void
305
krt_scan_ifaces_done(struct krt_proto *x)
306
{
307
  SCANOPT;
308

    
309
  p->accum_time += x->ifopt.scan_time;
310
  if (p->scan_time && p->accum_time >= p->scan_time)
311
    {
312
      p->accum_time %= p->scan_time;
313
      if (krt_scan_proc(x))
314
        krt_prune(x);
315
    }
316
}
317

    
318
void
319
krt_scan_preconfig(struct krt_proto *x)
320
{
321
  SCANOPT;
322

    
323
  p->scan_time = 1;
324
  p->learn = 0;
325
  init_list(&p->temp_ifs);
326
}
327

    
328
void
329
krt_scan_start(struct krt_proto *x)
330
{
331
  SCANOPT;
332

    
333
  /* Force krt scan after first interface scan */
334
  p->accum_time = p->scan_time - x->ifopt.scan_time;
335
}
336

    
337
void
338
krt_scan_shutdown(struct krt_proto *x)
339
{
340
}