Add OLSR support for NIIT (IP 4to6 tunnel device)
[olsrd.git] / src / linux / kernel_routes.c
index a244887..63bc12b 100644 (file)
@@ -52,6 +52,7 @@
 #define RT_DELETE_SIMILAR_ROUTE 3
 #define RT_AUTO_ADD_GATEWAY_ROUTE 4
 #define RT_DELETE_SIMILAR_AUTO_ROUTE 5
+#define RT_NIIT 6
 
 #if !LINUX_POLICY_ROUTING
 
@@ -233,7 +234,20 @@ olsr_netlink_route_int(const struct rt_entry *rt, uint8_t family, uint8_t rttabl
   req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
   req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK;
   req.n.nlmsg_type = cmd;
-  req.r.rtm_family = family;
+  
+  /*sanity check for niit ipv4 over ipv6 routes*/
+  if (family == AF_INET && flag == RT_NIIT) {
+    olsr_syslog(OLSR_LOG_ERR,"niit makes no sense with olsrd running on ipv4!");
+    return -1;
+  }
+
+  if (flag == RT_NIIT) {
+    req.r.rtm_family=AF_INET; /*we create an ipv4 niit route*/
+  }
+  else {
+    req.r.rtm_family = family;
+  }
+
   req.r.rtm_table = rttable;
 
   /* RTN_UNSPEC would be the wildcard, but blackhole broadcast or nat roules should usually not conflict */
@@ -246,7 +260,14 @@ olsr_netlink_route_int(const struct rt_entry *rt, uint8_t family, uint8_t rttabl
   /* as wildcard for deletion */
   req.r.rtm_scope = RT_SCOPE_NOWHERE;
 
-  if ( ( cmd != RTM_NEWRULE ) && ( cmd != RTM_DELRULE ) ) {
+  if ( ( cmd == RTM_NEWRULE ) || ( cmd == RTM_DELRULE ) ) {
+    /* add or delete a rule */
+    static uint32_t priority = 65535;
+
+    req.r.rtm_scope = RT_SCOPE_UNIVERSE;
+    olsr_netlink_addreq(&req, RTA_PRIORITY, &priority, sizeof(priority));
+  }
+  else {
     req.r.rtm_dst_len = rt->rt_dst.prefix_len;
 
     /* do not specify much as we wanna delete similar/conflicting routes */
@@ -258,15 +279,25 @@ olsr_netlink_route_int(const struct rt_entry *rt, uint8_t family, uint8_t rttabl
       req.r.rtm_scope = RT_SCOPE_LINK;
 
       /*add interface*/
-      olsr_netlink_addreq(&req, RTA_OIF, &nexthop->iif_index, sizeof(nexthop->iif_index));
-
-#if SOURCE_IP_ROUTES
-      /* source ip here is based on now static olsr_cnf->main_addr in this olsr-0.5.6-r4, should be based on orignator-id in newer olsrds */
-      if (AF_INET == family) {
-        olsr_netlink_addreq(&req, RTA_PREFSRC, &olsr_cnf->main_addr.v4.s_addr, sizeof(olsr_cnf->main_addr.v4.s_addr));
+      if (flag == RT_NIIT) {
+        olsr_netlink_addreq(&req, RTA_OIF, &olsr_cnf->niit_if_index, sizeof(&olsr_cnf->niit_if_index));
       }
       else {
-        olsr_netlink_addreq(&req, RTA_PREFSRC, &olsr_cnf->main_addr.v6.s6_addr, sizeof(olsr_cnf->main_addr.v6.s6_addr));
+        olsr_netlink_addreq(&req, RTA_OIF, &nexthop->iif_index, sizeof(nexthop->iif_index));
+      }
+
+#if SOURCE_IP_ROUTES
+      /**
+       * source ip here is based on now static olsr_cnf->main_addr in this olsr-0.5.6-r4,
+       * should be based on orignator-id in newer olsrds
+       **/
+      if (flag != RT_NIIT) {
+        if (AF_INET == family) {
+          olsr_netlink_addreq(&req, RTA_PREFSRC, &olsr_cnf->main_addr.v4.s_addr, sizeof(olsr_cnf->main_addr.v4.s_addr));
+        }
+        else {
+          olsr_netlink_addreq(&req, RTA_PREFSRC, &olsr_cnf->main_addr.v6.s6_addr, sizeof(olsr_cnf->main_addr.v6.s6_addr));
+        }
       }
 #endif
     }
@@ -281,10 +312,12 @@ olsr_netlink_route_int(const struct rt_entry *rt, uint8_t family, uint8_t rttabl
       req.r.rtm_dst_len = olsr_cnf->maxplen;
     }
 
-    /* for ipv4 or ipv6 we add gateway if one is specified, 
-    * or leave gateway away if we want to delete similar routes aswell, 
-    * or even use the gateway as target if we add a auto-generated route, 
-    * or if delete-similar to make insertion of auto-generated route possible */
+    /**
+     * for ipv4 or ipv6 we add gateway if one is specified,
+     * or leave gateway away if we want to delete similar routes aswell,
+     * or even use the gateway as target if we add a auto-generated route,
+     * or if delete-similar to make insertion of auto-generated route possible
+     **/
     if (AF_INET == family) {
       if ( ( flag != RT_AUTO_ADD_GATEWAY_ROUTE ) && (flag != RT_DELETE_SIMILAR_ROUTE) && 
            ( flag != RT_DELETE_SIMILAR_AUTO_ROUTE) && (rt->rt_dst.prefix.v4.s_addr != nexthop->gateway.v4.s_addr) ) {
@@ -294,20 +327,25 @@ olsr_netlink_route_int(const struct rt_entry *rt, uint8_t family, uint8_t rttabl
       olsr_netlink_addreq(&req, RTA_DST, ( (flag == RT_AUTO_ADD_GATEWAY_ROUTE) || (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) ) ? 
                           &nexthop->gateway.v4 : &rt->rt_dst.prefix.v4, sizeof(rt->rt_dst.prefix.v4));
     } else {
-      if ( ( flag != RT_AUTO_ADD_GATEWAY_ROUTE ) && (flag != RT_DELETE_SIMILAR_ROUTE ) && ( flag != RT_DELETE_SIMILAR_AUTO_ROUTE) 
-          && (0 != memcmp(&rt->rt_dst.prefix.v6, &nexthop->gateway.v6, sizeof(nexthop->gateway.v6))) ) {
-        olsr_netlink_addreq(&req, RTA_GATEWAY, &nexthop->gateway.v6, sizeof(nexthop->gateway.v6));
-        req.r.rtm_scope = RT_SCOPE_UNIVERSE;
+      if (flag == RT_NIIT) {
+        union olsr_ip_addr ipv4_addr;
+        /* create an ipv4 route */
+        olsr_syslog(OLSR_LOG_ERR,"niit suport not fully implemented!!"); 
+
+        /* fix prefix length */
+        req.r.rtm_dst_len = rt->rt_dst.prefix_len - 96;
+        olsr_netlink_addreq(&req, RTA_DST, olsr_ipv6_to_ipv4(&rt->rt_dst.prefix, &ipv4_addr), sizeof(ipv4_addr.v4));
+      }
+      else {
+        if ( ( flag != RT_AUTO_ADD_GATEWAY_ROUTE ) && (flag != RT_DELETE_SIMILAR_ROUTE ) && ( flag != RT_DELETE_SIMILAR_AUTO_ROUTE) 
+            && (0 != memcmp(&rt->rt_dst.prefix.v6, &nexthop->gateway.v6, sizeof(nexthop->gateway.v6))) ) {
+          olsr_netlink_addreq(&req, RTA_GATEWAY, &nexthop->gateway.v6, sizeof(nexthop->gateway.v6));
+          req.r.rtm_scope = RT_SCOPE_UNIVERSE;
+        }
+        olsr_netlink_addreq(&req, RTA_DST, ( (flag == RT_AUTO_ADD_GATEWAY_ROUTE) || (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) ) ? 
+                            &nexthop->gateway.v6 : &rt->rt_dst.prefix.v6, sizeof(rt->rt_dst.prefix.v6));
       }
-      olsr_netlink_addreq(&req, RTA_DST, ( (flag == RT_AUTO_ADD_GATEWAY_ROUTE) || (flag == RT_DELETE_SIMILAR_AUTO_ROUTE) ) ? 
-                          &nexthop->gateway.v6 : &rt->rt_dst.prefix.v6, sizeof(rt->rt_dst.prefix.v6));
     }
-  } else {
-    /* add or delete a rule */
-    static uint32_t priority = 65535;
-
-    req.r.rtm_scope = RT_SCOPE_UNIVERSE;
-    olsr_netlink_addreq(&req, RTA_PRIORITY, &priority, sizeof(priority));
   }
 
   iov.iov_base = &req.n;
@@ -343,6 +381,9 @@ olsr_netlink_route_int(const struct rt_entry *rt, uint8_t family, uint8_t rttabl
               else if ( cmd == RTM_DELRULE ) {
                 olsr_syslog(OLSR_LOG_ERR,"Error '%s' (%d) on deleting empty policy rule aimed to activate rtTable %u!", err_msg, errno, rttable);
               }
+              else if ( flag == RT_NIIT ) {
+                olsr_syslog(OLSR_LOG_ERR,"Error '%s' (%d) on manipulating niit route of %s!", err_msg, errno, olsr_ip_to_string(&ibuf,&rt->rt_dst.prefix));
+              }
               else if ( flag <= RT_RETRY_AFTER_DELETE_SIMILAR ) {
                 if (rt->rt_dst.prefix.v4.s_addr!=nexthop->gateway.v4.s_addr) {
                   olsr_syslog(OLSR_LOG_ERR, "error '%s' (%d) %s route to %s/%d via %s dev %s",
@@ -509,6 +550,11 @@ olsr_netlink_rule(uint8_t family, uint8_t rttable, uint16_t cmd)
 static int
 olsr_netlink_route(const struct rt_entry *rt, uint8_t family, uint8_t rttable, __u16 cmd)
 {
+  /*create/delete niit route if we have an niit device*/
+  if ((olsr_cnf->niit_if_index!=0) && (family != AF_INET) && (olsr_is_niit_ip(&rt->rt_dst.prefix))) {
+    olsr_netlink_route_int(rt, family, rttable, cmd, RT_NIIT);
+  }
+
   return olsr_netlink_route_int(rt, family, rttable, cmd, RT_ORIG_REQUEST);
 }