Skip to contentSkip to conversation

tools lib traceevent: Add support for IP address formats

PATCH Superseded David Ahern 5 participants 12 messages Dec 18, 2014 – Dec 22, 2014

Subsystems (3)

v1 of 4 Superseded Latest is v4 →

lore
Share & tools
lore
#0 lore raw

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

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
index cf3a44bf1ec3..48d57c9fc476 100644
@@ -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)
#1 lore raw

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 sockaddr

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 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 to print_ip_arg per Namhyung's comments
- added field length checks to sockaddr function

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
index cf3a44bf1ec3..48d57c9fc476 100644
@@ -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)
#2 lore raw
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

maintainer
#3 lore raw
In reply to Arnaldo Carvalho de Melo
Quoted 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.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

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.

#4 lore raw

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 sockaddr

Allows 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.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

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.

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

#5 lore raw
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

#6 lore raw
In reply to David Ahern
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...

#7 lore raw
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

#8 lore raw
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.004

And 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

#9 lore raw
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_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.004

And 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

#10 lore raw
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 bedfad82a159226f06a8035f6a7622fce6df7a0a Mon 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
new file mode 100644
index 000000000000..24e1e8a8b843
@@ -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
index ba3c0120786c..b564a28852d1 100644
@@ -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
index 214882e7d6de..aa6ba2ad93fd 100644
@@ -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
index f7c8bbeb27b7..294cb618baf5 100644
@@ -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)
#11 lore raw
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 bedfad82a159226f06a8035f6a7622fce6df7a0a Mon 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
new file mode 100644
index 000000000000..24e1e8a8b843
@@ -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
new file mode 100644
index 000000000000..db1ae85eaa0c
@@ -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
index ba3c0120786c..b564a28852d1 100644
@@ -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
index 214882e7d6de..aa6ba2ad93fd 100644
@@ -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
index f7c8bbeb27b7..294cb618baf5 100644
@@ -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)