Chris Caputo | 3 May 2009 06:40

[quagga-dev 6541] Re: [PATCH] [zebra] RFC 4191 Default Router Preference support for router advertisements

On Sun, 3 May 2009, Chris Caputo wrote:
> For consideration...  Feedback welcome.

2nd version.  (fix to adhere to a "MUST" clause in the RFC)

Chris

---
[PATCH] [zebra] RFC 4191 Default Router Preference support for router advertisements

Adds "ipv6 nd router-preference (high|medium|low)" and
"no ipv6 nd router-preference" interface commands.

Files modified:

   doc/ipv6.texi
   zebra/interface.c
   zebra/interface.h
   zebra/rtadv.c
   zebra/rtadv.h

Signed-off-by: Chris Caputo <ccaputo <at> alt.net>
---
 doc/ipv6.texi     |   10 +++++++-
 zebra/interface.c |    9 +++++++
 zebra/interface.h |    9 ++++++-
 zebra/rtadv.c     |   64 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 zebra/rtadv.h     |    2 +
 5 files changed, 91 insertions(+), 3 deletions(-)

diff --git a/doc/ipv6.texi b/doc/ipv6.texi
index 910253c..a78a92f 100644
--- a/doc/ipv6.texi
+++ b/doc/ipv6.texi
 <at>  <at>  -150,6 +150,13  <at>  <at>  in milliseconds, between successive unsolicited Router Advertisements.
 Default: not set
  <at> end deffn

+ <at> deffn {Interface Command} {ipv6 nd router-preference (high|medium|low)} {}
+ <at> deffnx {Interface Command} {no ipv6 nd router-preference} {}
+Set default router preference in IPv6 router advertisements per RFC4191.
+
+Default: medium
+ <at> end deffn
+
  <at> example
  <at> group
 interface eth0
 <at>  <at>  -160,4 +167,5  <at>  <at>  interface eth0

 For more information see  <at> cite{RFC2462 (IPv6 Stateless Address Autoconfiguration)}
 ,  <at> cite{RFC2461 (Neighbor Discovery for IP Version 6 (IPv6))}
-and  <at> cite{RFC3775 (Mobility Support in IPv6 (Mobile IPv6))}.
+,  <at> cite{RFC3775 (Mobility Support in IPv6 (Mobile IPv6))}
+and  <at> cite{RFC4191 (Default Router Preferences and More-Specific Routes)}.
diff --git a/zebra/interface.c b/zebra/interface.c
index 184b42a..d455cd1 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
 <at>  <at>  -41,6 +41,11  <at>  <at> 
 #include "zebra/debug.h"
 #include "zebra/irdp.h"

+#ifdef RTADV
+/* Order is intentional.  Matches RFC4191.  This array is also used for
+   command matching, so only modify with care. */
+const char *rtadv_pref_strs[] = { "medium", "high", "INVALID", "low", 0 };
+#endif /* RTADV */

 /* Called when new interface is added. */
 static int
 <at>  <at>  -76,6 +81,7  <at>  <at>  if_zebra_new_hook (struct interface *ifp)
     rtadv->HomeAgentPreference = 0;
     rtadv->HomeAgentLifetime = RTADV_ADV_DEFAULT_LIFETIME;
     rtadv->AdvIntervalOption = 0;
+    rtadv->DefaultPreference = RTADV_PREF_MEDIUM;

     rtadv->AdvPrefixList = list_new ();
   }    
 <at>  <at>  -623,6 +629,9  <at>  <at>  nd_dump_vty (struct vty *vty, struct interface *ifp)
 		 VTY_NEWLINE);
       vty_out (vty, "  ND router advertisements live for %d seconds%s",
 	       rtadv->AdvDefaultLifetime, VTY_NEWLINE);
+      vty_out (vty, "  ND router advertisement default router preference is "
+			"%s%s", rtadv_pref_strs[rtadv->DefaultPreference],
+		 VTY_NEWLINE);
       if (rtadv->AdvManagedFlag)
 	vty_out (vty, "  Hosts use DHCP to obtain routable addresses.%s",
 		 VTY_NEWLINE);
diff --git a/zebra/interface.h b/zebra/interface.h
index 0a6b036..ec047aa 100644
--- a/zebra/interface.h
+++ b/zebra/interface.h
 <at>  <at>  -46,7 +46,7  <at>  <at> 
 #endif

 #ifdef RTADV
