예제 #1
0
static void
test_sinlge_port_basic(void)
{
	int port = 0;
	uint16_t vlan = 0;
	uint16_t vrf = 1;
	uint32_t ifaddr = 0x650AA8C0; /* C0.A8.0A.65 = 192.168.10.101 */
	int masklen = 24;
	uint32_t bcast = ifaddr | odp_cpu_to_be_32(0xFF);
	struct ofp_ifnet *dev;
	struct ofp_nh_entry *nh;
	const char *res;

	res = ofp_config_interface_up_v4(port, vlan, vrf, ifaddr, masklen);
	CU_ASSERT_PTR_NULL_FATAL(res);

	dev = ofp_get_ifnet(port, vlan);
	assert_dev(dev, port, vlan, vrf, ifaddr, ifmtu, masklen, bcast,
		   link_local);
	nh = ofp_get_next_hop(vrf, ifaddr, NULL);
	assert_next_hop(nh, 0, port, vlan);


	res = ofp_config_interface_down(port, vlan);
	CU_ASSERT_PTR_NULL_FATAL(res);

	dev = ofp_get_ifnet(port, vlan);
	assert_dev(dev, port, vlan, vrf, 0, ifmtu, masklen, bcast, link_local);
	nh = ofp_get_next_hop(vrf, ifaddr, NULL);
	CU_ASSERT_PTR_NULL(nh);
}
예제 #2
0
/*
 * INIT
 */
