/proc vis rework

Message ID 20091130211445.GN4150@lunn.ch (mailing list archive)
State Accepted, archived
Headers

Commit Message

Andrew Lunn Nov. 30, 2009, 9:14 p.m. UTC
  Hi Folks

A while back i suggested we re-work the /proc/net/batman/vis format.
Attached are two patches to achieve this. One patch is for the kernel
model sources and the second extends batctl so that it can read from
the /proc file and output dot or json format as before. The patch
includes documentation for the new new batctl command in the man page.

I've tested the dot output using graphviz dot. However i don't have
any tools which use the json output. So that format is not tested.

    Andrew
  

Comments

Marek Lindner Dec. 19, 2009, 5:01 p.m. UTC | #1
Hey,

> A while back i suggested we re-work the /proc/net/batman/vis format.
> Attached are two patches to achieve this. One patch is for the kernel
> model sources and the second extends batctl so that it can read from
> the /proc file and output dot or json format as before. The patch
> includes documentation for the new new batctl command in the man page.

I reviewed the patches & fixed some issues:
* vis raw data (kernel): I upgraded the patch to make it apply on the latest 
trunk and added a descriptive commit message
* vis raw data (batctl): I did not change anything but I'd like to suggest we 
adapt the coding style to match the rest of batctl (maybe using Lindent?). 
Also, all other batctl modules follow the same behaviour regarding the "-h" 
option. To be consistent we may want to adapt that as well.
* vis_format remove: This patch removed the vis_format initializations but not 
the corresponding free calls. I fixed that.
* I added an additional patch (splitting /proc vis file into vis_server and 
vis_data) to follow the roadmap we layed out in Brussels.
* Last but not least: the mandatory batctl vis data path change

Please give it some more testing,
Marek
  

Patch

diff --git a/drivers/staging/batman-adv/proc.c b/drivers/staging/batman-adv/proc.c
index ed4c734..e214936 100644
--- a/drivers/staging/batman-adv/proc.c
+++ b/drivers/staging/batman-adv/proc.c
@@ -322,91 +322,76 @@  static int proc_transt_global_open(struct inode *inode, struct file *file)
 	return single_open(file, proc_transt_global_read, NULL);
 }
 
