tools lib traceevent: Add support for IP address formats
Subsystems (3)
PATCH 1/1 tools lib traceevent: Add support for IP address formats
Adds helper for following kernel formats:
%pi4 print an IPv4 address with leading zeros %pI4 print an IPv4 address without leading zeros %pi6 print an IPv6 address without colons %pI6 print an IPv6 address with colons %pI6c print an IPv6 address with colons %pISpc print an IP address from a sockaddr
Allows these formats to be used in tracepoints.
Quite a bit of this is adapted from code in lib/vsprintf.c.
v2:
- pass ptr+1 to print_ip_arg per Namhyung's comments
- added field length checks to sockaddr function
--- tools/lib/traceevent/event-parse.c | 326 +++++++++++++++++++++++++++++++++++++ 1 file changed, 326 insertions(+)
tools/lib/traceevent/event-parse.c +326 -0
@@ -32,6 +32,7 @@#include <stdint.h> #include <limits.h> +#include <netinet/ip6.h> #include "event-parse.h" #include "event-utils.h"
@@ -4149,6 +4150,322 @@ static void print_mac_arg(struct trace_seq *s, int mac, void *data, int size,trace_seq_printf (s, fmt, buf[0 ], buf[1 ], buf[2 ], buf[3 ], buf[4 ], buf[5 ]); } +static void print_ip4_addr (struct trace_seq *s,char i,unsigned char *buf) +{ +const char *fmt; + +if (i =='i' ) + fmt ="%03d.%03d.%03d.%03d" ; +else + fmt ="%d.%d.%d.%d" ; + +trace_seq_printf (s, fmt, buf[0 ], buf[1 ], buf[2 ], buf[3 ]); +} + +static inline bool ipv6_addr_v4mapped (const struct in6_addr *a) +{ +return ((unsigned long )(a->s6_addr32[0 ] | a->s6_addr32[1 ]) | + (unsigned long )(a->s6_addr32[2 ] ^htonl (0x0000ffff ))) ==0UL ; +} + +static inline bool ipv6_addr_is_isatap (const struct in6_addr *addr) +{ +return (addr->s6_addr32[2 ] |htonl (0x02000000 )) ==htonl (0x02005EFE ); +} + +static void print_ip6c_addr (struct trace_seq *s,unsigned char *addr) +{ +int i, j, range; +unsigned char zerolength[8 ]; +int longest =1 ; +int colonpos =-1 ; +uint16_t word; +uint8_t hi, lo; +bool needcolon = false; +bool useIPv4; +struct in6_addr in6; + +memcpy (&in6, addr,sizeof (struct in6_addr )); + + useIPv4 =ipv6_addr_v4mapped (&in6) ||ipv6_addr_is_isatap (&in6); + +memset (zerolength,0 ,sizeof (zerolength)); + +if (useIPv4) + range =6 ; +else + range =8 ; + +/* find position of longest 0 run */ +for (i =0 ; i < range; i++) { +for (j = i; j < range; j++) { +if (in6.s6_addr16[j] !=0 ) +break ; + zerolength[i]++; + } + } +for (i =0 ; i < range; i++) { +if (zerolength[i] > longest) { + longest = zerolength[i]; + colonpos = i; + } + } +if (longest ==1 )/* don't compress a single 0 */ + colonpos =-1 ; + +/* emit address */ +for (i =0 ; i < range; i++) { +if (i == colonpos) { +if (needcolon || i ==0 ) +trace_seq_printf (s,":" ); +trace_seq_printf (s,":" ); + needcolon = false; + i += longest -1 ; +continue ; + } +if (needcolon) { +trace_seq_printf (s,":" ); + needcolon = false; + } +/* hex u16 without leading 0s */ + word =ntohs (in6.s6_addr16[i]); + hi = word >>8 ; + lo = word &0xff ; +if (hi) +trace_seq_printf (s,"%x%02x" , hi, lo); +else +trace_seq_printf (s,"%x" , lo); + + needcolon = true; + } + +if (useIPv4) { +if (needcolon) +trace_seq_printf (s,":" ); +print_ip4_addr (s,'I' , &in6.s6_addr[12 ]); + } + +return ; +} + +static void print_ip6_addr (struct trace_seq *s,char i,unsigned char *buf) +{ +int j; + +for (j =0 ; j <16 ; j +=2 ) { +trace_seq_printf (s,"%02x%02x" , buf[j], buf[j+1 ]); +if (i =='I' && j <14 ) +trace_seq_printf (s,":" ); + } +} + +/* +* %pi4 print an IPv4 address with leading zeros +* %pI4 print an IPv4 address without leading zeros +* %pi6 print an IPv6 address without colons +* %pI6 print an IPv6 address with colons +* %pI6c print an IPv6 address in compressed form with colons +* %pISpc print an IP address based on sockaddr; p adds port. +*/ +static int print_ipv4_arg (struct trace_seq *s,const char *ptr,char i, +void *data,int size,struct event_format *event, +struct print_arg *arg) +{ +unsigned char *buf; + +if (arg->type ==PRINT_FUNC ) { +process_defined_func (s, data, size, event, arg); +return 0 ; + } + +if (arg->type !=PRINT_FIELD ) { +trace_seq_printf (s,"ARG TYPE NOT FIELD BUT %d" , arg->type); +return 0 ; + } + +if (!arg->field.field) { + arg->field.field = +pevent_find_any_field (event, arg->field.name); +if (!arg->field.field) { +do_warning ("%s: field %s not found" , + __func__, arg->field.name); +return 0 ; + } + } + + buf = data + arg->field.field->offset; + +if (arg->field.field->size !=4 ) { +trace_seq_printf (s,"INVALIDIPv4" ); +return 0 ; + } +print_ip4_addr (s, i, buf); + +return 0 ; +} + +static int print_ipv6_arg (struct trace_seq *s,const char *ptr,char i, +void *data,int size,struct event_format *event, +struct print_arg *arg) +{ +char have_c =0 ; +unsigned char *buf; +int rc =0 ; + +/* pI6c */ +if (*ptr =='c' ) { + have_c =1 ; + ptr++; + rc++; + } + +if (arg->type ==PRINT_FUNC ) { +process_defined_func (s, data, size, event, arg); +return rc; + } + +if (arg->type !=PRINT_FIELD ) { +trace_seq_printf (s,"ARG TYPE NOT FIELD BUT %d" , arg->type); +return rc; + } + +if (!arg->field.field) { + arg->field.field = +pevent_find_any_field (event, arg->field.name); +if (!arg->field.field) { +do_warning ("%s: field %s not found" , + __func__, arg->field.name); +return rc; + } + } + + buf = data + arg->field.field->offset; + +if (arg->field.field->size !=16 ) { +trace_seq_printf (s,"INVALIDIPv6" ); +return rc; + } + +if (have_c) +print_ip6c_addr (s, buf); +else +print_ip6_addr (s, i, buf); + +return rc; +} + +static int print_ipsa_arg (struct trace_seq *s,const char *ptr,char i, +void *data,int size,struct event_format *event, +struct print_arg *arg) +{ +char have_c =0 , have_p =0 ; +unsigned char *buf; +struct sockaddr_storage *sa; +int rc =0 ; + +/* pISpc */ +if (*ptr =='p' ) { + have_p =1 ; + ptr++; + rc++; + } +if (*ptr =='c' ) { + have_c =1 ; + ptr++; + rc++; + } + +if (arg->type ==PRINT_FUNC ) { +process_defined_func (s, data, size, event, arg); +return rc; + } + +if (arg->type !=PRINT_FIELD ) { +trace_seq_printf (s,"ARG TYPE NOT FIELD BUT %d" , arg->type); +return rc; + } + +if (!arg->field.field) { + arg->field.field = +pevent_find_any_field (event, arg->field.name); +if (!arg->field.field) { +do_warning ("%s: field %s not found" , + __func__, arg->field.name); +return rc; + } + } + + sa = (struct sockaddr_storage *) (data + arg->field.field->offset); + +if (sa->ss_family ==AF_INET ) { +struct sockaddr_in *sa4 = (struct sockaddr_in *) sa; + +if (arg->field.field->size <sizeof (struct sockaddr_in )) { +trace_seq_printf (s,"INVALIDIPv4" ); +return rc; + } + +print_ip4_addr (s, i, (unsigned char *) &sa4->sin_addr); +if (have_p) +trace_seq_printf (s,":%d" ,ntohs (sa4->sin_port)); + + + }else if (sa->ss_family ==AF_INET6 ) { +struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) sa; + +if (arg->field.field->size <sizeof (struct sockaddr_in6 )) { +trace_seq_printf (s,"INVALIDIPv6" ); +return rc; + } + +if (have_p) +trace_seq_printf (s,"[" ); + + buf = (unsigned char *) &sa6->sin6_addr; +if (have_c) +print_ip6c_addr (s, buf); +else +print_ip6_addr (s, i, buf); + +if (have_p) +trace_seq_printf (s,"]:%d" ,ntohs (sa6->sin6_port)); + } + +return rc; +} + +static int print_ip_arg (struct trace_seq *s,const char *ptr, +void *data,int size,struct event_format *event, +struct print_arg *arg) +{ +char i = *ptr;/* 'i' or 'I' */ +char ver; +int rc =0 ; + + ptr++; + rc++; + + ver = *ptr; + ptr++; + rc++; + +switch (ver) { +case '4' : + rc +=print_ipv4_arg (s, ptr, i, data, size, event, arg); +break ; +case '6' : + rc +=print_ipv6_arg (s, ptr, i, data, size, event, arg); +break ; +case 'S' : + rc +=print_ipsa_arg (s, ptr, i, data, size, event, arg); +break ; +default : +return 0 ; + } + +return rc; +} +static int is_printable_array (char *p,unsigned int len) {unsigned int i;
@@ -4337,6 +4654,15 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event ptr++; arg = arg->next;break ; + }else if (*(ptr+1 ) =='I' || *(ptr+1 ) =='i' ) { +int n; + + n =print_ip_arg (s, ptr+1 , data, size, event, arg); +if (n >0 ) { + ptr += n; + arg = arg->next; +break ; + } }/* fall through */
Signature · 1 line
1.9.3 (Apple Git-50)
Em Thu, Dec 18, 2014 at 08:10:43AM -0700, David Ahern escreveu:
Quoted 11 lines
Adds helper for following kernel formats:
%pi4 print an IPv4 address with leading zeros %pI4 print an IPv4 address without leading zeros %pi6 print an IPv6 address without colons %pI6 print an IPv6 address with colons %pI6c print an IPv6 address with colons %pISpc print an IP address from a sockaddrAllows these formats to be used in tracepoints.
Quite a bit of this is adapted from code in
lib/vsprintf.c.
Can't we try as much as possible use that code directly? Something like we do for lib/rbtree.c in tools/perf/, or like I did recently with tools/lib/util/find_next_bit.c, i.e. retain at least this kind of sharing:
diff -u tools/lib/util/find_next_bit.c lib/find_next_bit.c
Should show that only bits that we have not a need at the moment in tools/ were left behind.
We want to either get fixes for free by directly reusing or notice it easily, using diff.
- Arnaldo
Quoted 365 lines
v2:
- pass ptr+1 toprint_ip_argper Namhyung's comments
- added field length checks to sockaddr functionSigned-off-by David Ahern <[email protected]>Cc Namhyung Kim <[email protected]>Cc Jiri Olsa <[email protected]>Cc Steven Rostedt <[email protected]>--- tools/lib/traceevent/event-parse.c | 326 +++++++++++++++++++++++++++++++++++++ 1 file changed, 326 insertions(+)tools/lib/traceevent/event-parse.c +326
-0@@ -32,6 +32,7 @@#include <stdint.h> #include <limits.h> +#include <netinet/ip6.h> #include "event-parse.h" #include "event-utils.h" @@ -4149,6 +4150,322 @@ static void print_mac_arg(struct trace_seq *s, int mac, void *data, int size,trace_seq_printf (s, fmt, buf[0 ], buf[1 ], buf[2 ], buf[3 ], buf[4 ], buf[5 ]); } +static void print_ip4_addr (struct trace_seq *s,char i,unsigned char *buf) +{ +const char *fmt; + +if (i =='i' ) + fmt ="%03d.%03d.%03d.%03d" ; +else + fmt ="%d.%d.%d.%d" ; + +trace_seq_printf (s, fmt, buf[0 ], buf[1 ], buf[2 ], buf[3 ]); +} + +static inline bool ipv6_addr_v4mapped (const struct in6_addr *a) +{ +return ((unsigned long )(a->s6_addr32[0 ] | a->s6_addr32[1 ]) | + (unsigned long )(a->s6_addr32[2 ] ^htonl (0x0000ffff ))) ==0UL ; +} + +static inline bool ipv6_addr_is_isatap (const struct in6_addr *addr) +{ +return (addr->s6_addr32[2 ] |htonl (0x02000000 )) ==htonl (0x02005EFE ); +} + +static void print_ip6c_addr (struct trace_seq *s,unsigned char *addr) +{ +int i, j, range; +unsigned char zerolength[8 ]; +int longest =1 ; +int colonpos =-1 ; +uint16_t word; +uint8_t hi, lo; +bool needcolon = false; +bool useIPv4; +struct in6_addr in6; + +memcpy (&in6, addr,sizeof (struct in6_addr )); + + useIPv4 =ipv6_addr_v4mapped (&in6) ||ipv6_addr_is_isatap (&in6); + +memset (zerolength,0 ,sizeof (zerolength)); + +if (useIPv4) + range =6 ; +else + range =8 ; + +/* find position of longest 0 run */ +for (i =0 ; i < range; i++) { +for (j = i; j < range; j++) { +if (in6.s6_addr16[j] !=0 ) +break ; + zerolength[i]++; + } + } +for (i =0 ; i < range; i++) { +if (zerolength[i] > longest) { + longest = zerolength[i]; + colonpos = i; + } + } +if (longest ==1 )/* don't compress a single 0 */ + colonpos =-1 ; + +/* emit address */ +for (i =0 ; i < range; i++) { +if (i == colonpos) { +if (needcolon || i ==0 ) +trace_seq_printf (s,":" ); +trace_seq_printf (s,":" ); + needcolon = false; + i += longest -1 ; +continue ; + } +if (needcolon) { +trace_seq_printf (s,":" ); + needcolon = false; + } +/* hex u16 without leading 0s */ + word =ntohs (in6.s6_addr16[i]); + hi = word >>8 ; + lo = word &0xff ; +if (hi) +trace_seq_printf (s,"%x%02x" , hi, lo); +else +trace_seq_printf (s,"%x" , lo); + + needcolon = true; + } + +if (useIPv4) { +if (needcolon) +trace_seq_printf (s,":" ); +print_ip4_addr (s,'I' , &in6.s6_addr[12 ]); + } + +return ; +} + +static void print_ip6_addr (struct trace_seq *s,char i,unsigned char *buf) +{ +int j; + +for (j =0 ; j <16 ; j +=2 ) { +trace_seq_printf (s,"%02x%02x" , buf[j], buf[j+1 ]); +if (i =='I' && j <14 ) +trace_seq_printf (s,":" ); + } +} + +/* +* %pi4 print an IPv4 address with leading zeros +* %pI4 print an IPv4 address without leading zeros +* %pi6 print an IPv6 address without colons +* %pI6 print an IPv6 address with colons +* %pI6c print an IPv6 address in compressed form with colons +* %pISpc print an IP address based on sockaddr; p adds port. +*/ +static int print_ipv4_arg (struct trace_seq *s,const char *ptr,char i, +void *data,int size,struct event_format *event, +struct print_arg *arg) +{ +unsigned char *buf; + +if (arg->type ==PRINT_FUNC ) { +process_defined_func (s, data, size, event, arg); +return 0 ; + } + +if (arg->type !=PRINT_FIELD ) { +trace_seq_printf (s,"ARG TYPE NOT FIELD BUT %d" , arg->type); +return 0 ; + } + +if (!arg->field.field) { + arg->field.field = +pevent_find_any_field (event, arg->field.name); +if (!arg->field.field) { +do_warning ("%s: field %s not found" , + __func__, arg->field.name); +return 0 ; + } + } + + buf = data + arg->field.field->offset; + +if (arg->field.field->size !=4 ) { +trace_seq_printf (s,"INVALIDIPv4" ); +return 0 ; + } +print_ip4_addr (s, i, buf); + +return 0 ; +} + +static int print_ipv6_arg (struct trace_seq *s,const char *ptr,char i, +void *data,int size,struct event_format *event, +struct print_arg *arg) +{ +char have_c =0 ; +unsigned char *buf; +int rc =0 ; + +/* pI6c */ +if (*ptr =='c' ) { + have_c =1 ; + ptr++; + rc++; + } + +if (arg->type ==PRINT_FUNC ) { +process_defined_func (s, data, size, event, arg); +return rc; + } + +if (arg->type !=PRINT_FIELD ) { +trace_seq_printf (s,"ARG TYPE NOT FIELD BUT %d" , arg->type); +return rc; + } + +if (!arg->field.field) { + arg->field.field = +pevent_find_any_field (event, arg->field.name); +if (!arg->field.field) { +do_warning ("%s: field %s not found" , + __func__, arg->field.name); +return rc; + } + } + + buf = data + arg->field.field->offset; + +if (arg->field.field->size !=16 ) { +trace_seq_printf (s,"INVALIDIPv6" ); +return rc; + } + +if (have_c) +print_ip6c_addr (s, buf); +else +print_ip6_addr (s, i, buf); + +return rc; +} + +static int print_ipsa_arg (struct trace_seq *s,const char *ptr,char i, +void *data,int size,struct event_format *event, +struct print_arg *arg) +{ +char have_c =0 , have_p =0 ; +unsigned char *buf; +struct sockaddr_storage *sa; +int rc =0 ; + +/* pISpc */ +if (*ptr =='p' ) { + have_p =1 ; + ptr++; + rc++; + } +if (*ptr =='c' ) { + have_c =1 ; + ptr++; + rc++; + } + +if (arg->type ==PRINT_FUNC ) { +process_defined_func (s, data, size, event, arg); +return rc; + } + +if (arg->type !=PRINT_FIELD ) { +trace_seq_printf (s,"ARG TYPE NOT FIELD BUT %d" , arg->type); +return rc; + } + +if (!arg->field.field) { + arg->field.field = +pevent_find_any_field (event, arg->field.name); +if (!arg->field.field) { +do_warning ("%s: field %s not found" , + __func__, arg->field.name); +return rc; + } + } + + sa = (struct sockaddr_storage *) (data + arg->field.field->offset); + +if (sa->ss_family ==AF_INET ) { +struct sockaddr_in *sa4 = (struct sockaddr_in *) sa; + +if (arg->field.field->size <sizeof (struct sockaddr_in )) { +trace_seq_printf (s,"INVALIDIPv4" ); +return rc; + } + +print_ip4_addr (s, i, (unsigned char *) &sa4->sin_addr); +if (have_p) +trace_seq_printf (s,":%d" ,ntohs (sa4->sin_port)); + + + }else if (sa->ss_family ==AF_INET6 ) { +struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) sa; + +if (arg->field.field->size <sizeof (struct sockaddr_in6 )) { +trace_seq_printf (s,"INVALIDIPv6" ); +return rc; + } + +if (have_p) +trace_seq_printf (s,"[" ); + + buf = (unsigned char *) &sa6->sin6_addr; +if (have_c) +print_ip6c_addr (s, buf); +else +print_ip6_addr (s, i, buf); + +if (have_p) +trace_seq_printf (s,"]:%d" ,ntohs (sa6->sin6_port)); + } + +return rc; +} + +static int print_ip_arg (struct trace_seq *s,const char *ptr, +void *data,int size,struct event_format *event, +struct print_arg *arg) +{ +char i = *ptr;/* 'i' or 'I' */ +char ver; +int rc =0 ; + + ptr++; + rc++; + + ver = *ptr; + ptr++; + rc++; + +switch (ver) { +case '4' : + rc +=print_ipv4_arg (s, ptr, i, data, size, event, arg); +break ; +case '6' : + rc +=print_ipv6_arg (s, ptr, i, data, size, event, arg); +break ; +case 'S' : + rc +=print_ipsa_arg (s, ptr, i, data, size, event, arg); +break ; +default : +return 0 ; + } + +return rc; +} +static int is_printable_array (char *p,unsigned int len) {unsigned int i;@@ -4337,6 +4654,15 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event ptr++; arg = arg->next;break ; + }else if (*(ptr+1 ) =='I' || *(ptr+1 ) =='i' ) { +int n; + + n =print_ip_arg (s, ptr+1 , data, size, event, arg); +if (n >0 ) { + ptr += n; + arg = arg->next; +break ; + } }/* fall through */ Signature · 1 line
1.9.3 (Apple Git-50)
Quoted 9 lines · Arnaldo Carvalho de Melo
Em Thu, Dec 18, 2014 at 08:10:43AM -0700, David Ahern escreveu:
Quoted 8 lines
Adds helper for following kernel formats:
%pi4 print an IPv4 address with leading zeros %pI4 print an IPv4 address without leading zeros %pi6 print an IPv6 address without colons %pI6 print an IPv6 address with colons %pI6c print an IPv6 address with colons %pISpc print an IP address from a sockaddr
Quoted 5 lines
Quoted 3 lines
Allows these formats to be used in tracepoints.
Quite a bit of this is adapted from code in
lib/vsprintf.c.Can't we try as much as possible use that code directly? Something like
By my reading of that file I don't see how it can be reused directly.
David
Steven Rostedt
maintainerQuoted 9 lines · On Thu, 18 Dec 2014 12:52:55 -0300 Arnaldo Carvalho de Melo <[email protected]>…
Em Thu, Dec 18, 2014 at 08:10:43AM -0700, David Ahern escreveu:
Quoted 8 lines
Adds helper for following kernel formats:
%pi4 print an IPv4 address with leading zeros %pI4 print an IPv4 address without leading zeros %pi6 print an IPv6 address without colons %pI6 print an IPv6 address with colons %pI6c print an IPv6 address with colons %pISpc print an IP address from a sockaddr
Quoted 5 lines
Quoted 3 lines
Allows these formats to be used in tracepoints.
Quite a bit of this is adapted from code in
lib/vsprintf.c.Can't we try as much as possible use that code directly? Something like
Until we have a true shared library, please no. I'm still taking code from here and adding it manually to trace-cmd. And also sending patches to here from what I add to trace-cmd.
I do not want this directly linked to the kernel code. Note, the kernel internals have no guaranteed API, where this does.
Quoted 5 lines
we do for
lib/rbtree.cintools/perf/, or like I did recently withtools/lib/util/find_next_bit.c, i.e. retain at least this kind of sharing:diff -u
tools/lib/util/find_next_bit.clib/find_next_bit.c
Unless we convert code to trace_seq, I don't think this works. My patches to move seq_buf.c int lib/ have made it into the kernel. Perhaps we can copy the seq_buf.c code into tools/lib/traceevent, but that would take some work.
-- Steve
Quoted 7 lines
Should show that only bits that we have not a need at the moment in
tools/were left behind.We want to either get fixes for free by directly reusing or notice it easily, using diff.
Em Thu, Dec 18, 2014 at 11:27:15AM -0500, Steven Rostedt escreveu:
Quoted 16 lines
Quoted 12 lines · On Thu, 18 Dec 2014 12:52:55 -0300 Arnaldo Carvalho de Melo <[email protected]>…
Em Thu, Dec 18, 2014 at 08:10:43AM -0700, David Ahern escreveu:
Quoted 11 lines
Adds helper for following kernel formats:
%pi4 print an IPv4 address with leading zeros %pI4 print an IPv4 address without leading zeros %pi6 print an IPv6 address without colons %pI6 print an IPv6 address with colons %pI6c print an IPv6 address with colons %pISpc print an IP address from a sockaddrAllows these formats to be used in tracepoints.
Quite a bit of this is adapted from code in
lib/vsprintf.c.
Quoted 8 lines
Quoted 1 line
Can't we try as much as possible use that code directly? Something like
Until we have a true shared library, please no. I'm still taking code from here and adding it manually to trace-cmd. And also sending patches to here from what I add to trace-cmd.
I do not want this directly linked to the kernel code. Note, the kernel internals have no guaranteed API, where this does.
If using it directly is frowned upon, at least try to reduce the differences when copying code, be it by keeping function ordering in the source code, using the same file name and generally making it easier to see if changes ocurred on the original file over time.
Quoted 10 lines
Quoted 5 lines
we do for
lib/rbtree.cintools/perf/, or like I did recently withtools/lib/util/find_next_bit.c, i.e. retain at least this kind of sharing:diff -u
tools/lib/util/find_next_bit.clib/find_next_bit.cUnless we convert code to
trace_seq, I don't think this works. My patches to moveseq_buf.cintlib/have made it into the kernel. Perhaps we can copy theseq_buf.ccode intotools/lib/traceevent, but that would take some work.
Well, I thought that what that code was doing was just taking a string, looking for some specific %LETTER stuff, acting on it and returning the formatted result, i.e. a vsprintf function, thus I ended up shortcutting too fast to the conclusion that it was possible, my bad :-)
If take the time to look at the specifics I'll propose something more concrete, meanwhile, are you ok with David's changes? May I process his patch?
- Arnaldo
Quoted 3 lines · Arnaldo Carvalho de Melo
If take the time to look at the specifics I'll propose something more concrete, meanwhile, are you ok with David's changes? May I process his patch?
I need a v3 to respond to oversights noted responding to Valdis. Any other comments before I send a v3?
David
Quoted 7 lines · David Ahern
Adds helper for following kernel formats:
%pi4 print an IPv4 address with leading zeros %pI4 print an IPv4 address without leading zeros %pi6 print an IPv6 address without colons %pI6 print an IPv6 address with colons %pI6c print an IPv6 address with colons %pISpc print an IP address from a sockaddr
The description for %pI6C in the changelog doesn't match the code:
Quoted 1 line
+ * %pI6c print an IPv6 address in compressed form with colons
Threw me for a loop for a while trying to figure out how pI6 and pI6c were different, till I read the code...
Quoted 9 lines · On 12/18/14 2:45 PM, [email protected] wrote:
Quoted 7 lines · David Ahern
Adds helper for following kernel formats:
%pi4 print an IPv4 address with leading zeros %pI4 print an IPv4 address without leading zeros %pi6 print an IPv6 address without colons %pI6 print an IPv6 address with colons %pI6c print an IPv6 address with colons %pISpc print an IP address from a sockaddr
Quoted 7 lines
The description for %pI6C in the changelog doesn't match the code:
Quoted 1 line
+ * %pI6c print an IPv6 address in compressed form with colons
Threw me for a loop for a while trying to figure out how pI6 and pI6c were different, till I read the code...
Per Documentation/printk-formats.txt:
%pI6 0001:0002:0003:0004:0005:0006:0007:0008 %pi6 00010002000300040005000600070008 %pI6c 1:2:3:4:5:6:7:8
For printing IPv6 network-order 16-bit hex addresses. The 'I6' and 'i6' specifiers result in a printed address with ('I6') or without ('i6') colon-separators. Leading zeros are always used.
The additional 'c' specifier can be used with the 'I' specifier to print a compressed IPv6 address as described by
http://tools.ietf.org/html/rfc5952
I do see two mistakes in my patch -- use of 'c' and 'S' requires 'I'. After that the code that prints pI6c is a slightly modified version of what is in lib/vsprintf.c so the output between in-kernel tracing (cat trace_pipe) should match perf-script output. Compare ip6_compressed_string() in lib/vsprintf.c to print_ip6c_addr() in this patch.
Are you seeing something different?
David
Quoted 1 line · David Ahern
Are you seeing something different?
I put a tracepoint in the ipv4/ipv6 add/del address code. The IPv4 one prints the address using pi4 and pI4 and the IPv6 using pi6, pI6 and pI6c.
Using ifconfig eth1 1.2.3.4/24
I get this for trace_pipe which uses the in-kernel printf code:
root@localhost:/sys/kernel/debug/tracing/events# cat ../trace_pipe
ifconfig-601 [000] .... 710.660611: ipv4_del_addr:
pI4=1.2.3.4 pi4=001.002.003.004
ifconfig-602 [000] .... 720.833559: ipv4_add_addr:
pI4=1.2.3.4 pi4=001.002.003.004
ifconfig-602 [000] .Ns. 720.833966: ipv6_add_addr:
pi6=fe80000000000000000202fffe020211 pI6=fe80:0000:0000:0000:0002:02ff:fe02:0211 pI6c=fe80::2:2ff:fe02:211
ifconfig-602 [000] .... 720.835413: ipv4_del_addr:
pI4=1.2.3.4 pi4=001.002.003.004
ifconfig-602 [000] .N.. 720.835451: ipv4_add_addr:
pI4=1.2.3.4 pi4=001.002.003.004And this using perf:
root@localhost:~# perf record -a -e ipv4:* -e ipv6:* --no-buffering | perf --no-pager script
ifconfig 601 [000] 710.912862: ipv4:ipv4_del_addr:
pI4=1.2.3.4 pi4=001.002.003.004
ifconfig 602 [000] 721.090776: ipv4:ipv4_add_addr:
pI4=1.2.3.4 pi4=001.002.003.004
ifconfig 602 [000] 721.091177: ipv6:ipv6_add_addr:
pi6=fe80000000000000000202fffe020211 pI6=fe80:0000:0000:0000:0002:02ff:fe02:0211 pI6c=fe80::2:2ff:fe02:211
ifconfig 602 [000] 721.092626: ipv4:ipv4_del_addr:
pI4=1.2.3.4 pi4=001.002.003.004
ifconfig 602 [000] 721.092648: ipv4:ipv4_add_addr: pI4=1.2.3.4 pi4=001.002.003.004
(Don't be fooled by the differing timestamps; data collected from both using the same exact command. timestamp differences are perf vs tracing.)
which suggest with the patch perf output matches tracing.
David
Quoted 5 lines · David Ahern
Quoted 1 line · David Ahern
Are you seeing something different?
I put a tracepoint in the ipv4/ipv6 add/del address code. The IPv4 one prints the address using pi4 and pI4 and the IPv6 using pi6, pI6 and pI6c.
apart from your tracepoints, is there another tracepoint using this? I couldn't find any.. I dont think it's a problem.. just wanted to try it ;-)
thanks,
jirka
Quoted 42 lines
Using ifconfig eth1 1.2.3.4/24
I get this for
trace_pipewhich uses the in-kernel printf code:root@localhost:/sys/kernel/debug/tracing/events# cat ../trace_pipe ifconfig-601 [000] .... 710.660611: ipv4_del_addr: pI4=1.2.3.4 pi4=001.002.003.004 ifconfig-602 [000] .... 720.833559: ipv4_add_addr: pI4=1.2.3.4 pi4=001.002.003.004 ifconfig-602 [000] .Ns. 720.833966: ipv6_add_addr: pi6=fe80000000000000000202fffe020211 pI6=fe80:0000:0000:0000:0002:02ff:fe02:0211 pI6c=fe80::2:2ff:fe02:211 ifconfig-602 [000] .... 720.835413: ipv4_del_addr: pI4=1.2.3.4 pi4=001.002.003.004 ifconfig-602 [000] .N.. 720.835451: ipv4_add_addr: pI4=1.2.3.4 pi4=001.002.003.004And this using perf:
root@localhost:~# perf record -a -e ipv4:* -e ipv6:* --no-buffering | perf --no-pager scriptifconfig 601 [000] 710.912862: ipv4:ipv4_del_addr: pI4=1.2.3.4 pi4=001.002.003.004 ifconfig 602 [000] 721.090776: ipv4:ipv4_add_addr: pI4=1.2.3.4 pi4=001.002.003.004 ifconfig 602 [000] 721.091177: ipv6:ipv6_add_addr: pi6=fe80000000000000000202fffe020211 pI6=fe80:0000:0000:0000:0002:02ff:fe02:0211 pI6c=fe80::2:2ff:fe02:211 ifconfig 602 [000] 721.092626: ipv4:ipv4_del_addr: pI4=1.2.3.4 pi4=001.002.003.004 ifconfig 602 [000] 721.092648: ipv4:ipv4_add_addr: pI4=1.2.3.4pi4=001.002.003.004
(Don't be fooled by the differing timestamps; data collected from both using the same exact command. timestamp differences are perf vs tracing.)
which suggest with the patch perf output matches tracing.
David
Quoted 3 lines · Jiri Olsa
apart from your tracepoints, is there another tracepoint using this? I couldn't find any.. I dont think it's a problem.. just wanted to try it;-)
grrr... i was hoping no one would ask that question. I am not aware of any in tree. We use it locally in custom tracepoints in the networking stack (from what I can tell netdev will not take -- LTTng tried many years ago) and in a couple of klms.
The attached patch is what I used to test (plus our local versions). It is derived from a patch on the 3.4 kernel which allows us to trace address changes.
David
Quoted 1 line
From
bedfad82a159226f06a8035f6a7622fce6df7a0aMon Sep 17 00:00:00 2001
From: David Ahern <[email protected]>
Date: Thu, 18 Dec 2014 19:03:28 -0700
Subject: [PATCH 2/2] tracepoints to test IP address format output
--- include/trace/events/ipv4.h | 42 ++++++++++++++++++++++++++++++++++++++++++ include/trace/events/ipv6.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ net/core/net-traces.c | 2 ++ net/ipv4/devinet.c | 4 ++++ net/ipv6/addrconf.c | 4 ++++ 5 files changed, 96 insertions(+) create mode 100644 include/trace/events/ipv4.h create mode 100644 include/trace/events/ipv6.h
include/trace/events/ipv4.h new file +42 -0
@@ -0,0 +1,42 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM ipv4 + +#if !defined(_TRACE_EVENTS_IPV4_H) || defined(TRACE_HEADER_MULTI_READ ) +#define _TRACE_EVENTS_IPV4_H + +#include <linux/inetdevice.h> +#include <linux/tracepoint.h> + +DECLARE_EVENT_CLASS (ipv4_addr_template, + + TP_PROTO(struct in_ifaddr *ifa, + struct in_device *in_dev), + +TP_ARGS (ifa, in_dev), + +TP_STRUCT__entry ( +__array (__u8, addr,4 ) + ), + +TP_fast_assign ( + memcpy(&__entry->addr, &ifa->ifa_address, 4); + ), + +TP_printk ("pI4=%pI4 pi4=%pi4" , + __entry->addr, __entry->addr) +); + +DEFINE_EVENT (ipv4_addr_template, ipv4_add_addr, + TP_PROTO(struct in_ifaddr *ifa, struct in_device *in_dev), +TP_ARGS (ifa, in_dev) +); + +DEFINE_EVENT (ipv4_addr_template, ipv4_del_addr, + TP_PROTO(struct in_ifaddr *ifa, struct in_device *in_dev), +TP_ARGS (ifa, in_dev) +); + +#endif /* _TRACE_EVENTS_IPV4_H */ + +/* This part must be outside protection */ +#include <trace/define_trace.h>
include/trace/events/ipv6.h new file +44 -0
44 lines not on this page · raw message
net/core/net-traces.c +2 -0
@@ -31,6 +31,8 @@#include <trace/events/napi.h> #include <trace/events/sock.h> #include <trace/events/udp.h> +#include <trace/events/ipv4.h> +#include <trace/events/ipv6.h> EXPORT_TRACEPOINT_SYMBOL_GPL (kfree_skb);
net/ipv4/devinet.c +4 -0
@@ -64,6 +64,7 @@#include <net/rtnetlink.h> #include <net/net_namespace.h> #include <net/addrconf.h> +#include <trace/events/ipv4.h> #include "fib_lookup.h"
@@ -358,6 +359,7 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,inet_hash_remove (ifa); *ifap1 = ifa->ifa_next; +trace_ipv4_del_addr (ifa, in_dev);rtmsg_ifa (RTM_DELADDR , ifa, nlh, portid);blocking_notifier_call_chain (&inetaddr_chain,NETDEV_DOWN , ifa);
@@ -395,6 +397,7 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,is valid, it will try to restore deleted routes... Grr. So that, this order is correct. */ +trace_ipv4_del_addr (ifa1, in_dev);rtmsg_ifa (RTM_DELADDR , ifa1, nlh, portid);blocking_notifier_call_chain (&inetaddr_chain,NETDEV_DOWN , ifa1);
@@ -476,6 +479,7 @@ static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh, ifa->ifa_next = *ifap; *ifap = ifa; +trace_ipv4_add_addr (ifa, in_dev);inet_hash_insert (dev_net (in_dev->dev), ifa);cancel_delayed_work (&check_lifetime_work);
net/ipv6/addrconf.c +4 -0
@@ -90,6 +90,7 @@#include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/export.h> +#include <trace/events/ipv6.h> /* Set to 3 to get tracing... */ #define ACONF_DEBUG 2
@@ -874,6 +875,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr,in6_dev_hold (idev);/* For caller */ in6_ifa_hold (ifa); +trace_ipv6_add_addr (ifa);/* Add to big hash table */ hash =inet6_addr_hash (addr);
@@ -1658,8 +1660,10 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed) }else {spin_unlock_bh (&ifp->lock); } +trace_ipv6_del_addr (ifp);ipv6_del_addr (ifp); }else { +trace_ipv6_del_addr (ifp);ipv6_del_addr (ifp); } }
Signature · 1 line
1.9.3 (Apple Git-50)
Quoted 9 lines · David Ahern
Quoted 3 lines · Jiri Olsa
apart from your tracepoints, is there another tracepoint using this? I couldn't find any.. I dont think it's a problem.. just wanted to try it;-)
grrr... i was hoping no one would ask that question. I am not aware of any in tree. We use it locally in custom tracepoints in the networking stack (from what I can tell netdev will not take -- LTTng tried many years ago) and in a couple of klms.
hehe ;-) as I said I dont think this is a problem, as people can add their own tracepoints (like you did) with print fmt allowing anything that could go into printk..
Quoted 4 lines
The attached patch is what I used to test (plus our local versions). It is derived from a patch on the 3.4 kernel which allows us to trace address changes.
thanks,
jirka
Quoted 200 lines
David
From
bedfad82a159226f06a8035f6a7622fce6df7a0aMon Sep 17 00:00:00 2001
From: David Ahern <[email protected]>
Date: Thu, 18 Dec 2014 19:03:28 -0700
Subject: [PATCH 2/2] tracepoints to test IP address format outputSigned-off-by David Ahern <[email protected]>--- include/trace/events/ipv4.h | 42 ++++++++++++++++++++++++++++++++++++++++++ include/trace/events/ipv6.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ net/core/net-traces.c | 2 ++ net/ipv4/devinet.c | 4 ++++ net/ipv6/addrconf.c | 4 ++++ 5 files changed, 96 insertions(+) create mode 100644 include/trace/events/ipv4.h create mode 100644 include/trace/events/ipv6.hinclude/trace/events/ipv4.h new file +42
-0@@ -0,0 +1,42 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM ipv4 + +#if !defined(_TRACE_EVENTS_IPV4_H) || defined(TRACE_HEADER_MULTI_READ ) +#define _TRACE_EVENTS_IPV4_H + +#include <linux/inetdevice.h> +#include <linux/tracepoint.h> + +DECLARE_EVENT_CLASS (ipv4_addr_template, + + TP_PROTO(struct in_ifaddr *ifa, + struct in_device *in_dev), + +TP_ARGS (ifa, in_dev), + +TP_STRUCT__entry ( +__array (__u8, addr,4 ) + ), + +TP_fast_assign ( + memcpy(&__entry->addr, &ifa->ifa_address, 4); + ), + +TP_printk ("pI4=%pI4 pi4=%pi4" , + __entry->addr, __entry->addr) +); + +DEFINE_EVENT (ipv4_addr_template, ipv4_add_addr, + TP_PROTO(struct in_ifaddr *ifa, struct in_device *in_dev), +TP_ARGS (ifa, in_dev) +); + +DEFINE_EVENT (ipv4_addr_template, ipv4_del_addr, + TP_PROTO(struct in_ifaddr *ifa, struct in_device *in_dev), +TP_ARGS (ifa, in_dev) +); + +#endif /* _TRACE_EVENTS_IPV4_H */ + +/* This part must be outside protection */ +#include <trace/define_trace.h> include/trace/events/ipv6.h new file +44
-0@@ -0,0 +1,44 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM ipv6 + +#if !defined(_TRACE_EVENTS_IPV6_H) || defined(TRACE_HEADER_MULTI_READ ) +#define _TRACE_EVENTS_IPV6_H + +#include <net/if_inet6.h> +#include <linux/tracepoint.h> + +DECLARE_EVENT_CLASS (ipv6_addr_template, + + TP_PROTO(struct inet6_ifaddr *ifa), + +TP_ARGS (ifa), + +TP_STRUCT__entry ( +__array (__u8, addr, (int )sizeof (struct in6_addr )) + ), + +TP_fast_assign ( + memcpy(&__entry->addr, &ifa->addr, (int)sizeof(struct in6_addr)); + ), + +TP_printk ("pi6=%pi6 pI6=%pI6 pI6c=%pI6c" , + __entry->addr, __entry->addr, __entry->addr) +); + +DEFINE_EVENT (ipv6_addr_template, ipv6_add_addr, + + TP_PROTO(struct inet6_ifaddr *ifa), + +TP_ARGS (ifa) +); +DEFINE_EVENT (ipv6_addr_template, ipv6_del_addr, + + TP_PROTO(struct inet6_ifaddr *ifa), + +TP_ARGS (ifa) +); + +#endif /* _TRACE_EVENTS_IPV6_H */ + +/* This part must be outside protection */ +#include <trace/define_trace.h> net/core/net-traces.c +2
-0@@ -31,6 +31,8 @@#include <trace/events/napi.h> #include <trace/events/sock.h> #include <trace/events/udp.h> +#include <trace/events/ipv4.h> +#include <trace/events/ipv6.h> EXPORT_TRACEPOINT_SYMBOL_GPL (kfree_skb);net/ipv4/devinet.c +4
-0@@ -64,6 +64,7 @@#include <net/rtnetlink.h> #include <net/net_namespace.h> #include <net/addrconf.h> +#include <trace/events/ipv4.h> #include "fib_lookup.h" @@ -358,6 +359,7 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,inet_hash_remove (ifa); *ifap1 = ifa->ifa_next; +trace_ipv4_del_addr (ifa, in_dev);rtmsg_ifa (RTM_DELADDR , ifa, nlh, portid);blocking_notifier_call_chain (&inetaddr_chain,NETDEV_DOWN , ifa);@@ -395,6 +397,7 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,is valid, it will try to restore deleted routes... Grr. So that, this order is correct. */ +trace_ipv4_del_addr (ifa1, in_dev);rtmsg_ifa (RTM_DELADDR , ifa1, nlh, portid);blocking_notifier_call_chain (&inetaddr_chain,NETDEV_DOWN , ifa1);@@ -476,6 +479,7 @@ static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh, ifa->ifa_next = *ifap; *ifap = ifa; +trace_ipv4_add_addr (ifa, in_dev);inet_hash_insert (dev_net (in_dev->dev), ifa);cancel_delayed_work (&check_lifetime_work);net/ipv6/addrconf.c +4
-0@@ -90,6 +90,7 @@#include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/export.h> +#include <trace/events/ipv6.h> /* Set to 3 to get tracing... */ #define ACONF_DEBUG 2@@ -874,6 +875,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr,in6_dev_hold (idev);/* For caller */ in6_ifa_hold (ifa); +trace_ipv6_add_addr (ifa);/* Add to big hash table */ hash =inet6_addr_hash (addr);@@ -1658,8 +1660,10 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed) }else {spin_unlock_bh (&ifp->lock); } +trace_ipv6_del_addr (ifp);ipv6_del_addr (ifp); }else { +trace_ipv6_del_addr (ifp);ipv6_del_addr (ifp); } }Signature · 1 line
1.9.3 (Apple Git-50)