/* * Copyright (C) 2012-2014 Luigi Rizzo - Universita` di Pisa * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * glue code to build the netmap bsd code under linux. * Some of these tweaks are generic, some are specific for * character device drivers and network code/device drivers. */ #ifndef _BSD_GLUE_H #define _BSD_GLUE_H /* a set of headers used in netmap */ #include #include // ACCESS_ONCE() #include #include #include #include #include #include #include #include #include #include #include #include // eth_type_trans #include #include #include // virt_to_phys #include #include // msleep #include // skb_copy_to_linear_data_offset #include // virt_to_phys #include #define printf(fmt, arg...) printk(KERN_ERR fmt, ##arg) #define KASSERT(a, b) BUG_ON(!(a)) /*----- support for compiling on older versions of linux -----*/ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 21) #define HRTIMER_MODE_REL HRTIMER_REL #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) #define skb_copy_from_linear_data_offset(skb, offset, to, copy) \ memcpy(to, (skb)->data + offset, copy) #define skb_copy_to_linear_data_offset(skb, offset, from, copy) \ memcpy((skb)->data + offset, from, copy) #define skb_copy_to_linear_data(skb, from, copy) \ memcpy((skb)->data, from, copy) #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) #define ACCESS_ONCE(x) (x) #define uintptr_t unsigned long #define skb_get_queue_mapping(m) (0) #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25) /* Forward a hrtimer so it expires after the hrtimer's current now */ static inline u64 hrtimer_forward_now(struct hrtimer *timer, ktime_t interval) { return hrtimer_forward(timer, timer->base->get_time(), interval); } #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) typedef unsigned long phys_addr_t; extern struct net init_net; #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28) // XXX #define netdev_ops hard_start_xmit struct net_device_ops { int (*ndo_start_xmit)(struct sk_buff *skb, struct net_device *dev); }; #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) // XXX 31 #define netdev_tx_t int #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) #define usleep_range(a, b) msleep((a)+(b)+999) #endif /* up to 2.6.35 */ /*----------- end of LINUX_VERSION_CODE dependencies ----------*/ /* Type redefinitions. XXX check them */ typedef void * bus_dma_tag_t; typedef void * bus_dmamap_t; typedef int bus_size_t; typedef int bus_dma_segment_t; typedef void * bus_addr_t; #define vm_paddr_t phys_addr_t /* XXX the 'off_t' on Linux corresponds to a 'long' */ #define vm_offset_t uint32_t #define vm_ooffset_t unsigned long struct thread; /* endianness macros/functions */ #define le16toh le16_to_cpu #define le32toh le32_to_cpu #define le64toh le64_to_cpu #define be16toh be16_to_cpu #define be32toh be32_to_cpu #define be64toh be64_to_cpu #define htole32 cpu_to_le32 #define htole64 cpu_to_le64 #define htobe16 cpu_to_be16 #define htobe32 cpu_to_be32 #include #define time_second (jiffies_to_msecs(jiffies) / 1000U ) #define bzero(a, len) memset(a, 0, len) /* Atomic variables. */ #define NM_ATOMIC_TEST_AND_SET(p) test_and_set_bit(0, (p)) #define NM_ATOMIC_CLEAR(p) clear_bit(0, (p)) #define NM_ATOMIC_SET(p, v) atomic_set(p, v) #define NM_ATOMIC_INC(p) atomic_inc(p) #define NM_ATOMIC_READ_AND_CLEAR(p) atomic_xchg(p, 0) #define NM_ATOMIC_READ(p) atomic_read(p) // XXX maybe implement it as a proper function somewhere // it is important to set s->len before the copy. #define m_devget(_buf, _len, _ofs, _dev, _fn) ( { \ struct sk_buff *s = netdev_alloc_skb(_dev, _len); \ if (s) { \ skb_put(s, _len); \ skb_copy_to_linear_data_offset(s, _ofs, _buf, _len); \ s->protocol = eth_type_trans(s, _dev); \ } \ s; } ) #define mbuf sk_buff #define m_nextpkt next // chain of mbufs #define m_freem(m) dev_kfree_skb_any(m) // free a sk_buff #define GET_MBUF_REFCNT(m) NM_ATOMIC_READ(&((m)->users)) #define netmap_get_mbuf(size) alloc_skb(size, GFP_ATOMIC) /* * on tx we force skb->queue_mapping = ring_nr, * but on rx it is the driver that sets the value, * and it is 0 for no setting, ring_nr+1 otherwise. */ #define MBUF_TXQ(m) skb_get_queue_mapping(m) #define MBUF_RXQ(m) (skb_rx_queue_recorded(m) ? skb_get_rx_queue(m) : 0) #define SET_MBUF_DESTRUCTOR(m, f) m->destructor = (void *)&f /* Magic number for sk_buff.priority field, used to take decisions in * generic_ndo_start_xmit() and in linux_generic_rx_handler(). */ #define NM_MAGIC_PRIORITY_TX 0xad86d310U #define NM_MAGIC_PRIORITY_RX 0xad86d311U /* * m_copydata() copies from mbuf to buffer following the mbuf chain. * skb_copy_bits() copies the skb headlen and all the fragments. */ #define m_copydata(m, o, l, b) skb_copy_bits(m, o, b, l) #define copyin(_from, _to, _len) copy_from_user(_to, _from, _len) /* * struct ifnet is remapped into struct net_device on linux. * ifnet has an if_softc field pointing to the device-specific struct * (adapter). * On linux the ifnet/net_device is at the beginning of the device-specific * structure, so a pointer to the first field of the ifnet works. * We don't use this in netmap, though. * * if_xname name device name * if_capenable priv_flags * we would use "features" but it is all taken. * XXX check for conflict in flags use. * * In netmap we use if_pspare[0] to point to the netmap_adapter, * in linux we have no spares so we overload ax25_ptr, and the detection * for netmap-capable is some magic in the area pointed by that. */ #define WNA(_ifp) (_ifp)->ax25_ptr #define ifnet net_device /* remap */ #define if_xname name /* field ifnet-> net_device */ #define if_capenable priv_flags /* IFCAP_NETMAP */ /* some other FreeBSD APIs */ struct net_device* ifunit_ref(const char *name); void if_rele(struct net_device *ifp); /* hook to send from user space */ netdev_tx_t linux_netmap_start_xmit(struct sk_buff *, struct net_device *); /* prevent ring params change while in netmap mode */ int linux_netmap_set_ringparam(struct net_device *, struct ethtool_ringparam *); #ifdef ETHTOOL_SCHANNELS int linux_netmap_set_channels(struct net_device *, struct ethtool_channels *); #endif #define CURVNET_SET(x) #define CURVNET_RESTORE(x) #define refcount_acquire(_a) atomic_add(1, (atomic_t *)_a) #define refcount_release(_a) atomic_dec_and_test((atomic_t *)_a) /* * We use spin_lock_irqsave() because we use the lock in the * (hard) interrupt context. */ typedef struct { spinlock_t sl; ulong flags; } safe_spinlock_t; static inline void mtx_lock(safe_spinlock_t *m) { spin_lock_irqsave(&(m->sl), m->flags); } static inline void mtx_unlock(safe_spinlock_t *m) { ulong flags = ACCESS_ONCE(m->flags); spin_unlock_irqrestore(&(m->sl), flags); } #define mtx_init(a, b, c, d) spin_lock_init(&((a)->sl)) #define mtx_destroy(a) // XXX spin_lock_destroy(a) /* * XXX these must be changed, as we cannot sleep within the RCU. * Must change to proper rwlock, and then can move the definitions * into the main netmap.c file. */ #define BDG_RWLOCK_T struct rw_semaphore #define BDG_RWINIT(b) init_rwsem(&(b)->bdg_lock) #define BDG_WLOCK(b) down_write(&(b)->bdg_lock) #define BDG_WUNLOCK(b) up_write(&(b)->bdg_lock) #define BDG_RLOCK(b) down_read(&(b)->bdg_lock) #define BDG_RUNLOCK(b) up_read(&(b)->bdg_lock) #define BDG_RTRYLOCK(b) down_read_trylock(&(b)->bdg_lock) #define BDG_SET_VAR(lval, p) ((lval) = (p)) #define BDG_GET_VAR(lval) (lval) #define BDG_FREE(p) kfree(p) /* use volatile to fix a probable compiler error on 2.6.25 */ #define malloc(_size, type, flags) \ ({ volatile int _v = _size; kmalloc(_v, GFP_ATOMIC | __GFP_ZERO); }) #define free(a, t) kfree(a) // XXX do we need GPF_ZERO ? // XXX do we need GFP_DMA for slots ? // http://www.mjmwired.net/kernel/Documentation/DMA-API.txt #ifndef ilog2 /* not in 2.6.18 */ static inline int ilog2(uint64_t n) { uint64_t k = 1ULL<<63; int i; for (i = 63; i >= 0 && !(n &k); i--, k >>=1) ; return i; } #endif /* ilog2 */ #define contigmalloc(sz, ty, flags, a, b, pgsz, c) \ (char *) __get_free_pages(GFP_ATOMIC | __GFP_ZERO, \ ilog2(roundup_pow_of_two((sz)/PAGE_SIZE))) #define contigfree(va, sz, ty) free_pages((unsigned long)va, \ ilog2(roundup_pow_of_two(sz)/PAGE_SIZE)) #define vtophys virt_to_phys /*--- selrecord and friends ---*/ /* wake_up() or wake_up_interruptible() ? */ #define OS_selwakeup(sw, pri) wake_up(sw) #define selrecord(x, y) poll_wait((struct file *)x, y, pwait) // #define knlist_destroy(x) // XXX todo #define tsleep(a, b, c, t) msleep(10) // #define wakeup(sw) // XXX double check #define microtime do_gettimeofday // debugging /* * The following trick is to map a struct cdev into a struct miscdevice * On FreeBSD cdev and cdevsw are two different objects. */ #define cdev miscdevice #define cdevsw miscdevice /* * XXX to complete - the dmamap interface */ #define BUS_DMA_NOWAIT 0 #define bus_dmamap_load(_1, _2, _3, _4, _5, _6, _7) #define bus_dmamap_unload(_1, _2) typedef int (d_mmap_t)(struct file *f, struct vm_area_struct *vma); typedef unsigned int (d_poll_t)(struct file * file, struct poll_table_struct *pwait); /* * make_dev will set an error and return the first argument. * This relies on the availability of the 'error' local variable. * For old linux systems that do not have devfs, generate a * message in syslog so the sysadmin knows which command to run * in order to create the /dev/netmap entry */ #define make_dev(_cdev, _zero, _uid, _gid, _perm, _name) \ ({error = misc_register(_cdev); \ D("run mknod /dev/%s c %d %d # error %d", \ (_cdev)->name, MISC_MAJOR, (_cdev)->minor, error); \ _cdev; } ) #define destroy_dev(_cdev) misc_deregister(_cdev) /*--- sysctl API ----*/ /* * linux: sysctl are mapped into /sys/module/ipfw_mod parameters * windows: they are emulated via get/setsockopt */ #define CTLFLAG_RD 1 #define CTLFLAG_RW 2 struct sysctl_oid; struct sysctl_req; #define SYSCTL_DECL(_1) #define SYSCTL_OID(_1, _2, _3, _4, _5, _6, _7, _8) #define SYSCTL_NODE(_1, _2, _3, _4, _5, _6) #define _SYSCTL_BASE(_name, _var, _ty, _perm) \ module_param_named(_name, *(_var), _ty, \ ( (_perm) == CTLFLAG_RD) ? 0444: 0644 ) /* XXX should implement this */ extern struct kernel_param_ops generic_sysctl_ops; #define SYSCTL_PROC(_base, _oid, _name, _mode, _var, _val, _fn, _ty, _desc) \ module_param_cb(_name, &generic_sysctl_ops, _fn, \ ( (_mode) & CTLFLAG_WR) ? 0644: 0444 ) /* for a string, _var is a preallocated buffer of size _varlen */ #define SYSCTL_STRING(_base, _oid, _name, _mode, _var, _varlen, _desc) \ module_param_string(_name, _var, _varlen, \ ((_mode) == CTLFLAG_RD) ? 0444: 0644 ) #define SYSCTL_INT(_base, _oid, _name, _mode, _var, _val, _desc) \ _SYSCTL_BASE(_name, _var, int, _mode) #define SYSCTL_LONG(_base, _oid, _name, _mode, _var, _val, _desc) \ _SYSCTL_BASE(_name, _var, long, _mode) #define SYSCTL_ULONG(_base, _oid, _name, _mode, _var, _val, _desc) \ _SYSCTL_BASE(_name, _var, ulong, _mode) #define SYSCTL_UINT(_base, _oid, _name, _mode, _var, _val, _desc) \ _SYSCTL_BASE(_name, _var, uint, _mode) // #define TUNABLE_INT(_name, _ptr) #define SYSCTL_VNET_PROC SYSCTL_PROC #define SYSCTL_VNET_INT SYSCTL_INT #define SYSCTL_HANDLER_ARGS \ struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req int sysctl_handle_int(SYSCTL_HANDLER_ARGS); int sysctl_handle_long(SYSCTL_HANDLER_ARGS); #define MALLOC_DECLARE(a) #define MALLOC_DEFINE(a, b, c) #define devfs_get_cdevpriv(pp) \ ({ *(struct netmap_priv_d **)pp = ((struct file *)td)->private_data; \ (*pp ? 0 : ENOENT); }) /* devfs_set_cdevpriv cannot fail on linux */ #define devfs_set_cdevpriv(p, fn) \ ({ ((struct file *)td)->private_data = p; (p ? 0 : EINVAL); }) #define devfs_clear_cdevpriv() do { \ netmap_dtor(priv); ((struct file *)td)->private_data = 0; \ } while (0) #endif /* _BSD_GLUE_H */