Index | Thread | Search

From:
Florian Obser <florian@openbsd.org>
Subject:
Implement RFC 4191 default router preference.
To:
tech <tech@openbsd.org>
Date:
Tue, 23 Apr 2024 11:54:24 +0200

Download raw body.

Thread
  • Florian Obser:

    Implement RFC 4191 default router preference.

I'll work on RFC 4191 route information options next, which has the same
option. That's how I discovered that we never implemented this for the
default router. rtadvd had this feature back in the day...

OK?

diff --git frontend.c frontend.c
index 352479ffbba..6bda00ff4c2 100644
--- frontend.c
+++ frontend.c
@@ -1157,6 +1157,14 @@ build_packet(struct ra_iface *ra_iface)
 	else if (ra_options_conf->dfr) {
 		ra->nd_ra_router_lifetime =
 		    htons(ra_options_conf->router_lifetime);
+		/*
+		 * RFC 4191
+		 * If the Router Lifetime is zero, the preference value MUST be
+		 * set to (00) by the sender and MUST be ignored by the
+		 * receiver.
+		 */
+		if (ra_options_conf->router_lifetime > 0)
+			ra->nd_ra_flags_reserved |= ra_options_conf->rtpref;
 	}
 	ra->nd_ra_reachable = htonl(ra_options_conf->reachable_time);
 	ra->nd_ra_retransmit = htonl(ra_options_conf->retrans_timer);
diff --git parse.y parse.y
index 6ebd4eeb5d3..5b632521aff 100644
--- parse.y
+++ parse.y
@@ -29,6 +29,7 @@
 #include <sys/stat.h>
 
 #include <netinet/in.h>
+#include <netinet/icmp6.h>
 #include <net/if.h>
 
 #include <arpa/inet.h>
@@ -119,8 +120,8 @@ typedef struct {
 %token	RA_IFACE YES NO INCLUDE ERROR
 %token	DEFAULT ROUTER HOP LIMIT MANAGED ADDRESS
 %token	CONFIGURATION OTHER LIFETIME REACHABLE TIME RETRANS TIMER
-%token	AUTO PREFIX VALID PREFERRED LIFETIME ONLINK AUTONOMOUS
-%token	ADDRESS_CONFIGURATION DNS NAMESERVER SEARCH MTU NAT64
+%token	AUTO PREFIX VALID PREFERENCE PREFERRED LIFETIME ONLINK AUTONOMOUS
+%token	ADDRESS_CONFIGURATION DNS NAMESERVER SEARCH MTU NAT64 HIGH MEDIUM LOW
 
 %token	<v.string>	STRING
 %token	<v.number>	NUMBER
@@ -210,6 +211,15 @@ ra_opt_block	: DEFAULT ROUTER yesno {
 		| ROUTER LIFETIME NUMBER {
 			ra_options->router_lifetime = $3;
 		}
+		| ROUTER PREFERENCE HIGH {
+			ra_options->rtpref = ND_RA_FLAG_RTPREF_HIGH;
+		}
+		| ROUTER PREFERENCE MEDIUM {
+			ra_options->rtpref = ND_RA_FLAG_RTPREF_MEDIUM;
+		}
+		| ROUTER PREFERENCE LOW {
+			ra_options->rtpref = ND_RA_FLAG_RTPREF_LOW;
+		}
 		| REACHABLE TIME NUMBER {
 			ra_options->reachable_time = $3;
 		}
@@ -507,18 +517,22 @@ lookup(char *s)
 		{"configuration",	CONFIGURATION},
 		{"default",		DEFAULT},
 		{"dns",			DNS},
+		{"high",		HIGH},
 		{"hop",			HOP},
 		{"include",		INCLUDE},
 		{"interface",		RA_IFACE},
 		{"lifetime",		LIFETIME},
 		{"limit",		LIMIT},
+		{"low",			LOW},
 		{"managed",		MANAGED},
+		{"medium",		MEDIUM},
 		{"mtu",			MTU},
 		{"nameserver",		NAMESERVER},
 		{"nat64",		NAT64},
 		{"no",			NO},
 		{"on-link",		ONLINK},
 		{"other",		OTHER},
+		{"preference",		PREFERENCE},
 		{"preferred",		PREFERRED},
 		{"prefix",		PREFIX},
 		{"reachable",		REACHABLE},
diff --git printconf.c printconf.c
index f664e58de83..73468936547 100644
--- printconf.c
+++ printconf.c
@@ -23,6 +23,7 @@
 #include <sys/uio.h>
 
 #include <netinet/in.h>
+#include <netinet/icmp6.h>
 #include <net/if.h>
 
 #include <arpa/inet.h>
@@ -34,6 +35,7 @@
 #include "rad.h"
 
 const char*	yesno(int);
+const char*	rtpref(int);
 void		print_ra_options(const char*, const struct ra_options_conf*);
 void		print_prefix_options(const char*, const struct ra_prefix_conf*);
 
@@ -43,6 +45,22 @@ yesno(int flag)
 	return flag ? "yes" : "no";
 }
 
+const char*
+rtpref(int rtpref)
+{
+	switch (rtpref & ND_RA_FLAG_RTPREF_MASK) {
+	case ND_RA_FLAG_RTPREF_HIGH:
+		return "high";
+	case ND_RA_FLAG_RTPREF_MEDIUM:
+		return "medium";
+	case ND_RA_FLAG_RTPREF_LOW:
+		return "low";
+	default:
+		return "invalid";
+	}
+
+}
+
 void
 print_ra_options(const char *indent, const struct ra_options_conf *ra_options)
 {
@@ -56,6 +74,7 @@ print_ra_options(const char *indent, const struct ra_options_conf *ra_options)
 	printf("%smanaged address configuration %s\n", indent,
 	    yesno(ra_options->m_flag));
 	printf("%sother configuration %s\n", indent, yesno(ra_options->o_flag));
+	printf("%srouter preference %s\n", indent, rtpref(ra_options->rtpref));
 	printf("%srouter lifetime %d\n", indent, ra_options->router_lifetime);
 	printf("%sreachable time %u\n", indent, ra_options->reachable_time);
 	printf("%sretrans timer %u\n", indent, ra_options->retrans_timer);
diff --git rad.conf.5 rad.conf.5
index 3f71a9aeee9..6b9b210a945 100644
--- rad.conf.5
+++ rad.conf.5
@@ -120,6 +120,9 @@ like NTP servers or DNS name servers.
 The number of seconds this router is a valid default router after receiving
 a router advertisement message.
 The default is 1800 seconds.
+.It Ic router preference Pq Ic high Ns | Ns Ic medium Ns | Ns Ic low
+Indicates whether to prefer this router over other default routers.
+The default is medium.
 .\" .It Ic reachable time Ar number
 .\" XXX
 .\" .It Ic retrans timer Ar number
diff --git rad.h rad.h
index 714bb93765a..00f62bc9b24 100644
--- rad.h
+++ rad.h
@@ -93,6 +93,7 @@ struct ra_options_conf {
 	int		cur_hl;			/* current hop limit */
 	int		m_flag;			/* managed address conf flag */
 	int		o_flag;			/* other conf flag */
+	int		rtpref;			/* router preference */
 	int		router_lifetime;	/* default router lifetime */
 	uint32_t	reachable_time;
 	uint32_t	retrans_timer;

-- 
In my defence, I have been left unsupervised.