This commits allow overriding MTU using netlink attributes on
per-route basis. This is useful for routing protocols that can
advertice prefix specific MTUs between routers (e.g. NHRP).

Signed-off-by: Timo Teräs <[email protected]>
---
 lib/zclient.c         |  4 ++++
 lib/zclient.h         |  5 +++++
 zebra/connected.c     |  6 +++---
 zebra/kernel_socket.c |  4 ++--
 zebra/rib.h           |  9 ++++++--
 zebra/rt_netlink.c    | 57 +++++++++++++++++++++++++++++++++++++++++++++------
 zebra/zebra_rib.c     |  9 ++++++--
 zebra/zebra_vty.c     |  2 ++
 zebra/zserv.c         | 14 +++++++++++--
 9 files changed, 93 insertions(+), 17 deletions(-)

diff --git a/lib/zclient.c b/lib/zclient.c
index 0ce46fe..fa84c1b 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -563,6 +563,8 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, 
struct prefix_ipv4 *p,
     stream_putc (s, api->distance);
   if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC))
     stream_putl (s, api->metric);
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_MTU))
+    stream_putl (s, api->mtu);
 
   /* Put length at the first point of the stream. */
   stream_putw_at (s, 0, stream_get_endp (s));
@@ -617,6 +619,8 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, 
struct prefix_ipv6 *p,
     stream_putc (s, api->distance);
   if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC))
     stream_putl (s, api->metric);
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_MTU))
+    stream_putl (s, api->mtu);
 
   /* Put length at the first point of the stream. */
   stream_putw_at (s, 0, stream_get_endp (s));
diff --git a/lib/zclient.h b/lib/zclient.h
index 3490b32..6e1d08a 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -93,6 +93,7 @@ struct zclient
 #define ZAPI_MESSAGE_IFINDEX  0x02
 #define ZAPI_MESSAGE_DISTANCE 0x04
 #define ZAPI_MESSAGE_METRIC   0x08
+#define ZAPI_MESSAGE_MTU      0x10
 
 /* Zserv protocol message header */
 struct zserv_header
@@ -128,6 +129,8 @@ struct zapi_ipv4
 
   u_int32_t metric;
 
+  u_int32_t mtu;
+
   vrf_id_t vrf_id;
 };
 
@@ -201,6 +204,8 @@ struct zapi_ipv6
 
   u_int32_t metric;
 
+  u_int32_t mtu;
+
   vrf_id_t vrf_id;
 };
 
diff --git a/zebra/connected.c b/zebra/connected.c
index 244f291..84b0d1c 100644
--- a/zebra/connected.c
+++ b/zebra/connected.c
@@ -192,10 +192,10 @@ connected_up_ipv4 (struct interface *ifp, struct 
connected *ifc)
     return;
 
   rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex,
-       ifp->vrf_id, RT_TABLE_MAIN, ifp->metric, 0, SAFI_UNICAST);
+       ifp->vrf_id, RT_TABLE_MAIN, ifp->metric, 0, 0, SAFI_UNICAST);
 
   rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex,
-       ifp->vrf_id, RT_TABLE_MAIN, ifp->metric, 0, SAFI_MULTICAST);
+       ifp->vrf_id, RT_TABLE_MAIN, ifp->metric, 0, 0, SAFI_MULTICAST);
 
   rib_update (ifp->vrf_id);
 }
@@ -356,7 +356,7 @@ connected_up_ipv6 (struct interface *ifp, struct connected 
*ifc)
 #endif
 
   rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, ifp->vrf_id,
-                RT_TABLE_MAIN, ifp->metric, 0, SAFI_UNICAST);
+                RT_TABLE_MAIN, ifp->metric, 0, 0, SAFI_UNICAST);
 
   rib_update (ifp->vrf_id);
 }
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index 2f7d27e..3c94b52 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -963,7 +963,7 @@ rtm_read (struct rt_msghdr *rtm)
           || rtm->rtm_type == RTM_ADD
           || rtm->rtm_type == RTM_CHANGE)
         rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin.sin_addr,
