]>
git.proxmox.com Git - mirror_iproute2.git/blob - devlink/mnlg.c
2 * mnlg.c Generic Netlink helpers for libmnl
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
9 * Authors: Jiri Pirko <jiri@mellanox.com>
17 #include <libmnl/libmnl.h>
18 #include <linux/genetlink.h>
20 #include "libnetlink.h"
21 #include "mnl_utils.h"
26 struct mnl_socket
*nl
;
33 static struct nlmsghdr
*__mnlg_msg_prepare(struct mnlg_socket
*nlg
, uint8_t cmd
,
34 uint16_t flags
, uint32_t id
,
37 struct genlmsghdr genl
= {
43 nlh
= mnlu_msg_prepare(nlg
->buf
, id
, flags
, &genl
, sizeof(genl
));
44 nlg
->seq
= nlh
->nlmsg_seq
;
48 struct nlmsghdr
*mnlg_msg_prepare(struct mnlg_socket
*nlg
, uint8_t cmd
,
51 return __mnlg_msg_prepare(nlg
, cmd
, flags
, nlg
->id
, nlg
->version
);
54 int mnlg_socket_send(struct mnlg_socket
*nlg
, const struct nlmsghdr
*nlh
)
56 return mnl_socket_sendto(nlg
->nl
, nlh
, nlh
->nlmsg_len
);
59 int mnlg_socket_recv_run(struct mnlg_socket
*nlg
, mnl_cb_t data_cb
, void *data
)
61 return mnlu_socket_recv_run(nlg
->nl
, nlg
->seq
, nlg
->buf
, MNL_SOCKET_BUFFER_SIZE
,
71 static int parse_mc_grps_cb(const struct nlattr
*attr
, void *data
)
73 const struct nlattr
**tb
= data
;
74 int type
= mnl_attr_get_type(attr
);
76 if (mnl_attr_type_valid(attr
, CTRL_ATTR_MCAST_GRP_MAX
) < 0)
80 case CTRL_ATTR_MCAST_GRP_ID
:
81 if (mnl_attr_validate(attr
, MNL_TYPE_U32
) < 0)
84 case CTRL_ATTR_MCAST_GRP_NAME
:
85 if (mnl_attr_validate(attr
, MNL_TYPE_STRING
) < 0)
93 static void parse_genl_mc_grps(struct nlattr
*nested
,
94 struct group_info
*group_info
)
99 mnl_attr_for_each_nested(pos
, nested
) {
100 struct nlattr
*tb
[CTRL_ATTR_MCAST_GRP_MAX
+ 1] = {};
102 mnl_attr_parse_nested(pos
, parse_mc_grps_cb
, tb
);
103 if (!tb
[CTRL_ATTR_MCAST_GRP_NAME
] ||
104 !tb
[CTRL_ATTR_MCAST_GRP_ID
])
107 name
= mnl_attr_get_str(tb
[CTRL_ATTR_MCAST_GRP_NAME
]);
108 if (strcmp(name
, group_info
->name
) != 0)
111 group_info
->id
= mnl_attr_get_u32(tb
[CTRL_ATTR_MCAST_GRP_ID
]);
112 group_info
->found
= true;
116 static int get_group_id_attr_cb(const struct nlattr
*attr
, void *data
)
118 const struct nlattr
**tb
= data
;
119 int type
= mnl_attr_get_type(attr
);
121 if (mnl_attr_type_valid(attr
, CTRL_ATTR_MAX
) < 0)
124 if (type
== CTRL_ATTR_MCAST_GROUPS
&&
125 mnl_attr_validate(attr
, MNL_TYPE_NESTED
) < 0)
131 static int get_group_id_cb(const struct nlmsghdr
*nlh
, void *data
)
133 struct group_info
*group_info
= data
;
134 struct nlattr
*tb
[CTRL_ATTR_MAX
+ 1] = {};
135 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
137 mnl_attr_parse(nlh
, sizeof(*genl
), get_group_id_attr_cb
, tb
);
138 if (!tb
[CTRL_ATTR_MCAST_GROUPS
])
140 parse_genl_mc_grps(tb
[CTRL_ATTR_MCAST_GROUPS
], group_info
);
144 int mnlg_socket_group_add(struct mnlg_socket
*nlg
, const char *group_name
)
146 struct nlmsghdr
*nlh
;
147 struct group_info group_info
;
150 nlh
= __mnlg_msg_prepare(nlg
, CTRL_CMD_GETFAMILY
,
151 NLM_F_REQUEST
| NLM_F_ACK
, GENL_ID_CTRL
, 1);
152 mnl_attr_put_u16(nlh
, CTRL_ATTR_FAMILY_ID
, nlg
->id
);
154 err
= mnlg_socket_send(nlg
, nlh
);
158 group_info
.found
= false;
159 group_info
.name
= group_name
;
160 err
= mnlg_socket_recv_run(nlg
, get_group_id_cb
, &group_info
);
164 if (!group_info
.found
) {
169 err
= mnl_socket_setsockopt(nlg
->nl
, NETLINK_ADD_MEMBERSHIP
,
170 &group_info
.id
, sizeof(group_info
.id
));
177 static int get_family_id_attr_cb(const struct nlattr
*attr
, void *data
)
179 const struct nlattr
**tb
= data
;
180 int type
= mnl_attr_get_type(attr
);
182 if (mnl_attr_type_valid(attr
, CTRL_ATTR_MAX
) < 0)
185 if (type
== CTRL_ATTR_FAMILY_ID
&&
186 mnl_attr_validate(attr
, MNL_TYPE_U16
) < 0)
192 static int get_family_id_cb(const struct nlmsghdr
*nlh
, void *data
)
194 uint32_t *p_id
= data
;
195 struct nlattr
*tb
[CTRL_ATTR_MAX
+ 1] = {};
196 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
198 mnl_attr_parse(nlh
, sizeof(*genl
), get_family_id_attr_cb
, tb
);
199 if (!tb
[CTRL_ATTR_FAMILY_ID
])
201 *p_id
= mnl_attr_get_u16(tb
[CTRL_ATTR_FAMILY_ID
]);
205 struct mnlg_socket
*mnlg_socket_open(const char *family_name
, uint8_t version
)
207 struct mnlg_socket
*nlg
;
208 struct nlmsghdr
*nlh
;
211 nlg
= malloc(sizeof(*nlg
));
215 nlg
->buf
= malloc(MNL_SOCKET_BUFFER_SIZE
);
219 nlg
->nl
= mnlu_socket_open(NETLINK_GENERIC
);
221 goto err_socket_open
;
223 nlh
= __mnlg_msg_prepare(nlg
, CTRL_CMD_GETFAMILY
,
224 NLM_F_REQUEST
| NLM_F_ACK
, GENL_ID_CTRL
, 1);
225 mnl_attr_put_strz(nlh
, CTRL_ATTR_FAMILY_NAME
, family_name
);
227 err
= mnlg_socket_send(nlg
, nlh
);
229 goto err_mnlg_socket_send
;
231 err
= mnlg_socket_recv_run(nlg
, get_family_id_cb
, &nlg
->id
);
233 goto err_mnlg_socket_recv_run
;
235 nlg
->version
= version
;
238 err_mnlg_socket_recv_run
:
239 err_mnlg_socket_send
:
240 mnl_socket_close(nlg
->nl
);
248 void mnlg_socket_close(struct mnlg_socket
*nlg
)
250 mnl_socket_close(nlg
->nl
);
255 int mnlg_socket_get_fd(struct mnlg_socket
*nlg
)
257 return mnl_socket_get_fd(nlg
->nl
);