Skip to content

Commit

Permalink
net: openvswitch: Add support to count upcall packets
Browse files Browse the repository at this point in the history
Add support to count upall packets, when kmod of openvswitch
upcall to count the number of packets for upcall succeed and
failed, which is a better way to see how many packets upcalled
on every interfaces.

Signed-off-by: wangchuanlei <wangchuanlei@inspur.com>
Acked-by: Eelco Chaudron <echaudro@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
wangchuanlei authored and davem330 committed Dec 9, 2022
1 parent e47877c commit 1933ea3
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 0 deletions.
14 changes: 14 additions & 0 deletions include/uapi/linux/openvswitch.h
Original file line number Diff line number Diff line change
Expand Up @@ -277,11 +277,25 @@ enum ovs_vport_attr {
OVS_VPORT_ATTR_PAD,
OVS_VPORT_ATTR_IFINDEX,
OVS_VPORT_ATTR_NETNSID,
OVS_VPORT_ATTR_UPCALL_STATS,
__OVS_VPORT_ATTR_MAX
};

#define OVS_VPORT_ATTR_MAX (__OVS_VPORT_ATTR_MAX - 1)

/**
* enum ovs_vport_upcall_attr - attributes for %OVS_VPORT_UPCALL* commands
* @OVS_VPORT_UPCALL_SUCCESS: 64-bit upcall success packets.
* @OVS_VPORT_UPCALL_FAIL: 64-bit upcall fail packets.
*/
enum ovs_vport_upcall_attr {
OVS_VPORT_UPCALL_ATTR_SUCCESS,
OVS_VPORT_UPCALL_ATTR_FAIL,
__OVS_VPORT_UPCALL_ATTR_MAX
};

#define OVS_VPORT_UPCALL_ATTR_MAX (__OVS_VPORT_UPCALL_ATTR_MAX - 1)

enum {
OVS_VXLAN_EXT_UNSPEC,
OVS_VXLAN_EXT_GBP, /* Flag or __u32 */
Expand Down
41 changes: 41 additions & 0 deletions net/openvswitch/datapath.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,13 +209,36 @@ static struct vport *new_vport(const struct vport_parms *parms)
return vport;
}

static void ovs_vport_update_upcall_stats(struct sk_buff *skb,
const struct dp_upcall_info *upcall_info,
bool upcall_result)
{
struct vport *p = OVS_CB(skb)->input_vport;
struct vport_upcall_stats_percpu *stats;

if (upcall_info->cmd != OVS_PACKET_CMD_MISS &&
upcall_info->cmd != OVS_PACKET_CMD_ACTION)
return;

stats = this_cpu_ptr(p->upcall_stats);
u64_stats_update_begin(&stats->syncp);
if (upcall_result)
u64_stats_inc(&stats->n_success);
else
u64_stats_inc(&stats->n_fail);
u64_stats_update_end(&stats->syncp);
}

void ovs_dp_detach_port(struct vport *p)
{
ASSERT_OVSL();

/* First drop references to device. */
hlist_del_rcu(&p->dp_hash_node);

/* Free percpu memory */
free_percpu(p->upcall_stats);

/* Then destroy it. */
ovs_vport_del(p);
}
Expand Down Expand Up @@ -305,6 +328,8 @@ int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb,
err = queue_userspace_packet(dp, skb, key, upcall_info, cutlen);
else
err = queue_gso_packets(dp, skb, key, upcall_info, cutlen);

ovs_vport_update_upcall_stats(skb, upcall_info, !err);
if (err)
goto err;

Expand Down Expand Up @@ -1826,6 +1851,12 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
goto err_destroy_portids;
}

vport->upcall_stats = netdev_alloc_pcpu_stats(struct vport_upcall_stats_percpu);
if (!vport->upcall_stats) {
err = -ENOMEM;
goto err_destroy_portids;
}

err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
info->snd_seq, 0, OVS_DP_CMD_NEW);
BUG_ON(err < 0);
Expand Down Expand Up @@ -2098,6 +2129,9 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb,
OVS_VPORT_ATTR_PAD))
goto nla_put_failure;

if (ovs_vport_get_upcall_stats(vport, skb))
goto nla_put_failure;

if (ovs_vport_get_upcall_portids(vport, skb))
goto nla_put_failure;

Expand Down Expand Up @@ -2279,6 +2313,12 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
goto exit_unlock_free;
}

vport->upcall_stats = netdev_alloc_pcpu_stats(struct vport_upcall_stats_percpu);
if (!vport->upcall_stats) {
err = -ENOMEM;
goto exit_unlock_free;
}

