Esempio n. 1
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. 2
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;
}
Esempio n. 3
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;
	}
}