ell.lists.linux.dev archive mirror
 help / color / mirror / Atom feed
* Re: [PATCH 04/13] netconfig: Support IPv6 static configurations
@ 2022-04-27 13:30 Denis Kenzior
  0 siblings, 0 replies; 6+ messages in thread
From: Denis Kenzior @ 2022-04-27 13:30 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 4428 bytes --]

Hi Andrew,

On 4/22/22 13:59, Andrew Zaborowski wrote:
> ---
>   ell/netconfig.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++--
>   1 file changed, 143 insertions(+), 5 deletions(-)
> 

So I was going to apply this, but let me ask you this first...

<snip>

> @@ -159,6 +161,50 @@ static void netconfig_add_v4_routes(struct l_netconfig *nc, const char *ip,
>   	l_queue_push_tail(nc->routes.added, nc->v4_default_route);
>   }
>   
> +static void netconfig_add_v6_static_routes(struct l_netconfig *nc,
> +						const char *ip,
> +						uint8_t prefix_len)
> +{
> +	struct in6_addr in6_addr;
> +	char network[INET6_ADDRSTRLEN];
> +	struct l_rtnl_route *v6_subnet_route;
> +	struct l_rtnl_route *v6_default_route;
> +
> +	/* Subnet route */
> +
> +	if (L_WARN_ON(inet_pton(AF_INET6, ip, &in6_addr) != 1))
> +		return;
> +
> +	/* Zero out host address bits to produce network address */
> +	if (prefix_len & 7)
> +		in6_addr.s6_addr[prefix_len / 8] &= 0xff00 >> (prefix_len & 7);

Can we make this a bit cleaner? Something like

last_byte = prefix_len / 8;

if (prefix_len & 7) {
	/* zero out lsb bits */
	last_byte += 1;
}

memset(in6_addr + last_byte, 0, 16 - last_byte);

However, the more general question here is why do we want to store and compute 
the prefix route separately?  Is the assumption here that all addresses use the 
noprefixroute flag?  Wouldn't it be simpler to just have the kernel handle this?

> +
> +	if (prefix_len <= 120)
> +		memset(in6_addr.s6_addr + (prefix_len + 7) / 8, 0,
> +			16 - (prefix_len + 7) / 8);
> +
> +	if (L_WARN_ON(!inet_ntop(AF_INET6, &in6_addr, network,
> +					INET6_ADDRSTRLEN)))
> +		return;
> +
> +	v6_subnet_route = l_rtnl_route_new_prefix(network, prefix_len);
> +	l_rtnl_route_set_protocol(v6_subnet_route, RTPROT_STATIC);
> +	l_rtnl_route_set_priority(v6_subnet_route, nc->route_priority);
> +	l_queue_push_tail(nc->routes.current, v6_subnet_route);
> +	l_queue_push_tail(nc->routes.added, v6_subnet_route);
> +
> +	/* Gateway route */
> +
> +	if (!nc->v6_gateway_override)
> +		return;
> +
> +	v6_default_route = l_rtnl_route_new_gateway(nc->v6_gateway_override);
> +	l_rtnl_route_set_protocol(v6_default_route, RTPROT_STATIC);
> +	L_WARN_ON(!l_rtnl_route_set_prefsrc(v6_default_route, ip));
> +	l_queue_push_tail(nc->routes.current, v6_default_route);
> +	l_queue_push_tail(nc->routes.added, v6_default_route);
> +}
> +
>   static void netconfig_add_dhcp_address_routes(struct l_netconfig *nc)
>   {
>   	const struct l_dhcp_lease *lease =

<snip>

> @@ -580,11 +629,56 @@ static bool netconfig_check_v4_config(struct l_netconfig *netconfig)
>   	return true;
>   }
>   
> +static bool netconfig_check_v6_config(struct l_netconfig *netconfig)
> +{
> +	struct in6_addr local;
> +	struct in6_addr gateway;
> +	uint8_t prefix_len = 0;
> +	unsigned int dns_num = 0;
> +	_auto_(l_free) struct in6_addr *dns_list = NULL;
> +
> +	if (!netconfig->v6_enabled)
> +		return true;
> +
> +	if (netconfig->v6_static_addr) {
> +		char str[INET6_ADDRSTRLEN];
> +
> +		prefix_len = l_rtnl_address_get_prefix_length(
> +						netconfig->v6_static_addr);
> +		if (unlikely(prefix_len > 126))
> +			return false;
> +
> +		l_rtnl_address_get_address(netconfig->v6_static_addr, str);
> +		inet_pton(AF_INET6, str, &local);
> +	}
> +
> +	if (netconfig->v6_gateway_override) {
> +		if (unlikely(inet_pton(AF_INET6, netconfig->v6_gateway_override,
> +					&gateway) != 1))
> +			return false;
> +	}
> +
> +	if (netconfig->v6_dns_override &&
> +			(dns_num = l_strv_length(netconfig->v6_dns_override))) {
> +		unsigned int i;
> +
> +		dns_list = l_new(struct in6_addr, dns_num);
> +
> +		for (i = 0; i < dns_num; i++)
> +			if (inet_pton(AF_INET6, netconfig->v6_dns_override[i],
> +					&dns_list[i]) != 1)
> +				return false;
> +	}
> +

All this checking is pure copy-paste of the v4 version.  Can they be combined?

> +	return true;
> +}
> +
>   static bool netconfig_check_config(struct l_netconfig *netconfig)
>   {
>   	/* TODO: error reporting through a debug log handler or otherwise */
>   
> -	return netconfig_check_v4_config(netconfig);
> +	return netconfig_check_v4_config(netconfig) &&
> +		netconfig_check_v6_config(netconfig);
>   }
>   
>   LIB_EXPORT bool l_netconfig_check_config(struct l_netconfig *netconfig)

