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
 
 /**
  * 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;
 
                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;
 }
 
 /**
 
 
 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);
 
 #include "discover.h"
 #include "netlink.h"
 #include "monitor.h"
+#include "trace.h"
 
 #include <linux/pkt_sched.h>
 
 {
        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;
+}
 
 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);
 
 #include "monitor.h"
 #include "discover.h"
 #include "netlink.h"
+#include "trace.h"
 
 #define INVALID_NODE_SIG       0x10000
 #define NODE_CLEANUP_AFTER     300000
 
        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;
+}
 
 
 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,
 
 #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 */
 
        return skb->len;
 }
+
+u32 tipc_sock_get_portid(struct sock *sk)
+{
+       return (sk) ? (tipc_sk(sk))->portid : 0;
+}
+
+/**
+ * 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;
+}
 
 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);
+
 #endif
 
--- /dev/null
+/*
+ * 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"
+
+/**
+ * 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;
+}
 
--- /dev/null
+/*
+ * 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
+
+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);
+
+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);
+
+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(name) \
+DEFINE_EVENT(tipc_sk_class, name, \
+       TP_PROTO(struct sock *sk, struct sk_buff *skb, u16 dqueues, \
+                const char *header), \
+       TP_ARGS(sk, skb, dqueues, header))
+DEFINE_SK_EVENT(tipc_sk_dump);
+
+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);
+
+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);
+
+#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>