]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #1515 from donaldsharp/selected_to_front1
authorRenato Westphal <renato@openbsd.org>
Tue, 19 Dec 2017 16:09:03 +0000 (14:09 -0200)
committerGitHub <noreply@github.com>
Tue, 19 Dec 2017 16:09:03 +0000 (14:09 -0200)
Store selected_fib as a pointer off of rib_dest_t

1  2 
configure.ac
zebra/rib.h
zebra/zebra_rib.c
zebra/zebra_vty.c

diff --combined configure.ac
index a2606eff871922ad46aa1c3ef28ac53ca9ca27ab,cd0aab1adf21b1ae3e79699512da33202d417822..a3b38559e55fa054d5fd14fc6aa20de3ffd32a7e
@@@ -40,7 -40,7 +40,7 @@@ AS_IF([test "$host" != "$build"], 
    ( CPPFLAGS="$HOST_CPPFLAGS"; \
      CFLAGS="$HOST_CFLAGS"; \
      LDFLAGS="$HOST_LDFLAGS"; \
 -    cd hosttools; "${abssrc}/configure" "--host=$build" "--build=$build"; )
 +    cd hosttools; "${abssrc}/configure" "--host=$build" "--build=$build" "--enable-clippy-only" "--disable-nhrpd" "--disable-vtysh"; )
  
    AC_MSG_NOTICE([...])
    AC_MSG_NOTICE([... cross-compilation: finished self-configuring for build platform tools])
@@@ -354,8 -354,6 +354,8 @@@ AC_ARG_ENABLE(logfile_mask
    AS_HELP_STRING([--enable-logfile-mask=ARG], [set mask for log files]))
  AC_ARG_ENABLE(shell_access,
    AS_HELP_STRING([--enable-shell-access], [Allow users to access shell/telnet/ssh]))
 +AC_ARG_ENABLE(realms,
 +  AS_HELP_STRING([--enable-realms], [enable REALMS support under Linux]))
  AC_ARG_ENABLE(rtadv,
    AS_HELP_STRING([--disable-rtadv], [disable IPV6 router advertisement feature]))
  AC_ARG_ENABLE(irdp,
@@@ -394,10 -392,7 +394,10 @@@ AC_ARG_ENABLE([oldvpn_commands]
    AS_HELP_STRING([--enable-oldvpn-commands], [Keep old vpn commands]))
  AC_ARG_ENABLE(rpki,
    AS_HELP_STRING([--enable-rpki], [enable RPKI prefix validation support]))
 +AC_ARG_ENABLE([clippy-only],
 +  AS_HELP_STRING([--enable-clippy-only], [Only build clippy]))
  
 +AS_IF([test "${enable_clippy_only}" != "yes"], [
  AC_CHECK_HEADERS(json-c/json.h)
  AC_CHECK_LIB(json-c, json_object_get, LIBS="$LIBS -ljson-c", [], [-lm])
  if test $ac_cv_lib_json_c_json_object_get = no; then
        AC_MSG_ERROR([lib json is needed to compile])
    fi
  fi
 +])
  
  AC_ARG_ENABLE([dev_build],
      AS_HELP_STRING([--enable-dev-build], [build for development]))
@@@ -881,6 -875,7 +881,7 @@@ case "$host_os" i
  
      AC_DEFINE(OPEN_BSD,,OpenBSD)
      AC_DEFINE(KAME,1,KAME IPv6)
+     AC_DEFINE(BSD_V6_SYSCTL,1,BSD v6 sysctl to turn on and off forwarding)
  
      if test "x${enable_pimd}" != "xno"; then
        case "$host_os" in
  
      AC_DEFINE(HAVE_NET_RT_IFLIST,,NET_RT_IFLIST)
      AC_DEFINE(KAME,1,KAME IPv6)
+     AC_DEFINE(BSD_V6_SYSCTL,1,BSD v6 sysctl to turn on and off forwarding)
      ;;
  esac
  AM_CONDITIONAL(SOLARIS, test "${SOLARIS}" = "solaris")
  
  AC_SYS_LARGEFILE
  
 +dnl ------------------------
 +dnl Integrated REALMS option
 +dnl ------------------------
 +if test "${enable_realms}" = "yes"; then
 +    case "$host_os" in
 +      linux*)
 +       AC_DEFINE(SUPPORT_REALMS,, Realms support)
 +       ;;
 +      *)
 +       echo "Sorry, only Linux has REALMS support"
 +       exit 1
 +       ;;
 +    esac
 +fi
 +AM_CONDITIONAL([SUPPORT_REALMS], [test "${enable_realms}" = "yes"])
 +
  dnl ---------------------
  dnl Integrated VTY option
  dnl ---------------------
