[Openvpn-devel,v3,2/2] Add basic support for multipath gateway

Message ID 20210416120708.1532-2-themiron@yandex-team.ru
State Under Review
Delegated to: Antonio Quartulli
Headers show
Series [Openvpn-devel,v3,1/2] Fix IPv4 default gateway with multiple route tables | expand

Commit Message

Vladislav Grishenko April 16, 2021, 2:07 a.m. UTC
Load balancing setup over multiple upstreams may include multipath
gateway route, which is not not supported by OpenVPN.
Let's add basic support for that for selecting best route for zero
destination address - use any one of nexthop addresses as a gateway,
weights are not handled.

Setup example:

    ip route add default \
        nexthop via 192.168.1.1 dev eth1 weight 1 \
        nexthop via 192.168.2.1 dev eth2 weight 1

v2: keep gateway address unchanged on lookup error
v3: reduce ammout of gateway address copying

Reported-by: Donald Sharp <donaldsharp72@gmail.com>
Signed-off-by: Vladislav Grishenko <themiron@yandex-team.ru>
---
 src/openvpn/networking_sitnl.c | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

Comments

Gert Doering April 18, 2021, 4:15 a.m. UTC | #1
Hi,

On Fri, Apr 16, 2021 at 05:07:08PM +0500, Vladislav Grishenko wrote:
> Load balancing setup over multiple upstreams may include multipath
> gateway route, which is not not supported by OpenVPN.
> Let's add basic support for that for selecting best route for zero
> destination address - use any one of nexthop addresses as a gateway,
> weights are not handled.

What happens with the current code when we encounter such a situation?

I assume it will "just not work" and find no gateway address?

gert
Antonio Quartulli April 18, 2021, 4:55 a.m. UTC | #2
On 18/04/2021 16:15, Gert Doering wrote:
> Hi,
> 
> On Fri, Apr 16, 2021 at 05:07:08PM +0500, Vladislav Grishenko wrote:
>> Load balancing setup over multiple upstreams may include multipath
>> gateway route, which is not not supported by OpenVPN.
>> Let's add basic support for that for selecting best route for zero
>> destination address - use any one of nexthop addresses as a gateway,
>> weights are not handled.
> 
> What happens with the current code when we encounter such a situation?
> 
> I assume it will "just not work" and find no gateway address?

Yeah, nexthops groups are just not parsed. So if the default GW is
configured this way, it will not be found.

This said, it's very likely the main routing table will have a classic
default route most of the time.

Still, we want to handle nexthop groups somehow.

Cheers,
Gert Doering April 18, 2021, 4:55 a.m. UTC | #3
Hi,

On Sun, Apr 18, 2021 at 04:55:23PM +0200, Antonio Quartulli wrote:
> Still, we want to handle nexthop groups somehow.

Then it looks like this needs testing and an ACK :-)

gert

Patch

diff --git a/src/openvpn/networking_sitnl.c b/src/openvpn/networking_sitnl.c
index ea1621ed..aa35f5f5 100644
--- a/src/openvpn/networking_sitnl.c
+++ b/src/openvpn/networking_sitnl.c
@@ -450,6 +450,9 @@  sitnl_route_save(struct nlmsghdr *n, void *arg)
 
     while (RTA_OK(rta, len))
     {
+        struct rtnexthop *nh;
+        int nhlen;
+
         switch (rta->rta_type)
         {
             /* route interface */
@@ -470,6 +473,37 @@  sitnl_route_save(struct nlmsghdr *n, void *arg)
             case RTA_TABLE:
                 table = *(unsigned int *)RTA_DATA(rta);
                 break;
+
+            /* multipath nexthops */
+            case RTA_MULTIPATH:
+                nh = RTA_DATA(rta);
+                nhlen = RTA_PAYLOAD(rta);
+
+                while (RTNH_OK(nh, nhlen))
+                {
+                    struct rtattr *nha = RTNH_DATA(nh);
+                    int nhalen = nh->rtnh_len - sizeof(*nh);
+
+                    /* init route interface & gateway */
+                    ifindex = nh->rtnh_ifindex;
+                    gw = NULL;
+
+                    while (RTA_OK(nha, nhalen))
+                    {
+                        switch (nha->rta_type)
+                        {
+                            /* GW for the route */
+                            case RTA_GATEWAY:
+                                gw = RTA_DATA(nha);
+                                break;
+                        }
+
+                        nha = RTA_NEXT(nha, nhalen);
+                    }
+
+                    nh = RTNH_NEXT(nh);
+                }
+                break;
         }
 
         rta = RTA_NEXT(rta, len);