Statistics
| Branch: | Revision:

iof-bird-daemon / sysdep / bsd / krt-sock.c @ 153f02da

History | View | Annotate | Download (24.6 KB)

1 b1a1faba Ondrej Filip
/*
2 c01a9466 Ondrej Zajicek
 *        BIRD -- BSD Routing Table Syncing
3 b1a1faba Ondrej Filip
 *
4
 *        (c) 2004 Ondrej Filip <feela@network.cz>
5
 *
6
 *        Can be freely distributed and used under the terms of the GNU GPL.
7
 */
8
9
#include <stdio.h>
10 c01a9466 Ondrej Zajicek
#include <stdlib.h>
11 b1a1faba Ondrej Filip
#include <ctype.h>
12
#include <fcntl.h>
13
#include <unistd.h>
14
#include <sys/param.h>
15
#include <sys/types.h>
16
#include <sys/socket.h>
17
#include <sys/sysctl.h>
18
#include <sys/ioctl.h>
19
#include <netinet/in.h>
20
#include <net/route.h>
21
#include <net/if.h>
22
#include <net/if_dl.h>
23
24
#undef LOCAL_DEBUG
25
26
#include "nest/bird.h"
27
#include "nest/iface.h"
28
#include "nest/route.h"
29
#include "nest/protocol.h"
30
#include "nest/iface.h"
31 7152e5ef Jan Moskyto Matejka
#include "sysdep/unix/timer.h"
32
#include "sysdep/unix/unix.h"
33
#include "sysdep/unix/krt.h"
34 b1a1faba Ondrej Filip
#include "lib/string.h"
35
#include "lib/socket.h"
36
37 396dfa90 Ondrej Zajicek
38 c01a9466 Ondrej Zajicek
/*
39
 * There are significant differences in multiple tables support between BSD variants.
40
 *
41
 * OpenBSD has table_id field for routes in route socket protocol, therefore all
42
 * tables could be managed by one kernel socket. FreeBSD lacks such field,
43
 * therefore multiple sockets (locked to specific table using SO_SETFIB socket
44
 * option) must be used.
45
 *
46
 * Both FreeBSD and OpenBSD uses separate scans for each table. In OpenBSD,
47
 * table_id is specified explicitly as sysctl scan argument, while in FreeBSD it
48
 * is handled implicitly by changing default table using setfib() syscall.
49
 *
50
 * KRT_SHARED_SOCKET        - use shared kernel socked instead of one for each krt_proto
51
 * KRT_USE_SETFIB_SCAN        - use setfib() for sysctl() route scan
52
 * KRT_USE_SETFIB_SOCK        - use SO_SETFIB socket option for kernel sockets
53
 * KRT_USE_SYSCTL_7        - use 7-th arg of sysctl() as table id for route scans
54
 * KRT_USE_SYSCTL_NET_FIBS - use net.fibs sysctl() for dynamic max number of fibs
55
 */
56
57
#ifdef __FreeBSD__
58
#define KRT_MAX_TABLES 256
59
#define KRT_USE_SETFIB_SCAN
60
#define KRT_USE_SETFIB_SOCK
61
#define KRT_USE_SYSCTL_NET_FIBS
62 396dfa90 Ondrej Zajicek
#endif
63
64 c01a9466 Ondrej Zajicek
#ifdef __OpenBSD__
65
#define KRT_MAX_TABLES (RT_TABLEID_MAX+1)
66
#define KRT_SHARED_SOCKET
67
#define KRT_USE_SYSCTL_7
68
#endif
69
70
#ifndef KRT_MAX_TABLES
71
#define KRT_MAX_TABLES 1
72
#endif
73
74
75
/* Dynamic max number of tables */
76
77
int krt_max_tables;
78
79
#ifdef KRT_USE_SYSCTL_NET_FIBS
80
81
static int
82
krt_get_max_tables(void)
83 396dfa90 Ondrej Zajicek
{
84 c01a9466 Ondrej Zajicek
  int fibs;
85
  size_t fibs_len = sizeof(fibs);
86
87
  if (sysctlbyname("net.fibs", &fibs, &fibs_len, NULL, 0) < 0)
88
  {
89
    log(L_WARN "KRT: unable to get max number of fib tables: %m");
90
    return 1;
91
  }
92
93
  return MIN(fibs, KRT_MAX_TABLES);
94
}
95
96
#else
97
98
static int
99
krt_get_max_tables(void)
100
{
101
  return KRT_MAX_TABLES;
102
}
103
104
#endif /* KRT_USE_SYSCTL_NET_FIBS */
105
106
107
/* setfib() syscall for FreeBSD scans */
108
109
#ifdef KRT_USE_SETFIB_SCAN
110
111
/*
112
static int krt_default_fib;
113

114
static int
115
krt_get_active_fib(void)
116
{
117
  int fib;
118
  size_t fib_len = sizeof(fib);
119

120
  if (sysctlbyname("net.my_fibnum", &fib, &fib_len, NULL, 0) < 0)
121
  {
122
    log(L_WARN "KRT: unable to get active fib number: %m");
123
    return 0;
124
  }
125

126
  return fib;
127
}
128
*/
129
130
extern int setfib(int fib);
131 396dfa90 Ondrej Zajicek
132 c01a9466 Ondrej Zajicek
#endif /* KRT_USE_SETFIB_SCAN */
133 396dfa90 Ondrej Zajicek
134 c01a9466 Ondrej Zajicek
135
/* table_id -> krt_proto map */
136
137
#ifdef KRT_SHARED_SOCKET
138 8109eb76 Jan Moskyto Matejka
static struct krt_proto *krt_table_map[KRT_MAX_TABLES][2];
139 c01a9466 Ondrej Zajicek
#endif
140 396dfa90 Ondrej Zajicek
141
142 c01a9466 Ondrej Zajicek
/* Route socket message processing */
143 b1a1faba Ondrej Filip
144
int
145
krt_capable(rte *e)
146
{
147
  rta *a = e->attrs;
148
149 1d213067 Ondrej Zajicek (work)
  /* XXXX device routes are broken */
150 b1a1faba Ondrej Filip
  return
151 1d213067 Ondrej Zajicek (work)
    ((a->dest == RTD_UNICAST && ipa_nonzero(a->nh.gw) && !a->nh.next) /* No multipath support */
152 b1a1faba Ondrej Filip
#ifdef RTF_REJECT
153
     || a->dest == RTD_UNREACHABLE
154
#endif
155
#ifdef RTF_BLACKHOLE
156 ff2857b0 Ondrej Zajicek
     || a->dest == RTD_BLACKHOLE
157 b1a1faba Ondrej Filip
#endif
158
     );
159
}
160
161 c01a9466 Ondrej Zajicek
#ifndef RTAX_MAX
162
#define RTAX_MAX 8
163
#endif
164
165
struct ks_msg
166
{
167
  struct rt_msghdr rtm;
168
  struct sockaddr_storage buf[RTAX_MAX];
169
};
170
171 b1a1faba Ondrej Filip
#define ROUNDUP(a) \
172
        ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
173
174
#define NEXTADDR(w, u) \
175
        if (msg.rtm.rtm_addrs & (w)) {\
176
          l = ROUNDUP(((struct sockaddr *)&(u))->sa_len);\
177
          memmove(body, &(u), l); body += l;}
178
179 ff2857b0 Ondrej Zajicek
#define GETADDR(p, F) \
180
  bzero(p, sizeof(*p));\
