Revision c01a9466 sysdep/bsd/krt-sock.c

View differences:

sysdep/bsd/krt-sock.c
1 1
/*
2
 *	BIRD -- Unix Routing Table Syncing
2
 *	BIRD -- BSD Routing Table Syncing
3 3
 *
4 4
 *	(c) 2004 Ondrej Filip <feela@network.cz>
5 5
 *
......
7 7
 */
8 8

  
9 9
#include <stdio.h>
10
#include <stdlib.h>
10 11
#include <ctype.h>
11 12
#include <fcntl.h>
12 13
#include <unistd.h>
......
34 35
#include "lib/socket.h"
35 36

  
36 37

  
37
#ifndef RTAX_MAX
38
#define RTAX_MAX        8
38
/*
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
39 62
#endif
40 63

  
41
struct ks_msg
64
#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

  
76
/* Dynamic max number of tables */
77

  
78
int krt_max_tables;
79

  
80
#ifdef KRT_USE_SYSCTL_NET_FIBS
81

  
82
static int
83
krt_get_max_tables(void)
42 84
{
43
  struct rt_msghdr rtm;
44
  struct sockaddr_storage buf[RTAX_MAX];
45
};
85
  int fibs;
86
  size_t fibs_len = sizeof(fibs);
87

  
88
  if (sysctlbyname("net.fibs", &fibs, &fibs_len, NULL, 0) < 0)
89
  {
90
    log(L_WARN "KRT: unable to get max number of fib tables: %m");
91
    return 1;
92
  }
93

  
94
  return MIN(fibs, KRT_MAX_TABLES);
95
}
96

  
97
#else
98

  
99
static int
100
krt_get_max_tables(void)
101
{
102
  return KRT_MAX_TABLES;
103
}
104

  
105
#endif /* KRT_USE_SYSCTL_NET_FIBS */
106

  
107

  
108
/* setfib() syscall for FreeBSD scans */
109

  
110
#ifdef KRT_USE_SETFIB_SCAN
111

  
112
/*
113
static int krt_default_fib;
114

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

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

  
127
  return fib;
128
}
129
*/
130

  
131
extern int setfib(int fib);
46 132

  
133
#endif /* KRT_USE_SETFIB_SCAN */
47 134

  
48
static int rt_sock = 0;
135

  
136
/* table_id -> krt_proto map */
137

  
138
#ifdef KRT_SHARED_SOCKET
139
static struct krt_proto *krt_table_map[KRT_MAX_TABLES];
140
#endif
141

  
142

  
143
/* Route socket message processing */
49 144

  
50 145
int
51 146
krt_capable(rte *e)
......
65 160
     );
66 161
}
67 162

  
163
#ifndef RTAX_MAX
164
#define RTAX_MAX 8
165
#endif
166

  
167
struct ks_msg
168
{
169
  struct rt_msghdr rtm;
170
  struct sockaddr_storage buf[RTAX_MAX];
171
};
172

  
68 173
#define ROUNDUP(a) \
69 174
        ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
70 175

  
......
81 186
    body += l;}
