Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/netmap/netmap_freebsd.c
Show First 20 Lines • Show All 165 Lines • ▼ Show 20 Lines | |||||
void | void | ||||
nm_os_put_module(void) | nm_os_put_module(void) | ||||
{ | { | ||||
netmap_use_count--; | netmap_use_count--; | ||||
} | } | ||||
static void | static void | ||||
netmap_ifnet_arrival_handler(void *arg __unused, struct ifnet *ifp) | netmap_ifnet_arrival_handler(void *arg __unused, if_t ifp) | ||||
{ | { | ||||
netmap_undo_zombie(ifp); | netmap_undo_zombie(ifp); | ||||
} | } | ||||
static void | static void | ||||
netmap_ifnet_departure_handler(void *arg __unused, struct ifnet *ifp) | netmap_ifnet_departure_handler(void *arg __unused, if_t ifp) | ||||
{ | { | ||||
netmap_make_zombie(ifp); | netmap_make_zombie(ifp); | ||||
} | } | ||||
static eventhandler_tag nm_ifnet_ah_tag; | static eventhandler_tag nm_ifnet_ah_tag; | ||||
static eventhandler_tag nm_ifnet_dh_tag; | static eventhandler_tag nm_ifnet_dh_tag; | ||||
int | int | ||||
Show All 15 Lines | |||||
{ | { | ||||
EVENTHANDLER_DEREGISTER(ifnet_arrival_event, | EVENTHANDLER_DEREGISTER(ifnet_arrival_event, | ||||
nm_ifnet_ah_tag); | nm_ifnet_ah_tag); | ||||
EVENTHANDLER_DEREGISTER(ifnet_departure_event, | EVENTHANDLER_DEREGISTER(ifnet_departure_event, | ||||
nm_ifnet_dh_tag); | nm_ifnet_dh_tag); | ||||
} | } | ||||
unsigned | unsigned | ||||
nm_os_ifnet_mtu(struct ifnet *ifp) | nm_os_ifnet_mtu(if_t ifp) | ||||
{ | { | ||||
return ifp->if_mtu; | return if_getmtu(ifp); | ||||
} | } | ||||
rawsum_t | rawsum_t | ||||
nm_os_csum_raw(uint8_t *data, size_t len, rawsum_t cur_sum) | nm_os_csum_raw(uint8_t *data, size_t len, rawsum_t cur_sum) | ||||
{ | { | ||||
/* TODO XXX please use the FreeBSD implementation for this. */ | /* TODO XXX please use the FreeBSD implementation for this. */ | ||||
uint16_t *words = (uint16_t *)data; | uint16_t *words = (uint16_t *)data; | ||||
int nw = len / 2; | int nw = len / 2; | ||||
▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | if (!notsupported) { | ||||
notsupported = 1; | notsupported = 1; | ||||
nm_prerr("inet6 segmentation not supported"); | nm_prerr("inet6 segmentation not supported"); | ||||
} | } | ||||
#endif | #endif | ||||
} | } | ||||
/* on FreeBSD we send up one packet at a time */ | /* on FreeBSD we send up one packet at a time */ | ||||
void * | void * | ||||
nm_os_send_up(struct ifnet *ifp, struct mbuf *m, struct mbuf *prev) | nm_os_send_up(if_t ifp, struct mbuf *m, struct mbuf *prev) | ||||
{ | { | ||||
NA(ifp)->if_input(ifp, m); | NA(ifp)->if_input(ifp, m); | ||||
return NULL; | return NULL; | ||||
} | } | ||||
int | int | ||||
nm_os_mbuf_has_csum_offld(struct mbuf *m) | nm_os_mbuf_has_csum_offld(struct mbuf *m) | ||||
{ | { | ||||
return m->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP | CSUM_SCTP | | return m->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP | CSUM_SCTP | | ||||
CSUM_TCP_IPV6 | CSUM_UDP_IPV6 | | CSUM_TCP_IPV6 | CSUM_UDP_IPV6 | | ||||
CSUM_SCTP_IPV6); | CSUM_SCTP_IPV6); | ||||
} | } | ||||
int | int | ||||
nm_os_mbuf_has_seg_offld(struct mbuf *m) | nm_os_mbuf_has_seg_offld(struct mbuf *m) | ||||
{ | { | ||||
return m->m_pkthdr.csum_flags & CSUM_TSO; | return m->m_pkthdr.csum_flags & CSUM_TSO; | ||||
} | } | ||||
static void | static void | ||||
freebsd_generic_rx_handler(struct ifnet *ifp, struct mbuf *m) | freebsd_generic_rx_handler(if_t ifp, struct mbuf *m) | ||||
{ | { | ||||
int stolen; | int stolen; | ||||
if (unlikely(!NM_NA_VALID(ifp))) { | if (unlikely(!NM_NA_VALID(ifp))) { | ||||
nm_prlim(1, "Warning: RX packet intercepted, but no" | nm_prlim(1, "Warning: RX packet intercepted, but no" | ||||
" emulated adapter"); | " emulated adapter"); | ||||
return; | return; | ||||
} | } | ||||
Show All 9 Lines | |||||
/* | /* | ||||
* Intercept the rx routine in the standard device driver. | * Intercept the rx routine in the standard device driver. | ||||
* Second argument is non-zero to intercept, 0 to restore | * Second argument is non-zero to intercept, 0 to restore | ||||
*/ | */ | ||||
int | int | ||||
nm_os_catch_rx(struct netmap_generic_adapter *gna, int intercept) | nm_os_catch_rx(struct netmap_generic_adapter *gna, int intercept) | ||||
{ | { | ||||
struct netmap_adapter *na = &gna->up.up; | struct netmap_adapter *na = &gna->up.up; | ||||
struct ifnet *ifp = na->ifp; | if_t ifp = na->ifp; | ||||
int ret = 0; | int ret = 0; | ||||
nm_os_ifnet_lock(); | nm_os_ifnet_lock(); | ||||
if (intercept) { | if (intercept) { | ||||
if (gna->save_if_input) { | if (gna->save_if_input) { | ||||
nm_prerr("RX on %s already intercepted", na->name); | nm_prerr("RX on %s already intercepted", na->name); | ||||
ret = EBUSY; /* already set */ | ret = EBUSY; /* already set */ | ||||
goto out; | goto out; | ||||
} | } | ||||
if_setcapenablebit(ifp, IFCAP_NETMAP, 0); | |||||
ifp->if_capenable |= IFCAP_NETMAP; | gna->save_if_input = if_getinputfn(ifp); | ||||
gna->save_if_input = ifp->if_input; | if_setinputfn(ifp, freebsd_generic_rx_handler); | ||||
vmaffione: So a `if_getinputfn()` maybe? | |||||
Done Inline ActionsGood enough a name as any. jhibbits: Good enough a name as any. | |||||
ifp->if_input = freebsd_generic_rx_handler; | |||||
} else { | } else { | ||||
if (!gna->save_if_input) { | if (!gna->save_if_input) { | ||||
nm_prerr("Failed to undo RX intercept on %s", | nm_prerr("Failed to undo RX intercept on %s", | ||||
na->name); | na->name); | ||||
ret = EINVAL; /* not saved */ | ret = EINVAL; /* not saved */ | ||||
goto out; | goto out; | ||||
} | } | ||||
if_setcapenablebit(ifp, 0, IFCAP_NETMAP); | |||||
ifp->if_capenable &= ~IFCAP_NETMAP; | if_setinputfn(ifp, gna->save_if_input); | ||||
ifp->if_input = gna->save_if_input; | |||||
gna->save_if_input = NULL; | gna->save_if_input = NULL; | ||||
} | } | ||||
out: | out: | ||||
nm_os_ifnet_unlock(); | nm_os_ifnet_unlock(); | ||||
return ret; | return ret; | ||||
} | } | ||||
/* | /* | ||||
* Intercept the packet steering routine in the tx path, | * Intercept the packet steering routine in the tx path, | ||||
* so that we can decide which queue is used for an mbuf. | * so that we can decide which queue is used for an mbuf. | ||||
* Second argument is non-zero to intercept, 0 to restore. | * Second argument is non-zero to intercept, 0 to restore. | ||||
* On freebsd we just intercept if_transmit. | * On freebsd we just intercept if_transmit. | ||||
*/ | */ | ||||
int | int | ||||
nm_os_catch_tx(struct netmap_generic_adapter *gna, int intercept) | nm_os_catch_tx(struct netmap_generic_adapter *gna, int intercept) | ||||
{ | { | ||||
struct netmap_adapter *na = &gna->up.up; | struct netmap_adapter *na = &gna->up.up; | ||||
struct ifnet *ifp = netmap_generic_getifp(gna); | if_t ifp = netmap_generic_getifp(gna); | ||||
nm_os_ifnet_lock(); | nm_os_ifnet_lock(); | ||||
if (intercept) { | if (intercept) { | ||||
na->if_transmit = ifp->if_transmit; | na->if_transmit = if_gettransmitfn(ifp); | ||||
ifp->if_transmit = netmap_transmit; | if_settransmitfn(ifp, netmap_transmit); | ||||
Not Done Inline ActionsWhat about a if_gettransmitfn()? vmaffione: What about a `if_gettransmitfn()`? | |||||
} else { | } else { | ||||
ifp->if_transmit = na->if_transmit; | if_settransmitfn(ifp, na->if_transmit); | ||||
} | } | ||||
nm_os_ifnet_unlock(); | nm_os_ifnet_unlock(); | ||||
return 0; | return 0; | ||||
} | } | ||||
/* | /* | ||||
Show All 12 Lines | |||||
* i = curcpu % adapter->num_queues; | * i = curcpu % adapter->num_queues; | ||||
* | * | ||||
*/ | */ | ||||
int | int | ||||
nm_os_generic_xmit_frame(struct nm_os_gen_arg *a) | nm_os_generic_xmit_frame(struct nm_os_gen_arg *a) | ||||
{ | { | ||||
int ret; | int ret; | ||||
u_int len = a->len; | u_int len = a->len; | ||||
struct ifnet *ifp = a->ifp; | if_t ifp = a->ifp; | ||||
struct mbuf *m = a->m; | struct mbuf *m = a->m; | ||||
/* Link the external storage to | /* Link the external storage to | ||||
* the netmap buffer, so that no copy is necessary. */ | * the netmap buffer, so that no copy is necessary. */ | ||||
m->m_ext.ext_buf = m->m_data = a->addr; | m->m_ext.ext_buf = m->m_data = a->addr; | ||||
m->m_ext.ext_size = len; | m->m_ext.ext_size = len; | ||||
m->m_flags |= M_PKTHDR; | m->m_flags |= M_PKTHDR; | ||||
m->m_len = m->m_pkthdr.len = len; | m->m_len = m->m_pkthdr.len = len; | ||||
/* mbuf refcnt is not contended, no need to use atomic | /* mbuf refcnt is not contended, no need to use atomic | ||||
* (a memory barrier is enough). */ | * (a memory barrier is enough). */ | ||||
SET_MBUF_REFCNT(m, 2); | SET_MBUF_REFCNT(m, 2); | ||||
M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE); | M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE); | ||||
m->m_pkthdr.flowid = a->ring_nr; | m->m_pkthdr.flowid = a->ring_nr; | ||||
m->m_pkthdr.rcvif = ifp; /* used for tx notification */ | m->m_pkthdr.rcvif = ifp; /* used for tx notification */ | ||||
CURVNET_SET(ifp->if_vnet); | CURVNET_SET(if_getvnet(ifp)); | ||||
ret = NA(ifp)->if_transmit(ifp, m); | ret = NA(ifp)->if_transmit(ifp, m); | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
return ret ? -1 : 0; | return ret ? -1 : 0; | ||||
} | } | ||||
struct netmap_adapter * | struct netmap_adapter * | ||||
netmap_getna(if_t ifp) | netmap_getna(if_t ifp) | ||||
{ | { | ||||
return (NA((struct ifnet *)ifp)); | return (NA(ifp)); | ||||
} | } | ||||
/* | /* | ||||
* The following two functions are empty until we have a generic | * The following two functions are empty until we have a generic | ||||
* way to extract the info from the ifp | * way to extract the info from the ifp | ||||
*/ | */ | ||||
int | int | ||||
nm_os_generic_find_num_desc(struct ifnet *ifp, unsigned int *tx, unsigned int *rx) | nm_os_generic_find_num_desc(if_t ifp, unsigned int *tx, unsigned int *rx) | ||||
{ | { | ||||
return 0; | return 0; | ||||
} | } | ||||
void | void | ||||
nm_os_generic_find_num_queues(struct ifnet *ifp, u_int *txq, u_int *rxq) | nm_os_generic_find_num_queues(if_t ifp, u_int *txq, u_int *rxq) | ||||
{ | { | ||||
unsigned num_rings = netmap_generic_rings ? netmap_generic_rings : 1; | unsigned num_rings = netmap_generic_rings ? netmap_generic_rings : 1; | ||||
*txq = num_rings; | *txq = num_rings; | ||||
*rxq = num_rings; | *rxq = num_rings; | ||||
} | } | ||||
void | void | ||||
Show All 34 Lines | |||||
void | void | ||||
nm_os_mitigation_cleanup(struct nm_generic_mit *mit) | nm_os_mitigation_cleanup(struct nm_generic_mit *mit) | ||||
{ | { | ||||
} | } | ||||
static int | static int | ||||
nm_vi_dummy(struct ifnet *ifp, u_long cmd, caddr_t addr) | nm_vi_dummy(if_t ifp, u_long cmd, caddr_t addr) | ||||
{ | { | ||||
return EINVAL; | return EINVAL; | ||||
} | } | ||||
static void | static void | ||||
nm_vi_start(struct ifnet *ifp) | nm_vi_start(if_t ifp) | ||||
{ | { | ||||
panic("nm_vi_start() must not be called"); | panic("nm_vi_start() must not be called"); | ||||
} | } | ||||
/* | /* | ||||
* Index manager of persistent virtual interfaces. | * Index manager of persistent virtual interfaces. | ||||
* It is used to decide the lowest byte of the MAC address. | * It is used to decide the lowest byte of the MAC address. | ||||
* We use the same algorithm with management of bridge port index. | * We use the same algorithm with management of bridge port index. | ||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | |||||
* It is based on if_tap.c and ip_fw_log.c in FreeBSD 9. | * It is based on if_tap.c and ip_fw_log.c in FreeBSD 9. | ||||
* | * | ||||
* Note: Linux sets refcount to 0 on allocation of net_device, | * Note: Linux sets refcount to 0 on allocation of net_device, | ||||
* then increments it on registration to the system. | * then increments it on registration to the system. | ||||
* FreeBSD sets refcount to 1 on if_alloc(), and does not | * FreeBSD sets refcount to 1 on if_alloc(), and does not | ||||
* increment this refcount on if_attach(). | * increment this refcount on if_attach(). | ||||
*/ | */ | ||||
int | int | ||||
nm_os_vi_persist(const char *name, struct ifnet **ret) | nm_os_vi_persist(const char *name, if_t *ret) | ||||
{ | { | ||||
struct ifnet *ifp; | if_t ifp; | ||||
u_short macaddr_hi; | u_short macaddr_hi; | ||||
uint32_t macaddr_mid; | uint32_t macaddr_mid; | ||||
u_char eaddr[6]; | u_char eaddr[6]; | ||||
int unit = nm_vi_get_index(); /* just to decide MAC address */ | int unit = nm_vi_get_index(); /* just to decide MAC address */ | ||||
if (unit < 0) | if (unit < 0) | ||||
return EBUSY; | return EBUSY; | ||||
/* | /* | ||||
* We use the same MAC address generation method with tap | * We use the same MAC address generation method with tap | ||||
* except for the highest octet is 00:be instead of 00:bd | * except for the highest octet is 00:be instead of 00:bd | ||||
*/ | */ | ||||
macaddr_hi = htons(0x00be); /* XXX tap + 1 */ | macaddr_hi = htons(0x00be); /* XXX tap + 1 */ | ||||
macaddr_mid = (uint32_t) ticks; | macaddr_mid = (uint32_t) ticks; | ||||
bcopy(&macaddr_hi, eaddr, sizeof(short)); | bcopy(&macaddr_hi, eaddr, sizeof(short)); | ||||
bcopy(&macaddr_mid, &eaddr[2], sizeof(uint32_t)); | bcopy(&macaddr_mid, &eaddr[2], sizeof(uint32_t)); | ||||
eaddr[5] = (uint8_t)unit; | eaddr[5] = (uint8_t)unit; | ||||
ifp = if_alloc(IFT_ETHER); | ifp = if_alloc(IFT_ETHER); | ||||
if (ifp == NULL) { | if (ifp == NULL) { | ||||
nm_prerr("if_alloc failed"); | nm_prerr("if_alloc failed"); | ||||
return ENOMEM; | return ENOMEM; | ||||
} | } | ||||
if_initname(ifp, name, IF_DUNIT_NONE); | if_initname(ifp, name, IF_DUNIT_NONE); | ||||
ifp->if_flags = IFF_UP | IFF_SIMPLEX | IFF_MULTICAST; | if_setflags(ifp, IFF_UP | IFF_SIMPLEX | IFF_MULTICAST); | ||||
ifp->if_init = (void *)nm_vi_dummy; | if_setinitfn(ifp, (void *)nm_vi_dummy); | ||||
ifp->if_ioctl = nm_vi_dummy; | if_setioctlfn(ifp, nm_vi_dummy); | ||||
ifp->if_start = nm_vi_start; | if_setstartfn(ifp, nm_vi_start); | ||||
ifp->if_mtu = ETHERMTU; | if_setmtu(ifp, ETHERMTU); | ||||
IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); | if_setsendqlen(ifp, ifqmaxlen); | ||||
ifp->if_capabilities |= IFCAP_LINKSTATE; | if_setcapabilitiesbit(ifp, IFCAP_LINKSTATE, 0); | ||||
ifp->if_capenable |= IFCAP_LINKSTATE; | if_setcapenablebit(ifp, IFCAP_LINKSTATE, 0); | ||||
Not Done Inline Actions@vmaffione zlei: @vmaffione
The mtu set got overwritten by line 626
`if_setmtu(ifp, ETHERMTU);` | |||||
Done Inline ActionsThat's right, thanks. I dropped that line in the src main branch. vmaffione: That's right, thanks. I dropped that line in the src main branch. | |||||
ether_ifattach(ifp, eaddr); | ether_ifattach(ifp, eaddr); | ||||
*ret = ifp; | *ret = ifp; | ||||
return 0; | return 0; | ||||
} | } | ||||
/* unregister from the system and drop the final refcount */ | /* unregister from the system and drop the final refcount */ | ||||
void | void | ||||
nm_os_vi_detach(struct ifnet *ifp) | nm_os_vi_detach(if_t ifp) | ||||
{ | { | ||||
nm_vi_free_index(((char *)IF_LLADDR(ifp))[5]); | nm_vi_free_index(((char *)if_getlladdr(ifp))[5]); | ||||
ether_ifdetach(ifp); | ether_ifdetach(ifp); | ||||
if_free(ifp); | if_free(ifp); | ||||
} | } | ||||
#ifdef WITH_EXTMEM | #ifdef WITH_EXTMEM | ||||
#include <vm/vm_map.h> | #include <vm/vm_map.h> | ||||
#include <vm/vm_extern.h> | #include <vm/vm_extern.h> | ||||
#include <vm/vm_kern.h> | #include <vm/vm_kern.h> | ||||
▲ Show 20 Lines • Show All 847 Lines • ▼ Show 20 Lines | freebsd_netmap_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data, | ||||
error = netmap_ioctl(priv, cmd, data, td, /*nr_body_is_user=*/1); | error = netmap_ioctl(priv, cmd, data, td, /*nr_body_is_user=*/1); | ||||
out: | out: | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
return error; | return error; | ||||
} | } | ||||
void | void | ||||
nm_os_onattach(struct ifnet *ifp) | nm_os_onattach(if_t ifp) | ||||
{ | { | ||||
ifp->if_capabilities |= IFCAP_NETMAP; | if_setcapabilitiesbit(ifp, IFCAP_NETMAP, 0); | ||||
} | } | ||||
void | void | ||||
nm_os_onenter(struct ifnet *ifp) | nm_os_onenter(if_t ifp) | ||||
{ | { | ||||
struct netmap_adapter *na = NA(ifp); | struct netmap_adapter *na = NA(ifp); | ||||
na->if_transmit = ifp->if_transmit; | na->if_transmit = if_gettransmitfn(ifp); | ||||
ifp->if_transmit = netmap_transmit; | if_settransmitfn(ifp, netmap_transmit); | ||||
ifp->if_capenable |= IFCAP_NETMAP; | if_setcapenablebit(ifp, IFCAP_NETMAP, 0); | ||||
} | } | ||||
void | void | ||||
nm_os_onexit(struct ifnet *ifp) | nm_os_onexit(if_t ifp) | ||||
{ | { | ||||
struct netmap_adapter *na = NA(ifp); | struct netmap_adapter *na = NA(ifp); | ||||
ifp->if_transmit = na->if_transmit; | if_settransmitfn(ifp, na->if_transmit); | ||||
ifp->if_capenable &= ~IFCAP_NETMAP; | if_setcapenablebit(ifp, 0, IFCAP_NETMAP); | ||||
} | } | ||||
extern struct cdevsw netmap_cdevsw; /* XXX used in netmap.c, should go elsewhere */ | extern struct cdevsw netmap_cdevsw; /* XXX used in netmap.c, should go elsewhere */ | ||||
struct cdevsw netmap_cdevsw = { | struct cdevsw netmap_cdevsw = { | ||||
.d_version = D_VERSION, | .d_version = D_VERSION, | ||||
.d_name = "netmap", | .d_name = "netmap", | ||||
.d_open = netmap_open, | .d_open = netmap_open, | ||||
.d_mmap_single = netmap_mmap_single, | .d_mmap_single = netmap_mmap_single, | ||||
▲ Show 20 Lines • Show All 67 Lines • Show Last 20 Lines |
So a if_getinputfn() maybe?