181
  if ((addrs & (F)) && ((struct sockaddr *)body)->sa_len) {\
182 ae80a2de Pavel Tvrdík
    uint l = ROUNDUP(((struct sockaddr *)body)->sa_len);\
183 ff2857b0 Ondrej Zajicek
    memcpy(p, body, (l > sizeof(*p) ? sizeof(*p) : l));\
184
    body += l;}
185
186 32f95476 Ondrej Zajicek
static int
187 c01a9466 Ondrej Zajicek
krt_send_route(struct krt_proto *p, int cmd, rte *e)
188 b1a1faba Ondrej Filip
{
189
  net *net = e->net;
190
  rta *a = e->attrs;
191
  static int msg_seq;
192 4e276a89 Jan Moskyto Matejka
  struct iface *j, *i = a->nh.iface;
193 b1a1faba Ondrej Filip
  int l;
194
  struct ks_msg msg;
195
  char *body = (char *)msg.buf;
196
  sockaddr gate, mask, dst;
197
198 ff2857b0 Ondrej Zajicek
  DBG("krt-sock: send %I/%d via %I\n", net->n.prefix, net->n.pxlen, a->gw);
199 b1a1faba Ondrej Filip
200 b88a1d40 Ondrej Filip
  bzero(&msg,sizeof (struct rt_msghdr));
201 b1a1faba Ondrej Filip
  msg.rtm.rtm_version = RTM_VERSION;
202
  msg.rtm.rtm_type = cmd;
203
  msg.rtm.rtm_seq = msg_seq++;
204
  msg.rtm.rtm_addrs = RTA_DST;
205 ff2857b0 Ondrej Zajicek
  msg.rtm.rtm_flags = RTF_UP | RTF_PROTO1;
206 b1a1faba Ondrej Filip
207 d7661fbe Jan Moskyto Matejka
  /* XXXX */
208
  if (net_pxlen(net->n.addr) == net_max_prefix_length[net->n.addr->type])
209 b1a1faba Ondrej Filip
    msg.rtm.rtm_flags |= RTF_HOST;
210
  else
211
    msg.rtm.rtm_addrs |= RTA_NETMASK;
212 c01a9466 Ondrej Zajicek
213
#ifdef KRT_SHARED_SOCKET
214
  msg.rtm.rtm_tableid = KRT_CF->sys.table_id;
215
#endif
216 b1a1faba Ondrej Filip
217
#ifdef RTF_REJECT
218
  if(a->dest == RTD_UNREACHABLE)
219
    msg.rtm.rtm_flags |= RTF_REJECT;
220
#endif
221
#ifdef RTF_BLACKHOLE
222
  if(a->dest == RTD_BLACKHOLE)
223
    msg.rtm.rtm_flags |= RTF_BLACKHOLE;
224
#endif
225
226 62e64905 Ondrej Zajicek (work)
  /*
227
   * This is really very nasty, but I'm not able to add reject/blackhole route
228
   * without gateway address.
229 b1a1faba Ondrej Filip
   */
230 62e64905 Ondrej Zajicek (work)
  if (!i)
231 b1a1faba Ondrej Filip
  {
232 8281ff20 Ondrej Filip
    WALK_LIST(j, iface_list)
233
    {
234
      if (j->flags & IF_LOOPBACK)
235 b1a1faba Ondrej Filip
      {
236 8281ff20 Ondrej Filip
        i = j;
237
        break;
238 b1a1faba Ondrej Filip
      }
239
    }
240
241 62e64905 Ondrej Zajicek (work)
    if (!i)
242
    {
243
      log(L_ERR "KRT: Cannot find loopback iface");
244
      return -1;
245
    }
246
  }
247 44aa101c Ondrej Zajicek
248 9b136840 Jan Moskyto Matejka
  int af = AF_UNSPEC;
249
250
  switch (net->n.addr->type) {
251
    case NET_IP4:
252
      af = AF_INET;
253
      break;
254
    case NET_IP6:
255
      af = AF_INET6;
256
      break;
257
    default:
258 1d213067 Ondrej Zajicek (work)
      log(L_ERR "KRT: Not sending route %N to kernel", net->n.addr);
259 9b136840 Jan Moskyto Matejka
      return -1;
260
  }
261
262
  sockaddr_fill(&dst,  af, net_prefix(net->n.addr), NULL, 0);
263
  sockaddr_fill(&mask, af, net_pxmask(net->n.addr), NULL, 0);
264 44aa101c Ondrej Zajicek
265 b1a1faba Ondrej Filip
  switch (a->dest)
266
  {
267 62e64905 Ondrej Zajicek (work)
  case RTD_UNICAST:
268
    if (ipa_nonzero(a->nh.gw))
269
    {
270
      ip_addr gw = a->nh.gw;
271 4e276a89 Jan Moskyto Matejka
272 62e64905 Ondrej Zajicek (work)
      /* Embed interface ID to link-local address */
273
      if (ipa_is_link_local(gw))
274
        _I0(gw) = 0xfe800000 | (i->index & 0x0000ffff);
275
276
      sockaddr_fill(&gate, af, gw, NULL, 0);
277
      msg.rtm.rtm_flags |= RTF_GATEWAY;
278
      msg.rtm.rtm_addrs |= RTA_GATEWAY;
279 b1a1faba Ondrej Filip
      break;
280 62e64905 Ondrej Zajicek (work)
    }
281 029ec22d Ondrej Zajicek
282 b1a1faba Ondrej Filip
#ifdef RTF_REJECT
283 62e64905 Ondrej Zajicek (work)
  case RTD_UNREACHABLE:
284 b1a1faba Ondrej Filip
#endif
285
#ifdef RTF_BLACKHOLE
286 62e64905 Ondrej Zajicek (work)
  case RTD_BLACKHOLE:
287 b1a1faba Ondrej Filip
#endif
288 62e64905 Ondrej Zajicek (work)
  {
289
    /* Fallback for all other valid cases */
290
291
#ifdef RTF_CLONING
292
    if (cmd == RTM_ADD && (i->flags & IF_MULTIACCESS) != IF_MULTIACCESS)        /* PTP */
293
      msg.rtm.rtm_flags |= RTF_CLONING;
294
#endif
295
296 153f02da Ondrej Zajicek (work)
    struct ifa *addr = (net->n.addr->type == NET_IP4) ? i->addr4 : (i->addr6 ?: i->llv6);
297
298
    if (!addr)
299
    {
300
      log(L_ERR "KRT: interface %s has no IP addess", i->name);
301
      return -1;
302
    }
303
304
    sockaddr_fill(&gate, af, addr->ip, i, 0);
305 62e64905 Ondrej Zajicek (work)
    msg.rtm.rtm_addrs |= RTA_GATEWAY;
306 1d213067 Ondrej Zajicek (work)
    break;
307 62e64905 Ondrej Zajicek (work)
  }
308
309
  default:
310
    bug("krt-sock: unknown flags, but not filtered");
311 b1a1faba Ondrej Filip
  }
312
313 1554cc02 Ondrej Filip
  msg.rtm.rtm_index = i->index;
314 b1a1faba Ondrej Filip
315
  NEXTADDR(RTA_DST, dst);
316
  NEXTADDR(RTA_GATEWAY, gate);
317
  NEXTADDR(RTA_NETMASK, mask);
318
319
  l = body - (char *)&msg;
320
  msg.rtm.rtm_msglen = l;
321
322 c01a9466 Ondrej Zajicek
  if ((l = write(p->sys.sk->fd, (char *)&msg, l)) < 0) {
323 9b136840 Jan Moskyto Matejka
    log(L_ERR "KRT: Error sending route %N to kernel: %m", net->n.addr);
324 32f95476 Ondrej Zajicek
    return -1;
325 b1a1faba Ondrej Filip
  }
326 32f95476 Ondrej Zajicek
327
  return 0;
328 b1a1faba Ondrej Filip
}
329
330
void
331 c01a9466 Ondrej Zajicek
krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old,
332 7a2c48da Ondrej Zajicek
                struct ea_list *eattrs UNUSED)
