1/** 2 * \file 3 * \brief LWIP test/demo code 4 */ 5 6/* 7 * Copyright (c) 2013, University of Washington. 8 * All rights reserved. 9 * 10 * This file is distributed under the terms in the attached LICENSE file. 11 * If you do not find this file, copies can be found by writing to: 12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#include <stdio.h> 16#include <assert.h> 17#include <barrelfish/barrelfish.h> 18#include <netif/e1000.h> 19#include <netif/etharp.h> 20#include <lwip/ip.h> 21#include <lwip/udp.h> 22 23static ether_terminate_queue ether_terminate_queue_ptr = NULL; 24static ether_get_mac_address_t ether_get_mac_address_ptr = NULL; 25static ether_transmit_pbuf_list_t ether_transmit_pbuf_list_ptr = NULL; 26static ether_get_tx_free_slots tx_free_slots_fn_ptr = NULL; 27static ether_handle_free_TX_slot handle_free_tx_slot_fn_ptr = NULL; 28static ether_rx_register_buffer rx_register_buffer_fn_ptr = NULL; 29static ether_rx_get_free_slots rx_get_free_slots_fn_ptr = NULL; 30 31uint64_t interrupt_counter = 0; 32uint64_t total_rx_p_count = 0; 33uint64_t total_rx_datasize = 0; 34struct client_closure *g_cl = NULL; 35 36#define MAX_PACKETS 256 37#define PACKET_SIZE 2048 38 39struct packet { 40 uint8_t *payload; 41 lpaddr_t pa; 42 size_t len; 43}; 44 45static struct packet rx_packets[MAX_PACKETS], tx_packets[MAX_PACKETS]; 46 47void ethernetif_backend_init(char *service_name, uint64_t queueid, 48 ether_get_mac_address_t get_mac_ptr, 49 ether_terminate_queue terminate_queue_ptr, 50 ether_transmit_pbuf_list_t transmit_ptr, 51 ether_get_tx_free_slots tx_free_slots_ptr, 52 ether_handle_free_TX_slot handle_free_tx_slot_ptr, 53 size_t rx_bufsz, 54 ether_rx_register_buffer rx_register_buffer_ptr, 55 ether_rx_get_free_slots rx_get_free_slots_ptr) 56{ 57 ether_terminate_queue_ptr = terminate_queue_ptr; 58 ether_get_mac_address_ptr = get_mac_ptr; 59 ether_transmit_pbuf_list_ptr = transmit_ptr; 60 tx_free_slots_fn_ptr = tx_free_slots_ptr; 61 handle_free_tx_slot_fn_ptr = handle_free_tx_slot_ptr; 62 rx_register_buffer_fn_ptr = rx_register_buffer_ptr; 63 rx_get_free_slots_fn_ptr = rx_get_free_slots_ptr; 64 /* printf("PBUF_POOL_BUFSIZE = %u, rx buffer size = %zu\n", PBUF_POOL_BUFSIZE, */ 65 /* rx_bufsz); */ 66} 67 68static struct packet *get_tx_packet(void) 69{ 70 static unsigned int idx = 0; 71 struct packet *p = &tx_packets[idx]; 72 73 // Busy-wait until packet not in flight 74 while(p->len != 0) { 75 handle_free_tx_slot_fn_ptr(); 76 } 77 78 idx = (idx + 1) % MAX_PACKETS; 79 return p; 80} 81 82static void packet_output(struct packet *p) 83{ 84 struct driver_buffer buf; 85 86 buf.pa = p->pa; 87 buf.va = p->payload; 88 buf.len = p->len; 89 buf.flags = 0; 90 buf.opaque = p; 91 92 errval_t err = ether_transmit_pbuf_list_ptr(&buf, 1); 93 assert(err_is_ok(err)); 94} 95 96#include <barrelfish/sys_debug.h> 97 98// This is roughly Mon Apr 25 13:50 CEST 2011 99#define TOD_OFFSET 1303732456ULL 100 101int gettimeofday(struct timeval *tv, struct timezone *tz) 102{ 103 uint64_t now = rdtsc(); 104 static uint64_t tscperms = 0; 105 106 if(tscperms == 0) { 107 errval_t err = sys_debug_get_tsc_per_ms(&tscperms); 108 assert(err_is_ok(err)); 109 assert(tscperms >= 1000); 110 } 111 112 uint64_t tod_us = (TOD_OFFSET * 1000000) + (now / (tscperms / 1000)); 113 114 if(tv != NULL) { 115 tv->tv_sec = tod_us / 1000000; 116 tv->tv_usec = tod_us % 1000000; 117 } 118 119 assert(tz == NULL); 120 if(tz != NULL) { 121 } 122 123 return 0; 124} 125 126#define MAX_STAMPS 10000 127 128static uint64_t tstamp[MAX_STAMPS]; 129static int stamps = 0; 130 131void process_received_packet(struct driver_rx_buffer *buffer, size_t count, 132 uint64_t flags) 133{ 134 uint64_t instamp = rdtsc(); 135 136 struct packet *p = buffer->opaque; 137 assert(p != NULL); 138 assert(count == 1); 139 p->len = buffer->len; 140 141 /* printf("Incoming packet\n"); */ 142 143 // Drop packets with invalid checksums 144 if(flags & NETIF_RXFLAG_IPCHECKSUM) { 145 if(!(flags & NETIF_RXFLAG_IPCHECKSUM_GOOD)) { 146 goto out; 147 } 148 } 149 150 if(flags & NETIF_RXFLAG_L4CHECKSUM) { 151 if(!(flags & NETIF_RXFLAG_L4CHECKSUM_GOOD)) { 152 goto out; 153 } 154 } 155 156 /* printf("Checksum good\n"); */ 157 158 struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload; 159 switch (htons(ethhdr->type)) { 160 case ETHTYPE_ARP: 161 { 162 /* printf("Is an ARP packet\n"); */ 163 struct etharp_hdr *arphdr = (struct etharp_hdr *)(p->payload + SIZEOF_ETH_HDR); 164 struct eth_addr mymac; 165 bool ourarp = false; 166 167 if(htons(arphdr->opcode) == ARP_REQUEST) { 168 // 10.0.2.15 169 if(htons(arphdr->dipaddr.addrw[0]) == 0x0a00 && 170 htons(arphdr->dipaddr.addrw[1]) == 0x020f) { 171 memcpy(&mymac.addr, "\x52\x54\x00\x12\x34\x56", ETHARP_HWADDR_LEN); 172 ourarp = true; 173 } else if(htons(arphdr->dipaddr.addrw[0]) == 0x80d0 && 174 htons(arphdr->dipaddr.addrw[1]) == 0x0643) { 175 memcpy(&mymac.addr, "\xa0\x36\x9f\x10\x00\xa6", ETHARP_HWADDR_LEN); 176 ourarp = true; 177 } 178 } 179 180 if(ourarp) { 181 /* printf("ARP request for us\n"); */ 182 // Send reply 183 struct packet *outp = get_tx_packet(); 184 struct eth_hdr *myeth = (struct eth_hdr *)outp->payload; 185 struct etharp_hdr *myarp = (struct etharp_hdr *)(outp->payload + SIZEOF_ETH_HDR); 186 187 // ETH header 188 memcpy(&myeth->dest, &arphdr->shwaddr, ETHARP_HWADDR_LEN); 189 memcpy(&myeth->src, &mymac, ETHARP_HWADDR_LEN); 190 myeth->type = htons(ETHTYPE_ARP); 191 192 // ARP header 193 myarp->hwtype = htons(1); 194 myarp->proto = htons(ETHTYPE_IP); 195 myarp->hwlen = 6; 196 myarp->protolen = 4; 197 myarp->opcode = htons(ARP_REPLY); 198 memcpy(&myarp->shwaddr, &mymac, ETHARP_HWADDR_LEN); 199 memcpy(&myarp->sipaddr, &arphdr->dipaddr, sizeof(myarp->sipaddr)); 200 memcpy(&myarp->dhwaddr, &arphdr->shwaddr, ETHARP_HWADDR_LEN); 201 memcpy(&myarp->dipaddr, &arphdr->sipaddr, sizeof(myarp->dipaddr)); 202 203 outp->len = p->len; 204 packet_output(outp); 205 } 206 } 207 break; 208 209 case ETHTYPE_IP: 210 { 211 struct ip_hdr *iphdr = (struct ip_hdr *)(p->payload + SIZEOF_ETH_HDR); 212 213 /* printf("Is an IP packet, type %x\n", IPH_PROTO(iphdr)); */ 214 215 if(IPH_PROTO(iphdr) == IP_PROTO_UDP) { 216 struct udp_hdr *udphdr = (struct udp_hdr *)(p->payload + SIZEOF_ETH_HDR + (IPH_HL(iphdr) * 4)); 217 uint8_t *payload = p->payload + SIZEOF_ETH_HDR + (IPH_HL(iphdr) * 4) + sizeof(struct udp_hdr); 218 219 /* printf("Got UDP packet, dest IP %x, dest port %u\n", */ 220 /* iphdr->dest.addr, udphdr->dest); */ 221 222 if(htonl(iphdr->dest.addr) != 0x80d00643 || 223 htons(udphdr->dest) != 1234) { 224 goto out; 225 } 226 227 /* printf("payload '%s'\n", payload); */ 228 229 struct packet *outp = get_tx_packet(); 230 struct eth_hdr *myeth = (struct eth_hdr *)outp->payload; 231 struct ip_hdr *myip = (struct ip_hdr *)(outp->payload + SIZEOF_ETH_HDR); 232 struct udp_hdr *myudp = (struct udp_hdr *)(outp->payload + SIZEOF_ETH_HDR + (IPH_HL(iphdr) * 4)); 233 uint8_t *mypayload = outp->payload + SIZEOF_ETH_HDR + (IPH_HL(iphdr) * 4) + sizeof(struct udp_hdr); 234 235 // ETH header 236 memcpy(&myeth->dest, ðhdr->src, ETHARP_HWADDR_LEN); 237 memcpy(&myeth->src, ðhdr->dest, ETHARP_HWADDR_LEN); 238 myeth->type = htons(ETHTYPE_IP); 239 240 // IP header 241 memcpy(myip, iphdr, sizeof(struct ip_hdr)); 242 memcpy(&myip->src, &iphdr->dest, sizeof(ip_addr_p_t)); 243 memcpy(&myip->dest, &iphdr->src, sizeof(ip_addr_p_t)); 244 245 // UDP header 246 memcpy(myudp, udphdr, sizeof(struct udp_hdr)); 247 myudp->src = udphdr->dest; 248 myudp->dest = udphdr->src; 249 250 // Payload 251 memcpy(mypayload, payload, htons(udphdr->len) - 8); 252 253 outp->len = p->len; 254 packet_output(outp); 255 256 uint64_t now = rdtsc(); 257 tstamp[stamps] = now - instamp; 258 259 /* printf("got packet %d\n", stamps); */ 260 261 stamps++; 262 if(stamps == MAX_STAMPS) { 263 printf("latencies:\n"); 264 for(int i = 0; i < MAX_STAMPS; i++) { 265 printf("%" PRIu64 " cycles\n", tstamp[i]); 266 } 267 stamps = 0; 268 } 269 270 } 271 } 272 break; 273 274 default: 275 break; 276 } 277 278 out: 279 { 280 //now we have consumed the preregistered pbuf containing a received packet 281 //which was processed in this function. Therefore we have to register a new 282 //free buffer for receiving packets. 283 errval_t err = rx_register_buffer_fn_ptr(p->pa, p->payload, p); 284 assert(err_is_ok(err)); 285 } 286} 287 288bool handle_tx_done(void *opaque) 289{ 290 struct packet *p = opaque; 291 p->len = 0; 292 return true; 293} 294 295/* allocate a single frame, mapping it into our vspace with given attributes */ 296static void *alloc_map_frame(vregion_flags_t attr, size_t size, struct capref *retcap) 297{ 298 struct capref frame; 299 errval_t r; 300 301 r = frame_alloc(&frame, size, NULL); 302 assert(err_is_ok(r)); 303 void *va; 304 r = vspace_map_one_frame_attr(&va, size, frame, attr, 305 NULL, NULL); 306 if (err_is_fail(r)) { 307 DEBUG_ERR(r, "vspace_map_one_frame failed"); 308 return NULL; 309 } 310 311 if (retcap != NULL) { 312 *retcap = frame; 313 } 314 315 return va; 316} 317 318int main(int argc, char *argv[]) 319{ 320 uint8_t mac[6]; 321 322 printf("Starting e10k test program...\n"); 323 324 e1000n_driver_init(argc, argv); 325 326 ether_get_mac_address_ptr(mac); 327 printf("e10ktest MAC address %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n", 328 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 329 330 struct capref frame; 331 uint8_t *ram_base = alloc_map_frame(VREGION_FLAGS_READ_WRITE, 332 MAX_PACKETS * PACKET_SIZE, &frame); 333 assert(ram_base != NULL); 334 335 struct frame_identity id; 336 errval_t err = invoke_frame_identify(frame, &id); 337 assert(err_is_ok(err)); 338 339 // Add buffers to RX ring for packet reception 340 for(int i = 0; i < MAX_PACKETS; i++) { 341 struct packet *p = &rx_packets[i]; 342 343 p->payload = ram_base + (i * PACKET_SIZE); 344 p->pa = id.base + (i * PACKET_SIZE); 345 p->len = PACKET_SIZE; 346 347 err = rx_register_buffer_fn_ptr(p->pa, p->payload, p); 348 assert(err_is_ok(err)); 349 } 350 351 // Setup TX packets 352 ram_base = alloc_map_frame(VREGION_FLAGS_READ_WRITE, 353 MAX_PACKETS * PACKET_SIZE, &frame); 354 assert(ram_base != NULL); 355 err = invoke_frame_identify(frame, &id); 356 assert(err_is_ok(err)); 357 for(int i = 0; i < MAX_PACKETS; i++) { 358 struct packet *p = &tx_packets[i]; 359 p->payload = ram_base + (i * PACKET_SIZE); 360 p->pa = id.base + (i * PACKET_SIZE); 361 p->len = 0; 362 } 363 364 for(;;) { 365 e1000n_polling_loop(get_default_waitset()); 366 } 367 368 return 0; 369} 370