Regards,
-Denis

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 04/13] netconfig: Support IPv6 static configurations
@ 2022-04-27 22:01 Denis Kenzior
  0 siblings, 0 replies; 6+ messages in thread
From: Denis Kenzior @ 2022-04-27 22:01 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 3856 bytes --]

Hi Andrew,

On 4/27/22 16:42, Andrew Zaborowski wrote:
> On Wed, 27 Apr 2022 at 16:48, Denis Kenzior <denkenz(a)gmail.com> wrote:
>>>> However, the more general question here is why do we want to store and compute
>>>> the prefix route separately?  Is the assumption here that all addresses use the
>>>> noprefixroute flag?  Wouldn't it be simpler to just have the kernel handle this?
>>>
>>> So I think we can do that if we're committing the addresses to the
>>> kernel ourselves.  If we have to delegate it to NM we still need this
>>> code.  In the end I think it's easier to have just one branch here.
>>
>> Explain?  NM doesn't understand the noprefixroute flag?  Just curious.  I think
>> we do indeed need to do it as you propose.  See below.
> 
> After some digging my understanding is that NM internally stores the
> address flags bitmap and the IWD backend could set it or clear
> IFA_F_NOPREFIXROUTE on the addresses received from IWD.  But the core
> code doesn't often look at whether IFA_F_NOPREFIXROUTE is set because
> there's a policy in their netconfig code that basically it should be
> always set.  The logic is quite involved but basically NM will set the
> flag when talking to the kernel, and then will autogenerate the subnet
> routes for IPv4 (statically or dynamically assigned) and for IPv6
> static configs.  That means that IWD doesn't need to give NM those
> subnet routes, same as if IFA_F_NOPREFIXROUTE was cleared.

Thanks, that was helpful.

> 
> On the other hand my thinking is that 1. we might want to not shape
> the ell API based on current NM behaviour and might want to add the
> subnet routes at the risk of NM ignoring them or adding duplicates.

I really have no strong feelings one way or the other.  I suspect that unless we 
can add a metric info directly to the address, we are stuck using noprefixroute 
flag in all cases.

<snip>

> 
> Here are some interesting comments in NM code:
> https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/main/src/libnm-platform/nm-platform.c#L5388-5404
> https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/main/src/libnm-platform/nm-platform.h#L411-425
> https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/main/src/core/nm-l3-config-data.c#L2418-2430
> https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/main/src/core/nm-l3-config-data.c#L2457-2465
> 