static void init_ifnet(void)
{
	char str[256];

	ofp_config_interface_up_v4(port, vlan, vrf, dev_ip, 24);

	/* port 0 */
	dev = ofp_get_ifnet(port, vlan);
	memcpy(dev->mac, dev_mac, OFP_ETHER_ADDR_LEN);
	dev->if_mtu = def_mtu;
#ifdef SP
	dev->linux_index = port + 3; /* an if index of Linux != port val */
	ofp_update_ifindex_lookup_tab(dev);
#endif /* SP */

	dev->pkt_pool = odp_pool_lookup(pool_name);

	sprintf(str, "out default queue:%d", port);
	dev->outq_def = odp_queue_create(str, NULL);
	if (dev->outq_def == ODP_QUEUE_INVALID) {
		fail_with_odp("Out default queue create failed.\n");
		return;
	}

	dev->out_queue_num = 1;
	dev->out_queue_type = OFP_OUT_QUEUE_TYPE_QUEUE;

	/* port 0 vlan 1 */
	ofp_config_interface_up_v4(port, vlan + 1, vrf, dev_ip + 1, 24);

	dev_vlan = ofp_get_ifnet(port, vlan + 1);
	memcpy(dev_vlan->mac, dev_vlan_mac, OFP_ETHER_ADDR_LEN);
	dev_vlan->if_mtu = def_mtu;
#ifdef SP
	dev_vlan->linux_index = port + 4; /* an if index of Linux != port val */
	ofp_update_ifindex_lookup_tab(dev_vlan);
#endif /* SP */

	dev_vlan->pkt_pool = odp_pool_lookup(pool_name);

	sprintf(str, "out default queue:%d", port);
	dev_vlan->outq_def = odp_queue_create(str, NULL);
	if (dev_vlan->outq_def == ODP_QUEUE_INVALID) {
		fail_with_odp("Out default queue create failed.\n");
		return;
	}

	/* Tunnels */
	ofp_config_interface_up_tun(GRE_PORTS, 100, 0, dev_ip, tun_rem_ip,
				      tun_p2p, tun_addr, tun_mask);

	/* No nexthop for tunnel remote address */
	ofp_config_interface_up_tun(GRE_PORTS, 200, 0, dev_ip, 0x08070605,
				      tun_p2p + 1, tun_addr + 1, tun_mask);
}
예제 #3
0
static void
test_gre_port(void)
{
	int port = 0;
	uint16_t vlan = 10;
	uint16_t vrf = 1;
	uint32_t ifaddr = 0x650AA8C0; /* C0.A8.0A.65 = 192.168.10.101 */
	int masklen = 24, gre_ml = 32;
	uint16_t greid = 100;
	uint32_t greaddr = 0x010A0A0A;
	uint32_t grep2p = 0x020A0A0A;
	struct ofp_ifnet *dev;
	struct ofp_nh_entry *nh;
	const char *res;

	res = ofp_config_interface_up_v4(port, vlan, vrf, ifaddr, masklen);
	CU_ASSERT_PTR_NULL_FATAL(res);

	/* Non-existent endpoint in vrf */
	res = ofp_config_interface_up_tun(GRE_PORTS, greid, vrf + 1, ifaddr,
					    ifaddr + 1, greaddr, grep2p,
					    gre_ml);
	CU_ASSERT_PTR_NOT_NULL_FATAL(res);
	dev = ofp_get_ifnet(GRE_PORTS, greid);
	CU_ASSERT_PTR_NULL_FATAL(dev);

	/* Successful test */
	res = ofp_config_interface_up_tun(GRE_PORTS, greid, vrf, ifaddr,
					    ifaddr + 1, grep2p, greaddr,
					    gre_ml);
	CU_ASSERT_PTR_NULL_FATAL(res);
	dev = ofp_get_ifnet(GRE_PORTS, greid);
	CU_ASSERT_PTR_NOT_NULL_FATAL(dev);
	CU_ASSERT_EQUAL(dev->ip_local, ifaddr);
	CU_ASSERT_EQUAL(dev->ip_remote, ifaddr + 1);
	CU_ASSERT_EQUAL(dev->ip_addr, greaddr);
	CU_ASSERT_EQUAL(dev->ip_p2p, grep2p);
	CU_ASSERT_EQUAL(dev->masklen, gre_ml);
	CU_ASSERT_EQUAL(dev->if_mtu, ifmtu - 24);

	nh = ofp_get_next_hop(vrf, grep2p, NULL);
	assert_next_hop(nh, 0, GRE_PORTS, greid);

	res = ofp_config_interface_down(port, vlan);
	CU_ASSERT_PTR_NULL_FATAL(res);
	res = ofp_config_interface_down(GRE_PORTS, greid);
	CU_ASSERT_PTR_NULL_FATAL(res);
	dev = ofp_get_ifnet(GRE_PORTS, greid);
	CU_ASSERT_PTR_NULL_FATAL(dev);
}
예제 #4
0
static void
test_two_ports_vlan(void)
{
	int port = 0;
	uint16_t vlan = 0, vlan1 = 100;
	uint16_t vrf = 1, vrf1 = 2;
	uint32_t ifaddr = 0x650AA8C0; /* C0.A8.0A.65 = 192.168.10.101 */
	uint32_t ifaddr1 = 0x650AA8C1;
	int masklen = 24, masklen1 = 20;
	uint32_t bcast = ifaddr | odp_cpu_to_be_32(0xFF);
	uint32_t bcast1 = ifaddr1 | odp_cpu_to_be_32(0xFFF);
	struct ofp_ifnet *dev;
	struct ofp_nh_entry *nh;
	const char *res;

	res = ofp_config_interface_up_v4(port, vlan, vrf, ifaddr, masklen);
	CU_ASSERT_PTR_NULL_FATAL(res);
	res = ofp_config_interface_up_v4(port, vlan1, vrf1, ifaddr1, masklen1);
	CU_ASSERT_PTR_NULL_FATAL(res);

	dev = ofp_get_ifnet(port, vlan);
	CU_ASSERT_PTR_NOT_NULL_FATAL(dev);
	assert_dev(dev, port, vlan, vrf, ifaddr, ifmtu, masklen, bcast,
		   link_local);
	nh = ofp_get_next_hop(vrf, ifaddr, NULL);
	assert_next_hop(nh, 0, port, vlan);

	dev = ofp_get_ifnet(port, vlan1);
	assert_dev(dev, port, vlan1, vrf1, ifaddr1, ifmtu, masklen1, bcast1,
		   link_local);
	nh = ofp_get_next_hop(vrf1, ifaddr1, NULL);
	assert_next_hop(nh, 0, port, vlan1);

	res = ofp_config_interface_down(port, vlan);
	CU_ASSERT_PTR_NULL_FATAL(res);
	res = ofp_config_interface_down(port, vlan1);
	CU_ASSERT_PTR_NULL_FATAL(res);

	dev = ofp_get_ifnet(port, vlan);
	assert_dev(dev, port, vlan, vrf, 0, ifmtu, masklen, bcast, link_local);
	nh = ofp_get_next_hop(vrf, ifaddr, NULL);
	CU_ASSERT_PTR_NULL(nh);

	dev = ofp_get_ifnet(port, vlan1);
	CU_ASSERT_PTR_NULL_FATAL(dev);
	nh = ofp_get_next_hop(vrf1, ifaddr1, NULL);
	CU_ASSERT_PTR_NULL(nh);
}
예제 #5
0
static void init_ifnet(void)
{
    char str[256];

    ofp_config_interface_up_v4(port, vlan, vrf, dev_ip, 24);

    dev = ofp_get_ifnet(port, vlan);
    memcpy(dev->mac, dev_mac, OFP_ETHER_ADDR_LEN);
    dev->if_mtu = def_mtu;
#ifdef SP
    dev->linux_index = port + 3; /* an if index of Linux != port val */
    ofp_update_ifindex_lookup_tab(dev);
#endif /* SP */

    dev->pkt_pool = odp_pool_lookup("packet_pool");

    sprintf(str, "out default queue:%d", port);
    dev->outq_def = odp_queue_create(str, NULL);
    if (dev->outq_def == ODP_QUEUE_INVALID) {
        fail_with_odp("Out default queue create failed.\n");
        return;
    }

    dev->out_queue_num = 1;
    dev->out_queue_type = OFP_OUT_QUEUE_TYPE_QUEUE;
}
예제 #6
0
enum ofp_return_code send_pkt_loop(struct ofp_ifnet *dev,
	odp_packet_t pkt)
{
	if (odp_queue_enq(ofp_get_ifnet(dev->port, 0)->loopq_def,
		odp_packet_to_event(pkt)))
		return OFP_PKT_DROP;
	return OFP_PKT_PROCESSED;
}
예제 #7
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);

	if (odp_unlikely(eth == NULL)) {
		OFP_DBG("eth is NULL");
		return OFP_PKT_DROP;
	}

	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(ofp_if_type(ifnet) != OFP_IFT_VXLAN))
			odp_packet_user_ptr_set(*pkt, ifnet);
	}

	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;
	}
}
예제 #8
0
/*
 * INIT
 */
