Dynamic NIIT support
authorHenning Rogge <hrogge@googlemail.com>
Sat, 6 Feb 2010 11:00:56 +0000 (12:00 +0100)
committerHenning Rogge <hrogge@googlemail.com>
Sat, 6 Feb 2010 11:00:56 +0000 (12:00 +0100)
src/cfgparser/olsrd_conf.c
src/ipcalc.c
src/ipcalc.h
src/kernel_routes.h
src/linux/kernel_routes.c
src/main.c
src/olsr_niit.c
src/olsr_niit.h
src/process_routes.c

index 63e86cd..d78acc7 100644 (file)
@@ -821,8 +821,8 @@ static void update_has_gateway_fields(void) {
   olsr_cnf->has_ipv6_gateway = false;
 
   for (h = olsr_cnf->hna_entries; h != NULL; h = h->next) {
-    olsr_cnf->has_ipv4_gateway |= ip_prefix_is_v4_gw(&h->net) || ip_prefix_is_mappedv4_gw(&h->net);
-    olsr_cnf->has_ipv6_gateway |= ip_prefix_is_v6_gw(&h->net);
+    olsr_cnf->has_ipv4_gateway |= ip_prefix_is_v4_inetgw(&h->net) || ip_prefix_is_mappedv4_inetgw(&h->net);
+    olsr_cnf->has_ipv6_gateway |= ip_prefix_is_v6_inetgw(&h->net);
   }
 }
 
