chiark / gitweb /
sd-rtnl: extend type system to allow address-family to decide the union members
authorTom Gundersen <teg@jklm.no>
Sun, 8 Feb 2015 11:37:05 +0000 (12:37 +0100)
committerTom Gundersen <teg@jklm.no>
Sun, 8 Feb 2015 16:43:39 +0000 (17:43 +0100)
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...)

src/libsystemd/sd-rtnl/rtnl-message.c
src/libsystemd/sd-rtnl/rtnl-types.c
src/libsystemd/sd-rtnl/rtnl-types.h
src/libsystemd/sd-rtnl/test-rtnl.c
src/systemd/sd-rtnl.h

index 14a52dfae052a2128ba09d987d04904ac9435dc7..276591f31b9e2d029985e6912a37b1445f3fcd6e 100644 (file)
@@ -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;
 
index d4abe4cc3b0811cefe9df3b47078dfccaea8270e..4ef698a7f5f19d57db623bcb74824fb40b79a2dd 100644 (file)
@@ -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;
+}
index 9c0dc30331fb5dfe403b769249b58bf9de7e706d..1ab9444987b6e9563188bc6edcd8d3bef7f28b2e 100644 (file)
@@ -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,
index ed60b3cb4549ce30ee711200f000e0736417d785..02f7a8e38aaa61f747a8b7c32df14b8e999a6e47 100644 (file)
 #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);
 
index 0eb55470e9554dfeec66d1ad86834c52f9b2bc40..be318e58a8f9bb7d1b15a15e0fe52c1708ceca3c 100644 (file)
@@ -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);