-                      NULL, 0, VRF_DEFAULT, 0, 0, 0, SAFI_UNICAST);
+                      NULL, 0, VRF_DEFAULT, 0, 0, 0, 0, SAFI_UNICAST);
       else
         rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p,
                          &gate.sin.sin_addr, 0, VRF_DEFAULT, SAFI_UNICAST);
@@ -1005,7 +1005,7 @@ rtm_read (struct rt_msghdr *rtm)
           || rtm->rtm_type == RTM_ADD
           || rtm->rtm_type == RTM_CHANGE)
         rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, 
&gate.sin6.sin6_addr,
-                      ifindex, VRF_DEFAULT, RT_TABLE_MAIN, 0, 0, SAFI_UNICAST);
+                      ifindex, VRF_DEFAULT, RT_TABLE_MAIN, 0, 0, 0, 
SAFI_UNICAST);
       else
         rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p,
                          &gate.sin6.sin6_addr, ifindex,
diff --git a/zebra/rib.h b/zebra/rib.h
index 6e0966a..fbf4fc4 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -66,6 +66,10 @@ struct rib
   /* Metric */
   u_int32_t metric;
 
+  /* MTU */
+  u_int32_t mtu;
+  u_int32_t nexthop_mtu;
+
   /* Distance. */
   u_char distance;
 
@@ -494,7 +498,7 @@ extern struct route_table *zebra_vrf_static_table (afi_t, 
safi_t, vrf_id_t);
 extern int rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, 
                         struct in_addr *gate, struct in_addr *src,
                         unsigned int ifindex, vrf_id_t vrf_id, int table_id,
-                        u_int32_t, u_char, safi_t);
+                        u_int32_t, u_int32_t, u_char, safi_t);
 
 extern int rib_add_ipv4_multipath (struct prefix_ipv4 *, struct rib *, safi_t);
 
@@ -531,7 +535,8 @@ static_delete_ipv4_safi (safi_t safi, struct prefix *p, 
struct in_addr *gate,
 extern int
 rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p,
              struct in6_addr *gate, unsigned int ifindex, vrf_id_t vrf_id,
-             int table_id, u_int32_t metric, u_char distance, safi_t safi);
+             int table_id, u_int32_t metric, u_int32_t mtu,
+             u_char distance, safi_t safi);
 
 extern int
 rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 16f6cbe..02a2d72 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -668,6 +668,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct 
nlmsghdr *h,
   int index;
   int table;
   int metric;
+  u_int32_t mtu = 0;
 
   void *dest;
   void *gate;
@@ -730,6 +731,18 @@ netlink_routing_table (struct sockaddr_nl *snl, struct 
nlmsghdr *h,
   if (tb[RTA_PRIORITY])
     metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
 
+  if (tb[RTA_METRICS])
+    {
+      struct rtattr *mxrta[RTAX_MAX+1];
+
+      memset (mxrta, 0, sizeof mxrta);
+      netlink_parse_rtattr (mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]),
+                            RTA_PAYLOAD(tb[RTA_METRICS]));
+
+      if (mxrta[RTAX_MTU])
+        mtu = *(u_int32_t *) RTA_DATA(mxrta[RTAX_MTU]);
+    }
+
   if (rtm->rtm_family == AF_INET)
     {
       struct prefix_ipv4 p;
@@ -739,7 +752,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct 
nlmsghdr *h,
 
       if (!tb[RTA_MULTIPATH])
           rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index,
-                        vrf_id, table, metric, 0, SAFI_UNICAST);
+                        vrf_id, table, metric, mtu, 0, SAFI_UNICAST);
       else
         {
           /* This is a multipath route */
@@ -755,6 +768,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct 
nlmsghdr *h,
           rib->distance = 0;
           rib->flags = flags;
           rib->metric = metric;
+          rib->mtu = mtu;
           rib->vrf_id = vrf_id;
           rib->table = table;
           rib->nexthop_num = 0;
@@ -805,7 +819,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct 
nlmsghdr *h,
       p.prefixlen = rtm->rtm_dst_len;
 
       rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, vrf_id,
-                    table, metric, 0, SAFI_UNICAST);
+                    table, metric, mtu, 0, SAFI_UNICAST);
     }
 #endif /* HAVE_IPV6 */
 
