Allow txtinfo to display gateways
authorHenning Rogge <hrogge@googlemail.com>
Sat, 20 Feb 2010 16:24:51 +0000 (17:24 +0100)
committerHenning Rogge <hrogge@googlemail.com>
Sat, 20 Feb 2010 16:24:51 +0000 (17:24 +0100)
keep default inetgw route with smartgw, but add +2 to metric

lib/txtinfo/src/olsrd_txtinfo.c
src/gateway.c
src/gateway.h
src/gateway_default_handler.c
src/ipcalc.h
src/linux/kernel_routes_nl.c
src/process_routes.c

index df53063..3ce1728 100644 (file)
@@ -77,6 +77,7 @@
 #include "net_olsr.h"
 #include "lq_plugin.h"
 #include "common/autobuf.h"
+#include "gateway.h"
 
 #include "olsrd_txtinfo.h"
 #include "olsrd_plugin.h"
@@ -106,6 +107,8 @@ static void ipc_print_hna(struct autobuf *);
 
 static void ipc_print_mid(struct autobuf *);
 
+static void ipc_print_gateway(struct autobuf *);
+
 #define TXT_IPC_BUFSIZE 256
 
 #define SIW_ALL 0
@@ -116,6 +119,7 @@ static void ipc_print_mid(struct autobuf *);
 #define SIW_MID 5
 #define SIW_TOPO 6
 #define SIW_NEIGHLINK 7
+#define SIW_GATEWAY 8
 
 #define MAX_CLIENTS 3
 
@@ -310,6 +314,8 @@ ipc_action(int fd, void *data __attribute__ ((unused)), unsigned int flags __att
         send_what = SIW_MID;
       else if (0 != strstr(requ, "/topo"))
         send_what = SIW_TOPO;
+      else if (0 != strstr(requ, "/gateway"))
+        send_what = SIW_GATEWAY;
     }
   }
 
@@ -539,6 +545,60 @@ ipc_print_mid(struct autobuf *abuf)
 }
 
 static void
