void test_cos_with_l2_priority(void)
{
	odp_packet_t pkt;
	odph_ethhdr_t *ethhdr;
	odph_vlanhdr_t *vlan;
	odp_queue_t queue;
	uint32_t seq;

	uint8_t i;
	for (i = 0; i < CLS_L2_QOS_MAX; i++) {
		pkt = create_packet(true);
		seq = cls_pkt_get_seq(pkt);
		ethhdr = (odph_ethhdr_t *)odp_packet_l2_ptr(pkt, NULL);
		vlan = (odph_vlanhdr_t *)(&ethhdr->type);
		vlan->tci = odp_cpu_to_be_16(i << 13);
		enqueue_loop_interface(pkt);
		pkt = receive_packet(&queue, ODP_TIME_SEC);
		CU_ASSERT(queue == queue_list[CLS_L2_QOS_0 + i]);
		CU_ASSERT(seq == cls_pkt_get_seq(pkt));
		odp_packet_free(pkt);
	}
}
Esempio n. 2
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);
}
Esempio n. 3
0
static void
test_send_frame_novlan_to_vlan(void)
{
	odp_packet_t pkt = ODP_PACKET_INVALID;
	odp_event_t ev;
	struct ofp_ether_vlan_header *eth_vlan;
	uint8_t *buf;
	int res;

	if (create_odp_packet_ip4(&pkt, test_frame, sizeof(test_frame), 0)) {
		CU_FAIL("Fail to create packet");
		return;
	}

	res = ofp_send_frame(dev_vlan, pkt);
	CU_ASSERT_EQUAL(res, OFP_PKT_PROCESSED);

	ev = odp_queue_deq(dev->outq_def);
	CU_ASSERT_NOT_EQUAL_FATAL(ev, ODP_EVENT_INVALID);

	pkt = odp_packet_from_event(ev);
	CU_ASSERT_EQUAL_FATAL(odp_packet_len(pkt), sizeof(test_frame) + 4);

	eth_vlan = odp_packet_l2_ptr(pkt, NULL);
	if (memcmp(eth_vlan, test_frame, 2 * OFP_ETHER_ADDR_LEN))
		CU_FAIL("Frame data mismatch.");

	CU_ASSERT_EQUAL(eth_vlan->evl_encap_proto,
			odp_cpu_to_be_16(OFP_ETHERTYPE_VLAN));
	CU_ASSERT_EQUAL(eth_vlan->evl_tag,
			odp_cpu_to_be_16(dev_vlan->vlan));

	buf = (uint8_t *)eth_vlan;
	if (memcmp(&buf[16], &test_frame[12],
		   sizeof(test_frame) - 2 * OFP_ETHER_ADDR_LEN))
		CU_FAIL("Frame data mismatch.");
}
Esempio n. 4
0
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();
}
Esempio n. 5
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;
}
Esempio n. 6
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.");
}
Esempio n. 7
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;
}
Esempio n. 8
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;
}
Esempio n. 9
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;
}
Esempio n. 10
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;
}
Esempio n. 11
0
enum ofp_return_code ofp_eth_vlan_processing(odp_packet_t pkt)
{
	uint16_t vlan = 0, ethtype;
	struct ofp_ether_header *eth;
	struct ofp_ifnet *ifnet = odp_packet_user_ptr(pkt);

	eth = (struct ofp_ether_header *)odp_packet_l2_ptr(pkt, NULL);
#ifndef OFP_PERFORMANCE
	if (odp_unlikely(eth == NULL)) {
		OFP_DBG("eth is NULL");
		return OFP_PKT_DROP;
	}

	if (odp_unlikely(odp_packet_l3_ptr(pkt, NULL) == NULL ||
		(uintptr_t) odp_packet_l3_ptr(pkt, NULL) !=
			(uintptr_t)odp_packet_l2_ptr(pkt, NULL) +
				sizeof(struct ofp_ether_header))) {
		OFP_DBG("odp_packet_l3_offset_set");
		odp_packet_l3_offset_set(pkt, sizeof(struct ofp_ether_header));
	}
#endif
	ethtype = odp_be_to_cpu_16(eth->ether_type);

	if (ethtype == OFP_ETHERTYPE_VLAN) {
		struct ofp_ether_vlan_header *vlan_hdr;

		vlan_hdr = (struct ofp_ether_vlan_header *)eth;
		vlan = OFP_EVL_VLANOFTAG(odp_be_to_cpu_16(vlan_hdr->evl_tag));
		ethtype = odp_be_to_cpu_16(vlan_hdr->evl_proto);
		ifnet = ofp_get_ifnet(ifnet->port, vlan);
		if (!ifnet)
			return OFP_PKT_DROP;
		if (odp_likely(ifnet->port != VXLAN_PORTS))
			odp_packet_user_ptr_set(pkt, ifnet);
#ifndef OFP_PERFORMANCE
		odp_packet_l3_offset_set(pkt, sizeof(struct ofp_ether_vlan_header));
#endif
	}

	OFP_DBG("ETH TYPE = %04x", ethtype);

