diff options
Diffstat (limited to 'net/tipc')
| -rw-r--r-- | net/tipc/Makefile | 4 | ||||
| -rw-r--r-- | net/tipc/bearer.c | 9 | ||||
| -rw-r--r-- | net/tipc/bearer.h | 2 | ||||
| -rw-r--r-- | net/tipc/link.c | 220 | ||||
| -rw-r--r-- | net/tipc/link.h | 2 | ||||
| -rw-r--r-- | net/tipc/msg.h | 1 | ||||
| -rw-r--r-- | net/tipc/netlink_compat.c | 7 | ||||
| -rw-r--r-- | net/tipc/node.c | 96 | ||||
| -rw-r--r-- | net/tipc/node.h | 1 | ||||
| -rw-r--r-- | net/tipc/socket.c | 267 | ||||
| -rw-r--r-- | net/tipc/socket.h | 4 | ||||
| -rw-r--r-- | net/tipc/sysctl.c | 8 | ||||
| -rw-r--r-- | net/tipc/trace.c | 206 | ||||
| -rw-r--r-- | net/tipc/trace.h | 431 | ||||
| -rw-r--r-- | net/tipc/udp_media.c | 9 | 
15 files changed, 1188 insertions, 79 deletions
| diff --git a/net/tipc/Makefile b/net/tipc/Makefile index aca168f2abb1..c86aba0282af 100644 --- a/net/tipc/Makefile +++ b/net/tipc/Makefile @@ -9,7 +9,9 @@ tipc-y	+= addr.o bcast.o bearer.o \  	   core.o link.o discover.o msg.o  \  	   name_distr.o  subscr.o monitor.o name_table.o net.o  \  	   netlink.o netlink_compat.o node.o socket.o eth_media.o \ -	   topsrv.o socket.o group.o +	   topsrv.o socket.o group.o trace.o + +CFLAGS_trace.o += -I$(src)  tipc-$(CONFIG_TIPC_MEDIA_UDP)	+= udp_media.o  tipc-$(CONFIG_TIPC_MEDIA_IB)	+= ib_media.o diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index e65c3a8551e4..fb2c0d8f359f 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -43,6 +43,7 @@  #include "bcast.h"  #include "netlink.h"  #include "udp_media.h" +#include "trace.h"  #define MAX_ADDR_STR 60 @@ -99,7 +100,7 @@ static struct tipc_media *media_find_id(u8 type)  /**   * tipc_media_addr_printf - record media address in print buffer   */ -void tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a) +int tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a)  {  	char addr_str[MAX_ADDR_STR];  	struct tipc_media *m; @@ -114,9 +115,10 @@ void tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a)  		ret = scnprintf(buf, len, "UNKNOWN(%u)", a->media_id);  		for (i = 0; i < sizeof(a->value); i++) -			ret += scnprintf(buf - ret, len + ret, -					    "-%02x", a->value[i]); +			ret += scnprintf(buf + ret, len - ret, +					    "-%x", a->value[i]);  	} +	return ret;  }  /** @@ -607,6 +609,7 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,  	if (!b)  		return NOTIFY_DONE; +	trace_tipc_l2_device_event(dev, b, evt);  	switch (evt) {  	case NETDEV_CHANGE:  		if (netif_carrier_ok(dev) && netif_oper_up(dev)) { diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h index 394290cbbb1d..7f4c569594a5 100644 --- a/net/tipc/bearer.h +++ b/net/tipc/bearer.h @@ -207,7 +207,7 @@ int __tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info);  int tipc_media_set_priority(const char *name, u32 new_value);  int tipc_media_set_window(const char *name, u32 new_value); -void tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a); +int tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a);  int tipc_enable_l2_media(struct net *net, struct tipc_bearer *b,  			 struct nlattr *attrs[]);  void tipc_disable_l2_media(struct tipc_bearer *b); diff --git a/net/tipc/link.c b/net/tipc/link.c index 836727e363c4..2792a3cae682 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -43,6 +43,7 @@  #include "discover.h"  #include "netlink.h"  #include "monitor.h" +#include "trace.h"  #include <linux/pkt_sched.h> @@ -105,7 +106,7 @@ struct tipc_stats {   * @transmitq: queue for sent, non-acked messages   * @backlogq: queue for messages waiting to be sent   * @snt_nxt: next sequence number to use for outbound messages - * @last_retransmitted: sequence number of most recently retransmitted message + * @prev_from: sequence number of most previous retransmission request   * @stale_cnt: counter for number of identical retransmit attempts   * @stale_limit: time when repeated identical retransmits must force link reset   * @ackers: # of peers that needs to ack each packet before it can be released @@ -163,7 +164,7 @@ struct tipc_link {  		u16 limit;  	} backlog[5];  	u16 snd_nxt; -	u16 last_retransm; +	u16 prev_from;  	u16 window;  	u16 stale_cnt;  	unsigned long stale_limit; @@ -186,9 +187,6 @@ struct tipc_link {  	u16 acked;  	struct tipc_link *bc_rcvlink;  	struct tipc_link *bc_sndlink; -	unsigned long prev_retr; -	u16 prev_from; -	u16 prev_to;  	u8 nack_state;  	bool bc_peer_is_up; @@ -210,7 +208,7 @@ enum {  	BC_NACK_SND_SUPPRESS,  }; -#define TIPC_BC_RETR_LIMIT 10   /* [ms] */ +#define TIPC_BC_RETR_LIM msecs_to_jiffies(10)   /* [ms] */  /*   * Interval between NACKs when packets arrive out of order @@ -359,9 +357,11 @@ void tipc_link_remove_bc_peer(struct tipc_link *snd_l,  	rcv_l->bc_peer_is_up = true;  	rcv_l->state = LINK_ESTABLISHED;  	tipc_link_bc_ack_rcv(rcv_l, ack, xmitq); +	trace_tipc_link_reset(rcv_l, TIPC_DUMP_ALL, "bclink removed!");  	tipc_link_reset(rcv_l);  	rcv_l->state = LINK_RESET;  	if (!snd_l->ackers) { +		trace_tipc_link_reset(snd_l, TIPC_DUMP_ALL, "zero ackers!");  		tipc_link_reset(snd_l);  		snd_l->state = LINK_RESET;  		__skb_queue_purge(xmitq); @@ -525,6 +525,7 @@ bool tipc_link_bc_create(struct net *net, u32 ownnode, u32 peer,  	l = *link;  	strcpy(l->name, tipc_bclink_name); +	trace_tipc_link_reset(l, TIPC_DUMP_ALL, "bclink created!");  	tipc_link_reset(l);  	l->state = LINK_RESET;  	l->ackers = 0; @@ -549,6 +550,7 @@ bool tipc_link_bc_create(struct net *net, u32 ownnode, u32 peer,  int tipc_link_fsm_evt(struct tipc_link *l, int evt)  {  	int rc = 0; +	int old_state = l->state;  	switch (l->state) {  	case LINK_RESETTING: @@ -695,10 +697,12 @@ int tipc_link_fsm_evt(struct tipc_link *l, int evt)  	default:  		pr_err("Unknown FSM state %x in %s\n", l->state, l->name);  	} +	trace_tipc_link_fsm(l->name, old_state, l->state, evt);  	return rc;  illegal_evt:  	pr_err("Illegal FSM event %x in state %x on link %s\n",  	       evt, l->state, l->name); +	trace_tipc_link_fsm(l->name, old_state, l->state, evt);  	return rc;  } @@ -743,6 +747,18 @@ static void link_profile_stats(struct tipc_link *l)  		l->stats.msg_length_profile[6]++;  } +/** + * tipc_link_too_silent - check if link is "too silent" + * @l: tipc link to be checked + * + * Returns true if the link 'silent_intv_cnt' is about to reach the + * 'abort_limit' value, otherwise false + */ +bool tipc_link_too_silent(struct tipc_link *l) +{ +	return (l->silent_intv_cnt + 2 > l->abort_limit); +} +  /* tipc_link_timeout - perform periodic task as instructed from node timeout   */  int tipc_link_timeout(struct tipc_link *l, struct sk_buff_head *xmitq) @@ -756,6 +772,8 @@ int tipc_link_timeout(struct tipc_link *l, struct sk_buff_head *xmitq)  	u16 bc_acked = l->bc_rcvlink->acked;  	struct tipc_mon_state *mstate = &l->mon_state; +	trace_tipc_link_timeout(l, TIPC_DUMP_NONE, " "); +	trace_tipc_link_too_silent(l, TIPC_DUMP_ALL, " ");  	switch (l->state) {  	case LINK_ESTABLISHED:  	case LINK_SYNCHING: @@ -818,6 +836,7 @@ static int link_schedule_user(struct tipc_link *l, struct tipc_msg *hdr)  	TIPC_SKB_CB(skb)->chain_imp = msg_importance(hdr);  	skb_queue_tail(&l->wakeupq, skb);  	l->stats.link_congs++; +	trace_tipc_link_conges(l, TIPC_DUMP_ALL, "wakeup scheduled!");  	return -ELINKCONG;  } @@ -948,6 +967,10 @@ int tipc_link_xmit(struct tipc_link *l, struct sk_buff_head *list,  			}  			__skb_dequeue(list);  			__skb_queue_tail(transmq, skb); +			/* next retransmit attempt */ +			if (link_is_bc_sndlink(l)) +				TIPC_SKB_CB(skb)->nxt_retr = +					jiffies + TIPC_BC_RETR_LIM;  			__skb_queue_tail(xmitq, _skb);  			TIPC_SKB_CB(skb)->ackers = l->ackers;  			l->rcv_unacked = 0; @@ -995,6 +1018,10 @@ static void tipc_link_advance_backlog(struct tipc_link *l,  		hdr = buf_msg(skb);  		l->backlog[msg_importance(hdr)].len--;  		__skb_queue_tail(&l->transmq, skb); +		/* next retransmit attempt */ +		if (link_is_bc_sndlink(l)) +			TIPC_SKB_CB(skb)->nxt_retr = jiffies + TIPC_BC_RETR_LIM; +  		__skb_queue_tail(xmitq, _skb);  		TIPC_SKB_CB(skb)->ackers = l->ackers;  		msg_set_seqno(hdr, seqno); @@ -1036,14 +1063,20 @@ static int tipc_link_retrans(struct tipc_link *l, struct tipc_link *r,  	if (!skb)  		return 0; +	if (less(to, from)) +		return 0; +	trace_tipc_link_retrans(r, from, to, &l->transmq);  	/* Detect repeated retransmit failures on same packet */ -	if (r->last_retransm != buf_seqno(skb)) { -		r->last_retransm = buf_seqno(skb); +	if (r->prev_from != from) { +		r->prev_from = from;  		r->stale_limit = jiffies + msecs_to_jiffies(r->tolerance);  		r->stale_cnt = 0;  	} else if (++r->stale_cnt > 99 && time_after(jiffies, r->stale_limit)) {  		link_retransmit_failure(l, skb); +		trace_tipc_list_dump(&l->transmq, true, "retrans failure!"); +		trace_tipc_link_dump(l, TIPC_DUMP_NONE, "retrans failure!"); +		trace_tipc_link_dump(r, TIPC_DUMP_NONE, "retrans failure!");  		if (link_is_bc_sndlink(l))  			return TIPC_LINK_DOWN_EVT;  		return tipc_link_fsm_evt(l, LINK_FAILURE_EVT); @@ -1055,6 +1088,11 @@ static int tipc_link_retrans(struct tipc_link *l, struct tipc_link *r,  			continue;  		if (more(msg_seqno(hdr), to))  			break; +		if (link_is_bc_sndlink(l)) { +			if (time_before(jiffies, TIPC_SKB_CB(skb)->nxt_retr)) +				continue; +			TIPC_SKB_CB(skb)->nxt_retr = jiffies + TIPC_BC_RETR_LIM; +		}  		_skb = __pskb_copy(skb, MIN_H_SIZE, GFP_ATOMIC);  		if (!_skb)  			return 0; @@ -1398,6 +1436,7 @@ static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe,  		l->stats.sent_nacks++;  	skb->priority = TC_PRIO_CONTROL;  	__skb_queue_tail(xmitq, skb); +	trace_tipc_proto_build(skb, false, l->name);  }  void tipc_link_create_dummy_tnl_msg(struct tipc_link *l, @@ -1561,6 +1600,7 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb,  	char *if_name;  	int rc = 0; +	trace_tipc_proto_rcv(skb, false, l->name);  	if (tipc_link_is_blocked(l) || !xmitq)  		goto exit; @@ -1571,8 +1611,11 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb,  	hdr = buf_msg(skb);  	data = msg_data(hdr); -	if (!tipc_link_validate_msg(l, hdr)) +	if (!tipc_link_validate_msg(l, hdr)) { +		trace_tipc_skb_dump(skb, false, "PROTO invalid (1)!"); +		trace_tipc_link_dump(l, TIPC_DUMP_NONE, "PROTO invalid (1)!");  		goto exit; +	}  	switch (mtyp) {  	case RESET_MSG: @@ -1737,42 +1780,6 @@ void tipc_link_bc_init_rcv(struct tipc_link *l, struct tipc_msg *hdr)  		l->rcv_nxt = peers_snd_nxt;  } -/* link_bc_retr eval()- check if the indicated range can be retransmitted now - * - Adjust permitted range if there is overlap with previous retransmission - */ -static bool link_bc_retr_eval(struct tipc_link *l, u16 *from, u16 *to) -{ -	unsigned long elapsed = jiffies_to_msecs(jiffies - l->prev_retr); - -	if (less(*to, *from)) -		return false; - -	/* New retransmission request */ -	if ((elapsed > TIPC_BC_RETR_LIMIT) || -	    less(*to, l->prev_from) || more(*from, l->prev_to)) { -		l->prev_from = *from; -		l->prev_to = *to; -		l->prev_retr = jiffies; -		return true; -	} - -	/* Inside range of previous retransmit */ -	if (!less(*from, l->prev_from) && !more(*to, l->prev_to)) -		return false; - -	/* Fully or partially outside previous range => exclude overlap */ -	if (less(*from, l->prev_from)) { -		*to = l->prev_from - 1; -		l->prev_from = *from; -	} -	if (more(*to, l->prev_to)) { -		*from = l->prev_to + 1; -		l->prev_to = *to; -	} -	l->prev_retr = jiffies; -	return true; -} -  /* tipc_link_bc_sync_rcv - update rcv link according to peer's send state   */  int tipc_link_bc_sync_rcv(struct tipc_link *l, struct tipc_msg *hdr, @@ -1803,8 +1810,7 @@ int tipc_link_bc_sync_rcv(struct tipc_link *l, struct tipc_msg *hdr,  	if (more(peers_snd_nxt, l->rcv_nxt + l->window))  		return rc; -	if (link_bc_retr_eval(snd_l, &from, &to)) -		rc = tipc_link_retrans(snd_l, l, from, to, xmitq); +	rc = tipc_link_retrans(snd_l, l, from, to, xmitq);  	l->snd_nxt = peers_snd_nxt;  	if (link_bc_rcv_gap(l)) @@ -1852,6 +1858,7 @@ void tipc_link_bc_ack_rcv(struct tipc_link *l, u16 acked,  	if (!more(acked, l->acked))  		return; +	trace_tipc_link_bc_ack(l, l->acked, acked, &snd_l->transmq);  	/* Skip over packets peer has already acked */  	skb_queue_walk(&snd_l->transmq, skb) {  		if (more(buf_seqno(skb), l->acked)) @@ -2255,3 +2262,122 @@ void tipc_link_set_abort_limit(struct tipc_link *l, u32 limit)  {  	l->abort_limit = limit;  } + +char *tipc_link_name_ext(struct tipc_link *l, char *buf) +{ +	if (!l) +		scnprintf(buf, TIPC_MAX_LINK_NAME, "null"); +	else if (link_is_bc_sndlink(l)) +		scnprintf(buf, TIPC_MAX_LINK_NAME, "broadcast-sender"); +	else if (link_is_bc_rcvlink(l)) +		scnprintf(buf, TIPC_MAX_LINK_NAME, +			  "broadcast-receiver, peer %x", l->addr); +	else +		memcpy(buf, l->name, TIPC_MAX_LINK_NAME); + +	return buf; +} + +/** + * tipc_link_dump - dump TIPC link data + * @l: tipc link to be dumped + * @dqueues: bitmask to decide if any link queue to be dumped? + *           - TIPC_DUMP_NONE: don't dump link queues + *           - TIPC_DUMP_TRANSMQ: dump link transmq queue + *           - TIPC_DUMP_BACKLOGQ: dump link backlog queue + *           - TIPC_DUMP_DEFERDQ: dump link deferd queue + *           - TIPC_DUMP_INPUTQ: dump link input queue + *           - TIPC_DUMP_WAKEUP: dump link wakeup queue + *           - TIPC_DUMP_ALL: dump all the link queues above + * @buf: returned buffer of dump data in format + */ +int tipc_link_dump(struct tipc_link *l, u16 dqueues, char *buf) +{ +	int i = 0; +	size_t sz = (dqueues) ? LINK_LMAX : LINK_LMIN; +	struct sk_buff_head *list; +	struct sk_buff *hskb, *tskb; +	u32 len; + +	if (!l) { +		i += scnprintf(buf, sz, "link data: (null)\n"); +		return i; +	} + +	i += scnprintf(buf, sz, "link data: %x", l->addr); +	i += scnprintf(buf + i, sz - i, " %x", l->state); +	i += scnprintf(buf + i, sz - i, " %u", l->in_session); +	i += scnprintf(buf + i, sz - i, " %u", l->session); +	i += scnprintf(buf + i, sz - i, " %u", l->peer_session); +	i += scnprintf(buf + i, sz - i, " %u", l->snd_nxt); +	i += scnprintf(buf + i, sz - i, " %u", l->rcv_nxt); +	i += scnprintf(buf + i, sz - i, " %u", l->snd_nxt_state); +	i += scnprintf(buf + i, sz - i, " %u", l->rcv_nxt_state); +	i += scnprintf(buf + i, sz - i, " %x", l->peer_caps); +	i += scnprintf(buf + i, sz - i, " %u", l->silent_intv_cnt); +	i += scnprintf(buf + i, sz - i, " %u", l->rst_cnt); +	i += scnprintf(buf + i, sz - i, " %u", l->prev_from); +	i += scnprintf(buf + i, sz - i, " %u", l->stale_cnt); +	i += scnprintf(buf + i, sz - i, " %u", l->acked); + +	list = &l->transmq; +	len = skb_queue_len(list); +	hskb = skb_peek(list); +	tskb = skb_peek_tail(list); +	i += scnprintf(buf + i, sz - i, " | %u %u %u", len, +		       (hskb) ? msg_seqno(buf_msg(hskb)) : 0, +		       (tskb) ? msg_seqno(buf_msg(tskb)) : 0); + +	list = &l->deferdq; +	len = skb_queue_len(list); +	hskb = skb_peek(list); +	tskb = skb_peek_tail(list); +	i += scnprintf(buf + i, sz - i, " | %u %u %u", len, +		       (hskb) ? msg_seqno(buf_msg(hskb)) : 0, +		       (tskb) ? msg_seqno(buf_msg(tskb)) : 0); + +	list = &l->backlogq; +	len = skb_queue_len(list); +	hskb = skb_peek(list); +	tskb = skb_peek_tail(list); +	i += scnprintf(buf + i, sz - i, " | %u %u %u", len, +		       (hskb) ? msg_seqno(buf_msg(hskb)) : 0, +		       (tskb) ? msg_seqno(buf_msg(tskb)) : 0); + +	list = l->inputq; +	len = skb_queue_len(list); +	hskb = skb_peek(list); +	tskb = skb_peek_tail(list); +	i += scnprintf(buf + i, sz - i, " | %u %u %u\n", len, +		       (hskb) ? msg_seqno(buf_msg(hskb)) : 0, +		       (tskb) ? msg_seqno(buf_msg(tskb)) : 0); + +	if (dqueues & TIPC_DUMP_TRANSMQ) { +		i += scnprintf(buf + i, sz - i, "transmq: "); +		i += tipc_list_dump(&l->transmq, false, buf + i); +	} +	if (dqueues & TIPC_DUMP_BACKLOGQ) { +		i += scnprintf(buf + i, sz - i, +			       "backlogq: <%u %u %u %u %u>, ", +			       l->backlog[TIPC_LOW_IMPORTANCE].len, +			       l->backlog[TIPC_MEDIUM_IMPORTANCE].len, +			       l->backlog[TIPC_HIGH_IMPORTANCE].len, +			       l->backlog[TIPC_CRITICAL_IMPORTANCE].len, +			       l->backlog[TIPC_SYSTEM_IMPORTANCE].len); +		i += tipc_list_dump(&l->backlogq, false, buf + i); +	} +	if (dqueues & TIPC_DUMP_DEFERDQ) { +		i += scnprintf(buf + i, sz - i, "deferdq: "); +		i += tipc_list_dump(&l->deferdq, false, buf + i); +	} +	if (dqueues & TIPC_DUMP_INPUTQ) { +		i += scnprintf(buf + i, sz - i, "inputq: "); +		i += tipc_list_dump(l->inputq, false, buf + i); +	} +	if (dqueues & TIPC_DUMP_WAKEUP) { +		i += scnprintf(buf + i, sz - i, "wakeup: "); +		i += tipc_list_dump(&l->wakeupq, false, buf + i); +	} + +	return i; +} diff --git a/net/tipc/link.h b/net/tipc/link.h index 90488c538a4e..8439e0ee53a8 100644 --- a/net/tipc/link.h +++ b/net/tipc/link.h @@ -109,6 +109,7 @@ u16 tipc_link_rcv_nxt(struct tipc_link *l);  u16 tipc_link_acked(struct tipc_link *l);  u32 tipc_link_id(struct tipc_link *l);  char *tipc_link_name(struct tipc_link *l); +char *tipc_link_name_ext(struct tipc_link *l, char *buf);  u32 tipc_link_state(struct tipc_link *l);  char tipc_link_plane(struct tipc_link *l);  int tipc_link_prio(struct tipc_link *l); @@ -147,4 +148,5 @@ int tipc_link_bc_sync_rcv(struct tipc_link *l,   struct tipc_msg *hdr,  			  struct sk_buff_head *xmitq);  int tipc_link_bc_nack_rcv(struct tipc_link *l, struct sk_buff *skb,  			  struct sk_buff_head *xmitq); +bool tipc_link_too_silent(struct tipc_link *l);  #endif diff --git a/net/tipc/msg.h b/net/tipc/msg.h index a2879e6ec5b6..a0924956bb61 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -105,6 +105,7 @@ struct tipc_skb_cb {  	u32 bytes_read;  	u32 orig_member;  	struct sk_buff *tail; +	unsigned long nxt_retr;  	bool validated;  	u16 chain_imp;  	u16 ackers; diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c index 6376467e78f8..21f6ccc89401 100644 --- a/net/tipc/netlink_compat.c +++ b/net/tipc/netlink_compat.c @@ -951,8 +951,11 @@ static int tipc_nl_compat_sk_dump(struct tipc_nl_compat_msg *msg,  		u32 node;  		struct nlattr *con[TIPC_NLA_CON_MAX + 1]; -		nla_parse_nested(con, TIPC_NLA_CON_MAX, -				 sock[TIPC_NLA_SOCK_CON], NULL, NULL); +		err = nla_parse_nested(con, TIPC_NLA_CON_MAX, +				       sock[TIPC_NLA_SOCK_CON], NULL, NULL); + +		if (err) +			return err;  		node = nla_get_u32(con[TIPC_NLA_CON_NODE]);  		tipc_tlv_sprintf(msg->rep, "  connected to <%u.%u.%u:%u>", diff --git a/net/tipc/node.c b/net/tipc/node.c index 488019766433..db2a6c3e0be9 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -43,6 +43,7 @@  #include "monitor.h"  #include "discover.h"  #include "netlink.h" +#include "trace.h"  #define INVALID_NODE_SIG	0x10000  #define NODE_CLEANUP_AFTER	300000 @@ -432,6 +433,7 @@ static struct tipc_node *tipc_node_create(struct net *net, u32 addr,  			break;  	}  	list_add_tail_rcu(&n->list, &temp_node->list); +	trace_tipc_node_create(n, true, " ");  exit:  	spin_unlock_bh(&tn->node_list_lock);  	return n; @@ -459,6 +461,7 @@ static void tipc_node_delete_from_list(struct tipc_node *node)  static void tipc_node_delete(struct tipc_node *node)  { +	trace_tipc_node_delete(node, true, " ");  	tipc_node_delete_from_list(node);  	del_timer_sync(&node->timer); @@ -616,6 +619,7 @@ static void tipc_node_timeout(struct timer_list *t)  	int bearer_id;  	int rc = 0; +	trace_tipc_node_timeout(n, false, " ");  	if (!node_is_up(n) && tipc_node_cleanup(n)) {  		/*Removing the reference of Timer*/  		tipc_node_put(n); @@ -624,6 +628,12 @@ static void tipc_node_timeout(struct timer_list *t)  	__skb_queue_head_init(&xmitq); +	/* Initial node interval to value larger (10 seconds), then it will be +	 * recalculated with link lowest tolerance +	 */ +	tipc_node_read_lock(n); +	n->keepalive_intv = 10000; +	tipc_node_read_unlock(n);  	for (bearer_id = 0; remains && (bearer_id < MAX_BEARERS); bearer_id++) {  		tipc_node_read_lock(n);  		le = &n->links[bearer_id]; @@ -675,6 +685,7 @@ static void __tipc_node_link_up(struct tipc_node *n, int bearer_id,  	pr_debug("Established link <%s> on network plane %c\n",  		 tipc_link_name(nl), tipc_link_plane(nl)); +	trace_tipc_node_link_up(n, true, " ");  	/* Ensure that a STATE message goes first */  	tipc_link_build_state_msg(nl, xmitq); @@ -777,6 +788,7 @@ static void __tipc_node_link_down(struct tipc_node *n, int *bearer_id,  		if (tipc_link_peer_is_down(l))  			tipc_node_fsm_evt(n, PEER_LOST_CONTACT_EVT);  		tipc_node_fsm_evt(n, SELF_LOST_CONTACT_EVT); +		trace_tipc_link_reset(l, TIPC_DUMP_ALL, "link down!");  		tipc_link_fsm_evt(l, LINK_RESET_EVT);  		tipc_link_reset(l);  		tipc_link_build_reset_msg(l, xmitq); @@ -794,6 +806,7 @@ static void __tipc_node_link_down(struct tipc_node *n, int *bearer_id,  	tipc_node_fsm_evt(n, NODE_SYNCH_END_EVT);  	n->sync_point = tipc_link_rcv_nxt(tnl) + (U16_MAX / 2 - 1);  	tipc_link_tnl_prepare(l, tnl, FAILOVER_MSG, xmitq); +	trace_tipc_link_reset(l, TIPC_DUMP_ALL, "link down -> failover!");  	tipc_link_reset(l);  	tipc_link_fsm_evt(l, LINK_RESET_EVT);  	tipc_link_fsm_evt(l, LINK_FAILOVER_BEGIN_EVT); @@ -826,6 +839,7 @@ static void tipc_node_link_down(struct tipc_node *n, int bearer_id, bool delete)  		/* Defuse pending tipc_node_link_up() */  		tipc_link_fsm_evt(l, LINK_RESET_EVT);  	} +	trace_tipc_node_link_down(n, true, "node link down or deleted!");  	tipc_node_write_unlock(n);  	if (delete)  		tipc_mon_remove_peer(n->net, n->addr, old_bearer_id); @@ -1015,6 +1029,7 @@ void tipc_node_check_dest(struct net *net, u32 addr,  			*respond = false;  			goto exit;  		} +		trace_tipc_link_reset(l, TIPC_DUMP_ALL, "link created!");  		tipc_link_reset(l);  		tipc_link_fsm_evt(l, LINK_RESET_EVT);  		if (n->state == NODE_FAILINGOVER) @@ -1054,6 +1069,7 @@ static void tipc_node_reset_links(struct tipc_node *n)  	pr_warn("Resetting all links to %x\n", n->addr); +	trace_tipc_node_reset_links(n, true, " ");  	for (i = 0; i < MAX_BEARERS; i++) {  		tipc_node_link_down(n, i, false);  	} @@ -1229,11 +1245,13 @@ static void tipc_node_fsm_evt(struct tipc_node *n, int evt)  		pr_err("Unknown node fsm state %x\n", state);  		break;  	} +	trace_tipc_node_fsm(n->peer_id, n->state, state, evt);  	n->state = state;  	return;  illegal_evt:  	pr_err("Illegal node fsm evt %x in state %x\n", evt, state); +	trace_tipc_node_fsm(n->peer_id, n->state, state, evt);  }  static void node_lost_contact(struct tipc_node *n, @@ -1247,6 +1265,7 @@ static void node_lost_contact(struct tipc_node *n,  	pr_debug("Lost contact with %x\n", n->addr);  	n->delete_at = jiffies + msecs_to_jiffies(NODE_CLEANUP_AFTER); +	trace_tipc_node_lost_contact(n, true, " ");  	/* Clean up broadcast state */  	tipc_bcast_remove_peer(n->net, n->bc_entry.link); @@ -1543,6 +1562,10 @@ static void tipc_node_bc_rcv(struct net *net, struct sk_buff *skb, int bearer_id  	if (!skb_queue_empty(&be->inputq1))  		tipc_node_mcast_rcv(n); +	/* Handle NAME_DISTRIBUTOR messages sent from 1.7 nodes */ +	if (!skb_queue_empty(&n->bc_entry.namedq)) +		tipc_named_rcv(net, &n->bc_entry.namedq); +  	/* If reassembly or retransmission failure => reset all links to peer */  	if (rc & TIPC_LINK_DOWN_EVT)  		tipc_node_reset_links(n); @@ -1571,6 +1594,10 @@ static bool tipc_node_check_state(struct tipc_node *n, struct sk_buff *skb,  	struct tipc_media_addr *maddr;  	int pb_id; +	if (trace_tipc_node_check_state_enabled()) { +		trace_tipc_skb_dump(skb, false, "skb for node state check"); +		trace_tipc_node_check_state(n, true, " "); +	}  	l = n->links[bearer_id].link;  	if (!l)  		return false; @@ -1588,8 +1615,11 @@ static bool tipc_node_check_state(struct tipc_node *n, struct sk_buff *skb,  		}  	} -	if (!tipc_link_validate_msg(l, hdr)) +	if (!tipc_link_validate_msg(l, hdr)) { +		trace_tipc_skb_dump(skb, false, "PROTO invalid (2)!"); +		trace_tipc_link_dump(l, TIPC_DUMP_NONE, "PROTO invalid (2)!");  		return false; +	}  	/* Check and update node accesibility if applicable */  	if (state == SELF_UP_PEER_COMING) { @@ -1619,6 +1649,8 @@ static bool tipc_node_check_state(struct tipc_node *n, struct sk_buff *skb,  		syncpt = oseqno + exp_pkts - 1;  		if (pl && tipc_link_is_up(pl)) {  			__tipc_node_link_down(n, &pb_id, xmitq, &maddr); +			trace_tipc_node_link_down(n, true, +						  "node link down <- failover!");  			tipc_skb_queue_splice_tail_init(tipc_link_inputq(pl),  							tipc_link_inputq(l));  		} @@ -2425,3 +2457,65 @@ int tipc_nl_node_dump_monitor_peer(struct sk_buff *skb,  	return skb->len;  } + +u32 tipc_node_get_addr(struct tipc_node *node) +{ +	return (node) ? node->addr : 0; +} + +/** + * tipc_node_dump - dump TIPC node data + * @n: tipc node to be dumped + * @more: dump more? + *        - false: dump only tipc node data + *        - true: dump node link data as well + * @buf: returned buffer of dump data in format + */ +int tipc_node_dump(struct tipc_node *n, bool more, char *buf) +{ +	int i = 0; +	size_t sz = (more) ? NODE_LMAX : NODE_LMIN; + +	if (!n) { +		i += scnprintf(buf, sz, "node data: (null)\n"); +		return i; +	} + +	i += scnprintf(buf, sz, "node data: %x", n->addr); +	i += scnprintf(buf + i, sz - i, " %x", n->state); +	i += scnprintf(buf + i, sz - i, " %d", n->active_links[0]); +	i += scnprintf(buf + i, sz - i, " %d", n->active_links[1]); +	i += scnprintf(buf + i, sz - i, " %x", n->action_flags); +	i += scnprintf(buf + i, sz - i, " %u", n->failover_sent); +	i += scnprintf(buf + i, sz - i, " %u", n->sync_point); +	i += scnprintf(buf + i, sz - i, " %d", n->link_cnt); +	i += scnprintf(buf + i, sz - i, " %u", n->working_links); +	i += scnprintf(buf + i, sz - i, " %x", n->capabilities); +	i += scnprintf(buf + i, sz - i, " %lu\n", n->keepalive_intv); + +	if (!more) +		return i; + +	i += scnprintf(buf + i, sz - i, "link_entry[0]:\n"); +	i += scnprintf(buf + i, sz - i, " mtu: %u\n", n->links[0].mtu); +	i += scnprintf(buf + i, sz - i, " media: "); +	i += tipc_media_addr_printf(buf + i, sz - i, &n->links[0].maddr); +	i += scnprintf(buf + i, sz - i, "\n"); +	i += tipc_link_dump(n->links[0].link, TIPC_DUMP_NONE, buf + i); +	i += scnprintf(buf + i, sz - i, " inputq: "); +	i += tipc_list_dump(&n->links[0].inputq, false, buf + i); + +	i += scnprintf(buf + i, sz - i, "link_entry[1]:\n"); +	i += scnprintf(buf + i, sz - i, " mtu: %u\n", n->links[1].mtu); +	i += scnprintf(buf + i, sz - i, " media: "); +	i += tipc_media_addr_printf(buf + i, sz - i, &n->links[1].maddr); +	i += scnprintf(buf + i, sz - i, "\n"); +	i += tipc_link_dump(n->links[1].link, TIPC_DUMP_NONE, buf + i); +	i += scnprintf(buf + i, sz - i, " inputq: "); +	i += tipc_list_dump(&n->links[1].inputq, false, buf + i); + +	i += scnprintf(buf + i, sz - i, "bclink:\n "); +	i += tipc_link_dump(n->bc_entry.link, TIPC_DUMP_NONE, buf + i); + +	return i; +} diff --git a/net/tipc/node.h b/net/tipc/node.h index 03f5efb62cfb..4f59a30e989a 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h @@ -65,6 +65,7 @@ enum {  void tipc_node_stop(struct net *net);  bool tipc_node_get_id(struct net *net, u32 addr, u8 *id); +u32 tipc_node_get_addr(struct tipc_node *node);  u32 tipc_node_try_addr(struct net *net, u8 *id, u32 addr);  void tipc_node_check_dest(struct net *net, u32 onode, u8 *peer_id128,  			  struct tipc_bearer *bearer, diff --git a/net/tipc/socket.c b/net/tipc/socket.c index b57b1be7252b..1217c90a363b 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -46,6 +46,7 @@  #include "bcast.h"  #include "netlink.h"  #include "group.h" +#include "trace.h"  #define CONN_TIMEOUT_DEFAULT    8000    /* default connect timeout = 8s */  #define CONN_PROBING_INTV	msecs_to_jiffies(3600000)  /* [ms] => 1 h */ @@ -233,6 +234,7 @@ static u16 tsk_inc(struct tipc_sock *tsk, int msglen)   */  static void tsk_advance_rx_queue(struct sock *sk)  { +	trace_tipc_sk_advance_rx(sk, NULL, TIPC_DUMP_SK_RCVQ, " ");  	kfree_skb(__skb_dequeue(&sk->sk_receive_queue));  } @@ -247,6 +249,7 @@ static void tipc_sk_respond(struct sock *sk, struct sk_buff *skb, int err)  	if (!tipc_msg_reverse(onode, &skb, err))  		return; +	trace_tipc_sk_rej_msg(sk, skb, TIPC_DUMP_NONE, "@sk_respond!");  	dnode = msg_destnode(buf_msg(skb));  	selector = msg_origport(buf_msg(skb));  	tipc_node_xmit_skb(sock_net(sk), skb, dnode, selector); @@ -482,6 +485,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock,  			tsk_set_unreliable(tsk, true);  	} +	trace_tipc_sk_create(sk, NULL, TIPC_DUMP_NONE, " ");  	return 0;  } @@ -571,6 +575,7 @@ static int tipc_release(struct socket *sock)  	tsk = tipc_sk(sk);  	lock_sock(sk); +	trace_tipc_sk_release(sk, NULL, TIPC_DUMP_ALL, " ");  	__tipc_shutdown(sock, TIPC_ERR_NO_PORT);  	sk->sk_shutdown = SHUTDOWN_MASK;  	tipc_sk_leave(tsk); @@ -718,6 +723,7 @@ static __poll_t tipc_poll(struct file *file, struct socket *sock,  	__poll_t revents = 0;  	sock_poll_wait(file, sock, wait); +	trace_tipc_sk_poll(sk, NULL, TIPC_DUMP_ALL, " ");  	if (sk->sk_shutdown & RCV_SHUTDOWN)  		revents |= EPOLLRDHUP | EPOLLIN | EPOLLRDNORM; @@ -804,9 +810,12 @@ static int tipc_sendmcast(struct  socket *sock, struct tipc_name_seq *seq,  	rc = tipc_msg_build(hdr, msg, 0, dlen, mtu, &pkts);  	/* Send message if build was successful */ -	if (unlikely(rc == dlen)) +	if (unlikely(rc == dlen)) { +		trace_tipc_sk_sendmcast(sk, skb_peek(&pkts), +					TIPC_DUMP_SK_SNDQ, " ");  		rc = tipc_mcast_xmit(net, &pkts, method, &dsts,  				     &tsk->cong_link_cnt); +	}  	tipc_nlist_purge(&dsts); @@ -880,7 +889,6 @@ static int tipc_send_group_unicast(struct socket *sock, struct msghdr *m,  	DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name);  	int blks = tsk_blocks(GROUP_H_SIZE + dlen);  	struct tipc_sock *tsk = tipc_sk(sk); -	struct tipc_group *grp = tsk->group;  	struct net *net = sock_net(sk);  	struct tipc_member *mb = NULL;  	u32 node, port; @@ -894,7 +902,9 @@ static int tipc_send_group_unicast(struct socket *sock, struct msghdr *m,  	/* Block or return if destination link or member is congested */  	rc = tipc_wait_for_cond(sock, &timeout,  				!tipc_dest_find(&tsk->cong_links, node, 0) && -				!tipc_group_cong(grp, node, port, blks, &mb)); +				tsk->group && +				!tipc_group_cong(tsk->group, node, port, blks, +						 &mb));  	if (unlikely(rc))  		return rc; @@ -924,7 +934,6 @@ static int tipc_send_group_anycast(struct socket *sock, struct msghdr *m,  	struct tipc_sock *tsk = tipc_sk(sk);  	struct list_head *cong_links = &tsk->cong_links;  	int blks = tsk_blocks(GROUP_H_SIZE + dlen); -	struct tipc_group *grp = tsk->group;  	struct tipc_msg *hdr = &tsk->phdr;  	struct tipc_member *first = NULL;  	struct tipc_member *mbr = NULL; @@ -941,9 +950,10 @@ static int tipc_send_group_anycast(struct socket *sock, struct msghdr *m,  	type = msg_nametype(hdr);  	inst = dest->addr.name.name.instance;  	scope = msg_lookup_scope(hdr); -	exclude = tipc_group_exclude(grp);  	while (++lookups < 4) { +		exclude = tipc_group_exclude(tsk->group); +  		first = NULL;  		/* Look for a non-congested destination member, if any */ @@ -952,7 +962,8 @@ static int tipc_send_group_anycast(struct socket *sock, struct msghdr *m,  						 &dstcnt, exclude, false))  				return -EHOSTUNREACH;  			tipc_dest_pop(&dsts, &node, &port); -			cong = tipc_group_cong(grp, node, port, blks, &mbr); +			cong = tipc_group_cong(tsk->group, node, port, blks, +					       &mbr);  			if (!cong)  				break;  			if (mbr == first) @@ -971,7 +982,8 @@ static int tipc_send_group_anycast(struct socket *sock, struct msghdr *m,  		/* Block or return if destination link or member is congested */  		rc = tipc_wait_for_cond(sock, &timeout,  					!tipc_dest_find(cong_links, node, 0) && -					!tipc_group_cong(grp, node, port, +					tsk->group && +					!tipc_group_cong(tsk->group, node, port,  							 blks, &mbr));  		if (unlikely(rc))  			return rc; @@ -1006,8 +1018,7 @@ static int tipc_send_group_bcast(struct socket *sock, struct msghdr *m,  	struct sock *sk = sock->sk;  	struct net *net = sock_net(sk);  	struct tipc_sock *tsk = tipc_sk(sk); -	struct tipc_group *grp = tsk->group; -	struct tipc_nlist *dsts = tipc_group_dests(grp); +	struct tipc_nlist *dsts;  	struct tipc_mc_method *method = &tsk->mc_method;  	bool ack = method->mandatory && method->rcast;  	int blks = tsk_blocks(MCAST_H_SIZE + dlen); @@ -1016,15 +1027,17 @@ static int tipc_send_group_bcast(struct socket *sock, struct msghdr *m,  	struct sk_buff_head pkts;  	int rc = -EHOSTUNREACH; -	if (!dsts->local && !dsts->remote) -		return -EHOSTUNREACH; -  	/* Block or return if any destination link or member is congested */ -	rc = tipc_wait_for_cond(sock, &timeout,	!tsk->cong_link_cnt && -				!tipc_group_bc_cong(grp, blks)); +	rc = tipc_wait_for_cond(sock, &timeout, +				!tsk->cong_link_cnt && tsk->group && +				!tipc_group_bc_cong(tsk->group, blks));  	if (unlikely(rc))  		return rc; +	dsts = tipc_group_dests(tsk->group); +	if (!dsts->local && !dsts->remote) +		return -EHOSTUNREACH; +  	/* Complete message header */  	if (dest) {  		msg_set_type(hdr, TIPC_GRP_MCAST_MSG); @@ -1036,7 +1049,7 @@ static int tipc_send_group_bcast(struct socket *sock, struct msghdr *m,  	msg_set_hdr_sz(hdr, GROUP_H_SIZE);  	msg_set_destport(hdr, 0);  	msg_set_destnode(hdr, 0); -	msg_set_grp_bc_seqno(hdr, tipc_group_bc_snd_nxt(grp)); +	msg_set_grp_bc_seqno(hdr, tipc_group_bc_snd_nxt(tsk->group));  	/* Avoid getting stuck with repeated forced replicasts */  	msg_set_grp_bc_ack_req(hdr, ack); @@ -1208,8 +1221,10 @@ static void tipc_sk_conn_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb,  	bool conn_cong;  	/* Ignore if connection cannot be validated: */ -	if (!tsk_peer_msg(tsk, hdr)) +	if (!tsk_peer_msg(tsk, hdr)) { +		trace_tipc_sk_drop_msg(sk, skb, TIPC_DUMP_NONE, "@proto_rcv!");  		goto exit; +	}  	if (unlikely(msg_errcode(hdr))) {  		tipc_set_sk_state(sk, TIPC_DISCONNECTING); @@ -1377,6 +1392,7 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dlen)  	if (unlikely(syn && !tipc_msg_skb_clone(&pkts, &sk->sk_write_queue)))  		return -ENOMEM; +	trace_tipc_sk_sendmsg(sk, skb_peek(&pkts), TIPC_DUMP_SK_SNDQ, " ");  	rc = tipc_node_xmit(net, &pkts, dnode, tsk->portid);  	if (unlikely(rc == -ELINKCONG)) {  		tipc_dest_push(clinks, dnode, 0); @@ -1454,6 +1470,8 @@ static int __tipc_sendstream(struct socket *sock, struct msghdr *m, size_t dlen)  		if (unlikely(rc != send))  			break; +		trace_tipc_sk_sendstream(sk, skb_peek(&pkts), +					 TIPC_DUMP_SK_SNDQ, " ");  		rc = tipc_node_xmit(net, &pkts, dnode, tsk->portid);  		if (unlikely(rc == -ELINKCONG)) {  			tsk->cong_link_cnt = 1; @@ -2128,6 +2146,7 @@ static void tipc_sk_filter_rcv(struct sock *sk, struct sk_buff *skb,  	struct sk_buff_head inputq;  	int limit, err = TIPC_OK; +	trace_tipc_sk_filter_rcv(sk, skb, TIPC_DUMP_ALL, " ");  	TIPC_SKB_CB(skb)->bytes_read = 0;  	__skb_queue_head_init(&inputq);  	__skb_queue_tail(&inputq, skb); @@ -2147,17 +2166,25 @@ static void tipc_sk_filter_rcv(struct sock *sk, struct sk_buff *skb,  		    (!grp && msg_in_group(hdr)))  			err = TIPC_ERR_NO_PORT;  		else if (sk_rmem_alloc_get(sk) + skb->truesize >= limit) { +			trace_tipc_sk_dump(sk, skb, TIPC_DUMP_ALL, +					   "err_overload2!");  			atomic_inc(&sk->sk_drops);  			err = TIPC_ERR_OVERLOAD;  		}  		if (unlikely(err)) { -			tipc_skb_reject(net, err, skb, xmitq); +			if (tipc_msg_reverse(tipc_own_addr(net), &skb, err)) { +				trace_tipc_sk_rej_msg(sk, skb, TIPC_DUMP_NONE, +						      "@filter_rcv!"); +				__skb_queue_tail(xmitq, skb); +			}  			err = TIPC_OK;  			continue;  		}  		__skb_queue_tail(&sk->sk_receive_queue, skb);  		skb_set_owner_r(skb, sk); +		trace_tipc_sk_overlimit2(sk, skb, TIPC_DUMP_ALL, +					 "rcvq >90% allocated!");  		sk->sk_data_ready(sk);  	}  } @@ -2223,14 +2250,21 @@ static void tipc_sk_enqueue(struct sk_buff_head *inputq, struct sock *sk,  		if (!sk->sk_backlog.len)  			atomic_set(dcnt, 0);  		lim = rcvbuf_limit(sk, skb) + atomic_read(dcnt); -		if (likely(!sk_add_backlog(sk, skb, lim))) +		if (likely(!sk_add_backlog(sk, skb, lim))) { +			trace_tipc_sk_overlimit1(sk, skb, TIPC_DUMP_ALL, +						 "bklg & rcvq >90% allocated!");  			continue; +		} +		trace_tipc_sk_dump(sk, skb, TIPC_DUMP_ALL, "err_overload!");  		/* Overload => reject message back to sender */  		onode = tipc_own_addr(sock_net(sk));  		atomic_inc(&sk->sk_drops); -		if (tipc_msg_reverse(onode, &skb, TIPC_ERR_OVERLOAD)) +		if (tipc_msg_reverse(onode, &skb, TIPC_ERR_OVERLOAD)) { +			trace_tipc_sk_rej_msg(sk, skb, TIPC_DUMP_ALL, +					      "@sk_enqueue!");  			__skb_queue_tail(xmitq, skb); +		}  		break;  	}  } @@ -2279,6 +2313,8 @@ void tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq)  		/* Prepare for message rejection */  		if (!tipc_msg_reverse(tipc_own_addr(net), &skb, err))  			continue; + +		trace_tipc_sk_rej_msg(NULL, skb, TIPC_DUMP_NONE, "@sk_rcv!");  xmit:  		dnode = msg_destnode(buf_msg(skb));  		tipc_node_xmit_skb(net, skb, dnode, dport); @@ -2552,6 +2588,7 @@ static int tipc_shutdown(struct socket *sock, int how)  	lock_sock(sk); +	trace_tipc_sk_shutdown(sk, NULL, TIPC_DUMP_ALL, " ");  	__tipc_shutdown(sock, TIPC_CONN_SHUTDOWN);  	sk->sk_shutdown = SEND_SHUTDOWN; @@ -2724,11 +2761,15 @@ void tipc_sk_reinit(struct net *net)  		rhashtable_walk_start(&iter);  		while ((tsk = rhashtable_walk_next(&iter)) && !IS_ERR(tsk)) { -			spin_lock_bh(&tsk->sk.sk_lock.slock); +			sock_hold(&tsk->sk); +			rhashtable_walk_stop(&iter); +			lock_sock(&tsk->sk);  			msg = &tsk->phdr;  			msg_set_prevnode(msg, tipc_own_addr(net));  			msg_set_orignode(msg, tipc_own_addr(net)); -			spin_unlock_bh(&tsk->sk.sk_lock.slock); +			release_sock(&tsk->sk); +			rhashtable_walk_start(&iter); +			sock_put(&tsk->sk);  		}  		rhashtable_walk_stop(&iter); @@ -3564,3 +3605,187 @@ int tipc_nl_publ_dump(struct sk_buff *skb, struct netlink_callback *cb)  	return skb->len;  } + +/** + * tipc_sk_filtering - check if a socket should be traced + * @sk: the socket to be examined + * @sysctl_tipc_sk_filter[]: the socket tuple for filtering, + *  (portid, sock type, name type, name lower, name upper) + * + * Returns true if the socket meets the socket tuple data + * (value 0 = 'any') or when there is no tuple set (all = 0), + * otherwise false + */ +bool tipc_sk_filtering(struct sock *sk) +{ +	struct tipc_sock *tsk; +	struct publication *p; +	u32 _port, _sktype, _type, _lower, _upper; +	u32 type = 0, lower = 0, upper = 0; + +	if (!sk) +		return true; + +	tsk = tipc_sk(sk); + +	_port = sysctl_tipc_sk_filter[0]; +	_sktype = sysctl_tipc_sk_filter[1]; +	_type = sysctl_tipc_sk_filter[2]; +	_lower = sysctl_tipc_sk_filter[3]; +	_upper = sysctl_tipc_sk_filter[4]; + +	if (!_port && !_sktype && !_type && !_lower && !_upper) +		return true; + +	if (_port) +		return (_port == tsk->portid); + +	if (_sktype && _sktype != sk->sk_type) +		return false; + +	if (tsk->published) { +		p = list_first_entry_or_null(&tsk->publications, +					     struct publication, binding_sock); +		if (p) { +			type = p->type; +			lower = p->lower; +			upper = p->upper; +		} +	} + +	if (!tipc_sk_type_connectionless(sk)) { +		type = tsk->conn_type; +		lower = tsk->conn_instance; +		upper = tsk->conn_instance; +	} + +	if ((_type && _type != type) || (_lower && _lower != lower) || +	    (_upper && _upper != upper)) +		return false; + +	return true; +} + +u32 tipc_sock_get_portid(struct sock *sk) +{ +	return (sk) ? (tipc_sk(sk))->portid : 0; +} + +/** + * tipc_sk_overlimit1 - check if socket rx queue is about to be overloaded, + *			both the rcv and backlog queues are considered + * @sk: tipc sk to be checked + * @skb: tipc msg to be checked + * + * Returns true if the socket rx queue allocation is > 90%, otherwise false + */ + +bool tipc_sk_overlimit1(struct sock *sk, struct sk_buff *skb) +{ +	atomic_t *dcnt = &tipc_sk(sk)->dupl_rcvcnt; +	unsigned int lim = rcvbuf_limit(sk, skb) + atomic_read(dcnt); +	unsigned int qsize = sk->sk_backlog.len + sk_rmem_alloc_get(sk); + +	return (qsize > lim * 90 / 100); +} + +/** + * tipc_sk_overlimit2 - check if socket rx queue is about to be overloaded, + *			only the rcv queue is considered + * @sk: tipc sk to be checked + * @skb: tipc msg to be checked + * + * Returns true if the socket rx queue allocation is > 90%, otherwise false + */ + +bool tipc_sk_overlimit2(struct sock *sk, struct sk_buff *skb) +{ +	unsigned int lim = rcvbuf_limit(sk, skb); +	unsigned int qsize = sk_rmem_alloc_get(sk); + +	return (qsize > lim * 90 / 100); +} + +/** + * tipc_sk_dump - dump TIPC socket + * @sk: tipc sk to be dumped + * @dqueues: bitmask to decide if any socket queue to be dumped? + *           - TIPC_DUMP_NONE: don't dump socket queues + *           - TIPC_DUMP_SK_SNDQ: dump socket send queue + *           - TIPC_DUMP_SK_RCVQ: dump socket rcv queue + *           - TIPC_DUMP_SK_BKLGQ: dump socket backlog queue + *           - TIPC_DUMP_ALL: dump all the socket queues above + * @buf: returned buffer of dump data in format + */ +int tipc_sk_dump(struct sock *sk, u16 dqueues, char *buf) +{ +	int i = 0; +	size_t sz = (dqueues) ? SK_LMAX : SK_LMIN; +	struct tipc_sock *tsk; +	struct publication *p; +	bool tsk_connected; + +	if (!sk) { +		i += scnprintf(buf, sz, "sk data: (null)\n"); +		return i; +	} + +	tsk = tipc_sk(sk); +	tsk_connected = !tipc_sk_type_connectionless(sk); + +	i += scnprintf(buf, sz, "sk data: %u", sk->sk_type); +	i += scnprintf(buf + i, sz - i, " %d", sk->sk_state); +	i += scnprintf(buf + i, sz - i, " %x", tsk_own_node(tsk)); +	i += scnprintf(buf + i, sz - i, " %u", tsk->portid); +	i += scnprintf(buf + i, sz - i, " | %u", tsk_connected); +	if (tsk_connected) { +		i += scnprintf(buf + i, sz - i, " %x", tsk_peer_node(tsk)); +		i += scnprintf(buf + i, sz - i, " %u", tsk_peer_port(tsk)); +		i += scnprintf(buf + i, sz - i, " %u", tsk->conn_type); +		i += scnprintf(buf + i, sz - i, " %u", tsk->conn_instance); +	} +	i += scnprintf(buf + i, sz - i, " | %u", tsk->published); +	if (tsk->published) { +		p = list_first_entry_or_null(&tsk->publications, +					     struct publication, binding_sock); +		i += scnprintf(buf + i, sz - i, " %u", (p) ? p->type : 0); +		i += scnprintf(buf + i, sz - i, " %u", (p) ? p->lower : 0); +		i += scnprintf(buf + i, sz - i, " %u", (p) ? p->upper : 0); +	} +	i += scnprintf(buf + i, sz - i, " | %u", tsk->snd_win); +	i += scnprintf(buf + i, sz - i, " %u", tsk->rcv_win); +	i += scnprintf(buf + i, sz - i, " %u", tsk->max_pkt); +	i += scnprintf(buf + i, sz - i, " %x", tsk->peer_caps); +	i += scnprintf(buf + i, sz - i, " %u", tsk->cong_link_cnt); +	i += scnprintf(buf + i, sz - i, " %u", tsk->snt_unacked); +	i += scnprintf(buf + i, sz - i, " %u", tsk->rcv_unacked); +	i += scnprintf(buf + i, sz - i, " %u", atomic_read(&tsk->dupl_rcvcnt)); +	i += scnprintf(buf + i, sz - i, " %u", sk->sk_shutdown); +	i += scnprintf(buf + i, sz - i, " | %d", sk_wmem_alloc_get(sk)); +	i += scnprintf(buf + i, sz - i, " %d", sk->sk_sndbuf); +	i += scnprintf(buf + i, sz - i, " | %d", sk_rmem_alloc_get(sk)); +	i += scnprintf(buf + i, sz - i, " %d", sk->sk_rcvbuf); +	i += scnprintf(buf + i, sz - i, " | %d\n", sk->sk_backlog.len); + +	if (dqueues & TIPC_DUMP_SK_SNDQ) { +		i += scnprintf(buf + i, sz - i, "sk_write_queue: "); +		i += tipc_list_dump(&sk->sk_write_queue, false, buf + i); +	} + +	if (dqueues & TIPC_DUMP_SK_RCVQ) { +		i += scnprintf(buf + i, sz - i, "sk_receive_queue: "); +		i += tipc_list_dump(&sk->sk_receive_queue, false, buf + i); +	} + +	if (dqueues & TIPC_DUMP_SK_BKLGQ) { +		i += scnprintf(buf + i, sz - i, "sk_backlog:\n  head "); +		i += tipc_skb_dump(sk->sk_backlog.head, false, buf + i); +		if (sk->sk_backlog.tail != sk->sk_backlog.head) { +			i += scnprintf(buf + i, sz - i, "  tail "); +			i += tipc_skb_dump(sk->sk_backlog.tail, false, +					   buf + i); +		} +	} + +	return i; +} diff --git a/net/tipc/socket.h b/net/tipc/socket.h index 5e575f205afe..235b9679acee 100644 --- a/net/tipc/socket.h +++ b/net/tipc/socket.h @@ -71,4 +71,8 @@ int tipc_nl_sk_walk(struct sk_buff *skb, struct netlink_callback *cb,  int tipc_dump_start(struct netlink_callback *cb);  int __tipc_dump_start(struct netlink_callback *cb, struct net *net);  int tipc_dump_done(struct netlink_callback *cb); +u32 tipc_sock_get_portid(struct sock *sk); +bool tipc_sk_overlimit1(struct sock *sk, struct sk_buff *skb); +bool tipc_sk_overlimit2(struct sock *sk, struct sk_buff *skb); +  #endif diff --git a/net/tipc/sysctl.c b/net/tipc/sysctl.c index 1a779b1e8510..3481e4906bd6 100644 --- a/net/tipc/sysctl.c +++ b/net/tipc/sysctl.c @@ -34,6 +34,7 @@   */  #include "core.h" +#include "trace.h"  #include <linux/sysctl.h> @@ -54,6 +55,13 @@ static struct ctl_table tipc_table[] = {  		.mode		= 0644,  		.proc_handler	= proc_dointvec,  	}, +	{ +		.procname       = "sk_filter", +		.data           = &sysctl_tipc_sk_filter, +		.maxlen         = sizeof(sysctl_tipc_sk_filter), +		.mode           = 0644, +		.proc_handler   = proc_doulongvec_minmax, +	},  	{}  }; diff --git a/net/tipc/trace.c b/net/tipc/trace.c new file mode 100644 index 000000000000..964823841efe --- /dev/null +++ b/net/tipc/trace.c @@ -0,0 +1,206 @@ +/* + * net/tipc/trace.c: TIPC tracepoints code + * + * Copyright (c) 2018, Ericsson AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of its + *    contributors may be used to endorse or promote products derived from + *    this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "ASIS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define CREATE_TRACE_POINTS +#include "trace.h" + +/** + * socket tuples for filtering in socket traces: + * (portid, sock type, name type, name lower, name upper) + */ +unsigned long sysctl_tipc_sk_filter[5] __read_mostly = {0, }; + +/** + * tipc_skb_dump - dump TIPC skb data + * @skb: skb to be dumped + * @more: dump more? + *        - false: dump only tipc msg data + *        - true: dump kernel-related skb data and tipc cb[] array as well + * @buf: returned buffer of dump data in format + */ +int tipc_skb_dump(struct sk_buff *skb, bool more, char *buf) +{ +	int i = 0; +	size_t sz = (more) ? SKB_LMAX : SKB_LMIN; +	struct tipc_msg *hdr; +	struct tipc_skb_cb *skbcb; + +	if (!skb) { +		i += scnprintf(buf, sz, "msg: (null)\n"); +		return i; +	} + +	hdr = buf_msg(skb); +	skbcb = TIPC_SKB_CB(skb); + +	/* tipc msg data section */ +	i += scnprintf(buf, sz, "msg: %u", msg_user(hdr)); +	i += scnprintf(buf + i, sz - i, " %u", msg_type(hdr)); +	i += scnprintf(buf + i, sz - i, " %u", msg_hdr_sz(hdr)); +	i += scnprintf(buf + i, sz - i, " %u", msg_data_sz(hdr)); +	i += scnprintf(buf + i, sz - i, " %x", msg_orignode(hdr)); +	i += scnprintf(buf + i, sz - i, " %x", msg_destnode(hdr)); +	i += scnprintf(buf + i, sz - i, " %u", msg_seqno(hdr)); +	i += scnprintf(buf + i, sz - i, " %u", msg_ack(hdr)); +	i += scnprintf(buf + i, sz - i, " %u", msg_bcast_ack(hdr)); +	switch (msg_user(hdr)) { +	case LINK_PROTOCOL: +		i += scnprintf(buf + i, sz - i, " %c", msg_net_plane(hdr)); +		i += scnprintf(buf + i, sz - i, " %u", msg_probe(hdr)); +		i += scnprintf(buf + i, sz - i, " %u", msg_peer_stopping(hdr)); +		i += scnprintf(buf + i, sz - i, " %u", msg_session(hdr)); +		i += scnprintf(buf + i, sz - i, " %u", msg_next_sent(hdr)); +		i += scnprintf(buf + i, sz - i, " %u", msg_seq_gap(hdr)); +		i += scnprintf(buf + i, sz - i, " %u", msg_bc_snd_nxt(hdr)); +		i += scnprintf(buf + i, sz - i, " %u", msg_bc_gap(hdr)); +		break; +	case TIPC_LOW_IMPORTANCE: +	case TIPC_MEDIUM_IMPORTANCE: +	case TIPC_HIGH_IMPORTANCE: +	case TIPC_CRITICAL_IMPORTANCE: +	case CONN_MANAGER: +	case SOCK_WAKEUP: +		i += scnprintf(buf + i, sz - i, " | %u", msg_origport(hdr)); +		i += scnprintf(buf + i, sz - i, " %u", msg_destport(hdr)); +		switch (msg_type(hdr)) { +		case TIPC_NAMED_MSG: +			i += scnprintf(buf + i, sz - i, " %u", +				       msg_nametype(hdr)); +			i += scnprintf(buf + i, sz - i, " %u", +				       msg_nameinst(hdr)); +			break; +		case TIPC_MCAST_MSG: +			i += scnprintf(buf + i, sz - i, " %u", +				       msg_nametype(hdr)); +			i += scnprintf(buf + i, sz - i, " %u", +				       msg_namelower(hdr)); +			i += scnprintf(buf + i, sz - i, " %u", +				       msg_nameupper(hdr)); +			break; +		default: +			break; +		}; +		i += scnprintf(buf + i, sz - i, " | %u", +			       msg_src_droppable(hdr)); +		i += scnprintf(buf + i, sz - i, " %u", +			       msg_dest_droppable(hdr)); +		i += scnprintf(buf + i, sz - i, " %u", msg_errcode(hdr)); +		i += scnprintf(buf + i, sz - i, " %u", msg_reroute_cnt(hdr)); +		break; +	default: +		/* need more? */ +		break; +	}; + +	i += scnprintf(buf + i, sz - i, "\n"); +	if (!more) +		return i; + +	/* kernel-related skb data section */ +	i += scnprintf(buf + i, sz - i, "skb: %s", +		       (skb->dev) ? skb->dev->name : "n/a"); +	i += scnprintf(buf + i, sz - i, " %u", skb->len); +	i += scnprintf(buf + i, sz - i, " %u", skb->data_len); +	i += scnprintf(buf + i, sz - i, " %u", skb->hdr_len); +	i += scnprintf(buf + i, sz - i, " %u", skb->truesize); +	i += scnprintf(buf + i, sz - i, " %u", skb_cloned(skb)); +	i += scnprintf(buf + i, sz - i, " %p", skb->sk); +	i += scnprintf(buf + i, sz - i, " %u", skb_shinfo(skb)->nr_frags); +	i += scnprintf(buf + i, sz - i, " %llx", +		       ktime_to_ms(skb_get_ktime(skb))); +	i += scnprintf(buf + i, sz - i, " %llx\n", +		       ktime_to_ms(skb_hwtstamps(skb)->hwtstamp)); + +	/* tipc skb cb[] data section */ +	i += scnprintf(buf + i, sz - i, "cb[]: %u", skbcb->bytes_read); +	i += scnprintf(buf + i, sz - i, " %u", skbcb->orig_member); +	i += scnprintf(buf + i, sz - i, " %u", +		       jiffies_to_msecs(skbcb->nxt_retr)); +	i += scnprintf(buf + i, sz - i, " %u", skbcb->validated); +	i += scnprintf(buf + i, sz - i, " %u", skbcb->chain_imp); +	i += scnprintf(buf + i, sz - i, " %u\n", skbcb->ackers); + +	return i; +} + +/** + * tipc_list_dump - dump TIPC skb list/queue + * @list: list of skbs to be dumped + * @more: dump more? + *        - false: dump only the head & tail skbs + *        - true: dump the first & last 5 skbs + * @buf: returned buffer of dump data in format + */ +int tipc_list_dump(struct sk_buff_head *list, bool more, char *buf) +{ +	int i = 0; +	size_t sz = (more) ? LIST_LMAX : LIST_LMIN; +	u32 count, len; +	struct sk_buff *hskb, *tskb, *skb, *tmp; + +	if (!list) { +		i += scnprintf(buf, sz, "(null)\n"); +		return i; +	} + +	len = skb_queue_len(list); +	i += scnprintf(buf, sz, "len = %d\n", len); + +	if (!len) +		return i; + +	if (!more) { +		hskb = skb_peek(list); +		i += scnprintf(buf + i, sz - i, "  head "); +		i += tipc_skb_dump(hskb, false, buf + i); +		if (len > 1) { +			tskb = skb_peek_tail(list); +			i += scnprintf(buf + i, sz - i, "  tail "); +			i += tipc_skb_dump(tskb, false, buf + i); +		} +	} else { +		count = 0; +		skb_queue_walk_safe(list, skb, tmp) { +			count++; +			if (count == 6) +				i += scnprintf(buf + i, sz - i, "  .\n  .\n"); +			if (count > 5 && count <= len - 5) +				continue; +			i += scnprintf(buf + i, sz - i, "  #%d ", count); +			i += tipc_skb_dump(skb, false, buf + i); +		} +	} +	return i; +} diff --git a/net/tipc/trace.h b/net/tipc/trace.h new file mode 100644 index 000000000000..4d8e00483afc --- /dev/null +++ b/net/tipc/trace.h @@ -0,0 +1,431 @@ +/* + * net/tipc/trace.h: TIPC tracepoints + * + * Copyright (c) 2018, Ericsson AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of its + *    contributors may be used to endorse or promote products derived from + *    this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "ASIS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM tipc + +#if !defined(_TIPC_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TIPC_TRACE_H + +#include <linux/tracepoint.h> +#include "core.h" +#include "link.h" +#include "socket.h" +#include "node.h" + +#define SKB_LMIN	(100) +#define SKB_LMAX	(SKB_LMIN * 2) +#define LIST_LMIN	(SKB_LMIN * 3) +#define LIST_LMAX	(SKB_LMIN * 11) +#define SK_LMIN		(SKB_LMIN * 2) +#define SK_LMAX		(SKB_LMIN * 11) +#define LINK_LMIN	(SKB_LMIN) +#define LINK_LMAX	(SKB_LMIN * 16) +#define NODE_LMIN	(SKB_LMIN) +#define NODE_LMAX	(SKB_LMIN * 11) + +#ifndef __TIPC_TRACE_ENUM +#define __TIPC_TRACE_ENUM +enum { +	TIPC_DUMP_NONE		= 0, + +	TIPC_DUMP_TRANSMQ	= 1, +	TIPC_DUMP_BACKLOGQ	= (1 << 1), +	TIPC_DUMP_DEFERDQ	= (1 << 2), +	TIPC_DUMP_INPUTQ	= (1 << 3), +	TIPC_DUMP_WAKEUP        = (1 << 4), + +	TIPC_DUMP_SK_SNDQ	= (1 << 8), +	TIPC_DUMP_SK_RCVQ	= (1 << 9), +	TIPC_DUMP_SK_BKLGQ	= (1 << 10), +	TIPC_DUMP_ALL		= 0xffffu +}; +#endif + +/* Link & Node FSM states: */ +#define state_sym(val)							  \ +	__print_symbolic(val,						  \ +			{(0xe),		"ESTABLISHED"			},\ +			{(0xe << 4),	"ESTABLISHING"			},\ +			{(0x1 << 8),	"RESET"				},\ +			{(0x2 << 12),	"RESETTING"			},\ +			{(0xd << 16),	"PEER_RESET"			},\ +			{(0xf << 20),	"FAILINGOVER"			},\ +			{(0xc << 24),	"SYNCHING"			},\ +			{(0xdd),	"SELF_DOWN_PEER_DOWN"		},\ +			{(0xaa),	"SELF_UP_PEER_UP"		},\ +			{(0xd1),	"SELF_DOWN_PEER_LEAVING"	},\ +			{(0xac),	"SELF_UP_PEER_COMING"		},\ +			{(0xca),	"SELF_COMING_PEER_UP"		},\ +			{(0x1d),	"SELF_LEAVING_PEER_DOWN"	},\ +			{(0xf0),	"FAILINGOVER"			},\ +			{(0xcc),	"SYNCHING"			}) + +/* Link & Node FSM events: */ +#define evt_sym(val)							  \ +	__print_symbolic(val,						  \ +			{(0xec1ab1e),	"ESTABLISH_EVT"			},\ +			{(0x9eed0e),	"PEER_RESET_EVT"		},\ +			{(0xfa110e),	"FAILURE_EVT"			},\ +			{(0x10ca1d0e),	"RESET_EVT"			},\ +			{(0xfa110bee),	"FAILOVER_BEGIN_EVT"		},\ +			{(0xfa110ede),	"FAILOVER_END_EVT"		},\ +			{(0xc1ccbee),	"SYNCH_BEGIN_EVT"		},\ +			{(0xc1ccede),	"SYNCH_END_EVT"			},\ +			{(0xece),	"SELF_ESTABL_CONTACT_EVT"	},\ +			{(0x1ce),	"SELF_LOST_CONTACT_EVT"		},\ +			{(0x9ece),	"PEER_ESTABL_CONTACT_EVT"	},\ +			{(0x91ce),	"PEER_LOST_CONTACT_EVT"		},\ +			{(0xfbe),	"FAILOVER_BEGIN_EVT"		},\ +			{(0xfee),	"FAILOVER_END_EVT"		},\ +			{(0xcbe),	"SYNCH_BEGIN_EVT"		},\ +			{(0xcee),	"SYNCH_END_EVT"			}) + +/* Bearer, net device events: */ +#define dev_evt_sym(val)						  \ +	__print_symbolic(val,						  \ +			{(NETDEV_CHANGE),	"NETDEV_CHANGE"		},\ +			{(NETDEV_GOING_DOWN),	"NETDEV_GOING_DOWN"	},\ +			{(NETDEV_UP),		"NETDEV_UP"		},\ +			{(NETDEV_CHANGEMTU),	"NETDEV_CHANGEMTU"	},\ +			{(NETDEV_CHANGEADDR),	"NETDEV_CHANGEADDR"	},\ +			{(NETDEV_UNREGISTER),	"NETDEV_UNREGISTER"	},\ +			{(NETDEV_CHANGENAME),	"NETDEV_CHANGENAME"	}) + +extern unsigned long sysctl_tipc_sk_filter[5] __read_mostly; + +int tipc_skb_dump(struct sk_buff *skb, bool more, char *buf); +int tipc_list_dump(struct sk_buff_head *list, bool more, char *buf); +int tipc_sk_dump(struct sock *sk, u16 dqueues, char *buf); +int tipc_link_dump(struct tipc_link *l, u16 dqueues, char *buf); +int tipc_node_dump(struct tipc_node *n, bool more, char *buf); +bool tipc_sk_filtering(struct sock *sk); + +DECLARE_EVENT_CLASS(tipc_skb_class, + +	TP_PROTO(struct sk_buff *skb, bool more, const char *header), + +	TP_ARGS(skb, more, header), + +	TP_STRUCT__entry( +		__string(header, header) +		__dynamic_array(char, buf, (more) ? SKB_LMAX : SKB_LMIN) +	), + +	TP_fast_assign( +		__assign_str(header, header); +		tipc_skb_dump(skb, more, __get_str(buf)); +	), + +	TP_printk("%s\n%s", __get_str(header), __get_str(buf)) +) + +#define DEFINE_SKB_EVENT(name) \ +DEFINE_EVENT(tipc_skb_class, name, \ +	TP_PROTO(struct sk_buff *skb, bool more, const char *header), \ +	TP_ARGS(skb, more, header)) +DEFINE_SKB_EVENT(tipc_skb_dump); +DEFINE_SKB_EVENT(tipc_proto_build); +DEFINE_SKB_EVENT(tipc_proto_rcv); + +DECLARE_EVENT_CLASS(tipc_list_class, + +	TP_PROTO(struct sk_buff_head *list, bool more, const char *header), + +	TP_ARGS(list, more, header), + +	TP_STRUCT__entry( +		__string(header, header) +		__dynamic_array(char, buf, (more) ? LIST_LMAX : LIST_LMIN) +	), + +	TP_fast_assign( +		__assign_str(header, header); +		tipc_list_dump(list, more, __get_str(buf)); +	), + +	TP_printk("%s\n%s", __get_str(header), __get_str(buf)) +); + +#define DEFINE_LIST_EVENT(name) \ +DEFINE_EVENT(tipc_list_class, name, \ +	TP_PROTO(struct sk_buff_head *list, bool more, const char *header), \ +	TP_ARGS(list, more, header)) +DEFINE_LIST_EVENT(tipc_list_dump); + +DECLARE_EVENT_CLASS(tipc_sk_class, + +	TP_PROTO(struct sock *sk, struct sk_buff *skb, u16 dqueues, +		 const char *header), + +	TP_ARGS(sk, skb, dqueues, header), + +	TP_STRUCT__entry( +		__string(header, header) +		__field(u32, portid) +		__dynamic_array(char, buf, (dqueues) ? SK_LMAX : SK_LMIN) +		__dynamic_array(char, skb_buf, (skb) ? SKB_LMIN : 1) +	), + +	TP_fast_assign( +		__assign_str(header, header); +		__entry->portid = tipc_sock_get_portid(sk); +		tipc_sk_dump(sk, dqueues, __get_str(buf)); +		if (skb) +			tipc_skb_dump(skb, false, __get_str(skb_buf)); +		else +			*(__get_str(skb_buf)) = '\0'; +	), + +	TP_printk("<%u> %s\n%s%s", __entry->portid, __get_str(header), +		  __get_str(skb_buf), __get_str(buf)) +); + +#define DEFINE_SK_EVENT_FILTER(name) \ +DEFINE_EVENT_CONDITION(tipc_sk_class, name, \ +	TP_PROTO(struct sock *sk, struct sk_buff *skb, u16 dqueues, \ +		 const char *header), \ +	TP_ARGS(sk, skb, dqueues, header), \ +	TP_CONDITION(tipc_sk_filtering(sk))) +DEFINE_SK_EVENT_FILTER(tipc_sk_dump); +DEFINE_SK_EVENT_FILTER(tipc_sk_create); +DEFINE_SK_EVENT_FILTER(tipc_sk_sendmcast); +DEFINE_SK_EVENT_FILTER(tipc_sk_sendmsg); +DEFINE_SK_EVENT_FILTER(tipc_sk_sendstream); +DEFINE_SK_EVENT_FILTER(tipc_sk_poll); +DEFINE_SK_EVENT_FILTER(tipc_sk_filter_rcv); +DEFINE_SK_EVENT_FILTER(tipc_sk_advance_rx); +DEFINE_SK_EVENT_FILTER(tipc_sk_rej_msg); +DEFINE_SK_EVENT_FILTER(tipc_sk_drop_msg); +DEFINE_SK_EVENT_FILTER(tipc_sk_release); +DEFINE_SK_EVENT_FILTER(tipc_sk_shutdown); + +#define DEFINE_SK_EVENT_FILTER_COND(name, cond) \ +DEFINE_EVENT_CONDITION(tipc_sk_class, name, \ +	TP_PROTO(struct sock *sk, struct sk_buff *skb, u16 dqueues, \ +		 const char *header), \ +	TP_ARGS(sk, skb, dqueues, header), \ +	TP_CONDITION(tipc_sk_filtering(sk) && (cond))) +DEFINE_SK_EVENT_FILTER_COND(tipc_sk_overlimit1, tipc_sk_overlimit1(sk, skb)); +DEFINE_SK_EVENT_FILTER_COND(tipc_sk_overlimit2, tipc_sk_overlimit2(sk, skb)); + +DECLARE_EVENT_CLASS(tipc_link_class, + +	TP_PROTO(struct tipc_link *l, u16 dqueues, const char *header), + +	TP_ARGS(l, dqueues, header), + +	TP_STRUCT__entry( +		__string(header, header) +		__array(char, name, TIPC_MAX_LINK_NAME) +		__dynamic_array(char, buf, (dqueues) ? LINK_LMAX : LINK_LMIN) +	), + +	TP_fast_assign( +		__assign_str(header, header); +		tipc_link_name_ext(l, __entry->name); +		tipc_link_dump(l, dqueues, __get_str(buf)); +	), + +	TP_printk("<%s> %s\n%s", __entry->name, __get_str(header), +		  __get_str(buf)) +); + +#define DEFINE_LINK_EVENT(name) \ +DEFINE_EVENT(tipc_link_class, name, \ +	TP_PROTO(struct tipc_link *l, u16 dqueues, const char *header), \ +	TP_ARGS(l, dqueues, header)) +DEFINE_LINK_EVENT(tipc_link_dump); +DEFINE_LINK_EVENT(tipc_link_conges); +DEFINE_LINK_EVENT(tipc_link_timeout); +DEFINE_LINK_EVENT(tipc_link_reset); + +#define DEFINE_LINK_EVENT_COND(name, cond) \ +DEFINE_EVENT_CONDITION(tipc_link_class, name, \ +	TP_PROTO(struct tipc_link *l, u16 dqueues, const char *header), \ +	TP_ARGS(l, dqueues, header), \ +	TP_CONDITION(cond)) +DEFINE_LINK_EVENT_COND(tipc_link_too_silent, tipc_link_too_silent(l)); + +DECLARE_EVENT_CLASS(tipc_link_transmq_class, + +	TP_PROTO(struct tipc_link *r, u16 f, u16 t, struct sk_buff_head *tq), + +	TP_ARGS(r, f, t, tq), + +	TP_STRUCT__entry( +		__array(char, name, TIPC_MAX_LINK_NAME) +		__field(u16, from) +		__field(u16, to) +		__field(u32, len) +		__field(u16, fseqno) +		__field(u16, lseqno) +	), + +	TP_fast_assign( +		tipc_link_name_ext(r, __entry->name); +		__entry->from = f; +		__entry->to = t; +		__entry->len = skb_queue_len(tq); +		__entry->fseqno = msg_seqno(buf_msg(skb_peek(tq))); +		__entry->lseqno = msg_seqno(buf_msg(skb_peek_tail(tq))); +	), + +	TP_printk("<%s> retrans req: [%u-%u] transmq: %u [%u-%u]\n", +		  __entry->name, __entry->from, __entry->to, +		  __entry->len, __entry->fseqno, __entry->lseqno) +); + +DEFINE_EVENT(tipc_link_transmq_class, tipc_link_retrans, +	TP_PROTO(struct tipc_link *r, u16 f, u16 t, struct sk_buff_head *tq), +	TP_ARGS(r, f, t, tq) +); + +DEFINE_EVENT_PRINT(tipc_link_transmq_class, tipc_link_bc_ack, +	TP_PROTO(struct tipc_link *r, u16 f, u16 t, struct sk_buff_head *tq), +	TP_ARGS(r, f, t, tq), +	TP_printk("<%s> acked: [%u-%u] transmq: %u [%u-%u]\n", +		  __entry->name, __entry->from, __entry->to, +		  __entry->len, __entry->fseqno, __entry->lseqno) +); + +DECLARE_EVENT_CLASS(tipc_node_class, + +	TP_PROTO(struct tipc_node *n, bool more, const char *header), + +	TP_ARGS(n, more, header), + +	TP_STRUCT__entry( +		__string(header, header) +		__field(u32, addr) +		__dynamic_array(char, buf, (more) ? NODE_LMAX : NODE_LMIN) +	), + +	TP_fast_assign( +		__assign_str(header, header); +		__entry->addr = tipc_node_get_addr(n); +		tipc_node_dump(n, more, __get_str(buf)); +	), + +	TP_printk("<%x> %s\n%s", __entry->addr, __get_str(header), +		  __get_str(buf)) +); + +#define DEFINE_NODE_EVENT(name) \ +DEFINE_EVENT(tipc_node_class, name, \ +	TP_PROTO(struct tipc_node *n, bool more, const char *header), \ +	TP_ARGS(n, more, header)) +DEFINE_NODE_EVENT(tipc_node_dump); +DEFINE_NODE_EVENT(tipc_node_create); +DEFINE_NODE_EVENT(tipc_node_delete); +DEFINE_NODE_EVENT(tipc_node_lost_contact); +DEFINE_NODE_EVENT(tipc_node_timeout); +DEFINE_NODE_EVENT(tipc_node_link_up); +DEFINE_NODE_EVENT(tipc_node_link_down); +DEFINE_NODE_EVENT(tipc_node_reset_links); +DEFINE_NODE_EVENT(tipc_node_check_state); + +DECLARE_EVENT_CLASS(tipc_fsm_class, + +	TP_PROTO(const char *name, u32 os, u32 ns, int evt), + +	TP_ARGS(name, os, ns, evt), + +	TP_STRUCT__entry( +		__string(name, name) +		__field(u32, os) +		__field(u32, ns) +		__field(u32, evt) +	), + +	TP_fast_assign( +		__assign_str(name, name); +		__entry->os = os; +		__entry->ns = ns; +		__entry->evt = evt; +	), + +	TP_printk("<%s> %s--(%s)->%s\n", __get_str(name), +		  state_sym(__entry->os), evt_sym(__entry->evt), +		  state_sym(__entry->ns)) +); + +#define DEFINE_FSM_EVENT(fsm_name) \ +DEFINE_EVENT(tipc_fsm_class, fsm_name, \ +	TP_PROTO(const char *name, u32 os, u32 ns, int evt), \ +	TP_ARGS(name, os, ns, evt)) +DEFINE_FSM_EVENT(tipc_link_fsm); +DEFINE_FSM_EVENT(tipc_node_fsm); + +TRACE_EVENT(tipc_l2_device_event, + +	TP_PROTO(struct net_device *dev, struct tipc_bearer *b, +		 unsigned long evt), + +	TP_ARGS(dev, b, evt), + +	TP_STRUCT__entry( +		__string(dev_name, dev->name) +		__string(b_name, b->name) +		__field(unsigned long, evt) +		__field(u8, b_up) +		__field(u8, carrier) +		__field(u8, oper) +	), + +	TP_fast_assign( +		__assign_str(dev_name, dev->name); +		__assign_str(b_name, b->name); +		__entry->evt = evt; +		__entry->b_up = test_bit(0, &b->up); +		__entry->carrier = netif_carrier_ok(dev); +		__entry->oper = netif_oper_up(dev); +	), + +	TP_printk("%s on: <%s>/<%s> oper: %s carrier: %s bearer: %s\n", +		  dev_evt_sym(__entry->evt), __get_str(dev_name), +		  __get_str(b_name), (__entry->oper) ? "up" : "down", +		  (__entry->carrier) ? "ok" : "notok", +		  (__entry->b_up) ? "up" : "down") +); + +#endif /* _TIPC_TRACE_H */ + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace +#include <trace/define_trace.h> diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c index 10dc59ce9c82..4d85d71f16e2 100644 --- a/net/tipc/udp_media.c +++ b/net/tipc/udp_media.c @@ -245,10 +245,8 @@ static int tipc_udp_send_msg(struct net *net, struct sk_buff *skb,  		}  		err = tipc_udp_xmit(net, _skb, ub, src, &rcast->addr); -		if (err) { -			kfree_skb(_skb); +		if (err)  			goto out; -		}  	}  	err = 0;  out: @@ -681,6 +679,11 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,  	if (err)  		goto err; +	if (remote.proto != local.proto) { +		err = -EINVAL; +		goto err; +	} +  	/* Checking remote ip address */  	rmcast = tipc_udp_is_mcast_addr(&remote); | 