333 b1a1faba Ondrej Filip
{
334 32f95476 Ondrej Zajicek
  int err = 0;
335
336 b1a1faba Ondrej Filip
  if (old)
337 c01a9466 Ondrej Zajicek
    krt_send_route(p, RTM_DELETE, old);
338 32f95476 Ondrej Zajicek
339 b1a1faba Ondrej Filip
  if (new)
340 c01a9466 Ondrej Zajicek
    err = krt_send_route(p, RTM_ADD, new);
341 32f95476 Ondrej Zajicek
342
  if (err < 0)
343
    n->n.flags |= KRF_SYNC_ERROR;
344
  else
345
    n->n.flags &= ~KRF_SYNC_ERROR;
346 b1a1faba Ondrej Filip
}
347
348 ff2857b0 Ondrej Zajicek
#define SKIP(ARG...) do { DBG("KRT: Ignoring route - " ARG); return; } while(0)
349
350 282997f2 Ondrej Filip
static void
351 c01a9466 Ondrej Zajicek
krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
352 b1a1faba Ondrej Filip
{
353 c01a9466 Ondrej Zajicek
  /* p is NULL iff KRT_SHARED_SOCKET and !scan */
354
355 3f358161 Jan Moskyto Matejka
  int ipv6;
356 b1a1faba Ondrej Filip
  rte *e;
357
  net *net;
358 ff2857b0 Ondrej Zajicek
  sockaddr dst, gate, mask;
359 b1a1faba Ondrej Filip
  ip_addr idst, igate, imask;
360 9b136840 Jan Moskyto Matejka
  net_addr ndst;
361 b1a1faba Ondrej Filip
  void *body = (char *)msg->buf;
362 90097f4f Ondrej Zajicek
  int new = (msg->rtm.rtm_type != RTM_DELETE);
363 ff2857b0 Ondrej Zajicek
  char *errmsg = "KRT: Invalid route received";
364 b1a1faba Ondrej Filip
  int flags = msg->rtm.rtm_flags;
365
  int addrs = msg->rtm.rtm_addrs;
366 72aed1a0 Ondrej Zajicek
  int src;
367
  byte src2;
368 b1a1faba Ondrej Filip
369 ff2857b0 Ondrej Zajicek
  if (!(flags & RTF_UP) && scan)
370
    SKIP("not up in scan\n");
371 b1a1faba Ondrej Filip
372 ff2857b0 Ondrej Zajicek
  if (!(flags & RTF_DONE) && !scan)
373
    SKIP("not done in async\n");
374 b1a1faba Ondrej Filip
375 ff2857b0 Ondrej Zajicek
  if (flags & RTF_LLINFO)
376
    SKIP("link-local\n");
377 b1a1faba Ondrej Filip
378 ff2857b0 Ondrej Zajicek
  GETADDR(&dst, RTA_DST);
379
  GETADDR(&gate, RTA_GATEWAY);
380
  GETADDR(&mask, RTA_NETMASK);
381 b1a1faba Ondrej Filip
382 d7661fbe Jan Moskyto Matejka
  switch (dst.sa.sa_family) {
383
    case AF_INET:
384 3f358161 Jan Moskyto Matejka
      ipv6 = 0;
385
      break;
386 8109eb76 Jan Moskyto Matejka
    case AF_INET6:
387 3f358161 Jan Moskyto Matejka
      ipv6 = 1;
388 8109eb76 Jan Moskyto Matejka
      break;
389 d7661fbe Jan Moskyto Matejka
    default:
390
      SKIP("invalid DST");
391
  }
392 b1a1faba Ondrej Filip
393 3f358161 Jan Moskyto Matejka
  /* We do not test family for RTA_NETMASK, because BSD sends us
394
     some strange values, but interpreting them as IPv4/IPv6 works */
395
  mask.sa.sa_family = dst.sa.sa_family;
396
397 05476c4d Ondrej Zajicek
  idst  = ipa_from_sa(&dst);
398 8109eb76 Jan Moskyto Matejka
  imask = ipa_from_sa(&mask);
399 d7661fbe Jan Moskyto Matejka
  igate = (gate.sa.sa_family == dst.sa.sa_family) ? ipa_from_sa(&gate) : IPA_NONE;
400 b1a1faba Ondrej Filip
401 8109eb76 Jan Moskyto Matejka
#ifdef KRT_SHARED_SOCKET
402
  if (!scan)
403
  {
404
    int table_id = msg->rtm.rtm_tableid;
405 3f358161 Jan Moskyto Matejka
    p = (table_id < KRT_MAX_TABLES) ? krt_table_map[table_id][ipv6] : NULL;
406 05476c4d Ondrej Zajicek
407 8109eb76 Jan Moskyto Matejka
    if (!p)
408
      SKIP("unknown table id %d\n", table_id);
409
  }
410
#endif
411 ade389b3 Jan Moskyto Matejka
  if ((!ipv6) && (p->p.main_channel->table->addr_type != NET_IP4))
412 3f358161 Jan Moskyto Matejka
    SKIP("reading only IPv4 routes");
413 ade389b3 Jan Moskyto Matejka
  if (  ipv6  && (p->p.main_channel->table->addr_type != NET_IP6))
414 3f358161 Jan Moskyto Matejka
    SKIP("reading only IPv6 routes");
415 b1a1faba Ondrej Filip
416 ff2857b0 Ondrej Zajicek
  int c = ipa_classify_net(idst);
417
  if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
418
    SKIP("strange class/scope\n");
419 b1a1faba Ondrej Filip
420 8109eb76 Jan Moskyto Matejka
  int pxlen;
421 3f358161 Jan Moskyto Matejka
  if (ipv6)
422 8109eb76 Jan Moskyto Matejka
    pxlen = (flags & RTF_HOST) ? IP6_MAX_PREFIX_LENGTH : ip6_masklen(&ipa_to_ip6(imask));
423 3f358161 Jan Moskyto Matejka
  else
424
    pxlen = (flags & RTF_HOST) ? IP4_MAX_PREFIX_LENGTH : ip4_masklen(ipa_to_ip4(imask));
425 8109eb76 Jan Moskyto Matejka
426 ff2857b0 Ondrej Zajicek
  if (pxlen < 0)
427
    { log(L_ERR "%s (%I) - netmask %I", errmsg, idst, imask); return; }
428 b1a1faba Ondrej Filip
429 3f358161 Jan Moskyto Matejka
  if (ipv6)
430
    net_fill_ip6(&ndst, ipa_to_ip6(idst), pxlen);
431
  else
432
    net_fill_ip4(&ndst, ipa_to_ip4(idst), pxlen);
433 9b136840 Jan Moskyto Matejka
434 ff2857b0 Ondrej Zajicek
  if ((flags & RTF_GATEWAY) && ipa_zero(igate))
435 9b136840 Jan Moskyto Matejka
    { log(L_ERR "%s (%N) - missing gateway", errmsg, ndst); return; }
436 ff2857b0 Ondrej Zajicek
437
  u32 self_mask = RTF_PROTO1;
438 a9f380fe Ondrej Zajicek
  u32 alien_mask = RTF_STATIC | RTF_PROTO1 | RTF_GATEWAY;
439 ff2857b0 Ondrej Zajicek
440 72aed1a0 Ondrej Zajicek
  src2 = (flags & RTF_STATIC) ? 1 : 0;
441
  src2 |= (flags & RTF_PROTO1) ? 2 : 0;
442
443 ff2857b0 Ondrej Zajicek
#ifdef RTF_PROTO2
444
  alien_mask |= RTF_PROTO2;
445 72aed1a0 Ondrej Zajicek
  src2 |= (flags & RTF_PROTO2) ? 4 : 0;
446 ff2857b0 Ondrej Zajicek
#endif
447 b1a1faba Ondrej Filip
448 ff2857b0 Ondrej Zajicek
#ifdef RTF_PROTO3
449
  alien_mask |= RTF_PROTO3;
450 72aed1a0 Ondrej Zajicek
  src2 |= (flags & RTF_PROTO3) ? 8 : 0;
451 ff2857b0 Ondrej Zajicek
#endif
452
453 a9f380fe Ondrej Zajicek
#ifdef RTF_REJECT
454
  alien_mask |= RTF_REJECT;
455
#endif
456
457
#ifdef RTF_BLACKHOLE
458
  alien_mask |= RTF_BLACKHOLE;
459
#endif
460
461 ff2857b0 Ondrej Zajicek
  if (flags & (RTF_DYNAMIC | RTF_MODIFIED))
462
    src = KRT_SRC_REDIRECT;
463
  else if (flags & self_mask)
464
    {
465
      if (!scan)
466
        SKIP("echo\n");
467
      src = KRT_SRC_BIRD;
468
    }
469
  else if (flags & alien_mask)
470
    src = KRT_SRC_ALIEN;
471
  else
472
    src = KRT_SRC_KERNEL;
473
474 ade389b3 Jan Moskyto Matejka
  net = net_get(p->p.main_channel->table, &ndst);
475 b1a1faba Ondrej Filip
476 cfe34a31 Ondrej Zajicek
  rta a = {
477 094d2bdb Ondrej Zajicek
    .src = p->p.main_source,
478 cfe34a31 Ondrej Zajicek
    .source = RTS_INHERIT,
479
    .scope = SCOPE_UNIVERSE,
480
  };
481 b1a1faba Ondrej Filip
482 ff2857b0 Ondrej Zajicek
  /* reject/blackhole routes have also set RTF_GATEWAY,
483
     we wil check them first. */
484 b1a1faba Ondrej Filip
485
#ifdef RTF_REJECT
486
  if(flags & RTF_REJECT) {
487
    a.dest = RTD_UNREACHABLE;
488 ff2857b0 Ondrej Zajicek
    goto done;
489 b1a1faba Ondrej Filip
  }
490
#endif
491
492
#ifdef RTF_BLACKHOLE
493
  if(flags & RTF_BLACKHOLE) {
494
    a.dest = RTD_BLACKHOLE;
495 ff2857b0 Ondrej Zajicek
    goto done;
496 b1a1faba Ondrej Filip
  }
497
#endif
498
499 4e276a89 Jan Moskyto Matejka
  a.nh.iface = if_find_by_index(msg->rtm.rtm_index);
500
  if (!a.nh.iface)
501 ff2857b0 Ondrej Zajicek
    {
502 9b136840 Jan Moskyto Matejka
      log(L_ERR "KRT: Received route %N with unknown ifindex %u",
503
          net->n.addr, msg->rtm.rtm_index);
504 ff2857b0 Ondrej Zajicek
      return;
505
    }
506
507 4e276a89 Jan Moskyto Matejka
  a.dest = RTD_UNICAST;
508 ff2857b0 Ondrej Zajicek
  if (flags & RTF_GATEWAY)
509 b1a1faba Ondrej Filip
  {
510 ff2857b0 Ondrej Zajicek
    neighbor *ng;
511 4e276a89 Jan Moskyto Matejka
    a.nh.gw = igate;
512 b1a1faba Ondrej Filip
513 44aa101c Ondrej Zajicek
    /* Clean up embedded interface ID returned in link-local address */
514 4e276a89 Jan Moskyto Matejka
    if (ipa_is_link_local(a.nh.gw))
515
      _I0(a.nh.gw) = 0xfe800000;
516 44aa101c Ondrej Zajicek
517 4e276a89 Jan Moskyto Matejka
    ng = neigh_find2(&p->p, &a.nh.gw, a.nh.iface, 0);
518 ff2857b0 Ondrej Zajicek
    if (!ng || (ng->scope == SCOPE_HOST))
519
      {
520 de14a7c7 Ondrej Zajicek
        /* Ignore routes with next-hop 127.0.0.1, host routes with such
521
           next-hop appear on OpenBSD for address aliases. */
522 4e276a89 Jan Moskyto Matejka
        if (ipa_classify(a.nh.gw) == (IADDR_HOST | SCOPE_HOST))
523 de14a7c7 Ondrej Zajicek
          return;
524
525 9b136840 Jan Moskyto Matejka
        log(L_ERR "KRT: Received route %N with strange next-hop %I",
526 4e276a89 Jan Moskyto Matejka
            net->n.addr, a.nh.gw);
527 ff2857b0 Ondrej Zajicek
        return;
528
      }
529
  }
530 b1a1faba Ondrej Filip
531 ff2857b0 Ondrej Zajicek
 done:
532 b1a1faba Ondrej Filip
  e = rte_get_temp(&a);
533
  e->net = net;
534
  e->u.krt.src = src;
535 72aed1a0 Ondrej Zajicek
  e->u.krt.proto = src2;
536 e86cfd41 Ondrej Zajicek (work)
  e->u.krt.seen = 0;
537
  e->u.krt.best = 0;
538 b1a1faba Ondrej Filip
  e->u.krt.metric = 0;
539
540
  if (scan)
541
    krt_got_route(p, e);
542
  else
543
    krt_got_route_async(p, e, new);
544
}
545
546 282997f2 Ondrej Filip
static void
547 09686693 Ondrej Zajicek
krt_read_ifannounce(struct ks_msg *msg)
548
{
549
  struct if_announcemsghdr *ifam = (struct if_announcemsghdr *)&msg->rtm;
550
551
  if (ifam->ifan_what == IFAN_ARRIVAL)
552
  {
553
    /* Not enough info to create the iface, so we just trigger iface scan */
554
    kif_request_scan();
555
  }
556
  else if (ifam->ifan_what == IFAN_DEPARTURE)
557
  {
558
    struct iface *iface = if_find_by_index(ifam->ifan_index);
559
560
    /* Interface is destroyed */
561
    if (!iface)
562
    {
563
      DBG("KRT: unknown interface (%s, #%d) going down. Ignoring\n", ifam->ifan_name, ifam->ifan_index);
564
      return;
565
    }
566
567
    if_delete(iface);
568
  }
569
570
  DBG("KRT: IFANNOUNCE what: %d index %d name %s\n", ifam->ifan_what, ifam->ifan_index, ifam->ifan_name);
571
}
572
573
static void
574 3216eb03 Ondrej Zajicek
krt_read_ifinfo(struct ks_msg *msg, int scan)
575 b1a1faba Ondrej Filip
{
576
  struct if_msghdr *ifm = (struct if_msghdr *)&msg->rtm;
577
  void *body = (void *)(ifm + 1);
578
  struct sockaddr_dl *dl = NULL;
579 ae80a2de Pavel Tvrdík
  uint i;
580 732a0a25 Ondrej Zajicek
  struct iface *iface = NULL, f = {};
581 b1a1faba Ondrej Filip
  int fl = ifm->ifm_flags;
582 732a0a25 Ondrej Zajicek
  int nlen = 0;
583 b1a1faba Ondrej Filip
584 d32a071d Ondrej Zajicek
  for (i = 1; i<=RTA_IFP; i <<= 1)
585 b1a1faba Ondrej Filip
  {
586 d32a071d Ondrej Zajicek
    if (i & ifm->ifm_addrs)
587 b1a1faba Ondrej Filip
    {
588 d32a071d Ondrej Zajicek
      if (i == RTA_IFP)
589 b1a1faba Ondrej Filip
      {
590
        dl = (struct sockaddr_dl *)body;
591
        break;
592
      }
593 d32a071d Ondrej Zajicek
      body += ROUNDUP(((struct sockaddr *)&(body))->sa_len);
594 b1a1faba Ondrej Filip
    }
595
  }
596
597 732a0a25 Ondrej Zajicek
  if (dl && (dl->sdl_family != AF_LINK))
598 b1a1faba Ondrej Filip
  {
599 09686693 Ondrej Zajicek
    log(L_WARN "Ignoring strange IFINFO");
600 b1a1faba Ondrej Filip
    return;
601
  }
602
603 732a0a25 Ondrej Zajicek
  if (dl)
604
    nlen = MIN(sizeof(f.name)-1, dl->sdl_nlen);
605
606
  /* Note that asynchronous IFINFO messages do not contain iface
607
     name, so we have to found an existing iface by iface index */
608 b1a1faba Ondrej Filip
609 732a0a25 Ondrej Zajicek
  iface = if_find_by_index(ifm->ifm_index);
610
  if (!iface)
611 b1a1faba Ondrej Filip
  {
612
    /* New interface */
613 732a0a25 Ondrej Zajicek
    if (!dl)
614
      return;        /* No interface name, ignoring */
615 dad7ee70 Ondrej Zajicek
616 732a0a25 Ondrej Zajicek
    memcpy(f.name, dl->sdl_data, nlen);
617
    DBG("New interface '%s' found\n", f.name);
618
  }
619
  else if (dl && memcmp(iface->name, dl->sdl_data, nlen))
620
  {
621
    /* Interface renamed */
622
    if_delete(iface);
623
    memcpy(f.name, dl->sdl_data, nlen);
624 b1a1faba Ondrej Filip
  }
625
  else
626
  {
627 732a0a25 Ondrej Zajicek
    /* Old interface */
628
    memcpy(f.name, iface->name, sizeof(f.name));
629 b1a1faba Ondrej Filip
  }
630
631 732a0a25 Ondrej Zajicek
  f.index = ifm->ifm_index;
632 b1a1faba Ondrej Filip
  f.mtu = ifm->ifm_data.ifi_mtu;
633
634
  if (fl & IFF_UP)
635 f25cb0ef Ondrej Zajicek
    f.flags |= IF_ADMIN_UP;
636
  if (ifm->ifm_data.ifi_link_state != LINK_STATE_DOWN)
637
    f.flags |= IF_LINK_UP;          /* up or unknown */
638 b1a1faba Ondrej Filip
  if (fl & IFF_LOOPBACK)            /* Loopback */
639
    f.flags |= IF_MULTIACCESS | IF_LOOPBACK | IF_IGNORE;
640
  else if (fl & IFF_POINTOPOINT)    /* PtP */
641
    f.flags |= IF_MULTICAST;
642
  else if (fl & IFF_BROADCAST)      /* Broadcast */
643
    f.flags |= IF_MULTIACCESS | IF_BROADCAST | IF_MULTICAST;
644
  else
645
    f.flags |= IF_MULTIACCESS;      /* NBMA */
646
647 3216eb03 Ondrej Zajicek
  iface = if_update(&f);
648
649
  if (!scan)
650
    if_end_partial_update(iface);
651 b1a1faba Ondrej Filip
}
652
653 282997f2 Ondrej Filip
static void
654 3216eb03 Ondrej Zajicek
krt_read_addr(struct ks_msg *msg, int scan)
655 b1a1faba Ondrej Filip
{
656
  struct ifa_msghdr *ifam = (struct ifa_msghdr *)&msg->rtm;
657
  void *body = (void *)(ifam + 1);
658
  sockaddr addr, mask, brd;
659
  struct iface *iface = NULL;
660
  struct ifa ifa;
661
  struct sockaddr null;
662
  ip_addr iaddr, imask, ibrd;
663
  int addrs = ifam->ifam_addrs;
664
  int scope, masklen = -1;
665
  int new = (ifam->ifam_type == RTM_NEWADDR);
666
667 ff2857b0 Ondrej Zajicek
  /* Strange messages with zero (invalid) ifindex appear on OpenBSD */
668
  if (ifam->ifam_index == 0)
669
    return;
670
671 b1a1faba Ondrej Filip
  if(!(iface = if_find_by_index(ifam->ifam_index)))
672
  {
673
    log(L_ERR "KIF: Received address message for unknown interface %d", ifam->ifam_index);
674
    return;
675
  }
676
677
  GETADDR (&null, RTA_DST);
678
  GETADDR (&null, RTA_GATEWAY);
679
  GETADDR (&mask, RTA_NETMASK);
680
  GETADDR (&null, RTA_GENMASK);
681
  GETADDR (&null, RTA_IFP);
682
  GETADDR (&addr, RTA_IFA);
683
  GETADDR (&null, RTA_AUTHOR);
684
  GETADDR (&brd, RTA_BRD);
685
686 d7661fbe Jan Moskyto Matejka
  /* Is addr family IP4 or IP6? */
687
  int ipv6;
688
  switch (addr.sa.sa_family) {
689
    case AF_INET: ipv6 = 0; break;
690
    case AF_INET6: ipv6 = 1; break;
691
    default: return;
692
  }
693 b1a1faba Ondrej Filip
694 b644a490 Ondrej Zajicek (work)
  /* We do not test family for RTA_NETMASK, because BSD sends us
695
     some strange values, but interpreting them as IPv4/IPv6 works */
696
  mask.sa.sa_family = addr.sa.sa_family;
697
698 05476c4d Ondrej Zajicek
  iaddr = ipa_from_sa(&addr);
699
  imask = ipa_from_sa(&mask);
700
  ibrd  = ipa_from_sa(&brd);
701
702 8109eb76 Jan Moskyto Matejka
  if ((ipv6 ? (masklen = ip6_masklen(&ipa_to_ip6(imask))) : (masklen = ip4_masklen(ipa_to_ip4(imask)))) < 0)
703 b1a1faba Ondrej Filip
  {
704 8109eb76 Jan Moskyto Matejka
    log(L_ERR "KIF: Invalid mask %I for %s", imask, iface->name);
705 b1a1faba Ondrej Filip
    return;
706
  }
707
708 64534ea2 Ondrej Zajicek
  /* Clean up embedded interface ID returned in link-local address */
709 b1a1faba Ondrej Filip
710 304ac2e8 Ondrej Zajicek
  if (ipa_is_link_local(iaddr))
711 64534ea2 Ondrej Zajicek
    _I0(iaddr) = 0xfe800000;
712 b1a1faba Ondrej Filip
713 304ac2e8 Ondrej Zajicek
  if (ipa_is_link_local(ibrd))
714 64534ea2 Ondrej Zajicek
    _I0(ibrd) = 0xfe800000;
715 b1a1faba Ondrej Filip
716
717 64534ea2 Ondrej Zajicek
  bzero(&ifa, sizeof(ifa));
718
  ifa.iface = iface;
719
  ifa.ip = iaddr;
720 b1a1faba Ondrej Filip
721
  scope = ipa_classify(ifa.ip);
722
  if (scope < 0)
723
  {
724
    log(L_ERR "KIF: Invalid interface address %I for %s", ifa.ip, iface->name);
725
    return;
726
  }
727
  ifa.scope = scope & IADDR_SCOPE_MASK;
728
729 d7661fbe Jan Moskyto Matejka
  if (masklen < (ipv6 ? IP6_MAX_PREFIX_LENGTH : IP4_MAX_PREFIX_LENGTH))
730 ba321706 Ondrej Zajicek
  {
731 9b136840 Jan Moskyto Matejka
    net_fill_ipa(&ifa.prefix, ifa.ip, masklen);
732
    net_normalize(&ifa.prefix);
733 ba321706 Ondrej Zajicek
734 d7661fbe Jan Moskyto Matejka
    if (masklen == ((ipv6 ? IP6_MAX_PREFIX_LENGTH : IP4_MAX_PREFIX_LENGTH) - 1))
735 ba321706 Ondrej Zajicek
      ifa.opposite = ipa_opposite_m1(ifa.ip);
736
737 8109eb76 Jan Moskyto Matejka
    if ((!ipv6) && (masklen == IP4_MAX_PREFIX_LENGTH - 2))
738 ba321706 Ondrej Zajicek
      ifa.opposite = ipa_opposite_m2(ifa.ip);
739 f515e229 Ondrej Zajicek
740 64534ea2 Ondrej Zajicek
    if (iface->flags & IF_BROADCAST)
741
      ifa.brd = ibrd;
742
743 f515e229 Ondrej Zajicek
    if (!(iface->flags & IF_MULTIACCESS))
744 64534ea2 Ondrej Zajicek
      ifa.opposite = ibrd;
745 ba321706 Ondrej Zajicek
  }
746 64534ea2 Ondrej Zajicek
  else if (!(iface->flags & IF_MULTIACCESS) && ipa_nonzero(ibrd))
747 afa9f66c Ondrej Zajicek
  {
748 d7661fbe Jan Moskyto Matejka
    net_fill_ipa(&ifa.prefix, ibrd, (ipv6 ? IP6_MAX_PREFIX_LENGTH : IP4_MAX_PREFIX_LENGTH));
749 9b136840 Jan Moskyto Matejka
    ifa.opposite = ibrd;
750 52a43ae3 Ondrej Zajicek
    ifa.flags |= IA_PEER;
751 f515e229 Ondrej Zajicek
  }
752
  else
753
  {
754 d7661fbe Jan Moskyto Matejka
    net_fill_ipa(&ifa.prefix, ifa.ip, (ipv6 ? IP6_MAX_PREFIX_LENGTH : IP4_MAX_PREFIX_LENGTH));
755 f515e229 Ondrej Zajicek
    ifa.flags |= IA_HOST;
756 afa9f66c Ondrej Zajicek
  }
757
758 b1a1faba Ondrej Filip
  if (new)
759
    ifa_update(&ifa);
760
  else
761
    ifa_delete(&ifa);
762 3216eb03 Ondrej Zajicek
763
  if (!scan)
764
    if_end_partial_update(iface);
765 b1a1faba Ondrej Filip
}
766
767 c01a9466 Ondrej Zajicek
static void
768 b1a1faba Ondrej Filip
krt_read_msg(struct proto *p, struct ks_msg *msg, int scan)
769
{
770 c01a9466 Ondrej Zajicek
  /* p is NULL iff KRT_SHARED_SOCKET and !scan */
771
772 b1a1faba Ondrej Filip
  switch (msg->rtm.rtm_type)
773
  {
774
    case RTM_GET:
775
      if(!scan) return;
776
    case RTM_ADD:
777
    case RTM_DELETE:
778 90097f4f Ondrej Zajicek
    case RTM_CHANGE:
779 c01a9466 Ondrej Zajicek
      krt_read_route(msg, (struct krt_proto *)p, scan);
780 b1a1faba Ondrej Filip
      break;
781 09686693 Ondrej Zajicek
    case RTM_IFANNOUNCE:
782
      krt_read_ifannounce(msg);
783
      break;
784 b1a1faba Ondrej Filip
    case RTM_IFINFO:
785 3216eb03 Ondrej Zajicek
      krt_read_ifinfo(msg, scan);
786 b1a1faba Ondrej Filip
      break;
787
    case RTM_NEWADDR:
788
    case RTM_DELADDR:
789 3216eb03 Ondrej Zajicek
      krt_read_addr(msg, scan);
790 b1a1faba Ondrej Filip
      break;
791
    default:
792
      break;
793
  }
794
}
795
796 c01a9466 Ondrej Zajicek
797
/* Sysctl based scans */
798
799
static byte *krt_buffer;
800
static size_t krt_buflen, krt_bufmin;
801
static struct proto *krt_buffer_owner;
802
803
static byte *
804
krt_buffer_update(struct proto *p, size_t *needed)
805
{
806
  size_t req = *needed;
807
808
  if ((req > krt_buflen) ||
809
      ((p == krt_buffer_owner) && (req < krt_bufmin)))
810
  {
811
    /* min buflen is 32 kB, step is 8 kB, or 128 kB if > 1 MB */
812
    size_t step = (req < 0x100000) ? 0x2000 : 0x20000;
813
    krt_buflen = (req < 0x6000) ? 0x8000 : (req + step);
814
    krt_bufmin = (req < 0x8000) ? 0 : (req - 2*step);
815
816
    if (krt_buffer) 
817
      mb_free(krt_buffer);
818
    krt_buffer = mb_alloc(krt_pool, krt_buflen);
819
    krt_buffer_owner = p;
820
  }
821
822
  *needed = krt_buflen;
823
  return krt_buffer;
824
}
825
826 282997f2 Ondrej Filip
static void
827 c01a9466 Ondrej Zajicek
krt_buffer_release(struct proto *p)
828 b1a1faba Ondrej Filip
{
829 c01a9466 Ondrej Zajicek
  if (p == krt_buffer_owner)
830
  {
831
    mb_free(krt_buffer);
832
    krt_buffer = NULL;
833
    krt_buflen = 0;
834
    krt_buffer_owner = 0;
835
  }
836
}
837
838 282997f2 Ondrej Filip
static void
839 c01a9466 Ondrej Zajicek
krt_sysctl_scan(struct proto *p, int cmd, int table_id)
840 b1a1faba Ondrej Filip
{
841 c01a9466 Ondrej Zajicek
  byte *buf, *next;
842
  int mib[7], mcnt;
843
  size_t needed;
844 b1a1faba Ondrej Filip
  struct ks_msg *m;
845 4aef102b Ondrej Zajicek
  int retries = 3;
846 c01a9466 Ondrej Zajicek
  int rv;
847 b1a1faba Ondrej Filip
848
  mib[0] = CTL_NET;
849
  mib[1] = PF_ROUTE;
850
  mib[2] = 0;
851 8109eb76 Jan Moskyto Matejka
  mib[3] = 0; // Set AF to 0 for all available families
852 b1a1faba Ondrej Filip
  mib[4] = cmd;
853
  mib[5] = 0;
854 c01a9466 Ondrej Zajicek
  mcnt = 6;
855 b1a1faba Ondrej Filip
856 c01a9466 Ondrej Zajicek
#ifdef KRT_USE_SYSCTL_7
857
  if (table_id >= 0)
858
  {
859
    mib[6] = table_id;
860
    mcnt = 7;
861
  }
862
#endif
863 b1a1faba Ondrej Filip
864 c01a9466 Ondrej Zajicek
#ifdef KRT_USE_SETFIB_SCAN
865
  if (table_id > 0)
866
    if (setfib(table_id) < 0)
867
    {
868
      log(L_ERR "KRT: setfib(%d) failed: %m", table_id);
869
      return;
870
    }
871
#endif
872 b1a1faba Ondrej Filip
873 c01a9466 Ondrej Zajicek
 try:
874
  rv = sysctl(mib, mcnt, NULL, &needed, NULL, 0);
875
  if (rv < 0)
876 b1a1faba Ondrej Filip
  {
877 c01a9466 Ondrej Zajicek
    /* OpenBSD returns EINVAL for not yet used tables */
878
    if ((errno == EINVAL) && (table_id > 0))
879
      goto exit;
880
881
    log(L_ERR "KRT: Route scan estimate failed: %m");
882
    goto exit;
883 b1a1faba Ondrej Filip
  }
884
885 c01a9466 Ondrej Zajicek
  /* The table is empty */
886
  if (needed == 0)
887
    goto exit;
888
889
  buf = krt_buffer_update(p, &needed);
890
891
  rv = sysctl(mib, mcnt, buf, &needed, NULL, 0);
892
  if (rv < 0)
893 b1a1faba Ondrej Filip
  {
894 c01a9466 Ondrej Zajicek
    /* The buffer size changed since last sysctl ('needed' is not changed) */
895
    if ((errno == ENOMEM) && retries--)
896
      goto try;
897 4aef102b Ondrej Zajicek
898 c01a9466 Ondrej Zajicek
    log(L_ERR "KRT: Route scan failed: %m");
899
    goto exit;
900 b1a1faba Ondrej Filip
  }
901
902 c01a9466 Ondrej Zajicek
#ifdef KRT_USE_SETFIB_SCAN
903
  if (table_id > 0)
904
    if (setfib(0) < 0)
905
      die("KRT: setfib(%d) failed: %m", 0);
906
#endif
907
908
  /* Process received messages */
909
  for (next = buf; next < (buf + needed); next += m->rtm.rtm_msglen)
910 b1a1faba Ondrej Filip
  {
911
    m = (struct ks_msg *)next;
912
    krt_read_msg(p, m, 1);
913
  }
914
915 c01a9466 Ondrej Zajicek
  return;
916
917
 exit:
918
  krt_buffer_release(p);
919
920
#ifdef KRT_USE_SETFIB_SCAN
921
  if (table_id > 0)
922
    if (setfib(0) < 0)
923
      die("KRT: setfib(%d) failed: %m", 0);
924
#endif
925
}
926 ff2857b0 Ondrej Zajicek
927 b1a1faba Ondrej Filip
void
928 396dfa90 Ondrej Zajicek
krt_do_scan(struct krt_proto *p)
929 b1a1faba Ondrej Filip
{
930 c01a9466 Ondrej Zajicek
  krt_sysctl_scan(&p->p, NET_RT_DUMP, KRT_CF->sys.table_id);
931 b1a1faba Ondrej Filip
}
932
933
void
934 396dfa90 Ondrej Zajicek
kif_do_scan(struct kif_proto *p)
935 b1a1faba Ondrej Filip
{
936
  if_start_update();
937 c01a9466 Ondrej Zajicek
  krt_sysctl_scan(&p->p, NET_RT_IFLIST, -1);
938 b1a1faba Ondrej Filip
  if_end_update();
939
}
940
941 c01a9466 Ondrej Zajicek
942
/* Kernel sockets */
943
944 396dfa90 Ondrej Zajicek
static int
945 3e236955 Jan Moskyto Matejka
krt_sock_hook(sock *sk, uint size UNUSED)
946 396dfa90 Ondrej Zajicek
{
947
  struct ks_msg msg;
948
  int l = read(sk->fd, (char *)&msg, sizeof(msg));
949
950 c01a9466 Ondrej Zajicek
  if (l <= 0)
951 396dfa90 Ondrej Zajicek
    log(L_ERR "krt-sock: read failed");
952
  else
953 c01a9466 Ondrej Zajicek
    krt_read_msg((struct proto *) sk->data, &msg, 0);
954 396dfa90 Ondrej Zajicek
955
  return 0;
956
}
957 b1a1faba Ondrej Filip
958 ccd2a3ed Jan Moskyto Matejka
static void
959
krt_sock_err_hook(sock *sk, int e UNUSED)
960
{
961
  krt_sock_hook(sk, 0);
962
}
963
964 c01a9466 Ondrej Zajicek
static sock *
965 3e236955 Jan Moskyto Matejka
krt_sock_open(pool *pool, void *data, int table_id UNUSED)
966 c01a9466 Ondrej Zajicek
{
967
  sock *sk;
968
  int fd;
969
970
  fd = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
971
  if (fd < 0)
972
    die("Cannot open kernel socket for routes");
973
974
#ifdef KRT_USE_SETFIB_SOCK
975
  if (table_id > 0)
976
  {
977
    if (setsockopt(fd, SOL_SOCKET, SO_SETFIB, &table_id, sizeof(table_id)) < 0)
978
      die("Cannot set FIB %d for kernel socket: %m", table_id);
979
  }
980
#endif
981
982
  sk = sk_new(pool);
983
  sk->type = SK_MAGIC;
984
  sk->rx_hook = krt_sock_hook;
985 ccd2a3ed Jan Moskyto Matejka
  sk->err_hook = krt_sock_err_hook;
986 c01a9466 Ondrej Zajicek
  sk->fd = fd;
987
  sk->data = data;
988
989
  if (sk_open(sk) < 0)
990
    bug("krt-sock: sk_open failed");
991
992
  return sk;
993
}
994
995 8109eb76 Jan Moskyto Matejka
static u32 krt_table_cf[(KRT_MAX_TABLES+31) / 32][2];
996 c01a9466 Ondrej Zajicek
997
#ifdef KRT_SHARED_SOCKET
998
999
static sock *krt_sock;
1000
static int krt_sock_count;
1001
1002
1003
static void
1004
krt_sock_open_shared(void)
1005
{
1006
  if (!krt_sock_count)
1007
    krt_sock = krt_sock_open(krt_pool, NULL, -1);
1008
  
1009
  krt_sock_count++;
1010
}
1011
1012
static void
1013
krt_sock_close_shared(void)
1014
{
1015
  krt_sock_count--;
1016
1017
  if (!krt_sock_count)
1018
  {
1019
    rfree(krt_sock);
1020
    krt_sock = NULL;
1021
  }
1022
}
1023
1024 9ddbfbdd Jan Moskyto Matejka
int
1025 c01a9466 Ondrej Zajicek
krt_sys_start(struct krt_proto *p)
1026 b1a1faba Ondrej Filip
{
1027 8109eb76 Jan Moskyto Matejka
  int id = KRT_CF->sys.table_id;
1028
1029
  if (krt_table_cf[id/32][!!(p->af == AF_INET6)] & (1 << (id%32)))
1030
    {
1031
      log(L_ERR "%s: Multiple kernel syncers defined for table #%d", p->p.name, id);
1032
      return 0;
1033
    }
1034
1035
  krt_table_cf[id/32][!!(p->af == AF_INET6)] |= (1 << (id%32));
1036
1037
  krt_table_map[KRT_CF->sys.table_id][!!(p->af == AF_INET6)] = p;
1038 396dfa90 Ondrej Zajicek
1039 c01a9466 Ondrej Zajicek
  krt_sock_open_shared();
1040
  p->sys.sk = krt_sock;
1041 9ddbfbdd Jan Moskyto Matejka
1042
  return 1;
1043 c01a9466 Ondrej Zajicek
}
1044 396dfa90 Ondrej Zajicek
1045 c01a9466 Ondrej Zajicek
void
1046
krt_sys_shutdown(struct krt_proto *p)
1047
{
1048 8109eb76 Jan Moskyto Matejka
  krt_table_cf[(KRT_CF->sys.table_id)/32][!!(p->af == AF_INET6)] &= ~(1 << ((KRT_CF->sys.table_id)%32));
1049
1050 c01a9466 Ondrej Zajicek
  krt_sock_close_shared();
1051
  p->sys.sk = NULL;
1052 396dfa90 Ondrej Zajicek
1053 8109eb76 Jan Moskyto Matejka
  krt_table_map[KRT_CF->sys.table_id][!!(p->af == AF_INET6)] = NULL;
1054 396dfa90 Ondrej Zajicek
1055 c01a9466 Ondrej Zajicek
  krt_buffer_release(&p->p);
1056
}
1057 396dfa90 Ondrej Zajicek
1058 c01a9466 Ondrej Zajicek
#else
1059
1060 9ddbfbdd Jan Moskyto Matejka
int
1061 c01a9466 Ondrej Zajicek
krt_sys_start(struct krt_proto *p)
1062
{
1063 8109eb76 Jan Moskyto Matejka
  int id = KRT_CF->sys.table_id;
1064
1065
  if (krt_table_cf[id/32][!!(p->af == AF_INET6)] & (1 << (id%32)))
1066
    {
1067
      log(L_ERR "%s: Multiple kernel syncers defined for table #%d", p->p.name, id);
1068
      return 0;
1069
    }
1070
1071
  krt_table_cf[id/32][!!(p->af == AF_INET6)] |= (1 << (id%32));
1072
1073 c01a9466 Ondrej Zajicek
  p->sys.sk = krt_sock_open(p->p.pool, p, KRT_CF->sys.table_id);
1074 9ddbfbdd Jan Moskyto Matejka
  return 1;
1075 b1a1faba Ondrej Filip
}
1076
1077
void
1078 c01a9466 Ondrej Zajicek
krt_sys_shutdown(struct krt_proto *p)
1079 b1a1faba Ondrej Filip
{
1080 8109eb76 Jan Moskyto Matejka
  krt_table_cf[(KRT_CF->sys.table_id)/32][!!(p->af == AF_INET6)] &= ~(1 << ((KRT_CF->sys.table_id)%32));
1081
1082 c01a9466 Ondrej Zajicek
  rfree(p->sys.sk);
1083
  p->sys.sk = NULL;
1084 a209d5d8 Ondrej Zajicek
1085 c01a9466 Ondrej Zajicek
  krt_buffer_release(&p->p);
1086 ff2857b0 Ondrej Zajicek
}
1087 b1a1faba Ondrej Filip
1088 c01a9466 Ondrej Zajicek
#endif /* KRT_SHARED_SOCKET */
1089
1090 a209d5d8 Ondrej Zajicek
1091 c01a9466 Ondrej Zajicek
/* KRT configuration callbacks */
1092
1093
int
1094
krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n, struct krt_config *o)
1095
{
1096
  return n->sys.table_id == o->sys.table_id;
1097 ff2857b0 Ondrej Zajicek
}
1098 b1a1faba Ondrej Filip
1099
void
1100 c01a9466 Ondrej Zajicek
krt_sys_preconfig(struct config *c UNUSED)
1101 b1a1faba Ondrej Filip
{
1102 c01a9466 Ondrej Zajicek
  krt_max_tables = krt_get_max_tables();
1103
  bzero(&krt_table_cf, sizeof(krt_table_cf));
1104 b1a1faba Ondrej Filip
}
1105
1106 c01a9466 Ondrej Zajicek
void krt_sys_init_config(struct krt_config *c)
1107
{
1108
  c->sys.table_id = 0; /* Default table */
1109
}
1110 a209d5d8 Ondrej Zajicek
1111 c01a9466 Ondrej Zajicek
void krt_sys_copy_config(struct krt_config *d, struct krt_config *s)
1112
{
1113
  d->sys.table_id = s->sys.table_id;
1114
}
1115
1116
1117
/* KIF misc code */
1118
1119 b1a1faba Ondrej Filip
void
1120 c01a9466 Ondrej Zajicek
kif_sys_start(struct kif_proto *p UNUSED)
1121 b1a1faba Ondrej Filip
{
1122 c01a9466 Ondrej Zajicek
}
1123 a209d5d8 Ondrej Zajicek
1124 c01a9466 Ondrej Zajicek
void
1125
kif_sys_shutdown(struct kif_proto *p)
1126
{
1127
  krt_buffer_release(&p->p);
1128 b1a1faba Ondrej Filip
}
1129
1130 153f02da Ondrej Zajicek (work)
int
1131
kif_update_sysdep_addr(struct iface *i)
1132 e237b28a Ondrej Zajicek
{
1133
  static int fd = -1;
1134 153f02da Ondrej Zajicek (work)
1135 e237b28a Ondrej Zajicek
  if (fd < 0)
1136
    fd = socket(AF_INET, SOCK_DGRAM, 0);
1137
1138
  struct ifreq ifr;
1139
  memset(&ifr, 0, sizeof(ifr));
1140
  strncpy(ifr.ifr_name, i->name, IFNAMSIZ);
1141
1142
  int rv = ioctl(fd, SIOCGIFADDR, (char *) &ifr);
1143
  if (rv < 0)
1144 153f02da Ondrej Zajicek (work)
    return 0;
1145 e237b28a Ondrej Zajicek
1146 153f02da Ondrej Zajicek (work)
  ip4_addr old = i->sysdep;
1147
  i->sysdep = ip4_from_ipa(ipa_from_sa4(&ifr.ifr_addr);
1148 e237b28a Ondrej Zajicek
1149 153f02da Ondrej Zajicek (work)
  return !ip4_equal(i->sysdep, addr);
1150 e237b28a Ondrej Zajicek
}