Merge quagga mainline into the google ISIS code.

The steps were:

  $ git checkout google-is-is
  $ git merge quagga
  $ git checkout google-is-is -- isisd

  # Resolve conflicts in the following:
  lib/md5.h
  zebra/rt_netlink.c
  zebra/zebra_rib.c
  zebra/zserv.c

Note that the content in the isisd directory is left unchanged in the
merge. As a result, changes made to isisd as part of the following
commits on the quagga mainline are dropped.

  # 8ced4e82 is the merge base, e96b3121 is the current quagga master
  $ git log --oneline --reverse 8ced4e82..e96b3121 -- isisd
  5574999 isisd: fix crash on "no router isis" (BZ#536)
  8998075 isisd: raise hello rate for DIS (BZ#539)
  306ca83 isisd: include hash.h, not hash.c
  b82cdeb delete CVS keywords
  2f65867 isisd: indent longopts array
  b511468 quagga: option "-z" ("--socket <path>") added
  05e54ee build: delete .cvsignore files
  b4e45f6 fix zebra protocol after MP-BGP changes
  7fd6cd8 isisd: fix circuit state machine
  907fd95 isisd: send proper LSP after DIS election
  d034aa0 isisd: fix wrong next-hops from SPF
  c25eaff isisd: unexpected kernel routing table (BZ#544)
  e6b03b7 isisd: implement MD5 circuit authentication
diff --git a/zebra/.cvsignore b/zebra/.cvsignore
deleted file mode 100644
index 59c5889..0000000
--- a/zebra/.cvsignore
+++ /dev/null
@@ -1,13 +0,0 @@
-Makefile
-Makefile.in
-*.o
-zebra
-zebra.conf
-client
-tags
-TAGS
-.deps
-.nfs*
-.libs
-.arch-inventory
-.arch-ids
diff --git a/zebra/client_main.c b/zebra/client_main.c
index ce01231..8b95907 100644
--- a/zebra/client_main.c
+++ b/zebra/client_main.c
@@ -115,6 +115,7 @@
   { "static", ZEBRA_ROUTE_STATIC },
   { "rip",    ZEBRA_ROUTE_RIP },
   { "ripng",  ZEBRA_ROUTE_RIPNG },
+  { "babel",  ZEBRA_ROUTE_BABEL },
   { "ospf",   ZEBRA_ROUTE_OSPF },
   { "ospf6",  ZEBRA_ROUTE_OSPF6 },
   { "bgp",    ZEBRA_ROUTE_BGP },
diff --git a/zebra/connected.c b/zebra/connected.c
index 95399fa..f699b14 100644
--- a/zebra/connected.c
+++ b/zebra/connected.c
@@ -189,7 +189,7 @@
     return;
 
   rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex,
-	RT_TABLE_MAIN, ifp->metric, 0);
+	RT_TABLE_MAIN, ifp->metric, 0, SAFI_UNICAST);
 
   rib_update ();
 }
@@ -295,7 +295,7 @@
     return;
 
   /* Same logic as for connected_up_ipv4(): push the changes into the head. */
-  rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
+  rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, SAFI_UNICAST);
 
   rib_update ();
 }
@@ -343,7 +343,7 @@
 #endif
 
   rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, RT_TABLE_MAIN,
-                ifp->metric, 0);
+                ifp->metric, 0, SAFI_UNICAST);
 
   rib_update ();
 }
@@ -417,7 +417,7 @@
   if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
     return;
 
-  rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
+  rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, SAFI_UNICAST);
 
   rib_update ();
 }
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index 701c81b..86bd8ff 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -22,6 +22,8 @@
 
 #include <zebra.h>
 
+#include "zebra/zserv.h"
+
 extern int interface_lookup_netlink (void);
 
 /* Interface information read by netlink. */
diff --git a/zebra/interface.c b/zebra/interface.c
index 03e7ff7..2242259 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -76,9 +76,9 @@
     rtadv->AdvReachableTime = 0;
     rtadv->AdvRetransTimer = 0;
     rtadv->AdvCurHopLimit = 0;
-    rtadv->AdvDefaultLifetime = RTADV_ADV_DEFAULT_LIFETIME;
+    rtadv->AdvDefaultLifetime = -1; /* derive from MaxRtrAdvInterval */
     rtadv->HomeAgentPreference = 0;
-    rtadv->HomeAgentLifetime = RTADV_ADV_DEFAULT_LIFETIME;
+    rtadv->HomeAgentLifetime = -1; /* derive from AdvDefaultLifetime */
     rtadv->AdvIntervalOption = 0;
     rtadv->DefaultPreference = RTADV_PREF_MEDIUM;
 
@@ -216,7 +216,7 @@
  * interface will affect only the primary interface/address on Solaris.
  ************************End Solaris flags hacks ***********************
  */
-static inline void
+static void
 if_flags_mangle (struct interface *ifp, uint64_t *newflags)
 {
 #ifdef SUNOS_5
@@ -630,8 +630,12 @@
         vty_out (vty, "  ND router advertisements are sent every "
 			"%d seconds%s", interval / 1000,
 		 VTY_NEWLINE);
-      vty_out (vty, "  ND router advertisements live for %d seconds%s",
-	       rtadv->AdvDefaultLifetime, VTY_NEWLINE);
+      if (rtadv->AdvDefaultLifetime != -1)
+	vty_out (vty, "  ND router advertisements live for %d seconds%s",
+		 rtadv->AdvDefaultLifetime, VTY_NEWLINE);
+      else
+	vty_out (vty, "  ND router advertisements lifetime tracks ra-interval%s",
+		 VTY_NEWLINE);
       vty_out (vty, "  ND router advertisement default router preference is "
 			"%s%s", rtadv_pref_strs[rtadv->DefaultPreference],
 		 VTY_NEWLINE);
@@ -642,9 +646,19 @@
 	vty_out (vty, "  Hosts use stateless autoconfig for addresses.%s",
 		 VTY_NEWLINE);
       if (rtadv->AdvHomeAgentFlag)
+      {
       	vty_out (vty, "  ND router advertisements with "
 				"Home Agent flag bit set.%s",
 		 VTY_NEWLINE);
+	if (rtadv->HomeAgentLifetime != -1)
+	  vty_out (vty, "  Home Agent lifetime is %u seconds%s",
+	           rtadv->HomeAgentLifetime, VTY_NEWLINE);
+	else
+	  vty_out (vty, "  Home Agent lifetime tracks ra-lifetime%s",
+	           VTY_NEWLINE);
+	vty_out (vty, "  Home Agent preference is %u%s",
+	         rtadv->HomeAgentPreference, VTY_NEWLINE);
+      }
       if (rtadv->AdvIntervalOption)
       	vty_out (vty, "  ND router advertisements with Adv. Interval option.%s",
 		 VTY_NEWLINE);
diff --git a/zebra/interface.h b/zebra/interface.h
index 0cf6640..0777a2f 100644
--- a/zebra/interface.h
+++ b/zebra/interface.h
@@ -46,7 +46,7 @@
 #endif
 
 #ifdef RTADV
-/* Router advertisement parameter.  From RFC2461, RFC3775 and RFC4191. */
+/* Router advertisement parameter.  From RFC4861, RFC6275 and RFC4191. */
 struct rtadvconf
 {
   /* A flag indicating whether or not the router sends periodic Router
@@ -56,8 +56,8 @@
 
   /* The maximum time allowed between sending unsolicited multicast
      Router Advertisements from the interface, in milliseconds.
-     MUST be no less than 70 ms (RFC3775, section 7.4) and no greater 
-     than 1800000 ms (See RFC2461).
+     MUST be no less than 70 ms [RFC6275 7.5] and no greater
+     than 1800000 ms [RFC4861 6.2.1].
 
      Default: 600000 milliseconds */
   int MaxRtrAdvInterval;
@@ -65,11 +65,11 @@
 
   /* The minimum time allowed between sending unsolicited multicast
      Router Advertisements from the interface, in milliseconds.
-     MUST be no less than 30 ms (See RFC3775, section 7.4). 
+     MUST be no less than 30 ms [RFC6275 7.5].
      MUST be no greater than .75 * MaxRtrAdvInterval.
 
      Default: 0.33 * MaxRtrAdvInterval */
-  int MinRtrAdvInterval;
+  int MinRtrAdvInterval; /* This field is currently unused. */
 #define RTADV_MIN_RTR_ADV_INTERVAL (0.33 * RTADV_MAX_RTR_ADV_INTERVAL)
 
   /* Unsolicited Router Advertisements' interval timer. */
@@ -131,8 +131,7 @@
 
      Default: 3 * MaxRtrAdvInterval */
   int AdvDefaultLifetime;
-#define RTADV_ADV_DEFAULT_LIFETIME (3 * RTADV_MAX_RTR_ADV_INTERVAL)
-
+#define RTADV_MAX_RTRLIFETIME 9000 /* 2.5 hours */
 
   /* A list of prefixes to be placed in Prefix Information options in
      Router Advertisement messages sent from the interface.
@@ -144,7 +143,7 @@
   struct list *AdvPrefixList;
 
   /* The TRUE/FALSE value to be placed in the "Home agent"
-     flag field in the Router Advertisement.  See [RFC3775 7.1].
+     flag field in the Router Advertisement.  See [RFC6275 7.1].
 
      Default: FALSE */
   int AdvHomeAgentFlag;
@@ -167,7 +166,7 @@
 #define RTADV_MAX_HALIFETIME 65520 /* 18.2 hours */
 
   /* The TRUE/FALSE value to insert or not an Advertisement Interval
-     option. See [RFC 3775 7.3]
+     option. See [RFC 6275 7.3]
 
      Default: FALSE */
   int AdvIntervalOption;
diff --git a/zebra/ipforward_proc.c b/zebra/ipforward_proc.c
index 7384613..2876ede 100644
--- a/zebra/ipforward_proc.c
+++ b/zebra/ipforward_proc.c
@@ -45,7 +45,6 @@
 {
   FILE *fp;
   int ipforwarding = 0;
-  char *pnt;
   char buf[10];
 
   fp = fopen (proc_net_snmp, "r");
@@ -59,8 +58,8 @@
   /* Get ip_statistics.IpForwarding : 
      1 => ip forwarding enabled 
      2 => ip forwarding off. */
-  pnt = fgets (buf, 6, fp);
-  sscanf (buf, "Ip: %d", &ipforwarding);
+  if (fgets (buf, 6, fp))
+    sscanf (buf, "Ip: %d", &ipforwarding);
 
   fclose(fp);
   
@@ -140,8 +139,8 @@
   if (fp == NULL)
     return -1;
 
-  fgets (buf, 2, fp);
-  sscanf (buf, "%d", &ipforwarding);
+  if (fgets (buf, 2, fp))
+    sscanf (buf, "%d", &ipforwarding);
 
   fclose (fp);
   return ipforwarding;
diff --git a/zebra/irdp_interface.c b/zebra/irdp_interface.c
index 8742b62..6403830 100644
--- a/zebra/irdp_interface.c
+++ b/zebra/irdp_interface.c
@@ -99,14 +99,11 @@
 	  u_int32_t group, 
 	  int add_leave)
 {
-  struct zebra_if *zi;
   struct ip_mreq m;
   struct prefix *p;
   int ret;
   char b1[INET_ADDRSTRLEN];
 
-  zi = ifp->info;
-
   memset (&m, 0, sizeof (m));
   m.imr_multiaddr.s_addr = htonl (group);
   p = irdp_get_prefix(ifp);
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index feeaf5d..b7061e7 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -319,6 +319,7 @@
 ifm_read (struct if_msghdr *ifm)
 {
   struct interface *ifp = NULL;
+  struct sockaddr_dl *sdl;
   char ifname[IFNAMSIZ];
   short ifnlen = 0;
   caddr_t *cp;
@@ -356,6 +357,7 @@
   RTA_ADDR_GET (NULL, RTA_GATEWAY, ifm->ifm_addrs, cp);
   RTA_ATTR_GET (NULL, RTA_NETMASK, ifm->ifm_addrs, cp);
   RTA_ADDR_GET (NULL, RTA_GENMASK, ifm->ifm_addrs, cp);
+  sdl = (struct sockaddr_dl *)cp;
   RTA_NAME_GET (ifname, RTA_IFP, ifm->ifm_addrs, cp, ifnlen);
   RTA_ADDR_GET (NULL, RTA_IFA, ifm->ifm_addrs, cp);
   RTA_ADDR_GET (NULL, RTA_AUTHOR, ifm->ifm_addrs, cp);
@@ -454,6 +456,16 @@
 #endif /* __bsdi__ */
       if_get_metric (ifp);
 
+      /*
+       * XXX sockaddr_dl contents can be larger than the structure
+       * definition, so the user of the stored structure must be
+       * careful not to read off the end.
+       *
+       * a nonzero ifnlen from RTA_NAME_GET() means sdl is valid
+       */
+      if (ifnlen)
+	memcpy (&ifp->sdl, sdl, sizeof (struct sockaddr_dl));
+
       if_add_update (ifp);
     }
   else
@@ -606,7 +618,7 @@
 
   /* Assert read up end point matches to end point */
   if (pnt != end)
-    zlog_warn ("ifam_read() does't read all socket data");
+    zlog_warn ("ifam_read() doesn't read all socket data");
 }
 
 /* Interface's address information get. */
@@ -754,7 +766,7 @@
 
   /* Assert read up to the end of pointer. */
   if (pnt != end) 
-      zlog (NULL, LOG_WARNING, "rtm_read() does't read all socket data.");
+      zlog (NULL, LOG_WARNING, "rtm_read() doesn't read all socket data.");
 
   return rtm->rtm_flags;
 }
@@ -894,16 +906,16 @@
        */
       if (rtm->rtm_type == RTM_CHANGE)
         rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p,
-                         NULL, 0, 0);
+                         NULL, 0, 0, SAFI_UNICAST);
       
       if (rtm->rtm_type == RTM_GET 
           || rtm->rtm_type == RTM_ADD
           || rtm->rtm_type == RTM_CHANGE)
 	rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, 
