ip6: fix IPv6 address calculation error using "ip route add" CLI 22/33422/10
authorJieqiang Wang <jieqiang.wang@arm.com>
Tue, 3 Aug 2021 16:07:52 +0000 (16:07 +0000)
committerNeale Ranns <neale@graphiant.com>
Wed, 20 Oct 2021 18:17:20 +0000 (18:17 +0000)
Using VPP CLI "ip route add" to add static IPv6 entries outputs wrong
results. Fix this error by correctly calculating IPv6 addresses with
different increased ranges and grouping ip4/ip6 prefix calculation
functionality into two functions.

Type: fix

Signed-off-by: Jieqiang Wang <jieqiang.wang@arm.com>
Reviewed-by: Lijian Zhang <lijian.zhang@arm.com>
Reviewed-by: Tianyu Li <tianyu.li@arm.com>
Change-Id: If954876301ca2095f9331799a086f75db936f246

src/vnet/fib/fib_types.c
src/vnet/fib/fib_types.h
src/vnet/ip/lookup.c

index eab5ca2..15e795a 100644 (file)
@@ -785,3 +785,56 @@ fib_route_path_is_attached (const fib_route_path_t *rpath)
     }
     return (0);
 }
+
+static void
+fib_prefix_ip4_addr_increment (fib_prefix_t *pfx)
+{
+    /* Calculate the addend based on the host length of address */
+    u32 incr = 1ULL << (32 - pfx->fp_len);
+    ip4_address_t dst = (pfx->fp_addr).ip4;
+    dst.as_u32 = clib_host_to_net_u32 (incr + clib_net_to_host_u32 (dst.as_u32));
+    pfx->fp_addr.ip4.as_u32 = dst.as_u32;
+}
+
+static void
+fib_prefix_ip6_addr_increment (fib_prefix_t *pfx)
+{
+    /*
+     * Calculate the addend based on the host length of address
+     * and which part(lower 64 bits or higher 64 bits) it lies
+     * in
+     */
+    u32 host_len = 128 - pfx->fp_len;
+    u64 incr = 1ULL << ((host_len > 64) ? (host_len - 64) : host_len);
+    i32 bucket = (host_len < 64 ? 1 : 0);
+    ip6_address_t dst = (pfx->fp_addr).ip6;
+    u64 tmp = incr + clib_net_to_host_u64 (dst.as_u64[bucket]);
+    /* Handle overflow */
+    if (bucket && (tmp < incr))
+    {
+        dst.as_u64[1] = clib_host_to_net_u64 (tmp);
+        dst.as_u64[0] = clib_host_to_net_u64 (1ULL + clib_net_to_host_u64 (dst.as_u64[0]));
+    }
+    else
+        dst.as_u64[bucket] = clib_host_to_net_u64 (tmp);
+
+    pfx->fp_addr.ip6.as_u128 = dst.as_u128;
+}
+
+/*
+ * Increase IPv4/IPv6 address according to the prefix length
+ */
+void fib_prefix_increment (fib_prefix_t *pfx)
+{
+    switch (pfx->fp_proto)
+    {
+    case FIB_PROTOCOL_IP4:
+        fib_prefix_ip4_addr_increment (pfx);
+        break;
+    case FIB_PROTOCOL_IP6:
+        fib_prefix_ip6_addr_increment (pfx);
+        break;
+    case FIB_PROTOCOL_MPLS:
+        break;
+    }
+}
index 55b404b..dbd4e97 100644 (file)
@@ -285,6 +285,11 @@ extern u8 * format_fib_forw_chain_type(u8 * s, va_list * args);
 extern dpo_proto_t fib_proto_to_dpo(fib_protocol_t fib_proto);
 extern fib_protocol_t dpo_proto_to_fib(dpo_proto_t dpo_proto);
 
+/**
+ * \brief Increase IPv4/IPv6 address according to the prefix length
+ */
+extern void fib_prefix_increment (fib_prefix_t *pfx);
+
 /**
  * Convert from BIER next-hop proto to FIB proto
  */
index 192c4c7..2bb667b 100644 (file)
@@ -304,20 +304,17 @@ vnet_ip_route_cmd (vlib_main_t * vm,
        }
       else if (0 < vec_len (rpaths))
        {
-         u32 k, n, incr;
-         ip46_address_t dst = prefixs[i].fp_addr;
+         u32 k, n;
          f64 t[2];
          n = count;
          t[0] = vlib_time_now (vm);
-         incr = 1 << ((FIB_PROTOCOL_IP4 == prefixs[0].fp_proto ? 32 : 128) -
-                      prefixs[i].fp_len);
 
          for (k = 0; k < n; k++)
            {
              fib_prefix_t rpfx = {
                .fp_len = prefixs[i].fp_len,
                .fp_proto = prefixs[i].fp_proto,
-               .fp_addr = dst,
+               .fp_addr = prefixs[i].fp_addr,
              };
 
              if (is_del)
@@ -329,21 +326,7 @@ vnet_ip_route_cmd (vlib_main_t * vm,
                                           FIB_SOURCE_CLI,
                                           FIB_ENTRY_FLAG_NONE, rpaths);
 
-             if (FIB_PROTOCOL_IP4 == prefixs[0].fp_proto)
-               {
-                 dst.ip4.as_u32 =
-                   clib_host_to_net_u32 (incr +
-                                         clib_net_to_host_u32 (dst.
-                                                               ip4.as_u32));
-               }
-             else
-               {
-                 int bucket = (incr < 64 ? 0 : 1);
-                 dst.ip6.as_u64[bucket] =
-                   clib_host_to_net_u64 (incr +
-                                         clib_net_to_host_u64 (dst.ip6.as_u64
-                                                               [bucket]));
-               }
+             fib_prefix_increment (&prefixs[i]);
            }
 
          t[1] = vlib_time_now (vm);