blob: be34aa3165c1e331ff09d467f32ad2d4bf66c604 [file] [log] [blame]
/*
* Copyright 2010
* Princeton University. All rights reserved.
*
* 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 PRINCETON UNIVERSITY ``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 PRINCETON UNIVERSITY 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.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of Princeton University.
*
*/
/*
* @(#)if_host.c (Princeton) 11/8/2010
*
*/
/*
* Host interface driver for protocol testing and timing.
*/
#include "bsd_opt_atalk.h"
#include "bsd_opt_inet.h"
#include "bsd_opt_inet6.h"
#include "bsd_opt_ipx.h"
#include <sys/bsd_param.h>
#include <sys/bsd_systm.h>
#include <sys/bsd_kernel.h>
#include <sys/bsd_mbuf.h>
//#include <machine/bsd_bus.h>
#include <sys/bsd_rman.h>
#include <sys/bsd_socket.h>
#include <sys/bsd_sockio.h>
#include <net/bsd_if.h>
#include <net/bsd_if_types.h>
#include <net/bsd_route.h>
#include <net/bsd_vnet.h>
#include <net/bsd_ethernet.h>
#include <net/bsd_netisr.h>
#ifdef INET
#include <netinet/bsd_in.h>
#include <netinet/bsd_in_var.h>
#endif
#include <signal.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/if_packet.h>
#include <sys/mman.h>
#include <poll.h>
#include "host_serv.h"
#include "if_host.h"
#include "shmbuf_ring.h"
extern int mp_ncpus;
int hif_ioctl(struct ifnet *, u_long, caddr_t);
int hif_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct route *ro);
void hif_input(struct ifnet *ifp, struct mbuf *m);
static int hif_create(char*);
static void hif_destroy(struct ifnet *);
static int hif_setup_interface(char *name, struct adapter* padapter);
static int hif_allocate_rings(struct adapter *adapter);
static int hif_free_rings(struct adapter* p_adapter);
static int hif_create_thread(struct adapter* adap, int i, void *(*routine)(void*), int type);
static void* hif_tx_link(void * t_args);
static void* hif_rx(void * t_args);
static void* hif_rx_link(void * t_args);
#ifdef FOR_SIMULATION
static char *hif_sendbuf;
static char *sendbuf_ptr;
static int hif_link_send_fd;
static int hif_link_recv_fd;
#endif
#ifdef PERFORMANCE_TUNING
extern struct timeval global_roi_start_tv;
#endif
VNET_DEFINE(struct ifnet *, hif); /* Used externally */
static void
hif_destroy(struct ifnet *ifp)
{
if_detach(ifp);
if_free(ifp);
}
/*
* @hif_create()
*
* This function is responsible for:
* 1) initilizing adapter sturcture.
* 2) creating N hif_tx/rx threads and initialize them with tx/rx_rings
* 3) creating 1 hif_rx_link thread
*/
static int
hif_create(char* name)
{
struct adapter *p_adapter;
int error = 0;
int i;
/*
* Step.1 create adapter
*/
p_adapter = (struct adapter*)bsd_malloc(sizeof(struct adapter), M_DEVBUF, M_ZERO);
HIF_CORE_LOCK_INIT(p_adapter, name);
/*
* Set the frame limits assuming
* standard ethernet sized frames.
*/
p_adapter->max_frame_size = ETHER_MAX_LEN;
p_adapter->min_frame_size = ETHER_MIN_LEN;
/* Initialize ifnet structure */
error = hif_setup_interface(name, p_adapter);
if(error < 0)
goto failed;
/*
* Step.2 creating N hif_tx/rx threads and initialize them with tx/rx_rings
* NOTE: the actualy ring buffer allocation is done in the hif_tx()
* and hif_rx() routine.
*/
p_adapter->num_tx_rings = 1;
p_adapter->num_rx_rings = mp_ncpus;
p_adapter->num_tx_buf = HIF_DEFAULT_TXB;
p_adapter->num_rx_buf = HIF_DEFAULT_RXB;
p_adapter->rx_mbuf_sz = MCLBYTES;
/* Allocate Ring Buffers*/
if((error = hif_allocate_rings(p_adapter)) < 0)
goto failed;
/* Create dedicated threads for rx */
for(i = 0; i < p_adapter->num_rx_rings; i ++){
error = hif_create_thread(p_adapter, i, hif_rx, THREAD_TYPE_RX_TCPIP);
if(error < 0)
goto failed;
}
/*
* Step.3 creating 1 hif_tx_link & 1 hif_rx_link thread
* NOTE: we call the following function just for creating a thread
* by passing index = -1;
*/
error = hif_create_thread(p_adapter, -1, hif_tx_link, THREAD_TYPE_TX_LINK);
if(error < 0)
goto failed;
error = hif_create_thread(p_adapter, -1, hif_rx_link, THREAD_TYPE_RX_LINK);
if(error < 0)
goto failed;
/* Tell the stack that the interface is not active */
p_adapter->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
p_adapter->ifp->if_drv_flags |= ~(IFF_DRV_RUNNING | IFF_UP);
return 0;
failed:
hif_destroy(p_adapter->ifp);
hif_free_rings(p_adapter);
return error;
}
void
vnet_hif_init(const void *unused )
{
hif_create("hif");
}
//VNET_SYSINIT(vnet_hif_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
// vnet_hif_init, NULL);
static int
hif_setup_interface(char *name, struct adapter* padapter)
{
struct ifnet *ifp;
struct ifreq ifr;
struct sockaddr_in *hif_addr;
//struct in_ifaddr * ia;
//register struct ifaddr *ifa;
//int error = 0;
ifp = padapter->ifp = if_alloc(IFT_OTHER);
if (ifp == NULL)
return (ENOSPC);
if_initname(ifp, name, HIF_MTU);
ifp->if_mtu = HIF_MTU;
ifp->if_softc = padapter;
ifp->if_flags = IFF_SIMPLEX | IFF_MULTICAST;
ifp->if_ioctl = hif_ioctl;
ifp->if_output = hif_output;
ifp->if_input = hif_input;
#if 0//__FreeBSD_version >= 800000
ifp->if_transmit = igb_mq_start;
ifp->if_qflush = igb_qflush;
#endif
ifp->if_snd.ifq_maxlen = ifqmaxlen;
/* Although the flag of hif is not set for CKSUM,
* we still set the cksum flag for incoming pacet.
* Please check hif_link_recv_fd () */
ifp->if_capabilities = ifp->if_capenable = 0; //IFCAP_HWCSUM;
ifp->if_hwassist = 0;//HIF_CSUM_FEATURES;
if_attach(ifp);
memset(&ifr, 0, sizeof(ifr));
bcopy(name, ifr.ifr_name, sizeof(ifr.ifr_name));
hif_addr = (struct sockaddr_in*)&(ifr.ifr_addr);
hif_addr->sin_len = sizeof(struct sockaddr_in);
hif_addr->sin_family = AF_INET;
hif_addr->sin_port = 0;
#ifdef UPTCP_CLIENT
/* client: 10.10.10.11*/
hif_addr->sin_addr.s_addr = htonl((u_int32_t)0x0a0a0a0b);
#else
/* server: 10.10.10.12*/
hif_addr->sin_addr.s_addr = htonl((u_int32_t)0x0a0a0a0c);
#endif
bzero(&(hif_addr->sin_zero),8);
in_control(NULL, SIOCSIFADDR, (caddr_t)&ifr, ifp, NULL);
return 0;
}
/*
* @hif_output()
*
* this function is called by ip_output to send data. hif_output() does not
* perform the send operation, instead it just puts the packet into one of
* adpater's tx_rings' ring_buf.
*/
int
hif_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
struct route *ro)
{
struct adapter *p_adapter = ifp->if_softc;
struct tx_ring *txr;
int i = 0, err = 0;
/* Which queue to use */
if ((m->m_flags & M_FLOWID) != 0)
i = m->m_pkthdr.flowid % p_adapter->num_tx_rings;
else i = 0;
txr = &p_adapter->tx_rings[i];
err = drbr_enqueue(ifp, txr->br, m);
if(txr->tx_sleep){
HIF_TX_LOCK(txr);
HIF_TX_WAKEUP(txr);
HIF_TX_UNLOCK(txr);
}
return (err);
}
void hif_input(struct ifnet *ifp, struct mbuf *m)
{
struct ether_header *eh;
u_short ether_type;
/*
* * If the CRC is still on the packet, triom it off. We do this once
* * and once only in case we are re-entered. Nothing else on the
* * Ethernet receive path expects to see the FCS.
* */
if (m->m_flags & M_HASFCS) {
m_adj(m, -ETHER_CRC_LEN);
m->m_flags &= ~M_HASFCS;
}
ifp->if_ibytes += m->m_pkthdr.len;
eh = mtod(m, struct ether_header *);
ether_type = ntohs(eh->ether_type);
/*
* * Reset layer specific mbuf flags to avoid confusing upper layers.
* * Strip off Ethernet header.
* */
m->m_flags &= ~M_VLANTAG;
m->m_flags &= ~(M_PROTOFLAGS);
m_adj(m, ETHER_HDR_LEN);
if(ether_type == ETHERTYPE_IP)
netisr_dispatch(NETISR_IP, m);
else m_freem(m);
}
static int
hif_allocate_rings(struct adapter *p_adapter)
{
struct tx_ring *txr;
struct rx_ring *rxr;
int error = 0;
int i;
/* First allocate the TX ring struct memory */
if (!(p_adapter->tx_rings =
(struct tx_ring *) bsd_malloc(sizeof(struct tx_ring) * p_adapter->num_tx_rings, M_DEVBUF, M_ZERO))) {
printf("hif_allocate_rings(): Unable to allocate TX ring memory\n");
error = ENOMEM;
goto fail;
}
txr = p_adapter->tx_rings;
/* Next allocate the RX */
if (!(p_adapter->rx_rings =
(struct rx_ring *) bsd_malloc(sizeof(struct rx_ring) * p_adapter->num_rx_rings, M_DEVBUF, M_ZERO))) {
printf("hif_allocate_rings(): Unable to allocate RX ring memory\n");
error = ENOMEM;
goto rx_fail;
}
rxr = p_adapter->rx_rings;
/*
* Now set up the TX queues, txconf is needed to handle the
* possibility that things fail midcourse and we need to
* undo memory gracefully
*/
for (i = 0; i < p_adapter->num_tx_rings; i++) {
/* Set up some basics */
txr = &p_adapter->tx_rings[i];
txr->adapter = p_adapter;
txr->me = i;
/* Initialize the TX lock */
snprintf(txr->mtx_name, sizeof(txr->mtx_name), "%s:tx(%d)",
p_adapter->ifp->if_dname, txr->me);
mtx_init(&txr->tx_mtx, txr->mtx_name, NULL, MTX_DEF);
txr->tx_cond = host_pthread_cond_init();
txr->tx_sleep = 0;
/* Allocate a buf ring */
txr->br = buf_ring_alloc(HIF_BR_SIZE, M_DEVBUF,
M_WAITOK, &txr->tx_mtx);
if(txr->br == NULL)
goto err_tx_buf;
}
/*
* Next the RX queues...
*/
for (i = 0; i < p_adapter->num_rx_rings; i++) {
rxr = &p_adapter->rx_rings[i];
rxr->adapter = p_adapter;
rxr->me = i;
/* Initialize the RX lock */
snprintf(rxr->mtx_name, sizeof(rxr->mtx_name), "%s:rx(%d)",
p_adapter->ifp->if_dname, rxr->me);
mtx_init(&rxr->rx_mtx, rxr->mtx_name, NULL, MTX_DEF);
rxr->rx_cond = host_pthread_cond_init();
rxr->rx_sleep = 0;
/* Allocate a ring buffer for the ring*/
rxr->br = buf_ring_alloc(HIF_BR_SIZE, M_DEVBUF,
M_WAITOK, &rxr->rx_mtx);
if(rxr->br == NULL)
goto err_rx_buf;
}
return (0);
err_rx_buf:
for (i = 0; i < p_adapter->num_tx_rings; i++) {
txr = &p_adapter->tx_rings[i];
bsd_free(txr->br, M_DEVBUF);
}
err_tx_buf:
bsd_free(p_adapter->rx_rings, M_DEVBUF);
rx_fail:
bsd_free(p_adapter->tx_rings, M_DEVBUF);
fail:
return (error);
}
static int hif_free_rings(struct adapter* p_adapter)
{
int i;
struct tx_ring *txr;
struct rx_ring *rxr;
if(p_adapter->tx_rings != NULL){
for (i = 0; i < p_adapter->num_tx_rings; i++) {
txr = &p_adapter->tx_rings[i];
host_pthread_cond_destroy(txr->tx_cond);
if(txr->br != NULL && txr->br->br_ring != NULL)
bsd_free(txr->br->br_ring, M_DEVBUF);
}
}
bsd_free(p_adapter->tx_rings, M_DEVBUF);
if(p_adapter->rx_rings != NULL){
for (i = 0; i < p_adapter->num_rx_rings; i++) {
rxr = &p_adapter->rx_rings[i];
host_pthread_cond_destroy(rxr->rx_cond);
if(rxr->br != NULL && rxr->br->br_ring != NULL)
bsd_free(rxr->br->br_ring, M_DEVBUF);
}
}
bsd_free(p_adapter->rx_rings, M_DEVBUF);
return 0;
}
static struct mbuf*
hif_get_buf(struct adapter *p_adapter)
{
struct mbuf *mp;
mp = m_getjcl(M_DONTWAIT, MT_DATA,
M_PKTHDR, p_adapter->rx_mbuf_sz);
if (mp == NULL)
return NULL;
mp->m_len = p_adapter->rx_mbuf_sz;
mp->m_flags |= M_PKTHDR;
mp->m_pkthdr.len = mp->m_len;
return mp;
}
static int
hif_create_thread(struct adapter* adap, int index, void *(*routine)(void*), int type)
{
struct thread_args *t_args;
int error;
t_args = (struct thread_args*) bsd_malloc(sizeof(struct thread_args), M_DEVBUF, M_ZERO);
if(!t_args){
printf("hif_alloc_ring_and_thread(): bsd_malloc() for thread_args failed\n");
return -1;
}
t_args->p_adapter = adap;
t_args->ring_index = index;
/* we create a new thread to handle the accept socket */
error = host_thread_create(routine, (void*)t_args, type);
if(error < 0){
printf("hif_alloc_ring_and_thread(): pthread_create() failed\n");
bsd_free(t_args, M_DEVBUF);
return -1;
}
return 0;
}
/*
* @hif_tx_link()
* This is a routine running within a thread. hif_tx_link() is responsible for the
* following operations:
* 1) bind the local socket to a listen port
* 2) check if the ring buffer is empty
* if so, sleep;
* or, send data out via raw socket
*
*/
static void* hif_tx_link(void * t_args)
{
struct thread_args *args = (struct thread_args*)t_args;
struct adapter *p_adapter = args->p_adapter;
struct ifnet *ifp = p_adapter->ifp;
int index = 0; //args->ring_index; only one tx_thread
struct tx_ring *txr = &p_adapter->tx_rings[index];
struct mbuf *next;
sigset_t signal_set;
/*
* Block all signals in this thread.
*/
sigfillset ( &signal_set );
pthread_sigmask (SIG_BLOCK, &signal_set, NULL );
bsd_free(args, M_DEVBUF);
#ifdef FOR_SIMULATION
int res;
/* Step.1 create send buffer */
if((hif_sendbuf = (char*)malloc(HIF_MTU)) == NULL){
printf("hif_tx(): malloc hif_sendbuf error\n");
return (void*)-1;
}
/* Step.2 create a socket */
#ifdef UPTCP_CLIENT
if((hif_link_send_fd = host_connect_link(HIF_RECV_PORT)) < 0){ //client
#else
if((hif_link_send_fd = host_connect_link(HIF_SEND_PORT)) < 0){ //server
#endif
printf("hif_tx(): create raw socket failed\n");
return (void*)-1;
}
#else //!FOR_SIMULATION
int tmpfd, shmid;
char shm_key_file[64];
struct shm_bufring *hif_tx_shmbuf_ring;
/*Step.1 amalloc share memory*/
#ifdef UPTCP_CLIENT
sprintf(shm_key_file, "/tmp/uptcp_hif_rx_buf.dat"); //client
#else
sprintf(shm_key_file, "/tmp/uptcp_hif_tx_buf.dat"); //server
#endif
if((tmpfd = open(shm_key_file, O_CREAT | O_RDWR, S_IRWXU)) < 0){
printf("Error: open keyFile error\n");
return (void*)-1;
}
close(tmpfd);
key_t shm_key = ftok(shm_key_file, 1);
/* Step.1.5 check if already existed? */
if((shmid = shmget(shm_key, sizeof(struct shm_bufring), IPC_CREAT | S_IRUSR | S_IWUSR)) < 0){
printf("Error: shmget error\n");
return (void*)-1;
}
if((hif_tx_shmbuf_ring = (struct shm_bufring *) shmat(shmid, NULL, 0)) == (void*)-1){
printf("Error: shmat error\n");
return (void*)-1;
}
/* Step.2 initial shared buffer */
#ifndef UPTCP_CLIENT
hif_tx_shmbuf_ring->read_off = 0;
hif_tx_shmbuf_ring->write_off = 0;
#endif
#endif //!FOR_SIMULATION
/* Step.3 handle data of tx_ring's ring_buf*/
while (1) {
next = drbr_dequeue(ifp, txr->br);
if (next == NULL){
host_thread_enter_wait_region();
HIF_TX_LOCK(txr);
txr->tx_sleep = 1;
HIF_TX_SLEEP(txr);
txr->tx_sleep = 0;
HIF_TX_UNLOCK(txr);
host_thread_exit_wait_region();
continue;
}
#ifdef PERFORMANCE_TUNING
if(0){
struct timeval cur_time;
gettimeofday(&(cur_time), NULL);
unsigned long long _interval = (cur_time.tv_sec * 1000000 + cur_time.tv_usec) - (global_roi_start_tv.tv_sec * 1000000 + global_roi_start_tv.tv_usec);
printf("%llu: %-10s p_head=%u, p_tail=%u, c_head=%d, c_tail=%d\n",
_interval,
"txl_txr",
txr->br->br_prod_head,
txr->br->br_prod_tail,
txr->br->br_cons_head,
txr->br->br_cons_tail);
}
#endif
#ifdef FOR_SIMULATION
if(next->m_next == NULL){
/* send out the packet*/
if ((res = host_link_send(hif_link_send_fd, next->m_data, next->m_pkthdr.len)) < 0) {
if (next != NULL)
res = drbr_enqueue(ifp, txr->br, next);
}else {
drbr_stats_update(ifp, next->m_pkthdr.len, next->m_flags);
m_freem(next);
}
} else {
sendbuf_ptr = hif_sendbuf;
struct mbuf *m;
for(m = next; m != NULL; m = m->m_next){
bcopy(mtod(m, void *), (void*)sendbuf_ptr, m->m_len);
sendbuf_ptr += m->m_len;
}
/* send out the packet*/
if ((res = host_link_send(hif_link_send_fd, hif_sendbuf, next->m_pkthdr.len)) < 0) {
if (next != NULL)
res = drbr_enqueue(ifp, txr->br, next);
}else {
drbr_stats_update(ifp, next->m_pkthdr.len, next->m_flags);
m_freem(next);
}
}
#else //!FOR_SIMULATION
shm_bufring_enqueue(hif_tx_shmbuf_ring, next);
m_freem(next);
#endif //!FOR_SIMULATION
}
#ifdef FOR_SIMULATION
free(hif_sendbuf);
#endif
return NULL;
}
/*
* @hif_rx()
* This is a routine running within a thread. hif_rx() is responsible for the
* following operations:
* 1) check if the ring buffer is empty
* if so, sleep;
* or, call if_input() to handle data, and eventually send the data
* to sockbuf
*/
static void* hif_rx(void * t_args)
{
struct thread_args *args = (struct thread_args*)t_args;
struct adapter *p_adapter = args->p_adapter;
int index = args->ring_index;
struct ifnet *ifp = p_adapter->ifp;
struct rx_ring *rxr = &p_adapter->rx_rings[index];
struct mbuf* next;
sigset_t signal_set;
#ifdef PERFORMANCE_TUNING
int just_sleeped = 0;
#endif
/*
* Block all signals in this thread.
*/
sigfillset ( &signal_set );
pthread_sigmask (SIG_BLOCK, &signal_set, NULL );
bsd_free(args, M_DEVBUF);
while(1){
next = drbr_dequeue(ifp, rxr->br);
if (next == NULL){
#ifdef PERFORMANCE_TUNING
if(1){
struct timeval cur_time;
gettimeofday(&(cur_time), NULL);
unsigned long long _interval = (cur_time.tv_sec * 1000000 + cur_time.tv_usec) - (global_roi_start_tv.tv_sec * 1000000 + global_roi_start_tv.tv_usec);
printf("%llu: %-10s RXR-%d (p_head=%-4u \tp_tail=%-4u \tc_head=%-4d \tc_tail=%d)\n",
_interval,
"rx_sleep",
rxr->me,
rxr->br->br_prod_head,
rxr->br->br_prod_tail,
rxr->br->br_cons_head,
rxr->br->br_cons_tail);
just_sleeped = 1;
}
#endif
host_thread_enter_wait_region();
HIF_RX_LOCK(rxr);
rxr->rx_sleep = 1;
HIF_RX_SLEEP(rxr);
rxr->rx_sleep = 0;
HIF_RX_UNLOCK(rxr);
host_thread_exit_wait_region();
continue;
}
#ifdef PERFORMANCE_TUNING
if(1){
if(just_sleeped == 1){
struct timeval cur_time;
gettimeofday(&(cur_time), NULL);
unsigned long long _interval = (cur_time.tv_sec * 1000000 + cur_time.tv_usec) - (global_roi_start_tv.tv_sec * 1000000 + global_roi_start_tv.tv_usec);
#define IP_HLEN_OFFSET 0
#define IP_TYPE_OFFSET 9
#define TCP_SEQ_OFFSET 4
#define TCP_ACK_OFFSET 8
char *buf_ptr = mtod(next, char *);
int iphlen = ((*(unsigned char*)(buf_ptr + IP_HLEN_OFFSET)) & 0xF) << 2;
unsigned int tcpseq = ntohl(*(unsigned int*)(buf_ptr + TCP_SEQ_OFFSET + iphlen));
unsigned int tcpack = ntohl(*(unsigned int*)(buf_ptr + TCP_ACK_OFFSET + iphlen));
printf("%llu: %-10s RXR-%d (p_head=%-4u \tp_tail=%-4u \tc_head=%-4d \tc_tail=%d) \tTCP (seq=%-8u ack=%u)\n",
_interval,
"rx_wakeup",
rxr->me,
rxr->br->br_prod_head,
rxr->br->br_prod_tail,
rxr->br->br_cons_head,
rxr->br->br_cons_tail,
tcpseq,
tcpack);
just_sleeped = 0;
}
}
#endif
#ifdef PERFORMANCE_TUNING
//host_thread_enter_performance_region();
#endif
netisr_dispatch(NETISR_IP, next);
#ifdef PERFORMANCE_TUNING
//host_thread_exit_performance_region();
#endif
drbr_stats_update(ifp, next->m_pkthdr.len, next->m_flags);
}
return NULL;
}
/*
* @hif_rx_link()
* This is a routine running within a thread. It is responsible for capture
* all incoming packet received by host NIC and put the data into
* corresponding rx_rings.
*
*/
static void* hif_rx_link(void * t_args)
{
struct thread_args *args = (struct thread_args*)t_args;
struct adapter *p_adapter = args->p_adapter;
struct ifnet *ifp = p_adapter->ifp;
struct rx_ring *rxr;
struct mbuf *mp;
int i = 0;
int error;
unsigned long long total_packets = 0;
sigset_t signal_set;
/*
* Block all signals in this thread.
*/
sigfillset ( &signal_set );
pthread_sigmask (SIG_BLOCK, &signal_set, NULL );
bsd_free(args, M_DEVBUF);
#ifdef FOR_SIMULATION
/*
* Create hif_link_recv_fd
*/
/* Step.0 create a socket */
#ifdef UPTCP_CLIENT
if((hif_link_recv_fd = host_setup_link(HIF_SEND_PORT)) < 0){
#else
if((hif_link_recv_fd = host_setup_link(HIF_RECV_PORT)) < 0){
#endif
printf("hif_tx(): create raw socket failed\n");
return (void*)-1;
}
#else //!FOR_SIMULATION
int tmpfd, shmid;
char shm_key_file[64];
struct shm_bufring *hif_rx_shmbuf_ring;
/* malloc share memory*/
#ifdef UPTCP_CLIENT
sprintf(shm_key_file, "/tmp/uptcp_hif_tx_buf.dat"); //client
#else
sprintf(shm_key_file, "/tmp/uptcp_hif_rx_buf.dat"); //server
#endif
if((tmpfd = open(shm_key_file, O_CREAT | O_RDWR, S_IRWXU)) < 0){
printf("Error: open keyFile error\n");
return (void*)-1;
}
close(tmpfd);
key_t shm_key = ftok(shm_key_file, 1);
if((shmid = shmget(shm_key, sizeof(struct shm_bufring), IPC_CREAT | S_IRUSR | S_IWUSR)) < 0){
printf("Error: shmget error\n");
return (void*)-1;
}
if((hif_rx_shmbuf_ring = (struct shm_bufring *) shmat(shmid, NULL, 0)) == (void*)-1){
printf("Error: shmat error\n");
return (void*)-1;
}
#ifndef UPTCP_CLIENT
hif_rx_shmbuf_ring->read_off = 0;
hif_rx_shmbuf_ring->write_off = 0;
#endif
#endif //!FOR_SIMULATION
/* Step.2 recv */
while(1) {
/* get a mbuf */
if ((mp = hif_get_buf(p_adapter)) == NULL) {
ifp->if_iqdrops++;
continue;
}
#ifdef FOR_SIMULATION
if((error = host_link_recv(hif_link_recv_fd, mp->m_data, mp->m_len)) > 0){
#else
if((error = shm_bufring_dequeue(hif_rx_shmbuf_ring, mp->m_data, mp->m_len)) > 0){
#ifdef PERFORMANCE_TUNING
if(0){
struct timeval cur_time;
gettimeofday(&(cur_time), NULL);
unsigned long long _interval = (cur_time.tv_sec * 1000000 + cur_time.tv_usec) - (global_roi_start_tv.tv_sec * 1000000 + global_roi_start_tv.tv_usec);
printf("%llu: %-10s read=%-5d : write=%d\n",
_interval,
"rxl_shm",
hif_rx_shmbuf_ring->read_off,
hif_rx_shmbuf_ring->write_off);
}
#endif
#endif //FOR_SIMULATION
// FIXME: we need a way to classify incoming packets,
// for example, hashing based on port.
//
// We just use Round-Robin policy
//
if ((mp->m_flags & M_FLOWID) != 0)
i = mp->m_pkthdr.flowid % p_adapter->num_rx_rings;
else i = total_packets % mp_ncpus;
total_packets ++;
mp->m_pkthdr.rcvif = ifp;
/* Although the flag of hif is not set for CKSUM,
* we still set the cksum flag for incoming pacet.
* Please check hif_link_recv_fd () */
//if (ifp->if_capenable & IFCAP_RXCSUM) {
mp->m_pkthdr.csum_data = 0xffff;
mp->m_pkthdr.csum_flags = HIF_CSUM_SET;
//}
mp->m_pkthdr.csum_flags &= ~HIF_CSUM_FEATURES;
rxr = &p_adapter->rx_rings[i];
error = drbr_enqueue(ifp, rxr->br, mp);
#ifdef PERFORMANCE_TUNING
if(0){
struct timeval cur_time;
gettimeofday(&(cur_time), NULL);
unsigned long long _interval = (cur_time.tv_sec * 1000000 + cur_time.tv_usec) - (global_roi_start_tv.tv_sec * 1000000 + global_roi_start_tv.tv_usec);
printf("%llu: %-10s p_head=%u, p_tail=%u, c_head=%d, c_tail=%d\n",
_interval,
"rxl_rxr",
rxr->br->br_prod_head,
rxr->br->br_prod_tail,
rxr->br->br_cons_head,
rxr->br->br_cons_tail);
}
#endif
if(rxr->rx_sleep){
HIF_RX_LOCK(rxr);
HIF_RX_WAKEUP(rxr);
HIF_RX_UNLOCK(rxr);
}
}
} //while (1)
return NULL;
}
/*
* Process an ioctl request.
*/
/* ARGSUSED */
int
hif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
return 0;
}