void send_arp(struct arp *arp_pkt) { struct rte_mbuf *mbuf = NULL; struct arp *arp_hdr = NULL; struct ether_hdr *eth = NULL; int i; mbuf = get_mbuf(); assert(mbuf != NULL); arp_hdr = (struct arp *)rte_pktmbuf_prepend (mbuf, sizeof(struct arp)); eth = (struct ether_hdr *)rte_pktmbuf_prepend (mbuf, sizeof(struct ether_hdr)); logger(ARP, NORMAL, "Sending arp packet\n"); memcpy(arp_hdr, arp_pkt, sizeof(struct arp)); if(arp_pkt->opcode == ntohs(ARP_REQ)) { logger(ARP, ALL, "Sending arp request"); eth->ether_type = htons(ETHER_TYPE_ARP); for(i=0; i<6; i++) { eth->d_addr.addr_bytes[i] = 0xff; } memcpy(ð->s_addr.addr_bytes[0], arp_pkt->src_hw_add, sizeof(arp_pkt->hw_len)); } if(arp_pkt->opcode == ntohs(ARP_REPLY)) { logger(ARP, ALL, "Sending arp reply"); eth->ether_type = htons(ETHER_TYPE_ARP); for(i=0; i<6; i++) { eth->d_addr.addr_bytes[i] = 0xff; // should not be a brodcast ideally. fix it. } // memcpy(ð->d_addr.addr_bytes[0], arp_pkt->src_hw_add, sizeof(arp_pkt->hw_len)); memcpy(ð->s_addr.addr_bytes[0], arp_pkt->src_hw_add, sizeof(arp_pkt->hw_len)); } send_packet_out(mbuf, 0); }
void sendtcpdata(struct tcb *ptcb, unsigned char *data, int len) { printf("Sending tcp data\n"); static int counter_id = -1; if(counter_id == -1) { counter_id = create_counter("tcp_sent"); } counter_inc(counter_id, len); //uint8_t tcp_len = 0x50 + add_mss_option(mbuf, 1300);// + add_winscale_option(mbuf, 7); struct rte_mbuf *mbuf = get_mbuf(); // remove mbuf from parameters. uint8_t data_len = add_tcp_data(mbuf, data, len); uint8_t option_len = 0;//add_winscale_option(mbuf, 7) + add_mss_option(mbuf, 1300) + add_timestamp_option(mbuf, 203032, 0); uint8_t tcp_len = 20 + option_len; uint8_t pad = (tcp_len%4) ? 4 - (tcp_len % 4): 0; tcp_len += pad; logger(LOG_TCP, NORMAL, "padding option %d for tcb %u\n", pad, ptcb->identifier); char *nop = rte_pktmbuf_prepend (mbuf, pad); // always pad the option to make total size multiple of 4. memset(nop, 0, pad); tcp_len = (tcp_len + 3) / 4; // len is in multiple of 4 bytes; 20 will be 5 tcp_len = tcp_len << 4; // len has upper 4 bits position in tcp header. logger(LOG_TCP, NORMAL, "sending tcp data of len %d total %d for tcb %u\n", data_len, tcp_len, ptcb->identifier); struct tcp_hdr *ptcphdr = (struct tcp_hdr *)rte_pktmbuf_prepend (mbuf, sizeof(struct tcp_hdr)); // printf("head room2 = %d\n", rte_pktmbuf_headroom(mbuf)); if(ptcphdr == NULL) { // printf("tcp header is null\n"); } ptcphdr->src_port = htons(ptcb->dport); ptcphdr->dst_port = htons(ptcb->sport); ptcphdr->sent_seq = htonl(ptcb->next_seq); ptcb->next_seq += data_len; if(((ptcb->tcp_flags & TCP_FLAG_SYN) == TCP_FLAG_SYN) || ((ptcb->tcp_flags & TCP_FLAG_FIN) == TCP_FLAG_FIN)) { logger(LOG_TCP, NORMAL, "Increasing seq number by one for flag syn or fin for tcb %u\n", ptcb->identifier); ptcb->next_seq += 1; } logger(LOG_TCP, LOG_LEVEL_NORMAL, "Next seq number is %u flags %u for tcb %u\n", ptcb->next_seq, ptcb->tcp_flags, ptcb->identifier); ptcphdr->recv_ack = htonl(ptcb->ack); ptcphdr->data_off = tcp_len; ptcphdr->tcp_flags = ptcb->tcp_flags; ptcphdr->rx_win = 12000; ptcphdr->cksum = 0x0000; ptcphdr->tcp_urp = 0; ptcb->tcp_flags = 0; //reset the flags as we have sent them in packet now. //mbuf->ol_flags |= PKT_TX_IP_CKSUM; // someday will calclate checkum here only. // printf(" null\n"); // fflush(stdout); logger(LOG_TCP, NORMAL, "[SENDING TCP PACKET] sending tcp packet seq %u ack %u and datalen %u for tcb %u\n", ntohl(ptcphdr->sent_seq), ntohl(ptcphdr->recv_ack), data_len, ptcb->identifier); // push the mbuf in send_window unacknowledged data and increase the refrence count of this segment also start the rto timer for this tcb. PushDataToSendWindow(ptcb, mbuf, ntohl(ptcphdr->sent_seq), ptcb->next_seq, data_len); ip_out(ptcb, mbuf, ptcphdr, data_len); }
//smallboy: We change the whole func here; int ip_local_out(struct sk_buff *skb) { //us_nic_port *port = NULL; //port = get_local_out_port(skb); //if (port == NULL ){ // IP_INC_STATS_BH(skb->pnet, IPSTATS_MIB_OUTNOROUTES); // return US_ENETUNREACH; //} s32 ret = US_RET_OK; u32 n ; struct rte_mbuf *mbuf = (struct rte_mbuf*)(skb->head); struct net *pnet = skb->pnet; if(skb->nohdr ){ if( skb->nf_trace || skb->used > 0 ){ rte_pktmbuf_prepend(mbuf, skb->mac_len); } mbuf_rebuild(skb , pnet->port); //ret = ip_send_out(pnet,mbuf,skb); //smallboy: unkown error here; ip traunked; ??? recv_pkt_dump(&mbuf, 1); n = rte_eth_tx_burst(pnet->port_id, pnet->send_queue_id , &mbuf, 1); if(n < 1){ US_ERR("TH:%u ,tx_burst failed on skb_id:%u sk_id:%u \n" ,US_GET_LCORE(),skb->skb_id,skb->sk->sk_id); IP_ADD_STATS(skb->pnet,IPSTATS_MIB_OUTDISCARDS , 1); ret = US_ENETDOWN; }else{ ret = US_RET_OK; IP_ADD_STATS(skb->pnet,IPSTATS_MIB_OUTPKTS , 1); //skb->gso_segs == 1; } if(skb->users == 1){ //smallboy: More attention about the users,clone,used and nf_trace; __kfree_skb(skb,US_MBUF_FREE_BY_OTHER); //users == 1; not cloned; or errors here; }else{ if(ret == US_RET_OK) //smallboy: data send failed; No recover the users too; skb->users--; skb->used++; skb_reset_data_header(skb); } }else{ if(skb_can_gso(skb)){ ret = ip_send_out_batch(skb,pnet); } if(skb->users == 1){ //smallboy: More attention about the users,clone,used and nf_trace; __kfree_skb(skb,US_MBUF_FREE_BY_STACK); //users == 1; not cloned; or errors here; }else{ if(ret == US_RET_OK) skb->users--; skb->used++; skb_reset_data_header(skb); } } return ret; }
/* * Push&pop operations */ rofl_result_t push_datapacket_offset(datapacket_dpdk_t *dpkt, unsigned int offset, unsigned int num_of_bytes){ uint8_t *src_ptr = get_buffer_dpdk(dpkt); uint8_t *dst_ptr = (uint8_t*)rte_pktmbuf_prepend(dpkt->mbuf, num_of_bytes); //NOTE dst_ptr = src_ptr - num_of_bytes if( NULL==dst_ptr ) return ROFL_FAILURE; if(false==rte_pktmbuf_is_contiguous(dpkt->mbuf)){ assert(0); return ROFL_FAILURE; } // move header num_of_bytes backward memmove(dst_ptr, src_ptr, offset); #ifndef NDEBUG // initialize new pushed memory area with 0x00 memset(dst_ptr + offset, 0x00, num_of_bytes); #endif dpkt->clas_state.base = get_buffer_dpdk(dpkt); dpkt->clas_state.len = get_buffer_length_dpdk(dpkt); return ROFL_SUCCESS; }
// remove this api. not used now void sendfin(struct tcb *ptcb) { struct rte_mbuf *mbuf = get_mbuf(); uint8_t tcp_len = 20 ; tcp_len = (tcp_len + 3) / 4; // len is in multiple of 4 bytes; 20 will be 5 tcp_len = tcp_len << 4; // len has upper 4 bits position in tcp header. logger(LOG_TCP, NORMAL, "sending tcp packet\n"); struct tcp_hdr *ptcphdr = (struct tcp_hdr *)rte_pktmbuf_prepend (mbuf, sizeof(struct tcp_hdr)); // printf("head room2 = %d\n", rte_pktmbuf_headroom(mbuf)); if(ptcphdr == NULL) { // printf("tcp header is null\n"); } ptcphdr->src_port = htons(ptcb->dport); ptcphdr->dst_port = htons(ptcb->sport); ptcphdr->sent_seq = htonl(ptcb->next_seq); ptcb->next_seq ++; // for fin ptcphdr->recv_ack = htonl(ptcb->ack); ptcphdr->data_off = tcp_len; ptcphdr->tcp_flags = ptcb->tcp_flags | TCP_FLAG_FIN; ptcphdr->rx_win = 12000; // ptcphdr->cksum = 0x0001; ptcphdr->tcp_urp = 0; //mbuf->ol_flags |= PKT_TX_IP_CKSUM; // someday will calclate checkum here only. // printf(" null\n"); // fflush(stdout); ip_out(ptcb, mbuf, ptcphdr, 0); }
int send_arp_request(unsigned char *src_pr_add, unsigned char *dst_pr_add) { int i; struct rte_mbuf *new_mbuf = get_mbuf(); struct arp *arp_reply = (struct arp *)rte_pktmbuf_prepend (new_mbuf, sizeof(struct arp)); char mac[6]; // http://www.tcpipguide.com/free/t_ARPMessageFormat.htm arp_reply->hw_type = htons(HW_TYPE_ETHERNET); arp_reply->pr_type = htons(SW_TYPE_IPV4); arp_reply->hw_len = HW_LEN_ETHER; arp_reply->pr_len = PR_LEN_IPV4; arp_reply->opcode = htons(1); unsigned char dest_mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; uint32_t ip_add = GetIntAddFromChar(src_pr_add, 1); struct Interface *temp = NULL; temp = InterfaceList; while(temp && ip_add != GetIntAddFromChar(temp->IP, 1)) { temp = temp->Next; } if(temp == NULL) { logger(ARP, NORMAL, "Arp request failed, address not hosted\n"); return 0; } logger(ARP, NORMAL, "IP found in interface list\n"); int status = GetInterfaceMac(temp->InterfaceNumber, mac); memcpy(arp_reply->src_hw_add, mac, HW_LEN_ETHER); memcpy(arp_reply->dst_hw_add, dest_mac, HW_LEN_ETHER); memcpy(arp_reply->src_pr_add, src_pr_add, PR_LEN_IPV4); memcpy(arp_reply->dst_pr_add, dst_pr_add, PR_LEN_IPV4); send_arp(arp_reply); }
uint8_t add_winscale_option(struct rte_mbuf *mbuf, uint8_t value) { struct tcp_winscale_option *option = (struct tcp_winscale_option *)rte_pktmbuf_prepend (mbuf, sizeof(struct tcp_winscale_option)); option->type = 3; option->len = 3; option->value = value; return 3; }
uint8_t add_mss_option(struct rte_mbuf *mbuf, uint16_t mss_value) { struct tcp_mss_option *mss_option = (struct tcp_mss_option *)rte_pktmbuf_prepend (mbuf, sizeof(struct tcp_mss_option)); mss_option->type = 2; mss_option->len = 4; mss_option->value = htons(mss_value); return 4; // 1 * 4 bytes }
uint8_t add_timestamp_option(struct rte_mbuf *mbuf, uint32_t value, uint32_t echo) { struct tcp_timestamp_option *option = (struct tcp_timestamp_option *)rte_pktmbuf_prepend (mbuf, sizeof(struct tcp_timestamp_option)); option->type = 8; option->len = 10; option->value = value; option->echo = echo; return 10; }
static inline void app_pkt_metadata_flush(struct rte_mbuf *pkt) { struct app_pkt_metadata *pkt_meta = (struct app_pkt_metadata *) RTE_MBUF_METADATA_UINT8_PTR(pkt, 0); struct ether_hdr *ether_hdr = (struct ether_hdr *) rte_pktmbuf_prepend(pkt, (uint16_t) sizeof(struct ether_hdr)); ether_addr_copy(&pkt_meta->nh_arp, ðer_hdr->d_addr); ether_addr_copy(&local_ether_addr, ðer_hdr->s_addr); ether_hdr->ether_type = rte_bswap16(ETHER_TYPE_IPv4); pkt->pkt.vlan_macip.f.l2_len = sizeof(struct ether_hdr); }
/* * Function sends unmatched packets to vswitchd. */ void send_packet_to_vswitchd(struct rte_mbuf *mbuf, struct dpdk_upcall *info) { int rslt = 0; void *mbuf_ptr = NULL; const uint64_t dpif_send_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * DPIF_SEND_US; uint64_t cur_tsc = 0; uint64_t diff_tsc = 0; static uint64_t prev_tsc = 0; /* send one packet, delete information about segments */ rte_pktmbuf_pkt_len(mbuf) = rte_pktmbuf_data_len(mbuf); /* allocate space before the packet for the upcall info */ mbuf_ptr = rte_pktmbuf_prepend(mbuf, sizeof(*info)); if (mbuf_ptr == NULL) { printf("Cannot prepend upcall info\n"); rte_pktmbuf_free(mbuf); stats_vswitch_tx_drop_increment(INC_BY_1); stats_vport_tx_drop_increment(VSWITCHD, INC_BY_1); return; } rte_memcpy(mbuf_ptr, info, sizeof(*info)); /* send the packet and the upcall info to the daemon */ rslt = rte_ring_mp_enqueue(vswitchd_packet_ring, mbuf); if (rslt < 0) { if (rslt == -ENOBUFS) { rte_pktmbuf_free(mbuf); stats_vswitch_tx_drop_increment(INC_BY_1); stats_vport_tx_drop_increment(VSWITCHD, INC_BY_1); return; } else { stats_vport_overrun_increment(VSWITCHD, INC_BY_1); } } stats_vport_tx_increment(VSWITCHD, INC_BY_1); cur_tsc = rte_rdtsc(); diff_tsc = cur_tsc - prev_tsc; prev_tsc = cur_tsc; /* Only signal the daemon after 100 milliseconds */ if (unlikely(diff_tsc > dpif_send_tsc)) send_signal_to_dpif(); }
void send_reset(struct ipv4_hdr *ip_hdr, struct tcp_hdr *t_hdr) { printf("sending reset\n"); logger(LOG_TCP, LOG_LEVEL_CRITICAL, "sending reset\n"); struct rte_mbuf *mbuf = get_mbuf(); //printf("head room = %d\n", rte_pktmbuf_headroom(mbuf)); // rte_pktmbuf_adj(mbuf, sizeof(struct tcp_hdr) + sizeof(struct ipv4_hdr) + sizeof(struct ether_hdr)); struct tcp_hdr *ptcphdr = (struct tcp_hdr *)rte_pktmbuf_prepend (mbuf, sizeof(struct tcp_hdr)); //printf("head room2 = %d\n", rte_pktmbuf_headroom(mbuf)); if(ptcphdr == NULL) { //printf("tcp header is null\n"); } uint8_t tcp_len = 20 ; tcp_len = (tcp_len + 3) / 4; // len is in multiple of 4 bytes; 20 will be 5 tcp_len = tcp_len << 4; // len has upper 4 bits position in tcp header. // printf("head room2 = %d\n", rte_pktmbuf_headroom(mbuf)); if(ptcphdr == NULL) { // printf("tcp header is null\n"); } ptcphdr->data_off = tcp_len; ptcphdr->src_port = t_hdr->dst_port; ptcphdr->dst_port = t_hdr->src_port; ptcphdr->sent_seq = t_hdr->recv_ack; ptcphdr->recv_ack = 0; ptcphdr->tcp_flags = TCP_FLAG_RST; ptcphdr->rx_win = 12000; ptcphdr->tcp_urp = 0; // struct ipv4_hdr *hdr = (struct ipv4_hdr *)rte_pktmbuf_prepend (mbuf, sizeof(struct ipv4_hdr)); //printf("head room4 = %d\n", rte_pktmbuf_headroom(mbuf)); //printf("ip header is null\n"); // fflush(stdout); struct tcb ptcb; ptcb.identifier = 0; // dummy ptcb.ipv4_dst = ip_hdr->dst_addr; // fix it future , why we have htonl only for src ptcb.ipv4_src = htonl(ip_hdr->src_addr); fflush(stdout); ip_out(&ptcb, mbuf, ptcphdr, 0); }
/* Encapsulate IPv6 packet in QinQ where the QinQ is derived from the IPv6 address */ static inline uint8_t handle_qinq_encap6(struct rte_mbuf *mbuf, struct task_qinq_encap6 *task) { struct qinq_hdr *pqinq = (struct qinq_hdr *)rte_pktmbuf_prepend(mbuf, 2 * sizeof(struct vlan_hdr)); PROX_RUNTIME_ASSERT(pqinq); struct ipv6_hdr *pip6 = (struct ipv6_hdr *)(pqinq + 1); if (pip6->hop_limits) { pip6->hop_limits--; } else { plog_info("TTL = 0 => Dropping\n"); return NO_PORT_AVAIL; } // TODO: optimize to use bulk as intended with the rte_table_library uint64_t pkts_mask = RTE_LEN2MASK(1, uint64_t); uint64_t lookup_hit_mask; struct cpe_data* entries[64]; // TODO: use bulk size rte_table_hash_ext_dosig_ops.f_lookup(task->cpe_table, &mbuf, pkts_mask, &lookup_hit_mask, (void**)entries); if (lookup_hit_mask == 0x1) { /* will also overwrite part of the destination addr */ (*(uint64_t *)pqinq) = entries[0]->mac_port_8bytes; pqinq->svlan.eth_proto = task->qinq_tag; pqinq->cvlan.eth_proto = ETYPE_VLAN; pqinq->svlan.vlan_tci = entries[0]->qinq_svlan; pqinq->cvlan.vlan_tci = entries[0]->qinq_cvlan; pqinq->ether_type = ETYPE_IPv6; /* classification can only be done from this point */ if (task->runtime_flags & TASK_CLASSIFY) { rte_sched_port_pkt_write(mbuf, 0, entries[0]->user, 0, 0, 0); } return 0; } else { plogx_err("Unknown IP " IPv6_BYTES_FMT "\n", IPv6_BYTES(pip6->dst_addr)); return NO_PORT_AVAIL; } }
int ether_out(unsigned char *dst_mac, char *src_mac, uint16_t ether_type, struct rte_mbuf *mbuf) { int i = 0; struct ether_hdr *eth; eth = (struct ether_hdr *)rte_pktmbuf_prepend (mbuf, sizeof(struct ether_hdr)); eth->ether_type = htons(ether_type); for(i=0;i<6;i++) { eth->d_addr.addr_bytes[i] = dst_mac[i]; } // for(i=0;i<6;i++) { eth->s_addr.addr_bytes[0] = 0x6a; eth->s_addr.addr_bytes[1] = 0x9c; eth->s_addr.addr_bytes[2] = 0xba; eth->s_addr.addr_bytes[3] = 0xa0; eth->s_addr.addr_bytes[4] = 0x96; eth->s_addr.addr_bytes[5] = 0x24; // } // fix this this should be automatically detect the network interface id. send_packet_out(mbuf, 0); static int counter_id = -1; if(counter_id == -1) { counter_id = create_counter("sent_rate"); } int data_len = rte_pktmbuf_data_len(mbuf); counter_abs(counter_id, data_len); { static int counter_id = -1; if(counter_id == -1) { counter_id = create_counter("wire_sent"); } int data_len = rte_pktmbuf_data_len(mbuf); counter_inc(counter_id, data_len); } (void) src_mac; // jusat to avoid warning src_mac = NULL; return 0; }
/* * Function sends unmatched packets to vswitchd. */ static void send_packet_to_vswitchd(struct rte_mbuf *mbuf, struct dpdk_upcall *info) { int rslt = 0; struct statistics *vswd_stat = NULL; void *mbuf_ptr = NULL; vswd_stat = &vport_stats[VSWITCHD]; /* send one packet, delete information about segments */ rte_pktmbuf_pkt_len(mbuf) = rte_pktmbuf_data_len(mbuf); /* allocate space before the packet for the upcall info */ mbuf_ptr = rte_pktmbuf_prepend(mbuf, sizeof(*info)); if (mbuf_ptr == NULL) { printf("Cannot prepend upcall info\n"); rte_pktmbuf_free(mbuf); switch_tx_drop++; vswd_stat->tx_drop++; return; } rte_memcpy(mbuf_ptr, info, sizeof(*info)); /* send the packet and the upcall info to the daemon */ rslt = rte_ring_sp_enqueue(vswitch_packet_ring, mbuf); if (rslt < 0) { if (rslt == -ENOBUFS) { rte_pktmbuf_free(mbuf); switch_tx_drop++; vswd_stat->tx_drop++; return; } else { overruns++; } } vswd_stat->tx++; }
void sendtcpack(struct tcb *ptcb, struct rte_mbuf *mbuf, unsigned char *data, int len) { //uint8_t tcp_len = 0x50 + add_mss_option(mbuf, 1300);// + add_winscale_option(mbuf, 7); uint8_t data_len = add_tcp_data(mbuf, data, len); uint8_t option_len = add_winscale_option(mbuf, 7) + add_mss_option(mbuf, 1300) + add_timestamp_option(mbuf, 203032, 0); uint8_t tcp_len = 20 + option_len; uint8_t pad = (tcp_len%4) ? 4 - (tcp_len % 4): 0; tcp_len += pad; logger(LOG_TCP, NORMAL, "padding option %d\n", pad); char *nop = rte_pktmbuf_append (mbuf, pad); // always pad the option to make total size multiple of 4. memset(nop, 0, pad); tcp_len = (tcp_len + 3) / 4; // len is in multiple of 4 bytes; 20 will be 5 tcp_len = tcp_len << 4; // len has upper 4 bits position in tcp header. logger(LOG_TCP, NORMAL, "sending tcp packet\n"); struct tcp_hdr *ptcphdr = (struct tcp_hdr *)rte_pktmbuf_prepend (mbuf, sizeof(struct tcp_hdr)); // printf("head room2 = %d\n", rte_pktmbuf_headroom(mbuf)); if(ptcphdr == NULL) { // printf("tcp header is null\n"); } ptcphdr->src_port = htons(ptcb->dport); ptcphdr->dst_port = htons(ptcb->sport); ptcphdr->sent_seq = htonl(ptcb->next_seq); ptcb->next_seq += data_len; // ptcb->next_seq ++; // for syn ptcphdr->recv_ack = htonl(ptcb->ack); ptcphdr->data_off = tcp_len; ptcphdr->tcp_flags = TCP_FLAG_ACK; ptcphdr->rx_win = 12000; // ptcphdr->cksum = 0x0001; ptcphdr->tcp_urp = 0; //mbuf->ol_flags |= PKT_TX_IP_CKSUM; // someday will calclate checkum here only. // printf(" null\n"); // fflush(stdout); ip_out(ptcb, mbuf, ptcphdr, data_len); }
int ether_out(unsigned char *dst_mac, char *src_mac, uint16_t ether_type, struct rte_mbuf *mbuf) { int i = 0; struct ether_hdr *eth; eth = (struct ether_hdr *)rte_pktmbuf_prepend (mbuf, sizeof(struct ether_hdr)); eth->ether_type = htons(ether_type); for(i=0;i<6;i++) { eth->d_addr.addr_bytes[i] = dst_mac[i]; } // for(i=0;i<6;i++) { eth->s_addr.addr_bytes[0] = 0x6a; eth->s_addr.addr_bytes[1] = 0x9c; eth->s_addr.addr_bytes[2] = 0xba; eth->s_addr.addr_bytes[3] = 0xa0; eth->s_addr.addr_bytes[4] = 0x96; eth->s_addr.addr_bytes[5] = 0x24; // } // fix this this should be automatically detect the port id. send_packet_out(mbuf, 0); (void) src_mac; // jusat to avoid warning src_mac = NULL; return 0; }
static int test_blockcipher_one_case(const struct blockcipher_test_case *t, struct rte_mempool *mbuf_pool, struct rte_mempool *op_mpool, uint8_t dev_id, enum rte_cryptodev_type cryptodev_type, char *test_msg) { struct rte_mbuf *ibuf = NULL; struct rte_mbuf *obuf = NULL; struct rte_mbuf *iobuf; struct rte_crypto_sym_xform *cipher_xform = NULL; struct rte_crypto_sym_xform *auth_xform = NULL; struct rte_crypto_sym_xform *init_xform = NULL; struct rte_crypto_sym_op *sym_op = NULL; struct rte_crypto_op *op = NULL; struct rte_cryptodev_sym_session *sess = NULL; struct rte_cryptodev_info dev_info; int status = TEST_SUCCESS; const struct blockcipher_test_data *tdata = t->test_data; uint8_t cipher_key[tdata->cipher_key.len]; uint8_t auth_key[tdata->auth_key.len]; uint32_t buf_len = tdata->ciphertext.len; uint32_t digest_len = 0; char *buf_p = NULL; uint8_t src_pattern = 0xa5; uint8_t dst_pattern = 0xb6; uint8_t tmp_src_buf[MBUF_SIZE]; uint8_t tmp_dst_buf[MBUF_SIZE]; int nb_segs = 1; if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_SG) { rte_cryptodev_info_get(dev_id, &dev_info); if (!(dev_info.feature_flags & RTE_CRYPTODEV_FF_MBUF_SCATTER_GATHER)) { printf("Device doesn't support scatter-gather. " "Test Skipped.\n"); return 0; } nb_segs = 3; } if (tdata->cipher_key.len) memcpy(cipher_key, tdata->cipher_key.data, tdata->cipher_key.len); if (tdata->auth_key.len) memcpy(auth_key, tdata->auth_key.data, tdata->auth_key.len); switch (cryptodev_type) { case RTE_CRYPTODEV_QAT_SYM_PMD: case RTE_CRYPTODEV_OPENSSL_PMD: case RTE_CRYPTODEV_ARMV8_PMD: /* Fall through */ digest_len = tdata->digest.len; break; case RTE_CRYPTODEV_AESNI_MB_PMD: case RTE_CRYPTODEV_SCHEDULER_PMD: digest_len = tdata->digest.truncated_len; break; default: snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, "line %u FAILED: %s", __LINE__, "Unsupported PMD type"); status = TEST_FAILED; goto error_exit; } /* preparing data */ if (t->op_mask & BLOCKCIPHER_TEST_OP_CIPHER) buf_len += tdata->iv.len; if (t->op_mask & BLOCKCIPHER_TEST_OP_AUTH) buf_len += digest_len; /* for contiguous mbuf, nb_segs is 1 */ ibuf = create_segmented_mbuf(mbuf_pool, tdata->ciphertext.len, nb_segs, src_pattern); if (ibuf == NULL) { snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, "line %u FAILED: %s", __LINE__, "Cannot create source mbuf"); status = TEST_FAILED; goto error_exit; } /* only encryption requires plaintext.data input, * decryption/(digest gen)/(digest verify) use ciphertext.data * to be computed */ if (t->op_mask & BLOCKCIPHER_TEST_OP_ENCRYPT) pktmbuf_write(ibuf, 0, tdata->plaintext.len, tdata->plaintext.data); else pktmbuf_write(ibuf, 0, tdata->ciphertext.len, tdata->ciphertext.data); if (t->op_mask & BLOCKCIPHER_TEST_OP_CIPHER) { rte_memcpy(rte_pktmbuf_prepend(ibuf, tdata->iv.len), tdata->iv.data, tdata->iv.len); } buf_p = rte_pktmbuf_append(ibuf, digest_len); if (t->op_mask & BLOCKCIPHER_TEST_OP_AUTH_VERIFY) rte_memcpy(buf_p, tdata->digest.data, digest_len); else memset(buf_p, 0, digest_len); if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_OOP) { obuf = rte_pktmbuf_alloc(mbuf_pool); if (!obuf) { snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, "line %u " "FAILED: %s", __LINE__, "Allocation of rte_mbuf failed"); status = TEST_FAILED; goto error_exit; } memset(obuf->buf_addr, dst_pattern, obuf->buf_len); buf_p = rte_pktmbuf_append(obuf, buf_len); if (!buf_p) { snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, "line %u " "FAILED: %s", __LINE__, "No room to append mbuf"); status = TEST_FAILED; goto error_exit; } memset(buf_p, 0, buf_len); } /* Generate Crypto op data structure */ op = rte_crypto_op_alloc(op_mpool, RTE_CRYPTO_OP_TYPE_SYMMETRIC); if (!op) { snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, "line %u FAILED: %s", __LINE__, "Failed to allocate symmetric crypto " "operation struct"); status = TEST_FAILED; goto error_exit; } sym_op = op->sym; sym_op->m_src = ibuf; if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_OOP) { sym_op->m_dst = obuf; iobuf = obuf; } else { sym_op->m_dst = NULL; iobuf = ibuf; } /* sessionless op requires allocate xform using * rte_crypto_op_sym_xforms_alloc(), otherwise rte_zmalloc() * is used */ if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_SESSIONLESS) { uint32_t n_xforms = 0; if (t->op_mask & BLOCKCIPHER_TEST_OP_CIPHER) n_xforms++; if (t->op_mask & BLOCKCIPHER_TEST_OP_AUTH) n_xforms++; if (rte_crypto_op_sym_xforms_alloc(op, n_xforms) == NULL) { snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, "line %u " "FAILED: %s", __LINE__, "Failed to " "allocate space for crypto transforms"); status = TEST_FAILED; goto error_exit; } } else { cipher_xform = rte_zmalloc(NULL, sizeof(struct rte_crypto_sym_xform), 0); auth_xform = rte_zmalloc(NULL, sizeof(struct rte_crypto_sym_xform), 0); if (!cipher_xform || !auth_xform) { snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, "line %u " "FAILED: %s", __LINE__, "Failed to " "allocate memory for crypto transforms"); status = TEST_FAILED; goto error_exit; } } /* preparing xform, for sessioned op, init_xform is initialized * here and later as param in rte_cryptodev_sym_session_create() call */ if (t->op_mask == BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN) { if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_SESSIONLESS) { cipher_xform = op->sym->xform; auth_xform = cipher_xform->next; auth_xform->next = NULL; } else { cipher_xform->next = auth_xform; auth_xform->next = NULL; init_xform = cipher_xform; } } else if (t->op_mask == BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC) { if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_SESSIONLESS) { auth_xform = op->sym->xform; cipher_xform = auth_xform->next; cipher_xform->next = NULL; } else { auth_xform->next = cipher_xform; cipher_xform->next = NULL; init_xform = auth_xform; } } else if ((t->op_mask == BLOCKCIPHER_TEST_OP_ENCRYPT) || (t->op_mask == BLOCKCIPHER_TEST_OP_DECRYPT)) { if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_SESSIONLESS) cipher_xform = op->sym->xform; else init_xform = cipher_xform; cipher_xform->next = NULL; } else if ((t->op_mask == BLOCKCIPHER_TEST_OP_AUTH_GEN) || (t->op_mask == BLOCKCIPHER_TEST_OP_AUTH_VERIFY)) { if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_SESSIONLESS) auth_xform = op->sym->xform; else init_xform = auth_xform; auth_xform->next = NULL; } else { snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, "line %u FAILED: %s", __LINE__, "Unrecognized operation"); status = TEST_FAILED; goto error_exit; } /*configure xforms & sym_op cipher and auth data*/ if (t->op_mask & BLOCKCIPHER_TEST_OP_CIPHER) { cipher_xform->type = RTE_CRYPTO_SYM_XFORM_CIPHER; cipher_xform->cipher.algo = tdata->crypto_algo; if (t->op_mask & BLOCKCIPHER_TEST_OP_ENCRYPT) cipher_xform->cipher.op = RTE_CRYPTO_CIPHER_OP_ENCRYPT; else cipher_xform->cipher.op = RTE_CRYPTO_CIPHER_OP_DECRYPT; cipher_xform->cipher.key.data = cipher_key; cipher_xform->cipher.key.length = tdata->cipher_key.len; sym_op->cipher.data.offset = tdata->iv.len; sym_op->cipher.data.length = tdata->ciphertext.len; sym_op->cipher.iv.data = rte_pktmbuf_mtod(sym_op->m_src, uint8_t *); sym_op->cipher.iv.length = tdata->iv.len; sym_op->cipher.iv.phys_addr = rte_pktmbuf_mtophys( sym_op->m_src); }
/* * test data manipulation in mbuf */ static int test_one_pktmbuf(void) { struct rte_mbuf *m = NULL; char *data, *data2, *hdr; unsigned i; printf("Test pktmbuf API\n"); /* alloc a mbuf */ m = rte_pktmbuf_alloc(pktmbuf_pool); if (m == NULL) GOTO_FAIL("Cannot allocate mbuf"); if (rte_pktmbuf_pkt_len(m) != 0) GOTO_FAIL("Bad length"); rte_pktmbuf_dump(m, 0); /* append data */ data = rte_pktmbuf_append(m, MBUF_TEST_DATA_LEN); if (data == NULL) GOTO_FAIL("Cannot append data"); if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN) GOTO_FAIL("Bad pkt length"); if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN) GOTO_FAIL("Bad data length"); memset(data, 0x66, rte_pktmbuf_pkt_len(m)); if (!rte_pktmbuf_is_contiguous(m)) GOTO_FAIL("Buffer should be continuous"); rte_pktmbuf_dump(m, MBUF_TEST_DATA_LEN); rte_pktmbuf_dump(m, 2*MBUF_TEST_DATA_LEN); /* this append should fail */ data2 = rte_pktmbuf_append(m, (uint16_t)(rte_pktmbuf_tailroom(m) + 1)); if (data2 != NULL) GOTO_FAIL("Append should not succeed"); /* append some more data */ data2 = rte_pktmbuf_append(m, MBUF_TEST_DATA_LEN2); if (data2 == NULL) GOTO_FAIL("Cannot append data"); if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_DATA_LEN2) GOTO_FAIL("Bad pkt length"); if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_DATA_LEN2) GOTO_FAIL("Bad data length"); if (!rte_pktmbuf_is_contiguous(m)) GOTO_FAIL("Buffer should be continuous"); /* trim data at the end of mbuf */ if (rte_pktmbuf_trim(m, MBUF_TEST_DATA_LEN2) < 0) GOTO_FAIL("Cannot trim data"); if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN) GOTO_FAIL("Bad pkt length"); if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN) GOTO_FAIL("Bad data length"); if (!rte_pktmbuf_is_contiguous(m)) GOTO_FAIL("Buffer should be continuous"); /* this trim should fail */ if (rte_pktmbuf_trim(m, (uint16_t)(rte_pktmbuf_data_len(m) + 1)) == 0) GOTO_FAIL("trim should not succeed"); /* prepend one header */ hdr = rte_pktmbuf_prepend(m, MBUF_TEST_HDR1_LEN); if (hdr == NULL) GOTO_FAIL("Cannot prepend"); if (data - hdr != MBUF_TEST_HDR1_LEN) GOTO_FAIL("Prepend failed"); if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_HDR1_LEN) GOTO_FAIL("Bad pkt length"); if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_HDR1_LEN) GOTO_FAIL("Bad data length"); if (!rte_pktmbuf_is_contiguous(m)) GOTO_FAIL("Buffer should be continuous"); memset(hdr, 0x55, MBUF_TEST_HDR1_LEN); /* prepend another header */ hdr = rte_pktmbuf_prepend(m, MBUF_TEST_HDR2_LEN); if (hdr == NULL) GOTO_FAIL("Cannot prepend"); if (data - hdr != MBUF_TEST_ALL_HDRS_LEN) GOTO_FAIL("Prepend failed"); if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_ALL_HDRS_LEN) GOTO_FAIL("Bad pkt length"); if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_ALL_HDRS_LEN) GOTO_FAIL("Bad data length"); if (!rte_pktmbuf_is_contiguous(m)) GOTO_FAIL("Buffer should be continuous"); memset(hdr, 0x55, MBUF_TEST_HDR2_LEN); rte_mbuf_sanity_check(m, RTE_MBUF_PKT, 1); rte_mbuf_sanity_check(m, RTE_MBUF_PKT, 0); rte_pktmbuf_dump(m, 0); /* this prepend should fail */ hdr = rte_pktmbuf_prepend(m, (uint16_t)(rte_pktmbuf_headroom(m) + 1)); if (hdr != NULL) GOTO_FAIL("prepend should not succeed"); /* remove data at beginning of mbuf (adj) */ if (data != rte_pktmbuf_adj(m, MBUF_TEST_ALL_HDRS_LEN)) GOTO_FAIL("rte_pktmbuf_adj failed"); if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN) GOTO_FAIL("Bad pkt length"); if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN) GOTO_FAIL("Bad data length"); if (!rte_pktmbuf_is_contiguous(m)) GOTO_FAIL("Buffer should be continuous"); /* this adj should fail */ if (rte_pktmbuf_adj(m, (uint16_t)(rte_pktmbuf_data_len(m) + 1)) != NULL) GOTO_FAIL("rte_pktmbuf_adj should not succeed"); /* check data */ if (!rte_pktmbuf_is_contiguous(m)) GOTO_FAIL("Buffer should be continuous"); for (i=0; i<MBUF_TEST_DATA_LEN; i++) { if (data[i] != 0x66) GOTO_FAIL("Data corrupted at offset %u", i); } /* free mbuf */ rte_pktmbuf_free(m); m = NULL; return 0; fail: if (m) rte_pktmbuf_free(m); return -1; }