So they actually try and work around kernels with no 'noprefixroute' flag 
support.  We don't need to worry about this since iwd only works with kernels 
where this is standard.

>>
>>>
>>> Having the kernel handle the subnet routes is even more obvious for
>>> IPv4 because it works for static as well as DHCP.  For some reason the
>>> IWD code always sets this flag for both IPv4 and IPv6.
>>>
>>
>> I don't recall exactly why we originally added the connected route separately.
>> I'm pretty sure this resulted in two prefix routes in the routing table until I
>> introduced the noprefixroute flag to ell.
>>
>> But I *think* the reason we add a separate connected route, in icmp6 at least,
>> is to make sure the metric is applied properly.  If noprefixroute flag isn't
>> set, the kernel will automagically create a new connected route when the address
>> is installed.  But the metric used for this route is the default.
> 
> Ok I didn't know that, and it matches what NM comments say too.  I
> guess this matters because the local subnet needs a higher metric than
> other routes?

It is mostly to deal with multiple interfaces connected to the same subnet.  For 
example, you may have wifi + ethernet connected to the same access point.  You 
would want the packets to the local subnet to be routed over ethernet (with a 
lower metric) than over WiFi.

Regards,
-Denis

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 04/13] netconfig: Support IPv6 static configurations
@ 2022-04-27 21:42 Andrew Zaborowski
  0 siblings, 0 replies; 6+ messages in thread
From: Andrew Zaborowski @ 2022-04-27 21:42 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 3434 bytes --]

On Wed, 27 Apr 2022 at 16:48, Denis Kenzior <denkenz(a)gmail.com> wrote:
> >> However, the more general question here is why do we want to store and compute
> >> the prefix route separately?  Is the assumption here that all addresses use the
> >> noprefixroute flag?  Wouldn't it be simpler to just have the kernel handle this?
> >
> > So I think we can do that if we're committing the addresses to the
> > kernel ourselves.  If we have to delegate it to NM we still need this
> > code.  In the end I think it's easier to have just one branch here.
>
> Explain?  NM doesn't understand the noprefixroute flag?  Just curious.  I think
> we do indeed need to do it as you propose.  See below.

After some digging my understanding is that NM internally stores the
address flags bitmap and the IWD backend could set it or clear
IFA_F_NOPREFIXROUTE on the addresses received from IWD.  But the core
code doesn't often look at whether IFA_F_NOPREFIXROUTE is set because
there's a policy in their netconfig code that basically it should be
always set.  The logic is quite involved but basically NM will set the
flag when talking to the kernel, and then will autogenerate the subnet
routes for IPv4 (statically or dynamically assigned) and for IPv6
static configs.  That means that IWD doesn't need to give NM those
subnet routes, same as if IFA_F_NOPREFIXROUTE was cleared.

On the other hand my thinking is that 1. we might want to not shape
the ell API based on current NM behaviour and might want to add the
subnet routes at the risk of NM ignoring them or adding duplicates.
These routes can also be dropped (or added) at the IWD-backend or IWD
level.

2. We may want to avoid adding too many address parameters and flags
in the D-Bus API, or the ell C API.

Here are some interesting comments in NM code:
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/main/src/libnm-platform/nm-platform.c#L5388-5404
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/main/src/libnm-platform/nm-platform.h#L411-425
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/main/src/core/nm-l3-config-data.c#L2418-2430
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/main/src/core/nm-l3-config-data.c#L2457-2465

>
> >
> > Having the kernel handle the subnet routes is even more obvious for
> > IPv4 because it works for static as well as DHCP.  For some reason the
> > IWD code always sets this flag for both IPv4 and IPv6.
> >
>
> I don't recall exactly why we originally added the connected route separately.
> I'm pretty sure this resulted in two prefix routes in the routing table until I
> introduced the noprefixroute flag to ell.
>
> But I *think* the reason we add a separate connected route, in icmp6 at least,
> is to make sure the metric is applied properly.  If noprefixroute flag isn't
> set, the kernel will automagically create a new connected route when the address
> is installed.  But the metric used for this route is the default.

