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

     1  /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
     2  /* Copyright Authors of Cilium */
     3  
     4  /*
     5   * Drop & error notification via perf event ring buffer
     6   *
     7   * API:
     8   * int send_drop_notify(ctx, src, dst, dst_id, reason, exitcode, enum metric_dir direction)
     9   * int send_drop_notify_error(ctx, error, exitcode, enum metric_dir direction)
    10   *
    11   * If DROP_NOTIFY is not defined, the API will be compiled in as a NOP.
    12   */
    13  
    14  #pragma once
    15  
    16  #include "dbg.h"
    17  #include "events.h"
    18  #include "common.h"
    19  #include "utils.h"
    20  #include "metrics.h"
    21  
    22  #ifdef DROP_NOTIFY
    23  struct drop_notify {
    24  	NOTIFY_CAPTURE_HDR
    25  	__u32		src_label;
    26  	__u32		dst_label;
    27  	__u32		dst_id; /* 0 for egress */
    28  	__u16		line;
    29  	__u8		file;
    30  	__s8		ext_error;
    31  	__u32		ifindex;
    32  };
    33  
    34  /*
    35   * We pass information in the meta area as follows:
    36   *
    37   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    38   *     |                         Source Label                          |
    39   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    40   *     |                       Destination Label                       |
    41   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    42   *     |  Error Code   | Extended Error|            Unused             |
    43   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    44   *     |             Designated Destination Endpoint ID                |
    45   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    46   *     |   Exit Code   |  Source File  |         Source Line           |
    47   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    48   *
    49   */
    50  
    51  __section_tail(CILIUM_MAP_CALLS, CILIUM_CALL_DROP_NOTIFY)
    52  int __send_drop_notify(struct __ctx_buff *ctx)
    53  {
    54  	/* Mask needed to calm verifier. */
    55  	__u32 error = ctx_load_meta(ctx, 2) & 0xFFFFFFFF;
    56  	__u64 ctx_len = ctx_full_len(ctx);
    57  	__u64 cap_len = min_t(__u64, TRACE_PAYLOAD_LEN, ctx_len);
    58  	__u32 meta4 = ctx_load_meta(ctx, 4);
    59  	__u16 line = (__u16)(meta4 >> 16);
    60  	__u8 file = (__u8)(meta4 >> 8);
    61  	__u8 exitcode = (__u8)meta4;
    62  	struct drop_notify msg;
    63  
    64  	msg = (typeof(msg)) {
    65  		__notify_common_hdr(CILIUM_NOTIFY_DROP, (__u8)error),
    66  		__notify_pktcap_hdr(ctx_len, (__u16)cap_len),
    67  		.src_label	= ctx_load_meta(ctx, 0),
    68  		.dst_label	= ctx_load_meta(ctx, 1),
    69  		.dst_id		= ctx_load_meta(ctx, 3),
    70  		.line           = line,
    71  		.file           = file,
    72  		.ext_error      = (__s8)(__u8)(error >> 8),
    73  		.ifindex        = ctx_get_ifindex(ctx),
    74  	};
    75  
    76  	ctx_event_output(ctx, &EVENTS_MAP,
    77  			 (cap_len << 32) | BPF_F_CURRENT_CPU,
    78  			 &msg, sizeof(msg));
    79  
    80  	return exitcode;
    81  }
    82  
    83  /**
    84   * send_drop_notify
    85   * @ctx:	socket buffer
    86   * @src:	source identity
    87   * @dst:	destination identity
    88   * @dst_id:	designated destination endpoint ID, if ingress, otherwise 0
    89   * @reason:	Reason for drop
    90   * @exitcode:	error code to return to the kernel
    91   *
    92   * Generate a notification to indicate a packet was dropped.
    93   *
    94   * NOTE: This is terminal function and will cause the BPF program to exit
    95   */
    96  static __always_inline int
    97  _send_drop_notify(__u8 file, __u16 line, struct __ctx_buff *ctx,
    98  		  __u32 src, __u32 dst, __u32 dst_id,
    99  		  __u32 reason, __u32 exitcode, enum metric_dir direction)
   100  {
   101  	int ret __maybe_unused;
   102  
   103  	/* These fields should be constants and fit (together) in 32 bits */
   104  	if (!__builtin_constant_p(exitcode) || exitcode > 0xff ||
   105  	    !__builtin_constant_p(file) || file > 0xff ||
   106  	    !__builtin_constant_p(line) || line > 0xffff)
   107  		__throw_build_bug();
   108  
   109  	/* Non-zero 'dst_id' is only to be used for ingress. */
   110  	if (dst_id != 0 && (!__builtin_constant_p(direction) || direction != METRIC_INGRESS))
   111  		__throw_build_bug();
   112  
   113  	ctx_store_meta(ctx, 0, src);
   114  	ctx_store_meta(ctx, 1, dst);
   115  	ctx_store_meta(ctx, 2, reason);
   116  	ctx_store_meta(ctx, 3, dst_id);
   117  	ctx_store_meta(ctx, 4, exitcode | file << 8 | line << 16);
   118  
   119  	_update_metrics(ctx_full_len(ctx), direction, (__u8)reason, line, file);
   120  	ret = tail_call_internal(ctx, CILIUM_CALL_DROP_NOTIFY, NULL);
   121  	/* ignore the returned error, use caller-provided exitcode */
   122  
   123  	return exitcode;
   124  }
   125  #else
   126  static __always_inline
   127  int _send_drop_notify(__u8 file __maybe_unused, __u16 line __maybe_unused,
   128  		      struct __ctx_buff *ctx, __u32 src __maybe_unused,
   129  		      __u32 dst __maybe_unused, __u32 dst_id __maybe_unused,
   130  		      __u32 reason, __u32 exitcode, enum metric_dir direction)
   131  {
   132  	_update_metrics(ctx_full_len(ctx), direction, (__u8)reason, line, file);
   133  	return exitcode;
   134  }
   135  #endif /* DROP_NOTIFY */
   136  
   137  /*
   138   * The following macros are required in order to pass source file/line
   139   * information. The *_ext versions take an additional parameter ext_err
   140   * which can be used to pass additional information, e.g., this could be an
   141   * original error returned by fib_lookup (if reason == DROP_NO_FIB).
   142   */
   143  
   144  /*
   145   * Cilium errors are greater than absolute errno values, so we just pass
   146   * a positive value here
   147   */
   148  #define __DROP_REASON(err) ({ \
   149  	typeof(err) __err = (err); \
   150  	(__u8)(__err > 0 ? __err : -__err); \
   151  })
   152  
   153  /*
   154   * We only have 8 bits here to pass either a small positive value or an errno
   155   * (this can be fixed by changing the layout of struct drop_notify, but for now
   156   * we can hack this as follows). So we pass a negative errno value as is if it
   157   * is >= -128, and set it 0 if it is < -128 (which actually shoudn't happen in
   158   * our case)
   159   */
   160  #define __DROP_REASON_EXT(err, ext_err) ({ \
   161  	typeof(ext_err) __ext_err = (ext_err); \
   162  	__DROP_REASON(err) | ((__u8)(__ext_err < -128 ? 0 : __ext_err) << 8); \
   163  })
   164  
   165  #define send_drop_notify(ctx, src, dst, dst_id, reason, exitcode, direction) \
   166  	_send_drop_notify(__MAGIC_FILE__, __MAGIC_LINE__, ctx, src, dst, dst_id, \
   167  			  __DROP_REASON(reason), exitcode, direction)
   168  
   169  #define send_drop_notify_error(ctx, src, reason, exitcode, direction) \
   170  	_send_drop_notify(__MAGIC_FILE__, __MAGIC_LINE__, ctx, src, 0, 0, \
   171  			  __DROP_REASON(reason), exitcode, direction)
   172  
   173  #define send_drop_notify_ext(ctx, src, dst, dst_id, reason, ext_err, exitcode, direction) \
   174  	_send_drop_notify(__MAGIC_FILE__, __MAGIC_LINE__, ctx, src, dst, dst_id, \
   175  			  __DROP_REASON_EXT(reason, ext_err), exitcode, direction)
   176  
   177  #define send_drop_notify_error_ext(ctx, src, reason, ext_err, exitcode, direction) \
   178  	_send_drop_notify(__MAGIC_FILE__, __MAGIC_LINE__, ctx, src, 0, 0, \
   179  			  __DROP_REASON_EXT(reason, ext_err), exitcode, direction)