static void test_packet_output_gre_no_nexthop(void) { odp_packet_t pkt = ODP_PACKET_INVALID; odp_event_t ev; int res; if (create_odp_packet_ip4(&pkt, test_frame, sizeof(test_frame), tun_p2p + 1)) { CU_FAIL("Fail to create packet"); return; } /* * Packet's destination is GRE tunnel's p2p address, no next hop * is found for tunnel destination address, packet is dropped. */ res = ofp_ip_output(pkt, NULL); CU_ASSERT_EQUAL(res, OFP_PKT_DROP); res = ofp_send_pending_pkt(); CU_ASSERT_EQUAL(res, OFP_PKT_PROCESSED); ev = odp_queue_deq(dev->outq_def); CU_ASSERT_EQUAL_FATAL(ev, ODP_EVENT_INVALID); }
/* * 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 *pkt_io_recv(void *arg) { odp_pktin_queue_t pktin; odp_packet_t pkt, pkt_tbl[PKT_BURST_SIZE]; int pkt_idx, pkt_cnt; struct pktio_thr_arg *thr_args; ofp_pkt_processing_func pkt_func; thr_args = arg; pkt_func = thr_args->pkt_func; pktin = thr_args->pktin; if (ofp_init_local()) { OFP_ERR("Error: OFP local init failed.\n"); return NULL; } OFP_DBG("PKT-IO receive starting on cpu: %d", odp_cpu_id()); while (1) { pkt_cnt = odp_pktin_recv(pktin, pkt_tbl, PKT_BURST_SIZE); for (pkt_idx = 0; pkt_idx < pkt_cnt; pkt_idx++) { pkt = pkt_tbl[pkt_idx]; if (odp_unlikely(odp_packet_has_error(pkt))) { OFP_DBG("Packet with error dropped.\n"); odp_packet_free(pkt); continue; } ofp_packet_input(pkt, ODP_QUEUE_INVALID, pkt_func); } ofp_send_pending_pkt(); } /* Never reached */ return NULL; }
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); }
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(); }
int default_event_dispatcher(void *arg) { odp_event_t ev; odp_packet_t pkt; odp_queue_t in_queue; int event_idx = 0; int event_cnt = 0; ofp_pkt_processing_func pkt_func = (ofp_pkt_processing_func)arg; odp_bool_t *is_running = NULL; if (ofp_init_local()) { OFP_ERR("ofp_init_local failed"); return -1; } int rx_burst = global_param->evt_rx_burst_size; odp_event_t events[rx_burst]; is_running = ofp_get_processing_state(); if (is_running == NULL) { OFP_ERR("ofp_get_processing_state failed"); ofp_term_local(); return -1; } /* PER CORE DISPATCHER */ while (*is_running) { event_cnt = odp_schedule_multi(&in_queue, ODP_SCHED_WAIT, events, rx_burst); for (event_idx = 0; event_idx < event_cnt; event_idx++) { odp_event_type_t ev_type; ev = events[event_idx]; if (ev == ODP_EVENT_INVALID) continue; ev_type = odp_event_type(ev); if (odp_likely(ev_type == ODP_EVENT_PACKET)) { pkt = odp_packet_from_event(ev); #if 0 if (odp_unlikely(odp_packet_has_error(pkt))) { OFP_DBG("Dropping packet with error"); odp_packet_free(pkt); continue; } #endif ofp_packet_input(pkt, in_queue, pkt_func); continue; } if (ev_type == ODP_EVENT_TIMEOUT) { ofp_timer_handle(ev); continue; } OFP_ERR("Unexpected event type: %u", ev_type); odp_event_free(ev); } ofp_send_pending_pkt(); } if (ofp_term_local()) OFP_ERR("ofp_term_local failed"); return 0; }
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 ngx_int_t ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) { odp_packet_t pkts[OFP_PKT_RX_BURST_SIZE]; odp_packet_t odp_pkt; int pkt_cnt = 0; int pkt_idx = 0; pkt_cnt = odp_pktin_recv(in_queue, pkts, OFP_PKT_RX_BURST_SIZE); for (pkt_idx = 0; pkt_idx < pkt_cnt; pkt_idx++) { odp_pkt = pkts[pkt_idx]; ofp_packet_input(odp_pkt, ODP_QUEUE_INVALID, ofp_eth_vlan_processing); } if (pkt_cnt < 1) ofp_send_pending_pkt(); static uint32_t count = 0; /*odp_queue_deq has a lock that impacts performance*/ if (count ++ > 50) { count = 0; odp_queue_t timer_queue = ofp_timer_queue_cpu(-1); odp_event_t event = odp_queue_deq(timer_queue); if (event != ODP_EVENT_INVALID) { if (odp_event_type(event) == ODP_EVENT_TIMEOUT) { ofp_timer_handle(event); } else { odp_buffer_free(odp_buffer_from_event(event)); } } } #if OFP_NOTIFY return NGX_OK; #endif int ready, nready; ngx_err_t err; ngx_uint_t i, found; ngx_event_t *ev; ngx_queue_t *queue; struct timeval tv, *tp; ngx_connection_t *c; if (max_fd == -1) { for (i = 0; i < nevents; i++) { c = event_index[i]->data; ngx_log_debug(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "change max_fd: %i, c->fd : %d", max_fd, c->fd); if (max_fd < c->fd) { max_fd = c->fd; } } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "change max_fd: %i", max_fd); } #if (NGX_DEBUG) if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) { for (i = 0; i < nevents; i++) { ev = event_index[i]; c = ev->data; ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "select event: fd:%d wr:%d", c->fd, ev->write); } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "max_fd: %i", max_fd); } #endif if (timer == NGX_TIMER_INFINITE) { tp = NULL; } else { tv.tv_sec = (long) (timer / 1000); tv.tv_usec = (long) ((timer % 1000) * 1000); tp = &tv; } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "select timer: %M", timer); ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "select max_fd %d, tp %p ", max_fd, tp); ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, " master %p : work %p", (ofp_fd_set *)&master_read_fd_set, (ofp_fd_set *)&work_read_fd_set); ready = select(max_fd + 1, &master_read_fd_set, &master_write_fd_set, NULL, tp); err = (ready == -1) ? ngx_errno : 0; if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) { ngx_time_update(); } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "select ready %d", ready); if (err) { ngx_uint_t level; if (err == NGX_EINTR) { if (ngx_event_timer_alarm) { ngx_event_timer_alarm = 0; return NGX_OK; } level = NGX_LOG_INFO; } else { level = NGX_LOG_ALERT; } ngx_log_error(level, cycle->log, err, "select() failed"); if (err == NGX_EBADF) { /*ngx_select_repair_fd_sets(cycle);*/ } return NGX_ERROR; } if (ready == 0) { return NGX_OK; if (timer != NGX_TIMER_INFINITE) { return NGX_OK; } ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "select() returned no events without timeout"); return NGX_ERROR; } nready = 0; for (i = 0; i < nevents; i++) { ev = event_index[i]; c = ev->data; found = 0; if (ev->write) { if (FD_ISSET(c->fd, &master_write_fd_set)) { found = 1; ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "select write %d", c->fd); } } else { if (FD_ISSET(c->fd, &master_read_fd_set)) { found = 1; ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "select read %d", c->fd); } } if (found) { ev->ready = 1; queue = ev->accept ? &ngx_posted_accept_events : &ngx_posted_events; ngx_post_event(ev, queue); nready++; } } if (ready != nready) { /*ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "select ready != events: %d:%d", ready, nready); ngx_select_repair_fd_sets(cycle);*/ } return NGX_OK; }
void *default_event_dispatcher(void *arg) { odp_event_t ev; odp_packet_t pkt; odp_queue_t in_queue; odp_event_t events[OFP_EVT_RX_BURST_SIZE]; int event_idx = 0; int event_cnt = 0; ofp_pkt_processing_func pkt_func = (ofp_pkt_processing_func)arg; odp_bool_t *is_running = NULL; #if ODP_VERSION < 106 if (odp_init_local(ODP_THREAD_WORKER)) { OFP_ERR("odp_init_local failed"); return NULL; } #endif if (ofp_init_local()) { OFP_ERR("ofp_init_local failed"); return NULL; } is_running = ofp_get_processing_state(); if (is_running == NULL) { OFP_ERR("ofp_get_processing_state failed"); ofp_term_local(); return NULL; } /* PER CORE DISPATCHER */ while (*is_running) { event_cnt = odp_schedule_multi(&in_queue, ODP_SCHED_WAIT, events, OFP_EVT_RX_BURST_SIZE); for (event_idx = 0; event_idx < event_cnt; event_idx++) { ev = events[event_idx]; if (ev == ODP_EVENT_INVALID) continue; if (odp_event_type(ev) == ODP_EVENT_TIMEOUT) { ofp_timer_handle(ev); continue; } if (odp_event_type(ev) == ODP_EVENT_PACKET) { pkt = odp_packet_from_event(ev); #if 0 if (odp_unlikely(odp_packet_has_error(pkt))) { OFP_DBG("Dropping packet with error"); odp_packet_free(pkt); continue; } #endif ofp_packet_input(pkt, in_queue, pkt_func); continue; } OFP_ERR("Unexpected event type: %u", odp_event_type(ev)); /* Free events by type */ if (odp_event_type(ev) == ODP_EVENT_BUFFER) { odp_buffer_free(odp_buffer_from_event(ev)); continue; } if (odp_event_type(ev) == ODP_EVENT_CRYPTO_COMPL) { odp_crypto_compl_free( odp_crypto_compl_from_event(ev)); continue; } } ofp_send_pending_pkt(); } if (ofp_term_local()) OFP_ERR("ofp_term_local failed"); return NULL; }