Support for VETH_MRU in libnl
From: Fredrik Markstrom
Date: Tue May 09 2017 - 08:45:43 EST
---
include/linux/if_link.h | 1 +
include/netlink-private/types.h | 1 +
include/netlink/route/link/veth.h | 4 ++
lib/route/link.c | 4 ++
lib/route/link/veth.c | 141 +++++++++++++++++++++++++++++---------
5 files changed, 118 insertions(+), 33 deletions(-)
diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index 8b84939..b9859bd 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -316,6 +316,7 @@ struct ifla_vxlan_port_range {
enum {
VETH_INFO_UNSPEC,
VETH_INFO_PEER,
+ VETH_MRU,
__VETH_INFO_MAX
#define VETH_INFO_MAX (__VETH_INFO_MAX - 1)
diff --git a/include/netlink-private/types.h b/include/netlink-private/types.h
index 3ff4fe1..c97090b 100644
--- a/include/netlink-private/types.h
+++ b/include/netlink-private/types.h
@@ -165,6 +165,7 @@ struct rtnl_link
uint32_t l_flags;
uint32_t l_change;
uint32_t l_mtu;
+ uint32_t l_mru;
uint32_t l_link;
uint32_t l_txqlen;
uint32_t l_weight;
diff --git a/include/netlink/route/link/veth.h b/include/netlink/route/link/veth.h
index 35c2345..58eeb98 100644
--- a/include/netlink/route/link/veth.h
+++ b/include/netlink/route/link/veth.h
@@ -29,6 +29,10 @@ extern struct rtnl_link *rtnl_link_veth_get_peer(struct rtnl_link *);
extern int rtnl_link_veth_add(struct nl_sock *sock, const char *name,
const char *peer, pid_t pid);
+extern int rtnl_link_veth_set_mru(struct rtnl_link *, uint32_t);
+
+extern uint32_t rtnl_link_veth_get_mru(struct rtnl_link *);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/route/link.c b/lib/route/link.c
index 3d31ffc..3cdacbb 100644
--- a/lib/route/link.c
+++ b/lib/route/link.c
@@ -61,6 +61,7 @@
#define LINK_ATTR_PHYS_PORT_ID (1 << 28)
#define LINK_ATTR_NS_FD (1 << 29)
#define LINK_ATTR_NS_PID (1 << 30)
+#define LINK_ATTR_MRU (1 << 31)
static struct nl_cache_ops rtnl_link_ops;
static struct nl_object_ops link_obj_ops;
@@ -1255,6 +1256,9 @@ int rtnl_link_fill_info(struct nl_msg *msg, struct rtnl_link *link)
if (link->ce_mask & LINK_ATTR_MTU)
NLA_PUT_U32(msg, IFLA_MTU, link->l_mtu);
+ if (link->ce_mask & LINK_ATTR_MRU)
+ NLA_PUT_U32(msg, IFLA_MTU, link->l_mru);
+
if (link->ce_mask & LINK_ATTR_TXQLEN)
NLA_PUT_U32(msg, IFLA_TXQLEN, link->l_txqlen);
diff --git a/lib/route/link/veth.c b/lib/route/link/veth.c
index e7e4a26..5dc15af 100644
--- a/lib/route/link/veth.c
+++ b/lib/route/link/veth.c
@@ -33,16 +33,62 @@
#include <linux/if_link.h>
+#define VETH_HAS_MRU (1<<0)
+
+struct veth_info
+{
+ struct rtnl_link *peer;
+ uint32_t vei_mru;
+ uint32_t vei_mask;
+};
+
static struct nla_policy veth_policy[VETH_INFO_MAX+1] = {
[VETH_INFO_PEER] = { .minlen = sizeof(struct ifinfomsg) },
+ [VETH_MRU] = { .type = NLA_U32 },
};
+static int veth_alloc(struct rtnl_link *link)
+{
+ struct rtnl_link *peer;
+ struct veth_info *vei = link->l_info;
+ int err;
+
+ /* return early if we are in recursion */
+ if (vei && vei->peer)
+ return 0;
+
+ if (!(peer = rtnl_link_alloc()))
+ return -NLE_NOMEM;
+
+ if ((vei = calloc(1, sizeof(*vei))) == NULL)
+ return -NLE_NOMEM;
+
+ /* We don't need to hold a reference here, as link and
+ * its peer should always be freed together.
+ */
+ vei->peer = link;
+
+ peer->l_info = vei;
+ if ((err = rtnl_link_set_type(peer, "veth")) < 0) {
+ rtnl_link_put(peer);
+ return err;
+ }
+
+ if ((vei = calloc(1, sizeof(*vei))) == NULL)
+ return -NLE_NOMEM;
+
+ vei->peer = peer;
+ link->l_info = vei;
+ return 0;
+}
+
static int veth_parse(struct rtnl_link *link, struct nlattr *data,
struct nlattr *xstats)
{
struct nlattr *tb[VETH_INFO_MAX+1];
struct nlattr *peer_tb[IFLA_MAX + 1];
- struct rtnl_link *peer = link->l_info;
+ struct veth_info *vei = link->l_info;
+ struct rtnl_link *peer = vei->peer;
int err;
NL_DBG(3, "Parsing veth link info");
@@ -50,6 +96,14 @@ static int veth_parse(struct rtnl_link *link, struct nlattr *data,
if ((err = nla_parse_nested(tb, VETH_INFO_MAX, data, veth_policy)) < 0)
goto errout;
+ if ((err = veth_alloc(link)) < 0)
+ goto errout;
+
+ if (tb[VETH_MRU]) {
+ vei->vei_mru = nla_get_u32(tb[VETH_MRU]);
+ vei->vei_mask |= VETH_HAS_MRU;
+ }
+
if (tb[VETH_INFO_PEER]) {
struct nlattr *nla_peer;
struct ifinfomsg *ifi;
@@ -86,7 +140,8 @@ static void veth_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
static void veth_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
{
- struct rtnl_link *peer = link->l_info;
+ struct veth_info *vei = link->l_info;
+ struct rtnl_link *peer = vei->peer;
char *name;
name = rtnl_link_get_name(peer);
nl_dump(p, " peer ");
@@ -98,7 +153,14 @@ static void veth_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
static int veth_clone(struct rtnl_link *dst, struct rtnl_link *src)
{
- struct rtnl_link *dst_peer = NULL, *src_peer = src->l_info;
+ struct veth_info *src_vei = src->l_info;
+ struct veth_info *dst_vei = dst->l_info;
+ struct rtnl_link *dst_peer = NULL, *src_peer = src_vei->peer;
+
+
+ printf("veth_clone not implemented\n");
+
+ // FIXME:
/* we are calling nl_object_clone() recursively, this should
* happen only once */
@@ -116,7 +178,8 @@ static int veth_clone(struct rtnl_link *dst, struct rtnl_link *src)
static int veth_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
{
- struct rtnl_link *peer = link->l_info;
+ struct veth_info *vei = link->l_info;
+ struct rtnl_link *peer = vei->peer;
struct ifinfomsg ifi;
struct nlattr *data, *info_peer;
@@ -135,44 +198,31 @@ static int veth_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
return -NLE_MSGSIZE;
rtnl_link_fill_info(msg, peer);
nla_nest_end(msg, info_peer);
- nla_nest_end(msg, data);
- return 0;
-}
-
-static int veth_alloc(struct rtnl_link *link)
-{
- struct rtnl_link *peer;
- int err;
-
- /* return early if we are in recursion */
- if (link->l_info)
- return 0;
+ if (vei->vei_mask & VETH_HAS_MRU)
+ NLA_PUT_U32(msg, VETH_MRU, vei->vei_mru);
- if (!(peer = rtnl_link_alloc()))
- return -NLE_NOMEM;
+ nla_nest_end(msg, data);
- /* We don't need to hold a reference here, as link and
- * its peer should always be freed together.
- */
- peer->l_info = link;
- if ((err = rtnl_link_set_type(peer, "veth")) < 0) {
- rtnl_link_put(peer);
- return err;
- }
+nla_put_failure:
- link->l_info = peer;
return 0;
}
static void veth_free(struct rtnl_link *link)
{
- struct rtnl_link *peer = link->l_info;
- if (peer) {
+ struct veth_info *vei = link->l_info;
+ if (vei) {
+ struct rtnl_link *peer = vei->peer;
+ if (peer) {
+ vei->peer = NULL;
+ rtnl_link_put(peer);
+ /* avoid calling this recursively */
+ free(peer->l_info);
+ peer->l_info = NULL;
+ }
+ free(vei);
link->l_info = NULL;
- /* avoid calling this recursively */
- peer->l_info = NULL;
- rtnl_link_put(peer);
}
/* the caller should finally free link */
}
@@ -195,7 +245,7 @@ static struct rtnl_link_info_ops veth_info_ops = {
#define IS_VETH_LINK_ASSERT(link) \
if ((link)->l_info_ops != &veth_info_ops) { \
APPBUG("Link is not a veth link. set type \"veth\" first."); \
- return NULL; \
+ return -NLE_OPNOTSUPP; \
}
/** @endcond */
@@ -293,6 +343,31 @@ int rtnl_link_veth_add(struct nl_sock *sock, const char *name,
return err;
}
+int rtnl_link_veth_set_mru(struct rtnl_link *link, uint32_t mru)
+{
+ struct veth_info *vei = link->l_info;
+
+ IS_VETH_LINK_ASSERT(link);
+
+ vei->vei_mru = mru;
+ vei->vei_mask |= VETH_HAS_MRU;
+
+ return 0;
+}
+
+uint32_t rtnl_link_veth_get_mru(struct rtnl_link *link)
+{
+ struct veth_info *vei = link->l_info;
+
+ IS_VETH_LINK_ASSERT(link);
+
+ if (vei->vei_mask & VETH_HAS_MRU)
+ return vei->vei_mru;
+ else
+ return 0;
+}
+
+
/** @} */
static void __init veth_init(void)
--
2.10.1