Ok I didn't know that, and it matches what NM comments say too.  I
guess this matters because the local subnet needs a higher metric than
other routes?

>
> I don't think we found a way to affect the connected route's metric without
> resorting to the noprefixroute flag and adding the route separately.  Maybe it
> is possible?  Would save us a round trip.

Best regards

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 04/13] netconfig: Support IPv6 static configurations
@ 2022-04-27 14:47 Denis Kenzior
  0 siblings, 0 replies; 6+ messages in thread
From: Denis Kenzior @ 2022-04-27 14:47 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 1579 bytes --]

Hi Andrew,

>> However, the more general question here is why do we want to store and compute
>> the prefix route separately?  Is the assumption here that all addresses use the
>> noprefixroute flag?  Wouldn't it be simpler to just have the kernel handle this?
> 
> So I think we can do that if we're committing the addresses to the
> kernel ourselves.  If we have to delegate it to NM we still need this
> code.  In the end I think it's easier to have just one branch here.

Explain?  NM doesn't understand the noprefixroute flag?  Just curious.  I think 
we do indeed need to do it as you propose.  See below.

> 
> Having the kernel handle the subnet routes is even more obvious for
> IPv4 because it works for static as well as DHCP.  For some reason the
> IWD code always sets this flag for both IPv4 and IPv6.
> 

I don't recall exactly why we originally added the connected route separately. 
I'm pretty sure this resulted in two prefix routes in the routing table until I 
introduced the noprefixroute flag to ell.

But I *think* the reason we add a separate connected route, in icmp6 at least, 
is to make sure the metric is applied properly.  If noprefixroute flag isn't 
set, the kernel will automagically create a new connected route when the address 
is installed.  But the metric used for this route is the default.

I don't think we found a way to affect the connected route's metric without 
resorting to the noprefixroute flag and adding the route separately.  Maybe it 
is possible?  Would save us a round trip.

Regards,
-Denis

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 04/13] netconfig: Support IPv6 static configurations
@ 2022-04-27 14:18 Andrew Zaborowski
  0 siblings, 0 replies; 6+ messages in thread
From: Andrew Zaborowski @ 2022-04-27 14:18 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 3099 bytes --]

On Wed, 27 Apr 2022 at 15:30, Denis Kenzior <denkenz(a)gmail.com> wrote:
> On 4/22/22 13:59, Andrew Zaborowski wrote:
> > +     /* Zero out host address bits to produce network address */
> > +     if (prefix_len & 7)
> > +             in6_addr.s6_addr[prefix_len / 8] &= 0xff00 >> (prefix_len & 7);
>
> Can we make this a bit cleaner? Something like
>
> last_byte = prefix_len / 8;
>
> if (prefix_len & 7) {
>         /* zero out lsb bits */
>         last_byte += 1;
> }
>
> memset(in6_addr + last_byte, 0, 16 - last_byte);

Ok.

>
> However, the more general question here is why do we want to store and compute
> the prefix route separately?  Is the assumption here that all addresses use the
> noprefixroute flag?  Wouldn't it be simpler to just have the kernel handle this?

So I think we can do that if we're committing the addresses to the
kernel ourselves.  If we have to delegate it to NM we still need this
code.  In the end I think it's easier to have just one branch here.

Having the kernel handle the subnet routes is even more obvious for
IPv4 because it works for static as well as DHCP.  For some reason the
IWD code always sets this flag for both IPv4 and IPv6.

