Commit f8214865 authored by Martin Hundebøll's avatar Martin Hundebøll Committed by Antonio Quartulli

batman-adv: Add get_ethtool_stats() support

Added additional counters in a bat_stats structure, which are exported
through the ethtool api. The counters are specific to batman-adv and
includes:
 forwarded packets and bytes
 management packets and bytes (aggregated OGMs at this point)
 translation table packets

New counters are added by extending "enum bat_counters" in types.h and
adding corresponding  descriptive string(s) to bat_counters_strings in
soft-iface.c.

Counters are increased by calling batadv_add_counter() and incremented
by one by calling batadv_inc_counter().
Signed-off-by: default avatarMartin Hundebøll <martin@hundeboll.net>
Signed-off-by: default avatarSven Eckelmann <sven@narfation.org>
parent 66a1b2bc
...@@ -211,6 +211,11 @@ The debug output can be changed at runtime using the file ...@@ -211,6 +211,11 @@ The debug output can be changed at runtime using the file
will enable debug messages for when routes change. will enable debug messages for when routes change.
Counters for different types of packets entering and leaving the
batman-adv module are available through ethtool:
# ethtool --statistics bat0
BATCTL BATCTL
------ ------
......
...@@ -196,8 +196,12 @@ static void bat_iv_ogm_send_to_if(struct forw_packet *forw_packet, ...@@ -196,8 +196,12 @@ static void bat_iv_ogm_send_to_if(struct forw_packet *forw_packet,
/* create clone because function is called more than once */ /* create clone because function is called more than once */
skb = skb_clone(forw_packet->skb, GFP_ATOMIC); skb = skb_clone(forw_packet->skb, GFP_ATOMIC);
if (skb) if (skb) {
batadv_inc_counter(bat_priv, BAT_CNT_MGMT_TX);
batadv_add_counter(bat_priv, BAT_CNT_MGMT_TX_BYTES,
skb->len + ETH_HLEN);
send_skb_packet(skb, hard_iface, broadcast_addr); send_skb_packet(skb, hard_iface, broadcast_addr);
}
} }
/* send a batman ogm packet */ /* send a batman ogm packet */
...@@ -1203,6 +1207,10 @@ static int bat_iv_ogm_receive(struct sk_buff *skb, ...@@ -1203,6 +1207,10 @@ static int bat_iv_ogm_receive(struct sk_buff *skb,
if (bat_priv->bat_algo_ops->bat_ogm_emit != bat_iv_ogm_emit) if (bat_priv->bat_algo_ops->bat_ogm_emit != bat_iv_ogm_emit)
return NET_RX_DROP; return NET_RX_DROP;
batadv_inc_counter(bat_priv, BAT_CNT_MGMT_RX);
batadv_add_counter(bat_priv, BAT_CNT_MGMT_RX_BYTES,
skb->len + ETH_HLEN);
packet_len = skb_headlen(skb); packet_len = skb_headlen(skb);
ethhdr = (struct ethhdr *)skb_mac_header(skb); ethhdr = (struct ethhdr *)skb_mac_header(skb);
packet_buff = skb->data; packet_buff = skb->data;
......
...@@ -153,6 +153,8 @@ void mesh_free(struct net_device *soft_iface) ...@@ -153,6 +153,8 @@ void mesh_free(struct net_device *soft_iface)
bla_free(bat_priv); bla_free(bat_priv);
free_percpu(bat_priv->bat_counters);
atomic_set(&bat_priv->mesh_state, MESH_INACTIVE); atomic_set(&bat_priv->mesh_state, MESH_INACTIVE);
} }
......
...@@ -138,6 +138,7 @@ enum dbg_level { ...@@ -138,6 +138,7 @@ enum dbg_level {
#include <linux/kthread.h> /* kernel threads */ #include <linux/kthread.h> /* kernel threads */
#include <linux/pkt_sched.h> /* schedule types */ #include <linux/pkt_sched.h> /* schedule types */
#include <linux/workqueue.h> /* workqueue */ #include <linux/workqueue.h> /* workqueue */
#include <linux/percpu.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <net/sock.h> /* struct sock */ #include <net/sock.h> /* struct sock */
#include <linux/jiffies.h> #include <linux/jiffies.h>
...@@ -242,4 +243,30 @@ static inline bool has_timed_out(unsigned long timestamp, unsigned int timeout) ...@@ -242,4 +243,30 @@ static inline bool has_timed_out(unsigned long timestamp, unsigned int timeout)
_dummy > smallest_signed_int(_dummy); }) _dummy > smallest_signed_int(_dummy); })
#define seq_after(x, y) seq_before(y, x) #define seq_after(x, y) seq_before(y, x)
/* Stop preemption on local cpu while incrementing the counter */
static inline void batadv_add_counter(struct bat_priv *bat_priv, size_t idx,
size_t count)
{
int cpu = get_cpu();
per_cpu_ptr(bat_priv->bat_counters, cpu)[idx] += count;
put_cpu();
}
#define batadv_inc_counter(b, i) batadv_add_counter(b, i, 1)
/* Sum and return the cpu-local counters for index 'idx' */
static inline uint64_t batadv_sum_counter(struct bat_priv *bat_priv, size_t idx)
{
uint64_t *counters;
int cpu;
int sum = 0;
for_each_possible_cpu(cpu) {
counters = per_cpu_ptr(bat_priv->bat_counters, cpu);
sum += counters[idx];
}
return sum;
}
#endif /* _NET_BATMAN_ADV_MAIN_H_ */ #endif /* _NET_BATMAN_ADV_MAIN_H_ */
...@@ -600,6 +600,8 @@ int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if) ...@@ -600,6 +600,8 @@ int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if)
switch (tt_query->flags & TT_QUERY_TYPE_MASK) { switch (tt_query->flags & TT_QUERY_TYPE_MASK) {
case TT_REQUEST: case TT_REQUEST:
batadv_inc_counter(bat_priv, BAT_CNT_TT_REQUEST_RX);
/* If we cannot provide an answer the tt_request is /* If we cannot provide an answer the tt_request is
* forwarded */ * forwarded */
if (!send_tt_response(bat_priv, tt_query)) { if (!send_tt_response(bat_priv, tt_query)) {
...@@ -612,6 +614,8 @@ int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if) ...@@ -612,6 +614,8 @@ int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if)
} }
break; break;
case TT_RESPONSE: case TT_RESPONSE:
batadv_inc_counter(bat_priv, BAT_CNT_TT_RESPONSE_RX);
if (is_my_mac(tt_query->dst)) { if (is_my_mac(tt_query->dst)) {
/* packet needs to be linearized to access the TT /* packet needs to be linearized to access the TT
* changes */ * changes */
...@@ -665,6 +669,8 @@ int recv_roam_adv(struct sk_buff *skb, struct hard_iface *recv_if) ...@@ -665,6 +669,8 @@ int recv_roam_adv(struct sk_buff *skb, struct hard_iface *recv_if)
if (is_broadcast_ether_addr(ethhdr->h_source)) if (is_broadcast_ether_addr(ethhdr->h_source))
goto out; goto out;
batadv_inc_counter(bat_priv, BAT_CNT_TT_ROAM_ADV_RX);
roam_adv_packet = (struct roam_adv_packet *)skb->data; roam_adv_packet = (struct roam_adv_packet *)skb->data;
if (!is_my_mac(roam_adv_packet->dst)) if (!is_my_mac(roam_adv_packet->dst))
...@@ -872,6 +878,11 @@ static int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if) ...@@ -872,6 +878,11 @@ static int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
/* decrement ttl */ /* decrement ttl */
unicast_packet->header.ttl--; unicast_packet->header.ttl--;
/* Update stats counter */
batadv_inc_counter(bat_priv, BAT_CNT_FORWARD);
batadv_add_counter(bat_priv, BAT_CNT_FORWARD_BYTES,
skb->len + ETH_HLEN);
/* route it */ /* route it */
send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
ret = NET_RX_SUCCESS; ret = NET_RX_SUCCESS;
......
...@@ -45,6 +45,10 @@ static void bat_get_drvinfo(struct net_device *dev, ...@@ -45,6 +45,10 @@ static void bat_get_drvinfo(struct net_device *dev,
static u32 bat_get_msglevel(struct net_device *dev); static u32 bat_get_msglevel(struct net_device *dev);
static void bat_set_msglevel(struct net_device *dev, u32 value); static void bat_set_msglevel(struct net_device *dev, u32 value);
static u32 bat_get_link(struct net_device *dev); static u32 bat_get_link(struct net_device *dev);
static void batadv_get_strings(struct net_device *dev, u32 stringset, u8 *data);
static void batadv_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 *data);
static int batadv_get_sset_count(struct net_device *dev, int stringset);
static const struct ethtool_ops bat_ethtool_ops = { static const struct ethtool_ops bat_ethtool_ops = {
.get_settings = bat_get_settings, .get_settings = bat_get_settings,
...@@ -52,6 +56,9 @@ static const struct ethtool_ops bat_ethtool_ops = { ...@@ -52,6 +56,9 @@ static const struct ethtool_ops bat_ethtool_ops = {
.get_msglevel = bat_get_msglevel, .get_msglevel = bat_get_msglevel,
.set_msglevel = bat_set_msglevel, .set_msglevel = bat_set_msglevel,
.get_link = bat_get_link, .get_link = bat_get_link,
.get_strings = batadv_get_strings,
.get_ethtool_stats = batadv_get_ethtool_stats,
.get_sset_count = batadv_get_sset_count,
}; };
int my_skb_head_push(struct sk_buff *skb, unsigned int len) int my_skb_head_push(struct sk_buff *skb, unsigned int len)
...@@ -399,13 +406,18 @@ struct net_device *softif_create(const char *name) ...@@ -399,13 +406,18 @@ struct net_device *softif_create(const char *name)
bat_priv->primary_if = NULL; bat_priv->primary_if = NULL;
bat_priv->num_ifaces = 0; bat_priv->num_ifaces = 0;
bat_priv->bat_counters = __alloc_percpu(sizeof(uint64_t) * BAT_CNT_NUM,
__alignof__(uint64_t));
if (!bat_priv->bat_counters)
goto unreg_soft_iface;
ret = bat_algo_select(bat_priv, bat_routing_algo); ret = bat_algo_select(bat_priv, bat_routing_algo);
if (ret < 0) if (ret < 0)
goto unreg_soft_iface; goto free_bat_counters;
ret = sysfs_add_meshif(soft_iface); ret = sysfs_add_meshif(soft_iface);
if (ret < 0) if (ret < 0)
goto unreg_soft_iface; goto free_bat_counters;
ret = debugfs_add_meshif(soft_iface); ret = debugfs_add_meshif(soft_iface);
if (ret < 0) if (ret < 0)
...@@ -421,6 +433,8 @@ struct net_device *softif_create(const char *name) ...@@ -421,6 +433,8 @@ struct net_device *softif_create(const char *name)
debugfs_del_meshif(soft_iface); debugfs_del_meshif(soft_iface);
unreg_sysfs: unreg_sysfs:
sysfs_del_meshif(soft_iface); sysfs_del_meshif(soft_iface);
free_bat_counters:
free_percpu(bat_priv->bat_counters);
unreg_soft_iface: unreg_soft_iface:
unregister_netdevice(soft_iface); unregister_netdevice(soft_iface);
return NULL; return NULL;
...@@ -486,3 +500,51 @@ static u32 bat_get_link(struct net_device *dev) ...@@ -486,3 +500,51 @@ static u32 bat_get_link(struct net_device *dev)
{ {
return 1; return 1;
} }
/* Inspired by drivers/net/ethernet/dlink/sundance.c:1702
* Declare each description string in struct.name[] to get fixed sized buffer
* and compile time checking for strings longer than ETH_GSTRING_LEN.
*/
static const struct {
const char name[ETH_GSTRING_LEN];
} bat_counters_strings[] = {
{ "forward" },
{ "forward_bytes" },
{ "mgmt_tx" },
{ "mgmt_tx_bytes" },
{ "mgmt_rx" },
{ "mgmt_rx_bytes" },
{ "tt_request_tx" },
{ "tt_request_rx" },
{ "tt_response_tx" },
{ "tt_response_rx" },
{ "tt_roam_adv_tx" },
{ "tt_roam_adv_rx" },
};
static void batadv_get_strings(struct net_device *dev, uint32_t stringset,
uint8_t *data)
{
if (stringset == ETH_SS_STATS)
memcpy(data, bat_counters_strings,
sizeof(bat_counters_strings));
}
static void batadv_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats,
uint64_t *data)
{
struct bat_priv *bat_priv = netdev_priv(dev);
int i;
for (i = 0; i < BAT_CNT_NUM; i++)
data[i] = batadv_sum_counter(bat_priv, i);
}
static int batadv_get_sset_count(struct net_device *dev, int stringset)
{
if (stringset == ETH_SS_STATS)
return BAT_CNT_NUM;
return -EOPNOTSUPP;
}
...@@ -1356,6 +1356,8 @@ static int send_tt_request(struct bat_priv *bat_priv, ...@@ -1356,6 +1356,8 @@ static int send_tt_request(struct bat_priv *bat_priv,
dst_orig_node->orig, neigh_node->addr, dst_orig_node->orig, neigh_node->addr,
(full_table ? 'F' : '.')); (full_table ? 'F' : '.'));
batadv_inc_counter(bat_priv, BAT_CNT_TT_REQUEST_TX);
send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
ret = 0; ret = 0;
...@@ -1480,6 +1482,8 @@ static bool send_other_tt_response(struct bat_priv *bat_priv, ...@@ -1480,6 +1482,8 @@ static bool send_other_tt_response(struct bat_priv *bat_priv,
res_dst_orig_node->orig, neigh_node->addr, res_dst_orig_node->orig, neigh_node->addr,
req_dst_orig_node->orig, req_ttvn); req_dst_orig_node->orig, req_ttvn);
batadv_inc_counter(bat_priv, BAT_CNT_TT_RESPONSE_TX);
send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
ret = true; ret = true;
goto out; goto out;
...@@ -1596,6 +1600,8 @@ static bool send_my_tt_response(struct bat_priv *bat_priv, ...@@ -1596,6 +1600,8 @@ static bool send_my_tt_response(struct bat_priv *bat_priv,
orig_node->orig, neigh_node->addr, orig_node->orig, neigh_node->addr,
(tt_response->flags & TT_FULL_TABLE ? 'F' : '.')); (tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
batadv_inc_counter(bat_priv, BAT_CNT_TT_RESPONSE_TX);
send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
ret = true; ret = true;
goto out; goto out;
...@@ -1895,6 +1901,8 @@ static void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client, ...@@ -1895,6 +1901,8 @@ static void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
"Sending ROAMING_ADV to %pM (client %pM) via %pM\n", "Sending ROAMING_ADV to %pM (client %pM) via %pM\n",
orig_node->orig, client, neigh_node->addr); orig_node->orig, client, neigh_node->addr);
batadv_inc_counter(bat_priv, BAT_CNT_TT_ROAM_ADV_TX);
send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
ret = 0; ret = 0;
......
...@@ -148,9 +148,26 @@ struct bcast_duplist_entry { ...@@ -148,9 +148,26 @@ struct bcast_duplist_entry {
}; };
#endif #endif
enum bat_counters {
BAT_CNT_FORWARD,
BAT_CNT_FORWARD_BYTES,
BAT_CNT_MGMT_TX,
BAT_CNT_MGMT_TX_BYTES,
BAT_CNT_MGMT_RX,
BAT_CNT_MGMT_RX_BYTES,
BAT_CNT_TT_REQUEST_TX,
BAT_CNT_TT_REQUEST_RX,
BAT_CNT_TT_RESPONSE_TX,
BAT_CNT_TT_RESPONSE_RX,
BAT_CNT_TT_ROAM_ADV_TX,
BAT_CNT_TT_ROAM_ADV_RX,
BAT_CNT_NUM,
};
struct bat_priv { struct bat_priv {
atomic_t mesh_state; atomic_t mesh_state;
struct net_device_stats stats; struct net_device_stats stats;
uint64_t __percpu *bat_counters; /* Per cpu counters */
atomic_t aggregated_ogms; /* boolean */ atomic_t aggregated_ogms; /* boolean */
atomic_t bonding; /* boolean */ atomic_t bonding; /* boolean */
atomic_t fragmentation; /* boolean */ atomic_t fragmentation; /* boolean */
......
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