David S. Miller wrote:
From: Ben Greear <[EMAIL PROTECTED]>
Date: Fri, 02 Sep 2005 13:53:58 -0700


I'm trying to write some code to walk all of the places where
routes might exist and find any that reference a particular
net-device.


Man, good luck.  The IPSEC destination cache entries live in
chains only obtainable from the IPSEC database.  And when
routes are flushed, sometimes they only exist hung off of
sockets via sk->sk_dst, so you'll need to walk every single
socket in the system as well.  There are also dst entries
on the garbage collection list, which you'll need to scan
as well.

So, routing cache, IPSEC database, sockets, DST garbage
list... sounds big and complicated, a sign that you're
attacking the problem the wrong way.

It is better to implement this via backpointers in the
debugging information, perhaps.

I added logic to search the routing cache, packet, udp, and tcp sockets,
and the neighbour tables.  I cannot find the neighbour struct in any
of these places....

I'm not using IPSEC, so I assume it is not in there.  Also, the neighbour
object has a pointer to a neighbour table (n->tbl).  I do not seem to have
that table in existence either.

Unless there is some other place to search, or my search is incorrect,
I will assume that the neighbour object itself was leaked and attempt
to debug that problem....

Here are my methods to try to find the lost neighbour struct (and
a few methods to look for netdevs as well)...
I'd appreciate any suggestions that someone may have.

--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -611,6 +611,9 @@ void neigh_destroy(struct neighbour *nei

        NEIGH_PRINTK2("neigh %p is destroyed.\n", neigh);

+       /* Poison the struct for debugging purposes */
+       neigh->used = 0xabcdef01;
+       
        atomic_dec(&neigh->tbl->entries);
        kmem_cache_free(neigh->tbl->kmem_cachep, neigh);
 }
@@ -1398,6 +1401,71 @@ void neigh_table_init(struct neigh_table
        write_unlock(&neigh_tbl_lock);
 }

+#ifdef CONFIG_DEBUG_NETDEV_REFCOUNT
+void print_neigh_for_dev(struct net_device* dev) {
+       struct neigh_table* t;
+       int found_one = 0;
+       write_lock(&neigh_tbl_lock);
+       for (t = neigh_tables; t; t = t->next) {
+               int i;
+               for (i = 0; i <= t->hash_mask; i++) {
+                       struct neighbour *n;
+                       int z = 0;
+                       n = t->hash_buckets[i];
+                       while (n) {
+                               if (n->dev == dev) {
+                                       found_one = 1;
+                                       printk("Table: %s(%p)  Neighbor: [%d] [%d] 
%p holds dev: %p\n",
+                                              t->id, t, i, z, n, dev);
+                               }
+                               z++;
+                               n = n->next;
+                       } /* while, all neighbors in hash bucket i */
+               }/* for all hash buckets*/
+       }/* for all tables */
+       write_unlock(&neigh_tbl_lock);
+
+       if (!found_one) {
+               printk("No neighbor entries in the neighbor tables holds device: 
%p\n",
+                      dev);
+       }
+}
+EXPORT_SYMBOL(print_neigh_for_dev);
+
+
+void debug_locate_neigh(struct neighbour* neigh) {
+       struct neigh_table* t;
+       int found_one = 0;
+       write_lock(&neigh_tbl_lock);
+       for (t = neigh_tables; t; t = t->next) {
+               int i;
+               if (t == neigh->tbl) {
+                       printk("   Found neighbour's table (%p)\n", t);
+               }
+               for (i = 0; i <= t->hash_mask; i++) {
+                       struct neighbour *n;
+                       int z = 0;
+                       n = t->hash_buckets[i];
+                       while (n) {
+                               if (n == neigh) {
+                                       found_one = 1;
+                                       printk("Table: %s(%p)  Neighbor: [%d] [%d] %p 
exists, n->dev: %p\n",
+                                              t->id, t, i, z, n, n->dev);
+                               }
+                               z++;
+                               n = n->next;
+                       } /* while, all neighbors in hash bucket i */
+               }/* for all hash buckets*/
+       }/* for all tables */
+       write_unlock(&neigh_tbl_lock);
+
+       if (!found_one) {
+               printk("No neighbor with address: %p found.\n", neigh);
+       }
+}
+EXPORT_SYMBOL(debug_locate_neigh);
+#endif
+
 int neigh_table_clear(struct neigh_table *tbl)
 {
        struct neigh_table **tp;


+++ b/net/ipv4/route.c
@@ -274,13 +274,39 @@ void print_routes_for_dev(struct net_dev
                        }
                        rtt = rtt->u.rt_next;
                }/* while we have a valid route-table */
