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

Message ID 20210415230545.22317-2-themiron@yandex-team.ru
State Changes Requested
Headers show
Series [Openvpn-devel,v2,1/2] Fix IPv4 default gateway with multiple route tables | expand

Commit Message

Vladislav Grishenko April 15, 2021, 1:05 p.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

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

Patch

diff --git a/src/openvpn/networking_sitnl.c b/src/openvpn/networking_sitnl.c
index 402d3303..02c34d6b 100644
--- a/src/openvpn/networking_sitnl.c
+++ b/src/openvpn/networking_sitnl.c
@@ -452,6 +452,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 */
@@ -472,6 +475,38 @@  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);
+
+                    /* route interface */
+                    ifindex = nh->rtnh_ifindex;
+                    /* initial route gateway  */
+                    gw = res->gw;
+
+                    while (RTA_OK(nha, nhalen))
+                    {
+                        switch (nha->rta_type)
+                        {
+                            /* GW for the route */
+                            case RTA_GATEWAY:
+                                memcpy(&gw, RTA_DATA(nha), res->addr_size);
+                                break;
+                        }
+
+                        nha = RTA_NEXT(nha, nhalen);
+                    }
+
+                    nh = RTNH_NEXT(nh);
+                }
+                break;
         }
 
         rta = RTA_NEXT(rta, len);