82 187

  
83 188
static int
84
krt_sock_send(int cmd, rte *e)
189
krt_send_route(struct krt_proto *p, int cmd, rte *e)
85 190
{
86 191
  net *net = e->net;
87 192
  rta *a = e->attrs;
......
103 208
  msg.rtm.rtm_flags = RTF_UP | RTF_PROTO1;
104 209

  
105 210
  if (net->n.pxlen == MAX_PREFIX_LENGTH)
106
  {
107 211
    msg.rtm.rtm_flags |= RTF_HOST;
108
  }
109 212
  else
110
  {
111 213
    msg.rtm.rtm_addrs |= RTA_NETMASK;
112
  }
214

  
215
#ifdef KRT_SHARED_SOCKET
216
  msg.rtm.rtm_tableid = KRT_CF->sys.table_id;
217
#endif
113 218

  
114 219
#ifdef RTF_REJECT
115 220
  if(a->dest == RTD_UNREACHABLE)
......
192 297
  l = body - (char *)&msg;
193 298
  msg.rtm.rtm_msglen = l;
194 299

  
195
  if ((l = write(rt_sock, (char *)&msg, l)) < 0) {
300
  if ((l = write(p->sys.sk->fd, (char *)&msg, l)) < 0) {
196 301
    log(L_ERR "KRT: Error sending route %I/%d to kernel: %m", net->n.prefix, net->n.pxlen);
197 302
    return -1;
198 303
  }
......
201 306
}
202 307

  
203 308
void
204
krt_replace_rte(struct krt_proto *p UNUSED, net *n, rte *new, rte *old,
309
krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old,
205 310
		struct ea_list *eattrs UNUSED)
206 311
{
207 312
  int err = 0;
208 313

  
209 314
  if (old)
210
    krt_sock_send(RTM_DELETE, old);
315
    krt_send_route(p, RTM_DELETE, old);
211 316

  
212 317
  if (new)
213
    err = krt_sock_send(RTM_ADD, new);
318
    err = krt_send_route(p, RTM_ADD, new);
214 319

  
215 320
  if (err < 0)
216 321
    n->n.flags |= KRF_SYNC_ERROR;
......
221 326
#define SKIP(ARG...) do { DBG("KRT: Ignoring route - " ARG); return; } while(0)
222 327

  
223 328
static void
224
krt_read_rt(struct ks_msg *msg, struct krt_proto *p, int scan)
329
krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
225 330
{
331
  /* p is NULL iff KRT_SHARED_SOCKET and !scan */
332

  
226 333
  rte *e;
227 334
  net *net;
228 335
  sockaddr dst, gate, mask;
......
244 351
  if (flags & RTF_LLINFO)
245 352
    SKIP("link-local\n");
246 353

  
354
#ifdef KRT_SHARED_SOCKET
355
  if (!scan)
356
  {
357
    int table_id = msg->rtm.rtm_tableid;
358
    p = (table_id < KRT_MAX_TABLES) ? krt_table_map[table_id] : NULL;
359

  
360
    if (!p)
361
      SKIP("unknown table id %d\n", table_id);
362
  }
363
#endif
364

  
247 365
  GETADDR(&dst, RTA_DST);
248 366
  GETADDR(&gate, RTA_GATEWAY);
249 367
  GETADDR(&mask, RTA_NETMASK);
......
594 712
    ifa_delete(&ifa);
595 713
}
596 714

  
597

  
598
void
715
static void
599 716
krt_read_msg(struct proto *p, struct ks_msg *msg, int scan)
600 717
{
718
  /* p is NULL iff KRT_SHARED_SOCKET and !scan */
719

  
601 720
  switch (msg->rtm.rtm_type)
602 721
  {
603 722
    case RTM_GET:
604 723
      if(!scan) return;
605 724
    case RTM_ADD:
606 725
    case RTM_DELETE:
607
      krt_read_rt(msg, (struct krt_proto *)p, scan);
726
      krt_read_route(msg, (struct krt_proto *)p, scan);
608 727
      break;
609 728
    case RTM_IFANNOUNCE:
610 729
      krt_read_ifannounce(msg);
......
621 740
  }
622 741
}
623 742

  
743

  
744
/* Sysctl based scans */
745

  
746
static byte *krt_buffer;
747
static size_t krt_buflen, krt_bufmin;
748
static struct proto *krt_buffer_owner;
749

  
750
static byte *
751
krt_buffer_update(struct proto *p, size_t *needed)
752
{
753
  size_t req = *needed;
754

  
755
  if ((req > krt_buflen) ||
756
      ((p == krt_buffer_owner) && (req < krt_bufmin)))
757
  {
758
    /* min buflen is 32 kB, step is 8 kB, or 128 kB if > 1 MB */
759
    size_t step = (req < 0x100000) ? 0x2000 : 0x20000;
760
    krt_buflen = (req < 0x6000) ? 0x8000 : (req + step);
761
    krt_bufmin = (req < 0x8000) ? 0 : (req - 2*step);
762

  
763
    if (krt_buffer) 
764
      mb_free(krt_buffer);
765
    krt_buffer = mb_alloc(krt_pool, krt_buflen);
766
    krt_buffer_owner = p;
767
  }
768

  
769
  *needed = krt_buflen;
770
  return krt_buffer;
771
}
772

  
773
static void
774
krt_buffer_release(struct proto *p)
775
{
776
  if (p == krt_buffer_owner)
777
  {
778
    mb_free(krt_buffer);
779
    krt_buffer = NULL;
780
    krt_buflen = 0;
781
    krt_buffer_owner = 0;
782
  }
783
}
784

  
624 785
static void
625
krt_sysctl_scan(struct proto *p, pool *pool, byte **buf, size_t *bl, int cmd)
786
krt_sysctl_scan(struct proto *p, int cmd, int table_id)
626 787
{
627
  byte *next;
628
  int mib[6];
629
  size_t obl, needed;
788
  byte *buf, *next;
789
  int mib[7], mcnt;
790
  size_t needed;
630 791
  struct ks_msg *m;
631 792
  int retries = 3;
793
  int rv;
632 794

  
633 795
  mib[0] = CTL_NET;
634 796
  mib[1] = PF_ROUTE;
......
636 798
  mib[3] = BIRD_PF;
637 799
  mib[4] = cmd;
638 800
  mib[5] = 0;
801
  mcnt = 6;
639 802

  
640
 try:
641
  if (sysctl(mib, 6 , NULL , &needed, NULL, 0) < 0)
642
    die("krt_sysctl_scan 1: %m");
643

  
644
  obl = *bl;
803
#ifdef KRT_USE_SYSCTL_7
804
  if (table_id >= 0)
805
  {
806
    mib[6] = table_id;
807
    mcnt = 7;
808
  }
809
#endif
645 810

  
646
  while (needed > *bl) *bl *= 2;
647
  while (needed < (*bl/2)) *bl /= 2;
811
#ifdef KRT_USE_SETFIB_SCAN
812
  if (table_id > 0)
813
    if (setfib(table_id) < 0)
814
    {
815
      log(L_ERR "KRT: setfib(%d) failed: %m", table_id);
816
      return;
817
    }
818
#endif
648 819

  
649
  if ((obl!=*bl) || !*buf)
820
 try:
821
  rv = sysctl(mib, mcnt, NULL, &needed, NULL, 0);
822
  if (rv < 0)
650 823
  {
651
    if (*buf) mb_free(*buf);
652
    if ((*buf = mb_alloc(pool, *bl)) == NULL) die("RT scan buf alloc");
824
    /* OpenBSD returns EINVAL for not yet used tables */
825
    if ((errno == EINVAL) && (table_id > 0))
826
      goto exit;
827

  
828
    log(L_ERR "KRT: Route scan estimate failed: %m");
829
    goto exit;
653 830
  }
654 831

  
655
  if (sysctl(mib, 6 , *buf, &needed, NULL, 0) < 0)
832
  /* The table is empty */
833
  if (needed == 0)
834
    goto exit;
835

  
836
  buf = krt_buffer_update(p, &needed);
837

  
838
  rv = sysctl(mib, mcnt, buf, &needed, NULL, 0);
839
  if (rv < 0)
656 840
  {
657
    if (errno == ENOMEM)
658
    {
659
      /* The buffer size changed since last sysctl ('needed' is not changed) */
660
      if (retries--)
661
	goto try;
841
    /* The buffer size changed since last sysctl ('needed' is not changed) */
842
    if ((errno == ENOMEM) && retries--)
843
      goto try;
662 844

  
663
      log(L_ERR "KRT: Route scan failed");
664
      return;
665
    }
666
    die("krt_sysctl_scan 2: %m");
845
    log(L_ERR "KRT: Route scan failed: %m");
846
    goto exit;
667 847
  }
668 848

  
669
  for (next = *buf; next < (*buf + needed); next += m->rtm.rtm_msglen)
849
#ifdef KRT_USE_SETFIB_SCAN
850
  if (table_id > 0)
851
    if (setfib(0) < 0)
852
      die("KRT: setfib(%d) failed: %m", 0);
853
#endif
854

  
855
  /* Process received messages */
856
  for (next = buf; next < (buf + needed); next += m->rtm.rtm_msglen)
670 857
  {
671 858
    m = (struct ks_msg *)next;
672 859
    krt_read_msg(p, m, 1);
673 860
  }
674
}
675 861

  
676
static byte *krt_buffer = NULL;
677
static byte *kif_buffer = NULL;
678
static size_t krt_buflen = 32768;
679
static size_t kif_buflen = 4096;
862
  return;
863

  
864
 exit:
865
  krt_buffer_release(p);
866

  
867
#ifdef KRT_USE_SETFIB_SCAN
868
  if (table_id > 0)
869
    if (setfib(0) < 0)
870
      die("KRT: setfib(%d) failed: %m", 0);
871
#endif
872
}
680 873

  
681 874
void
682 875
krt_do_scan(struct krt_proto *p)
683 876
{
684
  krt_sysctl_scan(&p->p, p->p.pool, &krt_buffer, &krt_buflen, NET_RT_DUMP);
877
  krt_sysctl_scan(&p->p, NET_RT_DUMP, KRT_CF->sys.table_id);
685 878
}
686 879

  
687 880
void
688 881
kif_do_scan(struct kif_proto *p)
689 882
{
690 883
  if_start_update();
691
  krt_sysctl_scan(&p->p, p->p.pool, &kif_buffer, &kif_buflen, NET_RT_IFLIST);
884
  krt_sysctl_scan(&p->p, NET_RT_IFLIST, -1);
692 885
  if_end_update();
693 886
}
694 887

  
888

  
889
/* Kernel sockets */
890

  
695 891
static int
696 892
krt_sock_hook(sock *sk, int size UNUSED)
697 893
{
698 894
  struct ks_msg msg;
699 895
  int l = read(sk->fd, (char *)&msg, sizeof(msg));
700 896

  
701
  if(l <= 0)
897
  if (l <= 0)
702 898
    log(L_ERR "krt-sock: read failed");
703 899
  else
704
  krt_read_msg((struct proto *)sk->data, &msg, 0);
900
    krt_read_msg((struct proto *) sk->data, &msg, 0);
705 901

  
706 902
  return 0;
707 903
}
708 904

  
905
static sock *
906
krt_sock_open(pool *pool, void *data, int table_id)
907
{
908
  sock *sk;
909
  int fd;
910

  
911
  fd = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
912
  if (fd < 0)
913
    die("Cannot open kernel socket for routes");
914

  
915
#ifdef KRT_USE_SETFIB_SOCK
916
  if (table_id > 0)
917
  {
918
    if (setsockopt(fd, SOL_SOCKET, SO_SETFIB, &table_id, sizeof(table_id)) < 0)
919
      die("Cannot set FIB %d for kernel socket: %m", table_id);
920
  }
921
#endif
922

  
923
  sk = sk_new(pool);
924
  sk->type = SK_MAGIC;
925
  sk->rx_hook = krt_sock_hook;
926
  sk->fd = fd;
927
  sk->data = data;
928

  
929
  if (sk_open(sk) < 0)
930
    bug("krt-sock: sk_open failed");
931

  
932
  return sk;
933
}
934

  
935

  
936
#ifdef KRT_SHARED_SOCKET
937

  
938
static sock *krt_sock;
939
static int krt_sock_count;
940

  
941

  
942
static void
943
krt_sock_open_shared(void)
944
{
945
  if (!krt_sock_count)
946
    krt_sock = krt_sock_open(krt_pool, NULL, -1);
947
  
948
  krt_sock_count++;
949
}
950

  
951
static void
952
krt_sock_close_shared(void)
953
{
954
  krt_sock_count--;
955

  
956
  if (!krt_sock_count)
957
  {
958
    rfree(krt_sock);
959
    krt_sock = NULL;
960
  }
961
}
962

  
709 963
void
710
krt_sys_start(struct krt_proto *x)
964
krt_sys_start(struct krt_proto *p)
711 965
{
712
  sock *sk_rt;
713
  static int ks_open_tried = 0;
966
  krt_table_map[KRT_CF->sys.table_id] = p;
714 967

  
715
  if (ks_open_tried)
716
    return;
968
  krt_sock_open_shared();
969
  p->sys.sk = krt_sock;
970
}
717 971

  
718
  ks_open_tried = 1;
972
void
973
krt_sys_shutdown(struct krt_proto *p)
974
{
975
  krt_sock_close_shared();
976
  p->sys.sk = NULL;
719 977

  
720
  DBG("KRT: Opening kernel socket\n");
978
  krt_table_map[KRT_CF->sys.table_id] = NULL;
721 979

  
722
  if( (rt_sock = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC)) < 0)
723
    die("Cannot open kernel socket for routes");
980
  krt_buffer_release(&p->p);
981
}
724 982

  
725
  sk_rt = sk_new(krt_pool);
