1*522d5c66SAsim Jamshed /* for io_module_func def'ns */ 2*522d5c66SAsim Jamshed #include "io_module.h" 3*522d5c66SAsim Jamshed /* for mtcp related def'ns */ 4*522d5c66SAsim Jamshed #include "mtcp.h" 5*522d5c66SAsim Jamshed /* for errno */ 6*522d5c66SAsim Jamshed #include <errno.h> 7*522d5c66SAsim Jamshed /* for logging */ 8*522d5c66SAsim Jamshed #include "debug.h" 9*522d5c66SAsim Jamshed /* for num_devices_* */ 10*522d5c66SAsim Jamshed #include "config.h" 11*522d5c66SAsim Jamshed /* for netmap definitions */ 12*522d5c66SAsim Jamshed #define NETMAP_WITH_LIBS 13*522d5c66SAsim Jamshed #include "netmap_user.h" 14*522d5c66SAsim Jamshed /* for poll */ 15*522d5c66SAsim Jamshed #include <sys/poll.h> 16*522d5c66SAsim Jamshed /* for NBBY */ 17*522d5c66SAsim Jamshed #include <sys/param.h> 18*522d5c66SAsim Jamshed /*----------------------------------------------------------------------------*/ 19*522d5c66SAsim Jamshed #define MAX_PKT_BURST 64 20*522d5c66SAsim Jamshed #define ETHERNET_FRAME_SIZE 1514 21*522d5c66SAsim Jamshed #define MAX_IFNAMELEN (IF_NAMESIZE + 10) 22*522d5c66SAsim Jamshed #define EXTRA_BUFS 512 23*522d5c66SAsim Jamshed #define IDLE_POLL_WAIT 1 /* msecs */ 24*522d5c66SAsim Jamshed #define IDLE_POLL_COUNT 10 25*522d5c66SAsim Jamshed //#define CONST_POLLING 1 26*522d5c66SAsim Jamshed /*----------------------------------------------------------------------------*/ 27*522d5c66SAsim Jamshed 28*522d5c66SAsim Jamshed struct netmap_private_context { 29*522d5c66SAsim Jamshed struct nm_desc *local_nmd[MAX_DEVICES]; 30*522d5c66SAsim Jamshed unsigned char snd_pktbuf[MAX_DEVICES][ETHERNET_FRAME_SIZE]; 31*522d5c66SAsim Jamshed unsigned char *rcv_pktbuf[MAX_PKT_BURST]; 32*522d5c66SAsim Jamshed uint16_t rcv_pkt_len[MAX_PKT_BURST]; 33*522d5c66SAsim Jamshed uint16_t snd_pkt_size[MAX_DEVICES]; 34*522d5c66SAsim Jamshed uint8_t dev_poll_flag[MAX_DEVICES]; 35*522d5c66SAsim Jamshed uint8_t idle_poll_count; 36*522d5c66SAsim Jamshed } __attribute__((aligned(__WORDSIZE))); 37*522d5c66SAsim Jamshed /*----------------------------------------------------------------------------*/ 38*522d5c66SAsim Jamshed void 39*522d5c66SAsim Jamshed netmap_init_handle(struct mtcp_thread_context *ctxt) 40*522d5c66SAsim Jamshed { 41*522d5c66SAsim Jamshed struct netmap_private_context *npc; 42*522d5c66SAsim Jamshed char ifname[MAX_IFNAMELEN]; 43*522d5c66SAsim Jamshed char nifname[MAX_IFNAMELEN]; 44*522d5c66SAsim Jamshed struct netdev_entry **ent; 45*522d5c66SAsim Jamshed int j; 46*522d5c66SAsim Jamshed 47*522d5c66SAsim Jamshed ent = g_config.mos->netdev_table->ent; 48*522d5c66SAsim Jamshed /* create and initialize private I/O module context */ 49*522d5c66SAsim Jamshed ctxt->io_private_context = calloc(1, sizeof(struct netmap_private_context)); 50*522d5c66SAsim Jamshed if (ctxt->io_private_context == NULL) { 51*522d5c66SAsim Jamshed TRACE_ERROR("Failed to initialize ctxt->io_private_context: " 52*522d5c66SAsim Jamshed "Can't allocate memory\n"); 53*522d5c66SAsim Jamshed exit(EXIT_FAILURE); 54*522d5c66SAsim Jamshed } 55*522d5c66SAsim Jamshed 56*522d5c66SAsim Jamshed npc = (struct netmap_private_context *)ctxt->io_private_context; 57*522d5c66SAsim Jamshed 58*522d5c66SAsim Jamshed /* initialize per-thread netmap interfaces */ 59*522d5c66SAsim Jamshed for (j = 0; j < g_config.mos->netdev_table->num; j++) { 60*522d5c66SAsim Jamshed #if 0 61*522d5c66SAsim Jamshed if (if_indextoname(devices_attached[j], ifname) == NULL) { 62*522d5c66SAsim Jamshed TRACE_ERROR("Failed to initialize interface %s with ifidx: %d - " 63*522d5c66SAsim Jamshed "error string: %s\n", 64*522d5c66SAsim Jamshed ifname, devices_attached[j], strerror(errno)); 65*522d5c66SAsim Jamshed exit(EXIT_FAILURE); 66*522d5c66SAsim Jamshed } 67*522d5c66SAsim Jamshed #else 68*522d5c66SAsim Jamshed strcpy(ifname, ent[j]->dev_name); 69*522d5c66SAsim Jamshed #endif 70*522d5c66SAsim Jamshed if (unlikely(g_config.mos->num_cores == 1)) 71*522d5c66SAsim Jamshed sprintf(nifname, "netmap:%s", ifname); 72*522d5c66SAsim Jamshed else 73*522d5c66SAsim Jamshed sprintf(nifname, "netmap:%s-%d", ifname, ctxt->cpu); 74*522d5c66SAsim Jamshed 75*522d5c66SAsim Jamshed TRACE_INFO("Opening %s with j: %d (cpu: %d)\n", nifname, j, ctxt->cpu); 76*522d5c66SAsim Jamshed 77*522d5c66SAsim Jamshed struct nmreq base_nmd; 78*522d5c66SAsim Jamshed memset(&base_nmd, 0, sizeof(base_nmd)); 79*522d5c66SAsim Jamshed base_nmd.nr_arg3 = EXTRA_BUFS; 80*522d5c66SAsim Jamshed 81*522d5c66SAsim Jamshed npc->local_nmd[j] = nm_open(nifname, &base_nmd, 0, NULL); 82*522d5c66SAsim Jamshed if (npc->local_nmd[j] == NULL) { 83*522d5c66SAsim Jamshed TRACE_ERROR("Unable to open %s: %s\n", 84*522d5c66SAsim Jamshed nifname, strerror(errno)); 85*522d5c66SAsim Jamshed exit(EXIT_FAILURE); 86*522d5c66SAsim Jamshed } 87*522d5c66SAsim Jamshed } 88*522d5c66SAsim Jamshed } 89*522d5c66SAsim Jamshed /*----------------------------------------------------------------------------*/ 90*522d5c66SAsim Jamshed int 91*522d5c66SAsim Jamshed netmap_link_devices(struct mtcp_thread_context *ctxt) 92*522d5c66SAsim Jamshed { 93*522d5c66SAsim Jamshed /* linking takes place during mtcp_init() */ 94*522d5c66SAsim Jamshed 95*522d5c66SAsim Jamshed return 0; 96*522d5c66SAsim Jamshed } 97*522d5c66SAsim Jamshed /*----------------------------------------------------------------------------*/ 98*522d5c66SAsim Jamshed void 99*522d5c66SAsim Jamshed netmap_release_pkt(struct mtcp_thread_context *ctxt, int ifidx, unsigned char *pkt_data, int len) 100*522d5c66SAsim Jamshed { 101*522d5c66SAsim Jamshed /* 102*522d5c66SAsim Jamshed * do nothing over here - memory reclamation 103*522d5c66SAsim Jamshed * will take place in dpdk_recv_pkts 104*522d5c66SAsim Jamshed */ 105*522d5c66SAsim Jamshed } 106*522d5c66SAsim Jamshed /*----------------------------------------------------------------------------*/ 107*522d5c66SAsim Jamshed int 108*522d5c66SAsim Jamshed netmap_send_pkts(struct mtcp_thread_context *ctxt, int nif) 109*522d5c66SAsim Jamshed { 110*522d5c66SAsim Jamshed int pkt_size, idx; 111*522d5c66SAsim Jamshed struct netmap_private_context *npc; 112*522d5c66SAsim Jamshed mtcp_manager_t mtcp; 113*522d5c66SAsim Jamshed 114*522d5c66SAsim Jamshed npc = (struct netmap_private_context *)ctxt->io_private_context; 115*522d5c66SAsim Jamshed idx = nif; 116*522d5c66SAsim Jamshed pkt_size = npc->snd_pkt_size[idx]; 117*522d5c66SAsim Jamshed mtcp = ctxt->mtcp_manager; 118*522d5c66SAsim Jamshed 119*522d5c66SAsim Jamshed /* assert-type statement */ 120*522d5c66SAsim Jamshed if (pkt_size == 0) return 0; 121*522d5c66SAsim Jamshed 122*522d5c66SAsim Jamshed #ifdef NETSTAT 123*522d5c66SAsim Jamshed mtcp->nstat.tx_packets[nif]++; 124*522d5c66SAsim Jamshed mtcp->nstat.tx_bytes[nif] += pkt_size + 24; 125*522d5c66SAsim Jamshed #endif 126*522d5c66SAsim Jamshed 127*522d5c66SAsim Jamshed tx_again: 128*522d5c66SAsim Jamshed if (nm_inject(npc->local_nmd[idx], npc->snd_pktbuf[idx], pkt_size) == 0) { 129*522d5c66SAsim Jamshed TRACE_DBG("Failed to send pkt of size %d on interface: %d\n", 130*522d5c66SAsim Jamshed pkt_size, idx); 131*522d5c66SAsim Jamshed 132*522d5c66SAsim Jamshed ioctl(npc->local_nmd[idx]->fd, NIOCTXSYNC, NULL); 133*522d5c66SAsim Jamshed goto tx_again; 134*522d5c66SAsim Jamshed } 135*522d5c66SAsim Jamshed 136*522d5c66SAsim Jamshed #ifdef NETSTAT 137*522d5c66SAsim Jamshed // mtcp->nstat.rx_errors[idx]++; 138*522d5c66SAsim Jamshed #endif 139*522d5c66SAsim Jamshed npc->snd_pkt_size[idx] = 0; 140*522d5c66SAsim Jamshed 141*522d5c66SAsim Jamshed return 1; 142*522d5c66SAsim Jamshed } 143*522d5c66SAsim Jamshed /*----------------------------------------------------------------------------*/ 144*522d5c66SAsim Jamshed uint8_t * 145*522d5c66SAsim Jamshed netmap_get_wptr(struct mtcp_thread_context *ctxt, int nif, uint16_t pktsize) 146*522d5c66SAsim Jamshed { 147*522d5c66SAsim Jamshed struct netmap_private_context *npc; 148*522d5c66SAsim Jamshed int idx = nif; 149*522d5c66SAsim Jamshed 150*522d5c66SAsim Jamshed npc = (struct netmap_private_context *)ctxt->io_private_context; 151*522d5c66SAsim Jamshed if (npc->snd_pkt_size[idx] != 0) 152*522d5c66SAsim Jamshed netmap_send_pkts(ctxt, nif); 153*522d5c66SAsim Jamshed 154*522d5c66SAsim Jamshed npc->snd_pkt_size[idx] = pktsize; 155*522d5c66SAsim Jamshed 156*522d5c66SAsim Jamshed return (uint8_t *)npc->snd_pktbuf[idx]; 157*522d5c66SAsim Jamshed } 158*522d5c66SAsim Jamshed /*----------------------------------------------------------------------------*/ 159*522d5c66SAsim Jamshed int32_t 160*522d5c66SAsim Jamshed netmap_recv_pkts(struct mtcp_thread_context *ctxt, int ifidx) 161*522d5c66SAsim Jamshed { 162*522d5c66SAsim Jamshed struct netmap_private_context *npc; 163*522d5c66SAsim Jamshed struct nm_desc *d; 164*522d5c66SAsim Jamshed npc = (struct netmap_private_context *)ctxt->io_private_context; 165*522d5c66SAsim Jamshed d = npc->local_nmd[ifidx]; 166*522d5c66SAsim Jamshed 167*522d5c66SAsim Jamshed int p = 0; 168*522d5c66SAsim Jamshed int c, got = 0, ri = d->cur_rx_ring; 169*522d5c66SAsim Jamshed int n = d->last_rx_ring - d->first_rx_ring + 1; 170*522d5c66SAsim Jamshed int cnt = MAX_PKT_BURST; 171*522d5c66SAsim Jamshed 172*522d5c66SAsim Jamshed 173*522d5c66SAsim Jamshed 174*522d5c66SAsim Jamshed for (c = 0; c < n && cnt != got && npc->dev_poll_flag[ifidx]; c++) { 175*522d5c66SAsim Jamshed /* compute current ring to use */ 176*522d5c66SAsim Jamshed struct netmap_ring *ring; 177*522d5c66SAsim Jamshed 178*522d5c66SAsim Jamshed ri = d->cur_rx_ring + c; 179*522d5c66SAsim Jamshed if (ri > d->last_rx_ring) 180*522d5c66SAsim Jamshed ri = d->first_rx_ring; 181*522d5c66SAsim Jamshed ring = NETMAP_RXRING(d->nifp, ri); 182*522d5c66SAsim Jamshed for ( ; !nm_ring_empty(ring) && cnt != got; got++) { 183*522d5c66SAsim Jamshed u_int i = ring->cur; 184*522d5c66SAsim Jamshed u_int idx = ring->slot[i].buf_idx; 185*522d5c66SAsim Jamshed npc->rcv_pktbuf[p] = (u_char *)NETMAP_BUF(ring, idx); 186*522d5c66SAsim Jamshed npc->rcv_pkt_len[p] = ring->slot[i].len; 187*522d5c66SAsim Jamshed p++; 188*522d5c66SAsim Jamshed ring->head = ring->cur = nm_ring_next(ring, i); 189*522d5c66SAsim Jamshed } 190*522d5c66SAsim Jamshed } 191*522d5c66SAsim Jamshed d->cur_rx_ring = ri; 192*522d5c66SAsim Jamshed 193*522d5c66SAsim Jamshed npc->dev_poll_flag[ifidx] = 0; 194*522d5c66SAsim Jamshed 195*522d5c66SAsim Jamshed return p; 196*522d5c66SAsim Jamshed } 197*522d5c66SAsim Jamshed /*----------------------------------------------------------------------------*/ 198*522d5c66SAsim Jamshed uint8_t * 199*522d5c66SAsim Jamshed netmap_get_rptr(struct mtcp_thread_context *ctxt, int ifidx, int index, uint16_t *len) 200*522d5c66SAsim Jamshed { 201*522d5c66SAsim Jamshed struct netmap_private_context *npc; 202*522d5c66SAsim Jamshed npc = (struct netmap_private_context *)ctxt->io_private_context; 203*522d5c66SAsim Jamshed 204*522d5c66SAsim Jamshed *len = npc->rcv_pkt_len[index]; 205*522d5c66SAsim Jamshed return (unsigned char *)npc->rcv_pktbuf[index]; 206*522d5c66SAsim Jamshed } 207*522d5c66SAsim Jamshed /*----------------------------------------------------------------------------*/ 208*522d5c66SAsim Jamshed int32_t 209*522d5c66SAsim Jamshed netmap_select(struct mtcp_thread_context *ctxt) 210*522d5c66SAsim Jamshed { 211*522d5c66SAsim Jamshed int i, rc; 212*522d5c66SAsim Jamshed struct pollfd pfd[MAX_DEVICES]; 213*522d5c66SAsim Jamshed struct netmap_private_context *npc = 214*522d5c66SAsim Jamshed (struct netmap_private_context *)ctxt->io_private_context; 215*522d5c66SAsim Jamshed 216*522d5c66SAsim Jamshed /* see if num_devices have been registered */ 217*522d5c66SAsim Jamshed if (npc->local_nmd[0] == NULL) 218*522d5c66SAsim Jamshed return -1; 219*522d5c66SAsim Jamshed 220*522d5c66SAsim Jamshed for (i = 0; i < g_config.mos->netdev_table->num; i++) { 221*522d5c66SAsim Jamshed pfd[i].fd = npc->local_nmd[i]->fd; 222*522d5c66SAsim Jamshed pfd[i].events = POLLIN; 223*522d5c66SAsim Jamshed } 224*522d5c66SAsim Jamshed 225*522d5c66SAsim Jamshed #ifndef CONST_POLLING 226*522d5c66SAsim Jamshed if (npc->idle_poll_count >= IDLE_POLL_COUNT) { 227*522d5c66SAsim Jamshed rc = poll(pfd, g_config.mos->netdev_table->num, IDLE_POLL_WAIT); 228*522d5c66SAsim Jamshed } else 229*522d5c66SAsim Jamshed #endif 230*522d5c66SAsim Jamshed { 231*522d5c66SAsim Jamshed rc = poll(pfd, g_config.mos->netdev_table->num, 0); 232*522d5c66SAsim Jamshed } 233*522d5c66SAsim Jamshed 234*522d5c66SAsim Jamshed npc->idle_poll_count = (rc == 0) ? (npc->idle_poll_count + 1) : 0; 235*522d5c66SAsim Jamshed 236*522d5c66SAsim Jamshed for (i = 0; rc > 0 && i < g_config.mos->netdev_table->num; i++) 237*522d5c66SAsim Jamshed if (!(pfd[i].revents & (POLLERR))) 238*522d5c66SAsim Jamshed npc->dev_poll_flag[i] = 1; 239*522d5c66SAsim Jamshed return 0; 240*522d5c66SAsim Jamshed } 241*522d5c66SAsim Jamshed /*----------------------------------------------------------------------------*/ 242*522d5c66SAsim Jamshed int 243*522d5c66SAsim Jamshed netmap_get_nif(struct ifreq *ifr) 244*522d5c66SAsim Jamshed { 245*522d5c66SAsim Jamshed int i; 246*522d5c66SAsim Jamshed struct netdev_entry **ent = g_config.mos->netdev_table->ent; 247*522d5c66SAsim Jamshed 248*522d5c66SAsim Jamshed for (i = 0; i < g_config.mos->netdev_table->num; i++) 249*522d5c66SAsim Jamshed if (!strcmp(ifr->ifr_name, ent[i]->dev_name)) 250*522d5c66SAsim Jamshed return i; 251*522d5c66SAsim Jamshed 252*522d5c66SAsim Jamshed return -1; 253*522d5c66SAsim Jamshed } 254*522d5c66SAsim Jamshed /*----------------------------------------------------------------------------*/ 255*522d5c66SAsim Jamshed int32_t 256*522d5c66SAsim Jamshed netmap_dev_ioctl(struct mtcp_thread_context *ctx, int nif, int cmd, void *argp) 257*522d5c66SAsim Jamshed { 258*522d5c66SAsim Jamshed /* unimplemented */ 259*522d5c66SAsim Jamshed return -1; 260*522d5c66SAsim Jamshed } 261*522d5c66SAsim Jamshed /*----------------------------------------------------------------------------*/ 262*522d5c66SAsim Jamshed void 263*522d5c66SAsim Jamshed netmap_destroy_handle(struct mtcp_thread_context *ctxt) 264*522d5c66SAsim Jamshed { 265*522d5c66SAsim Jamshed int i; 266*522d5c66SAsim Jamshed struct netmap_private_context *npc; 267*522d5c66SAsim Jamshed 268*522d5c66SAsim Jamshed npc = (struct netmap_private_context *)ctxt->io_private_context; 269*522d5c66SAsim Jamshed 270*522d5c66SAsim Jamshed for (i = 0; i < g_config.mos->netdev_table->num; i++) 271*522d5c66SAsim Jamshed close(npc->local_nmd[i]->fd); 272*522d5c66SAsim Jamshed } 273*522d5c66SAsim Jamshed /*----------------------------------------------------------------------------*/ 274*522d5c66SAsim Jamshed void 275*522d5c66SAsim Jamshed netmap_load_module_upper_half(void) 276*522d5c66SAsim Jamshed { 277*522d5c66SAsim Jamshed int i; 278*522d5c66SAsim Jamshed int num_dev; 279*522d5c66SAsim Jamshed uint64_t cpu_mask; 280*522d5c66SAsim Jamshed int queue_range; 281*522d5c66SAsim Jamshed 282*522d5c66SAsim Jamshed num_dev = g_config.mos->netdev_table->num; 283*522d5c66SAsim Jamshed 284*522d5c66SAsim Jamshed for (i = 0; i < num_dev; i++) { 285*522d5c66SAsim Jamshed cpu_mask = g_config.mos->netdev_table->ent[i]->cpu_mask; 286*522d5c66SAsim Jamshed queue_range = sizeof(cpu_mask) * NBBY - __builtin_clzll(cpu_mask); 287*522d5c66SAsim Jamshed num_queues = (num_queues < queue_range) ? 288*522d5c66SAsim Jamshed queue_range : num_queues; 289*522d5c66SAsim Jamshed } 290*522d5c66SAsim Jamshed } 291*522d5c66SAsim Jamshed /*----------------------------------------------------------------------------*/ 292*522d5c66SAsim Jamshed io_module_func netmap_module_func = { 293*522d5c66SAsim Jamshed .load_module_upper_half = netmap_load_module_upper_half, 294*522d5c66SAsim Jamshed .load_module_lower_half = NULL, 295*522d5c66SAsim Jamshed .init_handle = netmap_init_handle, 296*522d5c66SAsim Jamshed .link_devices = netmap_link_devices, 297*522d5c66SAsim Jamshed .release_pkt = netmap_release_pkt, 298*522d5c66SAsim Jamshed .send_pkts = netmap_send_pkts, 299*522d5c66SAsim Jamshed .get_wptr = netmap_get_wptr, 300*522d5c66SAsim Jamshed .set_wptr = NULL, 301*522d5c66SAsim Jamshed .recv_pkts = netmap_recv_pkts, 302*522d5c66SAsim Jamshed .get_rptr = netmap_get_rptr, 303*522d5c66SAsim Jamshed .get_nif = netmap_get_nif, 304*522d5c66SAsim Jamshed .select = netmap_select, 305*522d5c66SAsim Jamshed .destroy_handle = netmap_destroy_handle, 306*522d5c66SAsim Jamshed .dev_ioctl = netmap_dev_ioctl, 307*522d5c66SAsim Jamshed }; 308*522d5c66SAsim Jamshed /*----------------------------------------------------------------------------*/ 309*522d5c66SAsim Jamshed 310