-		      &p, &gate.sin.sin_addr, NULL, 0, 0, 0, 0);
+		      &p, &gate.sin.sin_addr, NULL, 0, 0, 0, 0, SAFI_UNICAST);
       else
 	rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, 
-		      &p, &gate.sin.sin_addr, 0, 0);
+		      &p, &gate.sin.sin_addr, 0, 0, SAFI_UNICAST);
     }
 #ifdef HAVE_IPV6
   if (dest.sa.sa_family == AF_INET6)
@@ -936,16 +948,16 @@
        */
       if (rtm->rtm_type == RTM_CHANGE)
         rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p,
-                         NULL, 0, 0);
+                         NULL, 0, 0, SAFI_UNICAST);
       
       if (rtm->rtm_type == RTM_GET 
           || rtm->rtm_type == RTM_ADD
           || rtm->rtm_type == RTM_CHANGE)
 	rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags,
-		      &p, &gate.sin6.sin6_addr, ifindex, 0, 0, 0);
+		      &p, &gate.sin6.sin6_addr, ifindex, 0, 0, 0, SAFI_UNICAST);
       else
 	rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags,
-			 &p, &gate.sin6.sin6_addr, ifindex, 0);
+			 &p, &gate.sin6.sin6_addr, ifindex, 0, SAFI_UNICAST);
     }
 #endif /* HAVE_IPV6 */
 }
diff --git a/zebra/main.c b/zebra/main.c
index d829c04..5f26ce2 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -71,6 +71,7 @@
   { "keep_kernel", no_argument,       NULL, 'k'},
   { "config_file", required_argument, NULL, 'f'},
   { "pid_file",    required_argument, NULL, 'i'},
+  { "socket",      required_argument, NULL, 'z'},
   { "help",        no_argument,       NULL, 'h'},
   { "vty_addr",    required_argument, NULL, 'A'},
   { "vty_port",    required_argument, NULL, 'P'},
@@ -128,6 +129,7 @@
 	      "-d, --daemon       Runs in daemon mode\n"\
 	      "-f, --config_file  Set configuration file name\n"\
 	      "-i, --pid_file     Set process identifier file name\n"\
+	      "-z, --socket       Set path of zebra socket\n"\
 	      "-k, --keep_kernel  Don't delete old routes which installed by "\
 				  "zebra.\n"\
 	      "-C, --dryrun       Check configuration for validity and exit\n"\
@@ -214,6 +216,7 @@
   char *config_file = NULL;
   char *progname;
   struct thread thread;
+  char *zserv_path = NULL;
 
   /* Set umask before anything for security */
   umask (0027);
@@ -229,9 +232,9 @@
       int opt;
   
 #ifdef HAVE_NETLINK  
-      opt = getopt_long (argc, argv, "bdkf:i:hA:P:ru:g:vs:C", longopts, 0);
+      opt = getopt_long (argc, argv, "bdkf:i:z:hA:P:ru:g:vs:C", longopts, 0);
 #else
-      opt = getopt_long (argc, argv, "bdkf:i:hA:P:ru:g:vC", longopts, 0);
+      opt = getopt_long (argc, argv, "bdkf:i:z:hA:P:ru:g:vC", longopts, 0);
 #endif /* HAVE_NETLINK */
 
       if (opt == EOF)
@@ -261,6 +264,9 @@
         case 'i':
           pid_file = optarg;
           break;
+	case 'z':
+	  zserv_path = optarg;
+	  break;
 	case 'P':
 	  /* Deal with atoi() returning 0 on failure, and zebra not
 	     listening on zebra port... */
@@ -386,7 +392,7 @@
   pid = getpid ();
 
   /* This must be done only after locking pidfile (bug #403). */
-  zebra_zserv_socket_init ();
+  zebra_zserv_socket_init (zserv_path);
 
   /* Make vty server socket. */
   vty_serv_sock (vty_addr, vty_port, ZEBRA_VTYSH_PATH);
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
index a8107ae..4276f1d 100644
--- a/zebra/redistribute.c
+++ b/zebra/redistribute.c
@@ -245,26 +245,15 @@
 
   type = stream_getc (client->ibuf);
 
-  switch (type)
+  if (type == 0 || type >= ZEBRA_ROUTE_MAX)
+    return;
+
+  if (! client->redist[type])
     {
-    case ZEBRA_ROUTE_KERNEL:
-    case ZEBRA_ROUTE_CONNECT:
-    case ZEBRA_ROUTE_STATIC:
-    case ZEBRA_ROUTE_RIP:
-    case ZEBRA_ROUTE_RIPNG:
-    case ZEBRA_ROUTE_OSPF:
-    case ZEBRA_ROUTE_OSPF6:
-    case ZEBRA_ROUTE_BGP:
-      if (! client->redist[type])
-	{
-	  client->redist[type] = 1;
-	  zebra_redistribute (client, type);
-	}
-      break;
-    default:
-      break;
+      client->redist[type] = 1;
+      zebra_redistribute (client, type);
     }
-}     
+}
 
 void
 zebra_redistribute_delete (int command, struct zserv *client, int length)
@@ -273,22 +262,11 @@
 
   type = stream_getc (client->ibuf);
 
-  switch (type)
-    {
-    case ZEBRA_ROUTE_KERNEL:
-    case ZEBRA_ROUTE_CONNECT:
-    case ZEBRA_ROUTE_STATIC:
-    case ZEBRA_ROUTE_RIP:
-    case ZEBRA_ROUTE_RIPNG:
-    case ZEBRA_ROUTE_OSPF:
-    case ZEBRA_ROUTE_OSPF6:
-    case ZEBRA_ROUTE_BGP:
-      client->redist[type] = 0;
-      break;
-    default:
-      break;
-    }
-}     
+  if (type == 0 || type >= ZEBRA_ROUTE_MAX)
+    return;
+
+  client->redist[type] = 0;
+}
 
 void
 zebra_redistribute_default_add (int command, struct zserv *client, int length)