diff --combined zebra/rib.h
index 7e166f7e1ca48fcd6f97412ae89b4f2501865a4f,6027385cace468669a52a780e558bd563e0b248f..804372f18e1157037188a3faf25abc90ea528edb
@@@ -85,8 -85,7 +85,7 @@@ struct route_entry 
  /* to simplify NHT logic when NHs change, instead of doing a NH by NH cmp */
  #define ROUTE_ENTRY_NEXTHOPS_CHANGED 0x2
  #define ROUTE_ENTRY_CHANGED          0x4
- #define ROUTE_ENTRY_SELECTED_FIB     0x8
- #define ROUTE_ENTRY_LABELS_CHANGED   0x10
+ #define ROUTE_ENTRY_LABELS_CHANGED   0x8
  
        /* Nexthop information. */
        u_char nexthop_num;
@@@ -122,6 -121,8 +121,8 @@@ typedef struct rib_dest_t_ 
         */
        struct route_entry *routes;
  
+       struct route_entry *selected_fib;
        /*
         * Flags, see below.
         */
@@@ -296,7 -297,7 +297,7 @@@ extern int rib_add(afi_t afi, safi_t sa
                   u_short instance, int flags, struct prefix *p,
                   struct prefix_ipv6 *src_p, const struct nexthop *nh,
                   u_int32_t table_id, u_int32_t metric, u_int32_t mtu,
 -                 uint8_t distance);
 +                 uint8_t distance, route_tag_t tag);
  
  extern int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *,
                             struct prefix_ipv6 *src_p, struct route_entry *);
@@@ -435,8 -436,4 +436,8 @@@ static inline void rib_tables_iter_clea
  DECLARE_HOOK(rib_update, (struct route_node * rn, const char *reason),
             (rn, reason))
  
 +
 +extern void zebra_vty_init(void);
 +extern pid_t pid;
 +
  #endif /*_ZEBRA_RIB_H */
diff --combined zebra/zebra_rib.c
index 6406386b1ac0470c4480e4e5a3b492a6ce6dbdac,603d90b5992dc9a48d6abf4fc6e3aa13db9abf60..3eaf5597b2d4f1f1db3a874628d5be72700d1882
@@@ -383,10 -383,11 +383,11 @@@ static int nexthop_active(afi_t afi, st
        struct prefix p;
        struct route_table *table;
        struct route_node *rn;
-       struct route_entry *match;
+       struct route_entry *match = NULL;
        int resolved;
        struct nexthop *newhop;
        struct interface *ifp;
+       rib_dest_t *dest;
  
        if ((nexthop->type == NEXTHOP_TYPE_IPV4)
            || nexthop->type == NEXTHOP_TYPE_IPV6)
                    && !nh_resolve_via_default(p.family))
                        return 0;
  
