Commit 03b6fefd authored by Tuong Lien's avatar Tuong Lien Committed by David S. Miller
Browse files

tipc: add support for broadcast rcv stats dumping



This commit enables dumping the statistics of a broadcast-receiver link
like the traditional 'broadcast-link' one (which is for broadcast-
sender). The link dumping can be triggered via netlink (e.g. the
iproute2/tipc tool) by the link flag - 'TIPC_NLA_LINK_BROADCAST' as the
indicator.

The name of a broadcast-receiver link of a specific peer will be in the
format: 'broadcast-link:<peer-id>'.

For example:

Link <broadcast-link:1001002>
  Window:50 packets
  RX packets:7841 fragments:2408/440 bundles:0/0
  TX packets:0 fragments:0/0 bundles:0/0
  RX naks:0 defs:124 dups:0
  TX naks:21 acks:0 retrans:0
  Congestion link:0  Send queue max:0 avg:0

In addition, the broadcast-receiver link statistics can be reset in the
usual way via netlink by specifying that link name in command.

Note: the 'tipc_link_name_ext()' is removed because the link name can
now be retrieved simply via the 'l->name'.

Acked-by: default avatarYing Xue <ying.xue@windriver.com>
Acked-by: default avatarJon Maloy <jmaloy@redhat.com>
Signed-off-by: default avatarTuong Lien <tuong.t.lien@dektech.com.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a91d55d1
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -563,10 +563,8 @@ void tipc_bcast_remove_peer(struct net *net, struct tipc_link *rcv_l)
		tipc_sk_rcv(net, inputq);
}

int tipc_bclink_reset_stats(struct net *net)
int tipc_bclink_reset_stats(struct net *net, struct tipc_link *l)
{
	struct tipc_link *l = tipc_bc_sndlink(net);

	if (!l)
		return -ENOPROTOOPT;

@@ -694,7 +692,7 @@ int tipc_bcast_init(struct net *net)
	tn->bcbase = bb;
	spin_lock_init(&tipc_net(net)->bclock);

	if (!tipc_link_bc_create(net, 0, 0,
	if (!tipc_link_bc_create(net, 0, 0, NULL,
				 FB_MTU,
				 BCLINK_WIN_DEFAULT,
				 BCLINK_WIN_DEFAULT,
+3 −2
Original line number Diff line number Diff line
@@ -96,9 +96,10 @@ void tipc_bcast_ack_rcv(struct net *net, struct tipc_link *l,
int tipc_bcast_sync_rcv(struct net *net, struct tipc_link *l,
			struct tipc_msg *hdr,
			struct sk_buff_head *retrq);
int tipc_nl_add_bc_link(struct net *net, struct tipc_nl_msg *msg);
int tipc_nl_add_bc_link(struct net *net, struct tipc_nl_msg *msg,
			struct tipc_link *bcl);
int tipc_nl_bc_link_set(struct net *net, struct nlattr *attrs[]);
int tipc_bclink_reset_stats(struct net *net);
int tipc_bclink_reset_stats(struct net *net, struct tipc_link *l);

u32 tipc_bcast_get_broadcast_mode(struct net *net);
u32 tipc_bcast_get_broadcast_ratio(struct net *net);
+33 −32
Original line number Diff line number Diff line
@@ -539,7 +539,7 @@ bool tipc_link_create(struct net *net, char *if_name, int bearer_id,
 *
 * Returns true if link was created, otherwise false
 */
bool tipc_link_bc_create(struct net *net, u32 ownnode, u32 peer,
bool tipc_link_bc_create(struct net *net, u32 ownnode, u32 peer, u8 *peer_id,
			 int mtu, u32 min_win, u32 max_win, u16 peer_caps,
			 struct sk_buff_head *inputq,
			 struct sk_buff_head *namedq,
@@ -554,7 +554,18 @@ bool tipc_link_bc_create(struct net *net, u32 ownnode, u32 peer,
		return false;

	l = *link;
	if (peer_id) {
		char peer_str[NODE_ID_STR_LEN] = {0,};

		tipc_nodeid2string(peer_str, peer_id);
		if (strlen(peer_str) > 16)
			sprintf(peer_str, "%x", peer);
		/* Broadcast receiver link name: "broadcast-link:<peer>" */
		snprintf(l->name, sizeof(l->name), "%s:%s", tipc_bclink_name,
			 peer_str);
	} else {
		strcpy(l->name, tipc_bclink_name);
	}
	trace_tipc_link_reset(l, TIPC_DUMP_ALL, "bclink created!");
	tipc_link_reset(l);
	l->state = LINK_RESET;
@@ -1412,11 +1423,8 @@ static u8 __tipc_build_gap_ack_blks(struct tipc_gap_ack_blks *ga,
			gacks[n].ack = htons(expect - 1);
			gacks[n].gap = htons(seqno - expect);
			if (++n >= MAX_GAP_ACK_BLKS / 2) {
				char buf[TIPC_MAX_LINK_NAME];

				pr_info_ratelimited("Gacks on %s: %d, ql: %d!\n",
						    tipc_link_name_ext(l, buf),
						    n,
						    l->name, n,
						    skb_queue_len(&l->deferdq));
				return n;
			}
@@ -1587,6 +1595,8 @@ release:
			_skb->priority = TC_PRIO_CONTROL;
			__skb_queue_tail(xmitq, _skb);
			l->stats.retransmitted++;
			if (!is_uc)
				r->stats.retransmitted++;
			*retransmitted = true;
			/* Increase actual retrans counter & mark first time */
			if (!TIPC_SKB_CB(skb)->retr_cnt++)
@@ -1753,7 +1763,8 @@ int tipc_link_rcv(struct tipc_link *l, struct sk_buff *skb,

		/* Defer delivery if sequence gap */
		if (unlikely(seqno != rcv_nxt)) {
			__tipc_skb_queue_sorted(defq, seqno, skb);
			if (!__tipc_skb_queue_sorted(defq, seqno, skb))
				l->stats.duplicates++;
			rc |= tipc_link_build_nack_msg(l, xmitq);
			break;
		}
@@ -1787,15 +1798,15 @@ static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe,
				      int tolerance, int priority,
				      struct sk_buff_head *xmitq)
{
	struct tipc_mon_state *mstate = &l->mon_state;
	struct sk_buff_head *dfq = &l->deferdq;
	struct tipc_link *bcl = l->bc_rcvlink;
	struct sk_buff *skb;
	struct tipc_msg *hdr;
	struct sk_buff_head *dfq = &l->deferdq;
	struct sk_buff *skb;
	bool node_up = link_is_up(bcl);
	struct tipc_mon_state *mstate = &l->mon_state;
	u16 glen = 0, bc_rcvgap = 0;
	int dlen = 0;
	void *data;
	u16 glen = 0;

	/* Don't send protocol message during reset or link failover */
	if (tipc_link_is_blocked(l))
@@ -1833,7 +1844,8 @@ static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe,
		if (l->peer_caps & TIPC_LINK_PROTO_SEQNO)
			msg_set_seqno(hdr, l->snd_nxt_state++);
		msg_set_seq_gap(hdr, rcvgap);
		msg_set_bc_gap(hdr, link_bc_rcv_gap(bcl));
		bc_rcvgap = link_bc_rcv_gap(bcl);
		msg_set_bc_gap(hdr, bc_rcvgap);
		msg_set_probe(hdr, probe);
		msg_set_is_keepalive(hdr, probe || probe_reply);
		if (l->peer_caps & TIPC_GAP_ACK_BLOCK)
@@ -1858,6 +1870,8 @@ static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe,
		l->stats.sent_probes++;
	if (rcvgap)
		l->stats.sent_nacks++;
	if (bc_rcvgap)
		bcl->stats.sent_nacks++;
	skb->priority = TC_PRIO_CONTROL;
	__skb_queue_tail(xmitq, skb);
	trace_tipc_proto_build(skb, false, l->name);
@@ -2358,8 +2372,6 @@ int tipc_link_bc_sync_rcv(struct tipc_link *l, struct tipc_msg *hdr,
	if (!l->bc_peer_is_up)
		return rc;

	l->stats.recv_nacks++;

	/* Ignore if peers_snd_nxt goes beyond receive window */
	if (more(peers_snd_nxt, l->rcv_nxt + l->window))
		return rc;
@@ -2410,6 +2422,11 @@ int tipc_link_bc_ack_rcv(struct tipc_link *r, u16 acked, u16 gap,
	if (!link_is_up(r) || !r->bc_peer_is_up)
		return 0;

	if (gap) {
		l->stats.recv_nacks++;
		r->stats.recv_nacks++;
	}

	if (less(acked, r->acked) || (acked == r->acked && !gap && !ga))
		return 0;

@@ -2721,16 +2738,15 @@ msg_full:
	return -EMSGSIZE;
}

int tipc_nl_add_bc_link(struct net *net, struct tipc_nl_msg *msg)
int tipc_nl_add_bc_link(struct net *net, struct tipc_nl_msg *msg,
			struct tipc_link *bcl)
{
	int err;
	void *hdr;
	struct nlattr *attrs;
	struct nlattr *prop;
	struct tipc_net *tn = net_generic(net, tipc_net_id);
	u32 bc_mode = tipc_bcast_get_broadcast_mode(net);
	u32 bc_ratio = tipc_bcast_get_broadcast_ratio(net);
	struct tipc_link *bcl = tn->bcl;

	if (!bcl)
		return 0;
@@ -2817,21 +2833,6 @@ 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
+1 −2
Original line number Diff line number Diff line
@@ -80,7 +80,7 @@ bool tipc_link_create(struct net *net, char *if_name, int bearer_id,
		      struct sk_buff_head *inputq,
		      struct sk_buff_head *namedq,
		      struct tipc_link **link);
bool tipc_link_bc_create(struct net *net, u32 ownnode, u32 peer,
bool tipc_link_bc_create(struct net *net, u32 ownnode, u32 peer, u8 *peer_id,
			 int mtu, u32 min_win, u32 max_win, u16 peer_caps,
			 struct sk_buff_head *inputq,
			 struct sk_buff_head *namedq,
@@ -111,7 +111,6 @@ 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);
+5 −4
Original line number Diff line number Diff line
@@ -825,19 +825,19 @@ bool tipc_msg_pskb_copy(u32 dst, struct sk_buff_head *msg,
 * @seqno: sequence number of buffer to add
 * @skb: buffer to add
 */
void __tipc_skb_queue_sorted(struct sk_buff_head *list, u16 seqno,
bool __tipc_skb_queue_sorted(struct sk_buff_head *list, u16 seqno,
			     struct sk_buff *skb)
{
	struct sk_buff *_skb, *tmp;

	if (skb_queue_empty(list) || less(seqno, buf_seqno(skb_peek(list)))) {
		__skb_queue_head(list, skb);
		return;
		return true;
	}

	if (more(seqno, buf_seqno(skb_peek_tail(list)))) {
		__skb_queue_tail(list, skb);
		return;
		return true;
	}

	skb_queue_walk_safe(list, _skb, tmp) {
@@ -846,9 +846,10 @@ void __tipc_skb_queue_sorted(struct sk_buff_head *list, u16 seqno,
		if (seqno == buf_seqno(_skb))
			break;
		__skb_queue_before(list, _skb, skb);
		return;
		return true;
	}
	kfree_skb(skb);
	return false;
}

void tipc_skb_reject(struct net *net, int err, struct sk_buff *skb,
Loading