@@ -841,6 +855,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct 
nlmsghdr *h,
   int index;
   int table;
   int metric;
+  u_int32_t mtu = 0;
 
   void *dest;
   void *gate;
@@ -919,8 +934,23 @@ netlink_route_change (struct sockaddr_nl *snl, struct 
nlmsghdr *h,
   if (tb[RTA_PREFSRC])
     src = RTA_DATA (tb[RTA_PREFSRC]);
 
-  if (h->nlmsg_type == RTM_NEWROUTE && tb[RTA_PRIORITY])
-    metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
+  if (h->nlmsg_type == RTM_NEWROUTE)
+    {
+      if (tb[RTA_PRIORITY])
+        metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
+
+      if (tb[RTA_METRICS])
+        {
+          struct rtattr *mxrta[RTAX_MAX+1];
+
+          memset (mxrta, 0, sizeof mxrta);
+          netlink_parse_rtattr (mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]),
+                                RTA_PAYLOAD(tb[RTA_METRICS]));
+
+          if (mxrta[RTAX_MTU])
+            mtu = *(u_int32_t *) RTA_DATA(mxrta[RTAX_MTU]);
+        }
+    }
 
   if (rtm->rtm_family == AF_INET)
     {
@@ -941,7 +971,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct 
nlmsghdr *h,
         {
           if (!tb[RTA_MULTIPATH])
             rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, vrf_id,
-                          table, metric, 0, SAFI_UNICAST);
+                          table, metric, mtu, 0, SAFI_UNICAST);
           else
             {
               /* This is a multipath route */
@@ -957,6 +987,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct 
nlmsghdr *h,
               rib->distance = 0;
               rib->flags = 0;
               rib->metric = metric;
+              rib->mtu = mtu;
               rib->vrf_id = vrf_id;
               rib->table = table;
               rib->nexthop_num = 0;
@@ -1022,7 +1053,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct 
nlmsghdr *h,
 
       if (h->nlmsg_type == RTM_NEWROUTE)
         rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id, table,
-                      metric, 0, SAFI_UNICAST);
+                      metric, mtu, 0, SAFI_UNICAST);
       else
         rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id,
                          SAFI_UNICAST);
@@ -1635,6 +1666,20 @@ netlink_route_multipath (int cmd, struct prefix *p, 
struct rib *rib,
   /* Metric. */
   addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
 
+  if (rib->mtu || rib->nexthop_mtu)
+    {
+      char buf[NL_PKT_BUF_SIZE];
+      struct rtattr *rta = (void *) buf;
+      u_int32_t mtu = rib->mtu;
+      if (!mtu || (rib->nexthop_mtu && rib->nexthop_mtu < mtu))
+        mtu = rib->nexthop_mtu;
+      rta->rta_type = RTA_METRICS;
+      rta->rta_len = RTA_LENGTH(0);
+      rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTAX_MTU, &mtu, sizeof mtu);
+      addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_METRICS, RTA_DATA (rta),
+                 RTA_PAYLOAD (rta));
+    }
+
   if (discard)
     {
       if (cmd == RTM_NEWROUTE)
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index cb1d86d..385e2d6 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -361,6 +361,7 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop 
*nexthop, int set,
       UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
       nexthops_free(nexthop->resolved);
       nexthop->resolved = NULL;
+      rib->nexthop_mtu = 0;
     }
 
   /* Make lookup prefix. */
@@ -469,6 +470,8 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop 
*nexthop, int set,
                      }
                    resolved = 1;
                  }
+              if (resolved && set)
+                rib->nexthop_mtu = match->mtu;
              return resolved;
            }
          else