index d40399f..e17fb50 100644 (file)
@@ -212,13 +212,13 @@ ip_in_net(const union olsr_ip_addr *ipaddr, const struct olsr_ip_prefix *net)
 }
 
 bool is_prefix_inetgw(const struct olsr_ip_prefix *prefix) {
-  if (ip_prefix_is_v4_gw(prefix)) {
+  if (ip_prefix_is_v4_inetgw(prefix)) {
     return true;
   }
-  if (ip_prefix_is_v6_gw(prefix)) {
+  if (ip_prefix_is_v6_inetgw(prefix)) {
     return true;
   }
-  return ip_prefix_is_mappedv4_gw(prefix);
+  return ip_prefix_is_mappedv4_inetgw(prefix);
 }
 
 /*
index 6a1880b..97bd6c9 100644 (file)
@@ -171,30 +171,39 @@ prefix_to_netmask4(uint8_t prefixlen)
 
 static INLINE bool
 is_prefix_niit_ipv6(const struct olsr_ip_prefix *p) {
-  return olsr_cnf->ip_version == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&p->prefix.v6) && p->prefix_len >= 96;
+  return olsr_cnf->ip_version == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&p->prefix.v6)
+      && p->prefix_len >= mapped_v4_gw.prefix_len;
 }
 
 static INLINE struct olsr_ip_prefix *
 prefix_mappedv4_to_v4(struct olsr_ip_prefix *v4, const struct olsr_ip_prefix *v6) {
   memcpy(&v4->prefix.v4, &v6->prefix.v6.s6_addr[12], sizeof(struct in_addr));
-  v4->prefix_len = v6->prefix_len - 96;
+      v4->prefix_len = v6->prefix_len - 96;
   return v4;
 }
 
 
 static INLINE bool
-ip_prefix_is_mappedv4_gw(const struct olsr_ip_prefix *prefix) {
-  return olsr_cnf->ip_version == AF_INET6 && memcmp(prefix, &mapped_v4_gw, sizeof(struct olsr_ip_prefix)) == 0;
+ip_prefix_is_mappedv4(const struct olsr_ip_prefix *prefix) {
+  return prefix->prefix_len >= mapped_v4_gw.prefix_len
+      && memcmp(prefix, &mapped_v4_gw, mapped_v4_gw.prefix_len / 8) == 0;
 }
 
 static INLINE bool
-ip_prefix_is_v4_gw(const struct olsr_ip_prefix *prefix) {
+ip_prefix_is_mappedv4_inetgw(const struct olsr_ip_prefix *prefix) {
+  return olsr_cnf->ip_version == AF_INET6 && prefix->prefix_len == mapped_v4_gw.prefix_len
+      && memcmp(prefix, &mapped_v4_gw, mapped_v4_gw.prefix_len / 8) == 0;
+}
+
+static INLINE bool
+ip_prefix_is_v4_inetgw(const struct olsr_ip_prefix *prefix) {
   return olsr_cnf->ip_version == AF_INET && prefix->prefix_len == 0 && prefix->prefix.v4.s_addr == 0;
 }
 
 static INLINE bool
-ip_prefix_is_v6_gw(const struct olsr_ip_prefix *prefix) {
-  return olsr_cnf->ip_version == AF_INET6 && memcmp(prefix, &ipv6_internet_route, sizeof(struct olsr_ip_prefix)) == 0;
+ip_prefix_is_v6_inetgw(const struct olsr_ip_prefix *prefix) {
+  return olsr_cnf->ip_version == AF_INET6 && prefix->prefix_len == ipv6_internet_route.prefix_len
+      && memcmp(prefix, &ipv6_internet_route, ipv6_internet_route.prefix_len/8) == 0;
 }
 
 extern bool is_prefix_inetgw(const struct olsr_ip_prefix *prefix);
index f191fc2..a803f1e 100644 (file)
@@ -56,9 +56,10 @@ int olsr_ioctl_del_route6(const struct rt_entry *);
 #if LINUX_POLICY_ROUTING
 static const char TUNL_BASE[IFNAMSIZ] = "tunl0";
 
-int olsr_netlink_static_niit_routes(const struct olsr_ip_prefix *route, bool set);
+void olsr_os_niit_4to6_route(const struct olsr_ip_prefix *dst_v4, bool set);
+void olsr_os_niit_6to4_route(const struct olsr_ip_prefix *dst_v6, bool set);
 
-int olsr_netlink_rule(int family, int rttable, uint32_t priority, const char *if_name, bool set);
+int olsr_os_policy_rule(int family, int rttable, uint32_t priority, const char *if_name, bool set);
 
 int olsr_del_tunl(void);
 
index 91c1767..373aff7 100644 (file)
@@ -347,7 +347,7 @@ olsr_netlink_send(struct nlmsghdr *nl_hdr)
   return -l_err->error;
 }
 
-int olsr_netlink_rule(int family, int rttable, uint32_t priority, const char *if_name, bool set) {
+int olsr_os_policy_rule(int family, int rttable, uint32_t priority, const char *if_name, bool set) {
   struct olsr_rtreq req;
   int err;
 
@@ -412,7 +412,7 @@ int olsr_new_netlink_route(int family, int rttable, int if_index, int metric, in
   req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
   req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
   if (set) {
-    req.n.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
+    req.n.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
   }
 
   req.n.nlmsg_type = set ? RTM_NEWROUTE : RTM_DELROUTE;
@@ -485,35 +485,21 @@ int olsr_new_netlink_route(int family, int rttable, int if_index, int metric, in
   return err;
 }
 
-int olsr_netlink_static_niit_routes(const struct olsr_ip_prefix *route, bool set) {
-  int err;
-  if (!is_prefix_niit_ipv6(route)) {
-    return 0;
-  }
-
+void olsr_os_niit_6to4_route(const struct olsr_ip_prefix *dst_v6, bool set) {
   /* TODO: in welche Table kommen die NIIT-Routen ? ne eigene ? */
-  err = olsr_new_netlink_route(AF_INET6, olsr_cnf->rttable, olsr_cnf->niit6to4_if_index,
-      RT_METRIC_DEFAULT, RTPROT_BOOT, NULL, NULL, route, set, false);
-  if (err) {
+  if (olsr_new_netlink_route(AF_INET6, olsr_cnf->rttable, olsr_cnf->niit6to4_if_index,
+      RT_METRIC_DEFAULT, RTPROT_BOOT, NULL, NULL, dst_v6, set, false)) {
     olsr_syslog(OLSR_LOG_ERR, ". error while %s static niit route to %s",
-        set ? "setting" : "removing", olsr_ip_prefix_to_string(route));
+        set ? "setting" : "removing", olsr_ip_prefix_to_string(dst_v6));
   }
-  return err;
 }
 
-static void olsr_netlink_process_niit(const struct rt_entry *rt, bool set) {
-  struct olsr_ip_prefix dst_v4;
-  if (!olsr_cnf->use_niit || !is_prefix_niit_ipv6(&rt->rt_dst)) {
-    return;
-  }
-
-  prefix_mappedv4_to_v4(&dst_v4, &rt->rt_dst);
-
+void olsr_os_niit_4to6_route(const struct olsr_ip_prefix *dst_v4, bool set) {
   /* TODO: in welche Table kommen die NIIT-Routen ? ne eigene ? */
   if (olsr_new_netlink_route(AF_INET, olsr_cnf->rttable, olsr_cnf->niit4to6_if_index,
-      RT_METRIC_DEFAULT, RTPROT_BOOT, NULL, NULL, &dst_v4, set, false)) {
+      RT_METRIC_DEFAULT, RTPROT_BOOT, NULL, NULL, dst_v4, set, false)) {
     olsr_syslog(OLSR_LOG_ERR, ". error while %s niit route to %s",
-        set ? "setting" : "removing", olsr_ip_prefix_to_string(&dst_v4));
+        set ? "setting" : "removing", olsr_ip_prefix_to_string(dst_v4));
   }
 }
 
