Enhance vlib_buffer_clone to change headroom space for packet 20/18620/1
authorJohn Lo <loj@cisco.com>
Mon, 1 Apr 2019 15:30:07 +0000 (11:30 -0400)
committerJohn Lo <loj@cisco.com>
Mon, 1 Apr 2019 15:30:07 +0000 (11:30 -0400)
Add function vlib_buffer_clone_at_offset() so that the cloned
packets' 1st buffer will have the original packet header copied
at the specified offset (instead of current_data). This can be
used to increase headroom in the cloned packet to allow large
header encaps in case the stdandard 128B predata is not enough.
The original vlib_buffer_clone() still works the same as before.

Change-Id: I3b50c8ad7e3952568bc141710567c99a3dacddce
Signed-off-by: John Lo <loj@cisco.com>
src/vlib/buffer_funcs.h

index e7fd612..e9d0704 100644 (file)
@@ -1033,6 +1033,31 @@ vlib_buffer_copy_no_chain (vlib_main_t * vm, vlib_buffer_t * b, u32 * di)
   return d;
 }
 
+/*  \brief Move packet from current position to offset position in buffer.
+    Only work for small packet using one buffer with room to fit the move
+    @param vm - (vlib_main_t *) vlib main data structure pointer
+    @param b -  (vlib_buffer_t *) pointer to buffer
+    @param offset - (i16) position to move the packet in buffer
+ */
+always_inline void
+vlib_buffer_move (vlib_main_t * vm, vlib_buffer_t * b, i16 offset)
+{
+  ASSERT ((b->flags & VLIB_BUFFER_NEXT_PRESENT) == 0);
+  ASSERT (offset + VLIB_BUFFER_PRE_DATA_SIZE >= 0);
+  ASSERT (offset + b->current_length <
+         vlib_buffer_get_default_data_size (vm));
+
+  u8 *source = vlib_buffer_get_current (b);
+  b->current_data = offset;
+  u8 *destination = vlib_buffer_get_current (b);
+  u16 length = b->current_length;
+
+  if (source + length <= destination)  /* no overlap */
+    clib_memcpy_fast (destination, source, length);
+  else
+    memmove (destination, source, length);
+}
+
 /** \brief Create a maximum of 256 clones of buffer and store them
     in the supplied array
 
@@ -1042,12 +1067,14 @@ vlib_buffer_copy_no_chain (vlib_main_t * vm, vlib_buffer_t * b, u32 * di)
     @param n_buffers - (u16) number of buffer clones requested (<=256)
     @param head_end_offset - (u16) offset relative to current position
            where packet head ends
+    @param offset - (i16) copy packet head at current position if 0,
+           else at offset position to change headroom space as specified
     @return - (u16) number of buffers actually cloned, may be
     less than the number requested or zero
 */
 always_inline u16
 vlib_buffer_clone_256 (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
-                      u16 n_buffers, u16 head_end_offset)
+                      u16 n_buffers, u16 head_end_offset, i16 offset)
 {
   u16 i;
   vlib_buffer_t *s = vlib_get_buffer (vm, src_buffer);
@@ -1055,10 +1082,16 @@ vlib_buffer_clone_256 (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
   ASSERT (s->ref_count == 1);
   ASSERT (n_buffers);
   ASSERT (n_buffers <= 256);
+  ASSERT (offset + VLIB_BUFFER_PRE_DATA_SIZE >= 0);
+  ASSERT ((offset + head_end_offset) <
+         vlib_buffer_get_default_data_size (vm));
 
   if (s->current_length <= head_end_offset + CLIB_CACHE_LINE_BYTES * 2)
     {
       buffers[0] = src_buffer;
+      if (offset)
+       vlib_buffer_move (vm, s, offset);
+
       for (i = 1; i < n_buffers; i++)
        {
          vlib_buffer_t *d;
@@ -1071,7 +1104,7 @@ vlib_buffer_clone_256 (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
       return n_buffers;
     }
 
-  if (PREDICT_FALSE (n_buffers == 1))
+  if (PREDICT_FALSE ((n_buffers == 1) && (offset == 0)))
     {
       buffers[0] = src_buffer;
       return 1;
@@ -1083,7 +1116,11 @@ vlib_buffer_clone_256 (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
   for (i = 0; i < n_buffers; i++)
     {
       vlib_buffer_t *d = vlib_get_buffer (vm, buffers[i]);
-      d->current_data = s->current_data;
+      if (offset)
+       d->current_data = offset;
+      else
+       d->current_data = s->current_data;
+
       d->current_length = head_end_offset;
       ASSERT (d->buffer_pool_index == s->buffer_pool_index);
 
@@ -1122,12 +1159,14 @@ vlib_buffer_clone_256 (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
     @param n_buffers - (u16) number of buffer clones requested (<=256)
     @param head_end_offset - (u16) offset relative to current position
            where packet head ends
+    @param offset - (i16) copy packet head at current position if 0,
+           else at offset position to change headroom space as specified
     @return - (u16) number of buffers actually cloned, may be
     less than the number requested or zero
 */
 always_inline u16
-vlib_buffer_clone (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
-                  u16 n_buffers, u16 head_end_offset)
+vlib_buffer_clone_at_offset (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
+                            u16 n_buffers, u16 head_end_offset, i16 offset)
 {
   vlib_buffer_t *s = vlib_get_buffer (vm, src_buffer);
   u16 n_cloned = 0;
@@ -1139,16 +1178,36 @@ vlib_buffer_clone (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
       n_cloned += vlib_buffer_clone_256 (vm,
                                         vlib_get_buffer_index (vm, copy),
                                         (buffers + n_cloned),
-                                        256, head_end_offset);
+                                        256, head_end_offset, offset);
       n_buffers -= 256;
     }
   n_cloned += vlib_buffer_clone_256 (vm, src_buffer,
                                     buffers + n_cloned,
-                                    n_buffers, head_end_offset);
+                                    n_buffers, head_end_offset, offset);
 
   return n_cloned;
 }
 
+/** \brief Create multiple clones of buffer and store them
+    in the supplied array
+
+    @param vm - (vlib_main_t *) vlib main data structure pointer
+    @param src_buffer - (u32) source buffer index
+    @param buffers - (u32 * ) buffer index array
+    @param n_buffers - (u16) number of buffer clones requested (<=256)
+    @param head_end_offset - (u16) offset relative to current position
+           where packet head ends
+    @return - (u16) number of buffers actually cloned, may be
+    less than the number requested or zero
+*/
+always_inline u16
+vlib_buffer_clone (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
+                  u16 n_buffers, u16 head_end_offset)
+{
+  return vlib_buffer_clone_at_offset (vm, src_buffer, buffers, n_buffers,
+                                     head_end_offset, 0);
+}
+
 /** \brief Attach cloned tail to the buffer
 
     @param vm - (vlib_main_t *) vlib main data structure pointer