static void
test_init_ifnet(void)
{
    char str[256];

    ofp_config_interface_up_v4(port, vlan, vrf, local_ip, 24);

    ifnet = ofp_get_ifnet(port, vlan);
    ifnet->pkt_pool = odp_pool_lookup("packet_pool");

#ifdef SP
    ifnet->linux_index = port + 3; /* an if index of Linux != port val */
    ofp_update_ifindex_lookup_tab(ifnet);

    sprintf(str, "slow path stack port:%d", port);
    ifnet->spq_def = odp_queue_create(str,
                                      ODP_QUEUE_TYPE_POLL,
                                      NULL);
    if (ifnet->spq_def == ODP_QUEUE_INVALID) {
        fail_with_odp("Slow path queue create failed.\n");
        return;
    }
#endif

    sprintf(str, "out default queue:%d", port);
    ifnet->outq_def = odp_queue_create(str,
                                       ODP_QUEUE_TYPE_POLL,
                                       NULL);
    if (ifnet->outq_def == ODP_QUEUE_INVALID) {
        fail_with_odp("Out default queue create failed.\n");
        return;
    }

    sprintf(str, "interface queue:%d", port);
    interface_queue[port] =
        odp_queue_create(str, ODP_QUEUE_TYPE_POLL, NULL);
    if (interface_queue[port] == ODP_QUEUE_INVALID) {
        OFP_ERR("Poll queue create failed.\n");
        return;
    }
    ofp_queue_context_set(interface_queue[port], ifnet);

    ofp_config_interface_up_tun(GRE_PORTS, 100 + port, vrf, local_ip,
                                tun_rem_ip, tun_p2p, tun_addr,
                                tun_mask);
}
예제 #9
0
enum ofp_return_code send_pkt_out(struct ofp_ifnet *dev,
	odp_packet_t pkt)
{
	OFP_DBG("Sent packet out %s", dev->if_name);

	if (odp_queue_enq(ofp_get_ifnet(dev->port, 0)->outq_def,
			odp_packet_to_event(pkt))) {
		OFP_DBG("odp_queue_enq failed");
		return OFP_PKT_DROP;
	}

	OFP_DEBUG_PACKET(OFP_DEBUG_PKT_SEND_NIC, pkt, dev->port);

	OFP_UPDATE_PACKET_STAT(tx_fp, 1);

	return OFP_PKT_PROCESSED;
}
예제 #10
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;
}
예제 #11
0
/*
 * INIT
 */
