Esempio n. 1
0
static int
create_odp_packet_ip4(odp_packet_t *opkt, uint8_t *pkt_data, int plen,
                      uint32_t dst_addr)
{
    odp_pool_t pool;
    uint8_t *buf;
    odp_packet_t pkt = ODP_PACKET_INVALID;
    struct ofp_ip *iphdr;

    memset(orig_pkt_data, 0x0, sizeof(orig_pkt_data));

    pool = odp_pool_lookup("packet_pool");
    if (pool == ODP_POOL_INVALID) {
        fail_with_odp("ODP packet_pool not found\n");
        return -1;
    }

    pkt = odp_packet_alloc(pool, plen);
    if (pkt == ODP_PACKET_INVALID) {
        fail_with_odp("ODP packet alloc failed");
        return -1;
    }

    buf = odp_packet_data(pkt);

    if (odp_packet_copy_from_mem(pkt, 0, plen, pkt_data) < 0) {
        fail_with_odp("Packet data copy failed\n");
        return -1;
    };

    iphdr = (struct ofp_ip *)&buf[OFP_ETHER_HDR_LEN];

    /* changes to the default packet. Recalculate ip checksum */
    if (dst_addr) {
        iphdr->ip_dst.s_addr = dst_addr;
        iphdr->ip_sum = 0;
        iphdr->ip_sum =
            ofp_cksum_buffer((uint16_t *)iphdr, iphdr->ip_hl<<2);
    }
    /* END OF changes to the default packet */

    odp_packet_has_eth_set(pkt, 1);
    odp_packet_has_ipv4_set(pkt, 1);
    odp_packet_l2_offset_set(pkt, 0);
    odp_packet_l3_offset_set(pkt, OFP_ETHER_HDR_LEN);
    odp_packet_l4_offset_set(pkt, OFP_ETHER_HDR_LEN + (iphdr->ip_hl<<2));

    *opkt = pkt;

    memcpy(orig_pkt_data, pkt_data, plen);

    return 0;
}
Esempio n. 2
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);
}
Esempio n. 3
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. 4
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. 5
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);
}
Esempio n. 6
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");
}