-/* insert interface to the list of interfaces of one originator */
+/* While scanning for vis-entries of a particular vis-originator
+ * this list collects its interfaces to create a subgraph/cluster
+ * out of them later
+ */
+struct if_list_entry {
+	uint8_t addr[ETH_ALEN];
+	bool primary;
+	struct hlist_node list;
+};
+
+/* insert interface to the list of interfaces of one originator, if it
+ * does not already exist in the list */
 
 static void proc_vis_insert_interface(const uint8_t *interface,
-				      struct vis_if_list **if_entry,
+				      struct hlist_head *if_list,
 				      bool primary)
 {
-	/* Did we get an empty list? (then insert imediately) */
-	if (*if_entry == NULL) {
-		*if_entry = kmalloc(sizeof(struct vis_if_list), GFP_KERNEL);
-		if (*if_entry == NULL)
+	struct if_list_entry *entry;
+	struct hlist_node *pos;
+
+
+	hlist_for_each_entry(entry, pos, if_list, list) {
+		if (compare_orig(entry->addr, (void *)interface))
 			return;
+	}
 
-		(*if_entry)->primary = primary;
-		(*if_entry)->next = NULL;
-		memcpy((*if_entry)->addr, interface, ETH_ALEN);
-	} else {
-		struct vis_if_list *head_if_entry = *if_entry;
-		/* Do we already have this interface in our list? */
-		while (!compare_orig((*if_entry)->addr, (void *)interface)) {
-
-			/* Or did we reach the end (then append the interface) */
-			if ((*if_entry)->next == NULL) {
-				(*if_entry)->next = kmalloc(sizeof(struct vis_if_list), GFP_KERNEL);
-				if ((*if_entry)->next == NULL)
-					return;
-
-				memcpy((*if_entry)->next->addr, interface, ETH_ALEN);
-				(*if_entry)->next->primary = primary;
-				(*if_entry)->next->next = NULL;
-				break;
-			}
-			*if_entry = (*if_entry)->next;
+	/* its a new address, add it to the list */
+	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry)
+		return;
+	memcpy(entry->addr, interface, ETH_ALEN);
+	entry->primary = primary;
+	hlist_add_head(&entry->list, if_list);
+}
+
+static void proc_vis_read_prim_sec(struct seq_file *seq,
+				   struct hlist_head *if_list)
+{
+	struct if_list_entry *entry;
+	struct hlist_node *pos, *n;
+	char tmp_addr_str[ETH_STR_LEN];
+
+	hlist_for_each_entry_safe(entry, pos, n, if_list, list) {
+		if (entry->primary)
+			seq_printf(seq, "PRIMARY, ");
+		else {
+			addr_to_string(tmp_addr_str, entry->addr);
+			seq_printf(seq, "SEC %s, ", tmp_addr_str);
 		}
-		/* Rewind the list to its head */
-		*if_entry = head_if_entry;
+		hlist_del(&entry->list);
+		kfree(entry);
 	}
 }
-/* read an entry  */
 
+/* read an entry  */
 static void proc_vis_read_entry(struct seq_file *seq,
 				struct vis_info_entry *entry,
-				struct vis_if_list **if_entry,
-				uint8_t *vis_orig,
-				uint8_t current_format,
-				uint8_t first_line)
+				struct hlist_head *if_list,
+				uint8_t *vis_orig)
 {
-	char from[40];
 	char to[40];
-	int int_part, frac_part;
 
 	addr_to_string(to, entry->dest);
 	if (entry->quality == 0) {
-#ifndef VIS_SUBCLUSTERS_DISABLED
-		proc_vis_insert_interface(vis_orig, if_entry, true);
-#endif /* VIS_SUBCLUSTERS_DISABLED */
-		addr_to_string(from, vis_orig);
-		if (current_format == DOT_DRAW) {
-			seq_printf(seq, "\t\"%s\" -> \"%s\" [label=\"HNA\"]\n",
-				   from, to);
-		} else {
-			seq_printf(seq,
-				   "%s\t{ router : \"%s\", gateway   : \"%s\", label : \"HNA\" }",
-				   (first_line ? "" : ",\n"), from, to);
-		}
+		proc_vis_insert_interface(vis_orig, if_list, true);
+		seq_printf(seq, "HNA %s, ", to);
 	} else {
-#ifndef VIS_SUBCLUSTERS_DISABLED
-		proc_vis_insert_interface(entry->src, if_entry, compare_orig(entry->src, vis_orig));
-#endif /* VIS_SUBCLUSTERS_DISABLED */
-		addr_to_string(from, entry->src);
-
-		/* kernel has no printf-support for %f? it'd be better to return
-		 * this in float. */
-
-		int_part = TQ_MAX_VALUE / entry->quality;
-		frac_part = 1000 * TQ_MAX_VALUE / entry->quality - int_part * 1000;
-
-		if (current_format == DOT_DRAW) {
-			seq_printf(seq,
-				   "\t\"%s\" -> \"%s\" [label=\"%d.%d\"]\n",
-				   from, to, int_part, frac_part);
-		} else {
-			seq_printf(seq,
-				   "%s\t{ router : \"%s\", neighbour : \"%s\", label : %d.%d }",
-				   (first_line ? "" : ",\n"), from, to, int_part, frac_part);
-		}
+		proc_vis_insert_interface(entry->src, if_list,
+					  compare_orig(entry->src, vis_orig));
+		seq_printf(seq, "TQ %s %d, ", to, entry->quality);
 	}
 }
 
