/* Try to execute action with the drop action, which should succeed */ static void test_action_execute_drop(int argc, char *argv[]) { struct rte_mbuf buf_free; struct rte_mbuf buf_drop; struct action action_multiple[MAX_ACTIONS] = {0}; struct action action_drop[MAX_ACTIONS] = {0}; stats_init(); stats_vswitch_clear(); /* TODO: Break this into multiple tests? */ /* check that mbuf is freed on drop */ assert(memcmp(&buf_free, &buf_drop, sizeof(buf_drop)) != 0); buf_drop.pkt.next = NULL; /* Required for rte_pktmbuf_free */ memcpy(&buf_free, &buf_drop, sizeof(buf_drop)); assert(memcmp(&buf_free, &buf_drop, sizeof(buf_drop)) == 0); action_drop_build(&action_drop[0]); action_null_build(&action_drop[1]); action_execute(action_drop, &buf_free); assert(memcmp(&buf_free, &buf_drop, sizeof(buf_drop)) != 0); /* check that vswitch rx drop stats are increased */ stats_vswitch_clear(); assert(stats_vswitch_rx_drop_get() == 0); action_drop_build(&action_drop[0]); action_null_build(&action_drop[1]); action_execute(action_drop, &buf_drop); assert(stats_vswitch_rx_drop_get() == 1); }
/* Try to execute action with invalid parameters, which should fail * with -1 */ static void test_action_execute_output__invalid_params(int argc, char *argv[]) { struct rte_mbuf buf_multiple[5]; struct action action_multiple[MAX_ACTIONS] = {0}; int ret = 0; /* check incorrect parameters */ vport_init(); action_output_build(&action_multiple[0], 17); action_null_build(&action_multiple[1]); ret = action_execute(NULL, &buf_multiple[1]); assert(ret < 0); ret = action_execute(action_multiple, NULL); assert(ret < 0); }
/* Try to execute action with a pop vlan and output action, which should succeed */ static void test_action_execute_multiple_actions__pop_vlan_and_output(int argc, char *argv[]) { /* We write some data into the place where a VLAN tag would be and the 4 * bytes after. We then call action execute and make sure the fake VLAN tag * is gone and has been replaced by the data in the 4 bytes after * * We then output the packet to a port and make the same checks */ struct rte_mempool *pktmbuf_pool; struct action action_multiple[MAX_ACTIONS] = {0}; int count = 0; pktmbuf_pool = rte_mempool_create("MProc_pktmbuf_pool", 20, /* num mbufs */ 2048 + sizeof(struct rte_mbuf) + 128, /*pktmbuf size */ 32, /*cache size */ sizeof(struct rte_pktmbuf_pool_private), rte_pktmbuf_pool_init, NULL, rte_pktmbuf_init, NULL, 0, 0); struct rte_mbuf *vlan_output_buf = rte_pktmbuf_alloc(pktmbuf_pool); vport_init(); /* We have no real packet but the function which pops the VLAN does * some checks of pkt len so we define a fake one here */ vlan_output_buf->pkt.pkt_len = 20; action_pop_vlan_build(&action_multiple[0]); action_output_build(&action_multiple[1], 17); action_null_build(&action_multiple[2]); int *pktmbuf_data = rte_pktmbuf_mtod(vlan_output_buf, int *); *(pktmbuf_data + 2) = 0xCAFED00D; /* Note last 2 bytes must be 0081, ie 8100 in network format */ *(pktmbuf_data + 3) = 0x00000081; /* 12 bytes after src/dst MAC is vlan */ *(pktmbuf_data + 4) = 0xBABEFACE; action_execute(action_multiple, vlan_output_buf); pktmbuf_data = rte_pktmbuf_mtod(vlan_output_buf, int *); assert(*(pktmbuf_data + 3) != 0x00000081); assert(*(pktmbuf_data + 3) == 0xBABEFACE); count = receive_from_vport(17, &vlan_output_buf); pktmbuf_data = rte_pktmbuf_mtod(vlan_output_buf, int *); assert(count == 1); assert(*(pktmbuf_data + 3) != 0x00000081); assert(*(pktmbuf_data + 3) == 0xBABEFACE); }
/* Modify packet ethernet header */ static void test_action_execute_set_ethernet(int argc, char *argv[]) { struct rte_mempool *pktmbuf_pool; struct action action_multiple[MAX_ACTIONS] = {0}; pktmbuf_pool = rte_mempool_create("MProc_pktmbuf_pool", 20, /* num mbufs */ 2048 + sizeof(struct rte_mbuf) + 128, /*pktmbuf size */ 32, /*cache size */ sizeof(struct rte_pktmbuf_pool_private), rte_pktmbuf_pool_init, NULL, rte_pktmbuf_init, NULL, 0, 0); struct rte_mbuf *ethernet_buf = rte_pktmbuf_alloc(pktmbuf_pool); struct ovs_key_ethernet set_ethernet; __u8 eth_src_set[6] = {0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE}; __u8 eth_dst_set[6] = {0xCA, 0xFE, 0xDE, 0xAD, 0xBE, 0xEF}; memcpy(&set_ethernet.eth_src, ð_src_set, sizeof(eth_src_set)); memcpy(&set_ethernet.eth_dst, ð_dst_set, sizeof(eth_dst_set)); struct ovs_key_ethernet ethernet_orig; __u8 eth_src_orig[6] = {0xFF, 0xFF, 0xFF, 0xCC, 0xCC, 0xCC}; __u8 eth_dst_orig[6] = {0xAA, 0xAA, 0xAA, 0xEE, 0xEE, 0xEE}; memcpy(ðernet_orig.eth_src, ð_src_orig, sizeof(eth_src_orig)); memcpy(ðernet_orig.eth_dst, ð_dst_orig, sizeof(eth_dst_orig)); vport_init(); action_multiple[0].type = ACTION_SET_ETHERNET; action_multiple[0].data.ethernet = set_ethernet; action_null_build(&action_multiple[1]); struct ovs_key_ethernet *pktmbuf_data = rte_pktmbuf_mtod(ethernet_buf, struct ovs_key_ethernet *); memcpy(pktmbuf_data, ðernet_orig, sizeof(ethernet_orig)); action_execute(action_multiple, ethernet_buf); pktmbuf_data = rte_pktmbuf_mtod(ethernet_buf, struct ovs_key_ethernet *); /* Can't compare struct directly as ovs_key_ethernet has src first then * dst whereas the real ethernet header has dst first then source */ assert(memcmp(pktmbuf_data, &set_ethernet.eth_dst, sizeof(eth_dst_set)) == 0); assert(memcmp((uint8_t *)pktmbuf_data + sizeof(eth_dst_set), &set_ethernet.eth_src, sizeof(eth_src_set)) == 0); rte_pktmbuf_free(ethernet_buf); }
/* Try to execute action with the push vlan (PCP) action, which should * succeed */ static void test_action_execute_push_vlan__pcp(int argc, char *argv[]) { /* Write Ethertype value of 0x0800 to byte 11 of the packet, * where it is expected, and assign a length to the packet. * After call to action_execute: * - the length of the packet should have increased by 4 bytes * - the value of byte 11 should by 0x8100 (0081 in network format) * - the value of byte 15 should by 0x0800 (0008 in network format) * - the value of the TCI field should be equal to the assigned * value */ struct rte_mempool *pktmbuf_pool; struct action action_multiple[MAX_ACTIONS] = {0}; pktmbuf_pool = rte_mempool_create("MProc_pktmbuf_pool", 20, /* num mbufs */ 2048 + sizeof(struct rte_mbuf) + 128, /*pktmbuf size */ 32, /*cache size */ sizeof(struct rte_pktmbuf_pool_private), rte_pktmbuf_pool_init, NULL, rte_pktmbuf_init, NULL, 0, 0); struct rte_mbuf *pcp_buf = rte_pktmbuf_alloc(pktmbuf_pool); uint16_t pcp_tci = htons(0x2000); /* PCP is the upper 3 bits of the TCI */ vport_init(); /* Set the packet length - after the VLAN tag has been inserted, * the value should increase by 4 bytes (i.e. the length of the tag) */ pcp_buf->pkt.pkt_len = 64; action_push_vlan_build(&action_multiple[0], pcp_tci); action_null_build(&action_multiple[1]); short *pkt_data = rte_pktmbuf_mtod(pcp_buf, short *); *(pkt_data + 6) = 0x0008; /* Set Ethertype to 0008, i.e. 0800 in network format */ action_execute(action_multiple, pcp_buf); pkt_data = rte_pktmbuf_mtod(pcp_buf, short *); assert(*(pkt_data + 6) == 0x0081); /* 802.1Q Ethertype has been inserted */ assert(*(pkt_data + 7) == 0x0020); /* TCI value has been inserted */ assert(*(pkt_data + 8) == 0x0008); /* Ethertype has been shifted by 4 bytes */ assert(pcp_buf->pkt.pkt_len == 68);/* Packet length has increased by 4 bytes */ rte_pktmbuf_free(pcp_buf); }
/* * This function takes a packet and routes it as per the flow table. */ static void switch_packet(struct rte_mbuf *pkt, uint8_t in_port) { int pos = 0; struct dpdk_upcall info = {0}; flow_key_extract(pkt, in_port, &info.key); pos = rte_hash_lookup(handle, &info.key); if (pos < 0) { /* flow table miss, send unmatched packet to the daemon */ info.cmd = PACKET_CMD_MISS; send_packet_to_vswitchd(pkt, &info); } else { flow_table_update_stats(pos, pkt); action_execute(pos, pkt); } }
/* * This function takes a packet and routes it as per the flow table. */ void switch_packet(struct rte_mbuf *pkt, uint8_t in_port) { int ret = 0; struct dpdk_upcall info = {0}; struct action action = {0}; flow_key_extract(pkt, in_port, &info.key); ret = flow_table_get_flow(&info.key, &action, NULL); if (ret >= 0) { flow_table_update_stats(&info.key, pkt); action_execute(&action, pkt); } else { /* flow table miss, send unmatched packet to the daemon */ info.cmd = PACKET_CMD_MISS; send_packet_to_vswitchd(pkt, &info); } }
/* Modify packet ipv4 header */ static void test_action_execute_set_ipv4(int argc, char *argv[]) { struct rte_mempool *pktmbuf_pool; struct action action_multiple[MAX_ACTIONS] = {0}; struct ipv4_hdr *pkt_ipv4; pktmbuf_pool = rte_mempool_create("MProc_pktmbuf_pool", 20, /* num mbufs */ 2048 + sizeof(struct rte_mbuf) + 128, /*pktmbuf size */ 32, /*cache size */ sizeof(struct rte_pktmbuf_pool_private), rte_pktmbuf_pool_init, NULL, rte_pktmbuf_init, NULL, 0, 0); struct rte_mbuf *ipv4_buf = rte_pktmbuf_alloc(pktmbuf_pool); struct ovs_key_ipv4 set_ipv4; set_ipv4.ipv4_tos = 0xFF; vport_init(); action_multiple[0].type = ACTION_SET_IPV4; action_multiple[0].data.ipv4 = set_ipv4; action_null_build(&action_multiple[1]); uint8_t *pktmbuf_data = rte_pktmbuf_mtod(ipv4_buf, uint8_t *); pktmbuf_data += sizeof(struct ether_hdr); pkt_ipv4 = (struct ipv4_hdr *)(pktmbuf_data); pkt_ipv4->type_of_service = 0xaa; action_execute(action_multiple, ipv4_buf); pktmbuf_data = rte_pktmbuf_mtod(ipv4_buf, uint8_t *); pktmbuf_data += sizeof(struct ether_hdr); pkt_ipv4 = (struct ipv4_hdr *)(pktmbuf_data); assert(pkt_ipv4->type_of_service == set_ipv4.ipv4_tos); rte_pktmbuf_free(ipv4_buf); }
/* Try to execute action with three output actions, which should succeed */ static void test_action_execute_multiple_actions__three_output(int argc, char *argv[]) { /* Three different output ports */ /* We need to be able to clone mbufs which requires an * alloc which requires a mempool */ struct rte_mempool *pktmbuf_pool; struct rte_mbuf *mbuf_output = NULL; struct action action_multiple[MAX_ACTIONS] = {0}; int count = 0; pktmbuf_pool = rte_mempool_create("MProc_pktmbuf_pool", 20, /* num mbufs */ 2048 + sizeof(struct rte_mbuf) + 128, /*pktmbuf size */ 32, /*cache size */ sizeof(struct rte_pktmbuf_pool_private), rte_pktmbuf_pool_init, NULL, rte_pktmbuf_init, NULL, 0, 0); mbuf_output = rte_pktmbuf_alloc(pktmbuf_pool); vport_init(); action_output_build(&action_multiple[0], 3); action_output_build(&action_multiple[1], 33); action_output_build(&action_multiple[2], 17); action_null_build(&action_multiple[3]); action_execute(action_multiple, mbuf_output); count = receive_from_vport(3, &mbuf_output); assert(count == 1); count = receive_from_vport(33, &mbuf_output); assert(count == 1); count = receive_from_vport(17, &mbuf_output); assert(count == 1); }
/* Try to execute action with a client interface, which should succeed */ static void test_action_execute_output(int argc, char *argv[]) { struct rte_mbuf buf_multiple[5]; struct rte_mbuf *buf_p_multiple[5]; struct action action_multiple[MAX_ACTIONS] = {0}; int count = 0; uint8_t vportid = 3; buf_p_multiple[0] = &buf_multiple[0]; buf_p_multiple[1] = &buf_multiple[1]; buf_p_multiple[2] = &buf_multiple[2]; buf_p_multiple[3] = &buf_multiple[3]; buf_p_multiple[4] = &buf_multiple[4]; /* client */ vport_init(); action_output_build(&action_multiple[0], vportid); action_null_build(&action_multiple[1]); action_execute(action_multiple, buf_multiple); count = receive_from_vport(vportid, buf_p_multiple); assert(count == 1); assert(buf_p_multiple[1] == &buf_multiple[1]); }
/************************************** Return RET_NOK on error **************************************/ ret_code_t parse_incoming_data(context_t * context, Uint32 command, Uint32 command_size, char * data) { char * value = NULL; char * fullname; char * elements[512]; char * cksum; int i; char * user_name; char * password; if( !context_get_connected(context) && ( command != CMD_REQ_LOGIN && command != CMD_REQ_FILE) ) { werr(LOGUSER,"Request from not authenticated client, close connection"); return RET_NOK; } switch(command) { case CMD_REQ_LOGIN: wlog(LOGDEBUG,"Received CMD_REQ_LOGIN"); user_name = _strsep(&data,NETWORK_DELIMITER); password = _strsep(&data,NETWORK_DELIMITER); if(entry_read_string(PASSWD_TABLE, user_name, &value, PASSWD_KEY_PASSWORD,NULL) == RET_NOK) { return RET_NOK; } if( strcmp(value, password) != 0) { free(value); werr(LOGUSER,"Wrong login for %s",user_name); // send answer network_send_command(context, CMD_SEND_LOGIN_NOK, 0, NULL, false); // force client disconnection return RET_NOK; } else { free(value); if( context_set_username(context, user_name) == RET_NOK ) { return RET_NOK; } context_set_connected(context, true); // send answer network_send_command(context, CMD_SEND_LOGIN_OK, 0, NULL, false); wlog(LOGUSER,"Login successful for user %s",context->user_name); } break; case CMD_REQ_CHARACTER_LIST : wlog(LOGDEBUG,"Received CMD_REQ_CHARACTER_LIST"); character_send_list(context); wlog(LOGDEBUG,"character list sent"); break; case CMD_REQ_FILE : i = 0; elements[i] = _strsep(&data,NETWORK_DELIMITER); while(elements[i]) { i++; elements[i] = _strsep(&data,NETWORK_DELIMITER); } if(elements[0]==NULL || elements[1]==NULL) { werr(LOGDEV,"Received erroneous CMD_REQ_FILE"); break; } wlog(LOGDEBUG,"Received CMD_REQ_FILE for %s",elements[0]); /* compare checksum */ fullname = strconcat(base_directory,"/",elements[0],NULL); cksum = checksum_file(fullname); free(fullname); if( cksum == NULL) { werr(LOGUSER,"Required file %s doesn't exists",elements[0]); break; } if( strcmp(elements[1],cksum) == 0 ) { wlog(LOGDEBUG,"Client has already newest %s file",elements[0]); free(cksum); break; } free(cksum); network_send_file(context,elements[0]); wlog(LOGDEBUG,"File %s sent",elements[0]); break; case CMD_REQ_USER_CHARACTER_LIST : wlog(LOGDEBUG,"Received CMD_REQ_USER_CHARACTER_LIST"); character_user_send_list(context); wlog(LOGDEBUG,"user %s's character list sent",context->user_name); break; case CMD_REQ_START : if( context->in_game == false ) { context->id = strdup(data); context->in_game = true; context_update_from_file(context); context_spread(context); context_request_other_context(context); } wlog(LOGDEBUG,"Received CMD_REQ_START for %s /%s",context->user_name,context->id); break; case CMD_REQ_STOP : wlog(LOGDEBUG,"Received CMD_REQ_STOP for %s /%s",context->user_name,context->id); if( context->in_game == true ) { context->in_game = false; if( context->map ) { free(context->map); } context->map = NULL; if( context->prev_map ) { free(context->prev_map); } context->prev_map = NULL; if( context->id ) { free(context->id); } context->id = NULL; context_spread(context); } break; case CMD_REQ_ACTION : i = 0; elements[i] = NULL; elements[i] = _strsep(&data,NETWORK_DELIMITER); while(elements[i]) { i++; elements[i] = _strsep(&data,NETWORK_DELIMITER); } elements[i+1] = NULL; wlog(LOGDEBUG,"Received CMD_REQ_ACTION %s from %s /%s",elements[0],context->user_name,context->character_name); action_execute(context,elements[0],&elements[1]); break; default: werr(LOGDEV,"Unknown request %d from client",command); return RET_NOK; } return RET_OK; }
/* * Handle packet commands */ static void handle_packet_cmd(struct dpdk_packet_message *request, struct rte_mbuf *pkt) { action_execute(request->actions, pkt); }