-               rcu_read_lock_bh();
+               rcu_read_unlock_bh();
        }/* for all route table hashes */

        if (!found_one) {
                printk("No route tables hold that device.\n");
        }
 }
+EXPORT_SYMBOL(print_routes_for_dev);
+void debug_rt_locate_neigh(struct neighbour* neigh) {
+       struct rtable* rtt;
+       int i;
+       int found_one = 0;
+       
+       for (i = 0; i<=rt_hash_mask; i++) {
+               rcu_read_lock_bh();
+               rtt = rt_hash_table[i].chain;
+               while (rtt) {
+                       /* found a route table */
+                       if (rtt->u.dst.neighbour == neigh) {
+                               printk("Route hash table (%p) holds neighbour: 
%p\n",
+                                      rtt, neigh);
+                               found_one = 1;
+                       }
+                       rtt = rtt->u.rt_next;
+               }/* while we have a valid route-table */
+               rcu_read_unlock_bh();
+       }/* for all route table hashes */
+
+       if (!found_one) {
+               printk("Specified neighbour not found in route table.\n");
+       }
+}
+EXPORT_SYMBOL(debug_rt_locate_neigh);

 static struct rtable *rt_cache_get_first(struct seq_file *seq)
 {



+++ b/net/ipv4/tcp_diag.c
@@ -1,4 +1,4 @@
-/*
+/* -*- linux-c -*-
  * tcp_diag.c  Module for monitoring TCP sockets.
  *
  * Version:    $Id: tcp_diag.c,v 1.3 2002/02/01 22:01:04 davem Exp $
@@ -706,6 +706,72 @@ done:
        return skb->len;
 }

+
+void debug_tcp_locate_neigh(struct neighbour* neigh) {
+       int i;
+       int found_one = 0;
+       tcp_listen_lock();
+       for (i = 0; i < TCP_LHTABLE_SIZE; i++) {
+               struct sock *sk;
+               struct hlist_node *node;
+
+               sk_for_each(sk, node, &tcp_listening_hash[i]) {
+                       struct inet_sock *po = inet_sk(sk);
+                       if (po->sk.sk_dst_cache) { /* dst_entry */
+                               if (po->sk.sk_dst_cache->neighbour == neigh) {
+                                       printk("TCP socket %p in listening hash has 
neigh: %p in sk_dst_cache\n",
+                                              po, neigh);
+                                       found_one = 1;
+                               }
+                       }
+               }
+       }
+       tcp_listen_unlock();
+
+
+       for (i = 0; i < tcp_ehash_size; i++) {
+               struct tcp_ehash_bucket *head = &tcp_ehash[i];
+               struct sock *sk;
+               struct hlist_node *node;
+
+               read_lock_bh(&head->lock);
+
+               sk_for_each(sk, node, &head->chain) {
+                       struct inet_sock *po = inet_sk(sk);
+                       if (po->sk.sk_dst_cache) { /* dst_entry */
+                               if (po->sk.sk_dst_cache->neighbour == neigh) {
+                                       printk("TCP socket %p in e hash has neigh: 
%p in sk_dst_cache\n",
+                                              po, neigh);
+                                       found_one = 1;
+                               }
+                       }
+               }
+               read_unlock_bh(&head->lock);
+       }
+
+       for (i = 0; i < tcp_bhash_size; i++) {
+               struct tcp_bind_hashbucket *head = &tcp_bhash[i];
+               struct sock *sk;
+               struct hlist_node *node;
+
+               spin_lock(&head->lock);
+               
+               sk_for_each(sk, node, &head->chain) {
+                       struct inet_sock *po = inet_sk(sk);
+                       if (po->sk.sk_dst_cache) { /* dst_entry */
+                               if (po->sk.sk_dst_cache->neighbour == neigh) {
+                                       printk("TCP socket %p in b hash has neigh: 
%p in sk_dst_cache\n",
+                                              po, neigh);
+                                       found_one = 1;
+                               }
+                       }
+               }
+               spin_unlock(&head->lock);
+       }
+}
+EXPORT_SYMBOL(debug_tcp_locate_neigh);
+
+
 static int tcpdiag_dump_done(struct netlink_callback *cb)
 {
        return 0;
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1,4 +1,4 @@
-/*
+/* -*- linux-c -*-
  * INET                An implementation of the TCP/IP protocol suite for the 
LINUX
  *             operating system.  INET is implemented using the  BSD Socket
  *             interface as the means of communication with the user level.
@@ -216,6 +216,32 @@ static void udp_v4_unhash(struct sock *s
        write_unlock_bh(&udp_hash_lock);
 }

+
+void debug_udp_locate_neigh(struct neighbour* neigh) {
+       struct sock *sk;
+       struct hlist_node *node;
+       int found_one = 0;
+       int i;
+
+       for (i = 0; i<UDP_HTABLE_SIZE; i++) {
+               sk_for_each(sk, node, &udp_hash[i]) {
+                       struct inet_sock *po = inet_sk(sk);
+                       if (po->sk.sk_dst_cache) { /* dst_entry */
+                               if (po->sk.sk_dst_cache->neighbour == neigh) {
+                                       printk("Packet socket %p has neigh: %p in 
sk_dst_cache\n",
+                                              po, neigh);
+                                       found_one = 1;
+                               }
+                       }
+               }
+       }
+       
+       if (!found_one) {
+               printk("Neighbour not found in udp socket list...\n");
+       }
+}
+EXPORT_SYMBOL(debug_udp_locate_neigh);
+
 /* UDP is nearly always wildcards out the wazoo, it makes no sense to try
  * harder than this. -DaveM
  */
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1431,7 +1431,61 @@ static int packet_getsockopt(struct sock
        return 0;
 }