@@ -416,72 +401,40 @@  static int proc_vis_read(struct seq_file *seq, void *offset)
 	struct hash_it_t *hashit = NULL;
 	struct vis_info *info;
 	struct vis_info_entry *entries;
-	struct vis_if_list *if_entries = NULL;
+	HLIST_HEAD(vis_if_list);
 	int i;
-	uint8_t current_format, first_line = 1;
-#ifndef VIS_SUBCLUSTERS_DISABLED
+	uint8_t current_format;
 	char tmp_addr_str[ETH_STR_LEN];
-	struct vis_if_list *tmp_if_next;
-#endif /* VIS_SUBCLUSTERS_DISABLED */
 
 	current_format = vis_format;
 
 	rcu_read_lock();
 	if (list_empty(&if_list) || (!is_vis_server())) {
 		rcu_read_unlock();
-		if (current_format == DOT_DRAW)
-			seq_printf(seq, "digraph {\n}\n");
 		goto end;
 	}
 
 	rcu_read_unlock();
 
-	if (current_format == DOT_DRAW)
-		seq_printf(seq, "digraph {\n");
-
 	spin_lock(&vis_hash_lock);
 	while (NULL != (hashit = hash_iterate(vis_hash, hashit))) {
 		info = hashit->bucket->data;
 		entries = (struct vis_info_entry *)
 			((char *)info + sizeof(struct vis_info));
+		addr_to_string(tmp_addr_str, info->packet.vis_orig);
+		seq_printf(seq, "%s,", tmp_addr_str);
 
 		for (i = 0; i < info->packet.entries; i++) {
-			proc_vis_read_entry(seq, &entries[i], &if_entries,
-					    info->packet.vis_orig,
-					    current_format, first_line);
-			if (first_line)
-				first_line = 0;
+			proc_vis_read_entry(seq, &entries[i], &vis_if_list,
+					    info->packet.vis_orig);
 		}
 
-#ifndef VIS_SUBCLUSTERS_DISABLED
-		/* Generate subgraphs from the collected items */
-		if (current_format == DOT_DRAW) {
-
-			addr_to_string(tmp_addr_str, info->packet.vis_orig);
-			seq_printf(seq, "\tsubgraph \"cluster_%s\" {\n", tmp_addr_str);
-			while (if_entries != NULL) {
-
-				addr_to_string(tmp_addr_str, if_entries->addr);
-				if (if_entries->primary)
-					seq_printf(seq, "\t\t\"%s\" [peripheries=2]\n", tmp_addr_str);
-				else
-					seq_printf(seq, "\t\t\"%s\"\n", tmp_addr_str);
-
-				/* ... and empty the list while doing this */
-				tmp_if_next = if_entries->next;
-				kfree(if_entries);
-				if_entries = tmp_if_next;
-			}
-			seq_printf(seq, "\t}\n");
-		}
-#endif /* VIS_SUBCLUSTERS_DISABLED */
-	}
-	spin_unlock(&vis_hash_lock);
+		/* add primary/secondary records */
+		proc_vis_read_prim_sec(seq, &vis_if_list);
 
-	if (current_format == DOT_DRAW)
-		seq_printf(seq, "}\n");
-	else
 		seq_printf(seq, "\n");
+	}
+	spin_unlock(&vis_hash_lock);
 end:
 	return 0;
 }
diff --git a/drivers/staging/batman-adv/proc.h b/drivers/staging/batman-adv/proc.h
index 16d3efd..761c5f8 100644
--- a/drivers/staging/batman-adv/proc.h
+++ b/drivers/staging/batman-adv/proc.h
@@ -38,12 +38,3 @@ 
 void cleanup_procfs(void);
 int setup_procfs(void);
 
-/* While scanning for vis-entries of a particular vis-originator
- * this list collects its interfaces to create a subgraph/cluster
- * out of them later
- */
-struct vis_if_list {
-	uint8_t addr[ETH_ALEN];
-	bool primary;
-	struct vis_if_list *next;
-};