static struct rte_mbuf *build_packet(const unsigned char *data, size_t len) { struct rte_mempool *mp = pg_get_mempool(); struct rte_mbuf *pkt = rte_pktmbuf_alloc(mp); void *packet; pkt->pkt_len = len; pkt->data_len = len; pkt->nb_segs = 1; pkt->next = NULL; packet = rte_pktmbuf_mtod(pkt, void*); memcpy(packet, data, len); return pkt; }
static struct rte_mbuf *build_ip_packet(const char *src_ip, const char *dst_ip, uint16_t data) { struct rte_mempool *mp = pg_get_mempool(); struct rte_mbuf *pkt = rte_pktmbuf_alloc(mp); uint16_t len = sizeof(struct ether_hdr) + sizeof(struct ip) + sizeof(uint16_t); struct ether_hdr *eth; struct ip *ip; uint16_t *payload_ip; pkt->pkt_len = len; pkt->data_len = len; pkt->nb_segs = 1; pkt->next = NULL; /* ethernet header */ eth = rte_pktmbuf_mtod(pkt, struct ether_hdr*); memset(eth, 0, len); eth->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4); /* ipv4 header */ ip = (struct ip *)(eth + 1); ip->ip_v = IPVERSION; ip->ip_hl = sizeof(struct ip) >> 2; ip->ip_off = 0; ip->ip_ttl = 64; /* FEAR ! this is CHAOS ! */ ip->ip_p = 16; ip->ip_len = htons(sizeof(struct ip) + 1); ip->ip_src.s_addr = inet_addr(src_ip); ip->ip_dst.s_addr = inet_addr(dst_ip); /* write some data */ payload_ip = (uint16_t *)(ip + 1); *payload_ip = data; return pkt; }
static struct rte_mbuf *build_non_ip_packet(void) { struct rte_mempool *mp = pg_get_mempool(); struct rte_mbuf *pkt = rte_pktmbuf_alloc(mp); uint8_t *payload; struct ether_hdr *eth; uint16_t len = sizeof(struct ether_hdr) + 1; pkt->pkt_len = len; pkt->data_len = len; pkt->nb_segs = 1; pkt->next = NULL; /* ethernet header */ eth = rte_pktmbuf_mtod(pkt, struct ether_hdr*); memset(eth, 0, len); eth->ether_type = rte_cpu_to_be_16(ETHER_TYPE_ARP); /* write some data */ payload = (uint8_t *)(eth + 1); *payload = 42; return pkt; }
/* this test harness a Linux guest to check that packet are send and received * by the vhost brick. An ethernet bridge inside the guest will forward packets * between the two vhost-user virtio interfaces. */ static void test_vhost_flow_(int qemu_exit_signal) { const char mac_addr_0[18] = "52:54:00:12:34:11"; const char mac_addr_1[18] = "52:54:00:12:34:12"; struct rte_mempool *mbuf_pool = pg_get_mempool(); struct pg_brick *vhost_0, *vhost_1, *collect; struct rte_mbuf *pkts[PG_MAX_PKTS_BURST]; const char *socket_path_0, *socket_path_1; struct pg_error *error = NULL; struct rte_mbuf **result_pkts; int ret, qemu_pid, i; uint64_t pkts_mask; /* start vhost */ ret = pg_vhost_start("/tmp", &error); g_assert(ret == 0); g_assert(!error); /* instanciate brick */ vhost_0 = pg_vhost_new("vhost-0", &error); g_assert(!error); g_assert(vhost_0); vhost_1 = pg_vhost_new("vhost-1", &error); g_assert(!error); g_assert(vhost_1); collect = pg_collect_new("collect", &error); g_assert(!error); g_assert(collect); /* build the graph */ pg_brick_link(collect, vhost_1, &error); g_assert(!error); /* spawn first QEMU */ socket_path_0 = pg_vhost_socket_path(vhost_0, &error); g_assert(!error); g_assert(socket_path_0); socket_path_1 = pg_vhost_socket_path(vhost_1, &error); g_assert(!error); g_assert(socket_path_1); qemu_pid = pg_util_spawn_qemu(socket_path_0, socket_path_1, mac_addr_0, mac_addr_1, glob_vm_path, glob_vm_key_path, glob_hugepages_path, &error); g_assert(!error); g_assert(qemu_pid); /* Prepare VM's bridge. */ # define SSH(c) \ g_assert(pg_util_ssh("localhost", ssh_port_id, glob_vm_key_path, c) == 0) SSH("brctl addbr br0"); SSH("ifconfig br0 up"); SSH("ifconfig ens4 up"); SSH("ifconfig ens5 up"); SSH("brctl addif br0 ens4"); SSH("brctl addif br0 ens5"); SSH("brctl setfd br0 0"); SSH("brctl stp br0 off"); # undef SSH ssh_port_id++; /* prepare packet to send */ for (i = 0; i < NB_PKTS; i++) { pkts[i] = rte_pktmbuf_alloc(mbuf_pool); g_assert(pkts[i]); rte_pktmbuf_append(pkts[i], ETHER_MIN_LEN); /* set random dst/src mac address so the linux guest bridge * will not filter them */ pg_set_mac_addrs(pkts[i], "52:54:00:12:34:15", "52:54:00:12:34:16"); /* set size */ pg_set_ether_type(pkts[i], ETHER_MIN_LEN - ETHER_HDR_LEN - 4); } /* send packet to the guest via one interface */ pg_brick_burst_to_east(vhost_0, 0, pkts, pg_mask_firsts(NB_PKTS), &error); g_assert(!error); /* let the packet propagate and flow */ for (i = 0; i < 10; i++) { uint16_t count = 0; usleep(100000); pg_brick_poll(vhost_1, &count, &error); g_assert(!error); if (count) break; } result_pkts = pg_brick_east_burst_get(collect, &pkts_mask, &error); g_assert(!error); g_assert(result_pkts); g_assert(pg_brick_rx_bytes(vhost_0) == 0); g_assert(pg_brick_tx_bytes(vhost_0) != 0); g_assert(pg_brick_rx_bytes(vhost_1) != 0); g_assert(pg_brick_tx_bytes(vhost_1) == 0); /* kill QEMU */ pg_util_stop_qemu(qemu_pid, qemu_exit_signal); /* free result packets */ pg_packets_free(result_pkts, pkts_mask); /* free sent packet */ for (i = 0; i < NB_PKTS; i++) rte_pktmbuf_free(pkts[i]); /* break the graph */ pg_brick_unlink(collect, &error); g_assert(!error); /* clean up */ /* pg_brick_decref(vhost_0, &error); */ pg_brick_destroy(vhost_0); g_assert(!error); pg_brick_destroy(vhost_1); /* pg_brick_decref(vhost_1, &error); */ g_assert(!error); pg_brick_decref(collect, &error); g_assert(!error); /* stop vhost */ pg_vhost_stop(); }
static void test_queue_reset(void) { # define NB_PKTS 64 struct pg_error *error = NULL; struct pg_brick *queue1, *queue2, *collect; struct rte_mbuf **result_pkts; struct rte_mbuf *pkts[NB_PKTS]; uint64_t pkts_mask, i, j; uint16_t count = 0; struct rte_mempool *mbuf_pool = pg_get_mempool(); /** * Burst packets in queue1 and test reset of queue1 * [queue1] ~ [queue2]----[collect] */ queue1 = pg_queue_new("q1", 10, &error); CHECK_ERROR(error); queue2 = pg_queue_new("q2", 10, &error); CHECK_ERROR(error); collect = pg_collect_new("collect", 1, 1, &error); CHECK_ERROR(error); pg_brick_link(queue2, collect, &error); CHECK_ERROR(error); g_assert(!pg_queue_friend(queue1, queue2, &error)); CHECK_ERROR(error); for (i = 0; i < NB_PKTS; i++) { pkts[i] = rte_pktmbuf_alloc(mbuf_pool); g_assert(pkts[i]); pkts[i]->udata64 = i; pg_set_mac_addrs(pkts[i], "F0:F1:F2:F3:F4:F5", "E0:E1:E2:E3:E4:E5"); } for (j = 0; j < 100; j++) { for (i = 0; i < NB_PKTS; i++) pkts[i]->udata64 = i * j; /* burst and reset */ pg_brick_burst_to_east(queue1, 0, pkts, pg_mask_firsts(NB_PKTS), &error); CHECK_ERROR(error); g_assert(pg_queue_pressure(queue1) > 0); g_assert(!pg_brick_reset(queue1, &error)); g_assert(pg_queue_get_friend(queue1) == NULL); g_assert(pg_queue_get_friend(queue2) == NULL); g_assert(pg_queue_pressure(queue1) == 0); g_assert(pg_queue_pressure(queue2) == 0); pg_brick_poll(queue2, &count, &error); g_assert(!error); g_assert(count == 0); /* refriend and burst ok */ g_assert(!pg_queue_friend(queue1, queue2, &error)); g_assert(!error); g_assert(pg_queue_are_friend(queue1, queue2)); g_assert(!error); pg_brick_burst_to_east(queue1, 0, pkts, pg_mask_firsts(NB_PKTS), &error); CHECK_ERROR(error); g_assert(pg_queue_pressure(queue1) > 0); pg_brick_poll(queue2, &count, &error); g_assert(count == NB_PKTS); result_pkts = pg_brick_west_burst_get(collect, &pkts_mask, &error); CHECK_ERROR(error); g_assert(pkts_mask == pg_mask_firsts(NB_PKTS)); for (i = 0; i < NB_PKTS; i++) { g_assert(result_pkts[i]); g_assert(result_pkts[i]->udata64 == i * j); } pg_brick_reset(collect, &error); CHECK_ERROR(error); } /* clean */ for (i = 0; i < NB_PKTS; i++) rte_pktmbuf_free(pkts[i]); pg_brick_decref(queue1, &error); CHECK_ERROR(error); pg_brick_decref(queue2, &error); CHECK_ERROR(error); pg_brick_decref(collect, &error); CHECK_ERROR(error); # undef NB_PKTS }
static int packetsgen_poll(struct pg_brick *brick, uint16_t *pkts_cnt, struct pg_error **errp) { struct pg_packetsgen_state *state; struct rte_mempool *mp = pg_get_mempool(); struct rte_mbuf **pkts; struct pg_brick_side *s; uint64_t pkts_mask; int ret; uint16_t i; state = pg_brick_get_state(brick, struct pg_packetsgen_state); s = &brick->sides[state->output]; pkts = g_new0(struct rte_mbuf*, state->packets_nb); for (i = 0; i < state->packets_nb; i++) { pkts[i] = rte_pktmbuf_clone(state->packets[i], mp); pkts[i]->udata64 = i; } pkts_mask = pg_mask_firsts(state->packets_nb); *pkts_cnt = state->packets_nb; ret = pg_brick_side_forward(s, pg_flip_side(state->output), pkts, pkts_mask, errp); pg_packets_free(pkts, pkts_mask); g_free(pkts); return ret; }