eae189c0e6496c9a8e9a26a17f0c07f6f5ec44d7
[vpp.git] / vnet / vnet / devices / netmap / node.c
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2016 Cisco and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *------------------------------------------------------------------
16  */
17
18 #include <stdint.h>
19 #include <net/if.h>
20 #include <sys/ioctl.h>
21
22 #include <vlib/vlib.h>
23 #include <vlib/unix/unix.h>
24 #include <vnet/ethernet/ethernet.h>
25
26 #include <vnet/devices/netmap/net_netmap.h>
27 #include <vnet/devices/netmap/netmap.h>
28
29 #define foreach_netmap_input_error
30
31 typedef enum {
32 #define _(f,s) NETMAP_INPUT_ERROR_##f,
33   foreach_netmap_input_error
34 #undef _
35   NETMAP_INPUT_N_ERROR,
36 } netmap_input_error_t;
37
38 static char * netmap_input_error_strings[] = {
39 #define _(n,s) s,
40     foreach_netmap_input_error
41 #undef _
42 };
43
44 enum {
45   NETMAP_INPUT_NEXT_DROP,
46   NETMAP_INPUT_NEXT_ETHERNET_INPUT,
47   NETMAP_INPUT_N_NEXT,
48 };
49
50 typedef struct {
51   u32 next_index;
52   u32 hw_if_index;
53   struct netmap_slot slot;
54 } netmap_input_trace_t;
55
56 static u8 * format_netmap_input_trace (u8 * s, va_list * args)
57 {
58   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
59   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
60   netmap_input_trace_t * t = va_arg (*args, netmap_input_trace_t *);
61   uword indent = format_get_indent (s);
62
63   s = format (s, "netmap: hw_if_index %d next-index %d",
64               t->hw_if_index, t->next_index);
65   s = format (s, "\n%Uslot: flags 0x%x len %u buf_idx %u",
66               format_white_space, indent + 2,
67               t->slot.flags, t->slot.len, t->slot.buf_idx);
68   return s;
69 }
70
71 always_inline void
72 buffer_add_to_chain(vlib_main_t *vm, u32 bi, u32 first_bi, u32 prev_bi)
73 {
74   vlib_buffer_t * b = vlib_get_buffer (vm, bi);
75   vlib_buffer_t * first_b = vlib_get_buffer (vm, first_bi);
76   vlib_buffer_t * prev_b = vlib_get_buffer (vm, prev_bi);
77
78   /* update first buffer */
79   first_b->total_length_not_including_first_buffer +=  b->current_length;
80
81   /* update previous buffer */
82   prev_b->next_buffer = bi;
83   prev_b->flags |= VLIB_BUFFER_NEXT_PRESENT;
84
85   /* update current buffer */
86   b->next_buffer = 0;
87
88 #if DPDK > 0
89   struct rte_mbuf * mbuf = rte_mbuf_from_vlib_buffer(b);
90   struct rte_mbuf * first_mbuf = rte_mbuf_from_vlib_buffer(first_b);
91   struct rte_mbuf * prev_mbuf = rte_mbuf_from_vlib_buffer(prev_b);
92   first_mbuf->nb_segs++;
93   prev_mbuf->next = mbuf;
94   mbuf->data_len = b->current_length;
95   mbuf->data_off = RTE_PKTMBUF_HEADROOM + b->current_data;
96   mbuf->next = 0;
97 #endif
98 }
99
100 always_inline uword
101 netmap_device_input_fn  (vlib_main_t * vm, vlib_node_runtime_t * node,
102                             vlib_frame_t * frame, u32 device_idx)
103 {
104   u32 next_index = NETMAP_INPUT_NEXT_ETHERNET_INPUT;
105   uword n_trace = vlib_get_trace_count (vm, node);
106   netmap_main_t * nm = &netmap_main;
107   netmap_if_t * nif = pool_elt_at_index(nm->interfaces, device_idx);
108   u32 n_rx_packets = 0;
109   u32 n_rx_bytes = 0;
110   u32 * to_next = 0;
111   u32 n_free_bufs;
112   struct netmap_ring * ring;
113   int cur_ring;
114   u32 n_buffer_bytes = vlib_buffer_free_list_buffer_size (vm,
115     VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
116
117   if (nif->per_interface_next_index != ~0)
118       next_index = nif->per_interface_next_index;
119
120   n_free_bufs = vec_len (nm->rx_buffers);
121   if (PREDICT_FALSE(n_free_bufs < VLIB_FRAME_SIZE))
122     {
123       vec_validate(nm->rx_buffers, VLIB_FRAME_SIZE + n_free_bufs - 1);
124       n_free_bufs += vlib_buffer_alloc(vm, &nm->rx_buffers[n_free_bufs], VLIB_FRAME_SIZE);
125       _vec_len (nm->rx_buffers) = n_free_bufs;
126     }
127
128   cur_ring = nif->first_rx_ring;
129   while (cur_ring <= nif->last_rx_ring && n_free_bufs)
130     {
131       int r = 0;
132       u32 cur_slot_index;
133       ring = NETMAP_RXRING(nif->nifp, cur_ring);
134       r = nm_ring_space(ring);
135
136       if (!r)
137         {
138           cur_ring++;
139           continue;
140         }
141
142       if (r > n_free_bufs)
143         r = n_free_bufs;
144
145       cur_slot_index = ring->cur;
146       while (r)
147         {
148           u32 n_left_to_next;
149           u32 next0 = next_index;
150           vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
151
152           while (r && n_left_to_next)
153             {
154               vlib_buffer_t * b0, * first_b0 = 0;
155               u32 offset = 0;
156               u32 bi0 = 0, first_bi0 = 0, prev_bi0;
157               u32 next_slot_index = (cur_slot_index + 1) % ring->num_slots;
158               u32 next2_slot_index = (cur_slot_index + 2) % ring->num_slots;
159               struct netmap_slot * slot = &ring->slot[cur_slot_index];
160               u32 data_len = slot->len;
161
162               /* prefetch 2 slots in advance */
163               CLIB_PREFETCH (&ring->slot[next2_slot_index], CLIB_CACHE_LINE_BYTES, LOAD);
164               /* prefetch start of next packet */
165               CLIB_PREFETCH (NETMAP_BUF(ring, ring->slot[next_slot_index].buf_idx),
166                              CLIB_CACHE_LINE_BYTES, LOAD);
167
168               while (data_len && n_free_bufs)
169                 {
170                   /* grab free buffer */
171                   u32 last_empty_buffer = vec_len (nm->rx_buffers) - 1;
172                   prev_bi0 = bi0;
173                   bi0 = nm->rx_buffers[last_empty_buffer];
174                   b0 = vlib_get_buffer (vm, bi0);
175                   _vec_len (nm->rx_buffers) = last_empty_buffer;
176                   n_free_bufs--;
177
178                   /* copy data */
179                   u32 bytes_to_copy = data_len > n_buffer_bytes ? n_buffer_bytes : data_len;
180                   b0->current_data = 0;
181                   clib_memcpy (vlib_buffer_get_current (b0),
182                           (u8 *) NETMAP_BUF(ring, slot->buf_idx) + offset,
183                           bytes_to_copy);
184
185                   /* fill buffer header */
186                   b0->current_length = bytes_to_copy;
187
188                   if (offset == 0)
189                     {
190 #if DPDK > 0
191                       struct rte_mbuf * mb = rte_mbuf_from_vlib_buffer(b0);
192                       rte_pktmbuf_data_len (mb) = b0->current_length;
193                       rte_pktmbuf_pkt_len (mb) = b0->current_length;
194 #endif
195                       b0->total_length_not_including_first_buffer = 0;
196                       b0->flags = VLIB_BUFFER_TOTAL_LENGTH_VALID;
197                       vnet_buffer(b0)->sw_if_index[VLIB_RX] = nif->sw_if_index;
198                       vnet_buffer(b0)->sw_if_index[VLIB_TX] = (u32)~0;
199                       first_bi0 = bi0;
200                       first_b0 = vlib_get_buffer(vm, first_bi0);
201                     }
202                   else
203                     buffer_add_to_chain(vm, bi0, first_bi0, prev_bi0);
204
205                   offset += bytes_to_copy;
206                   data_len -= bytes_to_copy;
207                 }
208
209               /* trace */
210               VLIB_BUFFER_TRACE_TRAJECTORY_INIT(first_b0);
211               if (PREDICT_FALSE(n_trace > 0))
212                 {
213                   netmap_input_trace_t *tr;
214                   vlib_trace_buffer (vm, node, next0, first_b0, /* follow_chain */ 0);
215                   vlib_set_trace_count (vm, node, --n_trace);
216                   tr = vlib_add_trace (vm, node, first_b0, sizeof (*tr));
217                   tr->next_index = next0;
218                   tr->hw_if_index = nif->hw_if_index;
219                   memcpy (&tr->slot, slot, sizeof (struct netmap_slot));
220                 }
221               /* enque and take next packet */
222               vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
223                                                n_left_to_next, first_bi0, next0);
224
225               /* next packet */
226               n_rx_packets++;
227               n_rx_bytes += slot->len;
228               to_next[0] = first_bi0;
229               to_next += 1;
230               n_left_to_next--;
231               cur_slot_index = next_slot_index;
232
233               r--;
234             }
235           vlib_put_next_frame (vm, node, next_index, n_left_to_next);
236         }
237        ring->head = ring->cur = cur_slot_index;
238        cur_ring++;
239     }
240
241   if (n_rx_packets)
242     ioctl(nif->fd, NIOCRXSYNC, NULL);
243
244   vlib_increment_combined_counter
245     (vnet_get_main()->interface_main.combined_sw_if_counters
246      + VNET_INTERFACE_COUNTER_RX,
247      os_get_cpu_number(),
248      nif->hw_if_index,
249      n_rx_packets, n_rx_bytes);
250
251   return n_rx_packets;
252 }
253
254 static uword
255 netmap_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
256                     vlib_frame_t * frame)
257 {
258   int i;
259   u32 n_rx_packets = 0;
260
261   netmap_main_t * nm = &netmap_main;
262
263   clib_bitmap_foreach (i, nm->pending_input_bitmap,
264     ({
265       clib_bitmap_set (nm->pending_input_bitmap, i, 0);
266       n_rx_packets += netmap_device_input_fn(vm, node, frame, i);
267     }));
268
269   return n_rx_packets;
270 }
271
272 VLIB_REGISTER_NODE (netmap_input_node) = {
273   .function = netmap_input_fn,
274   .name = "netmap-input",
275   .format_trace = format_netmap_input_trace,
276   .type = VLIB_NODE_TYPE_INPUT,
277   .state = VLIB_NODE_STATE_INTERRUPT,
278   .n_errors = NETMAP_INPUT_N_ERROR,
279   .error_strings = netmap_input_error_strings,
280
281   .n_next_nodes = NETMAP_INPUT_N_NEXT,
282   .next_nodes = {
283     [NETMAP_INPUT_NEXT_DROP] = "error-drop",
284     [NETMAP_INPUT_NEXT_ETHERNET_INPUT] = "ethernet-input",
285   },
286 };
287
288 VLIB_NODE_FUNCTION_MULTIARCH (netmap_input_node, netmap_input_fn)
289