static void test_send_frame_vlan_to_novlan(void) { odp_packet_t pkt = ODP_PACKET_INVALID; odp_event_t ev; int res; if (create_odp_packet_ip4(&pkt, test_frame_vlan, sizeof(test_frame_vlan), 0)) { CU_FAIL("Fail to create packet"); return; } res = ofp_send_frame(dev, pkt); CU_ASSERT_EQUAL(res, OFP_PKT_PROCESSED); ev = odp_queue_deq(dev->outq_def); CU_ASSERT_NOT_EQUAL_FATAL(ev, ODP_EVENT_INVALID); pkt = odp_packet_from_event(ev); CU_ASSERT_EQUAL_FATAL(odp_packet_len(pkt), sizeof(test_frame)); if (memcmp(odp_packet_l2_ptr(pkt, NULL), test_frame, sizeof(test_frame))) CU_FAIL("Frame data mismatch."); }
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; }
/* * Trim packet data beyond the end of L3 payload * (i.e. from the offset (L3 offset + l3_len) to the end of the packet). */ static inline void trim_tail(odp_packet_t pkt, uint32_t l3_len) { uint32_t l3_offset = odp_packet_l3_offset(pkt); uint32_t len = odp_packet_len(pkt); if (len > l3_offset + l3_len) odp_packet_pull_tail(pkt, len - l3_offset - l3_len); }
/* * Tests */ static void test_packet_output_gre(void) { odp_packet_t pkt = ODP_PACKET_INVALID; odp_event_t ev; int res; struct ofp_ether_header *eth; struct ofp_ip *ip; struct ofp_ip *ip_orig; struct ofp_greip *greip; if (create_odp_packet_ip4(&pkt, test_frame, sizeof(test_frame), tun_p2p)) { CU_FAIL("Fail to create packet"); return; } /* * Packet's destination is GRE tunnel's p2p address, next hop is GRE * interface. GRE+IP header is prepended. Packet's new destination is * link local. Packet is put into output queue. */ res = ofp_ip_output(pkt, NULL); CU_ASSERT_EQUAL(res, OFP_PKT_PROCESSED); res = ofp_send_pending_pkt(); CU_ASSERT_EQUAL(res, OFP_PKT_PROCESSED); ev = odp_queue_deq(dev->outq_def); CU_ASSERT_NOT_EQUAL_FATAL(ev, ODP_EVENT_INVALID); pkt = odp_packet_from_event(ev); CU_ASSERT_EQUAL_FATAL(odp_packet_len(pkt), sizeof(test_frame) + 20 + 4); eth = odp_packet_l2_ptr(pkt, NULL); if (memcmp(eth->ether_dhost, tun_rem_mac, OFP_ETHER_ADDR_LEN)) CU_FAIL("Bad destination mac address."); if (memcmp(eth->ether_shost, dev->mac, OFP_ETHER_ADDR_LEN)) CU_FAIL("Bad source mac address."); ip = odp_packet_l3_ptr(pkt, NULL); CU_ASSERT_EQUAL(ip->ip_src.s_addr, dev_ip); CU_ASSERT_EQUAL(ip->ip_dst.s_addr, tun_rem_ip); CU_ASSERT_EQUAL(ip->ip_p, OFP_IPPROTO_GRE); greip = (struct ofp_greip *)ip; CU_ASSERT_EQUAL(greip->gi_g.flags, 0); CU_ASSERT_EQUAL(greip->gi_g.ptype, odp_cpu_to_be_16(OFP_ETHERTYPE_IP)); /* inner ip */ ip = (struct ofp_ip *)(greip + 1); ip_orig = (struct ofp_ip *)(&orig_pkt_data[OFP_ETHER_HDR_LEN]); if (memcmp(ip, ip_orig, odp_be_to_cpu_16(ip_orig->ip_len))) CU_FAIL("Inner IP packet error."); }
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"); }
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 }
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); }
static void test_ofp_packet_input_send_arp(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. * No ARP is found for gateway IP so an ARP req is sent. * Function returns OFP_PKT_DROP and packet can be reused.*/ my_test_val = TEST_FORWARD_HOOK; test_ofp_add_route(port, vrf, vlan, dst_ipaddr, 24, 4, dst_ipaddr + 1); 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); odp_packet_free(pkt); 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 */ pkt = odp_packet_from_event(ev); CU_ASSERT_NOT_EQUAL(pkt, ODP_PACKET_INVALID); CU_ASSERT_EQUAL(odp_packet_has_arp(pkt), 1); CU_ASSERT_EQUAL(odp_packet_has_vlan(pkt), 0); CU_ASSERT_EQUAL(odp_packet_len(pkt), sizeof(struct ofp_arphdr) + sizeof(struct ofp_ether_header)); odp_packet_free(odp_packet_from_event(ev)); ofp_arp_init_tables(); /* to clean saved packet */ CU_PASS("ofp_packet_input_send_arp"); }
static void test_packet_size_is_less_then_mtu(void) { odp_packet_t pkt_orig, pkt_sent; odp_event_t ev; int res; struct ofp_ether_header *eth; if (create_odp_packet_ip4(&pkt_orig, pkt1_frag1, sizeof(pkt1_frag1), 0)) { CU_FAIL("Fail to create packet"); return; } res = ofp_ip_output(pkt_orig, &nexthop); CU_ASSERT_EQUAL(res, OFP_PKT_PROCESSED); res = ofp_send_pending_pkt(); CU_ASSERT_EQUAL(res, OFP_PKT_PROCESSED); ev = odp_queue_deq(dev->outq_def); CU_ASSERT_NOT_EQUAL_FATAL(ev, ODP_EVENT_INVALID); CU_ASSERT_EQUAL_FATAL(odp_queue_deq(dev->outq_def), ODP_EVENT_INVALID); pkt_sent = odp_packet_from_event(ev); CU_ASSERT_EQUAL_FATAL(odp_packet_len(pkt_sent), sizeof(pkt1_frag1)); eth = odp_packet_l2_ptr(pkt_sent, NULL); if (memcmp(eth->ether_dhost, dst_mac, OFP_ETHER_ADDR_LEN)) CU_FAIL("Bad destination mac address."); if (memcmp(eth->ether_shost, dev->mac, OFP_ETHER_ADDR_LEN)) CU_FAIL("Bad source mac address."); if (memcmp(odp_packet_l3_ptr(pkt_sent, NULL), &orig_pkt_data[OFP_ETHER_HDR_LEN], sizeof(pkt1_frag1) - OFP_ETHER_HDR_LEN)) CU_FAIL("corrupt l3 + data forwarded"); CU_PASS("Correct packet"); odp_packet_free(pkt_sent); }
static void test_send_frame_novlan_to_vlan(void) { odp_packet_t pkt = ODP_PACKET_INVALID; odp_event_t ev; struct ofp_ether_vlan_header *eth_vlan; uint8_t *buf; int res; if (create_odp_packet_ip4(&pkt, test_frame, sizeof(test_frame), 0)) { CU_FAIL("Fail to create packet"); return; } res = ofp_send_frame(dev_vlan, pkt); CU_ASSERT_EQUAL(res, OFP_PKT_PROCESSED); ev = odp_queue_deq(dev->outq_def); CU_ASSERT_NOT_EQUAL_FATAL(ev, ODP_EVENT_INVALID); pkt = odp_packet_from_event(ev); CU_ASSERT_EQUAL_FATAL(odp_packet_len(pkt), sizeof(test_frame) + 4); eth_vlan = odp_packet_l2_ptr(pkt, NULL); if (memcmp(eth_vlan, test_frame, 2 * OFP_ETHER_ADDR_LEN)) CU_FAIL("Frame data mismatch."); CU_ASSERT_EQUAL(eth_vlan->evl_encap_proto, odp_cpu_to_be_16(OFP_ETHERTYPE_VLAN)); CU_ASSERT_EQUAL(eth_vlan->evl_tag, odp_cpu_to_be_16(dev_vlan->vlan)); buf = (uint8_t *)eth_vlan; if (memcmp(&buf[16], &test_frame[12], sizeof(test_frame) - 2 * OFP_ETHER_ADDR_LEN)) CU_FAIL("Frame data mismatch."); }
/* * Drop data from (the front of) a sockbuf. */ static void sbdrop_internal(struct sockbuf *sb, int len) { odp_packet_t pkt; while (len > 0) { pkt = ofp_sockbuf_get_first(sb); if (pkt == ODP_PACKET_INVALID) return; int buflen = odp_packet_len(pkt); if (buflen > len) { odp_packet_pull_head(pkt, len); sb->sb_cc -= len; if (sb->sb_sndptroff != 0) sb->sb_sndptroff -= len; break; } len -= buflen; pkt = ofp_sockbuf_remove_first(sb); sbfree(sb, pkt); ofp_sockbuf_packet_free(pkt); } }
enum ofp_return_code ofp_send_frame(struct ofp_ifnet *dev, odp_packet_t pkt) { struct ofp_ether_header *eth, eth_tmp; struct ofp_ether_vlan_header *eth_vlan, eth_vlan_tmp; uint32_t pkt_len, eth_hdr_len; enum ofp_return_code rc; if (ofp_if_type(dev) == OFP_IFT_GRE) { OFP_ERR("Send frame on GRE port"); return OFP_PKT_DROP; } ofp_packet_user_area_reset(pkt); /* Contsruct ethernet header */ eth = odp_packet_l2_ptr(pkt, NULL); eth_vlan = odp_packet_l2_ptr(pkt, NULL); if (odp_be_to_cpu_16(eth->ether_type) == OFP_ETHERTYPE_VLAN) { if (dev->vlan) { /* change vlan */ eth_vlan->evl_tag = odp_cpu_to_be_16(dev->vlan); } else { /* remove existing vlan */ eth_vlan_tmp = *eth_vlan; eth = odp_packet_pull_head(pkt, 4); if (!eth) { OFP_ERR("odp_packet_pull_head failed"); return OFP_PKT_DROP; } odp_packet_l3_offset_set(pkt, odp_packet_l3_offset(pkt) - 4); ofp_copy_mac(eth->ether_dhost, eth_vlan_tmp.evl_dhost); ofp_copy_mac(eth->ether_shost, eth_vlan_tmp.evl_shost); eth->ether_type = eth_vlan_tmp.evl_proto; } } else { if (dev->vlan) { /* insert vlan */ eth_tmp = *eth; eth_vlan = odp_packet_push_head(pkt, 4); if (!eth_vlan) { OFP_ERR("odp_packet_push_head failed"); return OFP_PKT_DROP; } odp_packet_l3_offset_set(pkt, odp_packet_l3_offset(pkt) + 4); ofp_copy_mac(eth_vlan->evl_dhost, eth_tmp.ether_dhost); ofp_copy_mac(eth_vlan->evl_shost, eth_tmp.ether_shost); eth_vlan->evl_encap_proto = odp_cpu_to_be_16(OFP_ETHERTYPE_VLAN); eth_vlan->evl_tag = odp_cpu_to_be_16(dev->vlan); eth_vlan->evl_proto = eth_tmp.ether_type; } } if (dev->vlan) eth_hdr_len = OFP_ETHER_HDR_LEN + OFP_ETHER_VLAN_ENCAP_LEN; else eth_hdr_len = OFP_ETHER_HDR_LEN; pkt_len = odp_packet_len(pkt) - eth_hdr_len; if (pkt_len > dev->if_mtu) { OFP_ERR("Packet size bigger than MTU: %d %d", pkt_len, dev->if_mtu); return OFP_PKT_DROP; } rc = send_pkt_out(dev, pkt); if (rc != OFP_PKT_PROCESSED) return rc; return ofp_send_pending_pkt(); }
static void test_packet_output_ipv6_to_gre(void) { odp_packet_t pkt = ODP_PACKET_INVALID; odp_event_t ev; int res; struct ofp_ether_header *eth; struct ofp_ip6_hdr *ip6, *ip6_orig; struct ofp_ip *ip; struct ofp_greip *greip; (void)tcp_frame; (void)icmp_frame; (void)arp_frame; (void)icmp6_frame; if (create_odp_packet_ip6(&pkt, ip6udp_frame, sizeof(ip6udp_frame))) { CU_FAIL("Fail to create packet"); return; } ip6 = odp_packet_l3_ptr(pkt, NULL); ofp_set_route6_params(OFP_ROUTE6_ADD, 0 /*vrf*/, 100 /*vlan*/, GRE_PORTS, ip6->ip6_dst.__u6_addr.__u6_addr8, 64 /*masklen*/, 0 /*gw*/, OFP_RTF_NET /* flags */); res = ofp_ip6_output(pkt, NULL); CU_ASSERT_EQUAL(res, OFP_PKT_PROCESSED); res = ofp_send_pending_pkt(); CU_ASSERT_EQUAL(res, OFP_PKT_PROCESSED); ev = odp_queue_deq(dev->outq_def); CU_ASSERT_NOT_EQUAL_FATAL(ev, ODP_EVENT_INVALID); pkt = odp_packet_from_event(ev); CU_ASSERT_EQUAL_FATAL(odp_packet_len(pkt), sizeof(ip6udp_frame) + 20 + 4); eth = odp_packet_l2_ptr(pkt, NULL); if (memcmp(eth->ether_dhost, tun_rem_mac, OFP_ETHER_ADDR_LEN)) CU_FAIL("Bad destination mac address."); if (memcmp(eth->ether_shost, dev->mac, OFP_ETHER_ADDR_LEN)) CU_FAIL("Bad source mac address."); ip = odp_packet_l3_ptr(pkt, NULL); CU_ASSERT_EQUAL(ip->ip_src.s_addr, dev_ip); CU_ASSERT_EQUAL(ip->ip_dst.s_addr, tun_rem_ip); CU_ASSERT_EQUAL(ip->ip_p, OFP_IPPROTO_GRE); greip = (struct ofp_greip *)ip; CU_ASSERT_EQUAL(greip->gi_g.flags, 0); CU_ASSERT_EQUAL(greip->gi_g.ptype, odp_cpu_to_be_16(OFP_ETHERTYPE_IPV6)); /* inner ip */ ip6 = (struct ofp_ip6_hdr *)(greip + 1); ip6_orig = (struct ofp_ip6_hdr *) (&orig_pkt_data[OFP_ETHER_HDR_LEN]); if (memcmp(ip6, ip6_orig, odp_be_to_cpu_16(ip6_orig->ofp_ip6_plen) + sizeof(*ip6))) CU_FAIL("Inner IP packet error."); }
static void test_fragment_fragmented_to_two(void) { odp_packet_t pkt_orig, pkt_sent; odp_event_t ev; int res; struct ofp_ether_header *eth; struct ofp_ip *ip; struct ofp_ip *ip_orig; uint16_t pl_pos, pl_len, orig_pl_len, pktlen, start_offset; dev->if_mtu = 620; if (create_odp_packet_ip4(&pkt_orig, pkt1_frag2, sizeof(pkt1_frag2), 0)) { CU_FAIL("Fail to create packet"); return; } res = ofp_ip_output(pkt_orig, &nexthop); CU_ASSERT_EQUAL(res, OFP_PKT_PROCESSED); res = ofp_send_pending_pkt(); CU_ASSERT_EQUAL(res, OFP_PKT_PROCESSED); /* ASSERT 1st fragment */ ev = odp_queue_deq(dev->outq_def); CU_ASSERT_NOT_EQUAL_FATAL(ev, ODP_EVENT_INVALID); pkt_sent = odp_packet_from_event(ev); CU_ASSERT_EQUAL_FATAL(odp_packet_len(pkt_sent), dev->if_mtu + OFP_ETHER_HDR_LEN); eth = odp_packet_l2_ptr(pkt_sent, NULL); if (memcmp(eth->ether_dhost, dst_mac, OFP_ETHER_ADDR_LEN)) CU_FAIL("Bad destination mac address."); if (memcmp(eth->ether_shost, dev->mac, OFP_ETHER_ADDR_LEN)) CU_FAIL("Bad source mac address."); ip = odp_packet_l3_ptr(pkt_sent, NULL); ip_orig = (struct ofp_ip *)(&orig_pkt_data[OFP_ETHER_HDR_LEN]); orig_pl_len = odp_be_to_cpu_16(ip_orig->ip_len) - (ip_orig->ip_hl<<2); start_offset = odp_be_to_cpu_16(ip_orig->ip_off) & OFP_IP_OFFMASK; assert_ip_header(ip, ip_orig, dev->if_mtu, 1, start_offset); pl_len = dev->if_mtu - (ip->ip_hl<<2); if (memcmp((uint8_t *)ip + (ip->ip_hl<<2), (uint8_t *)ip_orig + (ip_orig->ip_hl<<2), pl_len)) CU_FAIL("corrupt l3 + data forwarded"); pl_pos = pl_len; CU_PASS("Correct packet"); odp_packet_free(pkt_sent); /* ASSERT 2nd fragment */ ev = odp_queue_deq(dev->outq_def); CU_ASSERT_NOT_EQUAL_FATAL(ev, ODP_EVENT_INVALID); pkt_sent = odp_packet_from_event(ev); pl_len = orig_pl_len - pl_pos; pktlen = pl_len + OFP_ETHER_HDR_LEN + sizeof(struct ofp_ip); CU_ASSERT_EQUAL_FATAL(odp_packet_len(pkt_sent), pktlen); eth = odp_packet_l2_ptr(pkt_sent, NULL); if (memcmp(eth->ether_dhost, dst_mac, OFP_ETHER_ADDR_LEN)) CU_FAIL("Bad destination mac address."); if (memcmp(eth->ether_shost, dev->mac, OFP_ETHER_ADDR_LEN)) CU_FAIL("Bad source mac address."); ip = odp_packet_l3_ptr(pkt_sent, NULL); assert_ip_header(ip, ip_orig, pl_len + sizeof(struct ofp_ip), 0, start_offset + pl_pos/8); if (memcmp((uint8_t *)ip + (ip->ip_hl<<2), (uint8_t *)ip_orig + (ip_orig->ip_hl<<2) + pl_pos, pl_len)) CU_FAIL("corrupt l3 + data forwarded"); CU_PASS("Correct packet"); odp_packet_free(pkt_sent); /* no more fragments */ ev = odp_queue_deq(dev->outq_def); CU_ASSERT_EQUAL(ev, ODP_EVENT_INVALID); dev->if_mtu = def_mtu; }
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"); }
void pktio_test_send_failure(void) { odp_pktio_t pktio_tx, pktio_rx; odp_packet_t pkt_tbl[TX_BATCH_LEN]; uint32_t pkt_seq[TX_BATCH_LEN]; int ret, mtu, i, alloc_pkts; odp_pool_param_t pool_params; odp_pool_t pkt_pool; int long_pkt_idx = TX_BATCH_LEN / 2; pktio_info_t info_rx; pktio_tx = create_pktio(0, ODP_PKTIN_MODE_RECV, ODP_PKTOUT_MODE_SEND); if (pktio_tx == ODP_PKTIO_INVALID) { CU_FAIL("failed to open pktio"); return; } /* read the MTU from the transmit interface */ mtu = odp_pktio_mtu(pktio_tx); ret = odp_pktio_start(pktio_tx); CU_ASSERT_FATAL(ret == 0); /* configure the pool so that we can generate test packets larger * than the interface MTU */ memset(&pool_params, 0, sizeof(pool_params)); pool_params.pkt.len = mtu + 32; pool_params.pkt.seg_len = pool_params.pkt.len; pool_params.pkt.num = TX_BATCH_LEN + 1; pool_params.type = ODP_POOL_PACKET; pkt_pool = odp_pool_create("pkt_pool_oversize", &pool_params); CU_ASSERT_FATAL(pkt_pool != ODP_POOL_INVALID); if (num_ifaces > 1) { pktio_rx = create_pktio(1, ODP_PKTIN_MODE_RECV, ODP_PKTOUT_MODE_SEND); ret = odp_pktio_start(pktio_rx); CU_ASSERT_FATAL(ret == 0); } else { pktio_rx = pktio_tx; } /* generate a batch of packets with a single overly long packet * in the middle */ for (i = 0; i < TX_BATCH_LEN; ++i) { uint32_t pkt_len; if (i == long_pkt_idx) pkt_len = pool_params.pkt.len; else pkt_len = PKT_LEN_NORMAL; pkt_tbl[i] = odp_packet_alloc(pkt_pool, pkt_len); if (pkt_tbl[i] == ODP_PACKET_INVALID) break; pkt_seq[i] = pktio_init_packet(pkt_tbl[i]); pktio_pkt_set_macs(pkt_tbl[i], pktio_tx, pktio_rx); if (pktio_fixup_checksums(pkt_tbl[i]) != 0) { odp_packet_free(pkt_tbl[i]); break; } if (pkt_seq[i] == TEST_SEQ_INVALID) { odp_packet_free(pkt_tbl[i]); break; } } alloc_pkts = i; if (alloc_pkts == TX_BATCH_LEN) { /* try to send the batch with the long packet in the middle, * the initial short packets should be sent successfully */ odp_errno_zero(); ret = odp_pktio_send(pktio_tx, pkt_tbl, TX_BATCH_LEN); CU_ASSERT(ret == long_pkt_idx); CU_ASSERT(odp_errno() == 0); info_rx.id = pktio_rx; info_rx.outq = ODP_QUEUE_INVALID; info_rx.inq = ODP_QUEUE_INVALID; info_rx.in_mode = ODP_PKTIN_MODE_RECV; for (i = 0; i < ret; ++i) { pkt_tbl[i] = wait_for_packet(&info_rx, pkt_seq[i], ODP_TIME_SEC_IN_NS); if (pkt_tbl[i] == ODP_PACKET_INVALID) break; } if (i == ret) { /* now try to send starting with the too-long packet * and verify it fails */ odp_errno_zero(); ret = odp_pktio_send(pktio_tx, &pkt_tbl[long_pkt_idx], TX_BATCH_LEN - long_pkt_idx); CU_ASSERT(ret == -1); CU_ASSERT(odp_errno() != 0); } else { CU_FAIL("failed to receive transmitted packets\n"); } /* now reduce the size of the long packet and attempt to send * again - should work this time */ i = long_pkt_idx; odp_packet_pull_tail(pkt_tbl[i], odp_packet_len(pkt_tbl[i]) - PKT_LEN_NORMAL); pkt_seq[i] = pktio_init_packet(pkt_tbl[i]); pktio_pkt_set_macs(pkt_tbl[i], pktio_tx, pktio_rx); ret = pktio_fixup_checksums(pkt_tbl[i]); CU_ASSERT_FATAL(ret == 0); CU_ASSERT_FATAL(pkt_seq[i] != TEST_SEQ_INVALID); ret = odp_pktio_send(pktio_tx, &pkt_tbl[i], TX_BATCH_LEN - i); CU_ASSERT_FATAL(ret == (TX_BATCH_LEN - i)); for (; i < TX_BATCH_LEN; ++i) { pkt_tbl[i] = wait_for_packet(&info_rx, pkt_seq[i], ODP_TIME_SEC_IN_NS); if (pkt_tbl[i] == ODP_PACKET_INVALID) break; } CU_ASSERT(i == TX_BATCH_LEN); } else { CU_FAIL("failed to generate test packets\n"); } for (i = 0; i < alloc_pkts; ++i) { if (pkt_tbl[i] != ODP_PACKET_INVALID) odp_packet_free(pkt_tbl[i]); } if (pktio_rx != pktio_tx) CU_ASSERT(odp_pktio_close(pktio_rx) == 0); CU_ASSERT(odp_pktio_close(pktio_tx) == 0); CU_ASSERT(odp_pool_destroy(pkt_pool) == 0); }
static inline unsigned pkt_mmap_v2_tx(int sock, struct ring *ring, const odp_packet_t pkt_table[], unsigned len) { union frame_map ppd; uint32_t pkt_len; unsigned first_frame_num, frame_num, frame_count; int ret; uint8_t *buf; unsigned n, i = 0; unsigned nb_tx = 0; int send_errno; int total_len = 0; first_frame_num = ring->frame_num; frame_num = first_frame_num; frame_count = ring->rd_num; while (i < len) { ppd.raw = ring->rd[frame_num].iov_base; if (!odp_unlikely(mmap_tx_kernel_ready(ppd.raw))) break; pkt_len = odp_packet_len(pkt_table[i]); ppd.v2->tp_h.tp_snaplen = pkt_len; ppd.v2->tp_h.tp_len = pkt_len; total_len += pkt_len; buf = (uint8_t *)ppd.raw + TPACKET2_HDRLEN - sizeof(struct sockaddr_ll); odp_packet_copy_to_mem(pkt_table[i], 0, pkt_len, buf); mmap_tx_user_ready(ppd.raw); if (++frame_num >= frame_count) frame_num = 0; i++; } ret = sendto(sock, NULL, 0, MSG_DONTWAIT, NULL, 0); send_errno = errno; /* On success, the return value indicates the number of bytes sent. On * failure a value of -1 is returned, even if the failure occurred * after some of the packets in the ring have already been sent, so we * need to inspect the packet status to determine which were sent. */ if (odp_likely(ret == total_len)) { nb_tx = i; ring->frame_num = frame_num; } else if (ret == -1) { for (frame_num = first_frame_num, n = 0; n < i; ++n) { struct tpacket2_hdr *hdr = ring->rd[frame_num].iov_base; if (odp_likely(hdr->tp_status == TP_STATUS_AVAILABLE || hdr->tp_status == TP_STATUS_SENDING)) { nb_tx++; } else { /* The remaining frames weren't sent, clear * their status to indicate we're not waiting * for the kernel to process them. */ hdr->tp_status = TP_STATUS_AVAILABLE; } if (++frame_num >= frame_count) frame_num = 0; } ring->frame_num = (first_frame_num + nb_tx) % frame_count; if (nb_tx == 0 && SOCK_ERR_REPORT(send_errno)) { __odp_errno = send_errno; /* ENOBUFS indicates that the transmit queue is full, * which will happen regularly when overloaded so don't * print it */ if (errno != ENOBUFS) ODP_ERR("sendto(pkt mmap): %s\n", strerror(send_errno)); return -1; } } else { /* Short send, return value is number of bytes sent so use this * to determine number of complete frames sent. */ for (n = 0; n < i && ret > 0; ++n) { ret -= odp_packet_len(pkt_table[n]); if (ret >= 0) nb_tx++; } ring->frame_num = (first_frame_num + nb_tx) % frame_count; } for (i = 0; i < nb_tx; ++i) odp_packet_free(pkt_table[i]); return nb_tx; }
static void sigev_notify(union ofp_sigval sv) { struct ofp_sock_sigval *ss = sv.sival_ptr; if (!ss) return ; int s = ss->sockfd; int event = ss->event; odp_packet_t pkt = ss->pkt; ngx_uint_t i = 0; ngx_queue_t *queue = NULL; ngx_event_t *ev; ngx_connection_t *c; if (event == OFP_EVENT_ACCEPT) { for (i = 0; i < nevents; i++) { ev = event_index[i]; c = ev->data; if (ev->accept) { ev->ready = 1; ev->handler(ev); OFP_DBG("%s: posted on ACCEPT EVENT", __func__); break; } } return; } if (event == OFP_EVENT_SEND) { for (i = 0; i < nevents; i++) { ev = event_index[i]; c = ev->data; if (ev->write && CLR_FD_BIT(c->fd)==s) { OFP_DBG("%s: posted SEND event on fd=%d", __func__, s); ev->ready = 1; ngx_post_event(ev, &ngx_posted_events); } } return; } int r = odp_packet_len(pkt); if (r > 0) { for (i = 0; i < nevents; i++) { ev = event_index[i]; c = ev->data; if (s == CLR_FD_BIT(c->fd)) { queue = &ngx_posted_events; ngx_post_event(ev, queue); OFP_DBG("%s: posted on RECV EVENT", __func__); ev->ready = 1; break; } } } else if (r == 0) { odp_packet_free(pkt); ss->pkt = ODP_PACKET_INVALID; } return; }