/**
 * process the kernel change list.
 * the routes are already ordered such that nexthop routes
 * are on the head of the queue.
 * non-nexthop routes need to be changed first and therefore
 * the queue needs to be traversed from tail to head.
 */
static void
olsr_chg_kernel_routes(struct list_node *head_node)
{
  struct rt_entry *rt;

  if (list_is_empty(head_node)) {
    return;
  }

  /*
   * Traverse from the beginning to the end of the list,
   * such that nexthop routes are added first.
   */
  while (!list_is_empty(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*/
#ifdef LINUX_NETLINK_ROUTING
    /*delete routes with ipv6 only as it still doesn`t support NLM_F_REPLACE*/
    if (((olsr_cnf->ip_version != AF_INET )
         || (olsr_addroute_function != olsr_ioctl_add_route) || (olsr_addroute6_function != olsr_ioctl_add_route6)
         || (olsr_delroute_function != olsr_ioctl_del_route) || (olsr_delroute6_function != olsr_ioctl_del_route6))
        && (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);
#endif /*LINUX_NETLINK_ROUTING*/

    olsr_add_kernel_route(rt);

    list_remove(&rt->rt_change_node);
  }
}
/**
 * process the kernel change list.
 * the routes are already ordered such that nexthop routes
 * are on the head of the queue.
 * non-nexthop routes need to be changed first and therefore
 * the queue needs to be traversed from tail to head.
 */
static void
olsr_chg_kernel_routes(struct list_node *head_node)
{
  struct rt_entry *rt;

  if (list_is_empty(head_node)) {
    return;
  }

  /*
   * Traverse from the beginning to the end of the list,
   * such that nexthop routes are added first.
   */
  while (!list_is_empty(head_node)) {
    rt = changelist2rt(head_node->next);

#ifdef linux
    /*
    *   actively deleting routes is not necessary as we use (NLM_F_CREATE | NLM_F_REPLACE) with linux
    *        (i.e. new routes simply overwrite the old ones in kernel)
    *   BUT: We still have to actively delete routes if fib_metric != FLAT or we run on ipv6.
    *        As NLM_F_REPLACE is not supported with IPv6, or simply of no use with varying route metrics.
    *        We also actively delete routes if custom route functions are in place. (e.g. quagga plugin)
    */
    if (((olsr_cnf->ip_version != AF_INET ) || (olsr_cnf->fib_metric != FIBM_FLAT)
         || (olsr_addroute_function != olsr_ioctl_add_route) || (olsr_addroute6_function != olsr_ioctl_add_route6)
         || (olsr_delroute_function != olsr_ioctl_del_route) || (olsr_delroute6_function != olsr_ioctl_del_route6))
        && (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);
#endif /* linux */

    olsr_add_kernel_route(rt);

    list_remove(&rt->rt_change_node);
  }
}
/**
 * Walk all the routes, remove outdated routes and run
 * best path selection on the remaining set.
 * Finally compare the nexthop of the route head and the best
 * path and enqueue an add/chg operation.
 */
void
olsr_update_rib_routes(void)
{
  struct rt_entry *rt;

  OLSR_PRINTF(3, "Updating kernel routes...\n");

  /* walk all routes in the RIB. */

  OLSR_FOR_ALL_RT_ENTRIES(rt) {

    /* eliminate first unused routes */
    olsr_delete_outdated_routes(rt);

    if (!rt->rt_path_tree.count) {

      /* oops, all routes are gone - flush the route head */
  
      if (olsr_delete_kernel_route(rt) == 0) {
        /*only remove if deletion was successful*/
        avl_delete(&routingtree, &rt->rt_tree_node);
        olsr_cookie_free(rt_mem_cookie, rt);
      }

      continue;
    }

    /* run best route election */
    olsr_rt_best(rt);

    /* nexthop or hopcount change ? */
    if (olsr_nh_change(&rt->rt_best->rtp_nexthop, &rt->rt_nexthop)
        || (FIBM_CORRECT == olsr_cnf->fib_metric && olsr_hopcount_change(&rt->rt_best->rtp_metric, &rt->rt_metric))) {

        /* this is a route add or change. */
        olsr_enqueue_rt(&chg_kernel_list, rt);
    }
  }
  OLSR_FOR_ALL_RT_ENTRIES_END(rt);
}