+ipc_print_gateway(struct autobuf *abuf)
+{
+  static const char IPV4[] = "ipv4";
+  static const char IPV4_NAT[] = "ipv4(n)";
+  static const char IPV6[] = "ipv6";
+  static const char NONE[] = "-";
+
+  struct ipaddr_str buf;
+  struct gateway_entry *gw;
+  struct lqtextbuffer lqbuf;
+
+  // Status IP ETX Hopcount Uplink-Speed Downlink-Speed ipv4/ipv4-nat/- ipv6/- ipv6-prefix/-
+  abuf_puts(abuf, "Table: Gateways\n   Gateway\tETX\tHopcnt\tUplink\tDownlnk\tIPv4\tIPv6\tPrefix\n");
+  OLSR_FOR_ALL_GATEWAY_ENTRIES(gw) {
+    char v4 = '-', v6 = '-';
+    bool autoV4 = false, autoV6 = false;
+    const char *v4type = NONE, *v6type = NONE;
+    struct tc_entry *tc;
+
+    if ((tc = olsr_lookup_tc_entry(&gw->originator)) == NULL) {
+      continue;
+    }
+
+    if (gw == olsr_get_ipv4_inet_gateway(&autoV4)) {
+      v4 = autoV4 ? 'a' : 's';
+    }
+    else if (gw->ipv4 && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit)
+        && (olsr_cnf->smart_gw_allow_nat || !gw->ipv4nat)) {
+      v4 = 'u';
+    }
+
+    if (gw == olsr_get_ipv6_inet_gateway(&autoV6)) {
+      v6 = autoV6 ? 'a' : 's';
+    }
+    else if (gw->ipv6 && olsr_cnf->ip_version == AF_INET6) {
+      v6 = 'u';
+    }
+
+    if (gw->ipv4) {
+      v4type = gw->ipv4nat ? IPV4_NAT : IPV4;
+    }
+    if (gw->ipv6) {
+      v6type = IPV6;
+    }
+
+    abuf_appendf(abuf, "%c%c %s\t%s\t%d\t%u\t%u\t%s\t%s\t%s\n",
+        v4, v6, olsr_ip_to_string(&buf, &gw->originator),
+        get_linkcost_text(tc->path_cost, true, &lqbuf), tc->hops,
+        gw->uplink, gw->downlink, v4type, v6type,
+        gw->external_prefix.prefix_len == 0 ? NONE : olsr_ip_prefix_to_string(&gw->external_prefix));
+  } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(gw)
+}
+
+static void
 txtinfo_write_data(void *foo __attribute__ ((unused))) {
   fd_set set;
   int result, i, j, max;
@@ -626,6 +686,10 @@ send_info(int send_what, int the_socket)
   if ((send_what == SIW_ALL) || (send_what == SIW_ROUTE))
     ipc_print_routes(&abuf);
 
+  /* gateways */
+  if ((send_what == SIW_ALL) || (send_what == SIW_GATEWAY))
+    ipc_print_gateway(&abuf);
+
   outbuffer[outbuffer_count] = olsr_malloc(abuf.len, "txt output buffer");
   outbuffer_size[outbuffer_count] = abuf.len;
   outbuffer_written[outbuffer_count] = 0;
index 3f868b1..e73ffe6 100644 (file)
@@ -16,6 +16,7 @@
 #include "kernel_tunnel.h"
 #include "net_os.h"
 #include "duplicate_set.h"
+#include "log.h"
 #include "gateway_default_handler.h"
 #include "gateway.h"
 
@@ -31,6 +32,7 @@ static struct gateway_entry *current_ipv4_gw, *current_ipv6_gw;
 static struct olsr_gw_handler *gw_handler;
 
 static struct olsr_iptunnel_entry *v4gw_tunnel, *v6gw_tunnel;
+static bool v4gw_choosen_external, v6gw_choosen_external;
 
 /**
  * Reconstructs an uplink/downlink speed value from the encoded
@@ -206,20 +208,15 @@ olsr_set_inet_gateway(union olsr_ip_addr *originator, bool ipv4, bool ipv6, bool
     }
   }
 
-  /* gateway missing ? */
-  if (((ipv4 && current_ipv4_gw == NULL) || (ipv6 && current_ipv6_gw == NULL))  && external) {
-    /* trigger automatic lookup if user failed */
-    olsr_trigger_inetgw_selection(ipv4, ipv6);
-  }
-
   /* handle IPv4 */
   if (oldV4 != current_ipv4_gw) {
     if ((v4gw_tunnel = olsr_os_add_ipip_tunnel(&current_ipv4_gw->originator, true)) != NULL) {
       olsr_os_inetgw_tunnel_route(v4gw_tunnel->if_index, true, true);
+      v4gw_choosen_external = external;
     }
     else {
-      // TODO handle error
-fprintf(stderr, "add tunnel failed !\n");
+      // TODO: what to do now ? Choose another one ? Fire up a timer ?
+      current_ipv4_gw = NULL;
     }
     if (oldV4 != NULL) {
       olsr_os_del_ipip_tunnel(tunnelV4);
@@ -229,10 +226,11 @@ fprintf(stderr, "add tunnel failed !\n");
   if (oldV6 != current_ipv6_gw) {
     if ((v6gw_tunnel = olsr_os_add_ipip_tunnel(&current_ipv6_gw->originator, false)) != NULL) {
       olsr_os_inetgw_tunnel_route(v6gw_tunnel->if_index, false, true);
+      v6gw_choosen_external = external;
     }
     else {
-      // TODO handle error
-fprintf(stderr, "add tunnel failed !\n");
+      // TODO: what to do now ? Choose another one ? Fire up a timer ?
+      current_ipv6_gw = NULL;
     }
     if (oldV6 != NULL) {
       olsr_os_del_ipip_tunnel(tunnelV6);
@@ -242,12 +240,25 @@ fprintf(stderr, "add tunnel failed !\n");
 }
 
 /**
- * returns the gateway_entry of the current internet gw.
- * @param ipv6 true to lookup ipv6 gateway, false to lookup ipv4
+ * returns the gateway_entry of the current ipv4 internet gw.
  * @return pointer to gateway_entry or NULL if not set
  */
-struct gateway_entry *olsr_get_inet_gateway(bool ipv6) {
-  return ipv6 ? current_ipv6_gw : current_ipv4_gw;
+struct gateway_entry *olsr_get_ipv4_inet_gateway(bool *ext) {
+  if (ext) {
+    *ext = v4gw_choosen_external;
+  }
+  return current_ipv4_gw;
+}
+
+/**
+ * returns the gateway_entry of the current ipv6 internet gw.
+ * @return pointer to gateway_entry or NULL if not set
+ */
+struct gateway_entry *olsr_get_ipv6_inet_gateway(bool *ext) {
+  if (ext) {
+    *ext = v6gw_choosen_external;
+  }
+  return current_ipv6_gw;
 }
 
 /**
index 126e6a4..8724c78 100644 (file)
@@ -76,7 +76,8 @@ void olsr_delete_gateway_entry(union olsr_ip_addr *originator, uint8_t prefixlen
 void olsr_print_gateway_entries(void);
 
 bool olsr_set_inet_gateway(union olsr_ip_addr *originator, bool ipv4, bool ipv6, bool external);
-struct gateway_entry *olsr_get_inet_gateway(bool ipv6);
+struct gateway_entry *olsr_get_ipv4_inet_gateway(bool *);
+struct gateway_entry *olsr_get_ipv6_inet_gateway(bool *);
 bool olsr_is_smart_gateway(struct olsr_ip_prefix *prefix, union olsr_ip_addr *net);
 void olsr_modifiy_inetgw_netmask(union olsr_ip_addr *mask, int prefixlen);
 
index 8461222..e78019c 100644 (file)
@@ -125,9 +125,9 @@ static void gw_default_startup_handler(void) {
 static void gw_default_update_handler(struct gateway_entry *gw) {
   bool v4changed, v6changed;
 
-  v4changed = (gw == olsr_get_inet_gateway(false))
+  v4changed = (gw == olsr_get_ipv4_inet_gateway(NULL))
       && (!gw->ipv4 || (gw->ipv4nat && !olsr_cnf->smart_gw_allow_nat));
-  v6changed = (gw == olsr_get_inet_gateway(true)) && !gw->ipv6;
+  v6changed = (gw == olsr_get_ipv6_inet_gateway(NULL)) && !gw->ipv6;
 
   if (v4changed || v6changed) {
     olsr_gw_default_lookup_gateway(v4changed, v6changed);
@@ -137,8 +137,8 @@ static void gw_default_update_handler(struct gateway_entry *gw) {
 static void gw_default_delete_handler(struct gateway_entry *gw) {
   bool isv4, isv6;
 
-  isv4 = gw == olsr_get_inet_gateway(false);
-  isv6 = gw == olsr_get_inet_gateway(true);
+  isv4 = gw == olsr_get_ipv4_inet_gateway(NULL);
+  isv6 = gw == olsr_get_ipv6_inet_gateway(NULL);
 
   if (gw != NULL && (isv4 || isv6)) {
     olsr_gw_default_lookup_gateway(isv4, isv6);
index ea4660c..dffc9da 100644 (file)
@@ -185,6 +185,12 @@ prefix_mappedv4_to_v4(struct olsr_ip_prefix *v4, const struct olsr_ip_prefix *v6
 
 
 static INLINE bool
+ip_is_linklocal(const union olsr_ip_addr *ip) {
+  return olsr_cnf->ip_version == AF_INET6
+      && ip->v6.s6_addr[0] == 0xfe && (ip->v6.s6_addr[1] & 0xc0) == 0xc0;
+}
+
+static INLINE bool
 ip_prefix_is_mappedv4(const struct olsr_ip_prefix *prefix) {
   return prefix->prefix_len >= ipv6_mappedv4_route.prefix_len
       && memcmp(prefix, &ipv6_mappedv4_route, ipv6_mappedv4_route.prefix_len / 8) == 0;
index 809514a..160c258 100644 (file)
@@ -476,6 +476,11 @@ static int olsr_os_process_rt_entry(int af_family, const struct rt_entry *rt, bo
     metric = set ? rt->rt_best->rtp_metric.hops : rt->rt_metric.hops;
   }
 
+  if (olsr_cnf->smart_gw_active && is_prefix_inetgw(&rt->rt_dst)) {
+    /* make space for the tunnel gateway route */
+    metric += 2;
+  }
+
   /* get protocol
    * 0 gets replaced by OS-specifc default (3)
    * 1 is reserved so we take 0 instead (this really makes some sense)
@@ -501,7 +506,8 @@ static int olsr_os_process_rt_entry(int af_family, const struct rt_entry *rt, bo
   hostRoute = rt->rt_dst.prefix_len == olsr_cnf->ipsize * 8
       && ipequal(&nexthop->gateway, &rt->rt_dst.prefix);
 
-  if (0) {
+#if 0
+  {
     struct ipaddr_str buf1, buf2;
     olsr_syslog(OLSR_LOG_INFO, "hostroute (%s) = %d == %d && %s == %s",
         hostRoute ? "true" : "false",
@@ -509,6 +515,7 @@ static int olsr_os_process_rt_entry(int af_family, const struct rt_entry *rt, bo
         olsr_ip_to_string(&buf1, &nexthop->gateway),
         olsr_ip_to_string(&buf2, &rt->rt_dst.prefix));
   }
+#endif
 
   /* get src ip */
   if (olsr_cnf->use_src_ip_routes) {
index e784923..e7fc23b 100644 (file)
@@ -160,10 +160,14 @@ olsr_enqueue_rt(struct list_node *head_node, struct rt_entry *rt)
 static void
 olsr_delete_kernel_route(struct rt_entry *rt)
 {
-  if (olsr_cnf->smart_gw_active && is_prefix_inetgw(&rt->rt_dst)) {
-    /* skip default route in smartgateway mode */
-    return;
+  if (rt->rt_metric.hops > 1) {
+    /* multihop route */
+    if (ip_is_linklocal(&rt->rt_dst.prefix)) {
+      /* do not delete a route with a LL IP as a destination */
+      return;
+    }
   }
+
   if (!olsr_cnf->host_emul) {
     int16_t error = olsr_cnf->ip_version == AF_INET ? olsr_delroute_function(rt) : olsr_delroute6_function(rt);
 
@@ -191,11 +195,13 @@ olsr_delete_kernel_route(struct rt_entry *rt)
 static void
 olsr_add_kernel_route(struct rt_entry *rt)
 {
-  if (olsr_cnf->smart_gw_active && is_prefix_inetgw(&rt->rt_dst)) {
-    /* skip default route in smartgateway mode */
-    return;
+  if (rt->rt_best->rtp_metric.hops > 1) {
+    /* multihop route */
+    if (ip_is_linklocal(&rt->rt_best->rtp_dst.prefix)) {
+      /* do not create a route with a LL IP as a destination */
+      return;
+    }
   }
-
   if (!olsr_cnf->host_emul) {
     int16_t error = (olsr_cnf->ip_version == AF_INET) ? olsr_addroute_function(rt) : olsr_addroute6_function(rt);