There already are network trace points for transmit and receive but nothing for state changes. Add network tracepoints for before and after netlink callback is done. This is simple (without extack or other info) but that could be added if useful. Network namespace id would also be helpful but hard to get a string for it.
This is the result of a conversation about monitoring of link state changes with BPF. Parsing netlink is hard and unnecessary because the data exists (unserialized) already in the callbacks. # cd /sys/kernel/debug/tracing # echo 1 > events/net/net_dev_notifier_entry/enable # echo 1 > events/net/net_dev_notifier/enable # ip li set dev eno1 down # ip li set dev eno1 up # cat trace # tracer: nop # # _-----=> irqs-off # / _----=> need-resched # | / _---=> hardirq/softirq # || / _--=> preempt-depth # ||| / delay # TASK-PID CPU# |||| TIMESTAMP FUNCTION # | | | |||| | | ip-3194 [011] .... 74.926831: net_dev_notifier_entry: dev=eno1 event=GOING_DOWN ip-3194 [011] .... 74.926838: net_dev_notifier: dev=eno1 event=GOING_DOWN ret=1 ip-3194 [011] .... 75.029827: net_dev_notifier_entry: dev=eno1 event=DOWN ip-3194 [011] .... 75.031808: net_dev_notifier: dev=eno1 event=DOWN ret=1 ip-3195 [011] .... 78.063845: net_dev_notifier_entry: dev=eno1 event=PRE_UP ip-3195 [011] .... 78.063854: net_dev_notifier: dev=eno1 event=PRE_UP ret=1 ip-3195 [011] .... 78.279038: net_dev_notifier_entry: dev=eno1 event=UP ip-3195 [011] .... 78.279065: net_dev_notifier: dev=eno1 event=UP ret=1 Signed-off-by: Stephen Hemminger <step...@networkplumber.org> --- include/trace/events/net.h | 115 +++++++++++++++++++++++++++++++++++++ net/core/dev.c | 9 ++- 2 files changed, 123 insertions(+), 1 deletion(-) diff --git a/include/trace/events/net.h b/include/trace/events/net.h index 1efd7d9b25fe..141310d24610 100644 --- a/include/trace/events/net.h +++ b/include/trace/events/net.h @@ -11,6 +11,121 @@ #include <linux/ip.h> #include <linux/tracepoint.h> +TRACE_DEFINE_ENUM(NETDEV_UP); +TRACE_DEFINE_ENUM(NETDEV_DOWN); +TRACE_DEFINE_ENUM(NETDEV_REBOOT); +TRACE_DEFINE_ENUM(NETDEV_CHANGE); +TRACE_DEFINE_ENUM(NETDEV_REGISTER); +TRACE_DEFINE_ENUM(NETDEV_UNREGISTER); +TRACE_DEFINE_ENUM(NETDEV_CHANGEMTU); +TRACE_DEFINE_ENUM(NETDEV_CHANGEADDR); +TRACE_DEFINE_ENUM(NETDEV_PRE_CHANGEADDR); +TRACE_DEFINE_ENUM(NETDEV_GOING_DOWN); +TRACE_DEFINE_ENUM(NETDEV_CHANGENAME); +TRACE_DEFINE_ENUM(NETDEV_FEAT_CHANGE); +TRACE_DEFINE_ENUM(NETDEV_BONDING_FAILOVER); +TRACE_DEFINE_ENUM(NETDEV_PRE_UP); +TRACE_DEFINE_ENUM(NETDEV_PRE_TYPE_CHANGE); +TRACE_DEFINE_ENUM(NETDEV_POST_TYPE_CHANGE); +TRACE_DEFINE_ENUM(NETDEV_POST_INIT); +TRACE_DEFINE_ENUM(NETDEV_RELEASE); +TRACE_DEFINE_ENUM(NETDEV_NOTIFY_PEERS); +TRACE_DEFINE_ENUM(NETDEV_JOIN); +TRACE_DEFINE_ENUM(NETDEV_CHANGEUPPER); +TRACE_DEFINE_ENUM(NETDEV_RESEND_IGMP); +TRACE_DEFINE_ENUM(NETDEV_PRECHANGEMTU); +TRACE_DEFINE_ENUM(NETDEV_CHANGEINFODATA); +TRACE_DEFINE_ENUM(NETDEV_BONDING_INFO); +TRACE_DEFINE_ENUM(NETDEV_PRECHANGEUPPER); +TRACE_DEFINE_ENUM(NETDEV_CHANGELOWERSTATE); +TRACE_DEFINE_ENUM(NETDEV_UDP_TUNNEL_PUSH_INFO); +TRACE_DEFINE_ENUM(NETDEV_UDP_TUNNEL_DROP_INFO); +TRACE_DEFINE_ENUM(NETDEV_CHANGE_TX_QUEUE_LEN); +TRACE_DEFINE_ENUM(NETDEV_CVLAN_FILTER_PUSH_INFO); +TRACE_DEFINE_ENUM(NETDEV_CVLAN_FILTER_DROP_INFO); +TRACE_DEFINE_ENUM(NETDEV_SVLAN_FILTER_PUSH_INFO); +TRACE_DEFINE_ENUM(NETDEV_SVLAN_FILTER_DROP_INFO); + +#define netdev_event_type(type) \ + __print_symbolic(type, \ + { NETDEV_UP, "UP" }, \ + { NETDEV_DOWN, "DOWN" }, \ + { NETDEV_REBOOT, "REBOOT" }, \ + { NETDEV_CHANGE, "CHANGE" }, \ + { NETDEV_REGISTER, "REGISTER" }, \ + { NETDEV_UNREGISTER, "UNREGISTER" }, \ + { NETDEV_CHANGEMTU, "CHANGEMTU" }, \ + { NETDEV_CHANGEADDR, "CHANGEADDR" }, \ + { NETDEV_PRE_CHANGEADDR, "PRE_CHANGEADDR" }, \ + { NETDEV_GOING_DOWN, "GOING_DOWN" }, \ + { NETDEV_CHANGENAME, "CHANGENAME" }, \ + { NETDEV_FEAT_CHANGE, "FEAT_CHANGE" }, \ + { NETDEV_BONDING_FAILOVER, "BONDING_FAILOVER" }, \ + { NETDEV_PRE_UP, "PRE_UP" }, \ + { NETDEV_PRE_TYPE_CHANGE, "PRE_TYPE_CHANGE" }, \ + { NETDEV_POST_TYPE_CHANGE, "POST_TYPE_CHANGE" }, \ + { NETDEV_POST_INIT, "POST_INIT" }, \ + { NETDEV_RELEASE, "RELEASE" }, \ + { NETDEV_NOTIFY_PEERS, "NOTIFY_PEERS" }, \ + { NETDEV_JOIN, "JOIN" }, \ + { NETDEV_CHANGEUPPER, "CHANGEUPPER" }, \ + { NETDEV_RESEND_IGMP, "RESEND_IGMP" }, \ + { NETDEV_PRECHANGEMTU, "PRECHANGEMTU" }, \ + { NETDEV_CHANGEINFODATA, "CHANGEINFODATA" }, \ + { NETDEV_BONDING_INFO, "BONDING_INFO" }, \ + { NETDEV_PRECHANGEUPPER, "PRECHANGEUPPER" }, \ + { NETDEV_CHANGELOWERSTATE, "CHANGELOWERSTATE" }, \ + { NETDEV_UDP_TUNNEL_PUSH_INFO, "UDP_TUNNEL_PUSH_INFO" }, \ + { NETDEV_UDP_TUNNEL_DROP_INFO, "UDP_TUNNEL_DROP_INFO" }, \ + { NETDEV_CHANGE_TX_QUEUE_LEN, "CHANGE_TX_QUEUE_LEN" }, \ + { NETDEV_CVLAN_FILTER_PUSH_INFO, "CVLAN_FILTER_PUSH_INFO" }, \ + { NETDEV_CVLAN_FILTER_DROP_INFO, "CVLAN_FILTER_DROP_INFO" }, \ + { NETDEV_SVLAN_FILTER_PUSH_INFO, "SVLAN_FILTER_PUSH_INFO" }, \ + { NETDEV_SVLAN_FILTER_DROP_INFO, "SVLAN_FILTER_DROP_INFO" } ) + +TRACE_EVENT(net_dev_notifier_entry, + + TP_PROTO(const struct netdev_notifier_info *info, unsigned long val), + + TP_ARGS(info, val), + + TP_STRUCT__entry( + __string( name, info->dev->name ) + __field( enum netdev_cmd, event ) + ), + + TP_fast_assign( + __assign_str(name, info->dev->name); + __entry->event = val; + ), + + TP_printk("dev=%s event=%s", + __get_str(name), netdev_event_type(__entry->event)) +); + +TRACE_EVENT(net_dev_notifier, + + TP_PROTO(const struct netdev_notifier_info *info, int rc, unsigned long val), + + TP_ARGS(info, rc, val), + + TP_STRUCT__entry( + __string( name, info->dev->name ) + __field( enum netdev_cmd, event ) + __field( int, rc ) + ), + + TP_fast_assign( + __assign_str(name, info->dev->name); + __entry->event = val; + __entry->rc = rc; + ), + + TP_printk("dev=%s event=%s ret=%d", + __get_str(name), netdev_event_type(__entry->event), + __entry->rc) +); + TRACE_EVENT(net_dev_start_xmit, TP_PROTO(const struct sk_buff *skb, const struct net_device *dev), diff --git a/net/core/dev.c b/net/core/dev.c index 1b5a4410be0e..0906f317e5ca 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1735,8 +1735,15 @@ EXPORT_SYMBOL(unregister_netdevice_notifier); static int call_netdevice_notifiers_info(unsigned long val, struct netdev_notifier_info *info) { + int rc; + ASSERT_RTNL(); - return raw_notifier_call_chain(&netdev_chain, val, info); + + trace_net_dev_notifier_entry(info, val); + rc = raw_notifier_call_chain(&netdev_chain, val, info); + trace_net_dev_notifier(info, rc, val); + + return rc; } static int call_netdevice_notifiers_extack(unsigned long val, -- 2.19.2