Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

openvswitch: add trace points

This makes openvswitch module use the event tracing framework
to log the upcall interface and action execution pipeline. When
using openvswitch as the packet forwarding engine, some types of
debugging are made possible simply by using the ovs-vswitchd's
ofproto/trace command. However, such a command has some
limitations:

1. When trying to trace packets that go through the CT action,
the state of the packet can't be determined, and probably
would be potentially wrong.

2. Deducing problem packets can sometimes be difficult as well
even if many of the flows are known

3. It's possible to use the openvswitch module even without
the ovs-vswitchd (although, not common use).

Introduce the event tracing points here to make it possible for
working through these problems in kernel space. The style is
copied from the mac80211 driver-trace / trace code for
consistency - this creates some checkpatch splats, but the
official 'guide' for adding tracepoints, as well as the existing
examples all add the same splats so it seems acceptable.

Signed-off-by: Aaron Conole <aconole@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Aaron Conole and committed by
David S. Miller
c4ab7b56 b0e03950

+179
+3
net/openvswitch/Makefile
··· 13 13 flow_netlink.o \ 14 14 flow_table.o \ 15 15 meter.o \ 16 + openvswitch_trace.o \ 16 17 vport.o \ 17 18 vport-internal_dev.o \ 18 19 vport-netdev.o ··· 25 24 obj-$(CONFIG_OPENVSWITCH_VXLAN)+= vport-vxlan.o 26 25 obj-$(CONFIG_OPENVSWITCH_GENEVE)+= vport-geneve.o 27 26 obj-$(CONFIG_OPENVSWITCH_GRE) += vport-gre.o 27 + 28 + CFLAGS_openvswitch_trace.o = -I$(src)
+4
net/openvswitch/actions.c
··· 30 30 #include "conntrack.h" 31 31 #include "vport.h" 32 32 #include "flow_netlink.h" 33 + #include "openvswitch_trace.h" 33 34 34 35 struct deferred_action { 35 36 struct sk_buff *skb; ··· 1242 1241 for (a = attr, rem = len; rem > 0; 1243 1242 a = nla_next(a, &rem)) { 1244 1243 int err = 0; 1244 + 1245 + if (trace_ovs_do_execute_action_enabled()) 1246 + trace_ovs_do_execute_action(dp, skb, key, a, rem); 1245 1247 1246 1248 switch (nla_type(a)) { 1247 1249 case OVS_ACTION_ATTR_OUTPUT: {
+4
net/openvswitch/datapath.c
··· 43 43 #include "flow_table.h" 44 44 #include "flow_netlink.h" 45 45 #include "meter.h" 46 + #include "openvswitch_trace.h" 46 47 #include "vport-internal_dev.h" 47 48 #include "vport-netdev.h" 48 49 ··· 275 274 { 276 275 struct dp_stats_percpu *stats; 277 276 int err; 277 + 278 + if (trace_ovs_dp_upcall_enabled()) 279 + trace_ovs_dp_upcall(dp, skb, key, upcall_info); 278 280 279 281 if (upcall_info->portid == 0) { 280 282 err = -ENOTCONN;
+10
net/openvswitch/openvswitch_trace.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* bug in tracepoint.h, it should include this */ 3 + #include <linux/module.h> 4 + 5 + /* sparse isn't too happy with all macros... */ 6 + #ifndef __CHECKER__ 7 + #define CREATE_TRACE_POINTS 8 + #include "openvswitch_trace.h" 9 + 10 + #endif
+158
net/openvswitch/openvswitch_trace.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #undef TRACE_SYSTEM 3 + #define TRACE_SYSTEM openvswitch 4 + 5 + #if !defined(_TRACE_OPENVSWITCH_H) || defined(TRACE_HEADER_MULTI_READ) 6 + #define _TRACE_OPENVSWITCH_H 7 + 8 + #include <linux/tracepoint.h> 9 + 10 + #include "datapath.h" 11 + 12 + TRACE_EVENT(ovs_do_execute_action, 13 + 14 + TP_PROTO(struct datapath *dp, struct sk_buff *skb, 15 + struct sw_flow_key *key, const struct nlattr *a, int rem), 16 + 17 + TP_ARGS(dp, skb, key, a, rem), 18 + 19 + TP_STRUCT__entry( 20 + __field( void *, dpaddr ) 21 + __string( dp_name, ovs_dp_name(dp) ) 22 + __string( dev_name, skb->dev->name ) 23 + __field( void *, skbaddr ) 24 + __field( unsigned int, len ) 25 + __field( unsigned int, data_len ) 26 + __field( unsigned int, truesize ) 27 + __field( u8, nr_frags ) 28 + __field( u16, gso_size ) 29 + __field( u16, gso_type ) 30 + __field( u32, ovs_flow_hash ) 31 + __field( u32, recirc_id ) 32 + __field( void *, keyaddr ) 33 + __field( u16, key_eth_type ) 34 + __field( u8, key_ct_state ) 35 + __field( u8, key_ct_orig_proto ) 36 + __field( u16, key_ct_zone ) 37 + __field( unsigned int, flow_key_valid ) 38 + __field( u8, action_type ) 39 + __field( unsigned int, action_len ) 40 + __field( void *, action_data ) 41 + __field( u8, is_last ) 42 + ), 43 + 44 + TP_fast_assign( 45 + __entry->dpaddr = dp; 46 + __assign_str(dp_name, ovs_dp_name(dp)); 47 + __assign_str(dev_name, skb->dev->name); 48 + __entry->skbaddr = skb; 49 + __entry->len = skb->len; 50 + __entry->data_len = skb->data_len; 51 + __entry->truesize = skb->truesize; 52 + __entry->nr_frags = skb_shinfo(skb)->nr_frags; 53 + __entry->gso_size = skb_shinfo(skb)->gso_size; 54 + __entry->gso_type = skb_shinfo(skb)->gso_type; 55 + __entry->ovs_flow_hash = key->ovs_flow_hash; 56 + __entry->recirc_id = key->recirc_id; 57 + __entry->keyaddr = key; 58 + __entry->key_eth_type = key->eth.type; 59 + __entry->key_ct_state = key->ct_state; 60 + __entry->key_ct_orig_proto = key->ct_orig_proto; 61 + __entry->key_ct_zone = key->ct_zone; 62 + __entry->flow_key_valid = !(key->mac_proto & SW_FLOW_KEY_INVALID); 63 + __entry->action_type = nla_type(a); 64 + __entry->action_len = nla_len(a); 65 + __entry->action_data = nla_data(a); 66 + __entry->is_last = nla_is_last(a, rem); 67 + ), 68 + 69 + TP_printk("dpaddr=%p dp_name=%s dev=%s skbaddr=%p len=%u data_len=%u truesize=%u nr_frags=%d gso_size=%d gso_type=%#x ovs_flow_hash=0x%08x recirc_id=0x%08x keyaddr=%p eth_type=0x%04x ct_state=%02x ct_orig_proto=%02x ct_Zone=%04x flow_key_valid=%d action_type=%u action_len=%u action_data=%p is_last=%d", 70 + __entry->dpaddr, __get_str(dp_name), __get_str(dev_name), 71 + __entry->skbaddr, __entry->len, __entry->data_len, 72 + __entry->truesize, __entry->nr_frags, __entry->gso_size, 73 + __entry->gso_type, __entry->ovs_flow_hash, 74 + __entry->recirc_id, __entry->keyaddr, __entry->key_eth_type, 75 + __entry->key_ct_state, __entry->key_ct_orig_proto, 76 + __entry->key_ct_zone, 77 + __entry->flow_key_valid, 78 + __entry->action_type, __entry->action_len, 79 + __entry->action_data, __entry->is_last) 80 + ); 81 + 82 + TRACE_EVENT(ovs_dp_upcall, 83 + 84 + TP_PROTO(struct datapath *dp, struct sk_buff *skb, 85 + const struct sw_flow_key *key, 86 + const struct dp_upcall_info *upcall_info), 87 + 88 + TP_ARGS(dp, skb, key, upcall_info), 89 + 90 + TP_STRUCT__entry( 91 + __field( void *, dpaddr ) 92 + __string( dp_name, ovs_dp_name(dp) ) 93 + __string( dev_name, skb->dev->name ) 94 + __field( void *, skbaddr ) 95 + __field( unsigned int, len ) 96 + __field( unsigned int, data_len ) 97 + __field( unsigned int, truesize ) 98 + __field( u8, nr_frags ) 99 + __field( u16, gso_size ) 100 + __field( u16, gso_type ) 101 + __field( u32, ovs_flow_hash ) 102 + __field( u32, recirc_id ) 103 + __field( const void *, keyaddr ) 104 + __field( u16, key_eth_type ) 105 + __field( u8, key_ct_state ) 106 + __field( u8, key_ct_orig_proto ) 107 + __field( u16, key_ct_zone ) 108 + __field( unsigned int, flow_key_valid ) 109 + __field( u8, upcall_cmd ) 110 + __field( u32, upcall_port ) 111 + __field( u16, upcall_mru ) 112 + ), 113 + 114 + TP_fast_assign( 115 + __entry->dpaddr = dp; 116 + __assign_str(dp_name, ovs_dp_name(dp)); 117 + __assign_str(dev_name, skb->dev->name); 118 + __entry->skbaddr = skb; 119 + __entry->len = skb->len; 120 + __entry->data_len = skb->data_len; 121 + __entry->truesize = skb->truesize; 122 + __entry->nr_frags = skb_shinfo(skb)->nr_frags; 123 + __entry->gso_size = skb_shinfo(skb)->gso_size; 124 + __entry->gso_type = skb_shinfo(skb)->gso_type; 125 + __entry->ovs_flow_hash = key->ovs_flow_hash; 126 + __entry->recirc_id = key->recirc_id; 127 + __entry->keyaddr = key; 128 + __entry->key_eth_type = key->eth.type; 129 + __entry->key_ct_state = key->ct_state; 130 + __entry->key_ct_orig_proto = key->ct_orig_proto; 131 + __entry->key_ct_zone = key->ct_zone; 132 + __entry->flow_key_valid = !(key->mac_proto & SW_FLOW_KEY_INVALID); 133 + __entry->upcall_cmd = upcall_info->cmd; 134 + __entry->upcall_port = upcall_info->portid; 135 + __entry->upcall_mru = upcall_info->mru; 136 + ), 137 + 138 + TP_printk("dpaddr=%p dp_name=%s dev=%s skbaddr=%p len=%u data_len=%u truesize=%u nr_frags=%d gso_size=%d gso_type=%#x ovs_flow_hash=0x%08x recirc_id=0x%08x keyaddr=%p eth_type=0x%04x ct_state=%02x ct_orig_proto=%02x ct_zone=%04x flow_key_valid=%d upcall_cmd=%u upcall_port=%u upcall_mru=%u", 139 + __entry->dpaddr, __get_str(dp_name), __get_str(dev_name), 140 + __entry->skbaddr, __entry->len, __entry->data_len, 141 + __entry->truesize, __entry->nr_frags, __entry->gso_size, 142 + __entry->gso_type, __entry->ovs_flow_hash, 143 + __entry->recirc_id, __entry->keyaddr, __entry->key_eth_type, 144 + __entry->key_ct_state, __entry->key_ct_orig_proto, 145 + __entry->key_ct_zone, 146 + __entry->flow_key_valid, 147 + __entry->upcall_cmd, __entry->upcall_port, 148 + __entry->upcall_mru) 149 + ); 150 + 151 + #endif /* _TRACE_OPENVSWITCH_H */ 152 + 153 + /* This part must be outside protection */ 154 + #undef TRACE_INCLUDE_PATH 155 + #define TRACE_INCLUDE_PATH . 156 + #undef TRACE_INCLUDE_FILE 157 + #define TRACE_INCLUDE_FILE openvswitch_trace 158 + #include <trace/define_trace.h>