VPP-1283: IPv6 PMTU missing MTU value in ICMP6 message.
[vpp.git] / src / vnet / ip / ip6_forward.c
index b53cdc4..f4c51e2 100644 (file)
@@ -215,6 +215,50 @@ ip6_add_del_interface_address (vlib_main_t * vm,
                     vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
   vec_add1 (addr_fib, ip6_af);
 
+  /* *INDENT-OFF* */
+  if (!is_del)
+    {
+      /* When adding an address check that it does not conflict
+         with an existing address on any interface in this table. */
+      ip_interface_address_t *ia;
+      vnet_sw_interface_t *sif;
+
+      pool_foreach(sif, vnm->interface_main.sw_interfaces,
+      ({
+          if (im->fib_index_by_sw_if_index[sw_if_index] ==
+              im->fib_index_by_sw_if_index[sif->sw_if_index])
+            {
+              foreach_ip_interface_address
+                (&im->lookup_main, ia, sif->sw_if_index,
+                 0 /* honor unnumbered */ ,
+                 ({
+                   ip6_address_t * x =
+                     ip_interface_address_get_address
+                     (&im->lookup_main, ia);
+                   if (ip6_destination_matches_route
+                       (im, address, x, ia->address_length) ||
+                       ip6_destination_matches_route (im,
+                                                      x,
+                                                      address,
+                                                      address_length))
+                     {
+                       vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
+                       return
+                         clib_error_create
+                         ("failed to add %U which conflicts with %U for interface %U",
+                          format_ip6_address_and_length, address,
+                          address_length,
+                          format_ip6_address_and_length, x,
+                          ia->address_length,
+                          format_vnet_sw_if_index_name, vnm,
+                          sif->sw_if_index);
+                     }
+                 }));
+            }
+      }));
+    }
+  /* *INDENT-ON* */
+
   {
     uword elts_before = pool_elts (lm->if_address_pool);
 
@@ -1517,6 +1561,19 @@ typedef enum
  */
 #define IP6_MCAST_ADDR_MASK 0xffffffff
 
+always_inline void
+ip6_mtu_check (vlib_buffer_t * b, u16 packet_bytes,
+              u16 adj_packet_bytes, u32 * next, u32 * error)
+{
+  if (adj_packet_bytes >= 1280 && packet_bytes > adj_packet_bytes)
+    {
+      *error = IP6_ERROR_MTU_EXCEEDED;
+      icmp6_error_set_vnet_buffer (b, ICMP6_packet_too_big, 0,
+                                  adj_packet_bytes);
+      *next = IP6_REWRITE_NEXT_ICMP_ERROR;
+    }
+}
+
 always_inline uword
 ip6_rewrite_inline (vlib_main_t * vm,
                    vlib_node_runtime_t * node,
@@ -1662,16 +1719,14 @@ ip6_rewrite_inline (vlib_main_t * vm,
            }
 
          /* Check MTU of outgoing interface. */
-         error0 =
-           (vlib_buffer_length_in_chain (vm, p0) >
-            adj0[0].
-            rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
-            error0);
-         error1 =
-           (vlib_buffer_length_in_chain (vm, p1) >
-            adj1[0].
-            rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
-            error1);
+         ip6_mtu_check (p0, clib_net_to_host_u16 (ip0->payload_length) +
+                        sizeof (ip6_header_t),
+                        adj0[0].rewrite_header.max_l3_packet_bytes,
+                        &next0, &error0);
+         ip6_mtu_check (p1, clib_net_to_host_u16 (ip1->payload_length) +
+                        sizeof (ip6_header_t),
+                        adj1[0].rewrite_header.max_l3_packet_bytes,
+                        &next1, &error1);
 
          /* Don't adjust the buffer for hop count issue; icmp-error node
           * wants to see the IP headerr */
@@ -1805,14 +1860,13 @@ ip6_rewrite_inline (vlib_main_t * vm,
            }
 
          /* Check MTU of outgoing interface. */
-         error0 =
-           (vlib_buffer_length_in_chain (vm, p0) >
-            adj0[0].
-            rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
-            error0);
+         ip6_mtu_check (p0, clib_net_to_host_u16 (ip0->payload_length) +
+                        sizeof (ip6_header_t),
+                        adj0[0].rewrite_header.max_l3_packet_bytes,
+                        &next0, &error0);
 
          /* Don't adjust the buffer for hop count issue; icmp-error node
-          * wants to see the IP headerr */
+          * wants to see the IP header */
          if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
            {
              p0->current_data -= rw_len0;