summaryrefslogtreecommitdiff
path: root/sys/dev/netmap/netmap_kern.h
diff options
context:
space:
mode:
authorVincenzo Maffione <vmaffione@FreeBSD.org>2018-12-05 11:57:16 +0000
committerVincenzo Maffione <vmaffione@FreeBSD.org>2018-12-05 11:57:16 +0000
commitb6e66be22bdce2aadcf52ee6230faa1e6cd3f805 (patch)
treee9311c45835e19b2d58f105e0627078f15f1cd63 /sys/dev/netmap/netmap_kern.h
parentabc73e04c2a0add60dea19c7aab5a0a4d51ab418 (diff)
Notes
Diffstat (limited to 'sys/dev/netmap/netmap_kern.h')
-rw-r--r--sys/dev/netmap/netmap_kern.h341
1 files changed, 210 insertions, 131 deletions
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 4abd16b6d17f..5f21f586c46b 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -54,30 +54,31 @@
#if defined(CONFIG_NETMAP_GENERIC)
#define WITH_GENERIC
#endif
-#if defined(CONFIG_NETMAP_PTNETMAP_GUEST)
-#define WITH_PTNETMAP_GUEST
-#endif
-#if defined(CONFIG_NETMAP_PTNETMAP_HOST)
-#define WITH_PTNETMAP_HOST
+#if defined(CONFIG_NETMAP_PTNETMAP)
+#define WITH_PTNETMAP
#endif
#if defined(CONFIG_NETMAP_SINK)
#define WITH_SINK
#endif
+#if defined(CONFIG_NETMAP_NULL)
+#define WITH_NMNULL
+#endif
#elif defined (_WIN32)
#define WITH_VALE // comment out to disable VALE support
#define WITH_PIPES
#define WITH_MONITOR
#define WITH_GENERIC
+#define WITH_NMNULL
#else /* neither linux nor windows */
#define WITH_VALE // comment out to disable VALE support
#define WITH_PIPES
#define WITH_MONITOR
#define WITH_GENERIC
-#define WITH_PTNETMAP_HOST /* ptnetmap host support */
-#define WITH_PTNETMAP_GUEST /* ptnetmap guest support */
+#define WITH_PTNETMAP /* ptnetmap guest support */
#define WITH_EXTMEM
+#define WITH_NMNULL
#endif
#if defined(__FreeBSD__)
@@ -239,28 +240,39 @@ typedef struct hrtimer{
#define NMG_LOCK_ASSERT() NM_MTX_ASSERT(netmap_global_lock)
#if defined(__FreeBSD__)
-#define nm_prerr printf
-#define nm_prinf printf
+#define nm_prerr_int printf
+#define nm_prinf_int printf
#elif defined (_WIN32)
-#define nm_prerr DbgPrint
-#define nm_prinf DbgPrint
+#define nm_prerr_int DbgPrint
+#define nm_prinf_int DbgPrint
#elif defined(linux)
-#define nm_prerr(fmt, arg...) printk(KERN_ERR fmt, ##arg)
-#define nm_prinf(fmt, arg...) printk(KERN_INFO fmt, ##arg)
+#define nm_prerr_int(fmt, arg...) printk(KERN_ERR fmt, ##arg)
+#define nm_prinf_int(fmt, arg...) printk(KERN_INFO fmt, ##arg)
#endif
-#define ND(format, ...)
-#define D(format, ...) \
+#define nm_prinf(format, ...) \
+ do { \
+ struct timeval __xxts; \
+ microtime(&__xxts); \
+ nm_prinf_int("%03d.%06d [%4d] %-25s " format "\n",\
+ (int)__xxts.tv_sec % 1000, (int)__xxts.tv_usec, \
+ __LINE__, __FUNCTION__, ##__VA_ARGS__); \
+ } while (0)
+
+#define nm_prerr(format, ...) \
do { \
struct timeval __xxts; \
microtime(&__xxts); \
- nm_prerr("%03d.%06d [%4d] %-25s " format "\n", \
+ nm_prerr_int("%03d.%06d [%4d] %-25s " format "\n",\
(int)__xxts.tv_sec % 1000, (int)__xxts.tv_usec, \
__LINE__, __FUNCTION__, ##__VA_ARGS__); \
} while (0)
-/* rate limited, lps indicates how many per second */
-#define RD(lps, format, ...) \
+/* Disabled printf (used to be ND). */
+#define nm_prdis(format, ...)
+
+/* Rate limited, lps indicates how many per second. */
+#define nm_prlim(lps, format, ...) \
do { \
static int t0, __cnt; \
if (t0 != time_second) { \
@@ -268,9 +280,14 @@ typedef struct hrtimer{
__cnt = 0; \
} \
if (__cnt++ < lps) \
- D(format, ##__VA_ARGS__); \
+ nm_prinf(format, ##__VA_ARGS__); \
} while (0)
+/* Old macros. */
+#define ND nm_prdis
+#define D nm_prerr
+#define RD nm_prlim
+
struct netmap_adapter;
struct nm_bdg_fwd;
struct nm_bridge;
@@ -700,7 +717,7 @@ struct netmap_adapter {
*/
#define NAF_HOST_RINGS 64 /* the adapter supports the host rings */
#define NAF_FORCE_NATIVE 128 /* the adapter is always NATIVE */
-#define NAF_PTNETMAP_HOST 256 /* the adapter supports ptnetmap in the host */
+/* free */
#define NAF_MOREFRAG 512 /* the adapter supports NS_MOREFRAG */
#define NAF_ZOMBIE (1U<<30) /* the nic driver has been unloaded */
#define NAF_BUSY (1U<<31) /* the adapter is used internally and
@@ -718,9 +735,9 @@ struct netmap_adapter {
u_int num_tx_desc; /* number of descriptor in each queue */
u_int num_rx_desc;
- /* tx_rings and rx_rings are private but allocated
- * as a contiguous chunk of memory. Each array has
- * N+1 entries, for the adapter queues and for the host queue.
+ /* tx_rings and rx_rings are private but allocated as a
+ * contiguous chunk of memory. Each array has N+K entries,
+ * N for the hardware rings and K for the host rings.
*/
struct netmap_kring **tx_rings; /* array of TX rings. */
struct netmap_kring **rx_rings; /* array of RX rings. */
@@ -1080,12 +1097,12 @@ struct netmap_bwrap_adapter {
*/
struct netmap_vp_adapter *saved_na_vp;
};
-int nm_bdg_ctl_attach(struct nmreq_header *hdr, void *auth_token);
-int nm_bdg_ctl_detach(struct nmreq_header *hdr, void *auth_token);
int nm_bdg_polling(struct nmreq_header *hdr);
-int netmap_bdg_list(struct nmreq_header *hdr);
#ifdef WITH_VALE
+int netmap_vale_attach(struct nmreq_header *hdr, void *auth_token);
+int netmap_vale_detach(struct nmreq_header *hdr, void *auth_token);
+int netmap_vale_list(struct nmreq_header *hdr);
int netmap_vi_create(struct nmreq_header *hdr, int);
int nm_vi_create(struct nmreq_header *);
int nm_vi_destroy(const char *name);
@@ -1115,6 +1132,12 @@ struct netmap_pipe_adapter {
#endif /* WITH_PIPES */
+#ifdef WITH_NMNULL
+struct netmap_null_adapter {
+ struct netmap_adapter up;
+};
+#endif /* WITH_NMNULL */
+
/* return slots reserved to rx clients; used in drivers */
static inline uint32_t
@@ -1442,51 +1465,8 @@ void netmap_unget_na(struct netmap_adapter *na, struct ifnet *ifp);
int netmap_get_hw_na(struct ifnet *ifp,
struct netmap_mem_d *nmd, struct netmap_adapter **na);
-
-/*
- * The following bridge-related functions are used by other
- * kernel modules.
- *
- * VALE only supports unicast or broadcast. The lookup
- * function can return 0 .. NM_BDG_MAXPORTS-1 for regular ports,
- * NM_BDG_MAXPORTS for broadcast, NM_BDG_MAXPORTS+1 to indicate
- * drop.
- */
-typedef uint32_t (*bdg_lookup_fn_t)(struct nm_bdg_fwd *ft, uint8_t *ring_nr,
- struct netmap_vp_adapter *, void *private_data);
-typedef int (*bdg_config_fn_t)(struct nm_ifreq *);
-typedef void (*bdg_dtor_fn_t)(const struct netmap_vp_adapter *);
-typedef void *(*bdg_update_private_data_fn_t)(void *private_data, void *callback_data, int *error);
-typedef int (*bdg_vp_create_fn_t)(struct nmreq_header *hdr,
- struct ifnet *ifp, struct netmap_mem_d *nmd,
- struct netmap_vp_adapter **ret);
-typedef int (*bdg_bwrap_attach_fn_t)(const char *nr_name, struct netmap_adapter *hwna);
-struct netmap_bdg_ops {
- bdg_lookup_fn_t lookup;
- bdg_config_fn_t config;
- bdg_dtor_fn_t dtor;
- bdg_vp_create_fn_t vp_create;
- bdg_bwrap_attach_fn_t bwrap_attach;
- char name[IFNAMSIZ];
-};
-int netmap_bwrap_attach(const char *name, struct netmap_adapter *, struct netmap_bdg_ops *);
-int netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *private_data, void *auth_token);
-
-#define NM_BRIDGES 8 /* number of bridges */
-#define NM_BDG_MAXPORTS 254 /* up to 254 */
-#define NM_BDG_BROADCAST NM_BDG_MAXPORTS
-#define NM_BDG_NOPORT (NM_BDG_MAXPORTS+1)
-
-struct nm_bridge *netmap_init_bridges2(u_int);
-void netmap_uninit_bridges2(struct nm_bridge *, u_int);
-int netmap_init_bridges(void);
-void netmap_uninit_bridges(void);
-int nm_bdg_update_private_data(const char *name, bdg_update_private_data_fn_t callback,
- void *callback_data, void *auth_token);
-int netmap_bdg_config(struct nm_ifreq *nifr);
-
#ifdef WITH_VALE
-uint32_t netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
+uint32_t netmap_vale_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
struct netmap_vp_adapter *, void *private_data);
/* these are redefined in case of no VALE support */
@@ -1525,11 +1505,20 @@ void netmap_monitor_stop(struct netmap_adapter *na);
(((struct nmreq_register *)(uintptr_t)hdr->nr_body)->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX) ? EOPNOTSUPP : 0)
#endif
+#ifdef WITH_NMNULL
+int netmap_get_null_na(struct nmreq_header *hdr, struct netmap_adapter **na,
+ struct netmap_mem_d *nmd, int create);
+#else /* !WITH_NMNULL */
+#define netmap_get_null_na(hdr, _2, _3, _4) \
+ (((struct nmreq_register *)(uintptr_t)hdr->nr_body)->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX) ? EOPNOTSUPP : 0)
+#endif /* WITH_NMNULL */
+
#ifdef CONFIG_NET_NS
struct net *netmap_bns_get(void);
void netmap_bns_put(struct net *);
void netmap_bns_getbridges(struct nm_bridge **, u_int *);
#else
+extern struct nm_bridge *nm_bridges;
#define netmap_bns_get()
#define netmap_bns_put(_1)
#define netmap_bns_getbridges(b, n) \
@@ -1591,16 +1580,24 @@ int netmap_adapter_put(struct netmap_adapter *na);
#define NETMAP_BUF_SIZE(_na) ((_na)->na_lut.objsize)
extern int netmap_no_pendintr;
extern int netmap_mitigate;
-extern int netmap_verbose; /* for debugging */
-enum { /* verbose flags */
- NM_VERB_ON = 1, /* generic verbose */
- NM_VERB_HOST = 0x2, /* verbose host stack */
- NM_VERB_RXSYNC = 0x10, /* verbose on rxsync/txsync */
- NM_VERB_TXSYNC = 0x20,
- NM_VERB_RXINTR = 0x100, /* verbose on rx/tx intr (driver) */
- NM_VERB_TXINTR = 0x200,
- NM_VERB_NIC_RXSYNC = 0x1000, /* verbose on rx/tx intr (driver) */
- NM_VERB_NIC_TXSYNC = 0x2000,
+extern int netmap_verbose;
+#ifdef CONFIG_NETMAP_DEBUG
+extern int netmap_debug; /* for debugging */
+#else /* !CONFIG_NETMAP_DEBUG */
+#define netmap_debug (0)
+#endif /* !CONFIG_NETMAP_DEBUG */
+enum { /* debug flags */
+ NM_DEBUG_ON = 1, /* generic debug messsages */
+ NM_DEBUG_HOST = 0x2, /* debug host stack */
+ NM_DEBUG_RXSYNC = 0x10, /* debug on rxsync/txsync */
+ NM_DEBUG_TXSYNC = 0x20,
+ NM_DEBUG_RXINTR = 0x100, /* debug on rx/tx intr (driver) */
+ NM_DEBUG_TXINTR = 0x200,
+ NM_DEBUG_NIC_RXSYNC = 0x1000, /* debug on rx/tx intr (driver) */
+ NM_DEBUG_NIC_TXSYNC = 0x2000,
+ NM_DEBUG_MEM = 0x4000, /* verbose memory allocations/deallocations */
+ NM_DEBUG_VALE = 0x8000, /* debug messages from memory allocators */
+ NM_DEBUG_BDG = NM_DEBUG_VALE,
};
extern int netmap_txsync_retry;
@@ -1612,7 +1609,6 @@ extern int netmap_generic_rings;
#ifdef linux
extern int netmap_generic_txqdisc;
#endif
-extern int ptnetmap_tx_workers;
/*
* NA returns a pointer to the struct netmap adapter from the ifp.
@@ -1809,6 +1805,11 @@ static inline int
netmap_idx_n2k(struct netmap_kring *kr, int idx)
{
int n = kr->nkr_num_slots;
+
+ if (likely(kr->nkr_hwofs == 0)) {
+ return idx;
+ }
+
idx += kr->nkr_hwofs;
if (idx < 0)
return idx + n;
@@ -1823,6 +1824,11 @@ static inline int
netmap_idx_k2n(struct netmap_kring *kr, int idx)
{
int n = kr->nkr_num_slots;
+
+ if (likely(kr->nkr_hwofs == 0)) {
+ return idx;
+ }
+
idx -= kr->nkr_hwofs;
if (idx < 0)
return idx + n;
@@ -1911,6 +1917,9 @@ struct netmap_priv_d {
u_int np_qfirst[NR_TXRX],
np_qlast[NR_TXRX]; /* range of tx/rx rings to scan */
uint16_t np_txpoll;
+ uint16_t np_kloop_state; /* use with NMG_LOCK held */
+#define NM_SYNC_KLOOP_RUNNING (1 << 0)
+#define NM_SYNC_KLOOP_STOPPING (1 << 1)
int np_sync_flags; /* to be passed to nm_sync */
int np_refs; /* use with NMG_LOCK held */
@@ -1920,7 +1929,26 @@ struct netmap_priv_d {
* number of rings.
*/
NM_SELINFO_T *np_si[NR_TXRX];
+
+ /* In the optional CSB mode, the user must specify the start address
+ * of two arrays of Communication Status Block (CSB) entries, for the
+ * two directions (kernel read application write, and kernel write
+ * application read).
+ * The number of entries must agree with the number of rings bound to
+ * the netmap file descriptor. The entries corresponding to the TX
+ * rings are laid out before the ones corresponding to the RX rings.
+ *
+ * Array of CSB entries for application --> kernel communication
+ * (N entries). */
+ struct nm_csb_atok *np_csb_atok_base;
+ /* Array of CSB entries for kernel --> application communication
+ * (N entries). */
+ struct nm_csb_ktoa *np_csb_ktoa_base;
+
struct thread *np_td; /* kqueue, just debugging */
+#ifdef linux
+ struct file *np_filp; /* used by sync kloop */
+#endif /* linux */
};
struct netmap_priv_d *netmap_priv_new(void);
@@ -1943,6 +1971,14 @@ static inline int nm_kring_pending(struct netmap_priv_d *np)
return 0;
}
+/* call with NMG_LOCK held */
+static __inline int
+nm_si_user(struct netmap_priv_d *priv, enum txrx t)
+{
+ return (priv->np_na != NULL &&
+ (priv->np_qlast[t] - priv->np_qfirst[t] > 1));
+}
+
#ifdef WITH_PIPES
int netmap_pipe_txsync(struct netmap_kring *txkring, int flags);
int netmap_pipe_rxsync(struct netmap_kring *rxkring, int flags);
@@ -2143,17 +2179,14 @@ void nm_os_vi_init_index(void);
* kernel thread routines
*/
struct nm_kctx; /* OS-specific kernel context - opaque */
-typedef void (*nm_kctx_worker_fn_t)(void *data, int is_kthread);
-typedef void (*nm_kctx_notify_fn_t)(void *data);
+typedef void (*nm_kctx_worker_fn_t)(void *data);
/* kthread configuration */
struct nm_kctx_cfg {
long type; /* kthread type/identifier */
nm_kctx_worker_fn_t worker_fn; /* worker function */
void *worker_private;/* worker parameter */
- nm_kctx_notify_fn_t notify_fn; /* notify function */
int attach_user; /* attach kthread to user process */
- int use_kthread; /* use a kthread for the context */
};
/* kthread configuration */
struct nm_kctx *nm_os_kctx_create(struct nm_kctx_cfg *cfg,
@@ -2161,47 +2194,24 @@ struct nm_kctx *nm_os_kctx_create(struct nm_kctx_cfg *cfg,
int nm_os_kctx_worker_start(struct nm_kctx *);
void nm_os_kctx_worker_stop(struct nm_kctx *);
void nm_os_kctx_destroy(struct nm_kctx *);
-void nm_os_kctx_worker_wakeup(struct nm_kctx *nmk);
-void nm_os_kctx_send_irq(struct nm_kctx *);
void nm_os_kctx_worker_setaff(struct nm_kctx *, int);
u_int nm_os_ncpus(void);
-#ifdef WITH_PTNETMAP_HOST
-/*
- * netmap adapter for host ptnetmap ports
- */
-struct netmap_pt_host_adapter {
- struct netmap_adapter up;
+int netmap_sync_kloop(struct netmap_priv_d *priv,
+ struct nmreq_header *hdr);
+int netmap_sync_kloop_stop(struct netmap_priv_d *priv);
- /* the passed-through adapter */
- struct netmap_adapter *parent;
- /* parent->na_flags, saved at NETMAP_PT_HOST_CREATE time,
- * and restored at NETMAP_PT_HOST_DELETE time */
- uint32_t parent_na_flags;
+#ifdef WITH_PTNETMAP
+/* ptnetmap guest routines */
- int (*parent_nm_notify)(struct netmap_kring *kring, int flags);
- void *ptns;
-};
-
-/* ptnetmap host-side routines */
-int netmap_get_pt_host_na(struct nmreq_header *hdr, struct netmap_adapter **na,
- struct netmap_mem_d * nmd, int create);
-int ptnetmap_ctl(const char *nr_name, int create, struct netmap_adapter *na);
-
-static inline int
-nm_ptnetmap_host_on(struct netmap_adapter *na)
-{
- return na && na->na_flags & NAF_PTNETMAP_HOST;
-}
-#else /* !WITH_PTNETMAP_HOST */
-#define netmap_get_pt_host_na(hdr, _2, _3, _4) \
- (((struct nmreq_register *)(uintptr_t)hdr->nr_body)->nr_flags & (NR_PTNETMAP_HOST) ? EOPNOTSUPP : 0)
-#define ptnetmap_ctl(_1, _2, _3) EINVAL
-#define nm_ptnetmap_host_on(_1) EINVAL
-#endif /* !WITH_PTNETMAP_HOST */
-
-#ifdef WITH_PTNETMAP_GUEST
-/* ptnetmap GUEST routines */
+/*
+ * ptnetmap_memdev routines used to talk with ptnetmap_memdev device driver
+ */
+struct ptnetmap_memdev;
+int nm_os_pt_memdev_iomap(struct ptnetmap_memdev *, vm_paddr_t *, void **,
+ uint64_t *);
+void nm_os_pt_memdev_iounmap(struct ptnetmap_memdev *);
+uint32_t nm_os_pt_memdev_ioread(struct ptnetmap_memdev *, unsigned int);
/*
* netmap adapter for guest ptnetmap ports
@@ -2218,26 +2228,83 @@ struct netmap_pt_guest_adapter {
* network stack and netmap clients.
* Used to decide when we need (de)allocate krings/rings and
* start (stop) ptnetmap kthreads. */
- int backend_regifs;
+ int backend_users;
};
int netmap_pt_guest_attach(struct netmap_adapter *na,
unsigned int nifp_offset,
unsigned int memid);
-struct ptnet_csb_gh;
-struct ptnet_csb_hg;
-bool netmap_pt_guest_txsync(struct ptnet_csb_gh *ptgh,
- struct ptnet_csb_hg *pthg,
- struct netmap_kring *kring,
- int flags);
-bool netmap_pt_guest_rxsync(struct ptnet_csb_gh *ptgh,
- struct ptnet_csb_hg *pthg,
+bool netmap_pt_guest_txsync(struct nm_csb_atok *atok,
+ struct nm_csb_ktoa *ktoa,
+ struct netmap_kring *kring, int flags);
+bool netmap_pt_guest_rxsync(struct nm_csb_atok *atok,
+ struct nm_csb_ktoa *ktoa,
struct netmap_kring *kring, int flags);
int ptnet_nm_krings_create(struct netmap_adapter *na);
void ptnet_nm_krings_delete(struct netmap_adapter *na);
void ptnet_nm_dtor(struct netmap_adapter *na);
-#endif /* WITH_PTNETMAP_GUEST */
+
+/* Guest driver: Write kring pointers (cur, head) to the CSB.
+ * This routine is coupled with ptnetmap_host_read_kring_csb(). */
+static inline void
+ptnetmap_guest_write_kring_csb(struct nm_csb_atok *atok, uint32_t cur,
+ uint32_t head)
+{
+ /*
+ * We need to write cur and head to the CSB but we cannot do it atomically.
+ * There is no way we can prevent the host from reading the updated value
+ * of one of the two and the old value of the other. However, if we make
+ * sure that the host never reads a value of head more recent than the
+ * value of cur we are safe. We can allow the host to read a value of cur
+ * more recent than the value of head, since in the netmap ring cur can be
+ * ahead of head and cur cannot wrap around head because it must be behind
+ * tail. Inverting the order of writes below could instead result into the
+ * host to think head went ahead of cur, which would cause the sync
+ * prologue to fail.
+ *
+ * The following memory barrier scheme is used to make this happen:
+ *
+ * Guest Host
+ *
+ * STORE(cur) LOAD(head)
+ * mb() <-----------> mb()
+ * STORE(head) LOAD(cur)
+ */
+ atok->cur = cur;
+ nm_stst_barrier();
+ atok->head = head;
+}
+
+/* Guest driver: Read kring pointers (hwcur, hwtail) from the CSB.
+ * This routine is coupled with ptnetmap_host_write_kring_csb(). */
+static inline void
+ptnetmap_guest_read_kring_csb(struct nm_csb_ktoa *ktoa,
+ struct netmap_kring *kring)
+{
+ /*
+ * We place a memory barrier to make sure that the update of hwtail never
+ * overtakes the update of hwcur.
+ * (see explanation in ptnetmap_host_write_kring_csb).
+ */
+ kring->nr_hwtail = ktoa->hwtail;
+ nm_stst_barrier();
+ kring->nr_hwcur = ktoa->hwcur;
+}
+
+/* Helper function wrapping ptnetmap_guest_read_kring_csb(). */
+static inline void
+ptnet_sync_tail(struct nm_csb_ktoa *ktoa, struct netmap_kring *kring)
+{
+ struct netmap_ring *ring = kring->ring;
+
+ /* Update hwcur and hwtail as known by the host. */
+ ptnetmap_guest_read_kring_csb(ktoa, kring);
+
+ /* nm_sync_finalize */
+ ring->tail = kring->rtail = kring->nr_hwtail;
+}
+#endif /* WITH_PTNETMAP */
#ifdef __FreeBSD__
/*
@@ -2355,4 +2422,16 @@ nm_os_get_mbuf(struct ifnet *ifp, int len)
struct nmreq_option * nmreq_findoption(struct nmreq_option *, uint16_t);
int nmreq_checkduplicate(struct nmreq_option *);
+int netmap_init_bridges(void);
+void netmap_uninit_bridges(void);
+
+/* Functions to read and write CSB fields from the kernel. */
+#if defined (linux)
+#define CSB_READ(csb, field, r) (get_user(r, &csb->field))
+#define CSB_WRITE(csb, field, v) (put_user(v, &csb->field))
+#else /* ! linux */
+#define CSB_READ(csb, field, r) (r = fuword32(&csb->field))
+#define CSB_WRITE(csb, field, v) (suword32(&csb->field, v))
+#endif /* ! linux */
+
#endif /* _NET_NETMAP_KERN_H_ */