Staging: batman-adv: moving vis output formats out of the kernel
authorAndrew Lunn <andrew@lunn.ch>
Sat, 2 Jan 2010 10:30:44 +0000 (11:30 +0100)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 4 Mar 2010 00:42:35 +0000 (16:42 -0800)
The batman-adv kernel module is able to output visualization data using the
dot draw or JSON format. This patch transforms the output into a generic
format (called vis raw). User space tool may convert the raw data to support
a variety of formats without the need of modifying the kernel module.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/staging/batman-adv/TODO
drivers/staging/batman-adv/proc.c
drivers/staging/batman-adv/proc.h

index 8c2b89e82ad76468569ac01039eb67ef604a959e..b1e369cf9870f504f322a72aac4b145f6572334b 100644 (file)
 -> transtable_global (read-only) [outputs the global translation table]
 -> transtable_local (read-only) [outputs the local translation table]
 
-=> vis "raw" data output
-* the raw format shall replace dot draw / json to offer a neutral that can
-* be converted
-* the format (comma seperated entries):
--> "mac" -> mac address of an originator (each line begins with it)
--> "TQ mac value" -> src mac's link quality towards mac address
--> "HNA mac" -> HNA announced by source mac
--> "PRIMARY" -> this is a primary interface
--> "SEC mac" -> secondary mac address of source (requires preceeding
--> PRIMARY)
-
 => logging
 * make use of printk %pM support instead of converting mac addresses
 * manually
index 4afabad3abefef5a8ae5c46dcdd173033921d37f..3ecf8e7684a5add17844ab0275948b272dc5f19f 100644 (file)
@@ -322,166 +322,117 @@ 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\", neighbor : \"%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);
        }
 }
 
-
 static int proc_vis_read(struct seq_file *seq, void *offset)
 {
        HASHIT(hashit);
        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 (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 */
+               /* add primary/secondary records */
+               proc_vis_read_prim_sec(seq, &vis_if_list);
+               seq_printf(seq, "\n");
        }
        spin_unlock(&vis_hash_lock);
 
-       if (current_format == DOT_DRAW)
-               seq_printf(seq, "}\n");
-       else
-               seq_printf(seq, "\n");
 end:
        return 0;
 }
index 16d3efdebe52e34500475c4082bb7d2930b037c8..761c5f8f95f63e26ff299dd92298c8f0acd504d4 100644 (file)
 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;
-};