Blob Blame History Raw
From af6b1458f852dc164206dc2fc45467ade6a7f7ae Mon Sep 17 00:00:00 2001
From: Gris Ge <fge@redhat.com>
Date: Wed, 9 Feb 2022 23:33:40 +0800
Subject: [PATCH] python route: Add support of multipath route

Supporting the rout created by below command:

    sudo ip -6 route add 2001:db8:e::/64 proto static \
        nexthop via 2001:db8:f::254 dev eth1 weight 1 onlink \
        nexthop via 2001:db8:f::253 dev eth1 weight 256 onlink

Integration test case included.

Signed-off-by: Gris Ge <fge@redhat.com>
---
 libnmstate/nispor/route.py | 53 ++++++++++++++++++++++++++------------
 1 file changed, 36 insertions(+), 17 deletions(-)

diff --git a/libnmstate/nispor/route.py b/libnmstate/nispor/route.py
index 9852ba51..87543de2 100644
--- a/libnmstate/nispor/route.py
+++ b/libnmstate/nispor/route.py
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2020 Red Hat, Inc.
+# Copyright (c) 2020-2022 Red Hat, Inc.
 #
 # This file is part of nmstate
 #
@@ -17,6 +17,8 @@
 # along with this program. If not, see <https://www.gnu.org/licenses/>.
 #
 
+from copy import deepcopy
+
 from libnmstate.schema import Route
 
 
@@ -30,24 +32,24 @@ LOCAL_ROUTE_TABLE = 255
 
 
 def nispor_route_state_to_nmstate(np_routes):
-    return [
-        _nispor_route_to_nmstate(rt)
-        for rt in np_routes
-        if rt.scope in ["universe", "link"]
-        and rt.oif != "lo"
-        and rt.table != LOCAL_ROUTE_TABLE
-    ]
+    ret = []
+    for np_route in np_routes:
+        if np_route.oif != "lo" and np_route.table != LOCAL_ROUTE_TABLE:
+            ret.extend(_nispor_route_to_nmstate(np_route))
+    return ret
 
 
 def nispor_route_state_to_nmstate_static(np_routes):
-    return [
-        _nispor_route_to_nmstate(rt)
-        for rt in np_routes
-        if rt.scope in ["universe", "link"]
-        and rt.protocol not in ["kernel", "ra", "dhcp"]
-        and rt.oif != "lo"
-        and rt.table != LOCAL_ROUTE_TABLE
-    ]
+    ret = []
+    for np_route in np_routes:
+        if (
+            np_route.oif != "lo"
+            and np_route.table != LOCAL_ROUTE_TABLE
+            and np_route.scope in ["universe", "link"]
+            and np_route.protocol in ["static", "boot"]
+        ):
+            ret.extend(_nispor_route_to_nmstate(np_route))
+    return ret
 
 
 def _nispor_route_to_nmstate(np_rt):
@@ -71,10 +73,27 @@ def _nispor_route_to_nmstate(np_rt):
             else IPV4_EMPTY_NEXT_HOP_ADDRESS
         )
 
-    return {
+    nm_route = {
         Route.TABLE_ID: np_rt.table,
         Route.DESTINATION: destination,
         Route.NEXT_HOP_INTERFACE: np_rt.oif if np_rt.oif else "",
         Route.NEXT_HOP_ADDRESS: next_hop,
         Route.METRIC: np_rt.metric if np_rt.metric else 0,
     }
+    np_mp_rts = get_multipath_routes(np_rt)
+    if np_mp_rts:
+        ret = []
+        for np_mp_rt in np_mp_rts:
+            nm_route_clone = deepcopy(nm_route)
+            nm_route_clone[Route.NEXT_HOP_INTERFACE] = np_mp_rt["iface"]
+            nm_route_clone[Route.NEXT_HOP_ADDRESS] = np_mp_rt["via"]
+            ret.append(nm_route_clone)
+        return ret
+    else:
+        return [nm_route]
+
+
+# Instead of bumping nispor dependency version, we just use nispor private
+# property temporarily
+def get_multipath_routes(np_route):
+    return np_route._info.get("multipath")
-- 
2.27.0