Click
Loading...
Searching...
No Matches
netmapdevice.hh
1// -*- c-basic-offset: 4; related-file-name: "../../lib/netmapdevice.cc" -*-
2/*
3 * netmapdevice.{cc,hh} -- Library to use netmap
4 * Eddie Kohler, Luigi Rizzo, Tom Barbette
5 *
6 * Copyright (c) 2012 Eddie Kohler
7 * Copyright (c) 2014-2015 University of Liege
8 *
9 * NetmapBufQ implementation was started by Luigi Rizzo and moved from
10 * netmapinfo.hh.
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, subject to the conditions
15 * listed in the Click LICENSE file. These conditions include: you must
16 * preserve this copyright notice, and you cannot mention the copyright
17 * holders in advertising related to the Software without their permission.
18 * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
19 * notice is a summary of the Click LICENSE file; the license in that file is
20 * legally binding.
21 */
22#ifndef CLICK_NETMAPDEVICE_HH
23#define CLICK_NETMAPDEVICE_HH
24
25#if HAVE_NETMAP && CLICK_USERLEVEL
26#include <net/if.h>
27#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 0
28#include <linux/if.h>
29
30extern "C" {
31#include <net/netmap.h>
32#define NETMAP_WITH_LIBS 1
33#include <net/netmap_user.h>
34}
35#define NS_NOFREE 0x80 //We use this to set that a buffer is shared and should not be freed
36
37
38#include <click/error.hh>
39#include <click/ring.hh>
40#include <click/vector.hh>
41#include <click/hashmap.hh>
42#include <click/element.hh>
43#include <click/args.hh>
44#include <click/packet.hh>
45#include <click/sync.hh>
46
47CLICK_DECLS
48
49#define CLICK_NETMAP_POOL_DEBUG 0
50
51#define NETMAP_PACKET_POOL_SIZE 2048
52#define BUFFER_PTR(idx) reinterpret_cast<uint32_t *>(buf_start + idx * buf_size)
53#define BUFFER_NEXT_LIST(idx) *(((uint32_t*)BUFFER_PTR(idx)) + 1)
54
55#define CLICK_NETMAP_POOL_DEBUG_MAGIC(idx) (*(BUFFER_PTR(idx)+3))
56#define CLICK_NETMAP_POOL_DEBUG_MAGIC_VALUE 0b01011100010111000101110001011100
57
58/* a queue of netmap buffers, by index*/
59class NetmapBufQ {
60public:
61
62 NetmapBufQ();
63 ~NetmapBufQ();
64
65 inline void expand();
66
67 inline void insert(uint32_t idx);
68 inline void insert_p(unsigned char *p);
69 inline void insert_all(uint32_t idx, bool check_size);
70
71 inline uint32_t extract();
72 inline unsigned char * extract_p();
73
74 inline int count_buffers(uint32_t idx);
75
76 inline int count() const {
77 return _count;
78 };
79
80 //Static functions
81 static int static_initialize(struct nm_desc* nmd);
82 static uint32_t static_cleanup();
83
84 static void global_insert_all(uint32_t idx, int count);
85
86 inline static unsigned int buffer_size() {
87 return buf_size;
88 }
89
90 static void buffer_destructor(unsigned char *buf, size_t, void *) {
91 NetmapBufQ::local_pool()->insert_p(buf);
92 }
93
94 inline static bool is_netmap_packet(Packet* p) {
95 return (p->buffer_destructor() == buffer_destructor ||
96 (p->buffer() > NetmapBufQ::buf_start && p->buffer() < NetmapBufQ::buf_end));
97 }
98
99 inline static bool is_valid_netmap_buffer(void* data) {
100 return (data > NetmapBufQ::buf_start && data < NetmapBufQ::buf_end);
101 }
102
103 inline static bool is_valid_netmap_packet(Packet* p) {
104 return (p->buffer() > NetmapBufQ::buf_start && p->buffer() < NetmapBufQ::buf_end);
105 }
106
107 inline static NetmapBufQ* local_pool() {
108 return NetmapBufQ::netmap_buf_pools[click_current_cpu_id()];
109 }
110
111 static inline bool initialized() {
112 return netmap_buf_pools != 0;
113 }
114
115 bool check_list() {
116 return find_count(_head) == _count;
117 }
118
119 static int find_count(uint32_t cur,int limit = 65536) {
120 int c = 0;
121
122 while (cur > 0) {
123 uint32_t* p = BUFFER_PTR(cur);
124 cur = *p;
125 c++;
126 assert(c <= limit);
127 }
128 return c;
129 }
130private :
131 uint32_t _head; /* index of first buffer */
132 int _count; /* how many ? */
133
134 //Static attributes (shared between all queues)
135 static unsigned char *buf_start; /* base address */
136 static unsigned char *buf_end; /* error checking */
137 static unsigned int buf_size;
138 static uint32_t max_index; /* error checking */
139
140 static Spinlock global_buffer_lock;
141 //The global netmap buffer list is used to exchange batch of buffers between threads
142 //The second uint32_t in the buffer is used to point to the next batch
143 static uint32_t global_buffer_list;
144
145 static int messagelimit;
146 static NetmapBufQ** netmap_buf_pools;
147
148} __attribute__((aligned(64)));
149
153class NetmapDevice {
154 public:
155
156 NetmapDevice(String ifname) CLICK_COLD;
157 ~NetmapDevice() CLICK_COLD;
158
159 int initialize() CLICK_COLD;
160 void destroy() CLICK_COLD;
161
162 atomic_uint32_t n_refs;
163
164 struct nm_desc* parent_nmd;
165 Vector<struct nm_desc*> nmds;
166
167 String ifname;
168 int n_queues;
169
170#if HAVE_NETMAP_PACKET_POOL
171 static WritablePacket* make_netmap(unsigned char* data, struct netmap_ring* rxring, struct netmap_slot* slot);
172# if HAVE_BATCH
173 static PacketBatch* make_netmap_batch(unsigned int n, struct netmap_ring* rxring, unsigned int &cur);
174# endif
175#endif
176 static NetmapDevice* open(String ifname);
177 static void static_cleanup();
178 static struct nm_desc* some_nmd;
179 static int global_alloc;
180
181 int _minfd;
182 int _maxfd;
183
184 int get_num_slots() {
185 return some_nmd->some_ring->num_slots;
186 }
187
188private :
189 static HashMap<String,NetmapDevice*> nics;
190
191 int _use_count;
192};
193
194/*
195 * Inline functions
196 */
197
198inline void NetmapBufQ::expand() {
199 global_buffer_lock.acquire();
200 if (global_buffer_list != 0) {
201 //Transfer from global pool
202 _head = global_buffer_list;
203 global_buffer_list = BUFFER_NEXT_LIST(global_buffer_list);
204 _count = NETMAP_PACKET_POOL_SIZE;
205 } else {
206#ifdef NIOCALLOCBUF
207 click_chatter("Expanding buffer pool with %d new packets",NETMAP_PACKET_POOL_SIZE);
208 struct nmbufreq nbr;
209 nbr.num = NETMAP_PACKET_POOL_SIZE;
210 nbr.head = 0;
211 if (ioctl(NetmapDevice::some_nmd->fd,NIOCALLOCBUF,&nbr) == 0) {
212 insert_all(nbr.head,false);
213 } else
214#endif
215 {
216 if (messagelimit < 5)
217 click_chatter("No more netmap buffers !");
218 messagelimit++;
219}
220 }
221 global_buffer_lock.release();
222}
223
227inline void NetmapBufQ::insert_all(uint32_t idx,bool check_size = false) {
228 if (unlikely(idx >= max_index || idx == 0)) {
229 click_chatter("Error : cannot insert index %d",idx);
230 return;
231 }
232
233 uint32_t firstidx = idx;
234 uint32_t *p = 0;
235 while (idx > 0) { //Go to the end of the passed list
236 if (check_size) {
237 insert(idx);
238 } else {
239 p = BUFFER_PTR(idx);
240 idx = *p;
241 _count++;
242 }
243 }
244
245 //Add the current list at the end of this one
246 if (!check_size) {
247 *p = _head;
248 _head = firstidx;
249 }
250}
251
255int NetmapBufQ::count_buffers(uint32_t idx) {
256 int count=0;
257 while (idx != 0) {
258 count++;
259 idx = *BUFFER_PTR(idx);
260 }
261 return count;
262}
263
264inline void NetmapBufQ::insert(uint32_t idx) {
265#if CLICK_NETMAP_POOL_DEBUG
266 assert(idx > 0 && idx < max_index);
267 assert(CLICK_NETMAP_POOL_DEBUG_MAGIC(idx) != CLICK_NETMAP_POOL_DEBUG_MAGIC_VALUE);
268#endif
269
270 if (_count < NETMAP_PACKET_POOL_SIZE) {
271 *BUFFER_PTR(idx) = _head;
272 _head = idx;
273 _count++;
274 } else {
275#if CLICK_NETMAP_POOL_DEBUG
276 assert(_count == NETMAP_PACKET_POOL_SIZE);
277 assert(find_count(_head) == NETMAP_PACKET_POOL_SIZE);
278#endif
279 global_buffer_lock.acquire();
280 BUFFER_NEXT_LIST(_head) = global_buffer_list;
281 global_buffer_list = _head;
282 global_buffer_lock.release();
283 _head = idx;
284 *BUFFER_PTR(idx) = 0;
285 _count = 1;
286 }
287}
288
289inline void NetmapBufQ::insert_p(unsigned char* buf) {
290 insert((buf - buf_start) / buf_size);
291}
292
293inline uint32_t NetmapBufQ::extract() {
294 if (_count <= 0) {
295 expand();
296 if (_count == 0) return 0;
297 }
298 uint32_t idx;
299 uint32_t *p;
300 idx = _head;
301 p = BUFFER_PTR(idx);
302 _head = *p;
303 _count--;
304 #if CLICK_NETMAP_POOL_DEBUG
305 CLICK_NETMAP_POOL_DEBUG_MAGIC(idx) = 0;
306 #endif
307 return idx;
308}
309
310inline unsigned char* NetmapBufQ::extract_p() {
311 uint32_t idx = extract();
312 return (idx == 0) ? 0 : reinterpret_cast<unsigned char*>(BUFFER_PTR(idx));
313}
314
315#endif
316
317#endif
Definition packetbatch.hh:415
A network packet.
Definition packet.hh:68
const unsigned char * buffer() const
Return a pointer to the packet's data buffer.
Definition packet.hh:1243
A recursive spinlock for SMP Click threads.
Definition sync.hh:439
A string of characters.
Definition string.hh:22
Vector template.
Definition vector.hh:111
A network packet believed not to be shared.
Definition packet.hh:1004
A 32-bit integer with support for atomic operations.
Definition atomic.hh:71
Click's Element class.
Flexible error handling classes.
The Packet class models packets in Click.
Classes for synchronizing among multiple CPUs, particularly in the Linux kernel.
Click's vector container template.