1/* 2 * Copyright (c) 2017, ETH Zurich. 3 * All rights reserved. 4 * 5 * This file is distributed under the terms in the attached LICENSE file. 6 * If you do not find this file, copies can be found by writing to: 7 * ETH Zurich D-INFK, Universitaetstrasse 4, CH-8092 Zurich. Attn: Systems Group. 8 */ 9 10#include <stdlib.h> 11#include <stdio.h> 12#include <stdbool.h> 13#include <barrelfish/barrelfish.h> 14#include <barrelfish/waitset.h> 15#include <barrelfish/deferred.h> 16#include <devif/queue_interface.h> 17#include <devif/queue_interface_backend.h> 18#include <devif/backends/net/ip.h> 19#include <lwip/inet_chksum.h> 20#include <lwip/lwip/inet.h> 21#include <net_interfaces/flags.h> 22#include <net/net.h> 23#include <net/net_queue.h> 24#include <net/net_filter.h> 25#include <net/dhcp.h> 26#include <net/arp.h> 27#include "../headers.h" 28 29#include <bench/bench.h> 30 31#define MAX_NUM_REGIONS 64 32 33//#define DEBUG_ENABLED 34 35#if defined(DEBUG_ENABLED) 36#define DEBUG(x...) do { printf("IP_QUEUE: %s.%d:%s:%d: ", \ 37 disp_name(), disp_get_core_id(), __func__, __LINE__); \ 38 printf(x);\ 39 } while (0) 40 41#else 42#define DEBUG(x...) ((void)0) 43#endif 44 45struct region_vaddr { 46 void* va; 47 regionid_t rid; 48}; 49 50struct pkt_ip_headers { 51 struct eth_hdr eth; 52 struct ip_hdr ip; 53} __attribute__ ((packed)); 54 55struct ip_q { 56 struct devq my_q; 57 struct devq* q; 58 struct capref filter_ep; // connection to cards filter interface 59 struct pkt_ip_headers header; // can fill in this header and reuse it by copying 60 struct region_vaddr regions[MAX_NUM_REGIONS]; 61 struct net_filter_state* filter; 62 uint16_t hdr_len; 63 64 const char* name; 65#ifdef BENCH 66 bench_ctl_t en_rx; 67 bench_ctl_t en_tx; 68 bench_ctl_t deq_rx; 69 bench_ctl_t deq_tx; 70#endif 71}; 72 73 74#ifdef DEBUG_ENABLED 75static void print_buffer(struct ip_q* q, void* start, uint64_t len) 76{ 77 uint8_t* buf = (uint8_t*) start; 78 printf("Packet in region at address %p len %zu \n", 79 buf, len); 80 for (int i = 0; i < len; i+=2) { 81 if (((i % 16) == 0) && i > 0) { 82 printf("\n"); 83 } 84 printf("%2X", buf[i]); 85 printf("%2X ", buf[i+1]); 86 } 87 printf("\n"); 88} 89#endif 90 91static errval_t ip_register(struct devq* q, struct capref cap, 92 regionid_t rid) 93{ 94 95 errval_t err; 96 struct frame_identity frameid = { .base = 0, .bytes = 0 }; 97 98 struct ip_q* que = (struct ip_q*) q; 99 100 // Map device registers 101 err = frame_identify(cap, &frameid); 102 assert(err_is_ok(err)); 103 104 err = vspace_map_one_frame_attr(&que->regions[rid % MAX_NUM_REGIONS].va, 105 frameid.bytes, cap, VREGION_FLAGS_READ_WRITE, 106 NULL, NULL); 107 if (err_is_fail(err)) { 108 DEBUG_ERR(err, "vspace_map_one_frame failed"); 109 return err; 110 } 111 que->regions[rid % MAX_NUM_REGIONS].rid = rid; 112 DEBUG("id-%d va-%p \n", que->regions[rid % MAX_NUM_REGIONS].rid, 113 que->regions[rid % MAX_NUM_REGIONS].va); 114 115 return que->q->f.reg(que->q, cap, rid); 116} 117 118static errval_t ip_deregister(struct devq* q, regionid_t rid) 119{ 120 121 struct ip_q* que = (struct ip_q*) q; 122 que->regions[rid % MAX_NUM_REGIONS].va = NULL; 123 que->regions[rid % MAX_NUM_REGIONS].rid = 0; 124 return que->q->f.dereg(que->q, rid); 125} 126 127 128static errval_t ip_control(struct devq* q, uint64_t cmd, uint64_t value, 129 uint64_t* result) 130{ 131 struct ip_q* que = (struct ip_q*) q; 132 return que->q->f.ctrl(que->q, cmd, value, result); 133} 134 135 136static errval_t ip_notify(struct devq* q) 137{ 138 struct ip_q* que = (struct ip_q*) q; 139 return que->q->f.notify(que->q); 140} 141 142static errval_t ip_enqueue(struct devq* q, regionid_t rid, 143 genoffset_t offset, genoffset_t length, 144 genoffset_t valid_data, genoffset_t valid_length, 145 uint64_t flags) 146{ 147 148 // for now limit length 149 // TODO fragmentation 150 151 struct ip_q* que = (struct ip_q*) q; 152 if (flags & NETIF_TXFLAG) { 153 154 DEBUG("TX rid: %d offset %ld length %ld valid_length %ld \n", rid, offset, 155 length, valid_length); 156 assert(valid_length <= 1500); 157 que->header.ip._len = htons(valid_length + IP_HLEN); 158 que->header.ip._chksum = inet_chksum(&que->header, IP_HLEN); 159 160 assert(que->regions[rid % MAX_NUM_REGIONS].va != NULL); 161 162 uint8_t* start = (uint8_t*) que->regions[rid % MAX_NUM_REGIONS].va + 163 offset + valid_data; 164 165 memcpy(start, &que->header, sizeof(que->header)); 166 167#ifdef BENCH 168 uint64_t b_start, b_end; 169 errval_t err; 170 171 b_start = rdtscp(); 172 err = que->q->f.enq(que->q, rid, offset, length, valid_data, 173 valid_length+sizeof(struct pkt_ip_headers), flags); 174 b_end = rdtscp(); 175 if (err_is_ok(err)) { 176 uint64_t res = b_end - b_start; 177 bench_ctl_add_run(&que->en_tx, &res); 178 } 179 return err; 180#else 181 return que->q->f.enq(que->q, rid, offset, length, valid_data, 182 valid_length+sizeof(struct pkt_ip_headers), flags); 183#endif 184 } 185 186 if (flags & NETIF_RXFLAG) { 187 assert(valid_length <= 2048); 188 DEBUG("RX rid: %d offset %ld length %ld valid_length %ld \n", rid, offset, 189 length, valid_length); 190#ifdef BENCH 191 uint64_t start, end; 192 errval_t err; 193 194 start = rdtscp(); 195 err = que->q->f.enq(que->q, rid, offset, length, valid_data, 196 valid_length, flags); 197 end = rdtscp(); 198 if (err_is_ok(err)) { 199 uint64_t res = end - start; 200 bench_ctl_add_run(&que->en_rx, &res); 201 } 202 return err; 203#else 204 return que->q->f.enq(que->q, rid, offset, length, valid_data, 205 valid_length, flags); 206#endif 207 } 208 209 return NET_QUEUE_ERR_UNKNOWN_BUF_TYPE; 210} 211 212static errval_t ip_dequeue(struct devq* q, regionid_t* rid, genoffset_t* offset, 213 genoffset_t* length, genoffset_t* valid_data, 214 genoffset_t* valid_length, uint64_t* flags) 215{ 216 errval_t err; 217 struct ip_q* que = (struct ip_q*) q; 218 219#ifdef BENCH 220 uint64_t start, end; 221 start = rdtscp(); 222 err = que->q->f.deq(que->q, rid, offset, length, valid_data, valid_length, flags); 223 end = rdtscp(); 224 if (err_is_fail(err)) { 225 return err; 226 } 227#else 228 err = que->q->f.deq(que->q, rid, offset, length, valid_data, valid_length, flags); 229 if (err_is_fail(err)) { 230 return err; 231 } 232#endif 233 234 if (*flags & NETIF_RXFLAG) { 235 DEBUG("RX rid: %d offset %ld valid_data %ld length %ld va %p \n", *rid, 236 *offset, *valid_data, 237 *valid_length, que->regions[*rid % MAX_NUM_REGIONS].va + *offset + *valid_data); 238 239 struct pkt_ip_headers* header = (struct pkt_ip_headers*) 240 (que->regions[*rid % MAX_NUM_REGIONS].va + 241 *offset + *valid_data); 242 243 // IP checksum 244 if (header->ip._chksum == inet_chksum(&header->ip, IP_HLEN)) { 245 printf("IP queue: dropping packet wrong checksum \n"); 246 err = que->q->f.enq(que->q, *rid, *offset, *length, 0, 0, NETIF_RXFLAG); 247 return err_push(err, NET_QUEUE_ERR_CHECKSUM); 248 } 249 250 // Correct ip for this queue? 251 if (header->ip.src != que->header.ip.dest) { 252 printf("IP queue: dropping packet, wrong IP is %"PRIu32" should be %"PRIu32"\n", 253 header->ip.src, que->header.ip.dest); 254 err = que->q->f.enq(que->q, *rid, *offset, *length, 0, 0, NETIF_RXFLAG); 255 return err_push(err, NET_QUEUE_ERR_WRONG_IP); 256 } 257 258#ifdef DEBUG_ENABLED 259 print_buffer(que, que->regions[*rid % MAX_NUM_REGIONS].va + *offset, *valid_length); 260#endif 261 262 *valid_data = IP_HLEN + ETH_HLEN; 263 *valid_length = ntohs(header->ip._len) - IP_HLEN; 264 //print_buffer(que, que->regions[*rid % MAX_NUM_REGIONS].va + *offset+ *valid_data, *valid_length); 265 // 266 267#ifdef BENCH 268 uint64_t res = end - start; 269 bench_ctl_add_run(&que->deq_rx, &res); 270#endif 271 return SYS_ERR_OK; 272 } 273 274 DEBUG("TX rid: %d offset %ld length %ld \n", *rid, *offset, 275 *valid_length); 276 277#ifdef BENCH 278 uint64_t res = end - start; 279 bench_ctl_add_run(&que->deq_tx, &res); 280#endif 281 282 return SYS_ERR_OK; 283} 284 285/* 286 * Public functions 287 * 288 */ 289errval_t ip_create(struct ip_q** q, const char* card_name, uint64_t* qid, 290 uint8_t prot, uint32_t dst_ip, inthandler_t interrupt, bool poll) 291{ 292 errval_t err; 293 struct ip_q* que; 294 que = calloc(1, sizeof(struct ip_q)); 295 que->name = card_name; 296 assert(que); 297 298 // init other queue 299 err = net_queue_create(interrupt, card_name, NULL, qid, poll, &que->filter_ep, &que->q); 300 if (err_is_fail(err)) { 301 return err; 302 } 303 304 err = devq_init(&que->my_q, false); 305 if (err_is_fail(err)) { 306 // TODO net queue destroy 307 return err; 308 } 309 310 uint64_t src_mac; 311 err = devq_control(que->q, 0, 0, &src_mac); 312 if (err_is_fail(err)) { 313 return err; 314 } 315 316 uint32_t src_ip; 317 err = net_config_current_ip_query(NET_FLAGS_BLOCKING_INIT, &src_ip); 318 if (err_is_fail(err)) { 319 return err; 320 } 321 322 uint64_t mac; 323 err = arp_service_get_mac(htonl(dst_ip), &mac); 324 if (err_is_fail(err)) { 325 return err; 326 } 327 328 // fill in header that is reused for each packet 329 // Ethernet 330 memcpy(&(que->header.eth.dest.addr), &mac, ETH_HWADDR_LEN); 331 memcpy(&(que->header.eth.src.addr), &src_mac, ETH_HWADDR_LEN); 332 que->header.eth.type = htons(ETHTYPE_IP); 333 334 // IP 335 que->header.ip._v_hl = 69; 336 IPH_TOS_SET(&que->header.ip, 0x0); 337 IPH_ID_SET(&que->header.ip, htons(0x3)); 338 que->header.ip._offset = htons(IP_DF); 339 que->header.ip._proto = 0x11; // IP 340 que->header.ip._ttl = 0x40; // 64 341 que->header.ip.src = src_ip; 342 que->header.ip.dest = htonl(dst_ip); 343 344 que->my_q.f.reg = ip_register; 345 que->my_q.f.dereg = ip_deregister; 346 que->my_q.f.ctrl = ip_control; 347 que->my_q.f.notify = ip_notify; 348 que->my_q.f.enq = ip_enqueue; 349 que->my_q.f.deq = ip_dequeue; 350 *q = que; 351 352 /* 353 switch(prot) { 354 case UDP_PROT: 355 que->hdr_len = IP_HLEN + sizeof(struct udp_hdr); 356 break; 357 case TCP_PROT: 358 // TODO 359 break; 360 default: 361 USER_PANIC("Unkown protocol specified when creating IP queue \n"); 362 363 } 364 */ 365 366#ifdef BENCH 367 bench_init(); 368 369 que->en_tx.mode = BENCH_MODE_FIXEDRUNS; 370 que->en_tx.result_dimensions = 1; 371 que->en_tx.min_runs = BENCH_SIZE; 372 que->en_tx.data = calloc(que->en_tx.min_runs * que->en_tx.result_dimensions, 373 sizeof(*que->en_tx.data)); 374 375 que->en_rx.mode = BENCH_MODE_FIXEDRUNS; 376 que->en_rx.result_dimensions = 1; 377 que->en_rx.min_runs = BENCH_SIZE; 378 que->en_rx.data = calloc(que->en_rx.min_runs * que->en_rx.result_dimensions, 379 sizeof(*que->en_rx.data)); 380 381 que->deq_rx.mode = BENCH_MODE_FIXEDRUNS; 382 que->deq_rx.result_dimensions = 1; 383 que->deq_rx.min_runs = BENCH_SIZE; 384 que->deq_rx.data = calloc(que->deq_rx.min_runs * que->deq_rx.result_dimensions, 385 sizeof(*que->deq_rx.data)); 386 387 que->deq_tx.mode = BENCH_MODE_FIXEDRUNS; 388 que->deq_tx.result_dimensions = 1; 389 que->deq_tx.min_runs = BENCH_SIZE; 390 que->deq_tx.data = calloc(que->deq_tx.min_runs * que->deq_tx.result_dimensions, 391 sizeof(*que->deq_tx.data)); 392#endif 393 394 return SYS_ERR_OK; 395} 396 397errval_t ip_destroy(struct ip_q* q) 398{ 399 // TODO destroy q->q; 400 free(q); 401 402 return SYS_ERR_OK; 403} 404 405void ip_get_netfilter_ep(struct ip_q* q, struct capref* ep) 406{ 407 *ep = q->filter_ep; 408} 409 410struct bench_ctl* ip_get_benchmark_data(struct ip_q* q, uint8_t type) 411{ 412 switch (type) { 413#ifdef BENCH 414 case 0: 415 return &q->en_rx; 416 case 1: 417 return &q->en_tx; 418 case 2: 419 return &q->deq_rx; 420 case 3: 421 return &q->deq_tx; 422#endif 423 case 4: 424 return net_queue_get_bench_data((struct devq*) q->q, q->name, 0); 425 case 5: 426 return net_queue_get_bench_data((struct devq*) q->q, q->name, 1); 427 case 6: 428 return net_queue_get_bench_data((struct devq*) q->q, q->name, 2); 429 case 7: 430 return net_queue_get_bench_data((struct devq*) q->q, q->name, 3); 431 default: 432 return NULL; 433 } 434 return NULL; 435} 436 437