github.com/datadog/cilium@v1.6.12/bpf/lib/trace.h (about)

     1  /*
     2   *  Copyright (C) 2016-2018 Authors of Cilium
     3   *
     4   *  This program is free software; you can redistribute it and/or modify
     5   *  it under the terms of the GNU General Public License as published by
     6   *  the Free Software Foundation; either version 2 of the License, or
     7   *  (at your option) any later version.
     8   *
     9   *  This program is distributed in the hope that it will be useful,
    10   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    11   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12   *  GNU General Public License for more details.
    13   *
    14   *  You should have received a copy of the GNU General Public License
    15   *  along with this program; if not, write to the Free Software
    16   *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    17   */
    18  /*
    19   * Packet forwarding notification via perf event ring buffer.
    20   *
    21   * API:
    22   * void send_trace_notify(skb, obs_point, src, dst, dst_id, ifindex, reason, monitor)
    23   *
    24   * If TRACE_NOTIFY is not defined, the API will be compiled in as a NOP.
    25   */
    26  
    27  #ifndef __LIB_TRACE__
    28  #define __LIB_TRACE__
    29  
    30  #include "dbg.h"
    31  #include "events.h"
    32  #include "common.h"
    33  #include "utils.h"
    34  #include "metrics.h"
    35  
    36  /* Available observation points. */
    37  enum {
    38  	TRACE_TO_LXC,
    39  	TRACE_TO_PROXY,
    40  	TRACE_TO_HOST,
    41  	TRACE_TO_STACK,
    42  	TRACE_TO_OVERLAY,
    43  	TRACE_FROM_LXC,
    44  	TRACE_FROM_PROXY,
    45  	TRACE_FROM_HOST,
    46  	TRACE_FROM_STACK,
    47  	TRACE_FROM_OVERLAY,
    48  	TRACE_FROM_NETWORK,
    49  };
    50  
    51  /* Reasons for forwarding a packet. */
    52  enum {
    53  	TRACE_REASON_POLICY = CT_NEW,
    54  	TRACE_REASON_CT_ESTABLISHED = CT_ESTABLISHED,
    55  	TRACE_REASON_CT_REPLY = CT_REPLY,
    56  	TRACE_REASON_CT_RELATED = CT_RELATED,
    57  };
    58  
    59  #define TRACE_REASON_ENCRYPTED	    0x80
    60  
    61  /* Trace aggregation levels. */
    62  enum {
    63  	TRACE_AGGREGATE_NONE = 0,      /* Trace every packet on rx & tx */
    64  	TRACE_AGGREGATE_RX = 1,        /* Hide trace on packet receive */
    65  	TRACE_AGGREGATE_ACTIVE_CT = 3, /* Ratelimit active connection traces */
    66  };
    67  
    68  #ifndef MONITOR_AGGREGATION
    69  #define MONITOR_AGGREGATION TRACE_AGGREGATE_NONE
    70  #endif
    71  
    72  #ifdef TRACE_NOTIFY
    73  
    74  struct trace_notify {
    75  	NOTIFY_COMMON_HDR
    76  	__u32		len_orig;
    77  	__u32		len_cap;
    78  	__u32		src_label;
    79  	__u32		dst_label;
    80  	__u16		dst_id;
    81  	__u8		reason;
    82  	__u8		pad;
    83  	__u32		ifindex;
    84  };
    85  
    86  /**
    87   * send_trace_notify
    88   * @skb:	socket buffer
    89   * @obs_point:	observation point (TRACE_*)
    90   * @src:	source identity
    91   * @dst:	destination identity
    92   * @dst_id:	designated destination endpoint ID
    93   * @ifindex:	designated destination ifindex
    94   * @reason:	reason for forwarding the packet (TRACE_REASON_*)
    95   * @monitor:	length of notification to send (0 means don't send)
    96   *
    97   * Generate a notification to indicate a packet was forwarded at an observation point.
    98   */
    99  static inline void
   100  send_trace_notify(struct __sk_buff *skb, __u8 obs_point, __u32 src, __u32 dst,
   101  		  __u16 dst_id, __u32 ifindex, __u8 reason, __u32 monitor)
   102  {
   103  	__u8 encrypted;
   104  
   105  	switch (obs_point) {
   106  		case TRACE_TO_LXC:
   107  			update_metrics(skb->len, METRIC_INGRESS, REASON_FORWARDED);
   108  			break;
   109  
   110  		/* TRACE_FROM_LXC, i.e endpoint-to-endpoint delivery
   111  		 * is handled separately in ipv*_local_delivery() where we can bump
   112  		 * an egress forward. It could still be dropped but it would show
   113  		 * up later as an ingress drop, in that scenario.
   114  		 *
   115  		 * TRACE_TO_PROXY is not handled in datapath. This is because we have separate
   116  		 * L7 proxy "forwarded" and "dropped" (ingress/egress) counters in the proxy layer
   117  		 * to capture these metrics.
   118  		 */
   119  		case TRACE_TO_HOST:
   120  		case TRACE_TO_STACK:
   121  		case TRACE_TO_OVERLAY:
   122  			update_metrics(skb->len, METRIC_EGRESS, REASON_FORWARDED);
   123  			break;
   124  		case TRACE_FROM_OVERLAY:
   125  		case TRACE_FROM_NETWORK:
   126  			encrypted = reason & TRACE_REASON_ENCRYPTED;
   127  			if (!encrypted)
   128  				update_metrics(skb->len, METRIC_INGRESS, REASON_PLAINTEXT);
   129  			else
   130  				update_metrics(skb->len, METRIC_INGRESS, REASON_DECRYPT);
   131  			break;
   132  	}
   133  	if (MONITOR_AGGREGATION >= TRACE_AGGREGATE_RX) {
   134  		switch (obs_point) {
   135  		case TRACE_FROM_LXC:
   136  		case TRACE_FROM_PROXY:
   137  		case TRACE_FROM_HOST:
   138  		case TRACE_FROM_STACK:
   139  		case TRACE_FROM_OVERLAY:
   140  		case TRACE_FROM_NETWORK:
   141  			return;
   142  		default:
   143  			break;
   144  		}
   145  	}
   146  	if (MONITOR_AGGREGATION >= TRACE_AGGREGATE_ACTIVE_CT && !monitor)
   147  		return;
   148  
   149  	if (!monitor)
   150  		monitor = TRACE_PAYLOAD_LEN;
   151  	uint64_t skb_len = (uint64_t)skb->len, cap_len = min((uint64_t)monitor, (uint64_t)skb_len);
   152  	uint32_t hash = get_hash_recalc(skb);
   153  	struct trace_notify msg = {
   154  		.type = CILIUM_NOTIFY_TRACE,
   155  		.subtype = obs_point,
   156  		.source = EVENT_SOURCE,
   157  		.hash = hash,
   158  		.len_orig = skb_len,
   159  		.len_cap = cap_len,
   160  		.src_label = src,
   161  		.dst_label = dst,
   162  		.dst_id = dst_id,
   163  		.reason = reason,
   164  		.pad = 0,
   165  		.ifindex = ifindex,
   166  	};
   167  	skb_event_output(skb, &EVENTS_MAP,
   168  			 (cap_len << 32) | BPF_F_CURRENT_CPU,
   169  			 &msg, sizeof(msg));
   170  }
   171  
   172  #else
   173  
   174  static inline void send_trace_notify(struct __sk_buff *skb, __u8 obs_point, __u32 src, __u32 dst,
   175  				     __u16 dst_id, __u32 ifindex, __u8 reason, __u32 monitor)
   176  {
   177  	__u8 encrypted;
   178  
   179  	switch (obs_point) {
   180  		case TRACE_TO_LXC:
   181  			update_metrics(skb->len, METRIC_INGRESS, REASON_FORWARDED);
   182  			break;
   183  
   184  		/* TRACE_FROM_LXC, i.e endpoint-to-endpoint delivery
   185  		 * is handled separately in ipv*_local_delivery() where we can bump
   186  		 * an egress forward. It could still be dropped but it would show
   187  		 * up later as an ingress drop, in that scenario.
   188  		 *
   189  		 * TRACE_TO_PROXY is not handled in datapath. This is because we have separate
   190  		 * L7 proxy "forwarded" and "dropped" (ingress/egress) counters in the proxy layer
   191  		 * to capture these metrics.
   192  		 */
   193  		case TRACE_TO_HOST:
   194  		case TRACE_TO_STACK:
   195  		case TRACE_TO_OVERLAY:
   196  			update_metrics(skb->len, METRIC_EGRESS, REASON_FORWARDED);
   197  			break;
   198  		case TRACE_FROM_OVERLAY:
   199  		case TRACE_FROM_NETWORK:
   200  			encrypted = reason & TRACE_REASON_ENCRYPTED;
   201  			if (!encrypted)
   202  				update_metrics(skb->len, METRIC_INGRESS, REASON_PLAINTEXT);
   203  			else
   204  				update_metrics(skb->len, METRIC_INGRESS, REASON_DECRYPT);
   205  			break;
   206  	}
   207  }
   208  
   209  #endif
   210  
   211  #endif /* __LIB_TRACE__ */