-               RNODE_FOREACH_RE (rn, match) {
-                       if (CHECK_FLAG(match->status, ROUTE_ENTRY_REMOVED))
-                               continue;
-                       /* if the next hop is imported from another table, skip
-                        * it */
-                       if (match->type == ZEBRA_ROUTE_TABLE)
-                               continue;
-                       if (CHECK_FLAG(match->status, ROUTE_ENTRY_SELECTED_FIB))
-                               break;
-               }
+               dest = rib_dest_from_rnode(rn);
+               if (dest && dest->selected_fib &&
+                   !CHECK_FLAG(dest->selected_fib->status,
+                               ROUTE_ENTRY_REMOVED) &&
+                   dest->selected_fib->type != ZEBRA_ROUTE_TABLE)
+                       match = dest->selected_fib;
  
                /* If there is no selected route or matched route is EGP, go up
                   tree. */
@@@ -553,7 -549,7 +549,7 @@@ struct route_entry *rib_match(afi_t afi
        struct prefix p;
        struct route_table *table;
        struct route_node *rn;
-       struct route_entry *match;
+       struct route_entry *match = NULL;
        struct nexthop *newhop;
  
        /* Lookup table.  */
        rn = route_node_match(table, (struct prefix *)&p);
  
        while (rn) {
+               rib_dest_t *dest;
                route_unlock_node(rn);
  
-               /* Pick up selected route. */
-               RNODE_FOREACH_RE (rn, match) {
-                       if (CHECK_FLAG(match->status, ROUTE_ENTRY_REMOVED))
-                               continue;
-                       if (CHECK_FLAG(match->status, ROUTE_ENTRY_SELECTED_FIB))
-                               break;
-               }
+               dest = rib_dest_from_rnode(rn);
+               if (dest && dest->selected_fib &&
+                   !CHECK_FLAG(dest->selected_fib->status, ROUTE_ENTRY_REMOVED))
+                       match = dest->selected_fib;
  
                /* If there is no selected route or matched route is EGP, go up
                   tree. */
@@@ -689,8 -684,9 +684,9 @@@ struct route_entry *rib_lookup_ipv4(str
  {
        struct route_table *table;
        struct route_node *rn;
-       struct route_entry *match;
+       struct route_entry *match = NULL;
        struct nexthop *nexthop;
+       rib_dest_t *dest;
  
        /* Lookup table.  */
        table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, vrf_id);
  
        /* Unlock node. */
        route_unlock_node(rn);
+       dest = rib_dest_from_rnode(rn);
  
-       RNODE_FOREACH_RE (rn, match) {
-               if (CHECK_FLAG(match->status, ROUTE_ENTRY_REMOVED))
-                       continue;
-               if (CHECK_FLAG(match->status, ROUTE_ENTRY_SELECTED_FIB))
-                       break;
-       }
+       if (dest && dest->selected_fib &&
+           !CHECK_FLAG(dest->selected_fib->status, ROUTE_ENTRY_REMOVED))
+               match = dest->selected_fib;
  
        if (!match)
                return NULL;
@@@ -743,9 -737,10 +737,10 @@@ int rib_lookup_ipv4_route(struct prefix
  {
        struct route_table *table;
        struct route_node *rn;
-       struct route_entry *match;
+       struct route_entry *match = NULL;
        struct nexthop *nexthop;
        int nexthops_active;
+       rib_dest_t *dest;
  
        /* Lookup table.  */
        table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, vrf_id);
  
        /* Unlock node. */
        route_unlock_node(rn);
+       dest = rib_dest_from_rnode(rn);
  
        /* Find out if a "selected" RR for the discovered RIB entry exists ever.
         */
-       RNODE_FOREACH_RE (rn, match) {
-               if (CHECK_FLAG(match->status, ROUTE_ENTRY_REMOVED))
-                       continue;
-               if (CHECK_FLAG(match->status, ROUTE_ENTRY_SELECTED_FIB))
-                       break;
-       }
+       if (dest && dest->selected_fib &&
+           !CHECK_FLAG(dest->selected_fib->status, ROUTE_ENTRY_REMOVED))
+               match = dest->selected_fib;
  
        /* None such found :( */
        if (!match)
@@@ -1115,8 -1108,9 +1108,9 @@@ void rib_uninstall_kernel(struct route_
  static void rib_uninstall(struct route_node *rn, struct route_entry *re)
  {
        rib_table_info_t *info = srcdest_rnode_table_info(rn);
+       rib_dest_t *dest = rib_dest_from_rnode(rn);
  
-       if (CHECK_FLAG(re->status, ROUTE_ENTRY_SELECTED_FIB)) {
+       if (dest && dest->selected_fib == re) {
                if (info->safi == SAFI_UNICAST)
                        hook_call(rib_update, rn, "rib_uninstall");
  
                if (zebra_rib_labeled_unicast(re))
                        zebra_mpls_lsp_uninstall(info->zvrf, rn, re);
  
-               UNSET_FLAG(re->status, ROUTE_ENTRY_SELECTED_FIB);
+               dest->selected_fib = NULL;
        }
  
        if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) {
@@@ -1201,6 -1195,8 +1195,8 @@@ int rib_gc_dest(struct route_node *rn
  static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn,
                                struct route_entry *new)
  {
+       rib_dest_t *dest = rib_dest_from_rnode(rn);
        hook_call(rib_update, rn, "new route selected");
  
        /* Update real nexthop. This may actually determine if nexthop is active
                return;
        }
  
-       SET_FLAG(new->status, ROUTE_ENTRY_SELECTED_FIB);
+       dest->selected_fib = new;
        if (IS_ZEBRA_DEBUG_RIB) {
                char buf[SRCDEST2STR_BUFFER];
                srcdest_rnode2str(rn, buf, sizeof(buf));
  static void rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn,
                                struct route_entry *old)
  {
+       rib_dest_t *dest = rib_dest_from_rnode(rn);
        hook_call(rib_update, rn, "removing existing route");
  
        /* Uninstall from kernel. */
        if (!RIB_SYSTEM_ROUTE(old))
                rib_uninstall_kernel(rn, old);
  
-       UNSET_FLAG(old->status, ROUTE_ENTRY_SELECTED_FIB);
+       dest->selected_fib = NULL;
  
        /* Update nexthop for route, reset changed flag. */
        nexthop_active_update(rn, old, 1);
@@@ -1263,6 -1260,7 +1260,7 @@@ static void rib_process_update_fib(stru
        struct nexthop *nexthop = NULL;
        int nh_active = 0;
        int installed = 1;
+       rib_dest_t *dest = rib_dest_from_rnode(rn);
  
        /*
         * We have to install or update if a new route has been selected or
  
                        /* Update for redistribution. */
                        if (installed)
-                               SET_FLAG(new->status, ROUTE_ENTRY_SELECTED_FIB);
+                               dest->selected_fib = new;
                }
  
                /*
  
                        if (!RIB_SYSTEM_ROUTE(old))
                                rib_uninstall_kernel(rn, old);
-                       UNSET_FLAG(new->status, ROUTE_ENTRY_SELECTED_FIB);
+                       dest->selected_fib = NULL;
                }
        } else {
                /*
  
        /* Update prior route. */
        if (new != old) {
-               UNSET_FLAG(old->status, ROUTE_ENTRY_SELECTED_FIB);
                /* Set real nexthop. */
                nexthop_active_update(rn, old, 1);
                UNSET_FLAG(old->status, ROUTE_ENTRY_CHANGED);
@@@ -1475,6 -1471,8 +1471,8 @@@ static void rib_process(struct route_no
        if (IS_ZEBRA_DEBUG_RIB_DETAILED)
                zlog_debug("%u:%s: Processing rn %p", vrf_id, buf, rn);
  
+       old_fib = dest->selected_fib;
        RNODE_FOREACH_RE_SAFE (rn, re, next) {
                if (IS_ZEBRA_DEBUG_RIB_DETAILED)
                        zlog_debug(
                        assert(old_selected == NULL);
                        old_selected = re;
                }
-               /* Currently in fib */
-               if (CHECK_FLAG(re->status, ROUTE_ENTRY_SELECTED_FIB)) {
-                       assert(old_fib == NULL);
-                       old_fib = re;
-               }
  
                /* Skip deleted entries from selection */
                if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
@@@ -2183,8 -2176,8 +2176,8 @@@ void rib_lookup_and_pushup(struct prefi
  {
        struct route_table *table;
        struct route_node *rn;
-       struct route_entry *re;
        unsigned changed = 0;
+       rib_dest_t *dest;
  
        if (NULL == (table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, vrf_id))) {
                zlog_err("%s: zebra_vrf_table() returned NULL", __func__);
        /* Unlock node. */
        route_unlock_node(rn);
  
+       dest = rib_dest_from_rnode(rn);
        /* Check all RE entries. In case any changes have to be done, requeue
         * the RN into RIBQ head. If the routing message about the new connected
         * route (generated by the IP address we are going to assign very soon)
         * revalidation
         * of the rest of the RE.
         */
-       RNODE_FOREACH_RE (rn, re) {
-               if (CHECK_FLAG(re->status, ROUTE_ENTRY_SELECTED_FIB)
-                   && !RIB_SYSTEM_ROUTE(re)) {
-                       changed = 1;
-                       if (IS_ZEBRA_DEBUG_RIB) {
-                               char buf[PREFIX_STRLEN];
-                               zlog_debug(
-                                       "%u:%s: freeing way for connected prefix",
-                                       re->vrf_id,
-                                       prefix2str(&rn->p, buf, sizeof(buf)));
-                               route_entry_dump(&rn->p, NULL, re);
-                       }
-                       rib_uninstall(rn, re);
+       if (dest->selected_fib && !RIB_SYSTEM_ROUTE(dest->selected_fib)) {
+               changed = 1;
+               if (IS_ZEBRA_DEBUG_RIB) {
+                       char buf[PREFIX_STRLEN];
+                       zlog_debug("%u:%s: freeing way for connected prefix",
+                                  dest->selected_fib->vrf_id,
+                                  prefix2str(&rn->p, buf, sizeof(buf)));
+                       route_entry_dump(&rn->p, NULL, dest->selected_fib);
                }
+               rib_uninstall(rn, dest->selected_fib);
        }
        if (changed)
                rib_queue_add(rn);
@@@ -2325,6 -2316,7 +2316,7 @@@ void rib_delete(afi_t afi, safi_t safi
        struct route_entry *same = NULL;
        struct nexthop *rtnh;
        char buf2[INET6_ADDRSTRLEN];
+       rib_dest_t *dest;
  
        assert(!src_p || afi == AFI_IP6);
  
                return;
        }
  
+       dest = rib_dest_from_rnode(rn);
+       fib = dest->selected_fib;
        /* Lookup same type route. */
        RNODE_FOREACH_RE (rn, re) {
                if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
                        continue;
  
-               if (CHECK_FLAG(re->status, ROUTE_ENTRY_SELECTED_FIB))
-                       fib = re;
                if (re->type != type)
                        continue;
                if (re->instance != instance)
                                        UNSET_FLAG(rtnh->flags,
                                                   NEXTHOP_FLAG_FIB);
  
-                               UNSET_FLAG(fib->status,
-                                          ROUTE_ENTRY_SELECTED_FIB);
+                               dest->selected_fib = NULL;
                        } else {
                                /* This means someone else, other than Zebra,
                                 * has deleted
  int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, u_short instance,
            int flags, struct prefix *p, struct prefix_ipv6 *src_p,
            const struct nexthop *nh, u_int32_t table_id, u_int32_t metric,
 -          u_int32_t mtu, uint8_t distance)
 +          u_int32_t mtu, uint8_t distance, route_tag_t tag)
  {
        struct route_entry *re;
        struct nexthop *nexthop;
        re->vrf_id = vrf_id;
        re->nexthop_num = 0;
        re->uptime = time(NULL);
 +      re->tag = tag;
  
        /* Add nexthop. */
        nexthop = nexthop_new();
@@@ -2741,24 -2731,24 +2732,24 @@@ void rib_close_table(struct route_tabl
  {
        struct route_node *rn;
        rib_table_info_t *info;
-       struct route_entry *re;
+       rib_dest_t *dest;
  
        if (!table)
                return;
  
        info = table->info;
  
-       for (rn = route_top(table); rn; rn = srcdest_route_next(rn))
-               RNODE_FOREACH_RE (rn, re) {
-                       if (!CHECK_FLAG(re->status, ROUTE_ENTRY_SELECTED_FIB))
-                               continue;
+       for (rn = route_top(table); rn; rn = srcdest_route_next(rn)) {
+               dest = rib_dest_from_rnode(rn);
  
+               if (dest && dest->selected_fib) {
                        if (info->safi == SAFI_UNICAST)
                                hook_call(rib_update, rn, NULL);
  
-                       if (!RIB_SYSTEM_ROUTE(re))
-                               rib_uninstall_kernel(rn, re);
+                       if (!RIB_SYSTEM_ROUTE(dest->selected_fib))
+                               rib_uninstall_kernel(rn, dest->selected_fib);
                }
+       }
  }
  
  /* Routing information base initialize. */
diff --combined zebra/zebra_vty.c
index 9dab3f94666399f7985ca7a032281d930dbcac9c,198eb090cde4556473ec27fd633f4f6101245729..ccd0c703d49e1c649eae4a548369f5f8cd7d36f2
@@@ -47,8 -47,6 +47,8 @@@
  #include "zebra/zebra_vty_clippy.c"
  #endif
  #include "zebra/zserv.h"
 +#include "zebra/router-id.h"
 +#include "zebra/ipforward.h"
  
  extern int allow_delete;
  
@@@ -474,13 -472,8 +474,13 @@@ static void vty_show_ip_route_detail(st
                vty_out(vty, "\"");
                vty_out(vty, ", distance %u, metric %u", re->distance,
                        re->metric);
 -              if (re->tag)
 +              if (re->tag) {
                        vty_out(vty, ", tag %u", re->tag);
 +#if defined(SUPPORT_REALMS)
 +                      if (re->tag > 0 && re->tag <= 255)
 +                              vty_out(vty, "(realm)");
 +#endif
 +              }
                if (re->mtu)
                        vty_out(vty, ", mtu %u", re->mtu);
                if (re->vrf_id != VRF_DEFAULT) {
@@@ -968,6 -961,7 +968,7 @@@ static int do_show_ip_route(struct vty 
                            u_short ospf_instance_id)
  {
        struct route_table *table;
+       rib_dest_t *dest;
        struct route_node *rn;
        struct route_entry *re;
        int first = 1;
  
        /* Show all routes. */
        for (rn = route_top(table); rn; rn = route_next(rn)) {
+               dest = rib_dest_from_rnode(rn);
                RNODE_FOREACH_RE (rn, re) {
                        if (use_fib
-                           && !CHECK_FLAG(re->status,
-                                          ROUTE_ENTRY_SELECTED_FIB))
+                           && re != dest->selected_fib)
                                continue;
  
                        if (tag && re->tag != tag)
@@@ -2332,254 -2327,13 +2334,254 @@@ static int config_write_protocol(struc
        return 1;
  }
  
 +#ifdef HAVE_NETLINK
 +/* Display default rtm_table for all clients. */
 +DEFUN (show_table,
 +       show_table_cmd,
 +       "show table",
 +       SHOW_STR
 +       "default routing table to use for all clients\n")
 +{
 +      vty_out(vty, "table %d\n", zebrad.rtm_table_default);
 +      return CMD_SUCCESS;
 +}
 +
 +DEFUN (config_table,
 +       config_table_cmd,
 +       "table TABLENO",
 +       "Configure target kernel routing table\n"
 +       "TABLE integer\n")
 +{
 +      zebrad.rtm_table_default = strtol(argv[1]->arg, (char **)0, 10);
 +      return CMD_SUCCESS;
 +}
 +
 +DEFUN (no_config_table,
 +       no_config_table_cmd,
 +       "no table [TABLENO]",
 +       NO_STR
 +       "Configure target kernel routing table\n"
 +       "TABLE integer\n")
 +{
 +      zebrad.rtm_table_default = 0;
 +      return CMD_SUCCESS;
 +}
 +#endif
 +
 +DEFUN (show_zebra,
 +       show_zebra_cmd,
 +       "show zebra",
 +       SHOW_STR
 +       ZEBRA_STR)
 +{
 +      struct vrf *vrf;
 +
 +      vty_out(vty,
 +              "                            Route      Route      Neighbor   LSP        LSP\n");
 +      vty_out(vty,
 +              "VRF                         Installs   Removals    Updates   Installs   Removals\n");
 +
 +      RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
 +              struct zebra_vrf *zvrf = vrf->info;
 +
 +              vty_out(vty, "%-25s %10" PRIu64 " %10" PRIu64 " %10" PRIu64
 +                           " %10" PRIu64 " %10" PRIu64 "\n",
 +                      vrf->name, zvrf->installs, zvrf->removals,
 +                      zvrf->neigh_updates, zvrf->lsp_installs,
 +                      zvrf->lsp_removals);
 +      }
 +
 +      return CMD_SUCCESS;
 +}
 +
 +DEFUN (ip_forwarding,
 +       ip_forwarding_cmd,
 +       "ip forwarding",
 +       IP_STR
 +       "Turn on IP forwarding\n")
 +{
 +      int ret;
 +
 +      ret = ipforward();
 +      if (ret == 0)
 +              ret = ipforward_on();
 +
 +      if (ret == 0) {
 +              vty_out(vty, "Can't turn on IP forwarding\n");
 +              return CMD_WARNING_CONFIG_FAILED;
 +      }
 +
 +      return CMD_SUCCESS;
 +}
 +
 +DEFUN (no_ip_forwarding,
 +       no_ip_forwarding_cmd,
 +       "no ip forwarding",
 +       NO_STR
 +       IP_STR
 +       "Turn off IP forwarding\n")
 +{
 +      int ret;
 +
 +      ret = ipforward();
 +      if (ret != 0)
 +              ret = ipforward_off();
 +
 +      if (ret != 0) {
 +              vty_out(vty, "Can't turn off IP forwarding\n");
 +              return CMD_WARNING_CONFIG_FAILED;
 +      }
 +
 +      return CMD_SUCCESS;
 +}
 +
 +/* Only display ip forwarding is enabled or not. */
 +DEFUN (show_ip_forwarding,
 +       show_ip_forwarding_cmd,
 +       "show ip forwarding",
 +       SHOW_STR
 +       IP_STR
 +       "IP forwarding status\n")
 +{
 +      int ret;
 +
 +      ret = ipforward();
 +
 +      if (ret == 0)
 +              vty_out(vty, "IP forwarding is off\n");
 +      else
 +              vty_out(vty, "IP forwarding is on\n");
 +      return CMD_SUCCESS;
 +}
 +
 +/* Only display ipv6 forwarding is enabled or not. */
 +DEFUN (show_ipv6_forwarding,
 +       show_ipv6_forwarding_cmd,
 +       "show ipv6 forwarding",
 +       SHOW_STR
 +       "IPv6 information\n"
 +       "Forwarding status\n")
 +{
 +      int ret;
 +
 +      ret = ipforward_ipv6();
 +
 +      switch (ret) {
 +      case -1:
 +              vty_out(vty, "ipv6 forwarding is unknown\n");
 +              break;
 +      case 0:
 +              vty_out(vty, "ipv6 forwarding is %s\n", "off");
 +              break;
 +      case 1:
 +              vty_out(vty, "ipv6 forwarding is %s\n", "on");
 +              break;
 +      default:
 +              vty_out(vty, "ipv6 forwarding is %s\n", "off");
 +              break;
 +      }
 +      return CMD_SUCCESS;
 +}
 +
 +DEFUN (ipv6_forwarding,
 +       ipv6_forwarding_cmd,
 +       "ipv6 forwarding",
 +       IPV6_STR
 +       "Turn on IPv6 forwarding\n")
 +{
 +      int ret;
 +
 +      ret = ipforward_ipv6();
 +      if (ret == 0)
 +              ret = ipforward_ipv6_on();
 +
 +      if (ret == 0) {
 +              vty_out(vty, "Can't turn on IPv6 forwarding\n");
 +              return CMD_WARNING_CONFIG_FAILED;
 +      }
 +
 +      return CMD_SUCCESS;
 +}
 +
 +DEFUN (no_ipv6_forwarding,
 +       no_ipv6_forwarding_cmd,
 +       "no ipv6 forwarding",
 +       NO_STR
 +       IPV6_STR
 +       "Turn off IPv6 forwarding\n")
 +{
 +      int ret;
 +
 +      ret = ipforward_ipv6();
 +      if (ret != 0)
 +              ret = ipforward_ipv6_off();
 +
 +      if (ret != 0) {
 +              vty_out(vty, "Can't turn off IPv6 forwarding\n");
 +              return CMD_WARNING_CONFIG_FAILED;
 +      }
 +
 +      return CMD_SUCCESS;
 +}
 +
 +/* Table configuration write function. */
 +static int config_write_table(struct vty *vty)
 +{
 +      if (zebrad.rtm_table_default)
 +              vty_out(vty, "table %d\n", zebrad.rtm_table_default);
 +      return 0;
 +}
 +
 +/* IPForwarding configuration write function. */
 +static int config_write_forwarding(struct vty *vty)
 +{
 +      /* FIXME: Find better place for that. */
 +      router_id_write(vty);
 +
 +      if (!ipforward())
 +              vty_out(vty, "no ip forwarding\n");
 +      if (!ipforward_ipv6())
 +              vty_out(vty, "no ipv6 forwarding\n");
 +      vty_out(vty, "!\n");
 +      return 0;
 +}
 +
  /* IP node for static routes. */
  static struct cmd_node ip_node = {IP_NODE, "", 1};
  static struct cmd_node protocol_node = {PROTOCOL_NODE, "", 1};
 +/* table node for routing tables. */
 +static struct cmd_node table_node = {TABLE_NODE,
 +                                   "", /* This node has no interface. */
 +                                   1};
 +static struct cmd_node forwarding_node = {FORWARDING_NODE,
 +                                        "", /* This node has no interface. */
 +                                        1};
  
  /* Route VTY.  */
  void zebra_vty_init(void)
  {
 +      /* Install configuration write function. */
 +      install_node(&table_node, config_write_table);
 +      install_node(&forwarding_node, config_write_forwarding);
 +
 +      install_element(VIEW_NODE, &show_ip_forwarding_cmd);
 +      install_element(CONFIG_NODE, &ip_forwarding_cmd);
 +      install_element(CONFIG_NODE, &no_ip_forwarding_cmd);
 +      install_element(ENABLE_NODE, &show_zebra_cmd);
 +
 +#ifdef HAVE_NETLINK
 +      install_element(VIEW_NODE, &show_table_cmd);
 +      install_element(CONFIG_NODE, &config_table_cmd);
 +      install_element(CONFIG_NODE, &no_config_table_cmd);
 +#endif /* HAVE_NETLINK */
 +
 +      install_element(VIEW_NODE, &show_ipv6_forwarding_cmd);
 +      install_element(CONFIG_NODE, &ipv6_forwarding_cmd);
 +      install_element(CONFIG_NODE, &no_ipv6_forwarding_cmd);
 +
 +      /* Route-map */
 +      zebra_route_map_init();
 +
        install_node(&ip_node, zebra_ip_config);
        install_node(&protocol_node, config_write_protocol);