err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
info->snd_portid, info->snd_seq, 0,
OVS_VPORT_CMD_NEW, GFP_KERNEL);
Expand Down Expand Up @@ -2508,6 +2548,7 @@ static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = {
[OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED },
[OVS_VPORT_ATTR_IFINDEX] = { .type = NLA_U32 },
[OVS_VPORT_ATTR_NETNSID] = { .type = NLA_S32 },
[OVS_VPORT_ATTR_UPCALL_STATS] = { .type = NLA_NESTED },
};

static const struct genl_small_ops dp_vport_genl_ops[] = {
Expand Down
50 changes: 50 additions & 0 deletions net/openvswitch/vport.c
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,56 @@ void ovs_vport_get_stats(struct vport *vport, struct ovs_vport_stats *stats)
stats->tx_packets = dev_stats->tx_packets;
}

/**
* ovs_vport_get_upcall_stats - retrieve upcall stats
*
* @vport: vport from which to retrieve the stats.
* @skb: sk_buff where upcall stats should be appended.
*
* Retrieves upcall stats for the given device.
*
* Must be called with ovs_mutex or rcu_read_lock.
*/
int ovs_vport_get_upcall_stats(struct vport *vport, struct sk_buff *skb)
{
struct nlattr *nla;
int i;

__u64 tx_success = 0;
__u64 tx_fail = 0;

for_each_possible_cpu(i) {
const struct vport_upcall_stats_percpu *stats;
unsigned int start;

stats = per_cpu_ptr(vport->upcall_stats, i);
do {
start = u64_stats_fetch_begin(&stats->syncp);
tx_success += u64_stats_read(&stats->n_success);
tx_fail += u64_stats_read(&stats->n_fail);
} while (u64_stats_fetch_retry(&stats->syncp, start));
}

nla = nla_nest_start_noflag(skb, OVS_VPORT_ATTR_UPCALL_STATS);
if (!nla)
return -EMSGSIZE;

if (nla_put_u64_64bit(skb, OVS_VPORT_UPCALL_ATTR_SUCCESS, tx_success,
OVS_VPORT_ATTR_PAD)) {
nla_nest_cancel(skb, nla);
return -EMSGSIZE;
}

if (nla_put_u64_64bit(skb, OVS_VPORT_UPCALL_ATTR_FAIL, tx_fail,
OVS_VPORT_ATTR_PAD)) {
nla_nest_cancel(skb, nla);
return -EMSGSIZE;
}
nla_nest_end(skb, nla);

return 0;
}

/**
* ovs_vport_get_options - retrieve device options
*
Expand Down
16 changes: 16 additions & 0 deletions net/openvswitch/vport.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ struct vport *ovs_vport_locate(const struct net *net, const char *name);

void ovs_vport_get_stats(struct vport *, struct ovs_vport_stats *);

int ovs_vport_get_upcall_stats(struct vport *vport, struct sk_buff *skb);

int ovs_vport_set_options(struct vport *, struct nlattr *options);
int ovs_vport_get_options(const struct vport *, struct sk_buff *);

Expand Down Expand Up @@ -65,6 +67,7 @@ struct vport_portids {
* @hash_node: Element in @dev_table hash table in vport.c.
* @dp_hash_node: Element in @datapath->ports hash table in datapath.c.
* @ops: Class structure.
* @upcall_stats: Upcall stats of every ports.
* @detach_list: list used for detaching vport in net-exit call.
* @rcu: RCU callback head for deferred destruction.
*/
Expand All @@ -78,6 +81,7 @@ struct vport {
struct hlist_node hash_node;
struct hlist_node dp_hash_node;
const struct vport_ops *ops;
struct vport_upcall_stats_percpu __percpu *upcall_stats;

struct list_head detach_list;
struct rcu_head rcu;
Expand Down Expand Up @@ -137,6 +141,18 @@ struct vport_ops {
struct list_head list;
};

/**
* struct vport_upcall_stats_percpu - per-cpu packet upcall statistics for
* a given vport.
* @n_success: Number of packets that upcall to userspace succeed.
* @n_fail: Number of packets that upcall to userspace failed.
*/
struct vport_upcall_stats_percpu {
struct u64_stats_sync syncp;
u64_stats_t n_success;
u64_stats_t n_fail;
};

struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *,
const struct vport_parms *);
void ovs_vport_free(struct vport *);
Expand Down

0 comments on commit 1933ea3

Please sign in to comment.