Commit b801fede authored by Andrew Lunn's avatar Andrew Lunn Committed by Greg Kroah-Hartman

Staging: batman-adv: moving vis output formats out of the kernel

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: default avatarAndrew Lunn <andrew@lunn.ch>
Signed-off-by: default avatarMarek Lindner <lindner_marek@yahoo.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent b665aac8
...@@ -17,17 +17,6 @@ ...@@ -17,17 +17,6 @@
-> transtable_global (read-only) [outputs the global translation table] -> transtable_global (read-only) [outputs the global translation table]
-> transtable_local (read-only) [outputs the local 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 => logging
* make use of printk %pM support instead of converting mac addresses * make use of printk %pM support instead of converting mac addresses
* manually * manually
......
...@@ -322,166 +322,117 @@ static int proc_transt_global_open(struct inode *inode, struct file *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); 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, static void proc_vis_insert_interface(const uint8_t *interface,
struct vis_if_list **if_entry, struct hlist_head *if_list,
bool primary) bool primary)
{ {
/* Did we get an empty list? (then insert imediately) */ struct if_list_entry *entry;
if (*if_entry == NULL) { struct hlist_node *pos;
*if_entry = kmalloc(sizeof(struct vis_if_list), GFP_KERNEL);
if (*if_entry == NULL) hlist_for_each_entry(entry, pos, if_list, list) {
if (compare_orig(entry->addr, (void *)interface))
return; return;
}
(*if_entry)->primary = primary; /* its a new address, add it to the list */
(*if_entry)->next = NULL; entry = kmalloc(sizeof(*entry), GFP_KERNEL);
memcpy((*if_entry)->addr, interface, ETH_ALEN); if (!entry)
} else { return;
struct vis_if_list *head_if_entry = *if_entry; memcpy(entry->addr, interface, ETH_ALEN);
/* Do we already have this interface in our list? */ entry->primary = primary;
while (!compare_orig((*if_entry)->addr, (void *)interface)) { hlist_add_head(&entry->list, if_list);
}
/* Or did we reach the end (then append the interface) */
if ((*if_entry)->next == NULL) { static void proc_vis_read_prim_sec(struct seq_file *seq,
(*if_entry)->next = kmalloc(sizeof(struct vis_if_list), GFP_KERNEL); struct hlist_head *if_list)
if ((*if_entry)->next == NULL) {
return; struct if_list_entry *entry;
struct hlist_node *pos, *n;
memcpy((*if_entry)->next->addr, interface, ETH_ALEN); char tmp_addr_str[ETH_STR_LEN];
(*if_entry)->next->primary = primary;
(*if_entry)->next->next = NULL; hlist_for_each_entry_safe(entry, pos, n, if_list, list) {
break; if (entry->primary) {
} seq_printf(seq, "PRIMARY, ");
*if_entry = (*if_entry)->next; } 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, static void proc_vis_read_entry(struct seq_file *seq,
struct vis_info_entry *entry, struct vis_info_entry *entry,
struct vis_if_list **if_entry, struct hlist_head *if_list,
uint8_t *vis_orig, uint8_t *vis_orig)
uint8_t current_format,
uint8_t first_line)
{ {
char from[40];
char to[40]; char to[40];
int int_part, frac_part;
addr_to_string(to, entry->dest); addr_to_string(to, entry->dest);
if (entry->quality == 0) { if (entry->quality == 0) {
#ifndef VIS_SUBCLUSTERS_DISABLED proc_vis_insert_interface(vis_orig, if_list, true);
proc_vis_insert_interface(vis_orig, if_entry, true); seq_printf(seq, "HNA %s, ", to);
#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);
}
} else { } else {
#ifndef VIS_SUBCLUSTERS_DISABLED proc_vis_insert_interface(entry->src, if_list,
proc_vis_insert_interface(entry->src, if_entry, compare_orig(entry->src, vis_orig)); compare_orig(entry->src, vis_orig));
#endif /* VIS_SUBCLUSTERS_DISABLED */ seq_printf(seq, "TQ %s %d, ", to, entry->quality);
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);
}
} }
} }
static int proc_vis_read(struct seq_file *seq, void *offset) static int proc_vis_read(struct seq_file *seq, void *offset)
{ {
HASHIT(hashit); HASHIT(hashit);
struct vis_info *info; struct vis_info *info;
struct vis_info_entry *entries; struct vis_info_entry *entries;
struct vis_if_list *if_entries = NULL; HLIST_HEAD(vis_if_list);
int i; int i;
uint8_t current_format, first_line = 1; uint8_t current_format;
#ifndef VIS_SUBCLUSTERS_DISABLED
char tmp_addr_str[ETH_STR_LEN]; char tmp_addr_str[ETH_STR_LEN];
struct vis_if_list *tmp_if_next;
#endif /* VIS_SUBCLUSTERS_DISABLED */
current_format = vis_format; current_format = vis_format;
rcu_read_lock(); rcu_read_lock();
if (list_empty(&if_list) || (!is_vis_server())) { if (list_empty(&if_list) || (!is_vis_server())) {
rcu_read_unlock(); rcu_read_unlock();
if (current_format == DOT_DRAW)
seq_printf(seq, "digraph {\n}\n");
goto end; goto end;
} }
rcu_read_unlock(); rcu_read_unlock();
if (current_format == DOT_DRAW)
seq_printf(seq, "digraph {\n");
spin_lock(&vis_hash_lock); spin_lock(&vis_hash_lock);
while (hash_iterate(vis_hash, &hashit)) { while (hash_iterate(vis_hash, &hashit)) {
info = hashit.bucket->data; info = hashit.bucket->data;
entries = (struct vis_info_entry *) entries = (struct vis_info_entry *)
((char *)info + sizeof(struct vis_info)); ((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++) { for (i = 0; i < info->packet.entries; i++) {
proc_vis_read_entry(seq, &entries[i], &if_entries, proc_vis_read_entry(seq, &entries[i], &vis_if_list,
info->packet.vis_orig, info->packet.vis_orig);
current_format, first_line);
if (first_line)
first_line = 0;
} }
#ifndef VIS_SUBCLUSTERS_DISABLED /* add primary/secondary records */
/* Generate subgraphs from the collected items */ proc_vis_read_prim_sec(seq, &vis_if_list);
if (current_format == DOT_DRAW) { seq_printf(seq, "\n");
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); spin_unlock(&vis_hash_lock);
if (current_format == DOT_DRAW)
seq_printf(seq, "}\n");
else
seq_printf(seq, "\n");
end: end:
return 0; return 0;
} }
......
...@@ -38,12 +38,3 @@ ...@@ -38,12 +38,3 @@
void cleanup_procfs(void); void cleanup_procfs(void);
int setup_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;
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment