github.com/cilium/cilium@v1.16.2/bpf/lib/arp.h (about)

     1  /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
     2  /* Copyright Authors of Cilium */
     3  
     4  #pragma once
     5  
     6  #include <linux/if_arp.h>
     7  #include <linux/if_ether.h>
     8  #include "eth.h"
     9  #include "dbg.h"
    10  #include "drop.h"
    11  
    12  struct arp_eth {
    13  	unsigned char		ar_sha[ETH_ALEN];
    14  	__be32                  ar_sip;
    15  	unsigned char		ar_tha[ETH_ALEN];
    16  	__be32                  ar_tip;
    17  } __packed;
    18  
    19  /* Check if packet is ARP request for IP */
    20  static __always_inline int arp_check(struct ethhdr *eth,
    21  				     const struct arphdr *arp,
    22  				     union macaddr *mac)
    23  {
    24  	union macaddr *dmac = (union macaddr *) &eth->h_dest;
    25  
    26  	return arp->ar_op  == bpf_htons(ARPOP_REQUEST) &&
    27  	       arp->ar_hrd == bpf_htons(ARPHRD_ETHER) &&
    28  	       (eth_is_bcast(dmac) || !eth_addrcmp(dmac, mac));
    29  }
    30  
    31  static __always_inline int
    32  arp_prepare_response(struct __ctx_buff *ctx, union macaddr *smac, __be32 sip,
    33  		     union macaddr *dmac, __be32 tip)
    34  {
    35  	__be16 arpop = bpf_htons(ARPOP_REPLY);
    36  
    37  	if (eth_store_saddr(ctx, smac->addr, 0) < 0 ||
    38  	    eth_store_daddr(ctx, dmac->addr, 0) < 0 ||
    39  	    ctx_store_bytes(ctx, 20, &arpop, sizeof(arpop), 0) < 0 ||
    40  	    /* sizeof(macadrr)=8 because of padding, use ETH_ALEN instead */
    41  	    ctx_store_bytes(ctx, 22, smac, ETH_ALEN, 0) < 0 ||
    42  	    ctx_store_bytes(ctx, 28, &sip, sizeof(sip), 0) < 0 ||
    43  	    ctx_store_bytes(ctx, 32, dmac, ETH_ALEN, 0) < 0 ||
    44  	    ctx_store_bytes(ctx, 38, &tip, sizeof(tip), 0) < 0)
    45  		return DROP_WRITE_ERROR;
    46  
    47  	return 0;
    48  }
    49  
    50  static __always_inline bool
    51  arp_validate(const struct __ctx_buff *ctx, union macaddr *mac,
    52  	     union macaddr *smac, __be32 *sip, __be32 *tip)
    53  {
    54  	void *data_end = (void *) (long) ctx->data_end;
    55  	void *data = (void *) (long) ctx->data;
    56  	struct arphdr *arp = data + ETH_HLEN;
    57  	struct ethhdr *eth = data;
    58  	struct arp_eth *arp_eth;
    59  
    60  	if (data + ETH_HLEN + sizeof(*arp) + sizeof(*arp_eth) > data_end)
    61  		return false;
    62  
    63  	if (!arp_check(eth, arp, mac))
    64  		return false;
    65  
    66  	arp_eth = data + ETH_HLEN + sizeof(*arp);
    67  	*smac = *(union macaddr *) &eth->h_source;
    68  	*sip = arp_eth->ar_sip;
    69  	*tip = arp_eth->ar_tip;
    70  
    71  	return true;
    72  }
    73  
    74  static __always_inline int
    75  arp_respond(struct __ctx_buff *ctx, union macaddr *smac, __be32 sip,
    76  	    union macaddr *dmac, __be32 tip, int direction)
    77  {
    78  	int ret = arp_prepare_response(ctx, smac, sip, dmac, tip);
    79  
    80  	if (unlikely(ret != 0))
    81  		goto error;
    82  
    83  	cilium_dbg_capture(ctx, DBG_CAPTURE_DELIVERY,
    84  			   ctx_get_ifindex(ctx));
    85  	return ctx_redirect(ctx, ctx_get_ifindex(ctx), direction);
    86  
    87  error:
    88  	return send_drop_notify_error(ctx, UNKNOWN_ID, ret, CTX_ACT_DROP, METRIC_EGRESS);
    89  }