726
  sk_rt->type = SK_MAGIC;
727
  sk_rt->rx_hook = krt_sock_hook;
728
  sk_rt->fd = rt_sock;
729
  sk_rt->data = x;
730
  if (sk_open(sk_rt))
731
    bug("krt-sock: sk_open failed");
983
#else
984

  
985
void
986
krt_sys_start(struct krt_proto *p)
987
{
988
  p->sys.sk = krt_sock_open(p->p.pool, p, KRT_CF->sys.table_id);
732 989
}
733 990

  
734 991
void
735
krt_sys_shutdown(struct krt_proto *x UNUSED)
992
krt_sys_shutdown(struct krt_proto *p)
736 993
{
737
  if (!krt_buffer)
738
    return;
994
  rfree(p->sys.sk);
995
  p->sys.sk = NULL;
996

  
997
  krt_buffer_release(&p->p);
998
}
999

  
1000
#endif /* KRT_SHARED_SOCKET */
1001

  
739 1002

  
740
  mb_free(krt_buffer);
741
  krt_buffer = NULL;
1003
/* KRT configuration callbacks */
1004

  
1005
static u32 krt_table_cf[(KRT_MAX_TABLES+31) / 32];
1006

  
1007
int
1008
krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n, struct krt_config *o)
1009
{
1010
  return n->sys.table_id == o->sys.table_id;
742 1011
}
743 1012

  
1013
void
1014
krt_sys_preconfig(struct config *c UNUSED)
1015
{
1016
  krt_max_tables = krt_get_max_tables();
1017
  bzero(&krt_table_cf, sizeof(krt_table_cf));
1018
}
744 1019

  
745 1020
void
746
kif_sys_start(struct kif_proto *p UNUSED)
1021
krt_sys_postconfig(struct krt_config *x)
747 1022
{
1023
  u32 *tbl = krt_table_cf;
1024
  int id = x->sys.table_id;
1025

  
1026
  if (tbl[id/32] & (1 << (id%32)))
1027
    cf_error("Multiple kernel syncers defined for table #%d", id);
1028

  
1029
  tbl[id/32] |= (1 << (id%32));
748 1030
}
749 1031

  
1032
void krt_sys_init_config(struct krt_config *c)
1033
{
1034
  c->sys.table_id = 0; /* Default table */
1035
}
1036

  
1037
void krt_sys_copy_config(struct krt_config *d, struct krt_config *s)
1038
{
1039
  d->sys.table_id = s->sys.table_id;
1040
}
1041

  
1042

  
1043
/* KIF misc code */
1044

  
750 1045
void
751
kif_sys_shutdown(struct kif_proto *p UNUSED)
1046
kif_sys_start(struct kif_proto *p UNUSED)
752 1047
{
753
  if (!kif_buffer)
754
    return;
1048
}
755 1049

  
756
  mb_free(kif_buffer);
757
  kif_buffer = NULL;
1050
void
1051
kif_sys_shutdown(struct kif_proto *p)
1052
{
1053
  krt_buffer_release(&p->p);
758 1054
}
759 1055

  

Also available in: Unified diff