diff --git a/zebra/rib.h b/zebra/rib.h
index b5c9e05..1b85c81 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -253,13 +253,13 @@
 extern int rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, 
 			 struct in_addr *gate, struct in_addr *src,
 			 unsigned int ifindex, u_int32_t vrf_id,
-			 u_int32_t, u_char);
+			 u_int32_t, u_char, safi_t);
 
-extern int rib_add_ipv4_multipath (struct prefix_ipv4 *, struct rib *);
+extern int rib_add_ipv4_multipath (struct prefix_ipv4 *, struct rib *, safi_t);
 
 extern int rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p,
 		            struct in_addr *gate, unsigned int ifindex, 
-		            u_int32_t);
+		            u_int32_t, safi_t safi);
 
 extern struct rib *rib_match_ipv4 (struct in_addr);
 
@@ -270,6 +270,7 @@
 extern void rib_sweep_route (void);
 extern void rib_close (void);
 extern void rib_init (void);
+extern unsigned long rib_score_proto (u_char proto);
 
 extern int
 static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname,
@@ -283,11 +284,11 @@
 extern int
 rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p,
 	      struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id,
-	      u_int32_t metric, u_char distance);
+	      u_int32_t metric, u_char distance, safi_t safi);
 
 extern int
 rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
-		 struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id);
+		 struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id, safi_t safi);
 
 extern struct rib *rib_lookup_ipv6 (struct in6_addr *);
 
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 2cde50a..73097bf 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -732,7 +732,7 @@
 
       if (!tb[RTA_MULTIPATH])
           rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index,
-                        table, metric, 0);
+                        table, metric, 0, SAFI_UNICAST);
       else
         {
           /* This is a multipath route */
@@ -786,7 +786,7 @@
           if (rib->nexthop_num == 0)
             XFREE (MTYPE_RIB, rib);
           else
-            rib_add_ipv4_multipath (&p, rib);
+            rib_add_ipv4_multipath (&p, rib, SAFI_UNICAST);
         }
     }
 #ifdef HAVE_IPV6
@@ -798,7 +798,7 @@
       p.prefixlen = rtm->rtm_dst_len;
 
       rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table,
-		    metric, 0);
+		    metric, 0, SAFI_UNICAST);
     }
 #endif /* HAVE_IPV6 */
 
@@ -833,6 +833,7 @@
   int index;
   int table;
   int metric;
+
   void *dest;
   void *gate;
   void *src;
@@ -909,7 +910,7 @@
   if (tb[RTA_PREFSRC])
     src = RTA_DATA (tb[RTA_PREFSRC]);
 
-  if (tb[RTA_PRIORITY])
+  if (h->nlmsg_type == RTM_NEWROUTE && tb[RTA_PRIORITY])
     metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
 
   if (rtm->rtm_family == AF_INET)
@@ -933,7 +934,7 @@
         {
           if (!tb[RTA_MULTIPATH])
             rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table,
-                          metric, 0);
+                          metric, 0, SAFI_UNICAST);
           else
             {
               /* This is a multipath route */
@@ -987,11 +988,11 @@
               if (rib->nexthop_num == 0)
                 XFREE (MTYPE_RIB, rib);
               else
-                rib_add_ipv4_multipath (&p, rib);
+                rib_add_ipv4_multipath (&p, rib, SAFI_UNICAST);
             }
         }
       else
-        rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
+        rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, SAFI_UNICAST);
     }
 
 #ifdef HAVE_IPV6
@@ -1017,9 +1018,9 @@
         }
 
       if (h->nlmsg_type == RTM_NEWROUTE)
-        rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, 0, 0);
+        rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, metric, 0, SAFI_UNICAST);
       else
-        rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
+        rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, SAFI_UNICAST);
     }
 #endif /* HAVE_IPV6 */
 
