Пример #1
0
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 *)&eth->ether_shost);
	}
}
Пример #2
0
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);
}
Пример #4
0
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);
}
Пример #5
0
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 *)&eth->ether_shost);
	}
}
Пример #6
0
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;
}
Пример #7
0
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;
}
Пример #8
0
/*
 * 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.");
}
Пример #9
0
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);
}
Пример #10
0
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);
}
Пример #11
0
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);
}
Пример #12
0
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;
}
Пример #13
0
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;
}
Пример #14
0
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);
}
Пример #15
0
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;
}
Пример #16
0
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);
}
Пример #17
0
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;
}
Пример #18
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);
}
Пример #19
0
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;
}
Пример #20
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);
}
Пример #21
0
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;
}
Пример #22
0
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;
}
Пример #23
0
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;
}
Пример #24
0
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);
}
Пример #25
0
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;
}
Пример #26
0
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);
}
Пример #27
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;
}
Пример #28
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.");
}
Пример #29
0
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 *)(&ethhdr->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;
}
Пример #30
0
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;
}