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;
}
Exemple #2
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;
}