@@ -1953,11 +1954,7 @@
 static int
 kernel_read (struct thread *thread)
 {
-  int ret;
-  int sock;
-
-  sock = THREAD_FD (thread);
-  ret = netlink_parse_info (netlink_information_fetch, &netlink);
+  netlink_parse_info (netlink_information_fetch, &netlink);
   thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
 
   return 0;
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
index 8cc3c4c..ae5c5a1 100644
--- a/zebra/rtadv.c
+++ b/zebra/rtadv.c
@@ -163,6 +163,7 @@
   struct rtadv_prefix *rprefix;
   u_char all_nodes_addr[] = {0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
   struct listnode *node;
+  u_int16_t pkt_RouterLifetime;
 
   /*
    * Allocate control message bufffer.  This is dynamic because
@@ -190,7 +191,7 @@
   addr.sin6_len = sizeof (struct sockaddr_in6);
 #endif /* SIN6_LEN */
   addr.sin6_port = htons (IPPROTO_ICMPV6);
-  memcpy (&addr.sin6_addr, all_nodes_addr, sizeof (struct in6_addr));
+  IPV6_ADDR_COPY (&addr.sin6_addr, all_nodes_addr);
 
   /* Fetch interface information. */
   zif = ifp->info;
@@ -215,13 +216,32 @@
     rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER;
   if (zif->rtadv.AdvHomeAgentFlag)
     rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_HOME_AGENT;
-  rtadv->nd_ra_router_lifetime = htons (zif->rtadv.AdvDefaultLifetime);
+  /* Note that according to Neighbor Discovery (RFC 4861 [18]),
+   * AdvDefaultLifetime is by default based on the value of
+   * MaxRtrAdvInterval.  AdvDefaultLifetime is used in the Router Lifetime
+   * field of Router Advertisements.  Given that this field is expressed
+   * in seconds, a small MaxRtrAdvInterval value can result in a zero
+   * value for this field.  To prevent this, routers SHOULD keep
+   * AdvDefaultLifetime in at least one second, even if the use of
+   * MaxRtrAdvInterval would result in a smaller value. -- RFC6275, 7.5 */
+  pkt_RouterLifetime = zif->rtadv.AdvDefaultLifetime != -1 ?
+    zif->rtadv.AdvDefaultLifetime :
+    MAX (1, 0.003 * zif->rtadv.MaxRtrAdvInterval);
+  rtadv->nd_ra_router_lifetime = htons (pkt_RouterLifetime);
   rtadv->nd_ra_reachable = htonl (zif->rtadv.AdvReachableTime);
   rtadv->nd_ra_retransmit = htonl (0);
 
   len = sizeof (struct nd_router_advert);
 
-  if (zif->rtadv.AdvHomeAgentFlag)
+  /* If both the Home Agent Preference and Home Agent Lifetime are set to
+   * their default values specified above, this option SHOULD NOT be
+   * included in the Router Advertisement messages sent by this home
+   * agent. -- RFC6275, 7.4 */
+  if
+  (
+    zif->rtadv.AdvHomeAgentFlag &&
+    (zif->rtadv.HomeAgentPreference || zif->rtadv.HomeAgentLifetime != -1)
+  )
     {
       struct nd_opt_homeagent_info *ndopt_hai = 
 	(struct nd_opt_homeagent_info *)(buf + len);
@@ -229,7 +249,17 @@
       ndopt_hai->nd_opt_hai_len = 1;
       ndopt_hai->nd_opt_hai_reserved = 0;
       ndopt_hai->nd_opt_hai_preference = htons(zif->rtadv.HomeAgentPreference);
-      ndopt_hai->nd_opt_hai_lifetime = htons(zif->rtadv.HomeAgentLifetime);
+      /* 16-bit unsigned integer.  The lifetime associated with the home
+       * agent in units of seconds.  The default value is the same as the
+       * Router Lifetime, as specified in the main body of the Router
+       * Advertisement.  The maximum value corresponds to 18.2 hours.  A
+       * value of 0 MUST NOT be used. -- RFC6275, 7.5 */
+      ndopt_hai->nd_opt_hai_lifetime = htons
+      (
+        zif->rtadv.HomeAgentLifetime != -1 ?
+        zif->rtadv.HomeAgentLifetime :
+        MAX (1, pkt_RouterLifetime) /* 0 is OK for RL, but not for HAL*/
+      );
       len += sizeof(struct nd_opt_homeagent_info);
     }
 
@@ -267,8 +297,7 @@
       pinfo->nd_opt_pi_preferred_time = htonl (rprefix->AdvPreferredLifetime);
       pinfo->nd_opt_pi_reserved2 = 0;
 
-      memcpy (&pinfo->nd_opt_pi_prefix, &rprefix->prefix.u.prefix6,
-	      sizeof (struct in6_addr));
+      IPV6_ADDR_COPY (&pinfo->nd_opt_pi_prefix, &rprefix->prefix.prefix);
 
 #ifdef DEBUG
       {
@@ -319,6 +348,17 @@
     }
 #endif /* HAVE_STRUCT_SOCKADDR_DL */
 
+  /* MTU */
+  if (zif->rtadv.AdvLinkMTU)
+    {
+      struct nd_opt_mtu * opt = (struct nd_opt_mtu *) (buf + len);
+      opt->nd_opt_mtu_type = ND_OPT_MTU;
+      opt->nd_opt_mtu_len = 1;
+      opt->nd_opt_mtu_reserved = 0;
+      opt->nd_opt_mtu_mtu = htonl (zif->rtadv.AdvLinkMTU);
+      len += sizeof (struct nd_opt_mtu);
+    }
+
   msg.msg_name = (void *) &addr;
   msg.msg_namelen = sizeof (struct sockaddr_in6);
   msg.msg_iov = &iov;
@@ -368,7 +408,7 @@
 
   for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
     {
-      if (if_is_loopback (ifp))
+      if (if_is_loopback (ifp) || ! if_is_operative (ifp))
 	continue;
 
       zif = ifp->info;
@@ -378,6 +418,8 @@
 	  zif->rtadv.AdvIntervalTimer -= period;
 	  if (zif->rtadv.AdvIntervalTimer <= 0)
 	    {
+	      /* FIXME: using MaxRtrAdvInterval each time isn't what section
+	         6.2.4 of RFC4861 tells to do. */
 	      zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
 	      rtadv_send_packet (rtadv->sock, ifp);
 	    }
@@ -552,19 +594,19 @@
 }
 
 static struct rtadv_prefix *
-rtadv_prefix_lookup (struct list *rplist, struct prefix *p)
+rtadv_prefix_lookup (struct list *rplist, struct prefix_ipv6 *p)
 {
   struct listnode *node;
   struct rtadv_prefix *rprefix;
 
   for (ALL_LIST_ELEMENTS_RO (rplist, node, rprefix))
-    if (prefix_same (&rprefix->prefix, p))
+    if (prefix_same ((struct prefix *) &rprefix->prefix, (struct prefix *) p))
       return rprefix;
   return NULL;
 }
 
 static struct rtadv_prefix *
-rtadv_prefix_get (struct list *rplist, struct prefix *p)
+rtadv_prefix_get (struct list *rplist, struct prefix_ipv6 *p)
 {
   struct rtadv_prefix *rprefix;
   
@@ -573,7 +615,7 @@
     return rprefix;
 
   rprefix = rtadv_prefix_new ();
-  memcpy (&rprefix->prefix, p, sizeof (struct prefix));
+  memcpy (&rprefix->prefix, p, sizeof (struct prefix_ipv6));
   listnode_add (rplist, rprefix);
 
   return rprefix;
@@ -681,26 +723,22 @@
 
 DEFUN (ipv6_nd_ra_interval_msec,
        ipv6_nd_ra_interval_msec_cmd,
-       "ipv6 nd ra-interval msec MILLISECONDS",
+       "ipv6 nd ra-interval msec <70-1800000>",
        "Interface IPv6 config commands\n"
        "Neighbor discovery\n"
        "Router Advertisement interval\n"
        "Router Advertisement interval in milliseconds\n")
 {
-  int interval;
-  struct interface *ifp;
-  struct zebra_if *zif;
+  unsigned interval;
+  struct interface *ifp = (struct interface *) vty->index;
+  struct zebra_if *zif = ifp->info;
 
-  ifp = (struct interface *) vty->index;
-  zif = ifp->info;
-
-  interval = atoi (argv[0]);
-
-  if (interval <= 0)
-    {
-      vty_out (vty, "Invalid Router Advertisement Interval%s", VTY_NEWLINE);
-      return CMD_WARNING;
-    }
+  VTY_GET_INTEGER_RANGE ("router advertisement interval", interval, argv[0], 70, 1800000);
+  if ((zif->rtadv.AdvDefaultLifetime != -1 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime * 1000))
+  {
+    vty_out (vty, "This ra-interval would conflict with configured ra-lifetime!%s", VTY_NEWLINE);
+    return CMD_WARNING;
+  }
 
   if (zif->rtadv.MaxRtrAdvInterval % 1000)
     rtadv->adv_msec_if_count--;
@@ -717,26 +755,22 @@
 
 DEFUN (ipv6_nd_ra_interval,
        ipv6_nd_ra_interval_cmd,
-       "ipv6 nd ra-interval SECONDS",
+       "ipv6 nd ra-interval <1-1800>",
        "Interface IPv6 config commands\n"
        "Neighbor discovery\n"
        "Router Advertisement interval\n"
        "Router Advertisement interval in seconds\n")
 {
-  int interval;
-  struct interface *ifp;
-  struct zebra_if *zif;
+  unsigned interval;
+  struct interface *ifp = (struct interface *) vty->index;
+  struct zebra_if *zif = ifp->info;
 
-  ifp = (struct interface *) vty->index;
-  zif = ifp->info;
-
-  interval = atoi (argv[0]);
-
-  if (interval <= 0)
-    {
-      vty_out (vty, "Invalid Router Advertisement Interval%s", VTY_NEWLINE);
-      return CMD_WARNING;
-    }
+  VTY_GET_INTEGER_RANGE ("router advertisement interval", interval, argv[0], 1, 1800);
+  if ((zif->rtadv.AdvDefaultLifetime != -1 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime))
+  {
+    vty_out (vty, "This ra-interval would conflict with configured ra-lifetime!%s", VTY_NEWLINE);
+    return CMD_WARNING;
+  }
 
   if (zif->rtadv.MaxRtrAdvInterval % 1000)
     rtadv->adv_msec_if_count--;
@@ -775,13 +809,30 @@
   return CMD_SUCCESS;
 }
 
+ALIAS (no_ipv6_nd_ra_interval,
+       no_ipv6_nd_ra_interval_val_cmd,
+       "no ipv6 nd ra-interval <1-1800>",
+       NO_STR
+       "Interface IPv6 config commands\n"
+       "Neighbor discovery\n"
+       "Router Advertisement interval\n")
+
+ALIAS (no_ipv6_nd_ra_interval,
+       no_ipv6_nd_ra_interval_msec_val_cmd,
+       "no ipv6 nd ra-interval msec <1-1800000>",
+       NO_STR
+       "Interface IPv6 config commands\n"
+       "Neighbor discovery\n"
+       "Router Advertisement interval\n"
+       "Router Advertisement interval in milliseconds\n")
+
 DEFUN (ipv6_nd_ra_lifetime,
        ipv6_nd_ra_lifetime_cmd,
-       "ipv6 nd ra-lifetime SECONDS",
+       "ipv6 nd ra-lifetime <0-9000>",
        "Interface IPv6 config commands\n"
        "Neighbor discovery\n"
        "Router lifetime\n"
-       "Router lifetime in seconds\n")
+       "Router lifetime in seconds (0 stands for a non-default gw)\n")
 {
   int lifetime;
   struct interface *ifp;
@@ -790,11 +841,15 @@
   ifp = (struct interface *) vty->index;
   zif = ifp->info;
 
-  lifetime = atoi (argv[0]);
+  VTY_GET_INTEGER_RANGE ("router lifetime", lifetime, argv[0], 0, 9000);
 
-  if (lifetime < 0 || lifetime > 0xffff)
+  /* The value to be placed in the Router Lifetime field
+   * of Router Advertisements sent from the interface,
+   * in seconds.  MUST be either zero or between
+   * MaxRtrAdvInterval and 9000 seconds. -- RFC4861, 6.2.1 */
+  if ((lifetime != 0 && lifetime * 1000 < zif->rtadv.MaxRtrAdvInterval))
     {
-      vty_out (vty, "Invalid Router Lifetime%s", VTY_NEWLINE);
+      vty_out (vty, "This ra-lifetime would conflict with configured ra-interval%s", VTY_NEWLINE);
       return CMD_WARNING;
     }
 
@@ -817,36 +872,31 @@
   ifp = (struct interface *) vty->index;
   zif = ifp->info;
 
-  zif->rtadv.AdvDefaultLifetime = RTADV_ADV_DEFAULT_LIFETIME;
+  zif->rtadv.AdvDefaultLifetime = -1;
 
   return CMD_SUCCESS;
 }
 
+ALIAS (no_ipv6_nd_ra_lifetime,
+       no_ipv6_nd_ra_lifetime_val_cmd,
+       "no ipv6 nd ra-lifetime <0-9000>",
+       NO_STR
+       "Interface IPv6 config commands\n"
+       "Neighbor discovery\n"
+       "Router lifetime\n"
+       "Router lifetime in seconds (0 stands for a non-default gw)\n")
+
 DEFUN (ipv6_nd_reachable_time,
        ipv6_nd_reachable_time_cmd,
-       "ipv6 nd reachable-time MILLISECONDS",
+       "ipv6 nd reachable-time <1-3600000>",
        "Interface IPv6 config commands\n"
        "Neighbor discovery\n"
        "Reachable time\n"
        "Reachable time in milliseconds\n")
 {
-  u_int32_t rtime;
-  struct interface *ifp;
-  struct zebra_if *zif;
-
-  ifp = (struct interface *) vty->index;
-  zif = ifp->info;
-
-  rtime = (u_int32_t) atol (argv[0]);
-
-  if (rtime > RTADV_MAX_REACHABLE_TIME)
-    {
-      vty_out (vty, "Invalid Reachable time%s", VTY_NEWLINE);
-      return CMD_WARNING;
-    }
-
-  zif->rtadv.AdvReachableTime = rtime;
-
+  struct interface *ifp = (struct interface *) vty->index;
+  struct zebra_if *zif = ifp->info;
+  VTY_GET_INTEGER_RANGE ("reachable time", zif->rtadv.AdvReachableTime, argv[0], 1, RTADV_MAX_REACHABLE_TIME);
   return CMD_SUCCESS;
 }
 
@@ -869,31 +919,26 @@
   return CMD_SUCCESS;
 }
 
+ALIAS (no_ipv6_nd_reachable_time,
+       no_ipv6_nd_reachable_time_val_cmd,
+       "no ipv6 nd reachable-time <1-3600000>",
+       NO_STR
+       "Interface IPv6 config commands\n"
+       "Neighbor discovery\n"
+       "Reachable time\n"
+       "Reachable time in milliseconds\n")
+
 DEFUN (ipv6_nd_homeagent_preference,
        ipv6_nd_homeagent_preference_cmd,
-       "ipv6 nd home-agent-preference PREFERENCE",
+       "ipv6 nd home-agent-preference <0-65535>",
        "Interface IPv6 config commands\n"
        "Neighbor discovery\n"
        "Home Agent preference\n"
-       "Home Agent preference value 0..65535\n")
+       "preference value (default is 0, least preferred)\n")
 {
-  u_int32_t hapref;
-  struct interface *ifp;
-  struct zebra_if *zif;
-
-  ifp = (struct interface *) vty->index;
-  zif = ifp->info;
-
-  hapref = (u_int32_t) atol (argv[0]);
-
-  if (hapref > 65535)
-    {
-      vty_out (vty, "Invalid Home Agent preference%s", VTY_NEWLINE);
-      return CMD_WARNING;
-    }
-
-  zif->rtadv.HomeAgentPreference = hapref;
-
+  struct interface *ifp = (struct interface *) vty->index;
+  struct zebra_if *zif = ifp->info;
+  VTY_GET_INTEGER_RANGE ("home agent preference", zif->rtadv.HomeAgentPreference, argv[0], 0, 65535);
   return CMD_SUCCESS;
 }
 
@@ -916,31 +961,26 @@
   return CMD_SUCCESS;
 }
 
+ALIAS (no_ipv6_nd_homeagent_preference,
+       no_ipv6_nd_homeagent_preference_val_cmd,
+       "no ipv6 nd home-agent-preference <0-65535>",
+       NO_STR
+       "Interface IPv6 config commands\n"
+       "Neighbor discovery\n"
+       "Home Agent preference\n"
+       "preference value (default is 0, least preferred)\n")
+
 DEFUN (ipv6_nd_homeagent_lifetime,
        ipv6_nd_homeagent_lifetime_cmd,
-       "ipv6 nd home-agent-lifetime SECONDS",
+       "ipv6 nd home-agent-lifetime <0-65520>",
        "Interface IPv6 config commands\n"
        "Neighbor discovery\n"
        "Home Agent lifetime\n"
-       "Home Agent lifetime in seconds\n")
+       "Home Agent lifetime in seconds (0 to track ra-lifetime)\n")
 {
-  u_int32_t ha_ltime;
-  struct interface *ifp;
-  struct zebra_if *zif;
-
-  ifp = (struct interface *) vty->index;
-  zif = ifp->info;
-
-  ha_ltime = (u_int32_t) atol (argv[0]);
-
-  if (ha_ltime > RTADV_MAX_HALIFETIME)
-    {
-      vty_out (vty, "Invalid Home Agent Lifetime time%s", VTY_NEWLINE);
-      return CMD_WARNING;
-    }
-
-  zif->rtadv.HomeAgentLifetime = ha_ltime;
-
+  struct interface *ifp = (struct interface *) vty->index;
+  struct zebra_if *zif = ifp->info;
+  VTY_GET_INTEGER_RANGE ("home agent lifetime", zif->rtadv.HomeAgentLifetime, argv[0], 0, RTADV_MAX_HALIFETIME);
   return CMD_SUCCESS;
 }
 
@@ -958,11 +998,20 @@
   ifp = (struct interface *) vty->index;
   zif = ifp->info;
 
-  zif->rtadv.HomeAgentLifetime = 0;
+  zif->rtadv.HomeAgentLifetime = -1;
 
   return CMD_SUCCESS;
 }
 
+ALIAS (no_ipv6_nd_homeagent_lifetime,
+       no_ipv6_nd_homeagent_lifetime_val_cmd,
+       "no ipv6 nd home-agent-lifetime <0-65520>",
+       NO_STR
+       "Interface IPv6 config commands\n"
+       "Neighbor discovery\n"
+       "Home Agent lifetime\n"
+       "Home Agent lifetime in seconds (0 to track ra-lifetime)\n")
+
 DEFUN (ipv6_nd_managed_config_flag,
        ipv6_nd_managed_config_flag_cmd,
        "ipv6 nd managed-config-flag",
@@ -1137,12 +1186,13 @@
   ifp = (struct interface *) vty->index;
   zebra_if = ifp->info;
 
-  ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &rp.prefix);
+  ret = str2prefix_ipv6 (argv[0], &rp.prefix);
   if (!ret)
     {
       vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE);
       return CMD_WARNING;
     }
+  apply_mask_ipv6 (&rp.prefix); /* RFC4861 4.6.2 */
   rp.AdvOnLinkFlag = 1;
   rp.AdvAutonomousFlag = 1;
   rp.AdvRouterAddressFlag = 0;
@@ -1364,12 +1414,13 @@
   ifp = (struct interface *) vty->index;
   zebra_if = ifp->info;
 
-  ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &rp.prefix);
+  ret = str2prefix_ipv6 (argv[0], &rp.prefix);
   if (!ret)
     {
       vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE);
       return CMD_WARNING;
     }
+  apply_mask_ipv6 (&rp.prefix); /* RFC4861 4.6.2 */
 
   ret = rtadv_prefix_reset (zebra_if, &rp);
   if (!ret)
@@ -1430,6 +1481,54 @@
   return CMD_SUCCESS;
 }
 
+ALIAS (no_ipv6_nd_router_preference,
+       no_ipv6_nd_router_preference_val_cmd,
+       "no ipv6 nd router-preference (high|medium|low",
+       NO_STR
+       "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")
+
+DEFUN (ipv6_nd_mtu,
+       ipv6_nd_mtu_cmd,
+       "ipv6 nd mtu <1-65535>",
+       "Interface IPv6 config commands\n"
+       "Neighbor discovery\n"
+       "Advertised MTU\n"
+       "MTU in bytes\n")
+{
+  struct interface *ifp = (struct interface *) vty->index;
+  struct zebra_if *zif = ifp->info;
+  VTY_GET_INTEGER_RANGE ("MTU", zif->rtadv.AdvLinkMTU, argv[0], 1, 65535);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_nd_mtu,
+       no_ipv6_nd_mtu_cmd,
+       "no ipv6 nd mtu",
+       NO_STR
+       "Interface IPv6 config commands\n"
+       "Neighbor discovery\n"
+       "Advertised MTU\n")
+{
+  struct interface *ifp = (struct interface *) vty->index;
+  struct zebra_if *zif = ifp->info;
+  zif->rtadv.AdvLinkMTU = 0;
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ipv6_nd_mtu,
+       no_ipv6_nd_mtu_val_cmd,
+       "no ipv6 nd mtu <1-65535>",
+       NO_STR
+       "Interface IPv6 config commands\n"
+       "Neighbor discovery\n"
+       "Advertised MTU\n"
+       "MTU in bytes\n")
+
 /* Write configuration about router advertisement. */
 void
 rtadv_config_write (struct vty *vty, struct interface *ifp)
@@ -1463,10 +1562,24 @@
       vty_out (vty, " ipv6 nd ra-interval %d%s", interval / 1000,
 	     VTY_NEWLINE);
 
-  if (zif->rtadv.AdvDefaultLifetime != RTADV_ADV_DEFAULT_LIFETIME)
+  if (zif->rtadv.AdvIntervalOption)
+    vty_out (vty, " ipv6 nd adv-interval-option%s", VTY_NEWLINE);
+
+  if (zif->rtadv.AdvDefaultLifetime != -1)
     vty_out (vty, " ipv6 nd ra-lifetime %d%s", zif->rtadv.AdvDefaultLifetime,
 	     VTY_NEWLINE);
 
+  if (zif->rtadv.HomeAgentPreference)
+    vty_out (vty, " ipv6 nd home-agent-preference %u%s",
+	     zif->rtadv.HomeAgentPreference, VTY_NEWLINE);
+
+  if (zif->rtadv.HomeAgentLifetime != -1)
+    vty_out (vty, " ipv6 nd home-agent-lifetime %u%s",
+	     zif->rtadv.HomeAgentLifetime, VTY_NEWLINE);
+
+  if (zif->rtadv.AdvHomeAgentFlag)
+    vty_out (vty, " ipv6 nd home-agent-config-flag%s", VTY_NEWLINE);
+
   if (zif->rtadv.AdvReachableTime)
     vty_out (vty, " ipv6 nd reachable-time %d%s", zif->rtadv.AdvReachableTime,
 	     VTY_NEWLINE);
@@ -1482,10 +1595,13 @@
 	     rtadv_pref_strs[zif->rtadv.DefaultPreference],
 	     VTY_NEWLINE);
 
+  if (zif->rtadv.AdvLinkMTU)
+    vty_out (vty, " ipv6 nd mtu %d%s", zif->rtadv.AdvLinkMTU, VTY_NEWLINE);
+
   for (ALL_LIST_ELEMENTS_RO (zif->rtadv.AdvPrefixList, node, rprefix))
     {
       vty_out (vty, " ipv6 nd prefix %s/%d",
-	       inet_ntop (AF_INET6, &rprefix->prefix.u.prefix6, 
+	       inet_ntop (AF_INET6, &rprefix->prefix.prefix,
 			  (char *) buf, INET6_ADDRSTRLEN),
 	       rprefix->prefix.prefixlen);
       if ((rprefix->AdvValidLifetime != RTADV_VALID_LIFETIME) || 
@@ -1572,10 +1688,14 @@
   install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_cmd);
   install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_msec_cmd);
   install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_val_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_msec_val_cmd);
   install_element (INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd);
   install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_val_cmd);
   install_element (INTERFACE_NODE, &ipv6_nd_reachable_time_cmd);
   install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_val_cmd);
   install_element (INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd);
   install_element (INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd);
   install_element (INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd);
@@ -1584,8 +1704,10 @@
   install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_config_flag_cmd);
   install_element (INTERFACE_NODE, &ipv6_nd_homeagent_preference_cmd);
   install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_val_cmd);
   install_element (INTERFACE_NODE, &ipv6_nd_homeagent_lifetime_cmd);
   install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_val_cmd);
   install_element (INTERFACE_NODE, &ipv6_nd_adv_interval_config_option_cmd);
   install_element (INTERFACE_NODE, &no_ipv6_nd_adv_interval_config_option_cmd);
   install_element (INTERFACE_NODE, &ipv6_nd_prefix_cmd);
@@ -1605,6 +1727,10 @@
   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);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_router_preference_val_cmd);
+  install_element (INTERFACE_NODE, &ipv6_nd_mtu_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_mtu_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_mtu_val_cmd);
 }
 
 static int
diff --git a/zebra/rtadv.h b/zebra/rtadv.h
index d8d263d..564a4c6 100644
--- a/zebra/rtadv.h
+++ b/zebra/rtadv.h
@@ -30,7 +30,7 @@
 struct rtadv_prefix
 {
   /* Prefix to be advertised. */
-  struct prefix prefix;
+  struct prefix_ipv6 prefix;
   
   /* The value to be placed in the Valid Lifetime in the Prefix */
   u_int32_t AdvValidLifetime;
@@ -47,7 +47,7 @@
   /* The value to be placed in the Autonomous Flag. */
   int AdvAutonomousFlag;
 
-  /* The value to be placed in the Router Address Flag (RFC3775 7.2). */
+  /* The value to be placed in the Router Address Flag [RFC6275 7.2]. */
   int AdvRouterAddressFlag;
 #ifndef ND_OPT_PI_FLAG_RADDR
 #define ND_OPT_PI_FLAG_RADDR         0x20
@@ -58,7 +58,7 @@
 extern void rtadv_config_write (struct vty *, struct interface *);
 extern void rtadv_init (void);
 
-/* draft-ietf-mip6-mipext-advapi-03 */
+/* RFC4584 Extension to Sockets API for Mobile IPv6 */
 
 #ifndef ND_OPT_ADV_INTERVAL
 #define ND_OPT_ADV_INTERVAL	7   /* Adv Interval Option */
diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c
index 3e065c6..81bf0de 100644
--- a/zebra/rtread_getmsg.c
+++ b/zebra/rtread_getmsg.c
@@ -90,7 +90,7 @@
 	gateway.s_addr = routeEntry->ipRouteNextHop;
 
 	rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &prefix,
-		      &gateway, NULL, 0, 0, 0, 0);
+		      &gateway, NULL, 0, 0, 0, 0, SAFI_UNICAST);
 }
 
 void
diff --git a/zebra/rtread_netlink.c b/zebra/rtread_netlink.c
index 44715d9..066e844 100644
--- a/zebra/rtread_netlink.c
+++ b/zebra/rtread_netlink.c
@@ -21,6 +21,9 @@
  */
 
 #include <zebra.h>
+
+#include "zebra/zserv.h"
+
 extern void netlink_route_read (void);
 
 void route_read (void)
diff --git a/zebra/rtread_proc.c b/zebra/rtread_proc.c
index 1de435a..07e8491 100644
--- a/zebra/rtread_proc.c
+++ b/zebra/rtread_proc.c
@@ -96,7 +96,7 @@
       p.prefixlen = ip_masklen (tmpmask);
       sscanf (gate, "%lX", (unsigned long *)&gateway);
 
-      rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gateway, NULL, 0, 0, 0, 0);
+      rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gateway, NULL, 0, 0, 0, 0, SAFI_UNICAST);
     }
 
   fclose (fp);
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 8da6c84..2fa439c 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -55,18 +55,20 @@
 {  
   int key;
   int distance;
-} route_info[] =
+} route_info[ZEBRA_ROUTE_MAX] =
 {
-  {ZEBRA_ROUTE_SYSTEM,    0},
-  {ZEBRA_ROUTE_KERNEL,    0},
-  {ZEBRA_ROUTE_CONNECT,   0},
-  {ZEBRA_ROUTE_STATIC,    1},
-  {ZEBRA_ROUTE_RIP,     120},
-  {ZEBRA_ROUTE_RIPNG,   120},
-  {ZEBRA_ROUTE_OSPF,    110},
-  {ZEBRA_ROUTE_OSPF6,   110},
-  {ZEBRA_ROUTE_ISIS,    115},
-  {ZEBRA_ROUTE_BGP,      20  /* IBGP is 200. */}
+  [ZEBRA_ROUTE_SYSTEM]  = {ZEBRA_ROUTE_SYSTEM,    0},
+  [ZEBRA_ROUTE_KERNEL]  = {ZEBRA_ROUTE_KERNEL,    0},
+  [ZEBRA_ROUTE_CONNECT] = {ZEBRA_ROUTE_CONNECT,   0},
+  [ZEBRA_ROUTE_STATIC]  = {ZEBRA_ROUTE_STATIC,    1},
+  [ZEBRA_ROUTE_RIP]     = {ZEBRA_ROUTE_RIP,     120},
+  [ZEBRA_ROUTE_RIPNG]   = {ZEBRA_ROUTE_RIPNG,   120},
+  [ZEBRA_ROUTE_OSPF]    = {ZEBRA_ROUTE_OSPF,    110},
+  [ZEBRA_ROUTE_OSPF6]   = {ZEBRA_ROUTE_OSPF6,   110},
+  [ZEBRA_ROUTE_ISIS]    = {ZEBRA_ROUTE_ISIS,    115},
+  [ZEBRA_ROUTE_BGP]     = {ZEBRA_ROUTE_BGP,      20  /* IBGP is 200. */},
+  [ZEBRA_ROUTE_BABEL]   = {ZEBRA_ROUTE_BABEL,    95},
+  /* no entry/default: 150 */
 };
 
 /* Vector for routing table.  */
@@ -89,6 +91,11 @@
   vrf->table[AFI_IP6][SAFI_UNICAST] = route_table_init ();
   vrf->stable[AFI_IP][SAFI_UNICAST] = route_table_init ();
   vrf->stable[AFI_IP6][SAFI_UNICAST] = route_table_init ();
+  vrf->table[AFI_IP][SAFI_MULTICAST] = route_table_init ();
+  vrf->table[AFI_IP6][SAFI_MULTICAST] = route_table_init ();
+  vrf->stable[AFI_IP][SAFI_MULTICAST] = route_table_init ();
+  vrf->stable[AFI_IP6][SAFI_MULTICAST] = route_table_init ();
+
 
   return vrf;
 }
@@ -1229,6 +1236,7 @@
   [ZEBRA_ROUTE_ISIS]    = 2,
   [ZEBRA_ROUTE_BGP]     = 3,
   [ZEBRA_ROUTE_HSLS]    = 4,
+  [ZEBRA_ROUTE_BABEL]   = 2,
 };
 
 /* Look into the RN and queue it into one or more priority queues,
@@ -1519,7 +1527,7 @@
 rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, 
 	      struct in_addr *gate, struct in_addr *src,
 	      unsigned int ifindex, u_int32_t vrf_id,
-	      u_int32_t metric, u_char distance)
+	      u_int32_t metric, u_char distance, safi_t safi)
 {
   struct rib *rib;
   struct rib *same = NULL;
@@ -1528,7 +1536,7 @@
   struct nexthop *nexthop;
 
   /* Lookup table.  */
-  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  table = vrf_table (AFI_IP, safi, 0);
   if (! table)
     return 0;
 
@@ -1538,7 +1546,10 @@
   /* Set default distance by route type. */
   if (distance == 0)
     {
-      distance = route_info[type].distance;
+      if ((unsigned)type >= sizeof(route_info) / sizeof(route_info[0]))
+	distance = 150;
+      else
+        distance = route_info[type].distance;
 
       /* iBGP distance is 200. */
       if (type == ZEBRA_ROUTE_BGP && CHECK_FLAG (flags, ZEBRA_FLAG_IBGP))
@@ -1774,7 +1785,7 @@
 }
 
 int
-rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib)
+rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi)
 {
   struct route_table *table;
   struct route_node *rn;
@@ -1782,9 +1793,10 @@
   struct nexthop *nexthop;
   
   /* Lookup table.  */
-  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  table = vrf_table (AFI_IP, safi, 0);
   if (! table)
     return 0;
+
   /* Make it sure prefixlen is applied to the prefix. */
   apply_mask_ipv4 (p);
 
@@ -1847,7 +1859,7 @@
 /* XXX factor with rib_delete_ipv6 */
 int
 rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p,
-		 struct in_addr *gate, unsigned int ifindex, u_int32_t vrf_id)
+		 struct in_addr *gate, unsigned int ifindex, u_int32_t vrf_id, safi_t safi)
 {
   struct route_table *table;
   struct route_node *rn;
@@ -1859,7 +1871,7 @@
   char buf2[INET_ADDRSTRLEN];
 
   /* Lookup table.  */
-  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  table = vrf_table (AFI_IP, safi, 0);
   if (! table)
     return 0;
 
@@ -1906,8 +1918,10 @@
       if (rib->type != type)
 	continue;
       if (rib->type == ZEBRA_ROUTE_CONNECT && (nexthop = rib->nexthop) &&
-	  nexthop->type == NEXTHOP_TYPE_IFINDEX && nexthop->ifindex == ifindex)
+	  nexthop->type == NEXTHOP_TYPE_IFINDEX)
 	{
+	  if (nexthop->ifindex != ifindex)
+	    continue;
 	  if (rib->refcnt)
 	    {
 	      rib->refcnt--;
@@ -2308,7 +2322,7 @@
 int
 rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p,
 	      struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id,
-	      u_int32_t metric, u_char distance)
+	      u_int32_t metric, u_char distance, safi_t safi)
 {
   struct rib *rib;
   struct rib *same = NULL;
@@ -2317,7 +2331,7 @@
   struct nexthop *nexthop;
 
   /* Lookup table.  */
-  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  table = vrf_table (AFI_IP6, safi, 0);
   if (! table)
     return 0;
 
@@ -2402,7 +2416,7 @@
 /* XXX factor with rib_delete_ipv6 */
 int
 rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
-		 struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id)
+		 struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id, safi_t safi)
 {
   struct route_table *table;
   struct route_node *rn;
@@ -2417,7 +2431,7 @@
   apply_mask_ipv6 (p);
 
   /* Lookup table.  */
-  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  table = vrf_table (AFI_IP6, safi, 0);
   if (! table)
     return 0;
   
@@ -2454,8 +2468,10 @@
       if (rib->type != type)
         continue;
       if (rib->type == ZEBRA_ROUTE_CONNECT && (nexthop = rib->nexthop) &&
-	  nexthop->type == NEXTHOP_TYPE_IFINDEX && nexthop->ifindex == ifindex)
+	  nexthop->type == NEXTHOP_TYPE_IFINDEX)
 	{
+	  if (nexthop->ifindex != ifindex)
+	    continue;
 	  if (rib->refcnt)
 	    {
 	      rib->refcnt--;
@@ -2960,6 +2976,41 @@
     }
 }
 
