Commit 9bf881ff authored by Jiri Pirko's avatar Jiri Pirko Committed by David S. Miller
Browse files

flow_dissector: Move ARP dissection into a separate function



Make the main flow_dissect function a bit smaller and move the ARP
dissection into a separate function. Along with that, do the ARP header
processing only in case the flow dissection user requires it.

Signed-off-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent fa383d66
Loading
Loading
Loading
Loading
+67 −53
Original line number Diff line number Diff line
@@ -113,6 +113,66 @@ __be32 __skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto,
}
EXPORT_SYMBOL(__skb_flow_get_ports);

enum flow_dissect_ret {
	FLOW_DISSECT_RET_OUT_GOOD,
	FLOW_DISSECT_RET_OUT_BAD,
};

static enum flow_dissect_ret
__skb_flow_dissect_arp(const struct sk_buff *skb,
		       struct flow_dissector *flow_dissector,
		       void *target_container, void *data, int nhoff, int hlen)
{
	struct flow_dissector_key_arp *key_arp;
	struct {
		unsigned char ar_sha[ETH_ALEN];
		unsigned char ar_sip[4];
		unsigned char ar_tha[ETH_ALEN];
		unsigned char ar_tip[4];
	} *arp_eth, _arp_eth;
	const struct arphdr *arp;
	struct arphdr *_arp;

	if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_ARP))
		return FLOW_DISSECT_RET_OUT_GOOD;

	arp = __skb_header_pointer(skb, nhoff, sizeof(_arp), data,
				   hlen, &_arp);
	if (!arp)
		return FLOW_DISSECT_RET_OUT_BAD;

	if (arp->ar_hrd != htons(ARPHRD_ETHER) ||
	    arp->ar_pro != htons(ETH_P_IP) ||
	    arp->ar_hln != ETH_ALEN ||
	    arp->ar_pln != 4 ||
	    (arp->ar_op != htons(ARPOP_REPLY) &&
	     arp->ar_op != htons(ARPOP_REQUEST)))
		return FLOW_DISSECT_RET_OUT_BAD;

	arp_eth = __skb_header_pointer(skb, nhoff + sizeof(_arp),
				       sizeof(_arp_eth), data,
				       hlen, &_arp_eth);
	if (!arp_eth)
		return FLOW_DISSECT_RET_OUT_BAD;

	key_arp = skb_flow_dissector_target(flow_dissector,
					    FLOW_DISSECTOR_KEY_ARP,
					    target_container);

	memcpy(&key_arp->sip, arp_eth->ar_sip, sizeof(key_arp->sip));
	memcpy(&key_arp->tip, arp_eth->ar_tip, sizeof(key_arp->tip));

	/* Only store the lower byte of the opcode;
	 * this covers ARPOP_REPLY and ARPOP_REQUEST.
	 */
	key_arp->op = ntohs(arp->ar_op) & 0xff;

	ether_addr_copy(key_arp->sha, arp_eth->ar_sha);
	ether_addr_copy(key_arp->tha, arp_eth->ar_tha);

	return FLOW_DISSECT_RET_OUT_GOOD;
}

/**
 * __skb_flow_dissect - extract the flow_keys struct and return it
 * @skb: sk_buff to extract the flow from, can be NULL if the rest are specified
@@ -138,7 +198,6 @@ bool __skb_flow_dissect(const struct sk_buff *skb,
	struct flow_dissector_key_control *key_control;
	struct flow_dissector_key_basic *key_basic;
	struct flow_dissector_key_addrs *key_addrs;
	struct flow_dissector_key_arp *key_arp;
	struct flow_dissector_key_ports *key_ports;
	struct flow_dissector_key_icmp *key_icmp;
	struct flow_dissector_key_tags *key_tags;
@@ -382,60 +441,15 @@ mpls:
		goto out_good;

	case htons(ETH_P_ARP):
	case htons(ETH_P_RARP): {
		struct {
			unsigned char ar_sha[ETH_ALEN];
			unsigned char ar_sip[4];
			unsigned char ar_tha[ETH_ALEN];
			unsigned char ar_tip[4];
		} *arp_eth, _arp_eth;
		const struct arphdr *arp;
		struct arphdr *_arp;

		arp = __skb_header_pointer(skb, nhoff, sizeof(_arp), data,
					   hlen, &_arp);
		if (!arp)
			goto out_bad;

		if (arp->ar_hrd != htons(ARPHRD_ETHER) ||
		    arp->ar_pro != htons(ETH_P_IP) ||
		    arp->ar_hln != ETH_ALEN ||
		    arp->ar_pln != 4 ||
		    (arp->ar_op != htons(ARPOP_REPLY) &&
		     arp->ar_op != htons(ARPOP_REQUEST)))
			goto out_bad;

		arp_eth = __skb_header_pointer(skb, nhoff + sizeof(_arp),
					       sizeof(_arp_eth), data,
					       hlen,
					       &_arp_eth);
		if (!arp_eth)
			goto out_bad;

		if (dissector_uses_key(flow_dissector,
				       FLOW_DISSECTOR_KEY_ARP)) {

			key_arp = skb_flow_dissector_target(flow_dissector,
							    FLOW_DISSECTOR_KEY_ARP,
							    target_container);

			memcpy(&key_arp->sip, arp_eth->ar_sip,
			       sizeof(key_arp->sip));
			memcpy(&key_arp->tip, arp_eth->ar_tip,
			       sizeof(key_arp->tip));

			/* Only store the lower byte of the opcode;
			 * this covers ARPOP_REPLY and ARPOP_REQUEST.
			 */
			key_arp->op = ntohs(arp->ar_op) & 0xff;

			ether_addr_copy(key_arp->sha, arp_eth->ar_sha);
			ether_addr_copy(key_arp->tha, arp_eth->ar_tha);
		}

	case htons(ETH_P_RARP):
		switch (__skb_flow_dissect_arp(skb, flow_dissector,
					       target_container, data,
					       nhoff, hlen)) {
		case FLOW_DISSECT_RET_OUT_GOOD:
			goto out_good;
		case FLOW_DISSECT_RET_OUT_BAD:
			goto out_bad;
		}

	default:
		goto out_bad;
	}