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 *) ð->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 *) ð->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 }