@@ -1715,7 +1718,7 @@ int
 rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, 
              struct in_addr *gate, struct in_addr *src,
              unsigned int ifindex, vrf_id_t vrf_id, int table_id,
-             u_int32_t metric, u_char distance, safi_t safi)
+             u_int32_t metric, u_int32_t mtu, u_char distance, safi_t safi)
 {
   struct rib *rib;
   struct rib *same = NULL;
@@ -1778,6 +1781,7 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p,
   rib->distance = distance;
   rib->flags = flags;
   rib->metric = metric;
+  rib->mtu = mtu;
   rib->vrf_id = vrf_id;
   rib->table = table_id;
   rib->nexthop_num = 0;
@@ -2507,7 +2511,7 @@ int
 rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p,
              struct in6_addr *gate, unsigned int ifindex,
              vrf_id_t vrf_id, int table_id,
-             u_int32_t metric, u_char distance, safi_t safi)
+             u_int32_t metric, u_int32_t mtu, u_char distance, safi_t safi)
 {
   struct rib *rib;
   struct rib *same = NULL;
@@ -2563,6 +2567,7 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p,
   rib->distance = distance;
   rib->flags = flags;
   rib->metric = metric;
+  rib->mtu = mtu;
   rib->vrf_id = vrf_id;
   rib->table = table_id;
   rib->nexthop_num = 0;
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 6ad286f..b37b901 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -1290,6 +1290,8 @@ vty_show_ip_route_detail (struct vty *vty, struct 
route_node *rn, int mcast)
               VTY_NEWLINE);
       vty_out (vty, "  Known via \"%s\"", zebra_route_string (rib->type));
       vty_out (vty, ", distance %u, metric %u", rib->distance, rib->metric);
+      if (rib->mtu)
+        vty_out (vty, ", mtu %u", rib->mtu);
       vty_out (vty, ", vrf %u", rib->vrf_id);
       if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
         vty_out (vty, ", best");
diff --git a/zebra/zserv.c b/zebra/zserv.c
index e26c8ca..7a75ed4 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -455,6 +455,8 @@ zsend_route_multipath (int cmd, struct zserv *client, 
struct prefix *p,
       stream_putc (s, rib->distance);
       SET_FLAG (zapi_flags, ZAPI_MESSAGE_METRIC);
       stream_putl (s, rib->metric);
+      SET_FLAG (zapi_flags, ZAPI_MESSAGE_MTU);
+      stream_putl (s, rib->mtu);
     }
   
   /* write real message flags value */
@@ -903,6 +905,9 @@ zread_ipv4_add (struct zserv *client, u_short length, 
vrf_id_t vrf_id)
   if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC))
     rib->metric = stream_getl (s);
     
+  if (CHECK_FLAG (message, ZAPI_MESSAGE_MTU))
+    rib->mtu = stream_getl (s);
+
   /* Table */
   rib->table=zebrad.rtm_table_default;
   rib_add_ipv4_multipath (&p, rib, safi);
@@ -1092,15 +1097,20 @@ zread_ipv6_add (struct zserv *client, u_short length, 
vrf_id_t vrf_id)
     api.metric = stream_getl (s);
   else
     api.metric = 0;
+
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_MTU))
+    api.mtu = stream_getl (s);
+  else
+    api.mtu = 0;
     
   if (IN6_IS_ADDR_UNSPECIFIED (&nexthop))
     rib_add_ipv6 (api.type, api.flags, &p, NULL, ifindex,
                   vrf_id, zebrad.rtm_table_default, api.metric,
-                  api.distance, api.safi);
+                  api.mtu, api.distance, api.safi);
   else
     rib_add_ipv6 (api.type, api.flags, &p, &nexthop, ifindex,
                   vrf_id, zebrad.rtm_table_default, api.metric,
-                  api.distance, api.safi);
+                  api.mtu, api.distance, api.safi);
   return 0;
 }
 
-- 
2.6.1


_______________________________________________
Quagga-dev mailing list
[email protected]
https://lists.quagga.net/mailman/listinfo/quagga-dev

Reply via email to