Commit 9354d452 authored by Jiri Benc's avatar Jiri Benc Committed by David S. Miller

openvswitch: reliable interface indentification in port dumps

This patch allows reliable identification of netdevice interfaces connected
to openvswitch bridges. In particular, user space queries the netdev
interfaces belonging to the ports for statistics, up/down state, etc.
Datapath dump needs to provide enough information for the user space to be
able to do that.

Currently, only interface names are returned. This is not sufficient, as
openvswitch allows its ports to be in different name spaces and the
interface name is valid only in its name space. What is needed and generally
used in other netlink APIs, is the pair ifindex+netnsid.

The solution is addition of the ifindex+netnsid pair (or only ifindex if in
the same name space) to vport get/dump operation.

On request side, ideally the ifindex+netnsid pair could be used to
get/set/del the corresponding vport. This is not implemented by this patch
and can be added later if needed.
Signed-off-by: default avatarJiri Benc <jbenc@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7cbebc8a
...@@ -258,6 +258,8 @@ enum ovs_vport_attr { ...@@ -258,6 +258,8 @@ enum ovs_vport_attr {
/* receiving upcalls */ /* receiving upcalls */
OVS_VPORT_ATTR_STATS, /* struct ovs_vport_stats */ OVS_VPORT_ATTR_STATS, /* struct ovs_vport_stats */
OVS_VPORT_ATTR_PAD, OVS_VPORT_ATTR_PAD,
OVS_VPORT_ATTR_IFINDEX,
OVS_VPORT_ATTR_NETNSID,
__OVS_VPORT_ATTR_MAX __OVS_VPORT_ATTR_MAX
}; };
......
...@@ -1848,7 +1848,8 @@ static struct genl_family dp_datapath_genl_family __ro_after_init = { ...@@ -1848,7 +1848,8 @@ static struct genl_family dp_datapath_genl_family __ro_after_init = {
/* Called with ovs_mutex or RCU read lock. */ /* Called with ovs_mutex or RCU read lock. */
static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb,
u32 portid, u32 seq, u32 flags, u8 cmd) struct net *net, u32 portid, u32 seq,
u32 flags, u8 cmd)
{ {
struct ovs_header *ovs_header; struct ovs_header *ovs_header;
struct ovs_vport_stats vport_stats; struct ovs_vport_stats vport_stats;
...@@ -1864,9 +1865,17 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, ...@@ -1864,9 +1865,17 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb,
if (nla_put_u32(skb, OVS_VPORT_ATTR_PORT_NO, vport->port_no) || if (nla_put_u32(skb, OVS_VPORT_ATTR_PORT_NO, vport->port_no) ||
nla_put_u32(skb, OVS_VPORT_ATTR_TYPE, vport->ops->type) || nla_put_u32(skb, OVS_VPORT_ATTR_TYPE, vport->ops->type) ||
nla_put_string(skb, OVS_VPORT_ATTR_NAME, nla_put_string(skb, OVS_VPORT_ATTR_NAME,
ovs_vport_name(vport))) ovs_vport_name(vport)) ||
nla_put_u32(skb, OVS_VPORT_ATTR_IFINDEX, vport->dev->ifindex))
goto nla_put_failure; goto nla_put_failure;
if (!net_eq(net, dev_net(vport->dev))) {
int id = peernet2id_alloc(net, dev_net(vport->dev));
if (nla_put_s32(skb, OVS_VPORT_ATTR_NETNSID, id))
goto nla_put_failure;
}
ovs_vport_get_stats(vport, &vport_stats); ovs_vport_get_stats(vport, &vport_stats);
if (nla_put_64bit(skb, OVS_VPORT_ATTR_STATS, if (nla_put_64bit(skb, OVS_VPORT_ATTR_STATS,
sizeof(struct ovs_vport_stats), &vport_stats, sizeof(struct ovs_vport_stats), &vport_stats,
...@@ -1896,8 +1905,8 @@ static struct sk_buff *ovs_vport_cmd_alloc_info(void) ...@@ -1896,8 +1905,8 @@ static struct sk_buff *ovs_vport_cmd_alloc_info(void)
} }
/* Called with ovs_mutex, only via ovs_dp_notify_wq(). */ /* Called with ovs_mutex, only via ovs_dp_notify_wq(). */
struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, u32 portid, struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, struct net *net,
u32 seq, u8 cmd) u32 portid, u32 seq, u8 cmd)
{ {
struct sk_buff *skb; struct sk_buff *skb;
int retval; int retval;
...@@ -1906,7 +1915,7 @@ struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, u32 portid, ...@@ -1906,7 +1915,7 @@ struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, u32 portid,
if (!skb) if (!skb)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
retval = ovs_vport_cmd_fill_info(vport, skb, portid, seq, 0, cmd); retval = ovs_vport_cmd_fill_info(vport, skb, net, portid, seq, 0, cmd);
BUG_ON(retval < 0); BUG_ON(retval < 0);
return skb; return skb;
...@@ -1920,6 +1929,8 @@ static struct vport *lookup_vport(struct net *net, ...@@ -1920,6 +1929,8 @@ static struct vport *lookup_vport(struct net *net,
struct datapath *dp; struct datapath *dp;
struct vport *vport; struct vport *vport;
if (a[OVS_VPORT_ATTR_IFINDEX])
return ERR_PTR(-EOPNOTSUPP);
if (a[OVS_VPORT_ATTR_NAME]) { if (a[OVS_VPORT_ATTR_NAME]) {
vport = ovs_vport_locate(net, nla_data(a[OVS_VPORT_ATTR_NAME])); vport = ovs_vport_locate(net, nla_data(a[OVS_VPORT_ATTR_NAME]));
if (!vport) if (!vport)
...@@ -1944,6 +1955,7 @@ static struct vport *lookup_vport(struct net *net, ...@@ -1944,6 +1955,7 @@ static struct vport *lookup_vport(struct net *net,
return vport; return vport;
} else } else
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
/* Called with ovs_mutex */ /* Called with ovs_mutex */
...@@ -1983,6 +1995,8 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info) ...@@ -1983,6 +1995,8 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
if (!a[OVS_VPORT_ATTR_NAME] || !a[OVS_VPORT_ATTR_TYPE] || if (!a[OVS_VPORT_ATTR_NAME] || !a[OVS_VPORT_ATTR_TYPE] ||
!a[OVS_VPORT_ATTR_UPCALL_PID]) !a[OVS_VPORT_ATTR_UPCALL_PID])
return -EINVAL; return -EINVAL;
if (a[OVS_VPORT_ATTR_IFINDEX])
return -EOPNOTSUPP;
port_no = a[OVS_VPORT_ATTR_PORT_NO] port_no = a[OVS_VPORT_ATTR_PORT_NO]
? nla_get_u32(a[OVS_VPORT_ATTR_PORT_NO]) : 0; ? nla_get_u32(a[OVS_VPORT_ATTR_PORT_NO]) : 0;
...@@ -2032,8 +2046,9 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info) ...@@ -2032,8 +2046,9 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
goto exit_unlock_free; goto exit_unlock_free;
} }
err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid, err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
info->snd_seq, 0, OVS_VPORT_CMD_NEW); info->snd_portid, info->snd_seq, 0,
OVS_VPORT_CMD_NEW);
if (netdev_get_fwd_headroom(vport->dev) > dp->max_headroom) if (netdev_get_fwd_headroom(vport->dev) > dp->max_headroom)
update_headroom(dp); update_headroom(dp);
...@@ -2090,8 +2105,9 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info) ...@@ -2090,8 +2105,9 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info)
goto exit_unlock_free; goto exit_unlock_free;
} }
err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid, err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
info->snd_seq, 0, OVS_VPORT_CMD_NEW); info->snd_portid, info->snd_seq, 0,
OVS_VPORT_CMD_NEW);
BUG_ON(err < 0); BUG_ON(err < 0);
ovs_unlock(); ovs_unlock();
...@@ -2128,8 +2144,9 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info) ...@@ -2128,8 +2144,9 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
goto exit_unlock_free; goto exit_unlock_free;
} }
err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid, err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
info->snd_seq, 0, OVS_VPORT_CMD_DEL); info->snd_portid, info->snd_seq, 0,
OVS_VPORT_CMD_DEL);
BUG_ON(err < 0); BUG_ON(err < 0);
/* the vport deletion may trigger dp headroom update */ /* the vport deletion may trigger dp headroom update */
...@@ -2169,8 +2186,9 @@ static int ovs_vport_cmd_get(struct sk_buff *skb, struct genl_info *info) ...@@ -2169,8 +2186,9 @@ static int ovs_vport_cmd_get(struct sk_buff *skb, struct genl_info *info)
err = PTR_ERR(vport); err = PTR_ERR(vport);
if (IS_ERR(vport)) if (IS_ERR(vport))
goto exit_unlock_free; goto exit_unlock_free;
err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid, err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
info->snd_seq, 0, OVS_VPORT_CMD_NEW); info->snd_portid, info->snd_seq, 0,
OVS_VPORT_CMD_NEW);
BUG_ON(err < 0); BUG_ON(err < 0);
rcu_read_unlock(); rcu_read_unlock();
...@@ -2202,6 +2220,7 @@ static int ovs_vport_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -2202,6 +2220,7 @@ static int ovs_vport_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
hlist_for_each_entry_rcu(vport, &dp->ports[i], dp_hash_node) { hlist_for_each_entry_rcu(vport, &dp->ports[i], dp_hash_node) {
if (j >= skip && if (j >= skip &&
ovs_vport_cmd_fill_info(vport, skb, ovs_vport_cmd_fill_info(vport, skb,
sock_net(skb->sk),
NETLINK_CB(cb->skb).portid, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, cb->nlh->nlmsg_seq,
NLM_F_MULTI, NLM_F_MULTI,
...@@ -2228,6 +2247,8 @@ static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = { ...@@ -2228,6 +2247,8 @@ static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = {
[OVS_VPORT_ATTR_TYPE] = { .type = NLA_U32 }, [OVS_VPORT_ATTR_TYPE] = { .type = NLA_U32 },
[OVS_VPORT_ATTR_UPCALL_PID] = { .type = NLA_U32 }, [OVS_VPORT_ATTR_UPCALL_PID] = { .type = NLA_U32 },
[OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED }, [OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED },
[OVS_VPORT_ATTR_IFINDEX] = { .type = NLA_U32 },
[OVS_VPORT_ATTR_NETNSID] = { .type = NLA_S32 },
}; };
static const struct genl_ops dp_vport_genl_ops[] = { static const struct genl_ops dp_vport_genl_ops[] = {
......
...@@ -200,8 +200,8 @@ int ovs_dp_upcall(struct datapath *, struct sk_buff *, ...@@ -200,8 +200,8 @@ int ovs_dp_upcall(struct datapath *, struct sk_buff *,
uint32_t cutlen); uint32_t cutlen);
const char *ovs_dp_name(const struct datapath *dp); const char *ovs_dp_name(const struct datapath *dp);
struct sk_buff *ovs_vport_cmd_build_info(struct vport *, u32 pid, u32 seq, struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, struct net *net,
u8 cmd); u32 portid, u32 seq, u8 cmd);
int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb, int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb,
const struct sw_flow_actions *, struct sw_flow_key *); const struct sw_flow_actions *, struct sw_flow_key *);
......
...@@ -30,8 +30,8 @@ static void dp_detach_port_notify(struct vport *vport) ...@@ -30,8 +30,8 @@ static void dp_detach_port_notify(struct vport *vport)
struct datapath *dp; struct datapath *dp;
dp = vport->dp; dp = vport->dp;
notify = ovs_vport_cmd_build_info(vport, 0, 0, notify = ovs_vport_cmd_build_info(vport, ovs_dp_get_net(dp),
OVS_VPORT_CMD_DEL); 0, 0, OVS_VPORT_CMD_DEL);
ovs_dp_detach_port(vport); ovs_dp_detach_port(vport);
if (IS_ERR(notify)) { if (IS_ERR(notify)) {
genl_set_err(&dp_vport_genl_family, ovs_dp_get_net(dp), 0, genl_set_err(&dp_vport_genl_family, ovs_dp_get_net(dp), 0,
......
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