-/* Router advertisement parameter.  From RFC2461 and RFC3775. */
+/* Router advertisement parameter.  From RFC2461, RFC3775 and RFC4191. */
 struct rtadvconf
 {
   /* A flag indicating whether or not the router sends periodic Router
 <at>  <at>  -171,6 +171,13  <at>  <at>  struct rtadvconf

      Default: FALSE */
   int AdvIntervalOption;
+
+  /* The value to be placed in the Default Router Preference field of
+     a router advertisement. See [RFC 4191 2.1 & 2.2]
+
+     Default: 0 (medium) */
+  int DefaultPreference;
+#define RTADV_PREF_MEDIUM 0x0 /* Per RFC4191. */
 };

 #endif /* RTADV */
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
index 4bdb83d..c247bbf 100644
--- a/zebra/rtadv.c
+++ b/zebra/rtadv.c
 <at>  <at>  -209,7 +209,12  <at>  <at>  rtadv_send_packet (int sock, struct interface *ifp)
   rtadv->nd_ra_cksum = 0;

   rtadv->nd_ra_curhoplimit = 64;
-  rtadv->nd_ra_flags_reserved = 0;
+
+  /* RFC4191: Default Router Preference is 0 if Router Lifetime is 0. */
+  rtadv->nd_ra_flags_reserved =
+    zif->rtadv.AdvDefaultLifetime == 0 ? 0 : zif->rtadv.DefaultPreference;
+  rtadv->nd_ra_flags_reserved <<= 3;
+
   if (zif->rtadv.AdvManagedFlag)
     rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED;
   if (zif->rtadv.AdvOtherConfigFlag)
 <at>  <at>  -1372,6 +1377,56  <at>  <at>  DEFUN (no_ipv6_nd_prefix,

   return CMD_SUCCESS;
 }
+
+DEFUN (ipv6_nd_router_preference,
+       ipv6_nd_router_preference_cmd,
+       "ipv6 nd router-preference (high|medium|low)",
+       "Interface IPv6 config commands\n"
+       "Neighbor discovery\n"
+       "Default router preference\n"
+       "High default router preference\n"
+       "Low default router preference\n"
+       "Medium default router preference (default)\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zif;
+  int i = 0;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  while (0 != rtadv_pref_strs[i])
+    {
+      if (strncmp (argv[0], rtadv_pref_strs[i], 1) == 0)
+	{
+	  zif->rtadv.DefaultPreference = i;
+	  return CMD_SUCCESS;
+	}
+      i++;
+    }
+
+  return CMD_ERR_NO_MATCH;
+}
+
+DEFUN (no_ipv6_nd_router_preference,
+       no_ipv6_nd_router_preference_cmd,
+       "no ipv6 nd router-preference",
+       NO_STR
+       "Interface IPv6 config commands\n"
+       "Neighbor discovery\n"
+       "Default router preference\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  zif->rtadv.DefaultPreference = RTADV_PREF_MEDIUM; /* Default per RFC4191. */
+
+  return CMD_SUCCESS;
+}
+
 /* Write configuration about router advertisement. */
 void
 rtadv_config_write (struct vty *vty, struct interface *ifp)
 <at>  <at>  -1419,6 +1474,11  <at>  <at>  rtadv_config_write (struct vty *vty, struct interface *ifp)
   if (zif->rtadv.AdvOtherConfigFlag)
     vty_out (vty, " ipv6 nd other-config-flag%s", VTY_NEWLINE);

+  if (zif->rtadv.DefaultPreference != RTADV_PREF_MEDIUM)
+    vty_out (vty, " ipv6 nd router-preference %s%s",
+	     rtadv_pref_strs[zif->rtadv.DefaultPreference],
+	     VTY_NEWLINE);
+
   for (ALL_LIST_ELEMENTS_RO (zif->rtadv.AdvPrefixList, node, rprefix))
     {
       vty_out (vty, " ipv6 nd prefix %s/%d",
 <at>  <at>  -1540,6 +1600,8  <at>  <at>  rtadv_init (void)
   install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_rtaddr_cmd);
   install_element (INTERFACE_NODE, &ipv6_nd_prefix_prefix_cmd);
   install_element (INTERFACE_NODE, &no_ipv6_nd_prefix_cmd);
+  install_element (INTERFACE_NODE, &ipv6_nd_router_preference_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_router_preference_cmd);
 }

 static int
diff --git a/zebra/rtadv.h b/zebra/rtadv.h
index abd1c6f..d8d263d 100644
--- a/zebra/rtadv.h
+++ b/zebra/rtadv.h
 <at>  <at>  -94,4 +94,6  <at>  <at>  struct nd_opt_homeagent_info {  /* Home Agent info */
 } __attribute__((__packed__));
 #endif

+extern const char *rtadv_pref_strs[];
+
 #endif /* _ZEBRA_RTADV_H */
--

-- 
1.6.0.6

Gmane