void ofp_nd6_ns_input(odp_packet_t m, int off, int icmp6len) { struct ofp_ether_header *eth; struct ofp_ip6_hdr *ip6; struct ofp_icmp6_hdr *icmp6; struct ofp_ifnet *ifp; (void)icmp6len; ifp = odp_packet_user_ptr(m); eth = (struct ofp_ether_header *) odp_packet_l2_ptr(m, NULL); ip6 = (struct ofp_ip6_hdr *)odp_packet_l3_ptr(m, NULL); icmp6 = (struct ofp_icmp6_hdr *)((uint8_t *)ip6 + off); if (icmp6->ofp_icmp6_data8[20] == OFP_ND_OPT_SOURCE_LINKADDR && !OFP_IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) && !OFP_IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src)) { ofp_set_route6_params(OFP_ROUTE6_ADD, 0 /*vrf*/, ifp->vlan, ifp->port, ip6->ip6_src.ofp_s6_addr, 128 /*masklen*/, ofp_in6addr_any.ofp_s6_addr, OFP_RTF_HOST); ofp_add_mac6(ifp, &ip6->ip6_src.ofp_s6_addr[0], (uint8_t *)ð->ether_shost); } }
uint32_t cls_pkt_get_seq(odp_packet_t pkt) { uint32_t offset; cls_test_packet_t data; odph_ipv4hdr_t *ip; odph_tcphdr_t *tcp; ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL); offset = odp_packet_l4_offset(pkt); if (!offset && !ip) return TEST_SEQ_INVALID; if (ip->proto == ODPH_IPPROTO_UDP) odp_packet_copydata_out(pkt, offset + ODPH_UDPHDR_LEN, sizeof(data), &data); else { tcp = (odph_tcphdr_t *)odp_packet_l4_ptr(pkt, NULL); odp_packet_copydata_out(pkt, offset + tcp->hl * 4, sizeof(data), &data); } if (data.magic == DATA_MAGIC) return data.seq; return TEST_SEQ_INVALID; }
void test_pktio_pmr_match_set_cos(void) { uint32_t addr = 0; uint32_t mask; odph_ipv4hdr_t *ip; odph_udphdr_t *udp; odp_packet_t pkt; odp_queue_t queue; uint32_t seq; pkt = create_packet(false); seq = cls_pkt_get_seq(pkt); ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL); parse_ipv4_string(CLS_PMR_SET_SADDR, &addr, &mask); ip->src_addr = odp_cpu_to_be_32(addr); ip->chksum = 0; ip->chksum = odp_cpu_to_be_16(odph_ipv4_csum_update(pkt)); udp = (odph_udphdr_t *)odp_packet_l4_ptr(pkt, NULL); udp->src_port = odp_cpu_to_be_16(CLS_PMR_SET_SPORT); enqueue_loop_interface(pkt); pkt = receive_packet(&queue, ODP_TIME_SEC); CU_ASSERT(queue == queue_list[CLS_PMR_SET]); CU_ASSERT(seq == cls_pkt_get_seq(pkt)); odp_packet_free(pkt); }
enum ofp_return_code ofp_ipv6_processing(odp_packet_t *pkt) { int res; int protocol = IS_IPV6; uint32_t flags; struct ofp_ip6_hdr *ipv6; struct ofp_nh6_entry *nh; struct ofp_ifnet *dev = odp_packet_user_ptr(*pkt); int is_ours = 0; ipv6 = (struct ofp_ip6_hdr *)odp_packet_l3_ptr(*pkt, NULL); if (odp_unlikely(ipv6 == NULL)) return OFP_PKT_DROP; /* is ipv6->dst_addr one of my IPv6 addresses from this interface*/ if (ofp_ip6_equal(dev->ip6_addr, ipv6->ip6_dst.ofp_s6_addr) || OFP_IN6_IS_SOLICITED_NODE_MC(ipv6->ip6_dst, dev->ip6_addr) || (memcmp((const void *)((uintptr_t)dev->link_local + 8), (const void *)((uintptr_t)ipv6->ip6_dst.ofp_s6_addr + 8), 2 * sizeof(uint32_t)) == 0)) { is_ours = 1; } /* check if it's ours for another ipv6 address */ if (!is_ours) { nh = ofp_get_next_hop6(dev->vrf, ipv6->ip6_dst.ofp_s6_addr, &flags); if (nh && (nh->flags & OFP_RTF_LOCAL)) is_ours = 1; } if (is_ours) { OFP_HOOK(OFP_HOOK_LOCAL, *pkt, &protocol, &res); if (res != OFP_PKT_CONTINUE) { OFP_DBG("OFP_HOOK_LOCAL returned %d", res); return res; } OFP_HOOK(OFP_HOOK_LOCAL_IPv6, *pkt, NULL, &res); if (res != OFP_PKT_CONTINUE) { OFP_DBG("OFP_HOOK_LOCAL_IPv6 returned %d", res); return res; } return ipv6_transport_classifier(pkt, ipv6->ofp_ip6_nxt); } OFP_HOOK(OFP_HOOK_FWD_IPv6, *pkt, NULL, &res); if (res != OFP_PKT_CONTINUE) { OFP_DBG("OFP_HOOK_FWD_IPv6 returned %d", res); return res; } nh = ofp_get_next_hop6(dev->vrf, ipv6->ip6_dst.ofp_s6_addr, &flags); if (nh == NULL) return OFP_PKT_CONTINUE; return ofp_ip6_output(*pkt, nh); }
void ofp_nd6_na_input(odp_packet_t m, int off, int icmp6len) { struct ofp_ether_header *eth; struct ofp_ip6_hdr *ip6; struct ofp_icmp6_hdr *icmp6; struct ofp_ifnet *ifp; (void)icmp6len; ifp = odp_packet_user_ptr(m); eth = (struct ofp_ether_header *) odp_packet_l2_ptr(m, NULL); ip6 = (struct ofp_ip6_hdr *)odp_packet_l3_ptr(m, NULL); icmp6 = (struct ofp_icmp6_hdr *)((uint8_t *)ip6 + off); if (icmp6->ofp_icmp6_data8[20] == OFP_ND_OPT_TARGET_LINKADDR) { ofp_set_route6_params(OFP_ROUTE6_ADD, 0 /*vrf*/, ifp->vlan, ifp->port, &icmp6->ofp_icmp6_data8[4], 128 /*masklen*/, ofp_in6addr_any.ofp_s6_addr, OFP_RTF_HOST); ofp_add_mac6(ifp, &icmp6->ofp_icmp6_data8[4], (uint8_t *)ð->ether_shost); } }
int get_payload(struct rte_mbuf *pkt, unsigned char **payload, int *len) { odph_ipv4hdr_t *ip; int payload_offset; ip = (odph_ipv4hdr_t*)odp_packet_l3_ptr(pkt, NULL); if(ip == NULL) { fprintf(stderr, "recv non-ip packet!\n"); return -1; } payload_offset = (ip->ver_ihl & 0xf) << 2; if(ip->proto == 6)//TCP { odph_tcphdr_t *tcp; tcp = (odph_tcphdr_t*)odp_packet_l4_ptr(pkt, NULL); //printf("%d\n", (tcp->hl & 0xf) << 2); payload_offset += (tcp->hl & 0xf) << 2; *len = ntohs(ip->tot_len) - payload_offset; *payload = (unsigned char*)ip + payload_offset; //printf("payload %s\n", (char*)*payload); //printf("len %d\n", *len); return 0; } else if(ip->proto == 17) { payload_offset += 8; *len = ntohs(ip->tot_len) - payload_offset; *payload = (unsigned char*)ip + payload_offset; return 0; } fprintf(stderr, "recv non-tcp/udp packet!\n"); return -1; }
int cls_pkt_set_seq(odp_packet_t pkt) { static uint32_t seq; cls_test_packet_t data; uint32_t offset; odph_ipv4hdr_t *ip; odph_tcphdr_t *tcp; int status; data.magic = DATA_MAGIC; data.seq = ++seq; ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL); offset = odp_packet_l4_offset(pkt); CU_ASSERT_FATAL(offset != 0); if (ip->proto == ODPH_IPPROTO_UDP) status = odp_packet_copydata_in(pkt, offset + ODPH_UDPHDR_LEN, sizeof(data), &data); else { tcp = (odph_tcphdr_t *)odp_packet_l4_ptr(pkt, NULL); status = odp_packet_copydata_in(pkt, offset + tcp->hl * 4, sizeof(data), &data); } return status; }
/* * 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."); }
enum ofp_return_code ofp_gre_processing(odp_packet_t *pkt) { int frag_res = 0; struct ofp_ip *ip = (struct ofp_ip *)odp_packet_l3_ptr(*pkt, NULL); if (odp_unlikely(ofp_cksum_iph(ip, ip->ip_hl))) return OFP_PKT_DROP; if (odp_be_to_cpu_16(ip->ip_off) & 0x3fff) { frag_res = pkt_reassembly(pkt); if (frag_res != OFP_PKT_CONTINUE) return frag_res; ip = (struct ofp_ip *)odp_packet_l3_ptr(*pkt, NULL); } return ofp_inetsw[ofp_ip_protox_gre].pr_input(pkt, ip->ip_hl << 2); }
enum ofp_return_code ipv4_transport_classifier(odp_packet_t *pkt, uint8_t ip_proto) { struct ofp_ip *ip = (struct ofp_ip *)odp_packet_l3_ptr(*pkt, NULL); OFP_DBG("ip_proto=%d pr_input=%p", ip_proto, ofp_inetsw[ofp_ip_protox[ip_proto]].pr_input); return ofp_inetsw[ofp_ip_protox[ip_proto]].pr_input(pkt, ip->ip_hl << 2); }
enum ofp_return_code ofp_gre_processing(odp_packet_t pkt) { struct ofp_ip *ip = (struct ofp_ip *)odp_packet_l3_ptr(pkt, NULL); if (odp_unlikely(ofp_cksum_buffer((uint16_t *) ip, ip->ip_hl<<2))) return OFP_PKT_DROP; if (odp_be_to_cpu_16(ip->ip_off) & 0x3fff) { OFP_UPDATE_PACKET_STAT(rx_ip_frag, 1); pkt = ofp_ip_reass(pkt); if (pkt == ODP_PACKET_INVALID) return OFP_PKT_ON_HOLD; OFP_UPDATE_PACKET_STAT(rx_ip_reass, 1); ip = (struct ofp_ip *)odp_packet_l3_ptr(pkt, NULL); } return ofp_inetsw[ofp_ip_protox_gre].pr_input(pkt, ip->ip_hl << 2); }
proc_result_t pktinf_input(odp_packet_t pkt,void* args){ proc_result_t result; struct pkt_info *info = args; result.packet_handle = pkt; result.next_action = NA_CONTINUE; if(odp_packet_has_ipv4(pkt)){ odph_ipv4hdr_t* hdr = odp_packet_l3_ptr(pkt,NULL); *((uint32be_t*)info->src_ip) = hdr->src_addr; *((uint32be_t*)info->dst_ip) = hdr->dst_addr; }else if(odp_packet_has_ipv6(pkt)){ odph_ipv6hdr_t* hdr = odp_packet_l3_ptr(pkt,NULL); *((ipv6addr*)info->src_ip) = *((ipv6addr*)hdr->src_addr); *((ipv6addr*)info->dst_ip) = *((ipv6addr*)hdr->dst_addr); } if(odp_packet_has_tcp(pkt)||odp_packet_has_udp(pkt)||odp_packet_has_sctp(pkt)){ ports p = *((ports*)odp_packet_l4_ptr(pkt,NULL)); info->src_port = p.src; info->dst_port = p.dest; } return result; }
static enum ofp_return_code ofp_output_ipv4_to_gre( odp_packet_t pkt, struct ofp_ifnet *dev_gre, uint16_t vrfid, struct ofp_nh_entry **nh_new) { struct ofp_ip *ip; struct ofp_greip *greip; uint32_t flags; uint8_t l2_size = 0; int32_t offset; *nh_new = ofp_get_next_hop(vrfid, dev_gre->ip_remote, &flags); if (*nh_new == NULL) return OFP_PKT_DROP; ip = odp_packet_l3_ptr(pkt, NULL); /* Remove eth header, prepend gre + ip */ if (odp_packet_has_l2(pkt)) l2_size = odp_packet_l3_offset(pkt) - odp_packet_l2_offset(pkt); offset = sizeof(*greip) - l2_size; if (offset >= 0) greip = odp_packet_push_head(pkt, offset); else greip = odp_packet_pull_head(pkt, -offset); odp_packet_has_l2_set(pkt, 0); odp_packet_l3_offset_set(pkt, 0); if (!greip) return OFP_PKT_DROP; greip->gi_flags = 0; greip->gi_ptype = odp_cpu_to_be_16(OFP_GREPROTO_IP); greip->gi_i.ip_hl = 5; greip->gi_i.ip_v = 4; greip->gi_i.ip_tos = ip->ip_tos; greip->gi_i.ip_len = odp_cpu_to_be_16(odp_be_to_cpu_16(ip->ip_len) + sizeof(*greip)); greip->gi_i.ip_id = ip->ip_id; greip->gi_i.ip_off = 0; greip->gi_i.ip_ttl = ip->ip_ttl; greip->gi_i.ip_p = OFP_IPPROTO_GRE; greip->gi_i.ip_sum = 0; greip->gi_i.ip_src.s_addr = dev_gre->ip_local; greip->gi_i.ip_dst.s_addr = dev_gre->ip_remote; return OFP_PKT_CONTINUE; }
void test_pktio_error_cos(void) { odp_queue_t queue; odp_packet_t pkt; /*Create an error packet */ pkt = create_packet(false); odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL); /* Incorrect IpV4 version */ ip->ver_ihl = 8 << 4 | ODPH_IPV4HDR_IHL_MIN; ip->chksum = 0; enqueue_loop_interface(pkt); pkt = receive_packet(&queue, ODP_TIME_SEC); /* Error packet should be received in error queue */ CU_ASSERT(queue == queue_list[CLS_ERROR]); odp_packet_free(pkt); }
static enum ofp_return_code ofp_gre_update_target(odp_packet_t pkt, struct ip_out *odata) { struct ofp_nh_entry *nh_new = NULL; if (ofp_output_ipv4_to_gre(pkt, odata->dev_out, odata->vrf, &nh_new) == OFP_PKT_DROP) return OFP_PKT_DROP; odata->nh = nh_new; odata->gw = odata->nh->gw; odata->vlan = odata->nh->vlan; odata->out_port = odata->nh->port; odata->ip = odp_packet_l3_ptr(pkt, NULL); odata->dev_out = ofp_get_ifnet(odata->out_port, odata->vlan); if (!odata->dev_out) return OFP_PKT_DROP; return OFP_PKT_CONTINUE; }
int ofp_in6_cksum(odp_packet_t m, uint8_t nxt, uint32_t off, uint32_t len) { int sum; int tmp; union { uint16_t s[2]; uint32_t l; } l_util; struct ofp_ip6_hdr *ip6 = odp_packet_l3_ptr(m, NULL); /*Pseudo header*/ sum = _ofp_in6_cksum_pseudo(ip6, len, nxt, 0); /* Payload*/ tmp = ofp_getsum(m, odp_packet_l3_offset(m) + off, len); sum += tmp; REDUCE; return (~sum & 0xffff); }
static int pktio_fixup_checksums(odp_packet_t pkt) { odph_ipv4hdr_t *ip; odph_udphdr_t *udp; uint32_t len; ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, &len); if (ip->proto != ODPH_IPPROTO_UDP) { CU_FAIL("unexpected L4 protocol"); return -1; } udp = (odph_udphdr_t *)odp_packet_l4_ptr(pkt, &len); ip->chksum = 0; odph_ipv4_csum_update(pkt); udp->chksum = 0; udp->chksum = odp_cpu_to_be_16(odph_ipv4_udp_chksum(pkt)); return 0; }
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); }
int extract_tuple(odp_packet_t pkt, uint32_t ft[5]) { odph_ipv4hdr_t *ip; odph_udphdr_t *udp; ip = (odph_ipv4hdr_t*)odp_packet_l3_ptr(pkt, NULL); if(ip == NULL) { fprintf(stderr, "recv an invalid packet(is not ip packet)!\n"); return -1; } udp = (odph_udphdr_t*)odp_packet_l4_ptr(pkt, NULL); if(udp == NULL) { fprintf(stderr, "recv an invalid packet(is not tcp/udp packet)!\n"); return -1; } ft[0] = ntohl(ip->src_addr); ft[1] = ntohl(ip->dst_addr); ft[2] = ntohs(udp->src_port); ft[3] = ntohs(udp->dst_port); ft[4] = ip->proto; return 0; }
static void test_dont_fragment_set_pkt_dropped(void) { odp_packet_t pkt; odp_event_t ev; int res; struct ofp_ip *ip; if (create_odp_packet_ip4(&pkt, pkt1_full, sizeof(pkt1_full), 0)) { CU_FAIL("Fail to create packet"); return; } ip = odp_packet_l3_ptr(pkt, NULL); ip->ip_off |= odp_cpu_to_be_16(OFP_IP_DF); res = ofp_ip_output(pkt, &nexthop); CU_ASSERT_EQUAL(res, OFP_PKT_DROP); ev = odp_queue_deq(dev->outq_def); CU_ASSERT_EQUAL(ev, ODP_EVENT_INVALID); odp_packet_free(pkt); }
odp_bool_t verify_ipv4_packet(stream_db_entry_t *stream, odp_packet_t pkt) { ipsec_cache_entry_t *entry = NULL; uint8_t *data; odph_ipv4hdr_t *ip; odph_ahhdr_t *ah = NULL; odph_esphdr_t *esp = NULL; int hdr_len; odph_icmphdr_t *icmp; stream_pkt_hdr_t *test; uint32_t src_ip, dst_ip; if (stream->input.entry) entry = stream->input.entry; else if (stream->output.entry) entry = stream->output.entry; /* Basic IPv4 verify (add checksum verification) */ data = odp_packet_l3_ptr(pkt, NULL); ip = (odph_ipv4hdr_t *)data; data += sizeof(*ip); if (0x45 != ip->ver_ihl) return FALSE; src_ip = odp_be_to_cpu_32(ip->src_addr); dst_ip = odp_be_to_cpu_32(ip->dst_addr); if ((stream->src_ip != src_ip) && stream->output.entry && (stream->output.entry->tun_src_ip != src_ip)) return FALSE; if ((stream->dst_ip != dst_ip) && stream->output.entry && (stream->output.entry->tun_dst_ip != dst_ip)) return FALSE; if ((stream->src_ip != src_ip) && stream->input.entry && (stream->input.entry->tun_src_ip != src_ip)) return FALSE; if ((stream->dst_ip != dst_ip) && stream->input.entry && (stream->input.entry->tun_dst_ip != dst_ip)) return FALSE; /* Find IPsec headers if any and compare against entry */ hdr_len = locate_ipsec_headers(ip, &ah, &esp); /* Cleartext packet */ if (!ah && !esp) goto clear_packet; if (ah) { if (!entry) return FALSE; if (ODP_AUTH_ALG_NULL == entry->ah.alg) return FALSE; if (odp_be_to_cpu_32(ah->spi) != entry->ah.spi) return FALSE; if (ODP_AUTH_ALG_MD5_96 != entry->ah.alg) abort(); } else { if (entry && (ODP_AUTH_ALG_NULL != entry->ah.alg)) return FALSE; } if (esp) { if (!entry) return FALSE; if (ODP_CIPHER_ALG_NULL == entry->esp.alg) return FALSE; if (odp_be_to_cpu_32(esp->spi) != entry->esp.spi) return FALSE; if (ODP_CIPHER_ALG_3DES_CBC != entry->esp.alg) abort(); hdr_len += entry->esp.iv_len; } else { if (entry && (ODP_CIPHER_ALG_NULL != entry->esp.alg)) return FALSE; } data += hdr_len; /* Verify authentication (if present) */ if (ah) { uint8_t ip_tos; uint8_t ip_ttl; uint16_t ip_frag_offset; uint8_t icv[12]; uint8_t hash[EVP_MAX_MD_SIZE]; /* Save/clear mutable fields */ ip_tos = ip->tos; ip_ttl = ip->ttl; ip_frag_offset = odp_be_to_cpu_16(ip->frag_offset); ip->tos = 0; ip->ttl = 0; ip->frag_offset = 0; ip->chksum = 0; memcpy(icv, ah->icv, 12); memset(ah->icv, 0, 12); /* Calculate HMAC and compare */ HMAC(EVP_md5(), entry->ah.key.data, entry->ah.key.length, (uint8_t *)ip, odp_be_to_cpu_16(ip->tot_len), hash, NULL); if (0 != memcmp(icv, hash, sizeof(icv))) return FALSE; ip->proto = ah->next_header; ip->tos = ip_tos; ip->ttl = ip_ttl; ip->frag_offset = odp_cpu_to_be_16(ip_frag_offset); } /* Decipher if present */ if (esp) { odph_esptrl_t *esp_t; DES_key_schedule ks1, ks2, ks3; uint8_t iv[8]; int encrypt_len = ipv4_data_len(ip) - hdr_len; memcpy(iv, esp->iv, sizeof(iv)); 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((uint8_t *)data, (uint8_t *)data, encrypt_len, &ks1, &ks2, &ks3, (DES_cblock *)iv, 0); esp_t = (odph_esptrl_t *)(data + encrypt_len) - 1; ip->proto = esp_t->next_header; } clear_packet: /* Verify IP/ICMP packet */ if (entry && (entry->mode == IPSEC_SA_MODE_TUNNEL) && (ah || esp)) { if (ODPH_IPV4 != ip->proto) return FALSE; odph_ipv4hdr_t *inner_ip = (odph_ipv4hdr_t *)data; icmp = (odph_icmphdr_t *)(inner_ip + 1); data = (uint8_t *)icmp; } else { if (ODPH_IPPROTO_ICMP != ip->proto) return FALSE; icmp = (odph_icmphdr_t *)data; } /* Verify ICMP header */ data += sizeof(*icmp); if (ICMP_ECHO != icmp->type) return FALSE; if (0x1234 != odp_be_to_cpu_16(icmp->un.echo.id)) return FALSE; /* Now check our packet */ test = (stream_pkt_hdr_t *)data; if (STREAM_MAGIC != odp_be_to_cpu_64(test->magic)) return FALSE; return TRUE; }
static enum ofp_return_code ofp_fragment_pkt(odp_packet_t pkt, struct ip_out *odata) { struct ofp_ip *ip, *ip_new; int pl_len, seg_len, pl_pos, flen, hwlen; uint16_t frag, frag_new; uint8_t *payload_new; uint32_t payload_offset; odp_packet_t pkt_new; int ret = OFP_PKT_PROCESSED; ip = (struct ofp_ip *)odp_packet_l3_ptr(pkt, NULL); /* * Copy fragment IP options into a separate buffer, which is * copied into each fragment, except the first one. */ int ip_hlen = ip->ip_hl<<2; int iopts_len = ip_hlen - sizeof(struct ofp_ip); uint8_t fopts[(iopts_len+3)&0xfffc]; uint8_t *iopts = (uint8_t *)(ip + 1); int iopts_pos = 0, fopts_len = 0; while (iopts_pos < iopts_len) { int opt_len = 1; switch (OFP_IPOPT_NUMBER(iopts[iopts_pos])) { case OFP_IPOPT_EOL: case OFP_IPOPT_NOP: break; default: opt_len = iopts[iopts_pos+1]; if (opt_len > iopts_len - iopts_pos) opt_len = iopts_len - iopts_pos; if (OFP_IPOPT_COPIED(iopts[iopts_pos])) { memcpy(fopts + fopts_len, iopts + iopts_pos, opt_len); fopts_len += opt_len; } } iopts_pos += opt_len; } while (fopts_len & 3) fopts[fopts_len++] = 0; pl_len = odp_be_to_cpu_16(ip->ip_len) - ip_hlen; pl_pos = 0; frag = odp_be_to_cpu_16(ip->ip_off); payload_offset = odp_packet_l3_offset(pkt) + ip_hlen; OFP_UPDATE_PACKET_STAT(tx_eth_frag, 1); int first = 1; while (pl_pos < pl_len) { int f_ip_hl = ip->ip_hl; if (!first) f_ip_hl = (sizeof(struct ofp_ip) + fopts_len) >> 2; int f_ip_hlen = f_ip_hl<<2; seg_len = (odata->dev_out->if_mtu - f_ip_hlen) & 0xfff8; flen = (pl_len - pl_pos) > seg_len ? seg_len : (pl_len - pl_pos); hwlen = flen + f_ip_hlen; pkt_new = ofp_packet_alloc(hwlen); if (pkt_new == ODP_PACKET_INVALID) { OFP_ERR("ofp_packet_alloc failed"); return OFP_PKT_DROP; } odp_packet_user_ptr_set(pkt_new, odp_packet_user_ptr(pkt)); *ofp_packet_user_area(pkt_new) = *ofp_packet_user_area(pkt); odp_packet_l2_offset_set(pkt_new, 0); odp_packet_l3_offset_set(pkt_new, 0); ip_new = odp_packet_l3_ptr(pkt_new, NULL); *ip_new = *ip; if (first) memcpy(ip_new + 1, ip + 1, ip_hlen - sizeof(struct ofp_ip)); else memcpy(ip_new + 1, fopts, fopts_len); ip_new->ip_hl = f_ip_hl; payload_new = (uint8_t *)ip_new + f_ip_hlen; if (odp_packet_copy_to_mem(pkt, payload_offset + pl_pos, flen, payload_new) < 0) { OFP_ERR("odp_packet_copy_to_mem failed"); odp_packet_free(pkt_new); return OFP_PKT_DROP; }; ip_new->ip_len = odp_cpu_to_be_16(flen + f_ip_hlen); frag_new = frag + pl_pos/8; pl_pos += flen; if (pl_pos < pl_len) frag_new |= OFP_IP_MF; ip_new->ip_off = odp_cpu_to_be_16(frag_new); odata->ip = ip_new; odata->insert_checksum = 1; ret = ofp_ip_output_continue(pkt_new, odata); if (ret == OFP_PKT_DROP) { odp_packet_free(pkt_new); return OFP_PKT_DROP; } first = 0; } odp_packet_free(pkt); return OFP_PKT_PROCESSED; }
enum ofp_return_code ofp_arp_processing(odp_packet_t *pkt) { struct ofp_arphdr *arp; struct ofp_ifnet *dev = odp_packet_user_ptr(*pkt); struct ofp_ifnet *outdev = dev; uint16_t vlan = dev->vlan; uint8_t inner_from_mac[OFP_ETHER_ADDR_LEN]; uint32_t is_ours; arp = (struct ofp_arphdr *)odp_packet_l3_ptr(*pkt, NULL); if (odp_unlikely(arp == NULL)) { OFP_DBG("arp is NULL"); return OFP_PKT_DROP; } /* save the received arp info */ if (odp_be_to_cpu_16(arp->op) == OFP_ARPOP_REPLY) ofp_add_mac(dev, arp->ip_src, arp->eth_src); OFP_DBG("Device IP: %s, Packet Dest IP: %s", ofp_print_ip_addr(dev->ip_addr), ofp_print_ip_addr(arp->ip_dst)); /* Check for VXLAN interface */ if (odp_unlikely(ofp_if_type(dev) == OFP_IFT_VXLAN)) { ofp_vxlan_update_devices(*pkt, arp, &vlan, &dev, &outdev, inner_from_mac); } is_ours = dev->ip_addr && dev->ip_addr == (ofp_in_addr_t)(arp->ip_dst); if (!is_ours && !global_param->arp.check_interface) { /* This may be for some other local interface. */ uint32_t flags; struct ofp_nh_entry *nh; nh = ofp_get_next_hop(dev->vrf, arp->ip_dst, &flags); if (nh) is_ours = nh->flags & OFP_RTF_LOCAL; } /* on our interface an ARP request */ if (is_ours && odp_be_to_cpu_16(arp->op) == OFP_ARPOP_REQUEST) { struct ofp_arphdr tmp; struct ofp_ether_header tmp_eth; struct ofp_ether_vlan_header tmp_eth_vlan; void *l2_addr = odp_packet_l2_ptr(*pkt, NULL); struct ofp_ether_header *eth = (struct ofp_ether_header *)l2_addr; struct ofp_ether_vlan_header *eth_vlan = (struct ofp_ether_vlan_header *)l2_addr; ofp_add_mac(dev, arp->ip_src, arp->eth_src); if (vlan) tmp_eth_vlan = *eth_vlan; else tmp_eth = *eth; OFP_DBG("Reply to ARPOP_REQ from ip %s" #ifdef SP "on IF %d" #endif " mac %s ip %s", ofp_print_ip_addr(arp->ip_src), #ifdef SP dev->linux_index, #endif ofp_print_mac(dev->mac), ofp_print_ip_addr(arp->ip_dst)); tmp = *arp; tmp.ip_dst = arp->ip_src; tmp.ip_src = arp->ip_dst; memcpy(&tmp.eth_dst, &arp->eth_src, OFP_ETHER_ADDR_LEN); memcpy(&tmp.eth_src, dev->mac, OFP_ETHER_ADDR_LEN); tmp.op = odp_cpu_to_be_16(OFP_ARPOP_REPLY); *arp = tmp; if (vlan) { memcpy(tmp_eth_vlan.evl_dhost, &arp->eth_dst, OFP_ETHER_ADDR_LEN); memcpy(tmp_eth_vlan.evl_shost, &arp->eth_src, OFP_ETHER_ADDR_LEN); *eth_vlan = tmp_eth_vlan; } else { memcpy(tmp_eth.ether_dhost, &arp->eth_dst, OFP_ETHER_ADDR_LEN); memcpy(tmp_eth.ether_shost, &arp->eth_src, OFP_ETHER_ADDR_LEN); *eth = tmp_eth; } if (odp_unlikely(ofp_if_type(dev) == OFP_IFT_VXLAN)) { /* Restore the original vxlan header and update the addresses */ ofp_vxlan_restore_and_update_header (*pkt, outdev, inner_from_mac); } return send_pkt_out(outdev, *pkt); } return OFP_PKT_CONTINUE; }
enum ofp_return_code ofp_ipv4_processing(odp_packet_t pkt) { int res; int protocol = IS_IPV4; uint32_t flags; struct ofp_ip *ip; struct ofp_nh_entry *nh; struct ofp_ifnet *dev = odp_packet_user_ptr(pkt); uint32_t is_ours; ip = (struct ofp_ip *)odp_packet_l3_ptr(pkt, NULL); if (odp_unlikely(ip == NULL)) { OFP_DBG("ip is NULL"); return OFP_PKT_DROP; } if (odp_unlikely(!PHYS_PORT(dev->port))) { switch (dev->port) { case GRE_PORTS: /* Doesn't happen. */ break; case VXLAN_PORTS: { /* Look for the correct device. */ struct vxlan_user_data *saved = odp_packet_user_area(pkt); dev = ofp_get_ifnet(VXLAN_PORTS, saved->vni); if (!dev) return OFP_PKT_DROP; break; } } } #ifndef OFP_PERFORMANCE if (odp_unlikely(ip->ip_v != 4)) return OFP_PKT_DROP; if (odp_unlikely(ofp_cksum_buffer((uint16_t *) ip, ip->ip_hl<<2))) return OFP_PKT_DROP; /* TODO: handle broadcast */ if (dev->bcast_addr == ip->ip_dst.s_addr) return OFP_PKT_DROP; #endif OFP_DBG("Device IP: %s, Packet Dest IP: %s", ofp_print_ip_addr(dev->ip_addr), ofp_print_ip_addr(ip->ip_dst.s_addr)); is_ours = dev->ip_addr == ip->ip_dst.s_addr || OFP_IN_MULTICAST(odp_be_to_cpu_32(ip->ip_dst.s_addr)); if (!is_ours) { /* This may be for some other local interface. */ nh = ofp_get_next_hop(dev->vrf, ip->ip_dst.s_addr, &flags); if (nh) is_ours = nh->flags & OFP_RTF_LOCAL; } if (is_ours) { if (odp_be_to_cpu_16(ip->ip_off) & 0x3fff) { OFP_UPDATE_PACKET_STAT(rx_ip_frag, 1); pkt = ofp_ip_reass(pkt); if (pkt == ODP_PACKET_INVALID) return OFP_PKT_ON_HOLD; OFP_UPDATE_PACKET_STAT(rx_ip_reass, 1); ip = (struct ofp_ip *)odp_packet_l3_ptr(pkt, NULL); } OFP_HOOK(OFP_HOOK_LOCAL, pkt, &protocol, &res); if (res != OFP_PKT_CONTINUE) { OFP_DBG("OFP_HOOK_LOCAL returned %d", res); return res; } OFP_HOOK(OFP_HOOK_LOCAL_IPv4, pkt, NULL, &res); if (res != OFP_PKT_CONTINUE) { OFP_DBG("OFP_HOOK_LOCAL_IPv4 returned %d", res); return res; } return ipv4_transport_classifier(pkt, ip->ip_p); } OFP_HOOK(OFP_HOOK_FWD_IPv4, pkt, nh, &res); if (res != OFP_PKT_CONTINUE) { OFP_DBG("OFP_HOOK_FWD_IPv4 returned %d", res); return res; } if (nh == NULL) { OFP_DBG("nh is NULL, vrf=%d dest=%x", dev->vrf, ip->ip_dst.s_addr); return OFP_PKT_CONTINUE; } if (ip->ip_ttl <= 1) { OFP_DBG("OFP_ICMP_TIMXCEED"); ofp_icmp_error(pkt, OFP_ICMP_TIMXCEED, OFP_ICMP_TIMXCEED_INTRANS, 0, 0); return OFP_PKT_DROP; } /* * Decrement TTL and incrementally change the IP header checksum. */ ip->ip_ttl--; uint16_t a = ~odp_cpu_to_be_16(1 << 8); if (ip->ip_sum >= a) ip->ip_sum -= a; else ip->ip_sum += odp_cpu_to_be_16(1 << 8); #ifdef OFP_SEND_ICMP_REDIRECT /* 1. The interface on which the packet comes into the router is the * same interface on which the packet gets routed out. * 2. The subnet or network of the source IP address is on the same * subnet or network of the next-hop IP address of the routed packet. * 3. Stack configured to send redirects. */ #define INET_SUBNET_PREFIX(addr) \ (odp_be_to_cpu_32(addr) & ((~0) << (32 - dev->masklen))) if (nh->port == dev->port && (INET_SUBNET_PREFIX(ip->ip_src.s_addr) == INET_SUBNET_PREFIX(nh->gw))) { OFP_DBG("send OFP_ICMP_REDIRECT"); ofp_icmp_error(pkt, OFP_ICMP_REDIRECT, OFP_ICMP_REDIRECT_HOST, nh->gw, 0); } #endif return ofp_ip_output(pkt, nh); }
static enum ofp_return_code ofp_fragment_pkt(odp_packet_t pkt, struct ofp_ifnet *dev_out, uint8_t is_local_address) { struct ofp_ip *ip, *ip_new; uint16_t vlan = dev_out->vlan; int tot_len, pl_len, seg_len, pl_pos, flen, hwlen; uint16_t frag, frag_new; uint8_t *payload_new; uint32_t payload_offset; odp_pool_t pkt_pool; odp_packet_t pkt_new; struct ofp_ether_header *eth, *eth_new; struct ofp_ether_vlan_header *eth_vlan, *eth_new_vlan; int ret = OFP_PKT_PROCESSED; if (!vlan) eth = odp_packet_l2_ptr(pkt, NULL); else eth_vlan = odp_packet_l2_ptr(pkt, NULL); ip = (struct ofp_ip *)odp_packet_l3_ptr(pkt, NULL); pkt_pool = ofp_packet_pool; tot_len = odp_be_to_cpu_16(ip->ip_len); pl_len = tot_len - (ip->ip_hl<<2); seg_len = (dev_out->if_mtu - sizeof(struct ofp_ip)) & 0xfff8; pl_pos = 0; frag = odp_be_to_cpu_16(ip->ip_off); payload_offset = odp_packet_l3_offset(pkt) + (ip->ip_hl<<2); OFP_UPDATE_PACKET_STAT(tx_eth_frag, 1); while (pl_pos < pl_len) { flen = (pl_len - pl_pos) > seg_len ? seg_len : (pl_len - pl_pos); hwlen = flen + sizeof(struct ofp_ip) + (vlan ? sizeof(struct ofp_ether_vlan_header) : sizeof(struct ofp_ether_header)); pkt_new = odp_packet_alloc(pkt_pool, hwlen); if (pkt_new == ODP_PACKET_INVALID) { OFP_ERR("odp_packet_alloc failed"); return OFP_PKT_DROP; } odp_packet_user_ptr_set(pkt_new, odp_packet_user_ptr(pkt)); odp_packet_l2_offset_set(pkt_new, 0); if (vlan) { eth_new_vlan = odp_packet_l2_ptr(pkt_new, NULL); *eth_new_vlan = *eth_vlan; ip_new = (struct ofp_ip *)(eth_new_vlan + 1); odp_packet_l3_offset_set(pkt_new, OFP_ETHER_HDR_LEN + OFP_ETHER_VLAN_ENCAP_LEN); } else { eth_new = odp_packet_l2_ptr(pkt_new, NULL); *eth_new = *eth; ip_new = (struct ofp_ip *)(eth_new + 1); odp_packet_l3_offset_set(pkt_new, OFP_ETHER_HDR_LEN); } *ip_new = *ip; payload_new = (uint8_t *)(ip_new + 1); if (odp_packet_copydata_out(pkt, payload_offset + pl_pos, flen, payload_new) < 0) { OFP_ERR("odp_packet_copydata_out failed"); return OFP_PKT_DROP; }; ip_new->ip_len = odp_cpu_to_be_16(flen + sizeof(*ip_new)); frag_new = frag + pl_pos/8; pl_pos += flen; if (pl_pos < pl_len) frag_new |= OFP_IP_MF; ip_new->ip_off = odp_cpu_to_be_16(frag_new); ip_new->ip_sum = 0; ip_new->ip_sum = ofp_cksum_buffer((uint16_t *)ip_new, sizeof(*ip_new)); if (is_local_address) ret = send_pkt_loop(dev_out, pkt_new); else ret = send_pkt_out(dev_out, pkt_new); if (ret == OFP_PKT_DROP) { odp_packet_free(pkt_new); return OFP_PKT_DROP; } } odp_packet_free(pkt); return OFP_PKT_PROCESSED; }
enum ofp_return_code ofp_ipv4_processing(odp_packet_t *pkt) { int frag_res = 0, res; int protocol = IS_IPV4; uint32_t flags; struct ofp_ip *ip; struct ofp_nh_entry *nh; struct ofp_ifnet *dev = odp_packet_user_ptr(*pkt); uint32_t is_ours; ip = (struct ofp_ip *)odp_packet_l3_ptr(*pkt, NULL); if (odp_unlikely(ip == NULL)) { OFP_DBG("ip is NULL"); return OFP_PKT_DROP; } if (odp_unlikely(ofp_if_type(dev) == OFP_IFT_VXLAN)) { struct ofp_packet_user_area *ua; /* Look for the correct device. */ ua = ofp_packet_user_area(*pkt); dev = ofp_get_ifnet(VXLAN_PORTS, ua->vxlan.vni); if (!dev) return OFP_PKT_DROP; } if (odp_unlikely(ip->ip_v != OFP_IPVERSION)) return OFP_PKT_DROP; if (ofp_packet_user_area(*pkt)->chksum_flags & OFP_L3_CHKSUM_STATUS_VALID) { switch (odp_packet_l3_chksum_status(*pkt)) { case ODP_PACKET_CHKSUM_OK: break; case ODP_PACKET_CHKSUM_UNKNOWN: /* Checksum was not validated by HW */ if (odp_unlikely(ofp_cksum_iph(ip, ip->ip_hl))) return OFP_PKT_DROP; break; case ODP_PACKET_CHKSUM_BAD: return OFP_PKT_DROP; break; } ofp_packet_user_area(*pkt)->chksum_flags &= ~OFP_L3_CHKSUM_STATUS_VALID; } else if (odp_unlikely(ofp_cksum_iph(ip, ip->ip_hl))) return OFP_PKT_DROP; /* TODO: handle broadcast */ if (dev->bcast_addr == ip->ip_dst.s_addr) return OFP_PKT_DROP; OFP_DBG("Device IP: %s, Packet Dest IP: %s", ofp_print_ip_addr(dev->ip_addr), ofp_print_ip_addr(ip->ip_dst.s_addr)); is_ours = dev->ip_addr == ip->ip_dst.s_addr || OFP_IN_MULTICAST(odp_be_to_cpu_32(ip->ip_dst.s_addr)); if (!is_ours) { /* This may be for some other local interface. */ nh = ofp_get_next_hop(dev->vrf, ip->ip_dst.s_addr, &flags); if (nh) is_ours = nh->flags & OFP_RTF_LOCAL; } if (is_ours) { if (odp_be_to_cpu_16(ip->ip_off) & 0x3fff) { frag_res = pkt_reassembly(pkt); if (frag_res != OFP_PKT_CONTINUE) return frag_res; ip = (struct ofp_ip *)odp_packet_l3_ptr(*pkt, NULL); } OFP_HOOK(OFP_HOOK_LOCAL, *pkt, &protocol, &res); if (res != OFP_PKT_CONTINUE) { OFP_DBG("OFP_HOOK_LOCAL returned %d", res); return res; } OFP_HOOK(OFP_HOOK_LOCAL_IPv4, *pkt, NULL, &res); if (res != OFP_PKT_CONTINUE) { OFP_DBG("OFP_HOOK_LOCAL_IPv4 returned %d", res); return res; } return ipv4_transport_classifier(pkt, ip->ip_p); } OFP_HOOK(OFP_HOOK_FWD_IPv4, *pkt, nh, &res); if (res != OFP_PKT_CONTINUE) { OFP_DBG("OFP_HOOK_FWD_IPv4 returned %d", res); return res; } if (nh == NULL) { OFP_DBG("nh is NULL, vrf=%d dest=%x", dev->vrf, ip->ip_dst.s_addr); return OFP_PKT_CONTINUE; } if (ip->ip_ttl <= 1) { OFP_DBG("OFP_ICMP_TIMXCEED"); ofp_icmp_error(*pkt, OFP_ICMP_TIMXCEED, OFP_ICMP_TIMXCEED_INTRANS, 0, 0); return OFP_PKT_DROP; } /* * Decrement TTL and incrementally change the IP header checksum. */ ip->ip_ttl--; uint16_t a = ~odp_cpu_to_be_16(1 << 8); if (ip->ip_sum >= a) ip->ip_sum -= a; else ip->ip_sum += odp_cpu_to_be_16(1 << 8); #ifdef OFP_SEND_ICMP_REDIRECT /* 1. The interface on which the packet comes into the router is the * same interface on which the packet gets routed out. * 2. The subnet or network of the source IP address is on the same * subnet or network of the next-hop IP address of the routed packet. * 3. Stack configured to send redirects. */ #define INET_SUBNET_PREFIX(addr) \ (odp_be_to_cpu_32(addr) & ((~0) << (32 - dev->masklen))) if (nh->port == dev->port && (INET_SUBNET_PREFIX(ip->ip_src.s_addr) == INET_SUBNET_PREFIX(nh->gw))) { OFP_DBG("send OFP_ICMP_REDIRECT"); ofp_icmp_error(*pkt, OFP_ICMP_REDIRECT, OFP_ICMP_REDIRECT_HOST, nh->gw, 0); } #endif return ofp_ip_output_common_inline(*pkt, nh, 0); }
enum ofp_return_code ofp_nd6_ns_output(struct ofp_ifnet *dev, uint8_t *daddr6, uint8_t *taddr6) { size_t size = 0; size_t iter = 0; struct ofp_ether_header *e1; struct ofp_ether_vlan_header *e2; struct ofp_ip6_hdr *ip6hdr; struct ofp_icmp6_hdr *icmp; odp_packet_t pkt; if (dev->vlan) size = sizeof(struct ofp_ether_vlan_header); else size = sizeof(struct ofp_ether_header); size += sizeof(struct ofp_ip6_hdr) + sizeof(struct ofp_icmp6_hdr) + 16 /*target addr*/ + 8; /* option*/ pkt = ofp_packet_alloc(size); if (pkt == ODP_PACKET_INVALID) return OFP_PKT_DROP; odp_packet_has_eth_set(pkt, 1); odp_packet_l2_offset_set(pkt, iter); if (dev->vlan) { e2 = (struct ofp_ether_vlan_header *)odp_packet_l2_ptr(pkt, NULL); iter += sizeof(*e2); memset(e2->evl_dhost, 0xff, OFP_ETHER_ADDR_LEN); memcpy(e2->evl_shost, dev->mac, OFP_ETHER_ADDR_LEN); 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_IPV6); } else { e1 = (struct ofp_ether_header *)odp_packet_l2_ptr(pkt, NULL); iter += sizeof(*e1); memset(e1->ether_dhost, 0xff, OFP_ETHER_ADDR_LEN); memcpy(e1->ether_shost, dev->mac, OFP_ETHER_ADDR_LEN); e1->ether_type = odp_cpu_to_be_16(OFP_ETHERTYPE_IPV6); } odp_packet_l3_offset_set(pkt, iter); ip6hdr = (struct ofp_ip6_hdr *)odp_packet_l3_ptr(pkt, NULL); iter += sizeof(*ip6hdr); ip6hdr->ofp_ip6_flow = 0; ip6hdr->ofp_ip6_vfc = OFP_IPV6_VERSION; ip6hdr->ofp_ip6_plen = odp_cpu_to_be_16(32); /*sizeof(*icmp) + sizeof taddr + 8*/ /* for checksum calculation */ ip6hdr->ofp_ip6_nxt = 0; ip6hdr->ofp_ip6_hlim = OFP_IPPROTO_ICMPV6; /* XXX should be multicast address*/ memcpy(ip6hdr->ip6_src.ofp_s6_addr, dev->ip6_addr, 16); if (ofp_ip6_is_set(daddr6)) memcpy(ip6hdr->ip6_dst.ofp_s6_addr, daddr6, 16); else { /* Solicited-node multicast address */ ip6hdr->ip6_dst.ofp_s6_addr16[0] = OFP_IPV6_ADDR_INT16_MLL; ip6hdr->ip6_dst.ofp_s6_addr16[1] = 0; ip6hdr->ip6_dst.ofp_s6_addr32[1] = 0; ip6hdr->ip6_dst.ofp_s6_addr32[2] = OFP_IPV6_ADDR_INT32_ONE; ip6hdr->ip6_dst.ofp_s6_addr32[3] = *((uint32_t *)taddr6 + 3); ip6hdr->ip6_dst.ofp_s6_addr[12] = 0xff; } odp_packet_l4_offset_set(pkt, iter); icmp = (struct ofp_icmp6_hdr *)odp_packet_l4_ptr(pkt, NULL); iter += sizeof(*icmp) + 8 /* option */; icmp->icmp6_type = OFP_ND_NEIGHBOR_SOLICIT; icmp->icmp6_code = 0; icmp->icmp6_cksum = 0; icmp->ofp_icmp6_data32[0] = 0; /* Reserved */ memcpy(&icmp->ofp_icmp6_data8[4], taddr6, 16); /* Option: Source link-layer address */ icmp->ofp_icmp6_data8[20] = OFP_ND_OPT_SOURCE_LINKADDR; icmp->ofp_icmp6_data8[21] = 1; /* 8 octets */ memcpy(&icmp->ofp_icmp6_data8[22], dev->mac, 6); icmp->icmp6_cksum = ofp_cksum_buffer(&ip6hdr->ofp_ip6_plen, 68); ip6hdr->ofp_ip6_nxt = OFP_IPPROTO_ICMPV6; ip6hdr->ofp_ip6_hlim = 255; if (send_pkt_out(dev, pkt) == OFP_PKT_DROP) { OFP_ERR("Drop packet"); odp_packet_free(pkt); return OFP_PKT_DROP; } return OFP_PKT_PROCESSED; }
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."); }
odp_packet_t create_packet(odp_pool_t pool, bool vlan, odp_atomic_u32_t *seq, bool flag_udp) { uint32_t seqno; odph_ethhdr_t *ethhdr; odph_udphdr_t *udp; odph_tcphdr_t *tcp; odph_ipv4hdr_t *ip; uint8_t payload_len; char src_mac[ODPH_ETHADDR_LEN] = {0}; char dst_mac[ODPH_ETHADDR_LEN] = {0}; uint32_t addr = 0; uint32_t mask; int offset; odp_packet_t pkt; int packet_len = 0; payload_len = sizeof(cls_test_packet_t); packet_len += ODPH_ETHHDR_LEN; packet_len += ODPH_IPV4HDR_LEN; if (flag_udp) packet_len += ODPH_UDPHDR_LEN; else packet_len += ODPH_TCPHDR_LEN; packet_len += payload_len; if (vlan) packet_len += ODPH_VLANHDR_LEN; pkt = odp_packet_alloc(pool, packet_len); CU_ASSERT_FATAL(pkt != ODP_PACKET_INVALID); /* Ethernet Header */ offset = 0; odp_packet_l2_offset_set(pkt, offset); ethhdr = (odph_ethhdr_t *)odp_packet_l2_ptr(pkt, NULL); memcpy(ethhdr->src.addr, src_mac, ODPH_ETHADDR_LEN); memcpy(ethhdr->dst.addr, dst_mac, ODPH_ETHADDR_LEN); offset += sizeof(odph_ethhdr_t); if (vlan) { /* Default vlan header */ uint8_t *parseptr; odph_vlanhdr_t *vlan; vlan = (odph_vlanhdr_t *)(ðhdr->type); parseptr = (uint8_t *)vlan; vlan->tci = odp_cpu_to_be_16(0); vlan->tpid = odp_cpu_to_be_16(ODPH_ETHTYPE_VLAN); offset += sizeof(odph_vlanhdr_t); parseptr += sizeof(odph_vlanhdr_t); uint16be_t *type = (uint16be_t *)(void *)parseptr; *type = odp_cpu_to_be_16(ODPH_ETHTYPE_IPV4); } else { ethhdr->type = odp_cpu_to_be_16(ODPH_ETHTYPE_IPV4); } odp_packet_l3_offset_set(pkt, offset); /* ipv4 */ ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL); parse_ipv4_string(CLS_DEFAULT_SADDR, &addr, &mask); ip->dst_addr = odp_cpu_to_be_32(addr); parse_ipv4_string(CLS_DEFAULT_DADDR, &addr, &mask); ip->src_addr = odp_cpu_to_be_32(addr); ip->ver_ihl = ODPH_IPV4 << 4 | ODPH_IPV4HDR_IHL_MIN; if (flag_udp) ip->tot_len = odp_cpu_to_be_16(ODPH_UDPHDR_LEN + payload_len + ODPH_IPV4HDR_LEN); else ip->tot_len = odp_cpu_to_be_16(ODPH_TCPHDR_LEN + payload_len + ODPH_IPV4HDR_LEN); ip->ttl = 128; if (flag_udp) ip->proto = ODPH_IPPROTO_UDP; else ip->proto = ODPH_IPPROTO_TCP; seqno = odp_atomic_fetch_inc_u32(seq); ip->id = odp_cpu_to_be_16(seqno); ip->chksum = 0; ip->chksum = odph_ipv4_csum_update(pkt); offset += ODPH_IPV4HDR_LEN; /* udp */ if (flag_udp) { odp_packet_l4_offset_set(pkt, offset); udp = (odph_udphdr_t *)odp_packet_l4_ptr(pkt, NULL); udp->src_port = odp_cpu_to_be_16(CLS_DEFAULT_SPORT); udp->dst_port = odp_cpu_to_be_16(CLS_DEFAULT_DPORT); udp->length = odp_cpu_to_be_16(payload_len + ODPH_UDPHDR_LEN); udp->chksum = 0; } else { odp_packet_l4_offset_set(pkt, offset); tcp = (odph_tcphdr_t *)odp_packet_l4_ptr(pkt, NULL); tcp->src_port = odp_cpu_to_be_16(CLS_DEFAULT_SPORT); tcp->dst_port = odp_cpu_to_be_16(CLS_DEFAULT_DPORT); tcp->hl = ODPH_TCPHDR_LEN / 4; /* TODO: checksum field has to be updated */ tcp->cksm = 0; } /* set pkt sequence number */ cls_pkt_set_seq(pkt); return pkt; }
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; }