tipc: add loopback device tracking
authorJohn Rutherford <john.rutherford@dektech.com.au>
Wed, 7 Aug 2019 02:52:29 +0000 (12:52 +1000)
committerDavid S. Miller <davem@davemloft.net>
Fri, 9 Aug 2019 05:11:39 +0000 (22:11 -0700)
Since node internal messages are passed directly to the socket, it is not
possible to observe those messages via tcpdump or wireshark.

We now remedy this by making it possible to clone such messages and send
the clones to the loopback interface.  The clones are dropped at reception
and have no functional role except making the traffic visible.

The feature is enabled if network taps are active for the loopback device.
pcap filtering restrictions require the messages to be presented to the
receiving side of the loopback device.

v3 - Function dev_nit_active used to check for network taps.
   - Procedure netif_rx_ni used to send cloned messages to loopback device.

Signed-off-by: John Rutherford <john.rutherford@dektech.com.au>
Acked-by: Jon Maloy <jon.maloy@ericsson.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/tipc/bcast.c
net/tipc/bearer.c
net/tipc/bearer.h
net/tipc/core.c
net/tipc/core.h
net/tipc/node.c
net/tipc/topsrv.c

index 1336f3cdad38eabd6586a0197987c337fa8b838a..34f3e5641438cc41be0d9dc0970655645e90f6bc 100644 (file)
@@ -406,8 +406,10 @@ int tipc_mcast_xmit(struct net *net, struct sk_buff_head *pkts,
                        rc = tipc_bcast_xmit(net, pkts, cong_link_cnt);
        }
 
-       if (dests->local)
+       if (dests->local) {
+               tipc_loopback_trace(net, &localq);
                tipc_sk_mcast_rcv(net, &localq, &inputq);
+       }
 exit:
        /* This queue should normally be empty by now */
        __skb_queue_purge(pkts);
index a809c0ec8d15c7a5b9e419eeff7ba9a0ce2b285c..0214aa1c442789089c6597ddc9980deadacd9dcc 100644 (file)
@@ -389,6 +389,11 @@ int tipc_enable_l2_media(struct net *net, struct tipc_bearer *b,
                dev_put(dev);
                return -EINVAL;
        }
+       if (dev == net->loopback_dev) {
+               dev_put(dev);
+               pr_info("Enabling <%s> not permitted\n", b->name);
+               return -EINVAL;
+       }
 
        /* Autoconfigure own node identity if needed */
        if (!tipc_own_id(net) && hwaddr_len <= NODE_ID_LEN) {
@@ -674,6 +679,65 @@ void tipc_bearer_stop(struct net *net)
        }
 }
 
+void tipc_clone_to_loopback(struct net *net, struct sk_buff_head *pkts)
+{
+       struct net_device *dev = net->loopback_dev;
+       struct sk_buff *skb, *_skb;
+       int exp;
+
+       skb_queue_walk(pkts, _skb) {
+               skb = pskb_copy(_skb, GFP_ATOMIC);
+               if (!skb)
+                       continue;
+
+               exp = SKB_DATA_ALIGN(dev->hard_header_len - skb_headroom(skb));
+               if (exp > 0 && pskb_expand_head(skb, exp, 0, GFP_ATOMIC)) {
+                       kfree_skb(skb);
+                       continue;
+               }
+
+               skb_reset_network_header(skb);
+               dev_hard_header(skb, dev, ETH_P_TIPC, dev->dev_addr,
+                               dev->dev_addr, skb->len);
+               skb->dev = dev;
+               skb->pkt_type = PACKET_HOST;
+               skb->ip_summed = CHECKSUM_UNNECESSARY;
+               skb->protocol = eth_type_trans(skb, dev);
+               netif_rx_ni(skb);
+       }
+}
+
+static int tipc_loopback_rcv_pkt(struct sk_buff *skb, struct net_device *dev,
+                                struct packet_type *pt, struct net_device *od)
+{
+       consume_skb(skb);
+       return NET_RX_SUCCESS;
+}
+
+int tipc_attach_loopback(struct net *net)
+{
+       struct net_device *dev = net->loopback_dev;
+       struct tipc_net *tn = tipc_net(net);
+
+       if (!dev)
+               return -ENODEV;
+
+       dev_hold(dev);
+       tn->loopback_pt.dev = dev;
+       tn->loopback_pt.type = htons(ETH_P_TIPC);
+       tn->loopback_pt.func = tipc_loopback_rcv_pkt;
+       dev_add_pack(&tn->loopback_pt);
+       return 0;
+}
+
+void tipc_detach_loopback(struct net *net)
+{
+       struct tipc_net *tn = tipc_net(net);
+
+       dev_remove_pack(&tn->loopback_pt);
+       dev_put(net->loopback_dev);
+}
+
 /* Caller should hold rtnl_lock to protect the bearer */
 static int __tipc_nl_add_bearer(struct tipc_nl_msg *msg,
                                struct tipc_bearer *bearer, int nlflags)
