]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Implemented scanning of network interfaces. Mostly very ugly code due to
authorMartin Mares <mj@ucw.cz>
Tue, 26 May 1998 21:42:05 +0000 (21:42 +0000)
committerMartin Mares <mj@ucw.cz>
Tue, 26 May 1998 21:42:05 +0000 (21:42 +0000)
terrible kernel interface (SIOGIFCONF and friends).

nest/Makefile
nest/iface.c [new file with mode: 0644]
nest/iface.h
sysdep/unix/Modules
sysdep/unix/main.c
sysdep/unix/sync-if.c [new file with mode: 0644]

index 0a9d5fe856fd6602890d00a17a0e60151fe580b2..aaa0c2a0e937b2701d7549cb64c7e2ea6d58e449 100644 (file)
@@ -1,4 +1,4 @@
 THISDIR=nest
-OBJS=rt-table.o rt-fib.o rt-attr.o proto.o
+OBJS=rt-table.o rt-fib.o rt-attr.o proto.o iface.o
 
 include ../Rules
diff --git a/nest/iface.c b/nest/iface.c
new file mode 100644 (file)
index 0000000..79a7b7d
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ *     BIRD -- Management of Interfaces
+ *
+ *     (c) 1998 Martin Mares <mj@ucw.cz>
+ *
+ *     Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "nest/bird.h"
+#include "nest/iface.h"
+#include "lib/resource.h"
+
+list iface_list;
+
+static pool *if_pool;
+
+void
+if_dump(struct iface *i)
+{
+  struct ifa *a;
+
+  debug("IF%d: %s", i->index, i->name);
+  if (i->flags & IF_ADMIN_DOWN)
+    debug(" ADMIN-DOWN");
+  if (i->flags & IF_UP)
+    debug(" UP");
+  if (i->flags & IF_MULTIACCESS)
+    debug(" MA");
+  if (i->flags & IF_UNNUMBERED)
+    debug(" UNNUM");
+  if (i->flags & IF_BROADCAST)
+    debug(" BC");
+  if (i->flags & IF_MULTICAST)
+    debug(" MC");
+  if (i->flags & IF_TUNNEL)
+    debug(" TUNL");
+  if (i->flags & IF_LOOPBACK)
+    debug(" LOOP");
+  if (i->flags & IF_IGNORE)
+    debug(" IGN");
+  debug(" MTU=%d\n", i->mtu);
+  for(a=i->ifa; a; a=a->next)
+    debug("\t%08x, net %08x/%-2d bc %08x -> %08x\n", _I(a->ip), _I(a->prefix), a->pxlen, _I(a->brd), _I(a->opposite));
+}
+
+void
+if_dump_all(void)
+{
+  struct iface *i;
+
+  debug("Known network interfaces:\n\n");
+  WALK_LIST(i, iface_list)
+    if_dump(i);
+  debug("\n");
+}
+
+struct if_with_a {
+  struct iface i;
+  struct ifa a[0];
+};
+
+static struct iface *
+if_copy(struct iface *j)
+{
+  int len;
+  struct if_with_a *w;
+  struct iface *i;
+  struct ifa *a, **b, *c;
+
+  len = 0;
+  for(a=j->ifa; a; a=a->next)
+    len++;
+  w = mb_alloc(if_pool, sizeof(struct if_with_a) + len*sizeof(struct ifa));
+  i = &w->i;
+  c = w->a;
+  memcpy(i, j, sizeof(struct iface));
+  b = &i->ifa;
+  a = j->ifa;
+  while (a)
+    {
+      *b = c;
+      memcpy(c, a, sizeof(struct ifa));
+      b = &c->next;
+      a = a->next;
+      c++;
+    }
+  *b = NULL;
+  return i;
+}
+
+static inline void
+if_free(struct iface *i)
+{
+  mb_free(i);
+}
+
+static unsigned
+if_changed(struct iface *i, struct iface *j)
+{
+  unsigned f = 0;
+  struct ifa *x, *y;
+
+  x = i->ifa;
+  y = j->ifa;
+  while (x && y)
+    {
+      x = x->next;
+      y = y->next;
+    }
+  if (x || y)
+    f |= IF_CHANGE_ADDR;
+  if (i->mtu != j->mtu)
+    f |= IF_CHANGE_MTU;
+  if (i->flags != j->flags)
+    {
+      f |= IF_CHANGE_FLAGS;
+      if ((i->flags ^ j->flags) & IF_UP)
+       if (i->flags & IF_UP)
+         f |= IF_CHANGE_DOWN;
+       else
+         f |= IF_CHANGE_UP;
+    }
+  return f;
+}
+
+static void
+if_notify_change(unsigned c, struct iface *old, struct iface *new)
+{
+  debug("Interface change notification (%x) for %s\n", c, new->name);
+}
+
+void
+if_update(struct iface *new)
+{
+  struct iface *i;
+
+  WALK_LIST(i, iface_list)
+    if (!strcmp(new->name, i->name))
+      {
+       unsigned c = if_changed(i, new);
+       if (c)
+         {
+           struct iface *j = if_copy(new);
+           if_notify_change(c, i, j);
+           insert_node(&j->n, &i->n);
+           rem_node(&i->n);
+           if_free(i);
+         }
+       return;
+      }
+  i = if_copy(new);
+  add_tail(&iface_list, &i->n);
+  if_notify_change(IF_CHANGE_UP | IF_CHANGE_FLAGS | IF_CHANGE_MTU | IF_CHANGE_ADDR, NULL, i);
+}
+
+void
+if_end_update(void)
+{
+  struct iface *i, j;
+
+  WALK_LIST(i, iface_list)
+    if (i->flags & IF_UPDATED)
+      i->flags &= ~IF_UPDATED;
+    else
+      {
+       memcpy(&j, i, sizeof(struct iface));
+       i->flags = (i->flags & ~IF_UP) | IF_ADMIN_DOWN;
+       if_notify_change(IF_CHANGE_DOWN | IF_CHANGE_FLAGS, &j, i);
+      }
+}
+
+void
+if_init(void)
+{
+  if_pool = rp_new(&root_pool, "Interfaces");
+  init_list(&iface_list);
+}
index 454c05013c86c10d99d92f926b32134ea08282b6..4df98739df9a815385541a8568772ff4cb9eb80f 100644 (file)
 
 #include "lib/lists.h"
 
