Skip to content

Commit f7ceffb

Browse files
committed
ubus: add netlink.ethtool.pse topic
Add's a new ubus interface that provides the capability to expose get / set / dump methods for the ethtool pse aspect of netlink. It exposes this under netlink.ethtool.pse {get/set/dump}. It should be trivially straight forward to add any similar topic from the netlink interface. Signed-off-by: Bevan Weiss <bevan.weiss@gmail.com>
1 parent 226981d commit f7ceffb

File tree

10 files changed

+628
-0
lines changed

10 files changed

+628
-0
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
include $(TOPDIR)/rules.mk
2+
3+
PKG_NAME:=netlink
4+
PKG_VERSION:=1.0
5+
PKG_RELEASE:=1
6+
7+
PKG_MAINTAINER:=Bevan Weiss <bevan.weiss@gmail.com>
8+
PKG_LICENSE:=GPL-2.0-only
9+
10+
# Dependencies: libubox, libubus, and kernel headers for ethtool netlink
11+
PKG_BUILD_DEPENDS:=@LINUX_HEADERS
12+
DEPENDS:=@LINUX_HEADERS
13+
14+
# Source is local folder
15+
PKG_SOURCE:=
16+
PKG_SOURCE_URL:=
17+
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
18+
19+
include $(INCLUDE_DIR)/package.mk
20+
21+
ETHTOOL_KERNEL_VERSION ?= 612
22+
23+
define Package/netlink
24+
SECTION:=net
25+
CATEGORY:=Network
26+
TITLE:=UBUS helper for netlink
27+
DEPENDS:=+libubus +libubox +libmnl
28+
endef
29+
30+
define Package/netlink/description
31+
Expose netlink topics via ubus (currently PSE-PD).
32+
Future-proof: can add additional ethtool or netlink topics.
33+
endef
34+
35+
define Build/Prepare
36+
mkdir -p $(PKG_BUILD_DIR)
37+
$(CP) ./src/* $(PKG_BUILD_DIR)/
38+
$(CP) ./src/ethtool/* $(PKG_BUILD_DIR)/ethtool/
39+
endef
40+
41+
define Build/Compile
42+
$(TARGET_CC) $(TARGET_CFLAGS) \
43+
-I$(STAGING_DIR)/usr/include \
44+
-I$(STAGING_DIR)/usr/include/libubox \
45+
-I$(KERNEL_DIR)/include/uapi \
46+
-L$(STAGING_DIR)/usr/lib \
47+
-o $(PKG_BUILD_DIR)/netlink-ubus \
48+
$(PKG_BUILD_DIR)/main.c \
49+
$(PKG_BUILD_DIR)/nl.c \
50+
$(PKG_BUILD_DIR)/ubus.c \
51+
$(PKG_BUILD_DIR)/ethtool/*.c \
52+
-lubus -lubox -lmnl
53+
endef
54+
55+
define Package/netlink/install
56+
$(INSTALL_DIR) $(1)/usr/sbin
57+
$(INSTALL_BIN) $(PKG_BUILD_DIR)/netlink-ubus $(1)/usr/sbin/
58+
endef
59+
60+
$(eval $(call BuildPackage,netlink))
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include "ethtool.h"
2+
#include <linux/netlink.h>
3+
4+
/* The netlink family for ethtool messages */
5+
struct nl_family ethtool_nl_family = {
6+
.name = "ethtool",
7+
.id = 0, /* will be assigned by ethtool_nl_init */
8+
};
9+
10+
/* initialize netlink connection for ethtool family */
11+
int ethtool_nl_init(struct mnl_socket *nl)
12+
{
13+
/* minimal kernel 6.12 setup for testing */
14+
if (nl_lookup_family(nl, "ethtool", &ethtool_nl_family.id) < 0)
15+
return -1;
16+
return 0;
17+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#ifndef _ETHTOOL_H
2+
#define _ETHTOOL_H
3+
4+
#include <libmnl/libmnl.h>
5+
#include <linux/ethtool.h>
6+
#include "../nl.h"
7+
8+
/* Initialize netlink socket for ethtool family */
9+
int ethtool_nl_init(struct mnl_socket *nl);
10+
11+
/* Generic ethtool netlink family info */
12+
extern struct nl_family ethtool_nl_family;
13+
14+
#endif /* _ETHTOOL_H */
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
#include "pse.h"
2+
#include "ethtool.h"
3+
#include "../nl.h"
4+
5+
#include <libubus.h>
6+
#include <libubox/blobmsg.h>
7+
#include <linux/ethtool_netlink.h>
8+
#include <string.h>
9+
#include <net/if.h>
10+
11+
/* Keep your pse_fields exactly as agreed */
12+
static const struct nl_field pse_fields[] = {
13+
{
14+
.name = "admin_state",
15+
.attr = ETHTOOL_A_C33_PSE_ADMIN_STATE,
16+
.type = NL_T_U32,
17+
.dir = NL_F_GET | NL_F_SET,
18+
},
19+
{
20+
.name = "power_limit_max",
21+
.attr = ETHTOOL_A_C33_PSE_PW_LIMIT_MAX,
22+
.type = NL_T_U32,
23+
.dir = NL_F_GET,
24+
},
25+
{
26+
.name = "power_limit_min",
27+
.attr = ETHTOOL_A_C33_PSE_PW_LIMIT_MIN,
28+
.type = NL_T_U32,
29+
.dir = NL_F_GET,
30+
},
31+
{
32+
.name = "actual_power",
33+
.attr = ETHTOOL_A_C33_PSE_ACTUAL_PW,
34+
.type = NL_T_U32,
35+
.dir = NL_F_GET,
36+
},
37+
{ 0 }
38+
};
39+
40+
/* GET command */
41+
static const struct nl_cmd pse_get_cmd = {
42+
.cmd = ETHTOOL_MSG_PSE_GET,
43+
.flags = NLM_F_REQUEST | NLM_F_ACK,
44+
.fields = pse_fields,
45+
};
46+
47+
/* SET command (sparse updates) */
48+
static const struct nl_cmd pse_set_cmd = {
49+
.cmd = ETHTOOL_MSG_PSE_SET,
50+
.flags = NLM_F_REQUEST | NLM_F_ACK,
51+
.fields = pse_fields,
52+
};
53+
54+
/* UBUS policy: expect "ifname" string in GET/SET requests */
55+
static const struct blobmsg_policy pse_policy[] = {
56+
{ .name = "ifname", .type = BLOBMSG_TYPE_STRING },
57+
};
58+
59+
/* GET method */
60+
int pse_get(struct ubus_context *ctx,
61+
struct ubus_object *obj,
62+
struct ubus_request_data *req,
63+
const char *method,
64+
struct blob_attr *msg)
65+
{
66+
struct blob_attr *tb[ARRAY_SIZE(pse_policy)];
67+
char ifname[IFNAMSIZ];
68+
struct blob_buf reply;
69+
70+
blobmsg_parse(pse_policy, ARRAY_SIZE(pse_policy), tb, blob_data(msg), blob_len(msg));
71+
if (!tb[0])
72+
return UBUS_STATUS_INVALID_ARGUMENT;
73+
74+
strncpy(ifname, blobmsg_get_string(tb[0]), sizeof(ifname) - 1);
75+
ifname[sizeof(ifname) - 1] = '\0';
76+
77+
blob_buf_init(&reply, 0);
78+
79+
if (nl_do_get(NULL, &ethtool_nl_family, &pse_get_cmd,
80+
ETHTOOL_A_HEADER_DEV_NAME, ifname, &reply) < 0)
81+
return UBUS_STATUS_UNKNOWN_ERROR;
82+
83+
ubus_send_reply(ctx, req, reply.head);
84+
blob_buf_free(&reply);
85+
86+
return 0;
87+
}
88+
89+
/* SET method */
90+
int pse_set(struct ubus_context *ctx,
91+
struct ubus_object *obj,
92+
struct ubus_request_data *req,
93+
const char *method,
94+
struct blob_attr *msg)
95+
{
96+
struct blob_attr *tb[ARRAY_SIZE(pse_policy)];
97+
char ifname[IFNAMSIZ];
98+
const void *vals[] = { msg };
99+
100+
blobmsg_parse(pse_policy, ARRAY_SIZE(pse_policy), tb, blob_data(msg), blob_len(msg));
101+
if (!tb[0])
102+
return UBUS_STATUS_INVALID_ARGUMENT;
103+
104+
strncpy(ifname, blobmsg_get_string(tb[0]), sizeof(ifname) - 1);
105+
ifname[sizeof(ifname) - 1] = '\0';
106+
107+
if (nl_do_set(NULL, &ethtool_nl_family, &pse_set_cmd,
108+
ETHTOOL_A_HEADER_DEV_NAME, ifname,
109+
pse_fields, vals) < 0)
110+
return UBUS_STATUS_UNKNOWN_ERROR;
111+
112+
return 0;
113+
}
114+
115+
/* DUMP method (no arguments) */
116+
int pse_dump(struct ubus_context *ctx,
117+
struct ubus_object *obj,
118+
struct ubus_request_data *req,
119+
const char *method,
120+
struct blob_attr *msg)
121+
{
122+
struct blob_buf reply;
123+
blob_buf_init(&reply, 0);
124+
125+
/* nl_do_dump: 5 arguments now, last is blob_buf* */
126+
if (nl_do_dump(NULL, &ethtool_nl_family, &pse_get_cmd,
127+
ETHTOOL_A_HEADER_DEV_NAME, &reply) < 0) {
128+
blob_buf_free(&reply);
129+
return UBUS_STATUS_UNKNOWN_ERROR;
130+
}
131+
132+
ubus_send_reply(ctx, req, reply.head);
133+
blob_buf_free(&reply);
134+
135+
return 0;
136+
}
137+
138+
139+
/* UBUS methods array */
140+
static struct ubus_method pse_methods[] = {
141+
UBUS_METHOD("get", pse_get, pse_policy),
142+
UBUS_METHOD("set", pse_set, pse_policy),
143+
UBUS_METHOD_NOARG("dump", pse_dump),
144+
};
145+
146+
/* UBUS object type and object */
147+
struct ubus_object_type pse_object_type =
148+
UBUS_OBJECT_TYPE("netlink.ethtool.pse", pse_methods);
149+
150+
struct ubus_object ethtool_pse_object = {
151+
.name = "netlink.ethtool.pse",
152+
.type = &pse_object_type,
153+
.methods = pse_methods,
154+
.n_methods = ARRAY_SIZE(pse_methods),
155+
};
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#pragma once
2+
3+
#include <libubus.h>
4+
5+
/* ubus object exported by pse.c */
6+
extern struct ubus_object ethtool_pse_object;
7+
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#include <libubus.h>
2+
#include <libubox/uloop.h>
3+
#include "ubus.h"
4+
5+
int main(void)
6+
{
7+
struct ubus_context *ctx;
8+
9+
uloop_init();
10+
11+
ctx = ubus_connect(NULL);
12+
if (!ctx)
13+
return 1;
14+
15+
ubus_register_all(ctx);
16+
17+
/* Integrate ubus with uloop */
18+
ubus_add_uloop(ctx);
19+
uloop_run();
20+
21+
ubus_free(ctx);
22+
uloop_done();
23+
return 0;
24+
}

0 commit comments

Comments
 (0)