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

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
...@@ -563,10 +563,8 @@ void tipc_bcast_remove_peer(struct net *net, struct tipc_link *rcv_l) ...@@ -563,10 +563,8 @@ void tipc_bcast_remove_peer(struct net *net, struct tipc_link *rcv_l)
tipc_sk_rcv(net, inputq); 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) if (!l)
return -ENOPROTOOPT; return -ENOPROTOOPT;
...@@ -694,7 +692,7 @@ int tipc_bcast_init(struct net *net) ...@@ -694,7 +692,7 @@ int tipc_bcast_init(struct net *net)
tn->bcbase = bb; tn->bcbase = bb;
spin_lock_init(&tipc_net(net)->bclock); 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, FB_MTU,
BCLINK_WIN_DEFAULT, BCLINK_WIN_DEFAULT,
BCLINK_WIN_DEFAULT, BCLINK_WIN_DEFAULT,
......
...@@ -96,9 +96,10 @@ void tipc_bcast_ack_rcv(struct net *net, struct tipc_link *l, ...@@ -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, int tipc_bcast_sync_rcv(struct net *net, struct tipc_link *l,
struct tipc_msg *hdr, struct tipc_msg *hdr,
struct sk_buff_head *retrq); 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_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_mode(struct net *net);
u32 tipc_bcast_get_broadcast_ratio(struct net *net); u32 tipc_bcast_get_broadcast_ratio(struct net *net);
......
...@@ -539,7 +539,7 @@ bool tipc_link_create(struct net *net, char *if_name, int bearer_id, ...@@ -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 * 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, int mtu, u32 min_win, u32 max_win, u16 peer_caps,
struct sk_buff_head *inputq, struct sk_buff_head *inputq,
struct sk_buff_head *namedq, struct sk_buff_head *namedq,
...@@ -554,7 +554,18 @@ bool tipc_link_bc_create(struct net *net, u32 ownnode, u32 peer, ...@@ -554,7 +554,18 @@ bool tipc_link_bc_create(struct net *net, u32 ownnode, u32 peer,
return false; return false;
l = *link; l = *link;
strcpy(l->name, tipc_bclink_name); 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!"); trace_tipc_link_reset(l, TIPC_DUMP_ALL, "bclink created!");
tipc_link_reset(l); tipc_link_reset(l);
l->state = LINK_RESET; l->state = LINK_RESET;
...@@ -1412,11 +1423,8 @@ static u8 __tipc_build_gap_ack_blks(struct tipc_gap_ack_blks *ga, ...@@ -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].ack = htons(expect - 1);
gacks[n].gap = htons(seqno - expect); gacks[n].gap = htons(seqno - expect);
if (++n >= MAX_GAP_ACK_BLKS / 2) { if (++n >= MAX_GAP_ACK_BLKS / 2) {
char buf[TIPC_MAX_LINK_NAME];
pr_info_ratelimited("Gacks on %s: %d, ql: %d!\n", pr_info_ratelimited("Gacks on %s: %d, ql: %d!\n",
tipc_link_name_ext(l, buf), l->name, n,
n,
skb_queue_len(&l->deferdq)); skb_queue_len(&l->deferdq));
return n; return n;
} }
...@@ -1587,6 +1595,8 @@ static int tipc_link_advance_transmq(struct tipc_link *l, struct tipc_link *r, ...@@ -1587,6 +1595,8 @@ static int tipc_link_advance_transmq(struct tipc_link *l, struct tipc_link *r,
_skb->priority = TC_PRIO_CONTROL; _skb->priority = TC_PRIO_CONTROL;
__skb_queue_tail(xmitq, _skb); __skb_queue_tail(xmitq, _skb);
l->stats.retransmitted++; l->stats.retransmitted++;
if (!is_uc)
r->stats.retransmitted++;
*retransmitted = true; *retransmitted = true;
/* Increase actual retrans counter & mark first time */ /* Increase actual retrans counter & mark first time */
if (!TIPC_SKB_CB(skb)->retr_cnt++) if (!TIPC_SKB_CB(skb)->retr_cnt++)
...@@ -1753,7 +1763,8 @@ int tipc_link_rcv(struct tipc_link *l, struct sk_buff *skb, ...@@ -1753,7 +1763,8 @@ int tipc_link_rcv(struct tipc_link *l, struct sk_buff *skb,
/* Defer delivery if sequence gap */ /* Defer delivery if sequence gap */
if (unlikely(seqno != rcv_nxt)) { 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); rc |= tipc_link_build_nack_msg(l, xmitq);
break; break;
} }
...@@ -1787,15 +1798,15 @@ static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe, ...@@ -1787,15 +1798,15 @@ static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe,
int tolerance, int priority, int tolerance, int priority,
struct sk_buff_head *xmitq) 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 tipc_link *bcl = l->bc_rcvlink;
struct sk_buff *skb;
struct tipc_msg *hdr; struct tipc_msg *hdr;
struct sk_buff_head *dfq = &l->deferdq; struct sk_buff *skb;
bool node_up = link_is_up(bcl); bool node_up = link_is_up(bcl);
struct tipc_mon_state *mstate = &l->mon_state; u16 glen = 0, bc_rcvgap = 0;
int dlen = 0; int dlen = 0;
void *data; void *data;
u16 glen = 0;
/* Don't send protocol message during reset or link failover */ /* Don't send protocol message during reset or link failover */
if (tipc_link_is_blocked(l)) 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, ...@@ -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) if (l->peer_caps & TIPC_LINK_PROTO_SEQNO)
msg_set_seqno(hdr, l->snd_nxt_state++); msg_set_seqno(hdr, l->snd_nxt_state++);
msg_set_seq_gap(hdr, rcvgap); 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_probe(hdr, probe);
msg_set_is_keepalive(hdr, probe || probe_reply); msg_set_is_keepalive(hdr, probe || probe_reply);
if (l->peer_caps & TIPC_GAP_ACK_BLOCK) 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, ...@@ -1858,6 +1870,8 @@ static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe,
l->stats.sent_probes++; l->stats.sent_probes++;
if (rcvgap) if (rcvgap)
l->stats.sent_nacks++; l->stats.sent_nacks++;
if (bc_rcvgap)
bcl->stats.sent_nacks++;
skb->priority = TC_PRIO_CONTROL; skb->priority = TC_PRIO_CONTROL;
__skb_queue_tail(xmitq, skb); __skb_queue_tail(xmitq, skb);
trace_tipc_proto_build(skb, false, l->name); 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, ...@@ -2358,8 +2372,6 @@ int tipc_link_bc_sync_rcv(struct tipc_link *l, struct tipc_msg *hdr,
if (!l->bc_peer_is_up) if (!l->bc_peer_is_up)
return rc; return rc;
l->stats.recv_nacks++;
/* Ignore if peers_snd_nxt goes beyond receive window */ /* Ignore if peers_snd_nxt goes beyond receive window */
if (more(peers_snd_nxt, l->rcv_nxt + l->window)) if (more(peers_snd_nxt, l->rcv_nxt + l->window))
return rc; return rc;
...@@ -2410,6 +2422,11 @@ int tipc_link_bc_ack_rcv(struct tipc_link *r, u16 acked, u16 gap, ...@@ -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) if (!link_is_up(r) || !r->bc_peer_is_up)
return 0; return 0;
if (gap) {
l->stats.recv_nacks++;
r->stats.recv_nacks++;
}
if (less(acked, r->acked) || (acked == r->acked && !gap && !ga)) if (less(acked, r->acked) || (acked == r->acked && !gap && !ga))
return 0; return 0;
...@@ -2721,16 +2738,15 @@ static int __tipc_nl_add_bc_link_stat(struct sk_buff *skb, ...@@ -2721,16 +2738,15 @@ static int __tipc_nl_add_bc_link_stat(struct sk_buff *skb,
return -EMSGSIZE; 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; int err;
void *hdr; void *hdr;
struct nlattr *attrs; struct nlattr *attrs;
struct nlattr *prop; struct nlattr *prop;
struct tipc_net *tn = net_generic(net, tipc_net_id);
u32 bc_mode = tipc_bcast_get_broadcast_mode(net); u32 bc_mode = tipc_bcast_get_broadcast_mode(net);
u32 bc_ratio = tipc_bcast_get_broadcast_ratio(net); u32 bc_ratio = tipc_bcast_get_broadcast_ratio(net);
struct tipc_link *bcl = tn->bcl;
if (!bcl) if (!bcl)
return 0; return 0;
...@@ -2817,21 +2833,6 @@ void tipc_link_set_abort_limit(struct tipc_link *l, u32 limit) ...@@ -2817,21 +2833,6 @@ void tipc_link_set_abort_limit(struct tipc_link *l, u32 limit)
l->abort_limit = 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 * tipc_link_dump - dump TIPC link data
* @l: tipc link to be dumped * @l: tipc link to be dumped
......
...@@ -80,7 +80,7 @@ bool tipc_link_create(struct net *net, char *if_name, int bearer_id, ...@@ -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 *inputq,
struct sk_buff_head *namedq, struct sk_buff_head *namedq,
struct tipc_link **link); 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, int mtu, u32 min_win, u32 max_win, u16 peer_caps,
struct sk_buff_head *inputq, struct sk_buff_head *inputq,
struct sk_buff_head *namedq, struct sk_buff_head *namedq,
...@@ -111,7 +111,6 @@ u16 tipc_link_rcv_nxt(struct tipc_link *l); ...@@ -111,7 +111,6 @@ u16 tipc_link_rcv_nxt(struct tipc_link *l);
u16 tipc_link_acked(struct tipc_link *l); u16 tipc_link_acked(struct tipc_link *l);
u32 tipc_link_id(struct tipc_link *l); u32 tipc_link_id(struct tipc_link *l);
char *tipc_link_name(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); u32 tipc_link_state(struct tipc_link *l);
char tipc_link_plane(struct tipc_link *l); char tipc_link_plane(struct tipc_link *l);
int tipc_link_prio(struct tipc_link *l); int tipc_link_prio(struct tipc_link *l);
......
...@@ -825,19 +825,19 @@ bool tipc_msg_pskb_copy(u32 dst, struct sk_buff_head *msg, ...@@ -825,19 +825,19 @@ bool tipc_msg_pskb_copy(u32 dst, struct sk_buff_head *msg,
* @seqno: sequence number of buffer to add * @seqno: sequence number of buffer to add
* @skb: 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)
{ {
struct sk_buff *_skb, *tmp; struct sk_buff *_skb, *tmp;
if (skb_queue_empty(list) || less(seqno, buf_seqno(skb_peek(list)))) { if (skb_queue_empty(list) || less(seqno, buf_seqno(skb_peek(list)))) {
__skb_queue_head(list, skb); __skb_queue_head(list, skb);
return; return true;
} }
if (more(seqno, buf_seqno(skb_peek_tail(list)))) { if (more(seqno, buf_seqno(skb_peek_tail(list)))) {
__skb_queue_tail(list, skb); __skb_queue_tail(list, skb);
return; return true;
} }
skb_queue_walk_safe(list, _skb, tmp) { skb_queue_walk_safe(list, _skb, tmp) {
...@@ -846,9 +846,10 @@ void __tipc_skb_queue_sorted(struct sk_buff_head *list, u16 seqno, ...@@ -846,9 +846,10 @@ void __tipc_skb_queue_sorted(struct sk_buff_head *list, u16 seqno,
if (seqno == buf_seqno(_skb)) if (seqno == buf_seqno(_skb))
break; break;
__skb_queue_before(list, _skb, skb); __skb_queue_before(list, _skb, skb);
return; return true;
} }
kfree_skb(skb); kfree_skb(skb);
return false;
} }
void tipc_skb_reject(struct net *net, int err, struct sk_buff *skb, void tipc_skb_reject(struct net *net, int err, struct sk_buff *skb,
......
...@@ -1145,7 +1145,7 @@ bool tipc_msg_assemble(struct sk_buff_head *list); ...@@ -1145,7 +1145,7 @@ bool tipc_msg_assemble(struct sk_buff_head *list);
bool tipc_msg_reassemble(struct sk_buff_head *list, struct sk_buff_head *rcvq); bool tipc_msg_reassemble(struct sk_buff_head *list, struct sk_buff_head *rcvq);
bool tipc_msg_pskb_copy(u32 dst, struct sk_buff_head *msg, bool tipc_msg_pskb_copy(u32 dst, struct sk_buff_head *msg,
struct sk_buff_head *cpy); struct sk_buff_head *cpy);
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);
bool tipc_msg_skb_clone(struct sk_buff_head *msg, struct sk_buff_head *cpy); bool tipc_msg_skb_clone(struct sk_buff_head *msg, struct sk_buff_head *cpy);
......
...@@ -188,7 +188,7 @@ static const struct genl_ops tipc_genl_v2_ops[] = { ...@@ -188,7 +188,7 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
}, },
{ {
.cmd = TIPC_NL_LINK_GET, .cmd = TIPC_NL_LINK_GET,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .validate = GENL_DONT_VALIDATE_STRICT,
.doit = tipc_nl_node_get_link, .doit = tipc_nl_node_get_link,
.dumpit = tipc_nl_node_dump_link, .dumpit = tipc_nl_node_dump_link,
}, },
......
...@@ -1138,7 +1138,7 @@ void tipc_node_check_dest(struct net *net, u32 addr, ...@@ -1138,7 +1138,7 @@ void tipc_node_check_dest(struct net *net, u32 addr,
if (unlikely(!n->bc_entry.link)) { if (unlikely(!n->bc_entry.link)) {
snd_l = tipc_bc_sndlink(net); snd_l = tipc_bc_sndlink(net);
if (!tipc_link_bc_create(net, tipc_own_addr(net), if (!tipc_link_bc_create(net, tipc_own_addr(net),
addr, U16_MAX, addr, peer_id, U16_MAX,
tipc_link_min_win(snd_l), tipc_link_min_win(snd_l),
tipc_link_max_win(snd_l), tipc_link_max_win(snd_l),
n->capabilities, n->capabilities,
...@@ -2435,7 +2435,7 @@ int tipc_nl_node_get_link(struct sk_buff *skb, struct genl_info *info) ...@@ -2435,7 +2435,7 @@ int tipc_nl_node_get_link(struct sk_buff *skb, struct genl_info *info)
return -ENOMEM; return -ENOMEM;
if (strcmp(name, tipc_bclink_name) == 0) { if (strcmp(name, tipc_bclink_name) == 0) {
err = tipc_nl_add_bc_link(net, &msg); err = tipc_nl_add_bc_link(net, &msg, tipc_net(net)->bcl);
if (err) if (err)
goto err_free; goto err_free;
} else { } else {
...@@ -2479,6 +2479,7 @@ int tipc_nl_node_reset_link_stats(struct sk_buff *skb, struct genl_info *info) ...@@ -2479,6 +2479,7 @@ int tipc_nl_node_reset_link_stats(struct sk_buff *skb, struct genl_info *info)
struct tipc_node *node; struct tipc_node *node;
struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1]; struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1];
struct net *net = sock_net(skb->sk); struct net *net = sock_net(skb->sk);
struct tipc_net *tn = tipc_net(net);
struct tipc_link_entry *le; struct tipc_link_entry *le;
if (!info->attrs[TIPC_NLA_LINK]) if (!info->attrs[TIPC_NLA_LINK])
...@@ -2495,11 +2496,26 @@ int tipc_nl_node_reset_link_stats(struct sk_buff *skb, struct genl_info *info) ...@@ -2495,11 +2496,26 @@ int tipc_nl_node_reset_link_stats(struct sk_buff *skb, struct genl_info *info)
link_name = nla_data(attrs[TIPC_NLA_LINK_NAME]); link_name = nla_data(attrs[TIPC_NLA_LINK_NAME]);
if (strcmp(link_name, tipc_bclink_name) == 0) { err = -EINVAL;
err = tipc_bclink_reset_stats(net); if (!strcmp(link_name, tipc_bclink_name)) {
err = tipc_bclink_reset_stats(net, tipc_bc_sndlink(net));
if (err) if (err)
return err; return err;
return 0; return 0;
} else if (strstr(link_name, tipc_bclink_name)) {
rcu_read_lock();
list_for_each_entry_rcu(node, &tn->node_list, list) {
tipc_node_read_lock(node);
link = node->bc_entry.link;
if (link && !strcmp(link_name, tipc_link_name(link))) {
err = tipc_bclink_reset_stats(net, link);
tipc_node_read_unlock(node);
break;
}
tipc_node_read_unlock(node);
}
rcu_read_unlock();
return err;
} }
node = tipc_node_find_by_name(net, link_name, &bearer_id); node = tipc_node_find_by_name(net, link_name, &bearer_id);
...@@ -2523,7 +2539,8 @@ int tipc_nl_node_reset_link_stats(struct sk_buff *skb, struct genl_info *info) ...@@ -2523,7 +2539,8 @@ int tipc_nl_node_reset_link_stats(struct sk_buff *skb, struct genl_info *info)
/* Caller should hold node lock */ /* Caller should hold node lock */
static int __tipc_nl_add_node_links(struct net *net, struct tipc_nl_msg *msg, static int __tipc_nl_add_node_links(struct net *net, struct tipc_nl_msg *msg,
struct tipc_node *node, u32 *prev_link) struct tipc_node *node, u32 *prev_link,
bool bc_link)
{ {
u32 i; u32 i;
int err; int err;
...@@ -2539,6 +2556,14 @@ static int __tipc_nl_add_node_links(struct net *net, struct tipc_nl_msg *msg, ...@@ -2539,6 +2556,14 @@ static int __tipc_nl_add_node_links(struct net *net, struct tipc_nl_msg *msg,
if (err) if (err)
return err; return err;
} }
if (bc_link) {
*prev_link = i;
err = tipc_nl_add_bc_link(net, msg, node->bc_entry.link);
if (err)
return err;
}
*prev_link = 0; *prev_link = 0;
return 0; return 0;
...@@ -2547,17 +2572,36 @@ static int __tipc_nl_add_node_links(struct net *net, struct tipc_nl_msg *msg, ...@@ -2547,17 +2572,36 @@ static int __tipc_nl_add_node_links(struct net *net, struct tipc_nl_msg *msg,
int tipc_nl_node_dump_link(struct sk_buff *skb, struct netlink_callback *cb) int tipc_nl_node_dump_link(struct sk_buff *skb, struct netlink_callback *cb)
{ {
struct net *net = sock_net(skb->sk); struct net *net = sock_net(skb->sk);
struct nlattr **attrs = genl_dumpit_info(cb)->attrs;
struct nlattr *link[TIPC_NLA_LINK_MAX + 1];
struct tipc_net *tn = net_generic(net, tipc_net_id); struct tipc_net *tn = net_generic(net, tipc_net_id);
struct tipc_node *node; struct tipc_node *node;
struct tipc_nl_msg msg; struct tipc_nl_msg msg;
u32 prev_node = cb->args[0]; u32 prev_node = cb->args[0];
u32 prev_link = cb->args[1]; u32 prev_link = cb->args[1];
int done = cb->args[2]; int done = cb->args[2];
bool bc_link = cb->args[3];
int err; int err;
if (done) if (done)
return 0; return 0;
if (!prev_node) {
/* Check if broadcast-receiver links dumping is needed */
if (attrs && attrs[TIPC_NLA_LINK]) {
err = nla_parse_nested_deprecated(link,
TIPC_NLA_LINK_MAX,
attrs[TIPC_NLA_LINK],
tipc_nl_link_policy,
NULL);
if (unlikely(err))
return err;
if (unlikely(!link[TIPC_NLA_LINK_BROADCAST]))
return -EINVAL;
bc_link = true;
}
}
msg.skb = skb; msg.skb = skb;
msg.portid = NETLINK_CB(cb->skb).portid; msg.portid = NETLINK_CB(cb->skb).portid;
msg.seq = cb->nlh->nlmsg_seq; msg.seq = cb->nlh->nlmsg_seq;
...@@ -2581,7 +2625,7 @@ int tipc_nl_node_dump_link(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -2581,7 +2625,7 @@ int tipc_nl_node_dump_link(struct sk_buff *skb, struct netlink_callback *cb)
list) { list) {
tipc_node_read_lock(node); tipc_node_read_lock(node);
err = __tipc_nl_add_node_links(net, &msg, node, err = __tipc_nl_add_node_links(net, &msg, node,
&prev_link); &prev_link, bc_link);
tipc_node_read_unlock(node); tipc_node_read_unlock(node);
if (err) if (err)
goto out; goto out;
...@@ -2589,14 +2633,14 @@ int tipc_nl_node_dump_link(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -2589,14 +2633,14 @@ int tipc_nl_node_dump_link(struct sk_buff *skb, struct netlink_callback *cb)
prev_node = node->addr; prev_node = node->addr;
} }
} else { } else {
err = tipc_nl_add_bc_link(net, &msg); err = tipc_nl_add_bc_link(net, &msg, tn->bcl);
if (err) if (err)
goto out; goto out;
list_for_each_entry_rcu(node, &tn->node_list, list) { list_for_each_entry_rcu(node, &tn->node_list, list) {
tipc_node_read_lock(node); tipc_node_read_lock(node);
err = __tipc_nl_add_node_links(net, &msg, node, err = __tipc_nl_add_node_links(net, &msg, node,
&prev_link); &prev_link, bc_link);
tipc_node_read_unlock(node); tipc_node_read_unlock(node);
if (err) if (err)
goto out; goto out;
...@@ -2611,6 +2655,7 @@ int tipc_nl_node_dump_link(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -2611,6 +2655,7 @@ int tipc_nl_node_dump_link(struct sk_buff *skb, struct netlink_callback *cb)
cb->args[0] = prev_node; cb->args[0] = prev_node;
cb->args[1] = prev_link; cb->args[1] = prev_link;
cb->args[2] = done; cb->args[2] = done;
cb->args[3] = bc_link;
return skb->len; return skb->len;
} }
......
...@@ -255,7 +255,7 @@ DECLARE_EVENT_CLASS(tipc_link_class, ...@@ -255,7 +255,7 @@ DECLARE_EVENT_CLASS(tipc_link_class,
TP_fast_assign( TP_fast_assign(
__assign_str(header, header); __assign_str(header, header);
tipc_link_name_ext(l, __entry->name); memcpy(__entry->name, tipc_link_name(l), TIPC_MAX_LINK_NAME);
tipc_link_dump(l, dqueues, __get_str(buf)); tipc_link_dump(l, dqueues, __get_str(buf));
), ),
...@@ -295,7 +295,7 @@ DECLARE_EVENT_CLASS(tipc_link_transmq_class, ...@@ -295,7 +295,7 @@ DECLARE_EVENT_CLASS(tipc_link_transmq_class,
), ),
TP_fast_assign( TP_fast_assign(
tipc_link_name_ext(r, __entry->name); memcpy(__entry->name, tipc_link_name(r), TIPC_MAX_LINK_NAME);
__entry->from = f; __entry->from = f;
__entry->to = t; __entry->to = t;
__entry->len = skb_queue_len(tq); __entry->len = skb_queue_len(tq);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment