IPv6 transport class suppport

IPv6 supports the same concept of differentiated service for routing
protocols as IPv4, but like too many things, the standards committee
decided that having two names for the same thing wasn't good enough and
introduced a third more generic term transport class.

The socket option to set transport class works the same as IPv4, but the
arguments are different.

* lib/sockopt.[ch]
  * setsockopt_ipv6_tclass(): new function
* bgpd/bgp_network.c
  * bgp_connect(): set socket option
  * bgp_listener(): set socket option
* ospf6d/ospf6_network.c
  * ospf6_set_transport_class(): new function
  * ospf6_serv_sock(): set socket option
* ripngd/ripngd.c
  * ripng_make_socket(): set socket option
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index 9e3427d..b5fa948 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -322,6 +322,10 @@
 #ifdef IPTOS_PREC_INTERNETCONTROL
   if (sockunion_family (&peer->su) == AF_INET)
     setsockopt_ipv4_tos (peer->fd, IPTOS_PREC_INTERNETCONTROL);
+# ifdef HAVE_IPV6
+  else if (sockunion_family (&peer->su) == AF_INET6)
+    setsockopt_ipv6_tclass (peer->fd, IPTOS_PREC_INTERNETCONTROL);
+# endif
 #endif
 
   if (peer->password)
@@ -381,6 +385,10 @@
 #ifdef IPTOS_PREC_INTERNETCONTROL
   if (sa->sa_family == AF_INET)
     setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL);
+#  ifdef HAVE_IPV6
+  else if (sa->sa_family == AF_INET6)
+    setsockopt_ipv6_tclass (sock, IPTOS_PREC_INTERNETCONTROL);
+#  endif
 #endif
 
 #ifdef IPV6_V6ONLY
diff --git a/lib/sockopt.c b/lib/sockopt.c
index 9ff15ca..6385840 100644
--- a/lib/sockopt.c
+++ b/lib/sockopt.c
@@ -179,8 +179,19 @@
   
   return pktinfo->ipi6_ifindex;
 }
-#endif /* HAVE_IPV6 */
 
+int
+setsockopt_ipv6_tclass(int sock, int tclass)
+{
+  int ret;
+
+  ret = setsockopt (sock, IPPROTO_IPV6, IPV6_TCLASS, &tclass, sizeof (tclass));
+  if (ret < 0)
+    zlog_warn ("Can't set IPV6_TCLASS option for fd %d to %#x: %s",
+	       sock, tclass, safe_strerror(errno));
+  return ret;
+}
+#endif /* HAVE_IPV6 */
 
 /*
  * Process multicast socket options for IPv4 in an OS-dependent manner.
diff --git a/lib/sockopt.h b/lib/sockopt.h
index 69309e0..aced6d4 100644
--- a/lib/sockopt.h
+++ b/lib/sockopt.h
@@ -35,6 +35,7 @@
 extern int setsockopt_ipv6_unicast_hops (int, int);
 extern int setsockopt_ipv6_hoplimit (int, int);
 extern int setsockopt_ipv6_multicast_loop (int, int);
+extern int setsockopt_ipv6_tclass (int, int);
 #endif /* HAVE_IPV6 */
 
 /*
diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c
index 96b82af..3372238 100644
--- a/ospf6d/ospf6_network.c
+++ b/ospf6d/ospf6_network.c
@@ -64,6 +64,14 @@
 }
 
 void
+ospf6_set_transport_class (void)
+{
+#ifdef IPTOS_PREC_INTERNETCONTROL
+  setsockopt_ipv6_tclass (ospf6_sock, IPTOS_PREC_INTERNETCONTROL);
+#endif
+}
+
+void
 ospf6_set_checksum (void)
 {
   int offset = 12;
@@ -102,6 +110,7 @@
 #endif /*1*/
   ospf6_reset_mcastloop ();
   ospf6_set_pktinfo ();
+  ospf6_set_transport_class ();
   ospf6_set_checksum ();
 
   /* setup global in6_addr, allspf6 and alldr6 for later use */
diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c
index 6e32d83..d416255 100644
--- a/ripngd/ripngd.c
+++ b/ripngd/ripngd.c
@@ -117,6 +117,11 @@
   ret = setsockopt_ipv6_pktinfo (sock, 1);
   if (ret < 0)
     return ret;
+#ifdef IPTOS_PREC_INTERNETCONTROL
+  ret = setsockopt_ipv6_tclass (sock, IPTOS_PREC_INTERNETCONTROL);
+  if (ret < 0)
+    return ret;
+#endif
   ret = setsockopt_ipv6_multicast_hops (sock, 255);
   if (ret < 0)
     return ret;