|
30 | 30 | #include <net/genetlink.h>
|
31 | 31 | #include <net/netevent.h>
|
32 | 32 | #include <net/flow_offload.h>
|
| 33 | +#include <net/devlink.h> |
33 | 34 |
|
34 | 35 | #include <trace/events/skb.h>
|
35 | 36 | #include <trace/events/napi.h>
|
@@ -116,6 +117,9 @@ struct net_dm_alert_ops {
|
116 | 117 | void (*hw_work_item_func)(struct work_struct *work);
|
117 | 118 | void (*hw_probe)(struct sk_buff *skb,
|
118 | 119 | const struct net_dm_hw_metadata *hw_metadata);
|
| 120 | + void (*hw_trap_probe)(void *ignore, const struct devlink *devlink, |
| 121 | + struct sk_buff *skb, |
| 122 | + const struct devlink_trap_metadata *metadata); |
119 | 123 | };
|
120 | 124 |
|
121 | 125 | struct net_dm_skb_cb {
|
@@ -474,12 +478,57 @@ net_dm_hw_summary_probe(struct sk_buff *skb,
|
474 | 478 | spin_unlock_irqrestore(&hw_data->lock, flags);
|
475 | 479 | }
|
476 | 480 |
|
| 481 | +static void |
| 482 | +net_dm_hw_trap_summary_probe(void *ignore, const struct devlink *devlink, |
| 483 | + struct sk_buff *skb, |
| 484 | + const struct devlink_trap_metadata *metadata) |
| 485 | +{ |
| 486 | + struct net_dm_hw_entries *hw_entries; |
| 487 | + struct net_dm_hw_entry *hw_entry; |
| 488 | + struct per_cpu_dm_data *hw_data; |
| 489 | + unsigned long flags; |
| 490 | + int i; |
| 491 | + |
| 492 | + hw_data = this_cpu_ptr(&dm_hw_cpu_data); |
| 493 | + spin_lock_irqsave(&hw_data->lock, flags); |
| 494 | + hw_entries = hw_data->hw_entries; |
| 495 | + |
| 496 | + if (!hw_entries) |
| 497 | + goto out; |
| 498 | + |
| 499 | + for (i = 0; i < hw_entries->num_entries; i++) { |
| 500 | + hw_entry = &hw_entries->entries[i]; |
| 501 | + if (!strncmp(hw_entry->trap_name, metadata->trap_name, |
| 502 | + NET_DM_MAX_HW_TRAP_NAME_LEN - 1)) { |
| 503 | + hw_entry->count++; |
| 504 | + goto out; |
| 505 | + } |
| 506 | + } |
| 507 | + if (WARN_ON_ONCE(hw_entries->num_entries == dm_hit_limit)) |
| 508 | + goto out; |
| 509 | + |
| 510 | + hw_entry = &hw_entries->entries[hw_entries->num_entries]; |
| 511 | + strlcpy(hw_entry->trap_name, metadata->trap_name, |
| 512 | + NET_DM_MAX_HW_TRAP_NAME_LEN - 1); |
| 513 | + hw_entry->count = 1; |
| 514 | + hw_entries->num_entries++; |
| 515 | + |
| 516 | + if (!timer_pending(&hw_data->send_timer)) { |
| 517 | + hw_data->send_timer.expires = jiffies + dm_delay * HZ; |
| 518 | + add_timer(&hw_data->send_timer); |
| 519 | + } |
| 520 | + |
| 521 | +out: |
| 522 | + spin_unlock_irqrestore(&hw_data->lock, flags); |
| 523 | +} |
| 524 | + |
477 | 525 | static const struct net_dm_alert_ops net_dm_alert_summary_ops = {
|
478 | 526 | .kfree_skb_probe = trace_kfree_skb_hit,
|
479 | 527 | .napi_poll_probe = trace_napi_poll_hit,
|
480 | 528 | .work_item_func = send_dm_alert,
|
481 | 529 | .hw_work_item_func = net_dm_hw_summary_work,
|
482 | 530 | .hw_probe = net_dm_hw_summary_probe,
|
| 531 | + .hw_trap_probe = net_dm_hw_trap_summary_probe, |
483 | 532 | };
|
484 | 533 |
|
485 | 534 | static void net_dm_packet_trace_kfree_skb_hit(void *ignore,
|
@@ -858,6 +907,54 @@ net_dm_hw_metadata_clone(const struct net_dm_hw_metadata *hw_metadata)
|
858 | 907 | return NULL;
|
859 | 908 | }
|
860 | 909 |
|
| 910 | +static struct net_dm_hw_metadata * |
| 911 | +net_dm_hw_metadata_copy(const struct devlink_trap_metadata *metadata) |
| 912 | +{ |
| 913 | + const struct flow_action_cookie *fa_cookie; |
| 914 | + struct net_dm_hw_metadata *hw_metadata; |
| 915 | + const char *trap_group_name; |
| 916 | + const char *trap_name; |
| 917 | + |
| 918 | + hw_metadata = kzalloc(sizeof(*hw_metadata), GFP_ATOMIC); |
| 919 | + if (!hw_metadata) |
| 920 | + return NULL; |
| 921 | + |
| 922 | + trap_group_name = kstrdup(metadata->trap_group_name, GFP_ATOMIC); |
| 923 | + if (!trap_group_name) |
| 924 | + goto free_hw_metadata; |
| 925 | + hw_metadata->trap_group_name = trap_group_name; |
| 926 | + |
| 927 | + trap_name = kstrdup(metadata->trap_name, GFP_ATOMIC); |
| 928 | + if (!trap_name) |
| 929 | + goto free_trap_group; |
| 930 | + hw_metadata->trap_name = trap_name; |
| 931 | + |
| 932 | + if (metadata->fa_cookie) { |
| 933 | + size_t cookie_size = sizeof(*fa_cookie) + |
| 934 | + metadata->fa_cookie->cookie_len; |
| 935 | + |
| 936 | + fa_cookie = kmemdup(metadata->fa_cookie, cookie_size, |
| 937 | + GFP_ATOMIC); |
| 938 | + if (!fa_cookie) |
| 939 | + goto free_trap_name; |
| 940 | + hw_metadata->fa_cookie = fa_cookie; |
| 941 | + } |
| 942 | + |
| 943 | + hw_metadata->input_dev = metadata->input_dev; |
| 944 | + if (hw_metadata->input_dev) |
| 945 | + dev_hold(hw_metadata->input_dev); |
| 946 | + |
| 947 | + return hw_metadata; |
| 948 | + |
| 949 | +free_trap_name: |
| 950 | + kfree(trap_name); |
| 951 | +free_trap_group: |
| 952 | + kfree(trap_group_name); |
| 953 | +free_hw_metadata: |
| 954 | + kfree(hw_metadata); |
| 955 | + return NULL; |
| 956 | +} |
| 957 | + |
861 | 958 | static void
|
862 | 959 | net_dm_hw_metadata_free(const struct net_dm_hw_metadata *hw_metadata)
|
863 | 960 | {
|
@@ -970,12 +1067,61 @@ net_dm_hw_packet_probe(struct sk_buff *skb,
|
970 | 1067 | consume_skb(nskb);
|
971 | 1068 | }
|
972 | 1069 |
|
| 1070 | +static void |
| 1071 | +net_dm_hw_trap_packet_probe(void *ignore, const struct devlink *devlink, |
| 1072 | + struct sk_buff *skb, |
| 1073 | + const struct devlink_trap_metadata *metadata) |
| 1074 | +{ |
| 1075 | + struct net_dm_hw_metadata *n_hw_metadata; |
| 1076 | + ktime_t tstamp = ktime_get_real(); |
| 1077 | + struct per_cpu_dm_data *hw_data; |
| 1078 | + struct sk_buff *nskb; |
| 1079 | + unsigned long flags; |
| 1080 | + |
| 1081 | + if (!skb_mac_header_was_set(skb)) |
| 1082 | + return; |
| 1083 | + |
| 1084 | + nskb = skb_clone(skb, GFP_ATOMIC); |
| 1085 | + if (!nskb) |
| 1086 | + return; |
| 1087 | + |
| 1088 | + n_hw_metadata = net_dm_hw_metadata_copy(metadata); |
| 1089 | + if (!n_hw_metadata) |
| 1090 | + goto free; |
| 1091 | + |
| 1092 | + NET_DM_SKB_CB(nskb)->hw_metadata = n_hw_metadata; |
| 1093 | + nskb->tstamp = tstamp; |
| 1094 | + |
| 1095 | + hw_data = this_cpu_ptr(&dm_hw_cpu_data); |
| 1096 | + |
| 1097 | + spin_lock_irqsave(&hw_data->drop_queue.lock, flags); |
| 1098 | + if (skb_queue_len(&hw_data->drop_queue) < net_dm_queue_len) |
| 1099 | + __skb_queue_tail(&hw_data->drop_queue, nskb); |
| 1100 | + else |
| 1101 | + goto unlock_free; |
| 1102 | + spin_unlock_irqrestore(&hw_data->drop_queue.lock, flags); |
| 1103 | + |
| 1104 | + schedule_work(&hw_data->dm_alert_work); |
| 1105 | + |
| 1106 | + return; |
| 1107 | + |
| 1108 | +unlock_free: |
| 1109 | + spin_unlock_irqrestore(&hw_data->drop_queue.lock, flags); |
| 1110 | + u64_stats_update_begin(&hw_data->stats.syncp); |
| 1111 | + hw_data->stats.dropped++; |
| 1112 | + u64_stats_update_end(&hw_data->stats.syncp); |
| 1113 | + net_dm_hw_metadata_free(n_hw_metadata); |
| 1114 | +free: |
| 1115 | + consume_skb(nskb); |
| 1116 | +} |
| 1117 | + |
973 | 1118 | static const struct net_dm_alert_ops net_dm_alert_packet_ops = {
|
974 | 1119 | .kfree_skb_probe = net_dm_packet_trace_kfree_skb_hit,
|
975 | 1120 | .napi_poll_probe = net_dm_packet_trace_napi_poll_hit,
|
976 | 1121 | .work_item_func = net_dm_packet_work,
|
977 | 1122 | .hw_work_item_func = net_dm_hw_packet_work,
|
978 | 1123 | .hw_probe = net_dm_hw_packet_probe,
|
| 1124 | + .hw_trap_probe = net_dm_hw_trap_packet_probe, |
979 | 1125 | };
|
980 | 1126 |
|
981 | 1127 | static const struct net_dm_alert_ops *net_dm_alert_ops_arr[] = {
|
|
0 commit comments