platform: add VRF support

Add support for creating and parsing VRF links.
This commit is contained in:
Beniamino Galvani 2019-12-05 10:35:25 +01:00
parent 89d387f782
commit 7c73c6a038
9 changed files with 174 additions and 0 deletions

View file

@ -160,6 +160,7 @@ typedef enum {
NM_LINK_TYPE_TUN,
NM_LINK_TYPE_VETH,
NM_LINK_TYPE_VLAN,
NM_LINK_TYPE_VRF,
NM_LINK_TYPE_VXLAN,
NM_LINK_TYPE_WIREGUARD,
@ -197,6 +198,7 @@ typedef enum {
NMP_OBJECT_TYPE_LNK_SIT,
NMP_OBJECT_TYPE_LNK_TUN,
NMP_OBJECT_TYPE_LNK_VLAN,
NMP_OBJECT_TYPE_LNK_VRF,
NMP_OBJECT_TYPE_LNK_VXLAN,
NMP_OBJECT_TYPE_LNK_WIREGUARD,

View file

@ -656,6 +656,7 @@ static const LinkDesc linktypes[] = {
{ NM_LINK_TYPE_TUN, "tun", "tun", NULL },
{ NM_LINK_TYPE_VETH, "veth", "veth", NULL },
{ NM_LINK_TYPE_VLAN, "vlan", "vlan", "vlan" },
{ NM_LINK_TYPE_VRF, "vrf", "vrf", "vrf" },
{ NM_LINK_TYPE_VXLAN, "vxlan", "vxlan", "vxlan" },
{ NM_LINK_TYPE_WIREGUARD, "wireguard", "wireguard", "wireguard" },
@ -1754,6 +1755,8 @@ _parse_lnk_vlan (const char *kind, struct nlattr *info_data)
#undef IFLA_VXLAN_MAX
#define IFLA_VXLAN_MAX IFLA_VXLAN_LOCAL6
#define IFLA_VRF_TABLE 1
/* older kernel header might not contain 'struct ifla_vxlan_port_range'.
* Redefine it. */
struct nm_ifla_vxlan_port_range {
@ -1848,6 +1851,33 @@ _parse_lnk_vxlan (const char *kind, struct nlattr *info_data)
return obj;
}
static NMPObject *
_parse_lnk_vrf (const char *kind, struct nlattr *info_data)
{
static const struct nla_policy policy[] = {
[IFLA_VRF_TABLE] = { .type = NLA_U32 },
};
NMPlatformLnkVrf *props;
struct nlattr *tb[G_N_ELEMENTS (policy)];
NMPObject *obj;
if ( !info_data
|| !nm_streq0 (kind, "vrf"))
return NULL;
if (nla_parse_nested_arr (tb, info_data, policy) < 0)
return NULL;
obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_VRF, NULL);
props = &obj->lnk_vrf;
if (tb[IFLA_VRF_TABLE])
props->table = nla_get_u32 (tb[IFLA_VRF_TABLE]);
return obj;
}
/*****************************************************************************/
static gboolean
@ -2798,6 +2828,9 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
case NM_LINK_TYPE_VLAN:
lnk_data = _parse_lnk_vlan (nl_info_kind, nl_info_data);
break;
case NM_LINK_TYPE_VRF:
lnk_data = _parse_lnk_vrf (nl_info_kind, nl_info_data);
break;
case NM_LINK_TYPE_VXLAN:
lnk_data = _parse_lnk_vxlan (nl_info_kind, nl_info_data);
break;
@ -3728,6 +3761,17 @@ _nl_msg_new_link_set_linkinfo (struct nl_msg *msg,
}
break;
}
case NM_LINK_TYPE_VRF: {
const NMPlatformLnkVrf *props = extra_data;
nm_assert (extra_data);
if (!(data = nla_nest_start (msg, IFLA_INFO_DATA)))
goto nla_put_failure;
NLA_PUT_U32 (msg, IFLA_VRF_TABLE, props->table);
break;
}
case NM_LINK_TYPE_VXLAN: {
const NMPlatformLnkVxlan *props = extra_data;

View file

@ -1218,6 +1218,10 @@ nm_platform_link_add (NMPlatform *self,
nm_utils_strbuf_append_str (&buf_p, &buf_len, ", ");
nm_platform_lnk_vlan_to_string ((const NMPlatformLnkVlan *) extra_data, buf_p, buf_len);
break;
case NM_LINK_TYPE_VRF:
nm_utils_strbuf_append_str (&buf_p, &buf_len, ", ");
nm_platform_lnk_vrf_to_string ((const NMPlatformLnkVrf *) extra_data, buf_p, buf_len);
break;
case NM_LINK_TYPE_VXLAN:
nm_utils_strbuf_append_str (&buf_p, &buf_len, ", ");
nm_platform_lnk_vxlan_to_string ((const NMPlatformLnkVxlan *) extra_data, buf_p, buf_len);
@ -2252,6 +2256,12 @@ nm_platform_link_get_lnk_vlan (NMPlatform *self, int ifindex, const NMPlatformLi
return _link_get_lnk (self, ifindex, NM_LINK_TYPE_VLAN, out_link);
}
const NMPlatformLnkVrf *
nm_platform_link_get_lnk_vrf (NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
{
return _link_get_lnk (self, ifindex, NM_LINK_TYPE_VRF, out_link);
}
const NMPlatformLnkVxlan *
nm_platform_link_get_lnk_vxlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
{
@ -5484,6 +5494,20 @@ nm_platform_lnk_vlan_to_string (const NMPlatformLnkVlan *lnk, char *buf, gsize l
return buf;
}
const char *
nm_platform_lnk_vrf_to_string (const NMPlatformLnkVrf *lnk, char *buf, gsize len)
{
char *b;
if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len))
return buf;
b = buf;
nm_utils_strbuf_append (&b, &len, "table %u", lnk->table);
return buf;
}
const char *
nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize len)
{
@ -6850,6 +6874,21 @@ nm_platform_lnk_vlan_cmp (const NMPlatformLnkVlan *a, const NMPlatformLnkVlan *b
return 0;
}
void
nm_platform_lnk_vrf_hash_update (const NMPlatformLnkVrf *obj, NMHashState *h)
{
nm_hash_update_vals (h,
obj->table);
}
int
nm_platform_lnk_vrf_cmp (const NMPlatformLnkVrf *a, const NMPlatformLnkVrf *b)
{
NM_CMP_SELF (a, b);
NM_CMP_FIELD (a, b, table);
return 0;
}
void
nm_platform_lnk_vxlan_hash_update (const NMPlatformLnkVxlan *obj, NMHashState *h)
{

View file

@ -827,6 +827,10 @@ typedef struct {
NMVlanFlags flags;
} NMPlatformLnkVlan;
typedef struct {
guint32 table;
} NMPlatformLnkVrf;
typedef struct {
struct in6_addr group6;
struct in6_addr local6;
@ -1430,6 +1434,15 @@ nm_platform_link_vlan_add (NMPlatform *self,
out_link);
}
static inline int
nm_platform_link_vrf_add (NMPlatform *self,
const char *name,
const NMPlatformLnkVrf *props,
const NMPlatformLink **out_link)
{
return nm_platform_link_add (self, NM_LINK_TYPE_VRF, name, 0, NULL, 0, props, out_link);
}
static inline int
nm_platform_link_vxlan_add (NMPlatform *self,
const char *name,
@ -1621,6 +1634,7 @@ const NMPlatformLnkMacvlan *nm_platform_link_get_lnk_macvtap (NMPlatform *self,
const NMPlatformLnkSit *nm_platform_link_get_lnk_sit (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
const NMPlatformLnkTun *nm_platform_link_get_lnk_tun (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
const NMPlatformLnkVlan *nm_platform_link_get_lnk_vlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
const NMPlatformLnkVrf *nm_platform_link_get_lnk_vrf (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
const NMPlatformLnkVxlan *nm_platform_link_get_lnk_vxlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
const NMPlatformLnkWireGuard *nm_platform_link_get_lnk_wireguard (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
@ -1792,6 +1806,7 @@ const char *nm_platform_lnk_macvlan_to_string (const NMPlatformLnkMacvlan *lnk,
const char *nm_platform_lnk_sit_to_string (const NMPlatformLnkSit *lnk, char *buf, gsize len);
const char *nm_platform_lnk_tun_to_string (const NMPlatformLnkTun *lnk, char *buf, gsize len);
const char *nm_platform_lnk_vlan_to_string (const NMPlatformLnkVlan *lnk, char *buf, gsize len);
const char *nm_platform_lnk_vrf_to_string (const NMPlatformLnkVrf *lnk, char *buf, gsize len);
const char *nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize len);
const char *nm_platform_lnk_wireguard_to_string (const NMPlatformLnkWireGuard *lnk, char *buf, gsize len);
const char *nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address, char *buf, gsize len);
@ -1824,6 +1839,7 @@ int nm_platform_lnk_macvlan_cmp (const NMPlatformLnkMacvlan *a, const NMPlatform
int nm_platform_lnk_sit_cmp (const NMPlatformLnkSit *a, const NMPlatformLnkSit *b);
int nm_platform_lnk_tun_cmp (const NMPlatformLnkTun *a, const NMPlatformLnkTun *b);
int nm_platform_lnk_vlan_cmp (const NMPlatformLnkVlan *a, const NMPlatformLnkVlan *b);
int nm_platform_lnk_vrf_cmp (const NMPlatformLnkVrf *a, const NMPlatformLnkVrf *b);
int nm_platform_lnk_vxlan_cmp (const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan *b);
int nm_platform_lnk_wireguard_cmp (const NMPlatformLnkWireGuard *a, const NMPlatformLnkWireGuard *b);
int nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b);
@ -1870,6 +1886,7 @@ void nm_platform_lnk_macvlan_hash_update (const NMPlatformLnkMacvlan *obj, NMHas
void nm_platform_lnk_sit_hash_update (const NMPlatformLnkSit *obj, NMHashState *h);
void nm_platform_lnk_tun_hash_update (const NMPlatformLnkTun *obj, NMHashState *h);
void nm_platform_lnk_vlan_hash_update (const NMPlatformLnkVlan *obj, NMHashState *h);
void nm_platform_lnk_vrf_hash_update (const NMPlatformLnkVrf *obj, NMHashState *h);
void nm_platform_lnk_vxlan_hash_update (const NMPlatformLnkVxlan *obj, NMHashState *h);
void nm_platform_lnk_wireguard_hash_update (const NMPlatformLnkWireGuard *obj, NMHashState *h);

View file

@ -3336,6 +3336,18 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_vlan_hash_update,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_vlan_cmp,
},
[NMP_OBJECT_TYPE_LNK_VRF - 1] = {
.parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
.obj_type = NMP_OBJECT_TYPE_LNK_VRF,
.sizeof_data = sizeof (NMPObjectLnkVrf),
.sizeof_public = sizeof (NMPlatformLnkVrf),
.obj_type_name = "vrf",
.lnk_link_type = NM_LINK_TYPE_VRF,
.cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_vrf_to_string,
.cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_vrf_hash_update,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_vrf_cmp,
},
[NMP_OBJECT_TYPE_LNK_VXLAN - 1] = {
.parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
.obj_type = NMP_OBJECT_TYPE_LNK_VXLAN,

View file

@ -286,6 +286,10 @@ typedef struct {
const NMVlanQosMapping *egress_qos_map;
} NMPObjectLnkVlan;
typedef struct {
NMPlatformLnkVrf _public;
} NMPObjectLnkVrf;
typedef struct {
NMPlatformLnkVxlan _public;
} NMPObjectLnkVxlan;
@ -366,6 +370,9 @@ struct _NMPObject {
NMPlatformLnkVlan lnk_vlan;
NMPObjectLnkVlan _lnk_vlan;
NMPlatformLnkVrf lnk_vrf;
NMPObjectLnkVrf _lnk_vrf;
NMPlatformLnkVxlan lnk_vxlan;
NMPObjectLnkVxlan _lnk_vxlan;

View file

@ -1585,6 +1585,39 @@ nmtstp_link_tun_add (NMPlatform *platform,
return pllink;
}
const NMPlatformLink *
nmtstp_link_vrf_add (NMPlatform *platform,
gboolean external_command,
const char *name,
const NMPlatformLnkVrf *lnk)
{
const NMPlatformLink *pllink = NULL;
int err;
int r;
g_assert (nm_utils_is_valid_iface_name (name, NULL));
external_command = nmtstp_run_command_check_external (external_command);
_init_platform (&platform, external_command);
if (external_command) {
err = nmtstp_run_command ("ip link add %s type vrf table %u",
name,
lnk->table);
if (err == 0)
pllink = nmtstp_assert_wait_for_link (platform, name, NM_LINK_TYPE_VRF, 100);
} else {
r = nm_platform_link_vrf_add (platform, name, lnk, &pllink);
g_assert (NMTST_NM_ERR_SUCCESS (r));
g_assert (pllink);
}
g_assert_cmpint (pllink->type, ==, NM_LINK_TYPE_VRF);
g_assert_cmpstr (pllink->name, ==, name);
return pllink;
}
const NMPlatformLink *
nmtstp_link_vxlan_add (NMPlatform *platform,
gboolean external_command,

View file

@ -360,6 +360,10 @@ const NMPlatformLink *nmtstp_link_tun_add (NMPlatform *platform,
const char *name,
const NMPlatformLnkTun *lnk,
int *out_fd);
const NMPlatformLink *nmtstp_link_vrf_add (NMPlatform *platform,
gboolean external_command,
const char *name,
const NMPlatformLnkVrf *lnk);
const NMPlatformLink *nmtstp_link_vxlan_add (NMPlatform *platform,
gboolean external_command,
const char *name,

View file

@ -1182,6 +1182,14 @@ test_software_detect (gconstpointer user_data)
case NM_LINK_TYPE_VLAN:
nmtstp_run_command_check ("ip link add name %s link %s type vlan id 1242", DEVICE_NAME, PARENT_NAME);
break;
case NM_LINK_TYPE_VRF: {
NMPlatformLnkVrf lnk_vrf = { };
lnk_vrf.table = 9876;
nmtstp_link_vrf_add (NULL, ext, DEVICE_NAME, &lnk_vrf);
break;
}
case NM_LINK_TYPE_VXLAN: {
NMPlatformLnkVxlan lnk_vxlan = { };
@ -1444,6 +1452,13 @@ test_software_detect (gconstpointer user_data)
g_assert_cmpint (plnk->id, ==, 1242);
break;
}
case NM_LINK_TYPE_VRF: {
const NMPlatformLnkVrf *plnk = &lnk->lnk_vrf;
g_assert (plnk == nm_platform_link_get_lnk_vrf (NM_PLATFORM_GET, ifindex, NULL));
g_assert_cmpint (plnk->table, ==, 9876);
break;
}
case NM_LINK_TYPE_VXLAN: {
const NMPlatformLnkVxlan *plnk = &lnk->lnk_vxlan;
@ -3313,6 +3328,7 @@ _nmtstp_setup_tests (void)
test_software_detect_add ("/link/software/detect/sit", NM_LINK_TYPE_SIT, 0);
test_software_detect_add ("/link/software/detect/tun", NM_LINK_TYPE_TUN, 0);
test_software_detect_add ("/link/software/detect/vlan", NM_LINK_TYPE_VLAN, 0);
test_software_detect_add ("/link/software/detect/vrf", NM_LINK_TYPE_VRF, 0);
test_software_detect_add ("/link/software/detect/vxlan/0", NM_LINK_TYPE_VXLAN, 0);
test_software_detect_add ("/link/software/detect/vxlan/1", NM_LINK_TYPE_VXLAN, 1);
test_software_detect_add ("/link/software/detect/wireguard/0", NM_LINK_TYPE_WIREGUARD, 0);