> > @@ -580,11 +629,56 @@ static bool netconfig_check_v4_config(struct l_netconfig *netconfig)
> >       return true;
> >   }
> >
> > +static bool netconfig_check_v6_config(struct l_netconfig *netconfig)
> > +{
> > +     struct in6_addr local;
> > +     struct in6_addr gateway;
> > +     uint8_t prefix_len = 0;
> > +     unsigned int dns_num = 0;
> > +     _auto_(l_free) struct in6_addr *dns_list = NULL;
> > +
> > +     if (!netconfig->v6_enabled)
> > +             return true;
> > +
> > +     if (netconfig->v6_static_addr) {
> > +             char str[INET6_ADDRSTRLEN];
> > +
> > +             prefix_len = l_rtnl_address_get_prefix_length(
> > +                                             netconfig->v6_static_addr);
> > +             if (unlikely(prefix_len > 126))
> > +                     return false;
> > +
> > +             l_rtnl_address_get_address(netconfig->v6_static_addr, str);
> > +             inet_pton(AF_INET6, str, &local);
> > +     }
> > +
> > +     if (netconfig->v6_gateway_override) {
> > +             if (unlikely(inet_pton(AF_INET6, netconfig->v6_gateway_override,
> > +                                     &gateway) != 1))
> > +                     return false;
> > +     }
> > +
> > +     if (netconfig->v6_dns_override &&
> > +                     (dns_num = l_strv_length(netconfig->v6_dns_override))) {
> > +             unsigned int i;
> > +
> > +             dns_list = l_new(struct in6_addr, dns_num);
> > +
> > +             for (i = 0; i < dns_num; i++)
> > +                     if (inet_pton(AF_INET6, netconfig->v6_dns_override[i],
> > +                                     &dns_list[i]) != 1)
> > +                             return false;
> > +     }
> > +
>
> All this checking is pure copy-paste of the v4 version.  Can they be combined?

Ok, let me do it that way.

Best regards

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 04/13] netconfig: Support IPv6 static configurations
@ 2022-04-22 18:59 Andrew Zaborowski
  0 siblings, 0 replies; 6+ messages in thread
From: Andrew Zaborowski @ 2022-04-22 18:59 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 7880 bytes --]

---
 ell/netconfig.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 143 insertions(+), 5 deletions(-)

