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: Martin Hundebøll <martin@hundeboll.net> Signed-off-by: Sven Eckelmann <sven@narfation.org>
This commit is contained in:
committed by
Antonio Quartulli
parent
66a1b2bcb3
commit
f8214865a5
@@ -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,
|
|||||||
|
|
||||||
/* 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,
|
|||||||
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)
|
|||||||
|
|
||||||
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 {
|
|||||||
#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)
|
|||||||
_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)
|
|||||||
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
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)
|
|||||||
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)
|
|||||||
/* 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,
|
|||||||
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 = {
|
|||||||
.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)
|
|||||||
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 @@ unreg_debugfs:
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
"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 {
|
|||||||
};
|
};
|
||||||
#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 */
|
||||||
|
Reference in New Issue
Block a user