blob: 3bdb442dda2a69178733066cbe87a3b2e1298731 [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 *
39netmap_fd_read_ready (unix_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 Marion00a9dca2016-08-17 17:05:46 +020057 if (nif->unix_file_index != ~0)
58 {
59 unix_file_del (&unix_main, unix_main.file_pool + nif->unix_file_index);
60 nif->unix_file_index = ~0;
61 }
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;
140 nif->unix_file_index = ~0;
141
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 Marion00a9dca2016-08-17 17:05:46 +0200188 {
189 nif->lockp = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
190 CLIB_CACHE_LINE_BYTES);
191 memset ((void *) nif->lockp, 0, CLIB_CACHE_LINE_BYTES);
192 }
Mohsin KAZMIa7575ea2016-06-16 06:58:34 +0200193
Damjan Marion108c7312016-04-20 05:04:20 +0200194 {
Damjan Marion00a9dca2016-08-17 17:05:46 +0200195 unix_file_t template = { 0 };
Damjan Marion108c7312016-04-20 05:04:20 +0200196 template.read_function = netmap_fd_read_ready;
197 template.file_descriptor = nif->fd;
198 template.private_data = nif->if_index;
199 nif->unix_file_index = unix_file_add (&unix_main, &template);
200 }
201
202 /*use configured or generate random MAC address */
203 if (hw_addr_set)
Damjan Marion00a9dca2016-08-17 17:05:46 +0200204 memcpy (hw_addr, hw_addr_set, 6);
Damjan Marion108c7312016-04-20 05:04:20 +0200205 else
206 {
Damjan Marion00a9dca2016-08-17 17:05:46 +0200207 f64 now = vlib_time_now (vm);
Damjan Marion108c7312016-04-20 05:04:20 +0200208 u32 rnd;
209 rnd = (u32) (now * 1e6);
210 rnd = random_u32 (&rnd);
211
Damjan Marion00a9dca2016-08-17 17:05:46 +0200212 memcpy (hw_addr + 2, &rnd, sizeof (rnd));
Damjan Marion108c7312016-04-20 05:04:20 +0200213 hw_addr[0] = 2;
214 hw_addr[1] = 0xfe;
215 }
216
Damjan Marion00a9dca2016-08-17 17:05:46 +0200217 error = ethernet_register_interface (vnm, netmap_device_class.index,
218 nif->if_index, hw_addr,
219 &nif->hw_if_index,
220 netmap_eth_flag_change);
Damjan Marion108c7312016-04-20 05:04:20 +0200221
222 if (error)
223 {
224 clib_error_report (error);
225 ret = VNET_API_ERROR_SYSCALL_ERROR_1;
226 goto error;
227 }
228
229 sw = vnet_get_hw_sw_interface (vnm, nif->hw_if_index);
230 nif->sw_if_index = sw->sw_if_index;
231
Damjan Marion108c7312016-04-20 05:04:20 +0200232 mhash_set_mem (&nm->if_index_by_host_if_name, if_name, &nif->if_index, 0);
233
Pierre Pfister78ea9c22016-05-23 12:51:54 +0100234 if (sw_if_index)
235 *sw_if_index = nif->sw_if_index;
236
Damjan Marion00a9dca2016-08-17 17:05:46 +0200237 if (tm->n_vlib_mains > 1 && pool_elts (nm->interfaces) == 1)
238 netmap_worker_thread_enable ();
Mohsin KAZMI64f450d2016-07-06 03:17:50 +0200239
Damjan Marion108c7312016-04-20 05:04:20 +0200240 return 0;
241
242error:
Damjan Marion00a9dca2016-08-17 17:05:46 +0200243 close_netmap_if (nm, nif);
Damjan Marion108c7312016-04-20 05:04:20 +0200244 return ret;
245}
246
247int
Damjan Marion00a9dca2016-08-17 17:05:46 +0200248netmap_delete_if (vlib_main_t * vm, u8 * host_if_name)
Damjan Marion108c7312016-04-20 05:04:20 +0200249{
Damjan Marion00a9dca2016-08-17 17:05:46 +0200250 vnet_main_t *vnm = vnet_get_main ();
Damjan Marion108c7312016-04-20 05:04:20 +0200251 netmap_main_t *nm = &netmap_main;
252 netmap_if_t *nif;
253 uword *p;
Damjan Marion00a9dca2016-08-17 17:05:46 +0200254 vlib_thread_main_t *tm = vlib_get_thread_main ();
Damjan Marion108c7312016-04-20 05:04:20 +0200255
Damjan Marion00a9dca2016-08-17 17:05:46 +0200256 p = mhash_get (&nm->if_index_by_host_if_name, host_if_name);
257 if (p == NULL)
258 {
259 clib_warning ("Host interface %s does not exist", host_if_name);
260 return VNET_API_ERROR_SYSCALL_ERROR_1;
261 }
262 nif = pool_elt_at_index (nm->interfaces, p[0]);
Damjan Marion108c7312016-04-20 05:04:20 +0200263
264 /* bring down the interface */
Damjan Marion00a9dca2016-08-17 17:05:46 +0200265 vnet_hw_interface_set_flags (vnm, nif->hw_if_index, 0);
Damjan Marion108c7312016-04-20 05:04:20 +0200266
Damjan Marion00a9dca2016-08-17 17:05:46 +0200267 ethernet_delete_interface (vnm, nif->hw_if_index);
Damjan Marion108c7312016-04-20 05:04:20 +0200268
Damjan Marion00a9dca2016-08-17 17:05:46 +0200269 close_netmap_if (nm, nif);
Mohsin KAZMI64f450d2016-07-06 03:17:50 +0200270
Damjan Marion00a9dca2016-08-17 17:05:46 +0200271 if (tm->n_vlib_mains > 1 && pool_elts (nm->interfaces) == 0)
272 netmap_worker_thread_disable ();
Mohsin KAZMI64f450d2016-07-06 03:17:50 +0200273
Damjan Marion108c7312016-04-20 05:04:20 +0200274 return 0;
275}
276
277static clib_error_t *
278netmap_init (vlib_main_t * vm)
279{
Damjan Marion00a9dca2016-08-17 17:05:46 +0200280 netmap_main_t *nm = &netmap_main;
281 vlib_thread_main_t *tm = vlib_get_thread_main ();
282 vlib_thread_registration_t *tr;
283 uword *p;
Damjan Marion108c7312016-04-20 05:04:20 +0200284
285 memset (nm, 0, sizeof (netmap_main_t));
286
Mohsin KAZMIa7575ea2016-06-16 06:58:34 +0200287 nm->input_cpu_first_index = 0;
288 nm->input_cpu_count = 1;
289
290 /* find out which cpus will be used for input */
291 p = hash_get_mem (tm->thread_registrations_by_name, "workers");
292 tr = p ? (vlib_thread_registration_t *) p[0] : 0;
293
294 if (tr && tr->count > 0)
295 {
296 nm->input_cpu_first_index = tr->first_index;
297 nm->input_cpu_count = tr->count;
298 }
299
Damjan Marion108c7312016-04-20 05:04:20 +0200300 mhash_init_vec_string (&nm->if_index_by_host_if_name, sizeof (uword));
301
Mohsin KAZMIa7575ea2016-06-16 06:58:34 +0200302 vec_validate_aligned (nm->rx_buffers, tm->n_vlib_mains - 1,
Damjan Marion00a9dca2016-08-17 17:05:46 +0200303 CLIB_CACHE_LINE_BYTES);
Mohsin KAZMIa7575ea2016-06-16 06:58:34 +0200304
Damjan Marion108c7312016-04-20 05:04:20 +0200305 return 0;
306}
307
308VLIB_INIT_FUNCTION (netmap_init);
Damjan Marion00a9dca2016-08-17 17:05:46 +0200309
310/*
311 * fd.io coding-style-patch-verification: ON
312 *
313 * Local Variables:
314 * eval: (c-set-style "gnu")
315 * End:
316 */