diff --git a/ell/netconfig.c b/ell/netconfig.c
index 04d23b3..09c783d 100644
--- a/ell/netconfig.c
+++ b/ell/netconfig.c
@@ -62,11 +62,13 @@ struct l_netconfig {
 	struct l_idle *do_static_work;
 	bool v4_configured;
 	struct l_dhcp_client *dhcp_client;
+	bool v6_configured;
 
 	/* These objects, if not NULL, are owned by @addresses and @routes */
 	struct l_rtnl_address *v4_address;
 	struct l_rtnl_route *v4_subnet_route;
 	struct l_rtnl_route *v4_default_route;
+	struct l_rtnl_address *v6_address;
 
 	struct {
 		struct l_queue *current;
@@ -159,6 +161,50 @@ static void netconfig_add_v4_routes(struct l_netconfig *nc, const char *ip,
 	l_queue_push_tail(nc->routes.added, nc->v4_default_route);
 }
 
+static void netconfig_add_v6_static_routes(struct l_netconfig *nc,
+						const char *ip,
+						uint8_t prefix_len)
+{
+	struct in6_addr in6_addr;
+	char network[INET6_ADDRSTRLEN];
+	struct l_rtnl_route *v6_subnet_route;
+	struct l_rtnl_route *v6_default_route;
+
+	/* Subnet route */
+
+	if (L_WARN_ON(inet_pton(AF_INET6, ip, &in6_addr) != 1))
+		return;
+
+	/* Zero out host address bits to produce network address */
+	if (prefix_len & 7)
+		in6_addr.s6_addr[prefix_len / 8] &= 0xff00 >> (prefix_len & 7);
+
+	if (prefix_len <= 120)
+		memset(in6_addr.s6_addr + (prefix_len + 7) / 8, 0,
+			16 - (prefix_len + 7) / 8);
+
+	if (L_WARN_ON(!inet_ntop(AF_INET6, &in6_addr, network,
+					INET6_ADDRSTRLEN)))
+		return;
+
+	v6_subnet_route = l_rtnl_route_new_prefix(network, prefix_len);
+	l_rtnl_route_set_protocol(v6_subnet_route, RTPROT_STATIC);
+	l_rtnl_route_set_priority(v6_subnet_route, nc->route_priority);
+	l_queue_push_tail(nc->routes.current, v6_subnet_route);
+	l_queue_push_tail(nc->routes.added, v6_subnet_route);
+
+	/* Gateway route */
+
+	if (!nc->v6_gateway_override)
+		return;
+
+	v6_default_route = l_rtnl_route_new_gateway(nc->v6_gateway_override);
+	l_rtnl_route_set_protocol(v6_default_route, RTPROT_STATIC);
+	L_WARN_ON(!l_rtnl_route_set_prefsrc(v6_default_route, ip));
+	l_queue_push_tail(nc->routes.current, v6_default_route);
+	l_queue_push_tail(nc->routes.added, v6_default_route);
+}
+
 static void netconfig_add_dhcp_address_routes(struct l_netconfig *nc)
 {
 	const struct l_dhcp_lease *lease =
@@ -388,6 +434,9 @@ LIB_EXPORT bool l_netconfig_set_family_enabled(struct l_netconfig *netconfig,
 	case AF_INET:
 		netconfig->v4_enabled = enabled;
 		return true;
+	case AF_INET6:
+		netconfig->v6_enabled = enabled;
+		return true;
 	}
 
 	return false;
@@ -580,11 +629,56 @@ static bool netconfig_check_v4_config(struct l_netconfig *netconfig)
 	return true;
 }
 
+static bool netconfig_check_v6_config(struct l_netconfig *netconfig)
+{
+	struct in6_addr local;
+	struct in6_addr gateway;
+	uint8_t prefix_len = 0;
+	unsigned int dns_num = 0;
+	_auto_(l_free) struct in6_addr *dns_list = NULL;
+
+	if (!netconfig->v6_enabled)
+		return true;
+
+	if (netconfig->v6_static_addr) {
+		char str[INET6_ADDRSTRLEN];
+
+		prefix_len = l_rtnl_address_get_prefix_length(
+						netconfig->v6_static_addr);
+		if (unlikely(prefix_len > 126))
+			return false;
+
+		l_rtnl_address_get_address(netconfig->v6_static_addr, str);
+		inet_pton(AF_INET6, str, &local);
+	}
+
+	if (netconfig->v6_gateway_override) {
+		if (unlikely(inet_pton(AF_INET6, netconfig->v6_gateway_override,
+					&gateway) != 1))
+			return false;
+	}
+
+	if (netconfig->v6_dns_override &&
+			(dns_num = l_strv_length(netconfig->v6_dns_override))) {
+		unsigned int i;
+
+		dns_list = l_new(struct in6_addr, dns_num);
+
+		for (i = 0; i < dns_num; i++)
+			if (inet_pton(AF_INET6, netconfig->v6_dns_override[i],
+					&dns_list[i]) != 1)
+				return false;
+	}
+
+	return true;
+}
+
 static bool netconfig_check_config(struct l_netconfig *netconfig)
 {
 	/* TODO: error reporting through a debug log handler or otherwise */
 
-	return netconfig_check_v4_config(netconfig);
+	return netconfig_check_v4_config(netconfig) &&
+		netconfig_check_v6_config(netconfig);
 }
 
 LIB_EXPORT bool l_netconfig_check_config(struct l_netconfig *netconfig)
@@ -595,7 +689,7 @@ LIB_EXPORT bool l_netconfig_check_config(struct l_netconfig *netconfig)
 	return netconfig_check_config(netconfig);
 }
 
-static void netconfig_add_static_address_routes(struct l_netconfig *nc)
+static void netconfig_add_v4_static_address_routes(struct l_netconfig *nc)
 {
 	char ip[INET_ADDRSTRLEN];
 	uint32_t prefix_len;
@@ -609,6 +703,29 @@ static void netconfig_add_static_address_routes(struct l_netconfig *nc)
 	netconfig_add_v4_routes(nc, ip, prefix_len, NULL, RTPROT_STATIC);
 }
 
+/*
+ * Just mirror the IPv4 behaviour with static IPv6 configuration.  It would
+ * be more logical to let the user choose between static IPv6 address and
+ * DHCPv6, and, completely independently, choose between static routes
+ * (if a static prefix length and/or gateway address is set) and ICMPv6.
+ * Yet a mechanism identical with IPv4 is easier to understand for a typical
+ * user so providing a static address just disables all automatic
+ * configuration.
+ */
+static void netconfig_add_v6_static_address_routes(struct l_netconfig *nc)
+{
+	char ip[INET6_ADDRSTRLEN];
+	uint32_t prefix_len;
+
+	nc->v6_address = l_rtnl_address_clone(nc->v6_static_addr);
+	l_queue_push_tail(nc->addresses.current, nc->v6_address);
+	l_queue_push_tail(nc->addresses.added, nc->v6_address);
+
+	l_rtnl_address_get_address(nc->v6_static_addr, ip);
+	prefix_len = l_rtnl_address_get_prefix_length(nc->v6_static_addr);
+	netconfig_add_v6_static_routes(nc, ip, prefix_len);
+}
+
 static void netconfig_do_static_config(struct l_idle *idle, void *user_data)
 {
 	struct l_netconfig *nc = user_data;
@@ -616,10 +733,16 @@ static void netconfig_do_static_config(struct l_idle *idle, void *user_data)
 	l_idle_remove(l_steal_ptr(nc->do_static_work));
 
 	if (nc->v4_static_addr && !nc->v4_configured) {
-		netconfig_add_static_address_routes(nc);
+		netconfig_add_v4_static_address_routes(nc);
 		nc->v4_configured = true;
 		netconfig_emit_event(nc, AF_INET, L_NETCONFIG_EVENT_CONFIGURE);
 	}
+
+	if (nc->v6_static_addr && !nc->v6_configured) {
+		netconfig_add_v6_static_address_routes(nc);
+		nc->v6_configured = true;
+		netconfig_emit_event(nc, AF_INET6, L_NETCONFIG_EVENT_CONFIGURE);
+	}
 }
 
 LIB_EXPORT bool l_netconfig_start(struct l_netconfig *netconfig)
@@ -631,7 +754,7 @@ LIB_EXPORT bool l_netconfig_start(struct l_netconfig *netconfig)
 		return false;
 
 	if (!netconfig->v4_enabled)
-		goto done;
+		goto configure_ipv6;
 
 	if (netconfig->v4_static_addr) {
 		/*
@@ -641,12 +764,26 @@ LIB_EXPORT bool l_netconfig_start(struct l_netconfig *netconfig)
 		netconfig->do_static_work = l_idle_create(
 						netconfig_do_static_config,
 						netconfig, NULL);
-		goto done;
+		goto configure_ipv6;
 	}
 
 	if (!l_dhcp_client_start(netconfig->dhcp_client))
 		return false;
 
+configure_ipv6:
+	if (!netconfig->v6_enabled)
+		goto done;
+
+	if (netconfig->v6_static_addr && !netconfig->do_static_work) {
+		/*
+		 * We're basically ready to configure the interface
+		 * but do this in an idle callback.
+		 */
+		netconfig->do_static_work = l_idle_create(
+						netconfig_do_static_config,
+						netconfig, NULL);
+	}
+
 done:
 	netconfig->started = true;
 	return true;
@@ -670,6 +807,7 @@ LIB_EXPORT void l_netconfig_stop(struct l_netconfig *netconfig)
 	netconfig->v4_address = NULL;
 	netconfig->v4_subnet_route = NULL;
 	netconfig->v4_default_route = NULL;
+	netconfig->v6_address = NULL;
 
 	l_dhcp_client_stop(netconfig->dhcp_client);
 }
-- 
2.32.0

^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2022-04-27 22:01 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-27 13:30 [PATCH 04/13] netconfig: Support IPv6 static configurations Denis Kenzior
  -- strict thread matches above, loose matches on Subject: below --
2022-04-27 22:01 Denis Kenzior
2022-04-27 21:42 Andrew Zaborowski
2022-04-27 14:47 Denis Kenzior
2022-04-27 14:18 Andrew Zaborowski
2022-04-22 18:59 Andrew Zaborowski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).