static int
init_suite(void)
{
	odp_pool_param_t pool_params;
	ofp_pkt_hook pkt_hook[OFP_HOOK_MAX];
	struct ofp_ifnet *dev;
	odp_pool_t pool;

	/* Init ODP before calling anything else */
	if (odp_init_global(NULL, NULL)) {
		OFP_ERR("Error: ODP global init failed.\n");
		return -1;
	}

	/* Init this thread */
	if (odp_init_local(ODP_THREAD_CONTROL)) {
		OFP_ERR("Error: ODP local init failed.\n");
		return -1;
	}

	memset(pkt_hook, 0, sizeof(pkt_hook));

	pool_params.pkt.seg_len = SHM_PKT_POOL_BUFFER_SIZE;
	pool_params.pkt.len     = SHM_PKT_POOL_BUFFER_SIZE;
	pool_params.pkt.num     = SHM_PKT_POOL_SIZE / SHM_PKT_POOL_BUFFER_SIZE;
	pool_params.type        = ODP_POOL_PACKET;

	(void) ofp_init_pre_global("packet_pool", &pool_params, pkt_hook, &pool,
				   ARP_AGE_INTERVAL, ARP_ENTRY_TIMEOUT);

	ofp_arp_init_local();

	dev = ofp_get_ifnet(0, 0);
	dev->if_mtu = ifmtu;
	memcpy(dev->mac, ifmac, OFP_ETHER_ADDR_LEN);
	ofp_mac_to_link_local(ifmac, link_local);

	return 0;
}
예제 #12
0
int ofp_term_global(void)
{
	int rc = 0;
	uint16_t i;
	struct ofp_ifnet *ifnet;

	ofp_stop();

	/* Terminate CLI thread*/
	CHECK_ERROR(ofp_stop_cli_thread(), rc);

#ifdef SP
	/* Terminate Netlink thread*/
	if (shm->nl_thread_is_running) {
		odph_linux_pthread_join(&shm->nl_thread, 1);
		shm->nl_thread_is_running = 0;
	}
#endif /* SP */

	/* Cleanup interfaces: queues and pktios*/
	for (i = 0; i < VXLAN_PORTS; i++) {
		ifnet = ofp_get_ifnet((uint16_t)i, 0);
		if (!ifnet) {
			OFP_ERR("Failed to locate interface for port %d", i);
			rc = -1;
			continue;
		}
		if (ifnet->if_state == OFP_IFT_STATE_FREE)
			continue;

		if (ifnet->pktio == ODP_PKTIO_INVALID)
			continue;

		OFP_INFO("Cleaning device '%s' addr %s", ifnet->if_name,
			ofp_print_mac((uint8_t *)ifnet->mac));

		CHECK_ERROR(odp_pktio_stop(ifnet->pktio), rc);
#ifdef SP
		close(ifnet->fd);
		odph_linux_pthread_join(ifnet->rx_tbl, 1);
		odph_linux_pthread_join(ifnet->tx_tbl, 1);
		ifnet->fd = -1;
#endif /*SP*/

		/* Multicasting. */
		ofp_igmp_domifdetach(ifnet);
		ifnet->ii_inet.ii_igmp = NULL;

		if (ifnet->loopq_def != ODP_QUEUE_INVALID) {
			if (odp_queue_destroy(ifnet->loopq_def) < 0) {
				OFP_ERR("Failed to destroy loop queue for %s",
					ifnet->if_name);
				rc = -1;
			}
			ifnet->loopq_def = ODP_QUEUE_INVALID;
		}
#ifdef SP
		if (ifnet->spq_def != ODP_QUEUE_INVALID) {
			cleanup_pkt_queue(ifnet->spq_def);
			if (odp_queue_destroy(ifnet->spq_def) < 0) {
				OFP_ERR("Failed to destroy slow path "
					"queue for %s", ifnet->if_name);
				rc = -1;
			}
			ifnet->spq_def = ODP_QUEUE_INVALID;
		}
#endif /*SP*/
		ifnet->outq_def = ODP_QUEUE_INVALID;

		if (ifnet->pktio != ODP_PKTIO_INVALID) {
			if (odp_pktio_close(ifnet->pktio) < 0) {
				OFP_ERR("Failed to destroy pktio for %s",
					ifnet->if_name);
				rc = -1;
			}
			ifnet->pktio = ODP_PKTIO_INVALID;
		}

		if (ifnet->inq_def != ODP_QUEUE_INVALID) {
			cleanup_pkt_queue(ifnet->inq_def);
			if (odp_queue_destroy(ifnet->inq_def) < 0) {
				OFP_ERR("Failed to destroy default input "
					"queue for %s", ifnet->if_name);
				rc = -1;
			}
			ifnet->inq_def = ODP_QUEUE_INVALID;
		}
	}

	CHECK_ERROR(ofp_clean_vxlan_interface_queue(), rc);

	if (ofp_term_post_global(SHM_PACKET_POOL_NAME)) {
		OFP_ERR("Failed to cleanup resources\n");
		rc = -1;
	}

	return rc;
}
예제 #13
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);
}
예제 #14
0
int ofp_ioctl(int sockfd, int request, ...)
{
	va_list ap;
	void *data;
	struct ofp_ifnet *iface = NULL;
	struct socket  *so = ofp_get_sock_by_fd(sockfd);
	if (!so) {
		ofp_errno = OFP_EBADF;
		return -1;
	}

	va_start(ap, request);
	data = va_arg(ap, void *);
	va_end(ap);

	if (request == (int)(OFP_SIOCGIFCONF)) {
		ofp_errno = ((*so->so_proto->pr_usrreqs->pru_control)
			       (so, request, data, NULL, NULL));
	} else if (OFP_IOCGROUP(request) == 'i') {
		/* All the interface requests start with interface name */
		int port, vlan = 0;
		char *name = data;

		if (get_port_vlan_by_name(name, &port, &vlan) < 0) {
			ofp_errno = OFP_EBADF;
			return -1;
		}

		if (request == (int)(OFP_SIOCSIFTUN)) {
			struct ofp_in_tunreq *treq = data;
			const char *retstr =
				ofp_config_interface_up_tun
				(port, vlan, treq->iftun_vrf,
				 treq->iftun_local_addr.sin_addr.s_addr,
				 treq->iftun_remote_addr.sin_addr.s_addr,
				 treq->iftun_p2p_addr.sin_addr.s_addr,
				 treq->iftun_addr.sin_addr.s_addr, 30);
			if (!retstr)
				ofp_errno = 0;
			else
				ofp_errno = OFP_EBADMSG;
		} else {
			iface = ofp_get_ifnet(port, vlan);

			if (so->so_proto->pr_usrreqs->pru_control)
				ofp_errno = ((*so->so_proto->pr_usrreqs->pru_control)
					       (so, request, data, iface, NULL));
			else
				ofp_errno = OFP_EOPNOTSUPP;
		}
	} else if (OFP_IOCGROUP(request) == 'r') {
		int port = 0, vlan = 0;
		struct ofp_rtentry *rt = data;
		uint32_t dst  = ((struct ofp_sockaddr_in *)&rt->rt_dst)->sin_addr.s_addr;
		uint32_t mask = ((struct ofp_sockaddr_in *)&rt->rt_genmask)->sin_addr.s_addr;
		uint32_t gw   = ((struct ofp_sockaddr_in *)&rt->rt_gateway)->sin_addr.s_addr;
		uint32_t maskcpu = odp_be_to_cpu_32(mask);
		uint32_t mlen = 0;

		if (request != (int)OFP_SIOCADDRT &&
		    request != (int)OFP_SIOCDELRT) {
			ofp_errno = OFP_EBADF;
			return -1;
		}

		if (request == (int)OFP_SIOCADDRT) {
			if (rt->rt_dev) {
				if (get_port_vlan_by_name(rt->rt_dev, &port, &vlan) < 0) {
					ofp_errno = OFP_EBADF;
					return -1;
				}
			} else {
				uint32_t flags;
				struct ofp_nh_entry *nh =
					ofp_get_next_hop(rt->rt_vrf, gw, &flags);
				if (!nh) {
					ofp_errno = OFP_EBADF;
					return -1;
				}
				port = nh->port;
				vlan = nh->vlan;
			}
		}

		while (maskcpu) {
			mlen++;
			maskcpu <<= 1;
		}

		ofp_set_route_params((request == (int) OFP_SIOCADDRT) ? OFP_ROUTE_ADD : OFP_ROUTE_DEL,
				     rt->rt_vrf, vlan, port,
				     dst, mlen, gw,
				     (request == (int) OFP_SIOCADDRT) ?
				     (gw ? OFP_RTF_GATEWAY : OFP_RTF_NET) : 0);
	} else {
		ofp_errno = ofp_soo_ioctl(so, request, data, NULL, NULL);
	}

	if (ofp_errno)
		return -1;

	return 0;
}
예제 #15
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);
}