Executing `to_frame = vlib_get_frame_to_node (vm, node_index);` n_left_from 
times and `vlib_put_frame_to_node (vm, node_index, to_frame);` only once 
doesn’t sound sane. You are leaking frames…

— 
Damjan


> On 08.04.2021., at 14:12, David Gohberg <gohb...@gmail.com> wrote:
> 
> I edited the example for simplicity, frame->n_vectors is incremented on each 
> iteration of the main loop. maybe that is the issue?
> Here is the code with more context:
> 
> while (n_left_from > 0)
> {
>         u32 bi0;
>         bi0 = from[0];
>         from++;
>         n_left_from--;
>         to_frame = vlib_get_frame_to_node (vm, node_index);
>         to_next = vlib_frame_vector_args (to_frame);
>         // getting host interface node index from sw if index
>         vnet_hw_interface_t * host_intf = vnet_get_sup_hw_interface (vnm, 
> sw_if_index);
>         u32 host_interface_node_index = host_intf->tx_node_index;
>         // frame for the cloned packet
>         vlib_frame_t *host_if_frame = vlib_get_frame_to_node(vm, 
> host_interface_node_index);
>         u32 *intf_host_to_next = vlib_frame_vector_args (host_if_frame);
>         host_if_frame->n_vectors = 1;
>         // cloning the buffer
>         u32 cbi0[2];
>         u16 n_cloned = vlib_buffer_clone (vm, bi0, &cbi0, 2, 
> VLIB_BUFFER_CLONE_HEAD_SIZE);
>         // enqueuing both packets to two different nodes
>         intf_host_to_next[0] = cbi0[1];
>         vlib_put_frame_to_node (vm, host_interface_node_index, host_if_frame);
>         to_next[0] = bi0;       
>         to_next++;
>         to_frame->n_vectors++; 
> }
> vlib_put_frame_to_node (vm, node_index, to_frame);
> return from_frame->n_vectors;
> 
> 
> On Thu, Apr 8, 2021 at 2:35 PM Damjan Marion <dmar...@me.com> wrote:
> 
> Setting frame->n_vectors may help :)
> 
> — 
> Damjan
> 
>> On 08.04.2021., at 13:11, David Gohberg <gohb...@gmail.com> wrote:
>> 
>> Thanks Damjan,
>> 
>> This clarifies things regarding the cloning mechanism. However using 
>> n_clones=2 and putting the 2nd clone in the frame still results
>> in the buffer being sent only to the host interface, the flow I'm using is 
>> this: (minimal example)
>> 
>> // getting host interface node index from sw if index
>> vnet_hw_interface_t * host_intf = vnet_get_sup_hw_interface (vnm, 
>> sw_if_index);
>> u32 host_interface_node_index = host_intf->tx_node_index;
>> 
>> // original frame
>> vlib_frame_t *frame = vlib_get_frame_to_node(vm, node_index);
>> u32 *to_next = vlib_frame_vector_args (frame);
>> 
>> // frame for the cloned packet
>> vlib_frame_t *host_if_frame = vlib_get_frame_to_node(vm, 
>> host_interface_node_index);
>> u32 *intf_host_to_next = vlib_frame_vector_args (host_if_frame);
>> host_if_frame->n_vectors = 1;
>> 
>> // cloning the buffer
>> u32 cbi0[2];
>> u16 n_cloned = vlib_buffer_clone (vm, bi0, &cbi0, 2, 
>> VLIB_BUFFER_CLONE_HEAD_SIZE);
>> 
>> // enqueuing both packets to two different nodes
>> to_next[0] = bi0;
>> intf_host_to_next[0] = cbi0[1];
>> vlib_put_frame_to_node (vm, node_index, frame);
>> vlib_put_frame_to_node (vm, host_interface_node_index, host_if_frame);
>> 
>> This results in the packet being sent only to host interface. I've checked 
>> vpp source code for similar use cases that use buffer cloning 
>> but didn't find a place when a node mirrors a packet and enqueues it to two 
>> different nodes.
>> 
>> On Thu, Apr 8, 2021 at 1:04 PM Damjan Marion <dmar...@me.com> wrote:
>> 
>> 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 <gohb...@gmail.com> 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 (#19147): https://lists.fd.io/g/vpp-dev/message/19147
Mute This Topic: https://lists.fd.io/mt/81938105/21656
Group Owner: vpp-dev+ow...@lists.fd.io
Unsubscribe: https://lists.fd.io/g/vpp-dev/unsub [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to