2 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include <linux/netlink.h>
19 #include <vconf-keys.h>
21 #include "helper-nl.h"
22 #include "helper-nfacct-rule.h"
23 #include "helper-net-cls.h"
24 #include "helper-cgroup.h"
25 #include "helper-iptables.h"
27 #include "table-statistics.h"
28 #include "table-counters.h"
29 #include "stc-plugin-monitor.h"
30 #include "stc-plugin-monitor-connection.h"
31 #include "stc-plugin-monitor-rstn.h"
32 #include "stc-manager-plugin-exception.h"
34 static stc_system_s *g_system = NULL;
35 static stc_manager_stop_cb g_stop_cb = NULL;
37 static int __vconf_get_int(const char *key, int *value)
41 ret = vconf_get_int(key, value);
42 if (ret != VCONF_OK) {
43 STC_LOGE("Failed to get vconfkey [%s] value", key);
50 static stc_error_e __close_contr_sock(stc_system_s *system)
52 ret_value_msg_if(system == NULL, STC_ERROR_INVALID_PARAMETER, "invalid parameter");
54 /* close netlink socket for updating kernel counters */
55 if (system->contr_sock != -1) {
56 close(system->contr_sock);
57 system->contr_sock = -1;
60 if (system->contr_gsource_id != 0) {
61 g_source_remove(system->contr_gsource_id);
62 system->contr_gsource_id = 0;
65 return STC_ERROR_NONE;
68 static gboolean __process_contr_reply(GIOChannel *source,
69 GIOCondition condition,
72 static stc_error_e __close_and_reopen_contr_sock(stc_system_s *system)
74 GIOChannel *gio = NULL;
75 ret_value_msg_if(system == NULL, STC_ERROR_INVALID_PARAMETER, "invalid parameter");
77 /* close netlink socket for updating kernel counters */
78 if (system->contr_sock != -1) {
79 close(system->contr_sock);
80 system->contr_sock = -1;
83 if (system->contr_gsource_id != 0) {
84 g_source_remove(system->contr_gsource_id);
85 system->contr_gsource_id = 0;
88 /* create netlink socket for updating kernel counters */
89 system->contr_sock = create_netlink(NETLINK_NETFILTER, 0);
90 if (system->contr_sock < 0) {
91 STC_LOGE("failed to open socket");
94 return STC_ERROR_FAIL;
97 gio = g_io_channel_unix_new(system->contr_sock);
98 system->contr_gsource_id =
99 g_io_add_watch(gio, G_IO_IN | G_IO_ERR | G_IO_HUP,
100 (GIOFunc) __process_contr_reply,
102 g_io_channel_unref(gio);
104 return STC_ERROR_NONE;
107 static void __check_rstn_limit_exceeded(gpointer data,
110 stc_rstn_data_s *rstn_data = (stc_rstn_data_s *)data;
111 int32_t *limit_exceeded = (int32_t *)user_data;
113 if (rstn_data->limit_exceeded != 0)
114 *limit_exceeded = rstn_data->limit_exceeded;
117 static void __fill_nfacct_result(char *cnt_name, long long int bytes,
118 struct counter_arg *carg)
120 stc_monitor_rstn_reset_time_counters_if_required();
122 struct nfacct_rule counter = {
129 classid_bytes_context_s context = {
132 .data_limit_exceeded = FALSE,
135 if (!recreate_counter_by_name(cnt_name, &counter)) {
136 STC_LOGE("Can't parse counter name %s", cnt_name);
141 STC_LOGI("classid[\033[1;36m%u\033[0;m] iftype[%u] "
142 "iotype[%d] intend[%d] ifname[%s] bytes[%lld]",
143 context.counter->classid, context.counter->iftype,
144 context.counter->iotype, context.counter->intend,
145 context.counter->ifname, context.bytes);
147 if (context.counter->intend == NFACCT_COUNTER ||
148 context.counter->intend == NFACCT_TETH_COUNTER) {
149 if (g_system->apps) {
150 stc_app_value_s *lookup_app;
151 stc_rstn_value_s *lookup_rstn;
153 stc_monitor_app_update_iface_counter(&context);
155 lookup_app = g_hash_table_lookup(g_system->apps,
156 GUINT_TO_POINTER(context.counter->classid));
158 stc_monitor_app_update_counter(lookup_app, &context);
160 lookup_rstn = g_hash_table_lookup(g_system->rstns,
161 GUINT_TO_POINTER(context.counter->classid));
163 int32_t limit_exceeded = 0;
164 g_slist_foreach(lookup_rstn->rules,
165 __check_rstn_limit_exceeded, &limit_exceeded);
167 if (limit_exceeded != 0)
172 if (g_system->rstns) {
173 stc_rstn_value_s *lookup_value;
174 uint32_t classid = context.counter->classid;
176 stc_monitor_rstn_update_iface_counter(&context);
177 context.counter->classid = classid;
179 lookup_value = g_hash_table_lookup(g_system->rstns,
180 GUINT_TO_POINTER(classid));
182 g_slist_foreach(lookup_value->rules,
183 stc_monitor_rstn_update_counter,
190 static int __fill_counters(struct rtattr *attr_list[__NFACCT_MAX],
193 struct counter_arg *carg = user_data;
194 char *cnt_name = (char *)RTA_DATA(attr_list[NFACCT_NAME]);
195 if (carg->initiate) {
197 * TODO: this will be used when daemon starts to update existing
198 * counter data if present.
200 populate_counters(cnt_name, carg);
203 long long int *bytes_p =
204 (long long int *)RTA_DATA(attr_list[NFACCT_BYTES]);
205 int bytes = be64toh(*bytes_p);
207 ++carg->serialized_counters;
208 __fill_nfacct_result(cnt_name, bytes, carg);
215 static int __post_fill_counters(void *user_data)
217 struct counter_arg *carg = user_data;
225 static void __process_network_counter(struct genl *ans,
226 struct counter_arg *carg)
228 struct netlink_serialization_params ser_params = {
231 .eval_attr = __fill_counters,
232 .post_eval_attr = __post_fill_counters,
235 netlink_serialization_command *netlink =
236 netlink_create_command(&ser_params);
238 STC_LOGE("Can not create command");
242 netlink->deserialize_answer(&(netlink->params));
245 static gboolean __process_contr_reply(GIOChannel *source,
246 GIOCondition condition,
249 int sock = g_io_channel_unix_get_fd(source);
252 stc_s *stc = stc_get_manager();
255 void __gcov_flush(void);
259 if ((condition & G_IO_ERR) || (condition & G_IO_HUP) ||
260 (condition & G_IO_NVAL)) {
261 /* G_IO_ERR/G_IO_HUP/G_IO_NVAL received */
263 STC_LOGE("Counter socket received G_IO event, closing socket."
264 "G_IO_ERR [%u], G_IO_HUP [%u], G_IO_NVAL [%u]",
265 (condition & G_IO_ERR), (condition & G_IO_HUP),
266 (condition & G_IO_NVAL));
267 __close_and_reopen_contr_sock(g_system);
271 ans = MALLOC0(struct genl, 1);
273 STC_LOGE("Failed allocate memory to genl reply message");
278 STC_LOGE("Can't get stc data");
282 ret = read_netlink(sock, ans, sizeof(struct genl));
287 stc->carg->ans_len = ret;
288 stc->carg->last_run_time = time(NULL);
290 __process_network_counter(ans, stc->carg);
292 g_idle_add(stc_monitor_app_flush_stats_to_db, NULL);
293 g_idle_add(stc_monitor_rstn_flush_contr_to_db, NULL);
300 static gboolean __update_contr_cb(void *user_data)
302 /* Here we just sent command, answer we receive in another callback */
303 stc_s *stc = stc_get_manager();
304 ret_value_msg_if(stc == NULL, STC_ERROR_FAIL, "Can't get stc data");
306 stc->carg = MALLOC0(counter_arg_s, 1);
307 if (stc->carg == NULL)
308 return TRUE; /* we need to continue the timer */
310 stc->carg->sock = g_system->contr_sock;
314 void __gcov_flush(void);
318 /* STC_LOGD("Get all counters"); */
319 nfacct_send_get_all(stc->carg);
321 /* we need to continue the timer */
325 static void __fill_exceptions_list(void)
327 stc_plugin_fill_exception_list();
330 stc_error_e stc_plugin_monitor_initialize(stc_manager_stop_cb stop_cb)
332 __STC_LOG_FUNC_ENTER__;
334 ret_value_msg_if(stop_cb == NULL, STC_ERROR_INVALID_PARAMETER,
335 "stop_cb callback is NULL");
337 stc_system_s *system = MALLOC0(stc_system_s, 1);
338 GIOChannel *gio = NULL;
340 ret_value_msg_if(system == NULL, STC_ERROR_OUT_OF_MEMORY,
341 "stc_system_s malloc fail!");
345 /* initializing current classid */
346 init_current_classid();
348 /* initializing cgroups */
351 /* creating monitored application tree */
352 system->apps = stc_monitor_apps_init();
353 system->rstns = stc_monitor_rstns_init();
355 /* create netlink socket for updating kernel counters */
356 system->contr_sock = create_netlink(NETLINK_NETFILTER, 0);
357 if (system->contr_sock < 0) {
358 STC_LOGE("failed to open socket");
361 return STC_ERROR_FAIL;
364 gio = g_io_channel_unix_new(system->contr_sock);
365 system->contr_gsource_id =
366 g_io_add_watch(gio, G_IO_IN | G_IO_ERR | G_IO_HUP,
367 (GIOFunc) __process_contr_reply,
369 g_io_channel_unref(gio);
373 stc_monitor_app_add_by_iface(STC_TOTAL_DATACALL);
374 stc_monitor_app_add_by_iface(STC_TOTAL_WIFI);
375 stc_monitor_app_add_by_iface(STC_TOTAL_BLUETOOTH);
376 stc_monitor_app_add_by_iface(STC_TOTAL_IPV4);
377 stc_monitor_app_add_by_iface(STC_TOTAL_IPV6);
379 __update_contr_cb(NULL);
381 /* registering periodic kernel counters update callback */
382 g_system->contr_timer_id = g_timeout_add_seconds(CONTR_TIMER_INTERVAL,
385 if (g_system->contr_timer_id == 0) {
386 STC_LOGE("Failed to register kernel counters update timer");
387 __close_contr_sock(g_system);
388 return STC_ERROR_FAIL;
391 __vconf_get_int(VCONFKEY_STC_BACKGROUND_STATE,
392 (int *)&g_system->background_state);
394 __fill_exceptions_list();
395 stc_monitor_rstns_load();
397 __STC_LOG_FUNC_EXIT__;
398 return STC_ERROR_NONE;
401 stc_error_e stc_plugin_monitor_deinitialize(void)
403 ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!");
405 /* close netlink socket for updating kernel counters */
406 __close_contr_sock(g_system);
408 /* remove kernel counters update timer */
409 if (g_system->contr_timer_id > 0) {
410 g_source_remove(g_system->contr_timer_id);
411 g_system->contr_timer_id = 0;
414 /* destroy monitored application tree */
415 g_hash_table_destroy(g_system->apps);
416 g_system->apps = NULL;
418 /* destroy restriction rules tree */
419 g_hash_table_destroy(g_system->rstns);
420 g_system->rstns = NULL;
425 return STC_ERROR_NONE;
428 GHashTable *stc_monitor_get_system_apps(void)
430 ret_value_msg_if(g_system == NULL, NULL,
431 "stc monitor not initialized!");
433 ret_value_msg_if(g_system->apps == NULL, NULL,
436 return g_system->apps;
439 GHashTable *stc_monitor_get_system_rstns(void)
441 ret_value_msg_if(g_system == NULL, NULL,
442 "stc monitor not initialized!");
444 ret_value_msg_if(g_system->rstns == NULL, NULL,
447 return g_system->rstns;
450 int stc_monitor_get_contr_sock(void)
452 ret_value_msg_if(g_system == NULL, 0,
453 "stc monitor not initialized!");
455 return g_system->contr_sock;
458 time_t stc_monitor_get_last_month_ts(void)
460 ret_value_msg_if(g_system == NULL, 0,
461 "stc monitor not initialized!");
463 return g_system->last_month_ts;
466 void stc_monitor_set_last_month_ts(time_t time)
468 ret_msg_if(g_system == NULL, "stc monitor not initialized!");
470 g_system->last_month_ts = time;
473 time_t stc_monitor_get_last_week_ts(void)
475 ret_value_msg_if(g_system == NULL, 0,
476 "stc monitor not initialized!");
478 return g_system->last_week_ts;
481 void stc_monitor_set_last_week_ts(time_t time)
483 ret_msg_if(g_system == NULL, "stc monitor not initialized!");
485 g_system->last_week_ts = time;
488 time_t stc_monitor_get_last_day_ts(void)
490 ret_value_msg_if(g_system == NULL, 0,
491 "stc monitor not initialized!");
493 return g_system->last_day_ts;
496 void stc_monitor_set_last_day_ts(time_t time)
498 ret_msg_if(g_system == NULL, "stc monitor not initialized!");
500 g_system->last_day_ts = time;
503 void stc_monitor_set_rstns_updated(gboolean value)
505 ret_msg_if(g_system == NULL, "stc monitor not initialized!");
507 g_system->rstns_updated = value;
510 gboolean stc_monitor_get_rstns_updated(void)
512 ret_value_msg_if(g_system == NULL, FALSE,
513 "stc monitor not initialized!");
515 return g_system->rstns_updated;
518 void stc_monitor_set_apps_updated(gboolean value)
520 ret_msg_if(g_system == NULL, "stc monitor not initialized!");
522 g_system->apps_updated = value;
525 gboolean stc_monitor_get_apps_updated(void)
527 ret_value_msg_if(g_system == NULL, FALSE,
528 "stc monitor not initialized!");
530 return g_system->apps_updated;
533 void stc_monitor_set_background_state(gboolean value)
535 ret_msg_if(g_system == NULL, "stc monitor not initialized!");
537 g_system->background_state = value;
540 gboolean stc_monitor_get_background_state(void)
542 ret_value_msg_if(g_system == NULL, FALSE,
543 "stc monitor not initialized!");
545 return g_system->background_state;
548 void stc_monitor_update_by_connection(void *data)
550 stc_connection_s *connection = (stc_connection_s *)data;
552 if (connection != NULL && connection->path != NULL) {
553 stc_monitor_app_remove_by_connection(connection);
554 stc_monitor_rstn_remove_by_connection(connection);
556 iptables_flush_chains();
558 stc_monitor_app_add_by_connection(connection);
559 stc_monitor_rstn_add_by_connection(connection);
563 void stc_monitor_add_by_connection(void *data)
565 stc_connection_s *connection = (stc_connection_s *)data;
567 if (connection != NULL && connection->path != NULL) {
568 stc_monitor_app_add_by_connection(connection);
569 stc_monitor_rstn_add_by_connection(connection);
573 void stc_monitor_remove_by_connection(void *data)
575 stc_connection_s *connection = (stc_connection_s *)data;
577 if (connection != NULL && connection->path != NULL) {
578 stc_monitor_app_remove_by_connection(connection);
579 stc_monitor_rstn_remove_by_connection(connection);
583 API stc_plugin_monitor_s stc_plugin_monitor = {
585 stc_plugin_monitor_initialize,
586 .deinitialize_plugin =
587 stc_plugin_monitor_deinitialize,
589 stc_plugin_monitor_app_add,
590 .remove_application =
591 stc_plugin_monitor_app_remove,
592 .lookup_application =
593 stc_plugin_monitor_app_lookup,
595 stc_plugin_monitor_rstn_add,
596 .remove_restriction =
597 stc_plugin_monitor_rstn_remove,
599 stc_plugin_monitor_connection_init,
601 stc_plugin_monitor_connection_deinit,
603 stc_plugin_monitor_proc_add,
605 stc_plugin_monitor_proc_remove,
607 stc_plugin_monitor_proc_move,
608 .update_process_ground =
609 stc_plugin_monitor_proc_update_ground