static void test_ofp_packet_input_to_sp(void) { odp_packet_t pkt; odp_event_t ev; int res; my_test_val = TEST_FORWARD_HOOK; /* Call ofp_packet_input using a pkt with destination ip * that does NOT match the local ip on ifnet and NO route is found. * The packet is forwarded to slow path queue. */ if (create_odp_packet_ip4(&pkt, test_frame, sizeof(test_frame), 0, 0)) { CU_FAIL("Fail to create packet"); return; } res = ofp_packet_input(pkt, interface_queue[port], ofp_eth_vlan_processing); CU_ASSERT_EQUAL(res, OFP_PKT_PROCESSED); CU_ASSERT_NOT_EQUAL(ev = odp_queue_deq(ifnet->spq_def), ODP_EVENT_INVALID); CU_ASSERT_EQUAL(odp_queue_deq(ifnet->spq_def), ODP_EVENT_INVALID); CU_ASSERT_EQUAL(odp_queue_deq(ifnet->outq_def), ODP_EVENT_INVALID); if (memcmp(odp_packet_data(odp_packet_from_event(ev)), in_pkt_data, sizeof(test_frame))) CU_FAIL("corrupt data sent to slow path"); odp_packet_free(odp_packet_from_event(ev)); CU_PASS("ofp_packet_input_to_sp"); }
void *ofp_udp_packet_parse(odp_packet_t pkt, int *length, struct ofp_sockaddr *addr, ofp_socklen_t *addrlen) { struct ofp_sockaddr *src_addr = NULL; ofp_socklen_t src_len = 0; struct ofp_udphdr *uh = (struct ofp_udphdr *)odp_packet_l4_ptr(pkt, NULL); int udplen = odp_be_to_cpu_16(uh->uh_ulen) - sizeof(*uh); uint8_t *data = (uint8_t *)(uh + 1); uint8_t *start = odp_packet_data(pkt); if (addr && addrlen) { src_addr = (struct ofp_sockaddr *)odp_packet_l2_ptr(pkt, NULL); if (src_addr->sa_family == OFP_AF_INET) src_len = sizeof(struct ofp_sockaddr_in); else if (src_addr->sa_family == OFP_AF_INET6) src_len = sizeof(struct ofp_sockaddr_in6); else return NULL; memcpy(addr, src_addr, min(*addrlen, src_len)); *addrlen = src_len; } if (data > start) odp_packet_pull_head(pkt, (uint32_t)(data - start)); int pktlen = odp_packet_len(pkt); if (pktlen > udplen) odp_packet_pull_tail(pkt, (uint32_t)(pktlen - udplen)); if (length) *length = udplen; return data; }
static enum ofp_return_code fastpath_local_hook(odp_packet_t pkt, void *arg) { int protocol = *(int *)arg; (void) pkt; if (my_test_val == TEST_LOCAL_HOOK) { CU_ASSERT_EQUAL(protocol, IS_IPV4); CU_ASSERT_EQUAL(odp_packet_len(pkt), sizeof(test_frame)); if (memcmp((uint8_t *)odp_packet_data(pkt) + odp_packet_l3_offset(pkt), in_pkt_data + OFP_ETHER_HDR_LEN, odp_packet_len(pkt) - OFP_ETHER_HDR_LEN)) CU_FAIL("Corrupt data"); return OFP_TEST_LOCAL_HOOK; } else if (my_test_val == TEST_LOCAL_HOOK_GRE) { /* GRE packet is offered to local hook, then after processing to forward hook */ my_test_val = TEST_FORWARD_HOOK; return OFP_PKT_CONTINUE; } else if (my_test_val == TEST_LOCAL_HOOK_GRE_APP) { /* GRE packet is offered to local hook, then after tunnel is not found to GRE hook */ my_test_val = TEST_GRE_HOOK; return OFP_PKT_CONTINUE; } else if (my_test_val == TEST_LOCAL_IPv4_HOOK) return OFP_PKT_CONTINUE; else if (my_test_val == TEST_LOCAL_UDPv4_HOOK) return OFP_PKT_CONTINUE; else return OFP_TEST_FAIL; }
/** * Print odp packets * * @param thr worker id * @param pkt_tbl packets to be print * @param len packet number */ static void print_pkts(int thr, odp_packet_t pkt_tbl[], unsigned len) { odp_packet_t pkt; char *buf; odph_ipv4hdr_t *ip; odph_icmphdr_t *icmp; struct timeval tvrecv; struct timeval tvsend; double rtt; unsigned i; size_t offset; char msg[1024]; int rlen; for (i = 0; i < len; ++i) { pkt = pkt_tbl[i]; rlen = 0; /* only ip pkts */ if (!odp_packet_has_ipv4(pkt)) continue; odp_atomic_inc_u64(&counters.ip); buf = odp_packet_data(pkt); ip = (odph_ipv4hdr_t *)(buf + odp_packet_l3_offset(pkt)); offset = odp_packet_l4_offset(pkt); /* udp */ if (ip->proto == ODPH_IPPROTO_UDP) { odp_atomic_inc_u64(&counters.udp); } /* icmp */ if (ip->proto == ODPH_IPPROTO_ICMP) { icmp = (odph_icmphdr_t *)(buf + offset); /* echo reply */ if (icmp->type == ICMP_ECHOREPLY) { odp_atomic_inc_u64(&counters.icmp); memcpy(&tvsend, buf + offset + ODPH_ICMPHDR_LEN, sizeof(struct timeval)); /* TODO This should be changed to use an * ODP timer API once one exists. */ gettimeofday(&tvrecv, NULL); tv_sub(&tvrecv, &tvsend); rtt = tvrecv.tv_sec*1000 + tvrecv.tv_usec/1000; rlen += sprintf(msg + rlen, "ICMP Echo Reply seq %d time %.1f ", odp_be_to_cpu_16(icmp->un.echo.sequence) , rtt); } else if (icmp->type == ICMP_ECHO) { rlen += sprintf(msg + rlen, "Icmp Echo Request"); } msg[rlen] = '\0'; printf(" [%02i] %s\n", thr, msg); } } }
static void send_arp_request(struct ofp_ifnet *dev, uint32_t gw) { char buf[sizeof(struct ofp_ether_vlan_header) + sizeof(struct ofp_arphdr)]; struct ofp_arphdr *arp; struct ofp_ether_header *e1 = (struct ofp_ether_header *)buf; struct ofp_ether_vlan_header *e2 = (struct ofp_ether_vlan_header *)buf; size_t size; odp_packet_t pkt; memset(buf, 0, sizeof(buf)); memset(e1->ether_dhost, 0xff, OFP_ETHER_ADDR_LEN); memcpy(e1->ether_shost, dev->mac, OFP_ETHER_ADDR_LEN); if (ETH_WITH_VLAN(dev)) { arp = (struct ofp_arphdr *) (e2 + 1); e2->evl_encap_proto = odp_cpu_to_be_16(OFP_ETHERTYPE_VLAN); e2->evl_tag = odp_cpu_to_be_16(dev->vlan); e2->evl_proto = odp_cpu_to_be_16(OFP_ETHERTYPE_ARP); size = sizeof(*arp) + sizeof(*e2); } else { arp = (struct ofp_arphdr *) (e1 + 1); e1->ether_type = odp_cpu_to_be_16(OFP_ETHERTYPE_ARP); size = sizeof(*arp) + sizeof(*e1); } arp->hrd = odp_cpu_to_be_16(OFP_ARPHDR_ETHER); arp->pro = odp_cpu_to_be_16(OFP_ETHERTYPE_IP); arp->hln = OFP_ETHER_ADDR_LEN; arp->pln = sizeof(struct ofp_in_addr); arp->op = odp_cpu_to_be_16(OFP_ARPOP_REQUEST); memcpy(arp->eth_src, e1->ether_shost, OFP_ETHER_ADDR_LEN); arp->ip_src = dev->ip_addr; memcpy(arp->eth_dst, e1->ether_dhost, OFP_ETHER_ADDR_LEN); arp->ip_dst = gw; pkt = ofp_packet_alloc(size); if (pkt == ODP_PACKET_INVALID) { OFP_ERR("ofp_packet_alloc failed"); return; } memcpy(odp_packet_data(pkt), buf, size); if (odp_unlikely(ofp_if_type(dev) == OFP_IFT_VXLAN)) { ofp_vxlan_send_arp_request(pkt, dev); return; } odp_packet_has_eth_set(pkt, 1); odp_packet_has_arp_set(pkt, 1); odp_packet_l2_offset_set(pkt, 0); odp_packet_l3_offset_set(pkt, size - sizeof(struct ofp_arphdr)); if (send_pkt_out(dev, pkt) == OFP_PKT_DROP) odp_packet_free(pkt); }
/** * Set up an icmp packet * * @param pool Buffer pool to create packet in * * @return Handle of created packet * @retval ODP_PACKET_INVALID Packet could not be created */ static odp_packet_t pack_icmp_pkt(odp_pool_t pool) { odp_packet_t pkt; char *buf; odph_ethhdr_t *eth; odph_ipv4hdr_t *ip; odph_icmphdr_t *icmp; struct timeval tval; uint8_t *tval_d; unsigned short seq; args->appl.payload = 56; pkt = odp_packet_alloc(pool, args->appl.payload + ODPH_ICMPHDR_LEN + ODPH_IPV4HDR_LEN + ODPH_ETHHDR_LEN); if (pkt == ODP_PACKET_INVALID) return pkt; buf = odp_packet_data(pkt); /* ether */ odp_packet_l2_offset_set(pkt, 0); eth = (odph_ethhdr_t *)buf; memcpy((char *)eth->src.addr, args->appl.srcmac.addr, ODPH_ETHADDR_LEN); memcpy((char *)eth->dst.addr, args->appl.dstmac.addr, ODPH_ETHADDR_LEN); eth->type = odp_cpu_to_be_16(ODPH_ETHTYPE_IPV4); /* ip */ odp_packet_l3_offset_set(pkt, ODPH_ETHHDR_LEN); ip = (odph_ipv4hdr_t *)(buf + ODPH_ETHHDR_LEN); ip->dst_addr = odp_cpu_to_be_32(args->appl.dstip); ip->src_addr = odp_cpu_to_be_32(args->appl.srcip); ip->ver_ihl = ODPH_IPV4 << 4 | ODPH_IPV4HDR_IHL_MIN; ip->tot_len = odp_cpu_to_be_16(args->appl.payload + ODPH_ICMPHDR_LEN + ODPH_IPV4HDR_LEN); ip->proto = ODPH_IPPROTO_ICMP; seq = odp_atomic_fetch_add_u64(&counters.seq, 1) % 0xffff; ip->id = odp_cpu_to_be_16(seq); ip->chksum = 0; odph_ipv4_csum_update(pkt); /* icmp */ icmp = (odph_icmphdr_t *)(buf + ODPH_ETHHDR_LEN + ODPH_IPV4HDR_LEN); icmp->type = ICMP_ECHO; icmp->code = 0; icmp->un.echo.id = 0; icmp->un.echo.sequence = ip->id; tval_d = (uint8_t *)(buf + ODPH_ETHHDR_LEN + ODPH_IPV4HDR_LEN + ODPH_ICMPHDR_LEN); /* TODO This should be changed to use an * ODP timer API once one exists. */ gettimeofday(&tval, NULL); memcpy(tval_d, &tval, sizeof(struct timeval)); icmp->chksum = 0; icmp->chksum = odp_chksum(icmp, args->appl.payload + ODPH_ICMPHDR_LEN); return pkt; }
static void print_pkt_binary(odp_packet_t pkt) { uint32_t i; uint8_t *pnt = odp_packet_data(pkt); OFP_LOG_NO_CTX_NO_LEVEL("PACKET:\n"); for (i = 0; i < odp_packet_len(pkt); i++) OFP_LOG_NO_CTX_NO_LEVEL("%02hhx ", pnt[i]); OFP_LOG_NO_CTX_NO_LEVEL("\n"); }
static int create_odp_packet_ip4(odp_packet_t *opkt, uint8_t *pkt_data, int plen, uint32_t dst_addr) { odp_pool_t pool; uint8_t *buf; odp_packet_t pkt = ODP_PACKET_INVALID; struct ofp_ip *iphdr; memset(orig_pkt_data, 0x0, sizeof(orig_pkt_data)); pool = odp_pool_lookup("packet_pool"); if (pool == ODP_POOL_INVALID) { fail_with_odp("ODP packet_pool not found\n"); return -1; } pkt = odp_packet_alloc(pool, plen); if (pkt == ODP_PACKET_INVALID) { fail_with_odp("ODP packet alloc failed"); return -1; } buf = odp_packet_data(pkt); if (odp_packet_copy_from_mem(pkt, 0, plen, pkt_data) < 0) { fail_with_odp("Packet data copy failed\n"); return -1; }; iphdr = (struct ofp_ip *)&buf[OFP_ETHER_HDR_LEN]; /* changes to the default packet. Recalculate ip checksum */ if (dst_addr) { iphdr->ip_dst.s_addr = dst_addr; iphdr->ip_sum = 0; iphdr->ip_sum = ofp_cksum_buffer((uint16_t *)iphdr, iphdr->ip_hl<<2); } /* END OF changes to the default packet */ odp_packet_has_eth_set(pkt, 1); odp_packet_has_ipv4_set(pkt, 1); odp_packet_l2_offset_set(pkt, 0); odp_packet_l3_offset_set(pkt, OFP_ETHER_HDR_LEN); odp_packet_l4_offset_set(pkt, OFP_ETHER_HDR_LEN + (iphdr->ip_hl<<2)); *opkt = pkt; memcpy(orig_pkt_data, pkt_data, plen); return 0; }
static odp_packet_t pack_pkt(odp_pool_t pool, odph_ethaddr_t eth_src, odph_ethaddr_t eth_dst, uint32_t ip_src, uint32_t ip_dst, int payload, int is_ip) { odp_packet_t pkt; char *buf; odph_ethhdr_t *eth; odph_ipv4hdr_t *ip; odph_udphdr_t *udp; static unsigned short seq = 0; pkt = odp_packet_alloc(pool, payload + ODPH_UDPHDR_LEN + ODPH_IPV4HDR_LEN + ODPH_ETHHDR_LEN); if (pkt == ODP_PACKET_INVALID) return pkt; buf = odp_packet_data(pkt); /* ether */ odp_packet_l2_offset_set(pkt, 0); eth = (odph_ethhdr_t *)buf; memcpy((char *)eth->src.addr, eth_src.addr, ODPH_ETHADDR_LEN); memcpy((char *)eth->dst.addr, eth_dst.addr, ODPH_ETHADDR_LEN); if ( is_ip ) { eth->type = odp_cpu_to_be_16(ODPH_ETHTYPE_IPV4); odp_packet_l3_offset_set(pkt, ODPH_ETHHDR_LEN); ip = (odph_ipv4hdr_t *)(buf + ODPH_ETHHDR_LEN); ip->dst_addr = odp_cpu_to_be_32(ip_dst); ip->src_addr = odp_cpu_to_be_32(ip_src); ip->ver_ihl = ODPH_IPV4 << 4 | ODPH_IPV4HDR_IHL_MIN; ip->tot_len = odp_cpu_to_be_16(payload + ODPH_UDPHDR_LEN + ODPH_IPV4HDR_LEN); ip->proto = ODPH_IPPROTO_UDP; seq++; ip->id = odp_cpu_to_be_16(seq); ip->chksum = 0; odph_ipv4_csum_update(pkt); odp_packet_l4_offset_set(pkt, ODPH_ETHHDR_LEN + ODPH_IPV4HDR_LEN); udp = (odph_udphdr_t *)(buf + ODPH_ETHHDR_LEN + ODPH_IPV4HDR_LEN); udp->src_port = 0; udp->dst_port = 0; udp->length = odp_cpu_to_be_16(payload + ODPH_UDPHDR_LEN); udp->chksum = 0; udp->chksum = odp_cpu_to_be_16(odph_ipv4_udp_chksum(pkt)); } else { eth->type = odp_cpu_to_be_16(0xbeef); } return pkt; }
void ofp_print_packet(const char *comment, odp_packet_t pkt) { uint8_t *p; uint32_t len; p = odp_packet_data(pkt); len = odp_packet_len(pkt); (void)len; ofp_print_packet_buffer(comment, p); #ifdef PRINT_PACKETS_BINARY print_pkt_binary(pkt); #endif }
/** * set up an udp packet * * @param pool Buffer pool to create packet in * * @return Handle of created packet * @retval ODP_PACKET_INVALID Packet could not be created */ static odp_packet_t pack_udp_pkt(odp_pool_t pool) { odp_packet_t pkt; char *buf; odph_ethhdr_t *eth; odph_ipv4hdr_t *ip; odph_udphdr_t *udp; unsigned short seq; pkt = odp_packet_alloc(pool, args->appl.payload + ODPH_UDPHDR_LEN + ODPH_IPV4HDR_LEN + ODPH_ETHHDR_LEN); if (pkt == ODP_PACKET_INVALID) return pkt; buf = odp_packet_data(pkt); /* ether */ odp_packet_l2_offset_set(pkt, 0); eth = (odph_ethhdr_t *)buf; memcpy((char *)eth->src.addr, args->appl.srcmac.addr, ODPH_ETHADDR_LEN); memcpy((char *)eth->dst.addr, args->appl.dstmac.addr, ODPH_ETHADDR_LEN); eth->type = odp_cpu_to_be_16(ODPH_ETHTYPE_IPV4); /* ip */ odp_packet_l3_offset_set(pkt, ODPH_ETHHDR_LEN); ip = (odph_ipv4hdr_t *)(buf + ODPH_ETHHDR_LEN); ip->dst_addr = odp_cpu_to_be_32(args->appl.dstip); ip->src_addr = odp_cpu_to_be_32(args->appl.srcip); ip->ver_ihl = ODPH_IPV4 << 4 | ODPH_IPV4HDR_IHL_MIN; ip->tot_len = odp_cpu_to_be_16(args->appl.payload + ODPH_UDPHDR_LEN + ODPH_IPV4HDR_LEN); ip->proto = ODPH_IPPROTO_UDP; seq = odp_atomic_fetch_add_u64(&counters.seq, 1) % 0xFFFF; ip->id = odp_cpu_to_be_16(seq); ip->chksum = 0; odph_ipv4_csum_update(pkt); /* udp */ odp_packet_l4_offset_set(pkt, ODPH_ETHHDR_LEN + ODPH_IPV4HDR_LEN); udp = (odph_udphdr_t *)(buf + ODPH_ETHHDR_LEN + ODPH_IPV4HDR_LEN); udp->src_port = 0; udp->dst_port = 0; udp->length = odp_cpu_to_be_16(args->appl.payload + ODPH_UDPHDR_LEN); udp->chksum = 0; udp->chksum = odp_cpu_to_be_16(odph_ipv4_udp_chksum(pkt)); return pkt; }
static void test_ofp_packet_input_gre_orig_pkt_to_sp(void) { odp_packet_t pkt; int res; #ifdef SP odp_event_t ev; #endif my_test_val = TEST_LOCAL_HOOK_GRE_APP; /* Call ofp_packet_input using a GRE pkt with destination ip * that matches the local ip on ifnet, tunnel not found, * packet offered to GRE hook, returns continue. * Full packet sent to slowpath */ ifnet->ip_addr = local_ip; if (create_odp_packet_ip4(&pkt, gre_frame, sizeof(gre_frame), local_ip, tun_rem_ip + 1)) { CU_FAIL("Fail to create packet"); return; } res = ofp_packet_input(pkt, interface_queue[port], ofp_eth_vlan_processing); #ifdef SP CU_ASSERT_EQUAL(res, OFP_PKT_PROCESSED); CU_ASSERT_NOT_EQUAL_FATAL(ev = odp_queue_deq(ifnet->spq_def), ODP_EVENT_INVALID); CU_ASSERT_EQUAL(odp_queue_deq(ifnet->spq_def), ODP_EVENT_INVALID); CU_ASSERT_EQUAL(odp_queue_deq(ifnet->outq_def), ODP_EVENT_INVALID); if (memcmp(odp_packet_data(odp_packet_from_event(ev)), in_pkt_data, sizeof(gre_frame))) CU_FAIL("corrupt data sent to slow path"); odp_packet_free(odp_packet_from_event(ev)); ifnet->ip_addr = 0; CU_PASS("ofp_packet_input_gre_orig_pkt_to_sp"); #else CU_ASSERT_EQUAL(res, OFP_PKT_DROP); CU_ASSERT_EQUAL(odp_queue_deq(ifnet->outq_def), ODP_EVENT_INVALID); #endif }
static uint32_t pktio_init_packet(odp_packet_t pkt) { odph_ethhdr_t *eth; odph_ipv4hdr_t *ip; odph_udphdr_t *udp; char *buf; uint16_t seq; uint8_t mac[ODPH_ETHADDR_LEN] = {0}; int pkt_len = odp_packet_len(pkt); buf = odp_packet_data(pkt); /* Ethernet */ odp_packet_l2_offset_set(pkt, 0); eth = (odph_ethhdr_t *)buf; memcpy(eth->src.addr, mac, ODPH_ETHADDR_LEN); memcpy(eth->dst.addr, mac, ODPH_ETHADDR_LEN); eth->type = odp_cpu_to_be_16(ODPH_ETHTYPE_IPV4); /* IP */ odp_packet_l3_offset_set(pkt, ODPH_ETHHDR_LEN); ip = (odph_ipv4hdr_t *)(buf + ODPH_ETHHDR_LEN); ip->dst_addr = odp_cpu_to_be_32(0x0a000064); ip->src_addr = odp_cpu_to_be_32(0x0a000001); ip->ver_ihl = ODPH_IPV4 << 4 | ODPH_IPV4HDR_IHL_MIN; ip->tot_len = odp_cpu_to_be_16(pkt_len - ODPH_ETHHDR_LEN); ip->ttl = 128; ip->proto = ODPH_IPPROTO_UDP; seq = odp_atomic_fetch_inc_u32(&ip_seq); ip->id = odp_cpu_to_be_16(seq); ip->chksum = 0; odph_ipv4_csum_update(pkt); /* UDP */ odp_packet_l4_offset_set(pkt, ODPH_ETHHDR_LEN + ODPH_IPV4HDR_LEN); udp = (odph_udphdr_t *)(buf + ODPH_ETHHDR_LEN + ODPH_IPV4HDR_LEN); udp->src_port = odp_cpu_to_be_16(12049); udp->dst_port = odp_cpu_to_be_16(12050); udp->length = odp_cpu_to_be_16(pkt_len - ODPH_ETHHDR_LEN - ODPH_IPV4HDR_LEN); udp->chksum = 0; return pktio_pkt_set_seq(pkt); }
/* * Prepare a packet for L2 header prepend and output. The packet is pulled * or pushed as necessary so that there is exactly l2_size bytes in the * beginning of the packet before the data pointed to by the L3 offset. * * After return * - L2 offset is undefined * - L3 offset points to the same data as before the call * - Value of L3 offset is l2_size * - If packet was pushed or pulled, L4 offset is set to l2size + hlen * * Returns pointer to the L3 data or NULL if trimming failed. * */ static inline void *trim_for_output(odp_packet_t pkt, uint32_t l2_size, uint32_t hlen) { void *l2_addr; uint32_t l3_offset = odp_packet_l3_offset(pkt); if (l3_offset == l2_size) { l2_addr = odp_packet_data(pkt); } else if (l3_offset > l2_size) { l2_addr = odp_packet_pull_head(pkt, l3_offset - l2_size); odp_packet_l3_offset_set(pkt, l2_size); odp_packet_l4_offset_set(pkt, l2_size + hlen); } else { l2_addr = odp_packet_push_head(pkt, l2_size - l3_offset); odp_packet_l3_offset_set(pkt, l2_size); odp_packet_l4_offset_set(pkt, l2_size + hlen); } return l2_addr; }
odp_packet_t create_ipv4_packet(stream_db_entry_t *stream, uint8_t *dmac, odp_pool_t pkt_pool) { ipsec_cache_entry_t *entry = NULL; odp_packet_t pkt; uint8_t *base; uint8_t *data; odph_ethhdr_t *eth; odph_ipv4hdr_t *ip; odph_ipv4hdr_t *inner_ip = NULL; odph_ahhdr_t *ah = NULL; odph_esphdr_t *esp = NULL; odph_icmphdr_t *icmp; stream_pkt_hdr_t *test; unsigned i; if (stream->input.entry) entry = stream->input.entry; else if (stream->output.entry) entry = stream->output.entry; /* Get packet */ pkt = odp_packet_alloc(pkt_pool, 0); if (ODP_PACKET_INVALID == pkt) return ODP_PACKET_INVALID; base = odp_packet_data(pkt); data = odp_packet_data(pkt); /* Ethernet */ odp_packet_has_eth_set(pkt, 1); eth = (odph_ethhdr_t *)data; data += sizeof(*eth); memset((char *)eth->src.addr, (0x80 | stream->id), ODPH_ETHADDR_LEN); memcpy((char *)eth->dst.addr, dmac, ODPH_ETHADDR_LEN); eth->type = odp_cpu_to_be_16(ODPH_ETHTYPE_IPV4); /* IPv4 */ odp_packet_has_ipv4_set(pkt, 1); ip = (odph_ipv4hdr_t *)data; data += sizeof(*ip); /* Wait until almost finished to fill in mutable fields */ memset((char *)ip, 0, sizeof(*ip)); ip->ver_ihl = 0x45; ip->id = odp_cpu_to_be_16(stream->id); /* Outer IP header in tunnel mode */ if (entry && entry->mode == IPSEC_SA_MODE_TUNNEL && (entry == stream->input.entry)) { ip->proto = ODPH_IPV4; ip->src_addr = odp_cpu_to_be_32(entry->tun_src_ip); ip->dst_addr = odp_cpu_to_be_32(entry->tun_dst_ip); } else { ip->proto = ODPH_IPPROTO_ICMP; ip->src_addr = odp_cpu_to_be_32(stream->src_ip); ip->dst_addr = odp_cpu_to_be_32(stream->dst_ip); } /* AH (if specified) */ if (entry && (entry == stream->input.entry) && (ODP_AUTH_ALG_NULL != entry->ah.alg)) { if (ODP_AUTH_ALG_MD5_96 != entry->ah.alg) abort(); ah = (odph_ahhdr_t *)data; data += sizeof(*ah); data += entry->ah.icv_len; memset((char *)ah, 0, sizeof(*ah) + entry->ah.icv_len); ah->ah_len = 1 + (entry->ah.icv_len / 4); ah->spi = odp_cpu_to_be_32(entry->ah.spi); ah->seq_no = odp_cpu_to_be_32(stream->input.ah_seq++); } /* ESP (if specified) */ if (entry && (entry == stream->input.entry) && (ODP_CIPHER_ALG_NULL != entry->esp.alg)) { if (ODP_CIPHER_ALG_3DES_CBC != entry->esp.alg) abort(); esp = (odph_esphdr_t *)data; data += sizeof(*esp); data += entry->esp.iv_len; esp->spi = odp_cpu_to_be_32(entry->esp.spi); esp->seq_no = odp_cpu_to_be_32(stream->input.esp_seq++); RAND_bytes(esp->iv, 8); } /* Inner IP header in tunnel mode */ if (entry && (entry == stream->input.entry) && (entry->mode == IPSEC_SA_MODE_TUNNEL)) { inner_ip = (odph_ipv4hdr_t *)data; memset((char *)inner_ip, 0, sizeof(*inner_ip)); inner_ip->ver_ihl = 0x45; inner_ip->proto = ODPH_IPPROTO_ICMP; inner_ip->id = odp_cpu_to_be_16(stream->id); inner_ip->ttl = 64; inner_ip->tos = 0; inner_ip->frag_offset = 0; inner_ip->src_addr = odp_cpu_to_be_32(stream->src_ip); inner_ip->dst_addr = odp_cpu_to_be_32(stream->dst_ip); inner_ip->chksum = odp_chksum(inner_ip, sizeof(*inner_ip)); data += sizeof(*inner_ip); } /* ICMP header so we can see it on wireshark */ icmp = (odph_icmphdr_t *)data; data += sizeof(*icmp); icmp->type = ICMP_ECHO; icmp->code = 0; icmp->un.echo.id = odp_cpu_to_be_16(0x1234); icmp->un.echo.sequence = odp_cpu_to_be_16(stream->created); /* Packet payload of incrementing bytes */ test = (stream_pkt_hdr_t *)data; data += sizeof(*test); test->magic = odp_cpu_to_be_64(STREAM_MAGIC); for (i = 0; i < stream->length; i++) *data++ = (uint8_t)i; /* Close ICMP */ icmp->chksum = 0; icmp->chksum = odp_chksum(icmp, data - (uint8_t *)icmp); /* Close ESP if specified */ if (esp) { int payload_len = data - (uint8_t *)icmp; uint8_t *encrypt_start = (uint8_t *)icmp; if (entry->mode == IPSEC_SA_MODE_TUNNEL) { payload_len = data - (uint8_t *)inner_ip; encrypt_start = (uint8_t *)inner_ip; } int encrypt_len; odph_esptrl_t *esp_t; DES_key_schedule ks1, ks2, ks3; uint8_t iv[8]; memcpy(iv, esp->iv, sizeof(iv)); encrypt_len = ESP_ENCODE_LEN(payload_len + sizeof(*esp_t), entry->esp.block_len); memset(data, 0, encrypt_len - payload_len); data += encrypt_len - payload_len; esp_t = (odph_esptrl_t *)(data) - 1; esp_t->pad_len = encrypt_len - payload_len - sizeof(*esp_t); esp_t->next_header = ip->proto; ip->proto = ODPH_IPPROTO_ESP; DES_set_key((DES_cblock *)&entry->esp.key.data[0], &ks1); DES_set_key((DES_cblock *)&entry->esp.key.data[8], &ks2); DES_set_key((DES_cblock *)&entry->esp.key.data[16], &ks3); DES_ede3_cbc_encrypt(encrypt_start, encrypt_start, encrypt_len, &ks1, &ks2, &ks3, (DES_cblock *)iv, 1); } /* Since ESP can pad we can now fix IP length */ ip->tot_len = odp_cpu_to_be_16(data - (uint8_t *)ip); /* Close AH if specified */ if (ah) { uint8_t hash[EVP_MAX_MD_SIZE]; int auth_len = data - (uint8_t *)ip; ah->next_header = ip->proto; ip->proto = ODPH_IPPROTO_AH; HMAC(EVP_md5(), entry->ah.key.data, entry->ah.key.length, (uint8_t *)ip, auth_len, hash, NULL); memcpy(ah->icv, hash, 12); } /* Correct set packet length offsets */ odp_packet_push_tail(pkt, data - base); odp_packet_l2_offset_set(pkt, (uint8_t *)eth - base); odp_packet_l3_offset_set(pkt, (uint8_t *)ip - base); odp_packet_l4_offset_set(pkt, ((uint8_t *)ip - base) + sizeof(*ip)); /* Now fill in final IP header fields */ ip->ttl = 64; ip->tos = 0; ip->frag_offset = 0; ip->chksum = 0; odph_ipv4_csum_update(pkt); return pkt; }
static void test_ofp_packet_input_forwarding_to_output(void) { odp_packet_t pkt; odp_event_t ev; int res; /* Call ofp_packet_input using a pkt with destination ip * that does NOT match the local ip on ifnet and a route is found. * ARP is found for gateway IP. * Function returns OFP_PKT_PROCESSED and * packet is forwarded to ofp_ip_output.*/ unsigned char ll_addr[13] = "123456789012"; my_test_val = TEST_FORWARD_HOOK; CU_ASSERT_EQUAL( ofp_ipv4_lookup_mac(dst_ipaddr + 1, ll_addr, ifnet), -1); CU_ASSERT_EQUAL( ofp_arp_ipv4_insert(dst_ipaddr + 1, ll_addr, ifnet), 0); if (create_odp_packet_ip4(&pkt, test_frame, sizeof(test_frame), dst_ipaddr, 0)) { CU_FAIL("Fail to create packet"); return; } res = ofp_packet_input(pkt, interface_queue[port], ofp_eth_vlan_processing); CU_ASSERT_EQUAL(res, OFP_PKT_PROCESSED); CU_ASSERT_NOT_EQUAL(ev = odp_queue_deq(ifnet->outq_def), ODP_EVENT_INVALID); CU_ASSERT_EQUAL(odp_queue_deq(ifnet->outq_def), ODP_EVENT_INVALID); #ifdef SP CU_ASSERT_EQUAL(odp_queue_deq(ifnet->spq_def), ODP_EVENT_INVALID); #endif /* SP */ CU_ASSERT_EQUAL(odp_packet_len(pkt), sizeof(test_frame)); pkt = odp_packet_from_event(ev); struct ofp_ip *ip_in_pkt_data = (struct ofp_ip *)(in_pkt_data + OFP_ETHER_HDR_LEN); ip_in_pkt_data->ip_ttl--; #ifdef OFP_PERFORMANCE /*checksum is not filled on ip_output*/ ip_in_pkt_data->ip_sum = ((struct ofp_ip *)odp_packet_l3_ptr(pkt, NULL))->ip_sum; #else ip_in_pkt_data->ip_sum = 0; ip_in_pkt_data->ip_sum = ofp_cksum_buffer((uint16_t *)ip_in_pkt_data, ip_in_pkt_data->ip_hl<<2); #endif if (memcmp((uint8_t *)odp_packet_data(pkt) + odp_packet_l3_offset(pkt), in_pkt_data + OFP_ETHER_HDR_LEN, sizeof(test_frame) - OFP_ETHER_HDR_LEN)) CU_FAIL("corrupt l3 + data forwarded"); struct ofp_ether_header *eth = (struct ofp_ether_header *)odp_packet_l2_ptr(pkt, NULL); if (memcmp(eth->ether_dhost, ll_addr, OFP_ETHER_ADDR_LEN)) CU_FAIL("Bad destination mac address on the forwarded packet"); CU_ASSERT_EQUAL(eth->ether_type, odp_cpu_to_be_16(OFP_ETHERTYPE_IP)); CU_PASS("ofp_packet_input_forwarding_to_output"); }
static void test_ofp_packet_input_gre_processed_inner_pkt_forwarded(void) { odp_packet_t pkt; odp_event_t ev; int res; struct ofp_ether_header *eth; struct ofp_ip *ip; struct ofp_ip *ip_encap; uint32_t dst_ip; uint8_t dst_mac_addr[6] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; my_test_val = TEST_LOCAL_HOOK_GRE; /* Call ofp_packet_input using a GRE pkt with destination ip * that matches the local ip on ifnet, tunnel found, GRE processed. * Inner packet does not match local ip, route found, * packet forwarded */ ifnet->ip_addr = local_ip; if (create_odp_packet_ip4(&pkt, gre_frame, sizeof(gre_frame), local_ip, tun_rem_ip)) { CU_FAIL("Fail to create packet"); return; } ip_encap = (struct ofp_ip *)&in_pkt_data[38]; dst_ip = local_ip + 10; test_ofp_add_route(port, vrf, vlan, ip_encap->ip_dst.s_addr, 24, 4, dst_ip); ofp_arp_ipv4_insert(dst_ip, dst_mac_addr, ifnet); res = ofp_packet_input(pkt, interface_queue[port], ofp_eth_vlan_processing); CU_ASSERT_EQUAL(res, OFP_PKT_PROCESSED); CU_ASSERT_NOT_EQUAL_FATAL(ev = odp_queue_deq(ifnet->outq_def), ODP_EVENT_INVALID); #ifdef SP CU_ASSERT_EQUAL(odp_queue_deq(ifnet->spq_def), ODP_EVENT_INVALID); #endif CU_ASSERT_EQUAL(odp_queue_deq(ifnet->outq_def), ODP_EVENT_INVALID); pkt = odp_packet_from_event(ev); eth = odp_packet_data(pkt); ip = odp_packet_l3_ptr(pkt, NULL); if (memcmp(eth->ether_dhost, dst_mac_addr, OFP_ETHER_ADDR_LEN)) CU_FAIL("Bad destination mac address."); if (memcmp(eth->ether_shost, ifnet->mac, OFP_ETHER_ADDR_LEN)) CU_FAIL("Bad source mac address."); CU_ASSERT_EQUAL(ip->ip_src.s_addr, ip_encap->ip_src.s_addr); CU_ASSERT_EQUAL(ip->ip_dst.s_addr, ip_encap->ip_dst.s_addr); if (memcmp(ip + (ip->ip_hl << 2), ip_encap + (ip->ip_hl << 2), odp_be_to_cpu_16(ip_encap->ip_len) - (ip->ip_hl << 2))) CU_FAIL("corrupt l3 + data"); odp_packet_free(odp_packet_from_event(ev)); ifnet->ip_addr = 0; CU_PASS("ofp_packet_input_gre_processed_inner_pkt_to_sp"); }
/* * Generate a single test packet for transmission. */ static odp_packet_t pktio_create_packet(void) { odp_packet_t pkt; odph_ethhdr_t *eth; odph_ipv4hdr_t *ip; odph_udphdr_t *udp; char *buf; uint16_t seq; uint32_t offset; pkt_head_t pkt_hdr; size_t payload_len; uint8_t mac[ODPH_ETHADDR_LEN] = {0}; payload_len = sizeof(pkt_hdr) + gbl_args->args.pkt_len; pkt = odp_packet_alloc(transmit_pkt_pool, payload_len + ODPH_UDPHDR_LEN + ODPH_IPV4HDR_LEN + ODPH_ETHHDR_LEN); if (pkt == ODP_PACKET_INVALID) return ODP_PACKET_INVALID; buf = odp_packet_data(pkt); /* Ethernet */ offset = 0; odp_packet_l2_offset_set(pkt, offset); eth = (odph_ethhdr_t *)buf; memcpy(eth->src.addr, mac, ODPH_ETHADDR_LEN); memcpy(eth->dst.addr, mac, ODPH_ETHADDR_LEN); eth->type = odp_cpu_to_be_16(ODPH_ETHTYPE_IPV4); /* IP */ offset += ODPH_ETHHDR_LEN; odp_packet_l3_offset_set(pkt, ODPH_ETHHDR_LEN); ip = (odph_ipv4hdr_t *)(buf + ODPH_ETHHDR_LEN); ip->dst_addr = odp_cpu_to_be_32(0); ip->src_addr = odp_cpu_to_be_32(0); ip->ver_ihl = ODPH_IPV4 << 4 | ODPH_IPV4HDR_IHL_MIN; ip->tot_len = odp_cpu_to_be_16(payload_len + ODPH_UDPHDR_LEN + ODPH_IPV4HDR_LEN); ip->ttl = 128; ip->proto = ODPH_IPPROTO_UDP; seq = odp_atomic_fetch_inc_u32(&ip_seq); ip->id = odp_cpu_to_be_16(seq); ip->chksum = 0; odph_ipv4_csum_update(pkt); /* UDP */ offset += ODPH_IPV4HDR_LEN; odp_packet_l4_offset_set(pkt, offset); udp = (odph_udphdr_t *)(buf + offset); udp->src_port = odp_cpu_to_be_16(0); udp->dst_port = odp_cpu_to_be_16(0); udp->length = odp_cpu_to_be_16(payload_len + ODPH_UDPHDR_LEN); udp->chksum = 0; /* payload */ offset += ODPH_UDPHDR_LEN; pkt_hdr.magic = TEST_HDR_MAGIC; if (odp_packet_copydata_in(pkt, offset, sizeof(pkt_hdr), &pkt_hdr) != 0) LOG_ABORT("Failed to generate test packet.\n"); return pkt; }
/* Basic algorithm run function for async inplace mode. * Creates a session from input parameters and runs one operation * on input_vec. Checks the output of the crypto operation against * output_vec. Operation completion event is dequeued polling the * session output queue. Completion context pointer is retrieved * and checked against the one set before the operation. * Completion event can be a separate buffer or the input packet * buffer can be used. * */ static void alg_test(enum odp_crypto_op op, enum odp_cipher_alg cipher_alg, odp_crypto_iv_t ses_iv, uint8_t *op_iv_ptr, odp_crypto_key_t cipher_key, enum odp_auth_alg auth_alg, odp_crypto_key_t auth_key, uint8_t *input_vec, unsigned int input_vec_len, uint8_t *output_vec, unsigned int output_vec_len) { odp_crypto_session_t session; int rc; enum odp_crypto_ses_create_err status; odp_bool_t posted; odp_event_t event; odp_crypto_compl_t compl_event; odp_crypto_op_result_t result; /* Create a crypto session */ odp_crypto_session_params_t ses_params; memset(&ses_params, 0, sizeof(ses_params)); ses_params.op = op; ses_params.auth_cipher_text = false; ses_params.pref_mode = suite_context.pref_mode; ses_params.cipher_alg = cipher_alg; ses_params.auth_alg = auth_alg; ses_params.compl_queue = suite_context.queue; ses_params.output_pool = suite_context.pool; ses_params.cipher_key = cipher_key; ses_params.iv = ses_iv; ses_params.auth_key = auth_key; rc = odp_crypto_session_create(&ses_params, &session, &status); CU_ASSERT(!rc); CU_ASSERT(status == ODP_CRYPTO_SES_CREATE_ERR_NONE); CU_ASSERT(odp_crypto_session_to_u64(session) != odp_crypto_session_to_u64(ODP_CRYPTO_SESSION_INVALID)); /* Prepare input data */ odp_packet_t pkt = odp_packet_alloc(suite_context.pool, input_vec_len); CU_ASSERT(pkt != ODP_PACKET_INVALID); uint8_t *data_addr = odp_packet_data(pkt); memcpy(data_addr, input_vec, input_vec_len); const int data_off = 0; /* Prepare input/output params */ odp_crypto_op_params_t op_params; memset(&op_params, 0, sizeof(op_params)); op_params.session = session; op_params.pkt = pkt; op_params.out_pkt = pkt; op_params.ctx = (void *)0xdeadbeef; if (cipher_alg != ODP_CIPHER_ALG_NULL && auth_alg == ODP_AUTH_ALG_NULL) { op_params.cipher_range.offset = data_off; op_params.cipher_range.length = input_vec_len; if (op_iv_ptr) op_params.override_iv_ptr = op_iv_ptr; } else if (cipher_alg == ODP_CIPHER_ALG_NULL && auth_alg != ODP_AUTH_ALG_NULL) { op_params.auth_range.offset = data_off; op_params.auth_range.length = input_vec_len; op_params.hash_result_offset = data_off; } else { CU_FAIL("%s : not implemented for combined alg mode\n"); } rc = odp_crypto_operation(&op_params, &posted, &result); if (rc < 0) { CU_FAIL("Failed odp_crypto_operation()"); goto cleanup; } if (posted) { /* Poll completion queue for results */ do { event = odp_queue_deq(suite_context.queue); } while (event == ODP_EVENT_INVALID); compl_event = odp_crypto_compl_from_event(event); CU_ASSERT(odp_crypto_compl_to_u64(compl_event) == odp_crypto_compl_to_u64(odp_crypto_compl_from_event(event))); odp_crypto_compl_result(compl_event, &result); odp_crypto_compl_free(compl_event); } CU_ASSERT(result.ok); CU_ASSERT(result.pkt == pkt); CU_ASSERT(!memcmp(data_addr, output_vec, output_vec_len)); CU_ASSERT(result.ctx == (void *)0xdeadbeef); cleanup: rc = odp_crypto_session_destroy(session); CU_ASSERT(!rc); odp_packet_free(pkt); }
/* Basic algorithm run function for async inplace mode. * Creates a session from input parameters and runs one operation * on input_vec. Checks the output of the crypto operation against * output_vec. Operation completion event is dequeued polling the * session output queue. Completion context pointer is retrieved * and checked against the one set before the operation. * Completion event can be a separate buffer or the input packet * buffer can be used. * */ static void alg_test(odp_crypto_op_t op, odp_cipher_alg_t cipher_alg, odp_crypto_iv_t ses_iv, uint8_t *op_iv_ptr, odp_crypto_key_t cipher_key, odp_auth_alg_t auth_alg, odp_crypto_key_t auth_key, odp_crypto_data_range_t *cipher_range, odp_crypto_data_range_t *auth_range, const uint8_t *plaintext, unsigned int plaintext_len, const uint8_t *ciphertext, unsigned int ciphertext_len, const uint8_t *digest, unsigned int digest_len ) { odp_crypto_session_t session; int rc; odp_crypto_ses_create_err_t status; odp_bool_t posted; odp_event_t event; odp_crypto_compl_t compl_event; odp_crypto_op_result_t result; /* Create a crypto session */ odp_crypto_session_params_t ses_params; memset(&ses_params, 0, sizeof(ses_params)); ses_params.op = op; ses_params.auth_cipher_text = false; ses_params.pref_mode = suite_context.pref_mode; ses_params.cipher_alg = cipher_alg; ses_params.auth_alg = auth_alg; ses_params.compl_queue = suite_context.queue; ses_params.output_pool = suite_context.pool; ses_params.cipher_key = cipher_key; ses_params.iv = ses_iv; ses_params.auth_key = auth_key; rc = odp_crypto_session_create(&ses_params, &session, &status); CU_ASSERT_FATAL(!rc); CU_ASSERT(status == ODP_CRYPTO_SES_CREATE_ERR_NONE); CU_ASSERT(odp_crypto_session_to_u64(session) != odp_crypto_session_to_u64(ODP_CRYPTO_SESSION_INVALID)); /* Prepare input data */ odp_packet_t pkt = odp_packet_alloc(suite_context.pool, plaintext_len + digest_len); CU_ASSERT(pkt != ODP_PACKET_INVALID); uint8_t *data_addr = odp_packet_data(pkt); memcpy(data_addr, plaintext, plaintext_len); int data_off = 0; /* Prepare input/output params */ odp_crypto_op_params_t op_params; memset(&op_params, 0, sizeof(op_params)); op_params.session = session; op_params.pkt = pkt; op_params.out_pkt = pkt; op_params.ctx = (void *)0xdeadbeef; if (cipher_range) { op_params.cipher_range = *cipher_range; data_off = cipher_range->offset; } else { op_params.cipher_range.offset = data_off; op_params.cipher_range.length = plaintext_len; } if (auth_range) { op_params.auth_range = *auth_range; } else { op_params.auth_range.offset = data_off; op_params.auth_range.length = plaintext_len; } if (op_iv_ptr) op_params.override_iv_ptr = op_iv_ptr; op_params.hash_result_offset = plaintext_len; rc = odp_crypto_operation(&op_params, &posted, &result); if (rc < 0) { CU_FAIL("Failed odp_crypto_operation()"); goto cleanup; } if (posted) { /* Poll completion queue for results */ do { event = odp_queue_deq(suite_context.queue); } while (event == ODP_EVENT_INVALID); compl_event = odp_crypto_compl_from_event(event); CU_ASSERT(odp_crypto_compl_to_u64(compl_event) == odp_crypto_compl_to_u64(odp_crypto_compl_from_event(event))); odp_crypto_compl_result(compl_event, &result); odp_crypto_compl_free(compl_event); } CU_ASSERT(result.ok); CU_ASSERT(result.pkt == pkt); if (cipher_alg != ODP_CIPHER_ALG_NULL) { CU_ASSERT(!memcmp(data_addr, ciphertext, ciphertext_len)); if (memcmp(data_addr, ciphertext, ciphertext_len)) { printf("data:\n"); unsigned j; for (j = 0; j < ciphertext_len; ++j) printf("%02x ", data_addr[j]); printf("\ncipher: \n"); for (j = 0; j < ciphertext_len; ++j) printf("%02x ", ciphertext[j]); printf("\n\n"); }; }; if (op == ODP_CRYPTO_OP_ENCODE && auth_alg != ODP_AUTH_ALG_NULL) CU_ASSERT(!memcmp(data_addr + op_params.hash_result_offset, digest, digest_len)); CU_ASSERT(result.ctx == (void *)0xdeadbeef); cleanup: rc = odp_crypto_session_destroy(session); CU_ASSERT(!rc); odp_packet_free(pkt); }