	/* network layer classifier */
	switch (ethtype) {
	/* STUB: except for ARP, just terminate all traffic to slowpath.
	 * FIXME: test/implement other cases */
#ifdef INET
	case OFP_ETHERTYPE_IP:
		return ofp_ipv4_processing(pkt);
#endif /* INET */
#ifdef INET6
	case OFP_ETHERTYPE_IPV6:
		return ofp_ipv6_processing(pkt);
#endif /* INET6 */
#if 0
	case OFP_ETHERTYPE_MPLS:
		return OFP_PKT_DROP;
#endif
	case OFP_ETHERTYPE_ARP:
		return ofp_arp_processing(pkt);
	default:
		return OFP_PKT_CONTINUE;
	}
}
Esempio n. 12
0
static void
test_ofp_packet_input_forwarding_to_output(void)
{
    odp_packet_t pkt;
    odp_event_t ev;
    int res;

    /* Call ofp_packet_input using a pkt with destination ip
     * that does NOT match the local ip on ifnet and a route is found.
     * ARP is found for gateway IP.
     * Function returns OFP_PKT_PROCESSED and
     * packet is forwarded to ofp_ip_output.*/
    unsigned char ll_addr[13] = "123456789012";

    my_test_val = TEST_FORWARD_HOOK;

    CU_ASSERT_EQUAL(
        ofp_ipv4_lookup_mac(dst_ipaddr + 1, ll_addr, ifnet), -1);
    CU_ASSERT_EQUAL(
        ofp_arp_ipv4_insert(dst_ipaddr + 1, ll_addr, ifnet), 0);

    if (create_odp_packet_ip4(&pkt, test_frame, sizeof(test_frame),
                              dst_ipaddr, 0)) {
        CU_FAIL("Fail to create packet");
        return;
    }

    res = ofp_packet_input(pkt, interface_queue[port],
                           ofp_eth_vlan_processing);
    CU_ASSERT_EQUAL(res, OFP_PKT_PROCESSED);
    CU_ASSERT_NOT_EQUAL(ev = odp_queue_deq(ifnet->outq_def),
                        ODP_EVENT_INVALID);
    CU_ASSERT_EQUAL(odp_queue_deq(ifnet->outq_def), ODP_EVENT_INVALID);

#ifdef SP
    CU_ASSERT_EQUAL(odp_queue_deq(ifnet->spq_def), ODP_EVENT_INVALID);
#endif /* SP */

    CU_ASSERT_EQUAL(odp_packet_len(pkt), sizeof(test_frame));

    pkt = odp_packet_from_event(ev);
    struct ofp_ip *ip_in_pkt_data =
        (struct ofp_ip *)(in_pkt_data + OFP_ETHER_HDR_LEN);
    ip_in_pkt_data->ip_ttl--;

#ifdef OFP_PERFORMANCE
    /*checksum is not filled on ip_output*/
    ip_in_pkt_data->ip_sum =
        ((struct ofp_ip *)odp_packet_l3_ptr(pkt, NULL))->ip_sum;
#else
    ip_in_pkt_data->ip_sum = 0;
    ip_in_pkt_data->ip_sum = ofp_cksum_buffer((uint16_t *)ip_in_pkt_data,
                             ip_in_pkt_data->ip_hl<<2);

#endif

    if (memcmp((uint8_t *)odp_packet_data(pkt) + odp_packet_l3_offset(pkt),
               in_pkt_data + OFP_ETHER_HDR_LEN,
               sizeof(test_frame) - OFP_ETHER_HDR_LEN))
        CU_FAIL("corrupt l3 + data forwarded");
    struct ofp_ether_header *eth =
        (struct ofp_ether_header *)odp_packet_l2_ptr(pkt, NULL);

    if (memcmp(eth->ether_dhost, ll_addr, OFP_ETHER_ADDR_LEN))
        CU_FAIL("Bad destination mac address on the forwarded packet");
    CU_ASSERT_EQUAL(eth->ether_type, odp_cpu_to_be_16(OFP_ETHERTYPE_IP));

    CU_PASS("ofp_packet_input_forwarding_to_output");
}
Esempio n. 13
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];

	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(!PHYS_PORT(dev->port))) {
		switch (dev->port) {
		case GRE_PORTS:
			/* Never happens. */
			break;
		case VXLAN_PORTS: {
			ofp_vxlan_update_devices(arp, &vlan, &dev, &outdev,
						 inner_from_mac);
			break;
		}
		} /* switch */
	}

	/* on our interface an ARP request */
	if ((dev->ip_addr) && dev->ip_addr == (ofp_in_addr_t)(arp->ip_dst) &&
	    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(!PHYS_PORT(dev->port))) {
			switch (dev->port) {
			case GRE_PORTS:
				/* Never happens. */
				break;
			case VXLAN_PORTS: {
				/* Restore the original vxlan header and
				   update the addresses */
				ofp_vxlan_restore_and_update_header
					(pkt, outdev, inner_from_mac);
				break;
			}
			} /* switch */
		} /* not phys port */

		return send_pkt_out(outdev, pkt);
	}
	return OFP_PKT_CONTINUE;
}