index 7f4c569594a57a56181a0f1b54c0bbdc97483ea2..ea0f3c49cbedb02c27b8a4c25536905cca066a03 100644 (file)
@@ -232,6 +232,16 @@ void tipc_bearer_xmit(struct net *net, u32 bearer_id,
                      struct tipc_media_addr *dst);
 void tipc_bearer_bc_xmit(struct net *net, u32 bearer_id,
                         struct sk_buff_head *xmitq);
+void tipc_clone_to_loopback(struct net *net, struct sk_buff_head *pkts);
+int tipc_attach_loopback(struct net *net);
+void tipc_detach_loopback(struct net *net);
+
+static inline void tipc_loopback_trace(struct net *net,
+                                      struct sk_buff_head *pkts)
+{
+       if (unlikely(dev_nit_active(net->loopback_dev)))
+               tipc_clone_to_loopback(net, pkts);
+}
 
 /* check if device MTU is too low for tipc headers */
 static inline bool tipc_mtu_bad(struct net_device *dev, unsigned int reserve)
index c8370722f0bbccd24d90454e1cdf59a8d203745f..23cb379a93d603306aafdd2ecbc61426a3bea4ce 100644 (file)
@@ -82,6 +82,10 @@ static int __net_init tipc_init_net(struct net *net)
        if (err)
                goto out_bclink;
 
+       err = tipc_attach_loopback(net);
+       if (err)
+               goto out_bclink;
+
        return 0;
 
 out_bclink:
@@ -94,6 +98,7 @@ out_sk_rht:
 
 static void __net_exit tipc_exit_net(struct net *net)
 {
+       tipc_detach_loopback(net);
        tipc_net_stop(net);
        tipc_bcast_stop(net);
        tipc_nametbl_stop(net);
index 7a68e1b6a066922b54bbc50c3ad1bff7e65c0973..60d829581068b94f9c69e251f074902614a93540 100644 (file)
@@ -125,6 +125,9 @@ struct tipc_net {
 
        /* Cluster capabilities */
        u16 capabilities;
+
+       /* Tracing of node internal messages */
+       struct packet_type loopback_pt;
 };
 
 static inline struct tipc_net *tipc_net(struct net *net)
index 7ca019001f7c8236e1362e85d848943df2a3acb5..1bdcf0fc1a4d3b00df450a80a59c275fa4ba9c52 100644 (file)
@@ -1443,6 +1443,7 @@ int tipc_node_xmit(struct net *net, struct sk_buff_head *list,
        int rc;
 
        if (in_own_node(net, dnode)) {
+               tipc_loopback_trace(net, list);
                tipc_sk_rcv(net, list);
                return 0;
        }
index ca8ac96d22a9658c9e492105ff65765b176f93f2..3a12fc18239b8184526b027ee9b3afce5893f717 100644 (file)
@@ -40,6 +40,7 @@
 #include "socket.h"
 #include "addr.h"
 #include "msg.h"
+#include "bearer.h"
 #include <net/sock.h>
 #include <linux/module.h>
 
@@ -608,6 +609,7 @@ static void tipc_topsrv_kern_evt(struct net *net, struct tipc_event *evt)
        memcpy(msg_data(buf_msg(skb)), evt, sizeof(*evt));
        skb_queue_head_init(&evtq);
        __skb_queue_tail(&evtq, skb);
+       tipc_loopback_trace(net, &evtq);
        tipc_sk_rcv(net, &evtq);
 }