+
+/* Remove specific by protocol routes from 'table'. */
+static unsigned long
+rib_score_proto_table (u_char proto, struct route_table *table)
+{
+  struct route_node *rn;
+  struct rib *rib;
+  struct rib *next;
+  unsigned long n = 0;
+
+  if (table)
+    for (rn = route_top (table); rn; rn = route_next (rn))
+      for (rib = rn->info; rib; rib = next)
+        {
+          next = rib->next;
+          if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
+            continue;
+          if (rib->type == proto)
+            {
+              rib_delnode (rn, rib);
+              n++;
+            }
+        }
+
+  return n;
+}
+
+/* Remove specific by protocol routes. */
+unsigned long
+rib_score_proto (u_char proto)
+{
+  return  rib_score_proto_table (proto, vrf_table (AFI_IP,  SAFI_UNICAST, 0))
+         +rib_score_proto_table (proto, vrf_table (AFI_IP6, SAFI_UNICAST, 0));
+}
+
 /* Close RIB and clean up kernel routes. */
 static void
 rib_close_table (struct route_table *table)
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index ecb5d10..dafcf75 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -556,6 +556,7 @@
 #define ONE_WEEK_SECOND 60*60*24*7
       if (rib->type == ZEBRA_ROUTE_RIP
 	  || rib->type == ZEBRA_ROUTE_OSPF
+	  || rib->type == ZEBRA_ROUTE_BABEL
 	  || rib->type == ZEBRA_ROUTE_ISIS
 	  || rib->type == ZEBRA_ROUTE_BGP)
 	{
@@ -774,6 +775,7 @@
 
       if (rib->type == ZEBRA_ROUTE_RIP
 	  || rib->type == ZEBRA_ROUTE_OSPF
+	  || rib->type == ZEBRA_ROUTE_BABEL
 	  || rib->type == ZEBRA_ROUTE_ISIS
 	  || rib->type == ZEBRA_ROUTE_BGP)
 	{
@@ -802,10 +804,6 @@
     }
 }
 
-#define SHOW_ROUTE_V4_HEADER "Codes: K - kernel route, C - connected, " \
-  "S - static, R - RIP, O - OSPF,%s       I - ISIS, B - BGP, " \
-  "> - selected route, * - FIB route%s%s"
-
 DEFUN (show_ip_route,
        show_ip_route_cmd,
        "show ip route",
@@ -828,8 +826,7 @@
       {
 	if (first)
 	  {
-	    vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE, VTY_NEWLINE,
-		     VTY_NEWLINE);
+	    vty_out (vty, SHOW_ROUTE_V4_HEADER);
 	    first = 0;
 	  }
 	vty_show_ip_route (vty, rn, rib);
@@ -871,8 +868,7 @@
 	{
 	  if (first)
 	    {
-	      vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE,
-		       VTY_NEWLINE, VTY_NEWLINE);
+	      vty_out (vty, SHOW_ROUTE_V4_HEADER);
 	      first = 0;
 	    }
 	  vty_show_ip_route (vty, rn, rib);
@@ -910,8 +906,7 @@
 	  {
 	    if (first)
 	      {
-		vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE,
-			 VTY_NEWLINE, VTY_NEWLINE);
+		vty_out (vty, SHOW_ROUTE_V4_HEADER);
 		first = 0;
 	      }
 	    vty_show_ip_route (vty, rn, rib);
@@ -922,17 +917,11 @@
 
 DEFUN (show_ip_route_protocol,
        show_ip_route_protocol_cmd,
-       "show ip route (bgp|connected|isis|kernel|ospf|rip|static)",
+       "show ip route " QUAGGA_IP_REDIST_STR_ZEBRA,
        SHOW_STR
        IP_STR
        "IP routing table\n"
-       "Border Gateway Protocol (BGP)\n"
-       "Connected\n"
-       "ISO IS-IS (ISIS)\n"
-       "Kernel\n"
-       "Open Shortest Path First (OSPF)\n"
-       "Routing Information Protocol (RIP)\n"
-       "Static routes\n")
+       QUAGGA_IP_REDIST_HELP_STR_ZEBRA)
 {
   int type;
   struct route_table *table;
@@ -940,21 +929,8 @@
   struct rib *rib;
   int first = 1;
 
-  if (strncmp (argv[0], "b", 1) == 0)
-    type = ZEBRA_ROUTE_BGP;
-  else if (strncmp (argv[0], "c", 1) == 0)
-    type = ZEBRA_ROUTE_CONNECT;
-  else if (strncmp (argv[0], "k", 1) ==0)
-    type = ZEBRA_ROUTE_KERNEL;
-  else if (strncmp (argv[0], "o", 1) == 0)
-    type = ZEBRA_ROUTE_OSPF;
-  else if (strncmp (argv[0], "i", 1) == 0)
-    type = ZEBRA_ROUTE_ISIS;
-  else if (strncmp (argv[0], "r", 1) == 0)
-    type = ZEBRA_ROUTE_RIP;
-  else if (strncmp (argv[0], "s", 1) == 0)
-    type = ZEBRA_ROUTE_STATIC;
-  else 
+  type = proto_redistnum (AFI_IP, argv[0]);
+  if (type < 0)
     {
       vty_out (vty, "Unknown route type%s", VTY_NEWLINE);
       return CMD_WARNING;
@@ -971,8 +947,7 @@
 	{
 	  if (first)
 	    {
-	      vty_out (vty, SHOW_ROUTE_V4_HEADER,
-		       VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+	      vty_out (vty, SHOW_ROUTE_V4_HEADER);
 	      first = 0;
 	    }
 	  vty_show_ip_route (vty, rn, rib);
@@ -1559,6 +1534,7 @@
 #define ONE_WEEK_SECOND 60*60*24*7
       if (rib->type == ZEBRA_ROUTE_RIPNG
 	  || rib->type == ZEBRA_ROUTE_OSPF6
+	  || rib->type == ZEBRA_ROUTE_BABEL
 	  || rib->type == ZEBRA_ROUTE_ISIS
 	  || rib->type == ZEBRA_ROUTE_BGP)
 	{
@@ -1738,6 +1714,7 @@
       
       if (rib->type == ZEBRA_ROUTE_RIPNG
 	  || rib->type == ZEBRA_ROUTE_OSPF6
+	  || rib->type == ZEBRA_ROUTE_BABEL
 	  || rib->type == ZEBRA_ROUTE_ISIS
 	  || rib->type == ZEBRA_ROUTE_BGP)
 	{
@@ -1766,8 +1743,6 @@
     }
 }
 
-#define SHOW_ROUTE_V6_HEADER "Codes: K - kernel route, C - connected, S - static, R - RIPng, O - OSPFv3,%s       I - ISIS, B - BGP, * - FIB route.%s%s"
-
 DEFUN (show_ipv6_route,
        show_ipv6_route_cmd,
        "show ipv6 route",
@@ -1790,7 +1765,7 @@
       {
 	if (first)
 	  {
-	    vty_out (vty, SHOW_ROUTE_V6_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+	    vty_out (vty, SHOW_ROUTE_V6_HEADER);
 	    first = 0;
 	  }
 	vty_show_ipv6_route (vty, rn, rib);
@@ -1832,7 +1807,7 @@
 	{
 	  if (first)
 	    {
-	      vty_out (vty, SHOW_ROUTE_V6_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+	      vty_out (vty, SHOW_ROUTE_V6_HEADER);
 	      first = 0;
 	    }
 	  vty_show_ipv6_route (vty, rn, rib);
@@ -1842,17 +1817,11 @@
 
 DEFUN (show_ipv6_route_protocol,
        show_ipv6_route_protocol_cmd,
-       "show ipv6 route (bgp|connected|isis|kernel|ospf6|ripng|static)",
+       "show ipv6 route " QUAGGA_IP6_REDIST_STR_ZEBRA,
        SHOW_STR
        IP_STR
        "IP routing table\n"
-       "Border Gateway Protocol (BGP)\n"
-       "Connected\n"
-       "ISO IS-IS (ISIS)\n"
-       "Kernel\n"
-       "Open Shortest Path First (OSPFv3)\n"
-       "Routing Information Protocol (RIPng)\n"
-       "Static routes\n")
+	QUAGGA_IP6_REDIST_HELP_STR_ZEBRA)
 {
   int type;
   struct route_table *table;
@@ -1860,21 +1829,8 @@
   struct rib *rib;
   int first = 1;
 
-  if (strncmp (argv[0], "b", 1) == 0)
-    type = ZEBRA_ROUTE_BGP;
-  else if (strncmp (argv[0], "c", 1) == 0)
-    type = ZEBRA_ROUTE_CONNECT;
-  else if (strncmp (argv[0], "k", 1) ==0)
-    type = ZEBRA_ROUTE_KERNEL;
-  else if (strncmp (argv[0], "o", 1) == 0)
-    type = ZEBRA_ROUTE_OSPF6;
-  else if (strncmp (argv[0], "i", 1) == 0)
-    type = ZEBRA_ROUTE_ISIS;
-  else if (strncmp (argv[0], "r", 1) == 0)
-    type = ZEBRA_ROUTE_RIPNG;
-  else if (strncmp (argv[0], "s", 1) == 0)
-    type = ZEBRA_ROUTE_STATIC;
-  else 
+  type = proto_redistnum (AFI_IP6, argv[0]);
+  if (type < 0)
     {
       vty_out (vty, "Unknown route type%s", VTY_NEWLINE);
       return CMD_WARNING;
@@ -1891,7 +1847,7 @@
 	{
 	  if (first)
 	    {
-	      vty_out (vty, SHOW_ROUTE_V6_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+	      vty_out (vty, SHOW_ROUTE_V6_HEADER);
 	      first = 0;
 	    }
 	  vty_show_ipv6_route (vty, rn, rib);
@@ -1995,6 +1951,80 @@
   return CMD_SUCCESS;
 }
 
+/*
+ * Show IP mroute command to dump the BGP Multicast 
+ * routing table
+ */
+DEFUN (show_ip_mroute,
+       show_ip_mroute_cmd,
+       "show ip mroute",
+       SHOW_STR
+       IP_STR
+       "IP Multicast routing table\n")
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *rib;
+  int first = 1;
+
+  table = vrf_table (AFI_IP, SAFI_MULTICAST, 0);
+  if (! table)
+    return CMD_SUCCESS;
+
+  /* Show all IPv4 routes. */
+  for (rn = route_top (table); rn; rn = route_next (rn))
+    for (rib = rn->info; rib; rib = rib->next)
+      {
+       if (first)
+         {
+	   vty_out (vty, SHOW_ROUTE_V4_HEADER);
+           first = 0;
+         }
+       vty_show_ip_route (vty, rn, rib);
+      }
+  return CMD_SUCCESS;
+}
+
+/*
+ * Show IPv6 mroute command.Used to dump
+ * the Multicast routing table.
+ */
+
+DEFUN (show_ipv6_mroute,
+       show_ipv6_mroute_cmd,
+       "show ipv6 mroute",
+       SHOW_STR
+       IP_STR
+       "IPv6 Multicast routing table\n")
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *rib;
+  int first = 1;
+
+  table = vrf_table (AFI_IP6, SAFI_MULTICAST, 0);
+  if (! table)
+    return CMD_SUCCESS;
+
+  /* Show all IPv6 route. */
+  for (rn = route_top (table); rn; rn = route_next (rn))
+    for (rib = rn->info; rib; rib = rib->next)
+      {
+       if (first)
+         {
+	   vty_out (vty, SHOW_ROUTE_V6_HEADER);
+           first = 0;
+         }
+       vty_show_ipv6_route (vty, rn, rib);
+      }
+  return CMD_SUCCESS;
+}
+
+
+
+
+
+
 /* Write IPv6 static route configuration. */
 static int
 static_config_ipv6 (struct vty *vty)
@@ -2137,6 +2167,10 @@
   install_element (ENABLE_NODE, &show_ip_route_supernets_cmd);
   install_element (ENABLE_NODE, &show_ip_route_summary_cmd);
 
+  install_element (VIEW_NODE, &show_ip_mroute_cmd);
+  install_element (ENABLE_NODE, &show_ip_mroute_cmd);
+
+
 #ifdef HAVE_IPV6
   install_element (CONFIG_NODE, &ipv6_route_cmd);
   install_element (CONFIG_NODE, &ipv6_route_flags_cmd);
@@ -2166,5 +2200,8 @@
   install_element (ENABLE_NODE, &show_ipv6_route_prefix_cmd);
   install_element (ENABLE_NODE, &show_ipv6_route_prefix_longer_cmd);
   install_element (ENABLE_NODE, &show_ipv6_route_summary_cmd);
+
+  install_element (VIEW_NODE, &show_ipv6_mroute_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_mroute_cmd);
 #endif /* HAVE_IPV6 */
 }
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 23a5c4e..b1f539d 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -64,6 +64,15 @@
   return 0;
 }
 
+/* When client connects, it sends hello message
+ * with promise to send zebra routes of specific type.
+ * Zebra stores a socket fd of the client into
+ * this array. And use it to clean up routes that
+ * client didn't remove for some reasons after closing
+ * connection.
+ */
+static int route_type_oaths[ZEBRA_ROUTE_MAX];
+
 static int
 zserv_flush_data(struct thread *thread)
 {
@@ -721,6 +730,8 @@
   struct stream *s;
   unsigned int ifindex;
   u_char ifname_len;
+  safi_t safi;	
+
 
   /* Get input stream.  */
   s = client->ibuf;
@@ -739,6 +750,7 @@
 
   rib->flags = stream_getc (s);
   message = stream_getc (s); 
+  safi = stream_getw (s);
   rib->uptime = time (NULL);
 
   /* IPv4 prefix. */
@@ -790,7 +802,7 @@
     
   /* Table */
   rib->table=zebrad.rtm_table_default;
-  rib_add_ipv4_multipath (&p, rib);
+  rib_add_ipv4_multipath (&p, rib, safi);
   return 0;
 }
 
@@ -817,6 +829,7 @@
   api.type = stream_getc (s);
   api.flags = stream_getc (s);
   api.message = stream_getc (s);
+  api.safi = stream_getw (s);
 
   /* IPv4 prefix. */
   memset (&p, 0, sizeof (struct prefix_ipv4));
@@ -866,7 +879,7 @@
     api.metric = 0;
     
   rib_delete_ipv4 (api.type, api.flags, &p, nexthop_p, ifindex,
-		   client->rtm_table);
+		   client->rtm_table, api.safi);
   return 0;
 }
 
@@ -918,6 +931,7 @@
 
   api.flags = stream_getc (s);
   api.message = stream_getc (s);
+  api.safi = stream_getw (s);
 
   /* IPv4 prefix. */
   memset (&p, 0, sizeof (struct prefix_ipv6));
@@ -959,10 +973,10 @@
     
   if (IN6_IS_ADDR_UNSPECIFIED (&nexthop))
     rib_add_ipv6 (api.type, api.flags, &p, NULL, ifindex, zebrad.rtm_table_default, api.metric,
-		  api.distance);
+		  api.distance, api.safi);
   else
     rib_add_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, zebrad.rtm_table_default, api.metric,
-		  api.distance);
+		  api.distance, api.safi);
   return 0;
 }
 
@@ -985,6 +999,7 @@
   api.type = stream_getc (s);
   api.flags = stream_getc (s);
   api.message = stream_getc (s);
+  api.safi = stream_getw (s);
 
   /* IPv4 prefix. */
   memset (&p, 0, sizeof (struct prefix_ipv6));
@@ -1024,9 +1039,9 @@
     api.metric = 0;
     
   if (IN6_IS_ADDR_UNSPECIFIED (&nexthop))
-    rib_delete_ipv6 (api.type, api.flags, &p, NULL, ifindex, client->rtm_table);
+    rib_delete_ipv6 (api.type, api.flags, &p, NULL, ifindex, client->rtm_table, api.safi);
   else
-    rib_delete_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, client->rtm_table);
+    rib_delete_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, client->rtm_table, api.safi);
   return 0;
 }
 
@@ -1065,6 +1080,49 @@
   return 0;
 }
 
+/* Tie up route-type and client->sock */
+static void
+zread_hello (struct zserv *client)
+{
+  /* type of protocol (lib/zebra.h) */
+  u_char proto;
+  proto = stream_getc (client->ibuf);
+
+  /* accept only dynamic routing protocols */
+  if ((proto < ZEBRA_ROUTE_MAX)
+  &&  (proto > ZEBRA_ROUTE_STATIC))
+    {
+      zlog_notice ("client %d says hello and bids fair to announce only %s routes",
+                    client->sock, zebra_route_string(proto));
+
+      /* if route-type was binded by other client */
+      if (route_type_oaths[proto])
+        zlog_warn ("sender of %s routes changed %c->%c",
+                    zebra_route_string(proto), route_type_oaths[proto],
+                    client->sock);
+
+      route_type_oaths[proto] = client->sock;
+    }
+}
+
+/* If client sent routes of specific type, zebra removes it
+ * and returns number of deleted routes.
+ */
+static void
+zebra_score_rib (int client_sock)
+{
+  int i;
+
+  for (i = ZEBRA_ROUTE_RIP; i < ZEBRA_ROUTE_MAX; i++)
+    if (client_sock == route_type_oaths[i])
+      {
+        zlog_notice ("client %d disconnected. %lu %s routes removed from the rib",
+                      client_sock, rib_score_proto (i), zebra_route_string (i));
+        route_type_oaths[i] = 0;
+        break;
+      }
+}
+
 /* Close zebra client. */
 static void
 zebra_client_close (struct zserv *client)
@@ -1081,6 +1139,7 @@
   if (client->sock)
     {
       close (client->sock);
+      zebra_score_rib (client->sock);
       client->sock = -1;
     }
 
@@ -1288,6 +1347,9 @@
     case ZEBRA_IPV4_IMPORT_LOOKUP:
       zread_ipv4_import_lookup (client, length);
       break;
+    case ZEBRA_HELLO:
+      zread_hello (client);
+      break;
     default:
       zlog_info ("Zebra received unknown command %d", command);
       break;
@@ -1357,6 +1419,7 @@
       return;
     }
 
+  memset (&route_type_oaths, 0, sizeof (route_type_oaths));
   memset (&addr, 0, sizeof (struct sockaddr_in));
   addr.sin_family = AF_INET;
   addr.sin_port = htons (ZEBRA_PORT);
@@ -1427,6 +1490,8 @@
       return;
     }
 
+  memset (&route_type_oaths, 0, sizeof (route_type_oaths));
+
   /* Make server socket. */
   memset (&serv, 0, sizeof (struct sockaddr_un));
   serv.sun_family = AF_UNIX;
@@ -1738,11 +1803,11 @@
 
 /* Make zebra server socket, wiping any existing one (see bug #403). */
 void
-zebra_zserv_socket_init (void)
+zebra_zserv_socket_init (char *path)
 {
 #ifdef HAVE_TCP_ZEBRA
   zebra_serv ();
 #else
-  zebra_serv_un (ZEBRA_SERV_PATH);
+  zebra_serv_un (path ? path : ZEBRA_SERV_PATH);
 #endif /* HAVE_TCP_ZEBRA */
 }
diff --git a/zebra/zserv.h b/zebra/zserv.h
index e37041f..3d7ebbc 100644
--- a/zebra/zserv.h
+++ b/zebra/zserv.h
@@ -93,7 +93,7 @@
 /* Prototypes. */
 extern void zebra_init (void);
 extern void zebra_if_init (void);
-extern void zebra_zserv_socket_init (void);
+extern void zebra_zserv_socket_init (char *path);
 extern void hostinfo_get (void);
 extern void rib_init (void);
 extern void interface_list (void);