You need to say n_clones = 2 to get 2.
ref_cnt is updated only on tail buffer if tail buffer(s) exists.
Head buffers always have ref_cnt = 1.

Reason for that is that you actually never want to clone head buffer simply as 
if packet goes to 2
different interfaces it needs to have different L2 headers.

So it works as follows:

if n_clones = 1, simply return same buffer index

if n_clones > 1 and packet size is < VLIB_BUFFER_CLONE_HEAD_SIZE:
 - allocate (n_clones-1) new buffers
 - memcpy whole payload from original buffer to each allocated buffer

if n_clones > 1 and packet size is >= VLIB_BUFFER_CLONE_HEAD_SIZE
 - allocate (n_clones) new buffers
 - for each allocated buffer:
   - memcpy first VLIB_BUFFER_CLONE_HEAD_SIZE bytes of payload from original 
buffer
   - set b->next_buffer_index to point to the original buffer
 - advance b->current_data for VLIB_BUFFER_CLONE_HEAD_SIZE
 - set b->ref_cnt of the original buffer (and all his tails) to be n_clones
 

Hope this explains…

— 
Damjan





> On 08.04.2021., at 11:37, David Gohberg <[email protected]> wrote:
> 
> Hi,
> 
> In my node processing function, I want some buffers to be cloned and sent to 
> a specific host interface while also be sent to the "normal"  interface 
> resolved in the node.
> At the end, the node should be able to send the buffers to two different 
> interfaces simultaneously.
> packet -> node -> interface 1
>                     |
>                    V
>                 cloned packet
>                 to host interface
> 
> In my single loop where I process the buffers I added a call to this function:
> 
> static inline void replicate_and_send_buffer(vnet_main_t *vnm, vlib_main_t * 
> vm,
>                                 vlib_node_runtime_t * node,
>                                 u32 bi0,
>                                 u16 sw_if_index)
> {
>         u32 cbi0;
>         u16 n_cloned = vlib_buffer_clone (vm, bi0, &cbi0, 1, 
> VLIB_BUFFER_CLONE_HEAD_SIZE);
>         vnet_hw_interface_t * host_intf = vnet_get_sup_hw_interface (vnm, 
> sw_if_index);
>         u32 node_index = host_intf->tx_node_index;
>         vlib_frame_t *host_if_frame = vlib_get_frame_to_node(vm, node_index);
>         host_if_frame->n_vectors = 1;
>         u32 *to_next = vlib_frame_vector_args (host_if_frame);
>         to_next[0] = cbi0;
>         vlib_put_frame_to_node (vm, node_index, host_if_frame);
> }
> 
> What is happening here is that I clone the original buffer and put it in a 
> frame corresponding to the host interface node (in addition to the frame of 
> the main loop pointing to a different node)
> Running this code leads me to double-free crash.
> 
> I noticed that vlib_buffer_clone, when asked to create 1 clone, presented me 
> with a new buffer index that has the same address as the original buffer, but 
> the ref_count stays 1. Looking at the vlib_buffer_clone confirms that it only 
> copies the packet for n_clones > 1, but still not updating the ref_count. So 
> it looks like I'm missing something wrt how the cloning works.
> 
> I changed the code to create 2 clones and tried to use the 2nd clone in the 
> host interface frame. This resulted in the packet being sent only to the host 
> interface, but not to both of the interfaces.
> 
> I'm probably doing something wrong, how can I achieve the desired behavior?
> 
> Thanks,
> David
> 
> 
> 

-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#19142): https://lists.fd.io/g/vpp-dev/message/19142
Mute This Topic: https://lists.fd.io/mt/81938105/21656
Group Owner: [email protected]
Unsubscribe: https://lists.fd.io/g/vpp-dev/unsub [[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to