Exemplo n.º 1
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);
}
Exemplo n.º 2
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;
	}
}
Exemplo n.º 3
0
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
	int bind_value = -1;

	if (sockfd < OFP_SOCK_NUM_OFFSET) {
		bind_value = (*libc_bind)(sockfd, addr, addrlen);
	} else if (addr->sa_family == AF_INET) {
		struct ofp_sockaddr_in ofp_addr;

		bzero((char *) &ofp_addr, sizeof(ofp_addr));
		ofp_addr.sin_family = AF_INET;
		ofp_addr.sin_addr.s_addr =
			((const struct sockaddr_in *)addr)->sin_addr.s_addr;
		ofp_addr.sin_port =
			((const struct sockaddr_in *)addr)->sin_port;
		ofp_addr.sin_len = sizeof(struct ofp_sockaddr_in);

		bind_value = ofp_bind(sockfd,
				(const struct ofp_sockaddr *)&ofp_addr,
				addrlen);
	}

	OFP_DBG("Binding socket '%d' to the address '%x:%d' returns:%d",
		sockfd,	((const struct sockaddr_in *)addr)->sin_addr.s_addr,
		ntohs(((const struct sockaddr_in *)addr)->sin_port),
		bind_value);

	return bind_value;
}
Exemplo n.º 4
0
int socket(int domain, int type, int protocol)
{
	int sockfd = -1, ret_val;
	static int init_socket = 0;

	if (odp_unlikely(init_socket == 0)) {
		ret_val = ofp_libc_init();
		if (ret_val == EXIT_FAILURE)
			return sockfd;

		init_socket = 1;

		ret_val = ofp_lib_start();
		if (ret_val == EXIT_SUCCESS)
			init_socket = 2;
		else
			init_socket = 3;
	}

	if (odp_unlikely(domain != AF_INET || init_socket != 2))
		sockfd = (*libc_socket)(domain, type, protocol);
	else
		sockfd = ofp_socket(domain, type, protocol);

	OFP_DBG("Created socket '%d' with domain:%d, type:%d, protocol:%d.",
		sockfd, domain, type, protocol);

	return sockfd;
}
static void *pkt_io_recv(void *arg)
{
	odp_pktio_t pktio;
	odp_packet_t pkt, pkt_tbl[OFP_PKT_BURST_SIZE];
	int pkt_idx, pkt_cnt;
	struct pktio_thr_arg *thr_args;
	ofp_pkt_processing_func pkt_func;

	thr_args = arg;
	pkt_func = thr_args->pkt_func;

	if (odp_init_local(ODP_THREAD_WORKER)) {
		OFP_ERR("Error: ODP local init failed.\n");
		return NULL;
	}
	if (ofp_init_local()) {
		OFP_ERR("Error: OFP local init failed.\n");
		return NULL;
	}

	pktio = ofp_port_pktio_get(thr_args->port);

	OFP_DBG("PKT-IO receive starting on port: %d, pktio-id: %"PRIX64"\n",
		  thr_args->port, odp_pktio_to_u64(pktio));

	while (1) {
		pkt_cnt = odp_pktio_recv(pktio, pkt_tbl, OFP_PKT_BURST_SIZE);

		for (pkt_idx = 0; pkt_idx < pkt_cnt; pkt_idx++) {
			pkt = pkt_tbl[pkt_idx];

			if (odp_unlikely(odp_packet_has_error(pkt))) {
				OFP_DBG("Packet with error dropped.\n");
				odp_packet_free(pkt);
				continue;
			}

			ofp_packet_input(pkt, ODP_QUEUE_INVALID, pkt_func);
		}
#ifdef OFP_SEND_PKT_BURST
		ofp_send_pending_pkt_burst();
#endif /*OFP_SEND_PKT_BURST*/
	}

	/* Never reached */
	return NULL;
}
Exemplo n.º 6
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;
}
Exemplo n.º 7
0
static enum ofp_return_code ofp_ip_output_add_eth(odp_packet_t pkt,
						  struct ip_out *odata)
{
	uint8_t l2_size = 0;
	void *l2_addr;

	if (!odata->gw) /* link local */
		odata->gw = odata->ip->ip_dst.s_addr;