+extern list iface_list;
+
 struct iface {
   node n;
-  char *name;
+  char name[16];
   unsigned flags;
   unsigned mtu;
   struct ifa *ifa;                     /* First address is primary */
@@ -26,6 +28,10 @@ struct iface {
 #define IF_BROADCAST 8
 #define IF_MULTICAST 16
 #define IF_TUNNEL 32
+#define IF_ADMIN_DOWN 64
+#define IF_LOOPBACK 128
+#define IF_IGNORE 256
+#define IF_UPDATED 0x1000              /* Touched in last scan */
 
 /* Interface address */
 
@@ -39,4 +45,18 @@ struct ifa {
   struct neighbor *neigh;              /* List of neighbors on this interface */
 };
 
+/* Interface change events */
+
+#define IF_CHANGE_UP 1
+#define IF_CHANGE_DOWN 2
+#define IF_CHANGE_FLAGS 4
+#define IF_CHANGE_MTU 8
+#define IF_CHANGE_ADDR 16
+
+void if_init(void);
+void if_dump(struct iface *);
+void if_dump_all(void);
+void if_update(struct iface *);
+void if_end_update(void);
+
 #endif
index 95b80b3813cc9249e5f2236565a93ad52a3351fa..0b5117a50ace8a098c7c5bc17b0133cc6f770fb1 100644 (file)
@@ -3,3 +3,4 @@ main.c
 timer.h
 io.c
 unix.h
+sync-if.c
index b6b783b28780785b853dbea62eb880278b6fbd5b..293ee63f157024ed08345041782221700ecfca6f 100644 (file)
@@ -15,6 +15,7 @@
 #include "lib/socket.h"
 #include "nest/route.h"
 #include "nest/protocol.h"
+#include "nest/iface.h"
 
 #include "unix.h"
 
@@ -29,6 +30,7 @@ handle_sigusr(int sig)
 
   sk_dump_all();
   tm_dump_all();
+  if_dump_all();
   rta_dump_all();
   rt_dump_all();
 
@@ -83,29 +85,16 @@ main(void)
   resource_init();
   io_init();
   rt_init();
+  if_init();
   protos_init();
+
+  scan_if_init();
+
   signal_init();
 
-  {
-    sock *s = sk_new(&root_pool);
-
-    if (!s)
-      die("no socket");
-    s->type = SK_UDP_MC;
-    s->sport = 7899;
-    s->saddr = _MI(0x3ea80015);
-    s->daddr = _MI(0xe0000001);
-    s->dport = 7890;
-    s->rx_hook = xxx;
-    s->tx_hook = bla;
-    s->err_hook = erro;
-    s->rbsize = 1024;
-    s->tbsize = 1024;
-    s->ttl = 1;
-    if (sk_open(s))
-      die("open failed");
-    bla(s);
-  }
+  handle_sigusr(0);
+
+  debug("Entering I/O loop.\n");
 
   io_loop();
   die("I/O loop died");
diff --git a/sysdep/unix/sync-if.c b/sysdep/unix/sync-if.c
new file mode 100644 (file)
index 0000000..742421f
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ *     BIRD -- Unix Interface Scanning and Syncing
+ *
+ *     (c) 1998 Martin Mares <mj@ucw.cz>
+ *
+ *     Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#define LOCAL_DEBUG
+
+#include "nest/bird.h"
+#include "nest/iface.h"
+#include "lib/timer.h"
+
+#include "unix.h"
+
+int if_scan_sock;
+int if_scan_period = 60;
+
+static timer *if_scan_timer;
+
+static void
+scan_ifs(struct ifreq *r, int cnt)
+{
+  struct iface i;
+  struct ifa a;
+  char *err;
+  unsigned fl;
+  ip_addr netmask;
+  int l;
+
+  for (cnt /= sizeof(struct ifreq); cnt; cnt--, r++)
+    {
+      bzero(&i, sizeof(i));
+      bzero(&a, sizeof(a));
+      debug("%s\n", r->ifr_ifrn.ifrn_name);
+      strncpy(i.name, r->ifr_ifrn.ifrn_name, sizeof(i.name) - 1);
+      i.name[sizeof(i.name) - 1] = 0;
+      i.ifa = &a;
+      get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &a.ip, NULL);
+      l = ipa_classify(a.ip);
+      if (l < 0 || !(l & IADDR_HOST))
+       {
+         log(L_ERR "%s: Invalid interface address", i.name);
+         goto bad;
+       }
+      if ((l & IADDR_SCOPE_MASK) == SCOPE_HOST)
+       i.flags |= IF_LOOPBACK | IF_IGNORE;
+
+      if (ioctl(if_scan_sock, SIOCGIFFLAGS, r) < 0)
+       {
+         err = "SIOCGIFFLAGS";
+       faulty:
+         log(L_ERR "%s(%s): %m", err, i.name);
+       bad:
+         i.flags = (i.flags & ~IF_UP) | IF_ADMIN_DOWN;
+         continue;
+       }
+      fl = r->ifr_flags;
+      if (fl & IFF_UP)
+       i.flags |= IF_UP;
+
+      if (ioctl(if_scan_sock, SIOCGIFNETMASK, r) < 0)
+       { err = "SIOCGIFNETMASK"; goto faulty; }
+      get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &netmask, NULL);
+      l = ipa_mklen(netmask);
+      if (l < 0 || l == 31)
+       {
+         log(L_ERR "%s: Invalid netmask", i.name);
+         goto bad;
+       }
+      a.pxlen = l;
+
+      if (fl & IFF_POINTOPOINT)
+       {
+         i.flags |= IF_UNNUMBERED;
+         a.pxlen = BITS_PER_IP_ADDRESS;
+         if (ioctl(if_scan_sock, SIOCGIFDSTADDR, r) < 0)
+           { err = "SIOCGIFDSTADDR"; goto faulty; }
+         get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &a.opposite, NULL);
+       }
+      if (fl & IFF_LOOPBACK)
+       i.flags |= IF_LOOPBACK | IF_IGNORE;
+#ifndef CONFIG_ALL_MULTICAST
+      if (fl & IFF_MULTICAST)
+#endif
+       i.flags |= IF_MULTICAST;
+
+      a.prefix = ipa_and(a.ip, ipa_mkmask(a.pxlen));
+      if (a.pxlen < 32)
+       {
+         a.brd = ipa_or(a.prefix, ipa_not(ipa_mkmask(a.pxlen)));
+         if (ipa_equal(a.ip, a.prefix) || ipa_equal(a.ip, a.brd))
+           {
+             log(L_ERR "%s: Using network or broadcast address for interface", i.name);
+             goto bad;
+           }
+         if (fl & IFF_BROADCAST)
+           i.flags |= IF_BROADCAST;
+         if (a.pxlen < 30)
+           i.flags |= IF_MULTIACCESS;
+         else
+           a.opposite = ipa_opposite(a.ip);
+       }
+      else
+       a.brd = a.opposite;
+
+      if (ioctl(if_scan_sock, SIOCGIFMTU, r) < 0)
+       { err = "SIOCGIFMTU"; goto faulty; }
+      i.mtu = r->ifr_mtu;
+
+#ifdef SIOCGIFINDEX
+      if (ioctl(if_scan_sock, SIOCGIFINDEX, r) < 0)
+       { err = "SIOCGIFINDEX"; goto faulty; }
+      i.index = r->ifr_ifindex;
+#endif
+
+      if_update(&i);
+    }
+}
+
+static void
+scan_if(timer *t)
+{
+  struct ifconf ic;
+  static int last_ifbuf_size;
+  int res;
+
+  DBG("Scanning interfaces...\n");
+  for(;;)
+    {
+      if (last_ifbuf_size)
+       {
+         struct ifreq *r = alloca(last_ifbuf_size);
+         ic.ifc_ifcu.ifcu_req = r;
+         ic.ifc_len = last_ifbuf_size;
+         res = ioctl(if_scan_sock, SIOCGIFCONF, &ic);
+         if (res < 0 && errno != EFAULT)
+           die("SIOCCGIFCONF: %m");
+         if (res < last_ifbuf_size)
+           {
+             scan_ifs(r, ic.ifc_len);
+             break;
+           }
+       }
+      ic.ifc_ifcu.ifcu_req = NULL;
+      if (ioctl(if_scan_sock, SIOCGIFCONF, &ic) < 0)
+       die("SIOCIFCONF: %m");
+      ic.ifc_len += sizeof(struct ifreq);
+      if (last_ifbuf_size < ic.ifc_len)
+       {
+         last_ifbuf_size = ic.ifc_len;
+         DBG("Increased ifconf buffer size to %d\n", last_ifbuf_size);
+       }
+    }
+}
+
+void
+scan_if_init(void)
+{
+  if_scan_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+  DBG("Using socket %d for interface and route scanning\n", if_scan_sock);
+  if (if_scan_sock < 0)
+    die("Cannot create scanning socket: %m");
+  scan_if(NULL);
+  if_scan_timer = tm_new(&root_pool);
+  if_scan_timer->hook = scan_if;
+  if_scan_timer->recurrent = if_scan_period;
+  tm_start(if_scan_timer, if_scan_period);
+}
+