blob: fc49ed629b8aaefaee159ca494d57cf276b63534 [file] [log] [blame]
Damjan Marion108c7312016-04-20 05:04:20 +02001/*
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#include <sys/types.h>
22#include <fcntl.h>
23#include <vnet/devices/netmap/net_netmap.h>
24
25#include <vlib/vlib.h>
26#include <vlib/unix/unix.h>
27#include <vnet/ethernet/ethernet.h>
28#include <vnet/devices/netmap/netmap.h>
29
30static u32
Damjan Marion00a9dca2016-08-17 17:05:46 +020031netmap_eth_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hi,
32 u32 flags)
Damjan Marion108c7312016-04-20 05:04:20 +020033{
34 /* nothing for now */
35 return 0;
36}
37
Damjan Marion00a9dca2016-08-17 17:05:46 +020038static clib_error_t *
Damjan Marion56dd5432017-09-08 19:52:02 +020039netmap_fd_read_ready (clib_file_t * uf)
Damjan Marion108c7312016-04-20 05:04:20 +020040{
Damjan Marion00a9dca2016-08-17 17:05:46 +020041 vlib_main_t *vm = vlib_get_main ();
42 netmap_main_t *nm = &netmap_main;
Damjan Marion108c7312016-04-20 05:04:20 +020043 u32 idx = uf->private_data;
44
Damjan Marion00a9dca2016-08-17 17:05:46 +020045 nm->pending_input_bitmap =
46 clib_bitmap_set (nm->pending_input_bitmap, idx, 1);
Damjan Marion108c7312016-04-20 05:04:20 +020047
48 /* Schedule the rx node */
49 vlib_node_set_interrupt_pending (vm, netmap_input_node.index);
50
51 return 0;
52}
53
54static void
Damjan Marion00a9dca2016-08-17 17:05:46 +020055close_netmap_if (netmap_main_t * nm, netmap_if_t * nif)
Damjan Marion108c7312016-04-20 05:04:20 +020056{
Damjan Marion56dd5432017-09-08 19:52:02 +020057 if (nif->clib_file_index != ~0)
Damjan Marion00a9dca2016-08-17 17:05:46 +020058 {
Damjan Marion56dd5432017-09-08 19:52:02 +020059 clib_file_del (&file_main, file_main.file_pool + nif->clib_file_index);
60 nif->clib_file_index = ~0;
Damjan Marion00a9dca2016-08-17 17:05:46 +020061 }
Eyal Barif298ecf2016-09-19 18:47:39 +030062 else if (nif->fd > -1)
Damjan Marion00a9dca2016-08-17 17:05:46 +020063 close (nif->fd);
Damjan Marion108c7312016-04-20 05:04:20 +020064
65 if (nif->mem_region)
66 {
Damjan Marion00a9dca2016-08-17 17:05:46 +020067 netmap_mem_region_t *reg = &nm->mem_regions[nif->mem_region];
Damjan Marion108c7312016-04-20 05:04:20 +020068 if (--reg->refcnt == 0)
69 {
Damjan Marion00a9dca2016-08-17 17:05:46 +020070 munmap (reg->mem, reg->region_size);
Damjan Marion108c7312016-04-20 05:04:20 +020071 reg->region_size = 0;
72 }
73 }
74
75
Damjan Marion00a9dca2016-08-17 17:05:46 +020076 mhash_unset (&nm->if_index_by_host_if_name, nif->host_if_name,
77 &nif->if_index);
78 vec_free (nif->host_if_name);
79 vec_free (nif->req);
Damjan Marion108c7312016-04-20 05:04:20 +020080
Damjan Marion00a9dca2016-08-17 17:05:46 +020081 memset (nif, 0, sizeof (*nif));
82 pool_put (nm->interfaces, nif);
Damjan Marion108c7312016-04-20 05:04:20 +020083}
84
85int
Damjan Marion00a9dca2016-08-17 17:05:46 +020086netmap_worker_thread_enable ()
Mohsin KAZMI64f450d2016-07-06 03:17:50 +020087{
88 /* if worker threads are enabled, switch to polling mode */
Damjan Marion00a9dca2016-08-17 17:05:46 +020089 foreach_vlib_main ((
90 {
91 vlib_node_set_state (this_vlib_main,
92 netmap_input_node.index,
93 VLIB_NODE_STATE_POLLING);
94 }));
Mohsin KAZMI64f450d2016-07-06 03:17:50 +020095
96 return 0;
97}
98
99int
Damjan Marion00a9dca2016-08-17 17:05:46 +0200100netmap_worker_thread_disable ()
Mohsin KAZMI64f450d2016-07-06 03:17:50 +0200101{
Damjan Marion00a9dca2016-08-17 17:05:46 +0200102 foreach_vlib_main ((
103 {
104 vlib_node_set_state (this_vlib_main,
105 netmap_input_node.index,
106 VLIB_NODE_STATE_INTERRUPT);
107 }));
Mohsin KAZMI64f450d2016-07-06 03:17:50 +0200108
109 return 0;
110}
111
112int
Damjan Marion00a9dca2016-08-17 17:05:46 +0200113netmap_create_if (vlib_main_t * vm, u8 * if_name, u8 * hw_addr_set,
114 u8 is_pipe, u8 is_master, u32 * sw_if_index)
Damjan Marion108c7312016-04-20 05:04:20 +0200115{
Damjan Marion00a9dca2016-08-17 17:05:46 +0200116 netmap_main_t *nm = &netmap_main;
Damjan Marion108c7312016-04-20 05:04:20 +0200117 int ret = 0;
Damjan Marion00a9dca2016-08-17 17:05:46 +0200118 netmap_if_t *nif = 0;
Damjan Marion108c7312016-04-20 05:04:20 +0200119 u8 hw_addr[6];
Damjan Marion00a9dca2016-08-17 17:05:46 +0200120 clib_error_t *error = 0;
121 vnet_sw_interface_t *sw;
122 vnet_main_t *vnm = vnet_get_main ();
123 uword *p;
124 struct nmreq *req = 0;
125 netmap_mem_region_t *reg;
126 vlib_thread_main_t *tm = vlib_get_thread_main ();
Damjan Marion108c7312016-04-20 05:04:20 +0200127 int fd;
128
129 p = mhash_get (&nm->if_index_by_host_if_name, if_name);
130 if (p)
Damjan Marion00a9dca2016-08-17 17:05:46 +0200131 return VNET_API_ERROR_SUBIF_ALREADY_EXISTS;
Damjan Marion108c7312016-04-20 05:04:20 +0200132
Damjan Marion00a9dca2016-08-17 17:05:46 +0200133 fd = open ("/dev/netmap", O_RDWR);
Damjan Marion108c7312016-04-20 05:04:20 +0200134 if (fd < 0)
Damjan Marion00a9dca2016-08-17 17:05:46 +0200135 return VNET_API_ERROR_SUBIF_ALREADY_EXISTS;
Damjan Marion108c7312016-04-20 05:04:20 +0200136
137 pool_get (nm->interfaces, nif);
138 nif->if_index = nif - nm->interfaces;
139 nif->fd = fd;
Damjan Marion56dd5432017-09-08 19:52:02 +0200140 nif->clib_file_index = ~0;
Damjan Marion108c7312016-04-20 05:04:20 +0200141
Damjan Marion00a9dca2016-08-17 17:05:46 +0200142 vec_validate (req, 0);
Damjan Marion108c7312016-04-20 05:04:20 +0200143 nif->req = req;
144 req->nr_version = NETMAP_API;
145 req->nr_flags = NR_REG_ALL_NIC;
146
147 if (is_pipe)
148 req->nr_flags = is_master ? NR_REG_PIPE_MASTER : NR_REG_PIPE_SLAVE;
149 else
150 req->nr_flags = NR_REG_ALL_NIC;
151
152 req->nr_flags |= NR_ACCEPT_VNET_HDR;
Damjan Marion00a9dca2016-08-17 17:05:46 +0200153 snprintf (req->nr_name, IFNAMSIZ, "%s", if_name);
154 req->nr_name[IFNAMSIZ - 1] = 0;
Damjan Marion108c7312016-04-20 05:04:20 +0200155
Damjan Marion00a9dca2016-08-17 17:05:46 +0200156 if (ioctl (nif->fd, NIOCREGIF, req))
Damjan Marion108c7312016-04-20 05:04:20 +0200157 {
158 ret = VNET_API_ERROR_NOT_CONNECTED;
159 goto error;
160 }
161
162 nif->mem_region = req->nr_arg2;
163 vec_validate (nm->mem_regions, nif->mem_region);
164 reg = &nm->mem_regions[nif->mem_region];
165 if (reg->region_size == 0)
166 {
Damjan Marion00a9dca2016-08-17 17:05:46 +0200167 reg->mem = mmap (NULL, req->nr_memsize, PROT_READ | PROT_WRITE,
168 MAP_SHARED, fd, 0);
169 clib_warning ("mem %p", reg->mem);
Damjan Marion108c7312016-04-20 05:04:20 +0200170 if (reg->mem == MAP_FAILED)
171 {
172 ret = VNET_API_ERROR_NOT_CONNECTED;
173 goto error;
174 }
175 reg->region_size = req->nr_memsize;
176 }
177 reg->refcnt++;
178
Damjan Marion00a9dca2016-08-17 17:05:46 +0200179 nif->nifp = NETMAP_IF (reg->mem, req->nr_offset);
Damjan Marion108c7312016-04-20 05:04:20 +0200180 nif->first_rx_ring = 0;
181 nif->last_rx_ring = 0;
182 nif->first_tx_ring = 0;
183 nif->last_tx_ring = 0;
184 nif->host_if_name = if_name;
185 nif->per_interface_next_index = ~0;
186
Mohsin KAZMIa7575ea2016-06-16 06:58:34 +0200187 if (tm->n_vlib_mains > 1)
Damjan Marion1927da22017-03-27 17:08:20 +0200188 clib_spinlock_init (&nif->lockp);
Mohsin KAZMIa7575ea2016-06-16 06:58:34 +0200189
Damjan Marion108c7312016-04-20 05:04:20 +0200190 {
Damjan Marion56dd5432017-09-08 19:52:02 +0200191 clib_file_t template = { 0 };
Damjan Marion108c7312016-04-20 05:04:20 +0200192 template.read_function = netmap_fd_read_ready;
193 template.file_descriptor = nif->fd;
194 template.private_data = nif->if_index;
Damjan Marion56dd5432017-09-08 19:52:02 +0200195 nif->clib_file_index = clib_file_add (&file_main, &template);
Damjan Marion108c7312016-04-20 05:04:20 +0200196 }
197
198 /*use configured or generate random MAC address */
199 if (hw_addr_set)
Damjan Marion00a9dca2016-08-17 17:05:46 +0200200 memcpy (hw_addr, hw_addr_set, 6);
Damjan Marion108c7312016-04-20 05:04:20 +0200201 else
202 {
Damjan Marion00a9dca2016-08-17 17:05:46 +0200203 f64 now = vlib_time_now (vm);
Damjan Marion108c7312016-04-20 05:04:20 +0200204 u32 rnd;
205 rnd = (u32) (now * 1e6);
206 rnd = random_u32 (&rnd);
207
Damjan Marion00a9dca2016-08-17 17:05:46 +0200208 memcpy (hw_addr + 2, &rnd, sizeof (rnd));
Damjan Marion108c7312016-04-20 05:04:20 +0200209 hw_addr[0] = 2;
210 hw_addr[1] = 0xfe;
211 }
212
Damjan Marion00a9dca2016-08-17 17:05:46 +0200213 error = ethernet_register_interface (vnm, netmap_device_class.index,
214 nif->if_index, hw_addr,
215 &nif->hw_if_index,
216 netmap_eth_flag_change);
Damjan Marion108c7312016-04-20 05:04:20 +0200217
218 if (error)
219 {
220 clib_error_report (error);
221 ret = VNET_API_ERROR_SYSCALL_ERROR_1;
222 goto error;
223 }
224
225 sw = vnet_get_hw_sw_interface (vnm, nif->hw_if_index);
226 nif->sw_if_index = sw->sw_if_index;
227
Damjan Marion108c7312016-04-20 05:04:20 +0200228 mhash_set_mem (&nm->if_index_by_host_if_name, if_name, &nif->if_index, 0);
229
Pierre Pfister78ea9c22016-05-23 12:51:54 +0100230 if (sw_if_index)
231 *sw_if_index = nif->sw_if_index;
232
Damjan Marion00a9dca2016-08-17 17:05:46 +0200233 if (tm->n_vlib_mains > 1 && pool_elts (nm->interfaces) == 1)
234 netmap_worker_thread_enable ();
Mohsin KAZMI64f450d2016-07-06 03:17:50 +0200235
Damjan Marion108c7312016-04-20 05:04:20 +0200236 return 0;
237
238error:
Damjan Marion00a9dca2016-08-17 17:05:46 +0200239 close_netmap_if (nm, nif);
Damjan Marion108c7312016-04-20 05:04:20 +0200240 return ret;
241}
242
243int
Damjan Marion00a9dca2016-08-17 17:05:46 +0200244netmap_delete_if (vlib_main_t * vm, u8 * host_if_name)
Damjan Marion108c7312016-04-20 05:04:20 +0200245{
Damjan Marion00a9dca2016-08-17 17:05:46 +0200246 vnet_main_t *vnm = vnet_get_main ();
Damjan Marion108c7312016-04-20 05:04:20 +0200247 netmap_main_t *nm = &netmap_main;
248 netmap_if_t *nif;
249 uword *p;
Damjan Marion00a9dca2016-08-17 17:05:46 +0200250 vlib_thread_main_t *tm = vlib_get_thread_main ();
Damjan Marion108c7312016-04-20 05:04:20 +0200251
Damjan Marion00a9dca2016-08-17 17:05:46 +0200252 p = mhash_get (&nm->if_index_by_host_if_name, host_if_name);
253 if (p == NULL)
254 {
255 clib_warning ("Host interface %s does not exist", host_if_name);
256 return VNET_API_ERROR_SYSCALL_ERROR_1;
257 }
258 nif = pool_elt_at_index (nm->interfaces, p[0]);
Damjan Marion108c7312016-04-20 05:04:20 +0200259
260 /* bring down the interface */
Damjan Marion00a9dca2016-08-17 17:05:46 +0200261 vnet_hw_interface_set_flags (vnm, nif->hw_if_index, 0);
Damjan Marion108c7312016-04-20 05:04:20 +0200262
Damjan Marion00a9dca2016-08-17 17:05:46 +0200263 ethernet_delete_interface (vnm, nif->hw_if_index);
Damjan Marion108c7312016-04-20 05:04:20 +0200264
Damjan Marion00a9dca2016-08-17 17:05:46 +0200265 close_netmap_if (nm, nif);
Mohsin KAZMI64f450d2016-07-06 03:17:50 +0200266
Damjan Marion00a9dca2016-08-17 17:05:46 +0200267 if (tm->n_vlib_mains > 1 && pool_elts (nm->interfaces) == 0)
268 netmap_worker_thread_disable ();
Mohsin KAZMI64f450d2016-07-06 03:17:50 +0200269
Damjan Marion108c7312016-04-20 05:04:20 +0200270 return 0;
271}
272
273static clib_error_t *
274netmap_init (vlib_main_t * vm)
275{
Damjan Marion00a9dca2016-08-17 17:05:46 +0200276 netmap_main_t *nm = &netmap_main;
277 vlib_thread_main_t *tm = vlib_get_thread_main ();
278 vlib_thread_registration_t *tr;
279 uword *p;
Damjan Marion108c7312016-04-20 05:04:20 +0200280
281 memset (nm, 0, sizeof (netmap_main_t));
282
Mohsin KAZMIa7575ea2016-06-16 06:58:34 +0200283 nm->input_cpu_first_index = 0;
284 nm->input_cpu_count = 1;
285
286 /* find out which cpus will be used for input */
287 p = hash_get_mem (tm->thread_registrations_by_name, "workers");
288 tr = p ? (vlib_thread_registration_t *) p[0] : 0;
289
290 if (tr && tr->count > 0)
291 {
292 nm->input_cpu_first_index = tr->first_index;
293 nm->input_cpu_count = tr->count;
294 }
295
Damjan Marion108c7312016-04-20 05:04:20 +0200296 mhash_init_vec_string (&nm->if_index_by_host_if_name, sizeof (uword));
297
Mohsin KAZMIa7575ea2016-06-16 06:58:34 +0200298 vec_validate_aligned (nm->rx_buffers, tm->n_vlib_mains - 1,
Damjan Marion00a9dca2016-08-17 17:05:46 +0200299 CLIB_CACHE_LINE_BYTES);
Mohsin KAZMIa7575ea2016-06-16 06:58:34 +0200300
Damjan Marion108c7312016-04-20 05:04:20 +0200301 return 0;
302}
303
304VLIB_INIT_FUNCTION (netmap_init);
Damjan Marion00a9dca2016-08-17 17:05:46 +0200305
306/*
307 * fd.io coding-style-patch-verification: ON
308 *
309 * Local Variables:
310 * eval: (c-set-style "gnu")
311 * End:
312 */