	if (ETH_WITHOUT_VLAN(odata->vlan, odata->out_port))
		l2_size = sizeof(struct ofp_ether_header);
	else
		l2_size = sizeof(struct ofp_ether_vlan_header);

	if (odp_packet_l2_offset(pkt) + l2_size == odp_packet_l3_offset(pkt)) {
		l2_addr = odp_packet_l2_ptr(pkt, NULL);
	} else if (odp_packet_l3_offset(pkt) >= l2_size) {
		odp_packet_l2_offset_set(pkt,
					odp_packet_l3_offset(pkt) - l2_size);
		l2_addr = odp_packet_l2_ptr(pkt, NULL);
	} else {
		l2_addr = odp_packet_push_head(pkt,
					l2_size - odp_packet_l3_offset(pkt));
		odp_packet_l2_offset_set(pkt, 0);
		odp_packet_l3_offset_set(pkt, l2_size);
		odp_packet_l4_offset_set(pkt, l2_size + (odata->ip->ip_hl<<2));
	}

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

	if (ETH_WITHOUT_VLAN(odata->vlan, odata->out_port)) {
		struct ofp_ether_header *eth =
				(struct ofp_ether_header *)l2_addr;
		uint32_t addr = odp_be_to_cpu_32(odata->ip->ip_dst.s_addr);

		if (OFP_IN_MULTICAST(addr)) {
			eth->ether_dhost[0] = 0x01;
			eth->ether_dhost[1] = 0x00;
			eth->ether_dhost[2] = 0x5e;
			eth->ether_dhost[3] = (addr >> 16) & 0x7f;
			eth->ether_dhost[4] = (addr >> 8) & 0xff;
			eth->ether_dhost[5] = addr & 0xff;
		} else if (odata->dev_out->ip_addr == odata->ip->ip_dst.s_addr) {
			odata->is_local_address = 1;
			ofp_copy_mac(eth->ether_dhost, &(odata->dev_out->mac[0]));
		} else if (ofp_get_mac(odata->dev_out, odata->gw, eth->ether_dhost) < 0) {
			send_arp_request(odata->dev_out, odata->gw);
			return ofp_arp_save_ipv4_pkt(pkt, odata->nh,
						     odata->gw, odata->dev_out);
		}

		ofp_copy_mac(eth->ether_shost, odata->dev_out->mac);
		eth->ether_type = odp_cpu_to_be_16(OFP_ETHERTYPE_IP);
	} else {
Exemplo n.º 8
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);
}
Exemplo n.º 9
0
ssize_t recv(int sockfd, void *buf, size_t len, int flags)
{
	ssize_t recv_value;

	if (sockfd < OFP_SOCK_NUM_OFFSET)
		recv_value = (*libc_recv)(sockfd, buf, len, flags);
	else
		recv_value = ofp_recv(sockfd, buf, len, flags);

	OFP_DBG("Recv called on socket '%d'", sockfd);

	return recv_value;
}
Exemplo n.º 10
0
ssize_t send(int sockfd, const void *buf, size_t len, int flags)
{
	ssize_t send_value;

	if (sockfd < OFP_SOCK_NUM_OFFSET)
		send_value = (*libc_send)(sockfd, buf, len, flags);
	else
		send_value = ofp_send(sockfd, buf, len, flags);

	OFP_DBG("Send called on socket '%d'", sockfd);

	return send_value;
}
Exemplo n.º 11
0
static void *pkt_io_recv(void *arg)
{
	odp_pktin_queue_t pktin;
	odp_packet_t pkt, pkt_tbl[PKT_BURST_SIZE];
	int pkt_idx, pkt_cnt;
	struct pktio_thr_arg *thr_args;
	ofp_pkt_processing_func pkt_func;

	thr_args = arg;
	pkt_func = thr_args->pkt_func;
	pktin = thr_args->pktin;

	if (ofp_init_local()) {
		OFP_ERR("Error: OFP local init failed.\n");
		return NULL;
	}

	OFP_DBG("PKT-IO receive starting on cpu: %d", odp_cpu_id());

	while (1) {
		pkt_cnt = odp_pktin_recv(pktin, pkt_tbl, PKT_BURST_SIZE);

		for (pkt_idx = 0; pkt_idx < pkt_cnt; pkt_idx++) {
			pkt = pkt_tbl[pkt_idx];

			if (odp_unlikely(odp_packet_has_error(pkt))) {
				OFP_DBG("Packet with error dropped.\n");
				odp_packet_free(pkt);
				continue;
			}

			ofp_packet_input(pkt, ODP_QUEUE_INVALID, pkt_func);
		}
		ofp_send_pending_pkt();
	}

	/* Never reached */
	return NULL;
}
Exemplo n.º 12
0
int listen(int sockfd, int backlog)
{
	int listen_value;

	if (sockfd < OFP_SOCK_NUM_OFFSET)
		listen_value = (*libc_listen)(sockfd, backlog);
	else
		listen_value = ofp_listen(sockfd, backlog);

	OFP_DBG("Listen called on socket '%d' returns:'%d'",
		sockfd, listen_value);

	return listen_value;
}
Exemplo n.º 13
0
int shutdown(int sockfd, int how)
{
	int shutdown_value;

	if (sockfd < OFP_SOCK_NUM_OFFSET)
		shutdown_value = (*libc_shutdown)(sockfd, how);
	else
		shutdown_value = ofp_shutdown(sockfd, how);

	OFP_DBG("Socket '%d' shutdown with option '%d' returns:'%d'",
		sockfd, how, shutdown_value);

	return shutdown_value;
}
Exemplo n.º 14
0
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
{
	int accept_value = -1;

	if (sockfd < OFP_SOCK_NUM_OFFSET)
		accept_value = (*libc_accept)(sockfd, addr, addrlen);
	else
		accept_value = ofp_accept(sockfd,
			(struct ofp_sockaddr *)addr, addrlen);

	OFP_DBG("Accepting socket '%d' to the address '%x:%d' returns:'%d'",
		sockfd, ((struct sockaddr_in *)addr)->sin_addr.s_addr,
		ntohs(((struct sockaddr_in *)addr)->sin_port), accept_value);

	return accept_value;
}
Exemplo n.º 15
0
int close(int sockfd)
{
	int close_value;

	if (sockfd < OFP_SOCK_NUM_OFFSET) {
		if (libc_close == NULL)
			ofp_libc_init();
		close_value = (*libc_close)(sockfd);
	} else
		close_value = ofp_close(sockfd);

	OFP_DBG("Socket '%d' closed returns:'%d'",
		sockfd, close_value);

	return close_value;
}
Exemplo n.º 16
0
ssize_t write(int sockfd, void *buf, size_t len)
{
	ssize_t write_value;

	if (sockfd < OFP_SOCK_NUM_OFFSET) {
		if (libc_write == NULL)
			ofp_libc_init();

		write_value = (*libc_write)(sockfd, buf, len);
	} else
		write_value = ofp_send(sockfd, buf, len, 0);

	OFP_DBG("Write called on socket '%d'", sockfd);

	return write_value;
}
Exemplo n.º 17
0
ssize_t read(int sockfd, void *buf, size_t len)
{
	ssize_t read_value;

	if (sockfd < OFP_SOCK_NUM_OFFSET) {
		if (libc_read == NULL)
			ofp_libc_init();

		read_value = (*libc_read)(sockfd, buf, len);
	} else
		read_value = ofp_recv(sockfd, buf, len, 0);

	OFP_DBG("Read called on socket '%d'", sockfd);

	return read_value;
}
Exemplo n.º 18
0
int setsockopt(int sockfd, int level, int opt_name, const void *opt_val,
	socklen_t opt_len)
{
	int setsockopt_value;

	if (sockfd < OFP_SOCK_NUM_OFFSET)
		setsockopt_value = (*libc_setsockopt)(sockfd, level, opt_name,
			opt_val, opt_len);
	else
		setsockopt_value = ofp_setsockopt(sockfd, level, opt_name,
			opt_val, opt_len);

	OFP_DBG("Setsockopt on sock:'%d',level:'%d',opt_name:'%d'",
		sockfd, level, opt_name);

	return setsockopt_value;
}
Exemplo n.º 19
0
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
	int connect_value;

	if (sockfd < OFP_SOCK_NUM_OFFSET)
		connect_value = (*libc_connect)(sockfd, addr, addrlen);
	else
		connect_value = ofp_connect(sockfd,
			(const struct ofp_sockaddr *)addr,
			addrlen);

	OFP_DBG("Connecting socket '%d' to the address '%x:%d' returns:'%d'",
		sockfd, ((const struct sockaddr_in *)addr)->sin_addr.s_addr,
		ntohs(((const struct sockaddr_in *)addr)->sin_port),
		connect_value);

	return connect_value;
}
Exemplo n.º 20
0
static void ofp_ifconfig(void)
{
	struct ifaddrs *ifap, *ifa;
	struct sockaddr_in *sa;
	int port = 0;

	getifaddrs(&ifap);
	for (ifa = ifap; ifa; ifa = ifa->ifa_next)
		if (ifa->ifa_addr->sa_family == AF_INET) {
			sa = (struct sockaddr_in *) ifa->ifa_addr;
			OFP_DBG("Interface: %s\tAddress: %x\n",
				ifa->ifa_name, sa->sin_addr.s_addr);

			ofp_ifnet_create(ifa->ifa_name, NULL, NULL, NULL);
			ofp_config_interface_up_v4(port++, 0, 0,
				 sa->sin_addr.s_addr, 24);
		}

	freeifaddrs(ifap);
	return;
}
Exemplo n.º 21
0
static enum ofp_return_code ofp_ip_output_add_eth(odp_packet_t pkt,
						  struct ip_out *odata)
{
	uint32_t l2_size;
	void *l2_addr;
	struct ofp_ether_header *eth;
	uint32_t addr;
	uint32_t is_link_local = 0;

