map: Add several more MAP-T BR tests
[vpp.git] / extras / deprecated / netmap / device.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_tx_func_error           \
30 _(NO_FREE_SLOTS, "no free tx slots")           \
31 _(PENDING_MSGS, "pending msgs in tx ring")
32
33 typedef enum
34 {
35 #define _(f,s) NETMAP_TX_ERROR_##f,
36   foreach_netmap_tx_func_error
37 #undef _
38     NETMAP_TX_N_ERROR,
39 } netmap_tx_func_error_t;
40
41 static char *netmap_tx_func_error_strings[] = {
42 #define _(n,s) s,
43   foreach_netmap_tx_func_error
44 #undef _
45 };
46
47
48 static u8 *
49 format_netmap_device_name (u8 * s, va_list * args)
50 {
51   u32 i = va_arg (*args, u32);
52   netmap_main_t *apm = &netmap_main;
53   netmap_if_t *nif = pool_elt_at_index (apm->interfaces, i);
54
55   s = format (s, "netmap-%s", nif->host_if_name);
56   return s;
57 }
58
59 static u8 *
60 format_netmap_device (u8 * s, va_list * args)
61 {
62   u32 dev_instance = va_arg (*args, u32);
63   int verbose = va_arg (*args, int);
64   netmap_main_t *nm = &netmap_main;
65   netmap_if_t *nif = vec_elt_at_index (nm->interfaces, dev_instance);
66   u32 indent = format_get_indent (s);
67
68   s = format (s, "NETMAP interface");
69   if (verbose)
70     {
71       s = format (s, "\n%U version %d flags 0x%x"
72                   "\n%U region %u memsize 0x%x offset 0x%x"
73                   "\n%U tx_slots %u rx_slots %u tx_rings %u rx_rings %u",
74                   format_white_space, indent + 2,
75                   nif->req->nr_version,
76                   nif->req->nr_flags,
77                   format_white_space, indent + 2,
78                   nif->mem_region,
79                   nif->req->nr_memsize,
80                   nif->req->nr_offset,
81                   format_white_space, indent + 2,
82                   nif->req->nr_tx_slots,
83                   nif->req->nr_rx_slots,
84                   nif->req->nr_tx_rings, nif->req->nr_rx_rings);
85     }
86   return s;
87 }
88
89 static u8 *
90 format_netmap_tx_trace (u8 * s, va_list * args)
91 {
92   s = format (s, "Unimplemented...");
93   return s;
94 }
95
96 VNET_DEVICE_CLASS_TX_FN (netmap_device_class) (vlib_main_t * vm,
97                                                vlib_node_runtime_t * node,
98                                                vlib_frame_t * frame)
99 {
100   netmap_main_t *nm = &netmap_main;
101   u32 *buffers = vlib_frame_vector_args (frame);
102   u32 n_left = frame->n_vectors;
103   f64 const time_constant = 1e3;
104   vnet_interface_output_runtime_t *rd = (void *) node->runtime_data;
105   netmap_if_t *nif = pool_elt_at_index (nm->interfaces, rd->dev_instance);
106   int cur_ring;
107
108   clib_spinlock_lock_if_init (&nif->lockp);
109
110   cur_ring = nif->first_tx_ring;
111
112   while (n_left && cur_ring <= nif->last_tx_ring)
113     {
114       struct netmap_ring *ring = NETMAP_TXRING (nif->nifp, cur_ring);
115       int n_free_slots = nm_ring_space (ring);
116       uint cur = ring->cur;
117
118       if (nm_tx_pending (ring))
119         {
120           if (ioctl (nif->fd, NIOCTXSYNC, NULL) < 0)
121             clib_unix_warning ("NIOCTXSYNC");
122           clib_cpu_time_wait (time_constant);
123
124           if (nm_tx_pending (ring) && !n_free_slots)
125             {
126               cur_ring++;
127               continue;
128             }
129         }
130
131       while (n_left && n_free_slots)
132         {
133           vlib_buffer_t *b0 = 0;
134           u32 bi = buffers[0];
135           u32 len;
136           u32 offset = 0;
137           buffers++;
138
139           struct netmap_slot *slot = &ring->slot[cur];
140
141           do
142             {
143               b0 = vlib_get_buffer (vm, bi);
144               len = b0->current_length;
145               /* memcpy */
146               clib_memcpy_fast ((u8 *) NETMAP_BUF (ring, slot->buf_idx) +
147                                 offset, vlib_buffer_get_current (b0), len);
148               offset += len;
149             }
150           while ((bi = b0->next_buffer));
151
152           slot->len = offset;
153           cur = (cur + 1) % ring->num_slots;
154           n_free_slots--;
155           n_left--;
156         }
157       CLIB_MEMORY_BARRIER ();
158       ring->head = ring->cur = cur;
159     }
160
161   if (n_left < frame->n_vectors)
162     ioctl (nif->fd, NIOCTXSYNC, NULL);
163
164   clib_spinlock_unlock_if_init (&nif->lockp);
165
166   if (n_left)
167     vlib_error_count (vm, node->node_index,
168                       (n_left ==
169                        frame->n_vectors ? NETMAP_TX_ERROR_PENDING_MSGS :
170                        NETMAP_TX_ERROR_NO_FREE_SLOTS), n_left);
171
172   vlib_buffer_free (vm, vlib_frame_vector_args (frame), frame->n_vectors);
173   return frame->n_vectors;
174 }
175
176 static void
177 netmap_set_interface_next_node (vnet_main_t * vnm, u32 hw_if_index,
178                                 u32 node_index)
179 {
180   netmap_main_t *apm = &netmap_main;
181   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
182   netmap_if_t *nif = pool_elt_at_index (apm->interfaces, hw->dev_instance);
183
184   /* Shut off redirection */
185   if (node_index == ~0)
186     {
187       nif->per_interface_next_index = node_index;
188       return;
189     }
190
191   nif->per_interface_next_index =
192     vlib_node_add_next (vlib_get_main (), netmap_input_node.index,
193                         node_index);
194 }
195
196 static void
197 netmap_clear_hw_interface_counters (u32 instance)
198 {
199   /* Nothing for now */
200 }
201
202 static clib_error_t *
203 netmap_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
204 {
205   netmap_main_t *apm = &netmap_main;
206   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
207   netmap_if_t *nif = pool_elt_at_index (apm->interfaces, hw->dev_instance);
208   u32 hw_flags;
209
210   nif->is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
211
212   if (nif->is_admin_up)
213     hw_flags = VNET_HW_INTERFACE_FLAG_LINK_UP;
214   else
215     hw_flags = 0;
216
217   vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
218
219   return 0;
220 }
221
222 static clib_error_t *
223 netmap_subif_add_del_function (vnet_main_t * vnm,
224                                u32 hw_if_index,
225                                struct vnet_sw_interface_t *st, int is_add)
226 {
227   /* Nothing for now */
228   return 0;
229 }
230
231 /* *INDENT-OFF* */
232 VNET_DEVICE_CLASS (netmap_device_class) = {
233   .name = "netmap",
234   .format_device_name = format_netmap_device_name,
235   .format_device = format_netmap_device,
236   .format_tx_trace = format_netmap_tx_trace,
237   .tx_function_n_errors = NETMAP_TX_N_ERROR,
238   .tx_function_error_strings = netmap_tx_func_error_strings,
239   .rx_redirect_to_node = netmap_set_interface_next_node,
240   .clear_counters = netmap_clear_hw_interface_counters,
241   .admin_up_down_function = netmap_interface_admin_up_down,
242   .subif_add_del_function = netmap_subif_add_del_function,
243 };
244 /* *INDENT-ON* */
245
246 /*
247  * fd.io coding-style-patch-verification: ON
248  *
249  * Local Variables:
250  * eval: (c-set-style "gnu")
251  * End:
252  */