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