+void print_pktsock_for_dev(struct net_device* dev) {
+       struct sock *sk;
+       struct hlist_node *node;
+       int found_one = 0;
+       
+       read_lock(&packet_sklist_lock);
+       sk_for_each(sk, node, &packet_sklist) {
+               struct packet_sock *po = pkt_sk(sk);
+               if (po->sk.sk_dst_cache) { /* dst_entry */
+                       if (po->sk.sk_dst_cache->dev == dev) {
+                               printk("Packet socket %p has dev: %p in 
sk_dst_cache\n",
+                                      po, dev);
+                               found_one = 1;
+                       }
+                       if (po->sk.sk_dst_cache->neighbour &&
+                           po->sk.sk_dst_cache->neighbour->dev == dev) {
+                               printk("Packet socket %p has dev: %p in 
sk_dst_cache->neighbour->dev\n",
+                                      po, dev);
+                               found_one = 1;
+                       }
+               }
+       }
+       read_unlock(&packet_sklist_lock);
+
+       if (!found_one) {
+               printk("Device not found in packet socket list...\n");
+       }
+}
+EXPORT_SYMBOL(print_pktsock_for_dev);
+

+void debug_pkt_locate_neigh(struct neighbour* neigh) {
+       struct sock *sk;
+       struct hlist_node *node;
+       int found_one = 0;
+       
+       read_lock(&packet_sklist_lock);
+       sk_for_each(sk, node, &packet_sklist) {
+               struct packet_sock *po = pkt_sk(sk);
+               if (po->sk.sk_dst_cache) { /* dst_entry */
+                       if (po->sk.sk_dst_cache->neighbour == neigh) {
+                               printk("Packet socket %p has neigh: %p in 
sk_dst_cache\n",
+                                      po, neigh);
+                               found_one = 1;
+                       }
+               }
+       }
+       read_unlock(&packet_sklist_lock);
+
+       if (!found_one) {
+               printk("Neighbour not found in packet socket list...\n");
+       }
+}
+EXPORT_SYMBOL(debug_pkt_locate_neigh);
+               
 static int packet_notifier(struct notifier_block *this, unsigned long msg, 
void *data)
 {
        struct sock *sk;




-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html



--
Ben Greear <[EMAIL PROTECTED]>
Candela Technologies Inc  http://www.candelatech.com

-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to