	trim_tail(pkt, odp_be_to_cpu_16(odata->ip->ip_len));

	if (!odata->gw) { /* link local */
		odata->gw = odata->ip->ip_dst.s_addr;
		is_link_local = 1;
	}

	if (!ETH_WITH_VLAN(odata->dev_out))
		l2_size = sizeof(struct ofp_ether_header);
	else
		l2_size = sizeof(struct ofp_ether_vlan_header);

	l2_addr = trim_for_output(pkt, l2_size, odata->ip->ip_hl * 4);
	if (odp_unlikely(l2_addr == NULL)) {
		OFP_DBG("l2_addr == NULL");
		return OFP_PKT_DROP;
	}

	eth = l2_addr;
	addr = odp_be_to_cpu_32(odata->ip->ip_dst.s_addr);

	if (OFP_IN_MULTICAST(addr)) {
		eth->ether_dhost[0] = 0x01;
		eth->ether_dhost[1] = 0x00;
		eth->ether_dhost[2] = 0x5e;
		eth->ether_dhost[3] = (addr >> 16) & 0x7f;
		eth->ether_dhost[4] = (addr >> 8) & 0xff;
		eth->ether_dhost[5] = addr & 0xff;
	} else if (odata->dev_out->ip_addr == odata->ip->ip_dst.s_addr ||
Exemplo n.º 22
0
int default_event_dispatcher(void *arg)
{
	odp_event_t ev;
	odp_packet_t pkt;
	odp_queue_t in_queue;
	int event_idx = 0;
	int event_cnt = 0;
	ofp_pkt_processing_func pkt_func = (ofp_pkt_processing_func)arg;
	odp_bool_t *is_running = NULL;

	if (ofp_init_local()) {
		OFP_ERR("ofp_init_local failed");
		return -1;
	}

	int rx_burst = global_param->evt_rx_burst_size;
	odp_event_t events[rx_burst];

	is_running = ofp_get_processing_state();
	if (is_running == NULL) {
		OFP_ERR("ofp_get_processing_state failed");
		ofp_term_local();
		return -1;
	}

	/* PER CORE DISPATCHER */
	while (*is_running) {
		event_cnt = odp_schedule_multi(&in_queue, ODP_SCHED_WAIT,
					 events, rx_burst);
		for (event_idx = 0; event_idx < event_cnt; event_idx++) {
			odp_event_type_t ev_type;

			ev = events[event_idx];

			if (ev == ODP_EVENT_INVALID)
				continue;
			ev_type = odp_event_type(ev);

			if (odp_likely(ev_type == ODP_EVENT_PACKET)) {
				pkt = odp_packet_from_event(ev);
#if 0
				if (odp_unlikely(odp_packet_has_error(pkt))) {
					OFP_DBG("Dropping packet with error");
					odp_packet_free(pkt);
					continue;
				}
#endif
				ofp_packet_input(pkt, in_queue, pkt_func);
				continue;
			}
			if (ev_type == ODP_EVENT_TIMEOUT) {
				ofp_timer_handle(ev);
				continue;
			}

			OFP_ERR("Unexpected event type: %u", ev_type);
			odp_event_free(ev);
		}
		ofp_send_pending_pkt();
	}

	if (ofp_term_local())
		OFP_ERR("ofp_term_local failed");

	return 0;
}
Exemplo n.º 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;
}
/** main() Application entry point
 *
 * @param argc int
 * @param argv[] char*
 * @return int
 *
 */
int main(int argc, char *argv[])
{
	odph_linux_pthread_t thread_tbl[MAX_WORKERS], dispatcher_thread;
	appl_args_t params;
	int core_count, num_workers;
	odp_cpumask_t cpu_mask;
	char cpumaskstr[64];
	int cpu, first_cpu, i;
	struct pktio_thr_arg pktio_thr_args[MAX_WORKERS];

	/* Parse and store the application arguments */
	parse_args(argc, argv, &params);

	/* Print both system and application information */
	print_info(NO_PATH(argv[0]), &params);

	if (odp_init_global(NULL, NULL)) {
		OFP_ERR("Error: ODP global init failed.\n");
		exit(EXIT_FAILURE);
	}
	if (odp_init_local(ODP_THREAD_CONTROL)) {
		OFP_ERR("Error: ODP local init failed.\n");
		exit(EXIT_FAILURE);
	}

	memset(thread_tbl, 0, sizeof(thread_tbl));
	memset(pktio_thr_args, 0, sizeof(pktio_thr_args));

	core_count = odp_cpu_count();
	num_workers = core_count;
	first_cpu = 1;

	if (params.core_count)
		num_workers = params.core_count;
	if (num_workers > MAX_WORKERS)
		num_workers = MAX_WORKERS;

	/*
	 * By default core #0 runs Linux kernel background tasks.
	 * Start mapping thread from core #1
	 */
	memset(&app_init_params, 0, sizeof(app_init_params));

	app_init_params.linux_core_id = 0;

	if (core_count <= 1) {
		OFP_ERR("Burst mode requires multiple cores.\n");
		exit(EXIT_FAILURE);
	}
	num_workers--;

	printf("Num worker threads: %i\n", num_workers);
	printf("first CPU:          %i\n", first_cpu);

	app_init_params.if_count = params.if_count;
	app_init_params.if_names = params.if_names;
	app_init_params.pkt_hook[OFP_HOOK_LOCAL] = fastpath_local_hook;
	app_init_params.burst_recv_mode = 1;
	if (ofp_init_global(&app_init_params)) {
		OFP_ERR("Error: OFP global init failed.\n");
		exit(EXIT_FAILURE);
	}

	if (num_workers < params.if_count) {
		OFP_ERR("At least %u fastpath cores required.\n",
			  params.if_count);
		exit(EXIT_FAILURE);
	}

	for (i = 0; i < num_workers; ++i) {
		pktio_thr_args[i].pkt_func = ofp_eth_vlan_processing;
		pktio_thr_args[i].port = i % params.if_count;

		odp_cpumask_zero(&cpu_mask);
		cpu = first_cpu + i;
		odp_cpumask_set(&cpu_mask, cpu);
		odp_cpumask_to_str(&cpu_mask, cpumaskstr, sizeof(cpumaskstr));

		OFP_DBG("Starting pktio receive on core: %d port: %d\n",
			  cpu, pktio_thr_args[i].port);
		OFP_DBG("cpu mask: %s\n", cpumaskstr);

		ofp_linux_pthread_create(&thread_tbl[i],
					  &cpu_mask,
					  pkt_io_recv,
					  &pktio_thr_args[i],
					  ODP_THREAD_WORKER
					);
	}

	odp_cpumask_zero(&cpu_mask);
	odp_cpumask_set(&cpu_mask, app_init_params.linux_core_id);
	ofp_linux_pthread_create(&dispatcher_thread,
				  &cpu_mask,
				  event_dispatcher,
				  NULL,
				  ODP_THREAD_CONTROL
				);

	/* other app code here.*/
	/* Start CLI */
	ofp_start_cli_thread(app_init_params.linux_core_id, params.conf_file);

	odph_linux_pthread_join(thread_tbl, num_workers);
	printf("End Main()\n");

	return 0;
}
Exemplo n.º 25
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);
}
Exemplo n.º 26
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);
}
Exemplo n.º 27
0
void *default_event_dispatcher(void *arg)
{
	odp_event_t ev;
	odp_packet_t pkt;
	odp_queue_t in_queue;
	odp_event_t events[OFP_EVT_RX_BURST_SIZE];
	int event_idx = 0;
	int event_cnt = 0;
	ofp_pkt_processing_func pkt_func = (ofp_pkt_processing_func)arg;
	odp_bool_t *is_running = NULL;

#if ODP_VERSION < 106
	if (odp_init_local(ODP_THREAD_WORKER)) {
		OFP_ERR("odp_init_local failed");
		return NULL;
	}
#endif

	if (ofp_init_local()) {
		OFP_ERR("ofp_init_local failed");
		return NULL;
	}

	is_running = ofp_get_processing_state();
	if (is_running == NULL) {
		OFP_ERR("ofp_get_processing_state failed");
		ofp_term_local();
		return NULL;
	}

	/* PER CORE DISPATCHER */
	while (*is_running) {
		event_cnt = odp_schedule_multi(&in_queue, ODP_SCHED_WAIT,
					 events, OFP_EVT_RX_BURST_SIZE);
		for (event_idx = 0; event_idx < event_cnt; event_idx++) {
			ev = events[event_idx];

			if (ev == ODP_EVENT_INVALID)
				continue;

			if (odp_event_type(ev) == ODP_EVENT_TIMEOUT) {
				ofp_timer_handle(ev);
				continue;
			}

			if (odp_event_type(ev) == ODP_EVENT_PACKET) {
				pkt = odp_packet_from_event(ev);
#if 0
				if (odp_unlikely(odp_packet_has_error(pkt))) {
					OFP_DBG("Dropping packet with error");
					odp_packet_free(pkt);
					continue;
				}
#endif
				ofp_packet_input(pkt, in_queue, pkt_func);
				continue;
			}

			OFP_ERR("Unexpected event type: %u", odp_event_type(ev));

			/* Free events by type */
			if (odp_event_type(ev) == ODP_EVENT_BUFFER) {
				odp_buffer_free(odp_buffer_from_event(ev));
				continue;
			}

			if (odp_event_type(ev) == ODP_EVENT_CRYPTO_COMPL) {
				odp_crypto_compl_free(
					odp_crypto_compl_from_event(ev));
				continue;
			}

		}
		ofp_send_pending_pkt();
	}

	if (ofp_term_local())
		OFP_ERR("ofp_term_local failed");

	return NULL;
}
Exemplo n.º 28
0
static void sigev_notify(union ofp_sigval sv)
{
    struct ofp_sock_sigval *ss = sv.sival_ptr;
    if (!ss)
       return ;
    int s = ss->sockfd;
    int event = ss->event;
    odp_packet_t pkt = ss->pkt;
    ngx_uint_t         i = 0;
    ngx_queue_t       *queue = NULL;
    ngx_event_t       *ev;
    ngx_connection_t  *c;

    if (event == OFP_EVENT_ACCEPT)  {
        for (i = 0; i < nevents; i++) {
            ev = event_index[i];
            c  = ev->data;

            if (ev->accept) {
                ev->ready = 1;
                ev->handler(ev);
                OFP_DBG("%s: posted on ACCEPT EVENT", __func__);
                break;
            }
        }
	return;
    }

    if (event == OFP_EVENT_SEND)  {
	    for (i = 0; i < nevents; i++) {
		    ev = event_index[i];
		    c = ev->data;
		    if (ev->write && CLR_FD_BIT(c->fd)==s) {
			    OFP_DBG("%s: posted SEND event on fd=%d", __func__, s);
			    ev->ready = 1;
			    ngx_post_event(ev, &ngx_posted_events);
		    }
	    }
	    return;
    }

    int r = odp_packet_len(pkt);

    if (r > 0) {
        for (i = 0; i < nevents; i++) {
            ev = event_index[i];
            c  = ev->data;
            if (s == CLR_FD_BIT(c->fd))  {
                queue = &ngx_posted_events;
                ngx_post_event(ev, queue);
                OFP_DBG("%s: posted on RECV EVENT", __func__);
                ev->ready = 1;
                break;
            }
        }
    } else if (r == 0) {
        odp_packet_free(pkt);
        ss->pkt = ODP_PACKET_INVALID;
    }

    return;
}
Exemplo n.º 29
0
int main(int argc, char *argv[])
{
	odph_linux_pthread_t thread_tbl[MAX_WORKERS], dispatcher_thread;
	appl_args_t params;
	int core_count, num_workers;
	odp_cpumask_t cpu_mask;
	char cpumaskstr[64];
	int cpu, first_cpu, i;
	struct pktio_thr_arg pktio_thr_args[MAX_WORKERS];

	/* Parse and store the application arguments */
	parse_args(argc, argv, &params);

	/* Print both system and application information */
	print_info(NO_PATH(argv[0]), &params);

	if (odp_init_global(NULL, NULL)) {
		OFP_ERR("Error: ODP global init failed.\n");
		exit(EXIT_FAILURE);
	}
	odp_init_local(ODP_THREAD_CONTROL);

	memset(&app_init_params, 0, sizeof(app_init_params));
	app_init_params.linux_core_id = 0;
	app_init_params.if_count = params.if_count;
	app_init_params.if_names = params.if_names;
	app_init_params.burst_recv_mode = 1;

	ofp_init_global(&app_init_params);
	ofp_init_local();

	memset(thread_tbl, 0, sizeof(thread_tbl));
	memset(pktio_thr_args, 0, sizeof(pktio_thr_args));

	core_count = odp_cpu_count();
	num_workers = core_count;

	if (params.core_count)
		num_workers = params.core_count < core_count?
			params.core_count: core_count;

	first_cpu = 1;
	num_workers -= first_cpu;

	if (num_workers > MAX_WORKERS)
		num_workers = MAX_WORKERS;

	if (num_workers < params.if_count) {
		OFP_ERR("At least %u fastpath cores required.\n",
			  params.if_count);
		exit(EXIT_FAILURE);
	}

	printf("Num worker threads: %i\n", num_workers);
	printf("first CPU:          %i\n", first_cpu);

	for (i = 0; i < num_workers; ++i) {
		pktio_thr_args[i].pkt_func = ofp_eth_vlan_processing;
		pktio_thr_args[i].port = i % params.if_count;

		odp_cpumask_zero(&cpu_mask);
		cpu = first_cpu + i;
		odp_cpumask_set(&cpu_mask, cpu);
		odp_cpumask_to_str(&cpu_mask, cpumaskstr, sizeof(cpumaskstr));

		OFP_DBG("Starting pktio receive on core: %d port: %d\n",
			  cpu, pktio_thr_args[i].port);
		OFP_DBG("cpu mask: %s\n", cpumaskstr);

		ofp_linux_pthread_create(&thread_tbl[i],
					  &cpu_mask,
					  pkt_io_recv,
					  &pktio_thr_args[i],
					  ODP_THREAD_WORKER
					);
	}

	odp_cpumask_zero(&cpu_mask);
	odp_cpumask_set(&cpu_mask, app_init_params.linux_core_id + 1);
	ofp_linux_pthread_create(&dispatcher_thread,
				  &cpu_mask,
				  event_dispatcher,
				  NULL,
				  ODP_THREAD_CONTROL
				);

	/* Start CLI */
	ofp_start_cli_thread(app_init_params.linux_core_id, params.conf_file);

	sleep(1);

	udp_fwd_cfg(params.sock_count, params.laddr, params.raddr);

	odph_linux_pthread_join(thread_tbl, num_workers);

	printf("End Main()\n");
	return 0;
}
Exemplo n.º 30
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;
}