@@ -533,9 +519,6 @@ static int olsr_os_process_rt_entry(int af_family, const struct rt_entry *rt, bo
   bool hostRoute;
   int err;
 
-  /* handle NIIT special case */
-  olsr_netlink_process_niit(rt, set);
-
   /* handle smart gateway case */
   if (olsr_netlink_process_smartgw(rt, set)) {
     /* skip inetgw routes if smartgw is active */
@@ -1023,7 +1006,7 @@ olsr_netlink_route_int(const struct rt_entry *rt, uint8_t family, uint8_t rttabl
 
 /* external wrapper function for above patched multi purpose rtnetlink function */
 int
-olsr_netlink_rule(uint8_t family, uint8_t rttable, uint16_t cmd, uint32_t priority, char* dev)
+olsr_os_policy_rule(uint8_t family, uint8_t rttable, uint16_t cmd, uint32_t priority, char* dev)
 {
   return olsr_netlink_route_int((const struct rt_entry *) dev, family, rttable, cmd, priority);
 }
@@ -1294,7 +1277,7 @@ olsr_ioctl_del_route6(const struct rt_entry *rt)
 
   return rslt;
 #else /* !LINUX_POLICY_ROUTING */
-  return olsr_os_process_rt_entry(AF_INET, rt, false);
+  return olsr_os_process_rt_entry(AF_INET6, rt, false);
 #endif /* LINUX_POLICY_ROUTING */
 }
 
index fe7cfe0..08334ea 100644 (file)
@@ -581,21 +581,21 @@ printf("\nMain Table is %i prio %i", olsr_cnf->rttable, olsr_cnf->rttable_rule);
 
       /*table with default routes for olsr interfaces*/
       for (cfg_if = olsr_cnf->interfaces; cfg_if; cfg_if = cfg_if->next) {
-        olsr_netlink_rule(olsr_cnf->ip_version, olsr_cnf->rttable_default,
+        olsr_os_policy_rule(olsr_cnf->ip_version, olsr_cnf->rttable_default,
             olsr_cnf->rttable_default_rule, cfg_if->name, true);
       }
       /*table with route into tunnel (for all interfaces)*/
-      olsr_netlink_rule(olsr_cnf->ip_version, olsr_cnf->rttable_smartgw,
+      olsr_os_policy_rule(olsr_cnf->ip_version, olsr_cnf->rttable_smartgw,
                         olsr_cnf->rttable_smartgw_rule, NULL, true);
       /*backup rule to default route table (if tunnel table gets empty)*/
-      olsr_netlink_rule(olsr_cnf->ip_version, olsr_cnf->rttable_default,
+      olsr_os_policy_rule(olsr_cnf->ip_version, olsr_cnf->rttable_default,
                         olsr_cnf->rttable_backup_rule, NULL, true);
     }
   }
 
   /* Create rule for RtTable to resolve route insertion problems*/
   if ((olsr_cnf->rttable < 253) & (olsr_cnf->rttable > 0)) {
-    olsr_netlink_rule(olsr_cnf->ip_version, olsr_cnf->rttable, (olsr_cnf->rttable_rule>0?olsr_cnf->rttable_rule:65535), NULL, true);
+    olsr_os_policy_rule(olsr_cnf->ip_version, olsr_cnf->rttable, (olsr_cnf->rttable_rule>0?olsr_cnf->rttable_rule:65535), NULL, true);
   }
 
   /* Create rtnetlink socket to listen on interface change events RTMGRP_LINK and RTMGRP_IPV4_ROUTE */
@@ -803,13 +803,13 @@ static void olsr_shutdown(int signo __attribute__ ((unused)))
   if (olsr_cnf->rttable_default_rule>0) {
     struct olsr_if * cfg_if;
     for (cfg_if = olsr_cnf->interfaces; cfg_if; cfg_if = cfg_if->next) {
-      olsr_netlink_rule(olsr_cnf->ip_version, olsr_cnf->rttable_default, olsr_cnf->rttable_default_rule, cfg_if->name, false);
+      olsr_os_policy_rule(olsr_cnf->ip_version, olsr_cnf->rttable_default, olsr_cnf->rttable_default_rule, cfg_if->name, false);
     }
   }
   if (olsr_cnf->rttable_smartgw_rule>0)
-    olsr_netlink_rule(olsr_cnf->ip_version, olsr_cnf->rttable_smartgw, olsr_cnf->rttable_smartgw_rule, NULL, false);
+    olsr_os_policy_rule(olsr_cnf->ip_version, olsr_cnf->rttable_smartgw, olsr_cnf->rttable_smartgw_rule, NULL, false);
   if (olsr_cnf->rttable_backup_rule>0)
-    olsr_netlink_rule(olsr_cnf->ip_version, olsr_cnf->rttable_default, olsr_cnf->rttable_backup_rule, NULL, false);
+    olsr_os_policy_rule(olsr_cnf->ip_version, olsr_cnf->rttable_default, olsr_cnf->rttable_backup_rule, NULL, false);
 
   /*tunl0*/
   if (olsr_cnf->ipip_base_orig_down) {
@@ -819,7 +819,7 @@ static void olsr_shutdown(int signo __attribute__ ((unused)))
 
   /* RtTable backup rule */
   if ((olsr_cnf->rttable < 253) & (olsr_cnf->rttable > 0)) {
-    olsr_netlink_rule(olsr_cnf->ip_version, olsr_cnf->rttable, (olsr_cnf->rttable_rule?olsr_cnf->rttable_rule:65535), NULL, false);
+    olsr_os_policy_rule(olsr_cnf->ip_version, olsr_cnf->rttable, (olsr_cnf->rttable_rule?olsr_cnf->rttable_rule:65535), NULL, false);
   }
 
   close(olsr_cnf->rtnl_s);
index 6bb4d2f..738b995 100644 (file)
 
 #include <net/if.h>
 
+static void handle_niit_ifchange (int if_index, struct interface *iface, enum olsr_ifchg_flag);
+
+static bool niit4to6_active, niit6to4_active;
+
 #ifdef linux
-int olsr_init_niit(void) {
+void olsr_init_niit(void) {
+  if (olsr_cnf->ip_version == AF_INET) {
+    olsr_cnf->use_niit = false;
+    return;
+  }
+
   olsr_cnf->niit4to6_if_index = if_nametoindex(DEF_NIIT4TO6_IFNAME);
-  if (olsr_cnf->niit4to6_if_index <= 0 || !olsr_if_isup(DEF_NIIT4TO6_IFNAME)) {
+  if (olsr_cnf->niit4to6_if_index <= 0) {
     OLSR_PRINTF(1, "Warning, %s device is not available, deactivating NIIT\n", DEF_NIIT4TO6_IFNAME);
     olsr_cnf->use_niit = false;
-    return 0;
+    return;
   }
   olsr_cnf->niit6to4_if_index = if_nametoindex(DEF_NIIT6TO4_IFNAME);
-  if (olsr_cnf->niit6to4_if_index <= 0 || !olsr_if_isup(DEF_NIIT6TO4_IFNAME)) {
+  if (olsr_cnf->niit6to4_if_index <= 0) {
     OLSR_PRINTF(1, "Warning, %s device is not available, deactivating NIIT\n", DEF_NIIT6TO4_IFNAME);
     olsr_cnf->use_niit = false;
-    return 0;
+    return;
   }
-  return 0;
+
+  niit4to6_active = olsr_if_isup(DEF_NIIT4TO6_IFNAME);
+  niit6to4_active = olsr_if_isup(DEF_NIIT6TO4_IFNAME);
+
+  olsr_add_ifchange_handler(&handle_niit_ifchange);
+  olsr_add_ifchange_handler(&handle_niit_ifchange);
+  return;
 }
 
 void olsr_setup_niit_routes(void) {
   struct ip_prefix_list *h;
+
+  if (!niit4to6_active || !niit6to4_active) {
+    return;
+  }
   for (h = olsr_cnf->hna_entries; h != NULL; h = h->next) {
-    olsr_netlink_static_niit_routes(&h->net, true);
+    if (ip_prefix_is_mappedv4(&h->net)) {
+      olsr_os_niit_6to4_route(&h->net, true);
+    }
   }
 }
 
 void olsr_cleanup_niit_routes(void) {
   struct ip_prefix_list *h;
+
+  if (!niit6to4_active) {
+    return;
+  }
   for (h = olsr_cnf->hna_entries; h != NULL; h = h->next) {
-    olsr_netlink_static_niit_routes(&h->net, false);
+    if (ip_prefix_is_mappedv4(&h->net)) {
+      olsr_os_niit_6to4_route(&h->net, false);
+    }
+  }
+}
+
+void olsr_niit_handle_route(const struct rt_entry *rt, bool set) {
+  if (olsr_cnf->ip_version == AF_INET6 && olsr_cnf->use_niit
+      && niit4to6_active && niit6to4_active && is_prefix_niit_ipv6(&rt->rt_dst)) {
+    struct olsr_ip_prefix dst_v4;
+
+    prefix_mappedv4_to_v4(&dst_v4, &rt->rt_dst);
+    olsr_os_niit_4to6_route(&dst_v4, set);
   }
 }
+
+static void refresh_niit4to6_routes(bool set) {
+  struct rt_entry *rt;
+
+  if (set && (!niit4to6_active || !niit6to4_active)) {
+    return;
+  }
+  if (!set && !niit4to6_active) {
+    return;
+  }
+
+  OLSR_FOR_ALL_RT_ENTRIES(rt) {
+    if (is_prefix_niit_ipv6(&rt->rt_dst)) {
+      struct olsr_ip_prefix dst_v4;
+
+      prefix_mappedv4_to_v4(&dst_v4, &rt->rt_dst);
+      olsr_os_niit_4to6_route(&dst_v4, set);
+    }
+  } OLSR_FOR_ALL_RT_ENTRIES_END(rt)
+}
+
+static void handle_niit_ifchange (int if_index, struct interface *iface __attribute__ ((unused)),
+    enum olsr_ifchg_flag flag) {
+  bool active;
+
+  active = niit4to6_active && niit6to4_active;
+  if (if_index == olsr_cnf->niit4to6_if_index) {
+    niit4to6_active = flag != IFCHG_IF_REMOVE;
+  }
+  if (if_index == olsr_cnf->niit6to4_if_index) {
+    niit6to4_active = flag != IFCHG_IF_REMOVE;
+  }
+
+  if (active != (niit4to6_active && niit6to4_active)) {
+    /* niit status change */
+    if (!active) {
+      /* from inactive to active */
+      olsr_setup_niit_routes();
+      refresh_niit4to6_routes(true);
+    }
+    else {
+      /* the other way around */
+      olsr_cleanup_niit_routes();
+      refresh_niit4to6_routes(false);
+    }
+  }
+
+}
 #endif
index 64d0bf1..4e087a0 100644 (file)
 #define DEF_NIIT6TO4_IFNAME         "niit6to4"
 
 #ifdef linux
-int olsr_init_niit(void);
+void olsr_init_niit(void);
 void olsr_setup_niit_routes(void);
 void olsr_cleanup_niit_routes(void);
+
+void olsr_niit_handle_route(const struct rt_entry *rt, bool set);
 #endif
 
 #endif /* OLSR_NIIT_H_ */
index c64c31c..0461844 100644 (file)
@@ -52,6 +52,7 @@
 #include "net_olsr.h"
 #include "tc_set.h"
 #include "olsr_cookie.h"
+#include "olsr_niit.h"
 
 #ifdef WIN32
 char *StrError(unsigned int ErrNo);
@@ -169,6 +170,14 @@ olsr_delete_kernel_route(struct rt_entry *rt)
 
       olsr_syslog(OLSR_LOG_ERR, "Delete route %s: %s", routestr, err_msg);
     }
+    else {
+#ifdef linux
+      /* call NIIT handler */
+      if (olsr_cnf->use_niit) {
+        olsr_niit_handle_route(rt, false);
+      }
+#endif
+    }
   }
 }
 
@@ -191,12 +200,18 @@ olsr_add_kernel_route(struct rt_entry *rt)
 
       olsr_syslog(OLSR_LOG_ERR, "Add route %s: %s", routestr, err_msg);
     } else {
-
       /* route addition has suceeded */
 
       /* save the nexthop and metric in the route entry */
       rt->rt_nexthop = rt->rt_best->rtp_nexthop;
       rt->rt_metric = rt->rt_best->rtp_metric;
+
+#ifdef linux
+      /* call NIIT handler */
+      if (olsr_cnf->use_niit) {
+        olsr_niit_handle_route(rt, true);
+      }
+#endif
     }
   }
 }
@@ -225,12 +240,14 @@ olsr_chg_kernel_routes(struct list_node *head_node)
     rt = changelist2rt(head_node->next);
 
 /*deleting routes should not be required anymore as we use (NLM_F_CREATE | NLM_F_REPLACE) in linux rtnetlink*/
-#if !LINUX_POLICY_ROUTING
+#if LINUX_POLICY_ROUTING
+    /*delete routes with ipv6 only as it still doesn`t support NLM_F_REPLACE*/
+    if ((olsr_cnf->ip_version != AF_INET ) && (rt->rt_nexthop.iif_index > -1)) {
+      olsr_delete_kernel_route(rt);
+    }
+#else
     /*no rtnetlink we have to delete routes*/
     if (rt->rt_nexthop.iif_index > -1) olsr_delete_kernel_route(rt);
-#else
-    /*delete routes with ipv6 only as it still doesn`t support NLM_F_REPLACE*/
-    if ((family != AF_INET ) && (rt->rt_nexthop.iif_index > -1)) olsr_delete_kernel_route(rt);
 #endif
 
     olsr_add_kernel_route(rt);