mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-26 10:03:40 +03:00
sd-rtnl: extend type system to allow address-family to decide the union members
So far we only supported selecting them by sibling attributes. (This stuff is all a bit crazy, but there seems to be no other way...)
This commit is contained in:
parent
02f500532e
commit
4af7b60d42
@ -609,6 +609,49 @@ int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_rtnl_message_get_family(sd_rtnl_message *m, int *family) {
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(family, -EINVAL);
|
||||
|
||||
assert(m->hdr);
|
||||
|
||||
if (rtnl_message_type_is_link(m->hdr->nlmsg_type)) {
|
||||
struct ifinfomsg *ifi;
|
||||
|
||||
ifi = NLMSG_DATA(m->hdr);
|
||||
|
||||
*family = ifi->ifi_family;
|
||||
|
||||
return 0;
|
||||
} else if (rtnl_message_type_is_route(m->hdr->nlmsg_type)) {
|
||||
struct rtmsg *rtm;
|
||||
|
||||
rtm = NLMSG_DATA(m->hdr);
|
||||
|
||||
*family = rtm->rtm_family;
|
||||
|
||||
return 0;
|
||||
} else if (rtnl_message_type_is_neigh(m->hdr->nlmsg_type)) {
|
||||
struct ndmsg *ndm;
|
||||
|
||||
ndm = NLMSG_DATA(m->hdr);
|
||||
|
||||
*family = ndm->ndm_family;
|
||||
|
||||
return 0;
|
||||
} else if (rtnl_message_type_is_addr(m->hdr->nlmsg_type)) {
|
||||
struct ifaddrmsg *ifa;
|
||||
|
||||
ifa = NLMSG_DATA(m->hdr);
|
||||
|
||||
*family = ifa->ifa_family;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
int sd_rtnl_message_is_broadcast(sd_rtnl_message *m) {
|
||||
assert_return(m, -EINVAL);
|
||||
|
||||
@ -898,16 +941,37 @@ int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
|
||||
assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -ERANGE);
|
||||
|
||||
r = message_attribute_has_type(m, type, NLA_NESTED);
|
||||
if (r < 0)
|
||||
return r;
|
||||
else
|
||||
if (r < 0) {
|
||||
const NLTypeSystemUnion *type_system_union;
|
||||
int family;
|
||||
|
||||
r = message_attribute_has_type(m, type, NLA_UNION);
|
||||
if (r < 0)
|
||||
return r;
|
||||
size = (size_t) r;
|
||||
|
||||
r = sd_rtnl_message_get_family(m, &family);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = type_system_union_protocol_get_type_system(type_system_union,
|
||||
&m->container_type_system[m->n_containers + 1],
|
||||
family);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else {
|
||||
size = (size_t)r;
|
||||
|
||||
r = type_system_get_type_system(m->container_type_system[m->n_containers],
|
||||
&m->container_type_system[m->n_containers + 1],
|
||||
type);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = type_system_get_type_system(m->container_type_system[m->n_containers],
|
||||
&m->container_type_system[m->n_containers + 1],
|
||||
type);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = add_rtattr(m, type | NLA_F_NESTED, NULL, size);
|
||||
if (r < 0)
|
||||
@ -1181,7 +1245,6 @@ int sd_rtnl_message_enter_container(sd_rtnl_message *m, unsigned short type) {
|
||||
return r;
|
||||
} else if (nl_type->type == NLA_UNION) {
|
||||
const NLTypeSystemUnion *type_system_union;
|
||||
const char *key;
|
||||
|
||||
r = type_system_get_type_system_union(m->container_type_system[m->n_containers],
|
||||
&type_system_union,
|
||||
@ -1189,15 +1252,42 @@ int sd_rtnl_message_enter_container(sd_rtnl_message *m, unsigned short type) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_rtnl_message_read_string(m, type_system_union->match, &key);
|
||||
if (r < 0)
|
||||
return r;
|
||||
switch (type_system_union->match_type) {
|
||||
case NL_MATCH_SIBLING:
|
||||
{
|
||||
const char *key;
|
||||
|
||||
r = type_system_union_get_type_system(type_system_union,
|
||||
&type_system,
|
||||
key);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = sd_rtnl_message_read_string(m, type_system_union->match, &key);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = type_system_union_get_type_system(type_system_union,
|
||||
&type_system,
|
||||
key);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
}
|
||||
case NL_MATCH_PROTOCOL:
|
||||
{
|
||||
int family;
|
||||
|
||||
r = sd_rtnl_message_get_family(m, &family);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = type_system_union_protocol_get_type_system(type_system_union,
|
||||
&type_system,
|
||||
family);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert_not_reached("sd-rtnl: invalid type system union type");
|
||||
}
|
||||
} else
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -224,6 +224,7 @@ static const NLTypeSystemUnion rtnl_link_info_data_type_system_union = {
|
||||
.num = _NL_UNION_LINK_INFO_DATA_MAX,
|
||||
.lookup = nl_union_link_info_data_from_string,
|
||||
.type_systems = rtnl_link_info_data_type_systems,
|
||||
.match_type = NL_MATCH_SIBLING,
|
||||
.match = IFLA_INFO_KIND,
|
||||
};
|
||||
|
||||
@ -242,7 +243,7 @@ static const NLTypeSystem rtnl_link_info_type_system = {
|
||||
.types = rtnl_link_info_types,
|
||||
};
|
||||
|
||||
static const struct NLType rtnl_bridge_port_types[IFLA_BRPORT_MAX + 1] = {
|
||||
static const struct NLType rtnl_prot_info_bridge_port_types[IFLA_BRPORT_MAX + 1] = {
|
||||
[IFLA_BRPORT_STATE] = { .type = NLA_U8 },
|
||||
[IFLA_BRPORT_COST] = { .type = NLA_U32 },
|
||||
[IFLA_BRPORT_PRIORITY] = { .type = NLA_U16 },
|
||||
@ -253,9 +254,15 @@ static const struct NLType rtnl_bridge_port_types[IFLA_BRPORT_MAX + 1] = {
|
||||
[IFLA_BRPORT_UNICAST_FLOOD] = { .type = NLA_U8 },
|
||||
};
|
||||
|
||||
static const NLTypeSystem rtnl_bridge_port_type_system = {
|
||||
.max = ELEMENTSOF(rtnl_bridge_port_types) - 1,
|
||||
.types = rtnl_bridge_port_types,
|
||||
static const NLTypeSystem rtnl_prot_info_type_systems[AF_MAX] = {
|
||||
[AF_BRIDGE] = { .max = ELEMENTSOF(rtnl_prot_info_bridge_port_types) - 1,
|
||||
.types = rtnl_prot_info_bridge_port_types },
|
||||
};
|
||||
|
||||
static const NLTypeSystemUnion rtnl_prot_info_type_system_union = {
|
||||
.num = AF_MAX,
|
||||
.type_systems = rtnl_prot_info_type_systems,
|
||||
.match_type = NL_MATCH_PROTOCOL,
|
||||
};
|
||||
|
||||
static const NLType rtnl_link_types[IFLA_MAX + 1 ] = {
|
||||
@ -273,9 +280,8 @@ static const NLType rtnl_link_types[IFLA_MAX + 1 ] = {
|
||||
[IFLA_MASTER] = { .type = NLA_U32 },
|
||||
/*
|
||||
[IFLA_WIRELESS],
|
||||
[IFLA_PROTINFO],
|
||||
*/
|
||||
[IFLA_PROTINFO] = { .type = NLA_NESTED, .type_system = &rtnl_bridge_port_type_system },
|
||||
[IFLA_PROTINFO] = { .type = NLA_UNION, .type_system_union = &rtnl_prot_info_type_system_union },
|
||||
[IFLA_TXQLEN] = { .type = NLA_U32 },
|
||||
/*
|
||||
[IFLA_MAP] = { .len = sizeof(struct rtnl_link_ifmap) },
|
||||
@ -463,6 +469,7 @@ int type_system_union_get_type_system(const NLTypeSystemUnion *type_system_union
|
||||
int type;
|
||||
|
||||
assert(type_system_union);
|
||||
assert_return(type_system_union->match_type == NL_MATCH_SIBLING, -EINVAL);
|
||||
assert(type_system_union->lookup);
|
||||
assert(type_system_union->type_systems);
|
||||
assert(ret);
|
||||
@ -478,3 +485,25 @@ int type_system_union_get_type_system(const NLTypeSystemUnion *type_system_union
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int type_system_union_protocol_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, uint16_t protocol) {
|
||||
const NLTypeSystem *type_system;
|
||||
|
||||
assert(type_system_union);
|
||||
assert(type_system_union->type_systems);
|
||||
assert(ret);
|
||||
assert_return(type_system_union->match_type == NL_MATCH_PROTOCOL, -EINVAL);
|
||||
assert_return(protocol < type_system_union->num, -EINVAL);
|
||||
|
||||
if (protocol >= type_system_union->num)
|
||||
return -ENOTSUP;
|
||||
|
||||
type_system = &type_system_union->type_systems[protocol];
|
||||
|
||||
if (!type_system)
|
||||
return -ENOTSUP;
|
||||
|
||||
*ret = type_system;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -36,12 +36,18 @@ enum {
|
||||
NLA_UNION,
|
||||
};
|
||||
|
||||
typedef enum NLMatchType {
|
||||
NL_MATCH_SIBLING,
|
||||
NL_MATCH_PROTOCOL,
|
||||
} NLMatchType;
|
||||
|
||||
typedef struct NLTypeSystemUnion NLTypeSystemUnion;
|
||||
typedef struct NLTypeSystem NLTypeSystem;
|
||||
typedef struct NLType NLType;
|
||||
|
||||
struct NLTypeSystemUnion {
|
||||
int num;
|
||||
NLMatchType match_type;
|
||||
uint16_t match;
|
||||
int (*lookup)(const char *);
|
||||
const NLTypeSystem *type_systems;
|
||||
@ -63,6 +69,7 @@ int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, ui
|
||||
int type_system_get_type_system(const NLTypeSystem *type_system, const NLTypeSystem **ret, uint16_t type);
|
||||
int type_system_get_type_system_union(const NLTypeSystem *type_system, const NLTypeSystemUnion **ret, uint16_t type);
|
||||
int type_system_union_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, const char *key);
|
||||
int type_system_union_protocol_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, uint16_t protocol);
|
||||
|
||||
typedef enum NLUnionLinkInfoData {
|
||||
NL_UNION_LINK_INFO_DATA_BOND,
|
||||
|
@ -31,8 +31,26 @@
|
||||
#include "missing.h"
|
||||
#include "rtnl-internal.h"
|
||||
|
||||
static void test_message_link_bridge(sd_rtnl *rtnl) {
|
||||
_cleanup_rtnl_message_unref_ sd_rtnl_message *message = NULL;
|
||||
uint32_t cost;
|
||||
|
||||
assert_se(sd_rtnl_message_new_link(rtnl, &message, RTM_NEWLINK, 1) >= 0);
|
||||
assert_se(sd_rtnl_message_link_set_family(message, PF_BRIDGE) >= 0);
|
||||
assert_se(sd_rtnl_message_open_container(message, IFLA_PROTINFO) >= 0);
|
||||
assert_se(sd_rtnl_message_append_u32(message, IFLA_BRPORT_COST, 10) >= 0);
|
||||
assert_se(sd_rtnl_message_close_container(message) >= 0);
|
||||
|
||||
assert_se(sd_rtnl_message_rewind(message) >= 0);
|
||||
|
||||
assert_se(sd_rtnl_message_enter_container(message, IFLA_PROTINFO) >= 0);
|
||||
assert_se(sd_rtnl_message_read_u32(message, IFLA_BRPORT_COST, &cost) >= 0);
|
||||
assert_se(cost == 10);
|
||||
assert_se(sd_rtnl_message_exit_container(message) >= 0);
|
||||
}
|
||||
|
||||
static void test_link_configure(sd_rtnl *rtnl, int ifindex) {
|
||||
_cleanup_rtnl_message_unref_ sd_rtnl_message *message;
|
||||
_cleanup_rtnl_message_unref_ sd_rtnl_message *message = NULL;
|
||||
const char *mac = "98:fe:94:3f:c6:18", *name = "test";
|
||||
char buffer[ETHER_ADDR_TO_STRING_MAX];
|
||||
unsigned int mtu = 1450, mtu_out;
|
||||
@ -394,6 +412,8 @@ int main(void) {
|
||||
|
||||
test_get_addresses(rtnl);
|
||||
|
||||
test_message_link_bridge(rtnl);
|
||||
|
||||
assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, if_loopback) >= 0);
|
||||
assert_se(m);
|
||||
|
||||
|
@ -88,6 +88,8 @@ int sd_rtnl_message_get_errno(sd_rtnl_message *m);
|
||||
int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type);
|
||||
int sd_rtnl_message_is_broadcast(sd_rtnl_message *m);
|
||||
|
||||
int sd_rtnl_message_get_family(sd_rtnl_message *m, int *family);
|
||||
|
||||
int sd_rtnl_message_addr_set_prefixlen(sd_rtnl_message *m, unsigned char prefixlen);
|
||||
int sd_rtnl_message_addr_set_scope(sd_rtnl_message *m, unsigned char scope);
|
||||
int sd_rtnl_message_addr_set_flags(sd_rtnl_message *m, unsigned char flags);
|
||||
|
Loading…
x
Reference in New Issue
Block a user