2 * rpcd - UBUS RPC server
4 * Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
27 #include <sys/types.h>
30 #include <libubox/avl.h>
31 #include <libubox/avl-cmp.h>
33 #include <rpcd/plugin.h>
35 #define RPC_BWMON_HISTORY 120
45 const char *types
[] = {
52 struct rpc_bwmon_device
{
54 char ifname
[IF_NAMESIZE
];
57 uint32_t values
[4][RPC_BWMON_HISTORY
];
60 static struct blob_buf buf
;
61 static struct avl_tree devices
;
69 static const struct blobmsg_policy rpc_stats_policy
[__RPC_STATS_MAX
] = {
70 [RPC_STATS_DEVICE
] = { .name
= "device", .type
= BLOBMSG_TYPE_STRING
},
75 rpc_bwmon_devices(struct ubus_context
*ctx
, struct ubus_object
*obj
,
76 struct ubus_request_data
*req
, const char *method
,
77 struct blob_attr
*msg
)
80 struct rpc_bwmon_device
*dev
;
82 blob_buf_init(&buf
, 0);
83 c
= blobmsg_open_array(&buf
, "devices");
85 avl_for_each_element(&devices
, dev
, avl
)
86 blobmsg_add_string(&buf
, NULL
, dev
->ifname
);
88 blobmsg_close_array(&buf
, c
);
90 ubus_send_reply(ctx
, req
, buf
.head
);
96 rpc_bwmon_dump_stats(struct rpc_bwmon_device
*dev
)
101 for (i
= 0; i
< 4; i
++)
103 c
= blobmsg_open_array(&buf
, types
[i
]);
105 for (j
= 0; j
< RPC_BWMON_HISTORY
; j
++)
106 blobmsg_add_u32(&buf
, NULL
,
107 dev
->values
[i
][(dev
->pos
+ j
) % RPC_BWMON_HISTORY
]);
109 blobmsg_close_array(&buf
, c
);
114 rpc_bwmon_stats(struct ubus_context
*ctx
, struct ubus_object
*obj
,
115 struct ubus_request_data
*req
, const char *method
,
116 struct blob_attr
*msg
)
119 struct rpc_bwmon_device
*dev
;
120 struct blob_attr
*tb
[__RPC_STATS_MAX
];
122 blobmsg_parse(rpc_stats_policy
, __RPC_STATS_MAX
, tb
,
123 blob_data(msg
), blob_len(msg
));
125 blob_buf_init(&buf
, 0);
127 if (tb
[RPC_STATS_DEVICE
])
129 dev
= avl_find_element(&devices
,
130 blobmsg_get_string(tb
[RPC_STATS_DEVICE
]),
134 return UBUS_STATUS_NOT_FOUND
;
136 c
= blobmsg_open_table(&buf
, "statistics");
137 rpc_bwmon_dump_stats(dev
);
138 blobmsg_close_table(&buf
, c
);
140 ubus_send_reply(ctx
, req
, buf
.head
);
144 c
= blobmsg_open_table(&buf
, "statistics");
146 avl_for_each_element(&devices
, dev
, avl
)
148 d
= blobmsg_open_table(&buf
, dev
->ifname
);
149 rpc_bwmon_dump_stats(dev
);
150 blobmsg_close_table(&buf
, d
);
153 blobmsg_close_table(&buf
, c
);
155 ubus_send_reply(ctx
, req
, buf
.head
);
161 read_int(const char *ifname
, const char *name
)
165 char buf
[32] = { }, path
[PATH_MAX
] = { };
167 snprintf(path
, sizeof(path
) - 1, "/sys/class/net/%s/%s", ifname
, name
);
169 if ((file
= fopen(path
, "r")) != NULL
)
171 if (fread(buf
, 1, sizeof(buf
) - 1, file
) > 0)
172 val
= strtoull(buf
, NULL
, 0);
180 static struct rpc_bwmon_device
*
181 get_device(const char *ifname
, bool create
)
183 struct rpc_bwmon_device
*dev
;
185 dev
= avl_find_element(&devices
, ifname
, dev
, avl
);
189 dev
= calloc(1, sizeof(*dev
));
195 dev
->avl
.key
= strcpy(dev
->ifname
, ifname
);
197 avl_insert(&devices
, &dev
->avl
);
204 put_value(struct rpc_bwmon_device
*dev
, int type
, uint64_t value
)
207 dev
->values
[type
][dev
->pos
] = (uint32_t)(value
- dev
->prev
[type
]);
209 dev
->prev
[type
] = value
;
213 rpc_bwmon_collect(struct uloop_timeout
*t
)
218 struct rpc_bwmon_device
*dev
;
220 if ((dir
= opendir("/sys/class/net")))
222 while ((e
= readdir(dir
)) != NULL
)
224 up
= read_int(e
->d_name
, "flags") & 1;
225 dev
= get_device(e
->d_name
, up
);
230 put_value(dev
, RX_BYTES
,
231 read_int(e
->d_name
, "statistics/rx_bytes"));
233 put_value(dev
, TX_BYTES
,
234 read_int(e
->d_name
, "statistics/tx_bytes"));
236 put_value(dev
, RX_PACKETS
,
237 read_int(e
->d_name
, "statistics/rx_packets"));
239 put_value(dev
, TX_PACKETS
,
240 read_int(e
->d_name
, "statistics/tx_packets"));
242 dev
->pos
= (dev
->pos
+ 1) % RPC_BWMON_HISTORY
;
248 uloop_timeout_set(t
, 1000);
253 rpc_bwmon_api_init(const struct rpc_daemon_ops
*o
, struct ubus_context
*ctx
)
255 static const struct ubus_method bwmon_methods
[] = {
256 UBUS_METHOD_NOARG("devices", rpc_bwmon_devices
),
257 UBUS_METHOD("statistics", rpc_bwmon_stats
, rpc_stats_policy
)
260 static struct ubus_object_type bwmon_type
=
261 UBUS_OBJECT_TYPE("luci-rpc-bwmon", bwmon_methods
);
263 static struct ubus_object bwmon_obj
= {
264 .name
= "luci2.network.bwmon",
266 .methods
= bwmon_methods
,
267 .n_methods
= ARRAY_SIZE(bwmon_methods
),
270 static struct uloop_timeout t
= {
271 .cb
= rpc_bwmon_collect
274 avl_init(&devices
, avl_strcmp
, false, NULL
);
276 uloop_timeout_set(&t
, 1000);
278 return ubus_add_object(ctx
, &bwmon_obj
);
281 const struct rpc_plugin rpc_plugin
= {
282 .init
= rpc_bwmon_api_init