aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorDavid Ahern <dsahern@gmail.com>2014-12-18 21:11:11 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2015-01-26 10:04:41 -0500
commit3d199b5be53348bef84883013c484b414adf0a2e (patch)
treed28981b8121f3415ec0f4ff61925433a2d756904 /tools
parent4397bd2f90459d550deca7f6ba32c12e382d8b57 (diff)
tools lib traceevent: Add support for IP address formats
Add helpers for the 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 in compressed form 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. v4: - fixed pI6c description in git commit message per Valdis' comment v3: - use of 'c' and 'p' requires 'I' v2: - pass ptr+1 to print_ip_arg per Namhyung's comments - added field length checks to sockaddr function Signed-off-by: David Ahern <dsahern@gmail.com> Acked-by: Steven Rostedt <rostedt@goodmis.org> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Namhyung Kim <namhyung@kernel.org> Link: http://lkml.kernel.org/r/1418955071-36241-1-git-send-email-dsahern@gmail.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/lib/traceevent/event-parse.c328
1 files changed, 328 insertions, 0 deletions
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c
index cf3a44bf1ec3..afe20ed9fac8 100644
--- a/tools/lib/traceevent/event-parse.c
+++ b/tools/lib/traceevent/event-parse.c
@@ -32,6 +32,7 @@
32#include <stdint.h> 32#include <stdint.h>
33#include <limits.h> 33#include <limits.h>
34 34
35#include <netinet/ip6.h>
35#include "event-parse.h" 36#include "event-parse.h"
36#include "event-utils.h" 37#include "event-utils.h"
37 38
@@ -4149,6 +4150,324 @@ static void print_mac_arg(struct trace_seq *s, int mac, void *data, int size,
4149 trace_seq_printf(s, fmt, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); 4150 trace_seq_printf(s, fmt, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
4150} 4151}
4151 4152
4153static void print_ip4_addr(struct trace_seq *s, char i, unsigned char *buf)
4154{
4155 const char *fmt;
4156
4157 if (i == 'i')
4158 fmt = "%03d.%03d.%03d.%03d";
4159 else
4160 fmt = "%d.%d.%d.%d";
4161
4162 trace_seq_printf(s, fmt, buf[0], buf[1], buf[2], buf[3]);
4163}
4164
4165static inline bool ipv6_addr_v4mapped(const struct in6_addr *a)
4166{
4167 return ((unsigned long)(a->s6_addr32[0] | a->s6_addr32[1]) |
4168 (unsigned long)(a->s6_addr32[2] ^ htonl(0x0000ffff))) == 0UL;
4169}
4170
4171static inline bool ipv6_addr_is_isatap(const struct in6_addr *addr)
4172{
4173 return (addr->s6_addr32[2] | htonl(0x02000000)) == htonl(0x02005EFE);
4174}
4175
4176static void print_ip6c_addr(struct trace_seq *s, unsigned char *addr)
4177{
4178 int i, j, range;
4179 unsigned char zerolength[8];
4180 int longest = 1;
4181 int colonpos = -1;
4182 uint16_t word;
4183 uint8_t hi, lo;
4184 bool needcolon = false;
4185 bool useIPv4;
4186 struct in6_addr in6;
4187
4188 memcpy(&in6, addr, sizeof(struct in6_addr));
4189
4190 useIPv4 = ipv6_addr_v4mapped(&in6) || ipv6_addr_is_isatap(&in6);
4191
4192 memset(zerolength, 0, sizeof(zerolength));
4193
4194 if (useIPv4)
4195 range = 6;
4196 else
4197 range = 8;
4198
4199 /* find position of longest 0 run */
4200 for (i = 0; i < range; i++) {
4201 for (j = i; j < range; j++) {
4202 if (in6.s6_addr16[j] != 0)
4203 break;
4204 zerolength[i]++;
4205 }
4206 }
4207 for (i = 0; i < range; i++) {
4208 if (zerolength[i] > longest) {
4209 longest = zerolength[i];
4210 colonpos = i;
4211 }
4212 }
4213 if (longest == 1) /* don't compress a single 0 */
4214 colonpos = -1;
4215
4216 /* emit address */
4217 for (i = 0; i < range; i++) {
4218 if (i == colonpos) {
4219 if (needcolon || i == 0)
4220 trace_seq_printf(s, ":");
4221 trace_seq_printf(s, ":");
4222 needcolon = false;
4223 i += longest - 1;
4224 continue;
4225 }
4226 if (needcolon) {
4227 trace_seq_printf(s, ":");
4228 needcolon = false;
4229 }
4230 /* hex u16 without leading 0s */
4231 word = ntohs(in6.s6_addr16[i]);
4232 hi = word >> 8;
4233 lo = word & 0xff;
4234 if (hi)
4235 trace_seq_printf(s, "%x%02x", hi, lo);
4236 else
4237 trace_seq_printf(s, "%x", lo);
4238
4239 needcolon = true;
4240 }
4241
4242 if (useIPv4) {
4243 if (needcolon)
4244 trace_seq_printf(s, ":");
4245 print_ip4_addr(s, 'I', &in6.s6_addr[12]);
4246 }
4247
4248 return;
4249}
4250
4251static void print_ip6_addr(struct trace_seq *s, char i, unsigned char *buf)
4252{
4253 int j;
4254
4255 for (j = 0; j < 16; j += 2) {
4256 trace_seq_printf(s, "%02x%02x", buf[j], buf[j+1]);
4257 if (i == 'I' && j < 14)
4258 trace_seq_printf(s, ":");
4259 }
4260}
4261
4262/*
4263 * %pi4 print an IPv4 address with leading zeros
4264 * %pI4 print an IPv4 address without leading zeros
4265 * %pi6 print an IPv6 address without colons
4266 * %pI6 print an IPv6 address with colons
4267 * %pI6c print an IPv6 address in compressed form with colons
4268 * %pISpc print an IP address based on sockaddr; p adds port.
4269 */
4270static int print_ipv4_arg(struct trace_seq *s, const char *ptr, char i,
4271 void *data, int size, struct event_format *event,
4272 struct print_arg *arg)
4273{
4274 unsigned char *buf;
4275
4276 if (arg->type == PRINT_FUNC) {
4277 process_defined_func(s, data, size, event, arg);
4278 return 0;
4279 }
4280
4281 if (arg->type != PRINT_FIELD) {
4282 trace_seq_printf(s, "ARG TYPE NOT FIELD BUT %d", arg->type);
4283 return 0;
4284 }
4285
4286 if (!arg->field.field) {
4287 arg->field.field =
4288 pevent_find_any_field(event, arg->field.name);
4289 if (!arg->field.field) {
4290 do_warning("%s: field %s not found",
4291 __func__, arg->field.name);
4292 return 0;
4293 }
4294 }
4295
4296 buf = data + arg->field.field->offset;
4297
4298 if (arg->field.field->size != 4) {
4299 trace_seq_printf(s, "INVALIDIPv4");
4300 return 0;
4301 }
4302 print_ip4_addr(s, i, buf);
4303
4304 return 0;
4305}
4306
4307static int print_ipv6_arg(struct trace_seq *s, const char *ptr, char i,
4308 void *data, int size, struct event_format *event,
4309 struct print_arg *arg)
4310{
4311 char have_c = 0;
4312 unsigned char *buf;
4313 int rc = 0;
4314
4315 /* pI6c */
4316 if (i == 'I' && *ptr == 'c') {
4317 have_c = 1;
4318 ptr++;
4319 rc++;
4320 }
4321
4322 if (arg->type == PRINT_FUNC) {
4323 process_defined_func(s, data, size, event, arg);
4324 return rc;
4325 }
4326
4327 if (arg->type != PRINT_FIELD) {
4328 trace_seq_printf(s, "ARG TYPE NOT FIELD BUT %d", arg->type);
4329 return rc;
4330 }
4331
4332 if (!arg->field.field) {
4333 arg->field.field =
4334 pevent_find_any_field(event, arg->field.name);
4335 if (!arg->field.field) {
4336 do_warning("%s: field %s not found",
4337 __func__, arg->field.name);
4338 return rc;
4339 }
4340 }
4341
4342 buf = data + arg->field.field->offset;
4343
4344 if (arg->field.field->size != 16) {
4345 trace_seq_printf(s, "INVALIDIPv6");
4346 return rc;
4347 }
4348
4349 if (have_c)
4350 print_ip6c_addr(s, buf);
4351 else
4352 print_ip6_addr(s, i, buf);
4353
4354 return rc;
4355}
4356
4357static int print_ipsa_arg(struct trace_seq *s, const char *ptr, char i,
4358 void *data, int size, struct event_format *event,
4359 struct print_arg *arg)
4360{
4361 char have_c = 0, have_p = 0;
4362 unsigned char *buf;
4363 struct sockaddr_storage *sa;
4364 int rc = 0;
4365
4366 /* pISpc */
4367 if (i == 'I') {
4368 if (*ptr == 'p') {
4369 have_p = 1;
4370 ptr++;
4371 rc++;
4372 }
4373 if (*ptr == 'c') {
4374 have_c = 1;
4375 ptr++;
4376 rc++;
4377 }
4378 }
4379
4380 if (arg->type == PRINT_FUNC) {
4381 process_defined_func(s, data, size, event, arg);
4382 return rc;
4383 }
4384
4385 if (arg->type != PRINT_FIELD) {
4386 trace_seq_printf(s, "ARG TYPE NOT FIELD BUT %d", arg->type);
4387 return rc;
4388 }
4389
4390 if (!arg->field.field) {
4391 arg->field.field =
4392 pevent_find_any_field(event, arg->field.name);
4393 if (!arg->field.field) {
4394 do_warning("%s: field %s not found",
4395 __func__, arg->field.name);
4396 return rc;
4397 }
4398 }
4399
4400 sa = (struct sockaddr_storage *) (data + arg->field.field->offset);
4401
4402 if (sa->ss_family == AF_INET) {
4403 struct sockaddr_in *sa4 = (struct sockaddr_in *) sa;
4404
4405 if (arg->field.field->size < sizeof(struct sockaddr_in)) {
4406 trace_seq_printf(s, "INVALIDIPv4");
4407 return rc;
4408 }
4409
4410 print_ip4_addr(s, i, (unsigned char *) &sa4->sin_addr);
4411 if (have_p)
4412 trace_seq_printf(s, ":%d", ntohs(sa4->sin_port));
4413
4414
4415 } else if (sa->ss_family == AF_INET6) {
4416 struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) sa;
4417
4418 if (arg->field.field->size < sizeof(struct sockaddr_in6)) {
4419 trace_seq_printf(s, "INVALIDIPv6");
4420 return rc;
4421 }
4422
4423 if (have_p)
4424 trace_seq_printf(s, "[");
4425
4426 buf = (unsigned char *) &sa6->sin6_addr;
4427 if (have_c)
4428 print_ip6c_addr(s, buf);
4429 else
4430 print_ip6_addr(s, i, buf);
4431
4432 if (have_p)
4433 trace_seq_printf(s, "]:%d", ntohs(sa6->sin6_port));
4434 }
4435
4436 return rc;
4437}
4438
4439static int print_ip_arg(struct trace_seq *s, const char *ptr,
4440 void *data, int size, struct event_format *event,
4441 struct print_arg *arg)
4442{
4443 char i = *ptr; /* 'i' or 'I' */
4444 char ver;
4445 int rc = 0;
4446
4447 ptr++;
4448 rc++;
4449
4450 ver = *ptr;
4451 ptr++;
4452 rc++;
4453
4454 switch (ver) {
4455 case '4':
4456 rc += print_ipv4_arg(s, ptr, i, data, size, event, arg);
4457 break;
4458 case '6':
4459 rc += print_ipv6_arg(s, ptr, i, data, size, event, arg);
4460 break;
4461 case 'S':
4462 rc += print_ipsa_arg(s, ptr, i, data, size, event, arg);
4463 break;
4464 default:
4465 return 0;
4466 }
4467
4468 return rc;
4469}
4470
4152static int is_printable_array(char *p, unsigned int len) 4471static int is_printable_array(char *p, unsigned int len)
4153{ 4472{
4154 unsigned int i; 4473 unsigned int i;
@@ -4337,6 +4656,15 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
4337 ptr++; 4656 ptr++;
4338 arg = arg->next; 4657 arg = arg->next;
4339 break; 4658 break;
4659 } else if (*(ptr+1) == 'I' || *(ptr+1) == 'i') {
4660 int n;
4661
4662 n = print_ip_arg(s, ptr+1, data, size, event, arg);
4663 if (n > 0) {
4664 ptr += n;
4665 arg = arg->next;
4666 break;
4667 }
4340 } 4668 }
4341 4669
4342 /* fall through */ 4670 /* fall through */