tizen 2.3.1 release
[kernel/api/system-resource.git] / src / network / nfacct-rule.c
1 /*
2  * resourced
3  *
4  * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 /**
20  * @file nfacct-rule.c
21  *
22  * @desc Datausage module
23  *
24  * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
25  *
26  */
27
28 #include <errno.h>
29 #include <inttypes.h>
30 #include <stdbool.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/types.h>
34 #include <sys/wait.h>
35 #include <unistd.h>
36
37 #include "const.h"
38 #include "counter.h"
39 #include "iface.h"
40 #include "macro.h"
41 #include "module-data.h"
42 #include "nfacct-rule.h"
43 #include "nl-helper.h"
44 #include "resourced.h"
45 #include "trace.h"
46
47 #define IPTABLES "/usr/sbin/iptables"
48 #define IPTABLES_CHECK "-C"
49 #define APPEND "-A"
50 #define DELETE "-D"
51 #define INSERT "-I"
52
53 #define NFACCT_NAME_MOD " -m nfacct --nfacct-name %s"
54 #define REJECT_RULE " -j REJECT"
55 #define ACCEPT_RULE " -j ACCEPT"
56
57 /* TODO idea to use the same rule both for BLOCK (REJECT) and WARNING (ACCEPT) */
58 #define RULE_APP_OUT "%s -w %s OUTPUT -o %s -m cgroup --cgroup %u %s %s"
59 #define RULE_APP_IN "%s -w %s INPUT -i %s -m cgroup --cgroup %u %s %s"
60
61 #define RULE_IFACE_OUT "%s -w %s OUTPUT -o %s %s -m cgroup ! --cgroup 0 %s"
62 #define RULE_IFACE_IN "%s -w %s INPUT -i %s %s -m cgroup ! --cgroup 0 %s"
63
64 #define NFNL_SUBSYS_ACCT                7
65
66 enum nfnl_acct_flags {
67         NFACCT_F_QUOTA_PKTS     = (1 << 0),
68         NFACCT_F_QUOTA_BYTES    = (1 << 1),
69         NFACCT_F_OVERQUOTA      = (1 << 2), /* can't be set from userspace */
70 };
71
72 static void prepare_netlink_msg(struct genl *req, int type, int flag)
73 {
74         int seq = time(NULL);
75         memset(req, 0, sizeof(struct genl));
76         req->n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
77         req->n.nlmsg_type = (NFNL_SUBSYS_ACCT << 8) | type;
78         req->n.nlmsg_flags = NLM_F_REQUEST | flag;
79         req->n.nlmsg_seq = seq;
80 }
81
82 static void add_value_attr(struct genl *req, const void *data, int len, int type)
83 {
84         int payload;
85         /* get tail */
86         struct nlattr *na = (struct nlattr *)(
87                  (char *)req + NLMSG_ALIGN(req->n.nlmsg_len));
88
89         na->nla_type = type;
90         payload = len + NLA_HDRLEN;
91         na->nla_len = payload;
92         memcpy(NLA_DATA(na), data, len);
93         req->n.nlmsg_len += NLMSG_ALIGN(payload);
94 }
95
96 /*
97  * following 2 function should be used in combination.
98  * start_nest_attr returns nlattr structure, which should be completed by
99  * end_nest_attr,
100  * before these invocations any number of netlink arguments could be inserted
101  * */
102 static struct nlattr *start_nest_attr(struct genl *req, uint16_t type)
103 {
104         struct nlattr *start = (struct nlattr *)(
105                  (char *)req + NLMSG_ALIGN(req->n.nlmsg_len));
106
107         start->nla_type = NLA_F_NESTED | type;
108         req->n.nlmsg_len += NLMSG_ALIGN(sizeof(struct nlattr));
109         return start;
110 }
111
112 static void end_nest_attr(struct genl *req, struct nlattr *start)
113 {
114         start->nla_len = (__u16)(
115                  (char *)req + NLMSG_ALIGN(req->n.nlmsg_len) - (char *)start);
116 }
117
118 static void add_string_attr(struct genl *req, const char *str, int type)
119 {
120         add_value_attr(req, str, strlen(str) + 1, type);
121 }
122
123 static void add_uint64_attr(struct genl *req, const uint64_t v, int type)
124 {
125         add_value_attr(req, &v, sizeof(v), type);
126 }
127
128 /* macros or templare, due uint64 and uint32 is the same functions */
129 static void add_uint32_attr(struct genl *req, const uint32_t v, int type)
130 {
131         add_value_attr(req, &v, sizeof(v), type);
132 }
133
134 static resourced_ret_c send_nfacct_request(int sock, struct genl *req)
135 {
136         struct sockaddr_nl nladdr = {.nl_family = AF_NETLINK};
137         int ret = sendto(sock, (char *)(&req->n), req->n.nlmsg_len, 0,
138                       (struct sockaddr *)&nladdr, sizeof(nladdr));
139         ret_value_msg_if(ret < 0, RESOURCED_ERROR_FAIL,
140                         "Failed to send command to get outgoing traffic");
141
142         return RESOURCED_ERROR_NONE;
143 }
144
145 static resourced_ret_c nfacct_send_new(struct nfacct_rule *counter)
146 {
147         struct genl req;
148
149         prepare_netlink_msg(&req, NFNL_MSG_ACCT_NEW, NLM_F_CREATE | NLM_F_ACK);
150         add_string_attr(&req, counter->name, NFACCT_NAME);
151         _D("counter name %s", counter->name);
152         /* padding */
153         add_uint64_attr(&req, 0, NFACCT_PKTS);
154         add_uint64_attr(&req, 0, NFACCT_BYTES);
155         if (counter->quota) {
156                 _D("quota bytes %"PRId64, counter->quota);
157                 add_uint32_attr(&req, htobe32(NFACCT_F_QUOTA_BYTES), NFACCT_FLAGS);
158                 add_uint64_attr(&req, htobe64(counter->quota), NFACCT_QUOTA);
159         }
160
161         return send_nfacct_request(counter->carg->sock, &req);
162 }
163
164 static resourced_ret_c nfacct_send_del(struct nfacct_rule *counter)
165 {
166         struct genl req;
167
168         prepare_netlink_msg(&req, NFNL_MSG_ACCT_DEL, NLM_F_ACK);
169         add_string_attr(&req, counter->name, NFACCT_NAME);
170         return send_nfacct_request(counter->carg->sock, &req);
171 }
172 #define NFACCT_F_QUOTAS (NFACCT_F_QUOTA_BYTES | NFACCT_F_QUOTA_PKTS)
173 resourced_ret_c nfacct_send_get(struct counter_arg *carg)
174 {
175         struct genl req;
176         struct nlattr *na;
177         prepare_netlink_msg(&req, NFNL_MSG_ACCT_GET_CTRZERO,
178                 NLM_F_DUMP);
179         /* due we don't get counter with quota any where else,
180         * here we will request just counters by default */
181         na = start_nest_attr(&req, NFACCT_FILTER);
182         add_uint32_attr(&req, NFACCT_F_QUOTAS,
183                 NFACCT_FILTER_ATTR_MASK);
184         add_uint32_attr(&req, 0, NFACCT_FILTER_ATTR_VALUE);
185         end_nest_attr(&req, na);
186         return send_nfacct_request(carg->sock, &req);
187 }
188
189 resourced_ret_c nfacct_send_initiate(struct counter_arg *carg)
190 {
191         struct genl req;
192         prepare_netlink_msg(&req, NFNL_MSG_ACCT_GET,
193                 NLM_F_DUMP);
194         return send_nfacct_request(carg->sock, &req);
195 }
196
197 static nfacct_rule_direction convert_to_iotype(int type)
198 {
199         return type < NFACCT_COUNTER_LAST_ELEM && type > NFACCT_COUNTER_UNKNOWN ?
200                 type : NFACCT_COUNTER_UNKNOWN;
201 }
202
203 static resourced_iface_type convert_to_iftype(int type)
204 {
205         return type < RESOURCED_IFACE_LAST_ELEM && type > RESOURCED_IFACE_UNKNOWN ?
206                 type : RESOURCED_IFACE_UNKNOWN;
207 }
208
209 bool recreate_counter_by_name(char *cnt_name, struct nfacct_rule *cnt)
210 {
211         char *iftype_part;
212         char *classid_part;
213         char *io_part;
214         char *ifname_part;
215         char *saveptr;
216
217         switch (cnt_name[0]) {
218         case 'c':
219                 cnt->intend  = NFACCT_COUNTER;
220                 break;
221         case 'w':
222                 cnt->intend  = NFACCT_WARN;
223                 break;
224         case 'r':
225                 cnt->intend  = NFACCT_BLOCK;
226                 break;
227         default:
228                 return false;
229         }
230
231         io_part = strtok_r(cnt_name, "_", &saveptr);
232         if (io_part != NULL)
233                 cnt->iotype = convert_to_iotype(atoi(io_part + 1));
234         else
235                 return false;
236
237         iftype_part = strtok_r(NULL, "_", &saveptr);
238         if (iftype_part != NULL)
239                 cnt->iftype = convert_to_iftype(atoi(iftype_part));
240         else
241                 return false;
242
243         classid_part = strtok_r(NULL, "_", &saveptr);
244         if (classid_part != NULL)
245                 cnt->classid = atoi(classid_part);
246         else {
247                 cnt->classid = RESOURCED_ALL_APP_CLASSID;
248                 return cnt->intend == NFACCT_BLOCK ? true : false;
249         }
250
251         ifname_part = strtok_r(NULL, "\0", &saveptr);
252         if (ifname_part != NULL)
253                 STRING_SAVE_COPY(cnt->ifname, ifname_part);
254         else
255                 return false;
256
257         return true;
258 }
259
260 static void _process_answer(struct netlink_serialization_params *params)
261 {
262         struct rtattr *na;
263         struct rtattr *attr_list[__NFACCT_MAX] = {0};
264         struct counter_arg *carg = params->carg;
265         struct genl *ans = params->ans;;
266         struct nlmsghdr *nlhdr = &ans->n;
267         int len = GENLMSG_PAYLOAD(nlhdr);
268         int ans_len = carg->ans_len;
269
270         if (len == 0)
271                 return;
272
273         /* parse reply message */
274         na = (struct rtattr *)GENLMSG_DATA(ans);
275
276         while (NLMSG_OK(nlhdr, ans_len )) {
277
278                 fill_attribute_list(attr_list, NFACCT_MAX,
279                         na, len);
280                 if (!attr_list[NFACCT_NAME] ||
281                         !attr_list[NFACCT_BYTES])
282                         goto next;
283                 params->eval_attr(attr_list, carg);
284
285 next:
286                 nlhdr = NLMSG_NEXT(nlhdr, ans_len);
287                 if (ans_len < 0)
288                         break;
289                 na = (struct rtattr *)GENLMSG_DATA(nlhdr);
290         }
291
292         if (params->post_eval_attr)
293                 params->post_eval_attr(carg);
294 }
295
296 netlink_serialization_command *netlink_create_command(
297         struct netlink_serialization_params *params)
298 {
299         static netlink_serialization_command command = {0,};
300         command.deserialize_answer = _process_answer;
301         command.params = *params;
302         return &command;
303 }
304
305 static unsigned int get_args_number(const char *cmd_buf)
306 {
307         char *str;
308         unsigned int count = 0;
309
310         for (str = (char *)cmd_buf; *str != '\0'; ++str) {
311                 if (*str == ' ')
312                         ++count;
313         }
314         return count;
315 }
316
317 static void wait_for_rule_cmd(struct nfacct_rule *rule, pid_t pid)
318 {
319         int status;
320         char buf[256];
321
322         pid_t ret_pid = waitpid(pid, &status, 0);
323         if (ret_pid < 0) {
324                 strerror_r(errno, buf, sizeof(buf));
325                 _D("can't wait for a pid %d %d %s", pid, status, buf);
326         }
327 }
328
329 static char* get_cmd_pos(const char *cmd_buf)
330 {
331         char *cmd_pos = strstr(cmd_buf, APPEND);
332         if (!cmd_pos)
333                 cmd_pos = strstr(cmd_buf, INSERT);
334
335         return cmd_pos;
336 }
337
338 static bool is_rule_exists(const char *cmd_buf)
339 {
340         size_t buf_len;
341         char *exec_buf;
342         char *cmd_pos = get_cmd_pos(cmd_buf);
343         bool ret = false;
344         if (!cmd_pos)
345                 return false;
346
347         buf_len = strlen(cmd_buf) + 1;
348         exec_buf = (char *)malloc(buf_len);
349         if (!exec_buf)
350                 return false;
351
352         strncpy(exec_buf, cmd_buf, buf_len);
353         strncpy(exec_buf + (cmd_pos - cmd_buf), IPTABLES_CHECK,
354                 sizeof(IPTABLES_CHECK) - 1);
355         _D("check rule %s", exec_buf);
356         ret = system(exec_buf) == 0;
357         free(exec_buf);
358         return ret;
359 }
360
361 resourced_ret_c exec_iptables_cmd(const char *cmd_buf, pid_t *cmd_pid)
362 {
363         pid_t pid = fork();
364
365         if (pid == 0) {
366                 char *cmd;
367                 char *saveptr;
368                 unsigned int i;
369                 const size_t args_number = get_args_number(cmd_buf);
370                 char *args[args_number + 2];
371                 int ret;
372                 char buf[256];
373
374                 _D("executing iptables cmd %s in forked process", cmd_buf);
375                 ret_value_msg_if(args_number == 0, RESOURCED_ERROR_FAIL, "no arguments");
376
377                 if (is_rule_exists(cmd_buf)) {
378                         _D("Rule %s already exists", cmd_buf);
379                         exit(0);
380                 }
381                 args[0] = "iptables";
382                 cmd = strtok_r((char *)cmd_buf, " ", &saveptr);
383                 for (i = 1; i <= args_number; ++i) {
384                         args[i] = strtok_r(NULL, " ", &saveptr);
385                 }
386                 args[i] = NULL;
387
388                 ret = execv(cmd, args);
389                 if (ret) {
390                         strerror_r(errno, buf, sizeof(buf));
391                         _E("Can't execute %s: %s",
392                                 cmd_buf, buf);
393                 }
394                 exit(ret);
395         }
396
397         *cmd_pid = pid;
398         return RESOURCED_ERROR_NONE;
399 }
400
401 static char *choose_iftype_name(struct nfacct_rule *rule)
402 {
403         return strlen(rule->ifname) != 0 ? rule->ifname :
404                         get_iftype_name(rule->iftype);
405 }
406
407 static resourced_ret_c exec_iface_cmd(const char *pattern, const char *cmd,
408                 const char *nfacct, const char *jump,
409                 char *iftype_name, pid_t *pid)
410 {
411         char block_buf[MAX_PATH_LENGTH];
412         int ret;
413
414         ret_value_msg_if(iftype_name == NULL, RESOURCED_ERROR_FAIL,
415                 "Invalid network interface name argument");
416
417         ret = snprintf(block_buf, sizeof(block_buf), pattern, IPTABLES, cmd,
418                 iftype_name, nfacct, jump);
419         ret_value_msg_if(ret > sizeof(block_buf), RESOURCED_ERROR_NONE,
420                 "Not enough buffer");
421         return exec_iptables_cmd(block_buf, pid);
422 }
423
424 static resourced_ret_c exec_app_cmd(const char *pattern, const char *cmd,
425                 const char *nfacct, const char *jump,
426                 const u_int32_t classid, char *iftype_name,
427                 pid_t *pid)
428 {
429         char block_buf[MAX_PATH_LENGTH];
430         int ret;
431         ret_value_msg_if(iftype_name == NULL, RESOURCED_ERROR_FAIL,
432                 "Invalid network interface name argument");
433         ret = snprintf(block_buf, sizeof(block_buf), pattern, IPTABLES, cmd,
434                 iftype_name, classid, nfacct, jump);
435         ret_value_msg_if(ret > sizeof(block_buf), RESOURCED_ERROR_NONE,
436                 "Not enough buffer");
437         return exec_iptables_cmd(block_buf, pid);
438 }
439
440 static char *get_iptables_cmd(const nfacct_rule_action action)
441 {
442         if (action == NFACCT_ACTION_APPEND)
443                 return APPEND;
444         else if(action == NFACCT_ACTION_DELETE)
445                 return DELETE;
446         else if (action == NFACCT_ACTION_INSERT)
447                 return INSERT;
448
449         return "";
450 }
451
452 static char *get_iptables_jump(const nfacct_rule_jump jump)
453 {
454         if (jump == NFACCT_JUMP_ACCEPT)
455                 return ACCEPT_RULE;
456         else if (jump == NFACCT_JUMP_REJECT)
457                 return REJECT_RULE;
458
459         return "";
460 }
461
462 static resourced_ret_c produce_app_rule(struct nfacct_rule *rule,
463                         const int send_limit, const int rcv_limit,
464                         const nfacct_rule_action action,
465                         const nfacct_rule_jump jump,
466                         const nfacct_rule_direction iotype)
467 {
468         char *set_cmd = get_iptables_cmd(action);
469         char *jump_cmd = get_iptables_jump(jump);
470         char nfacct_buf[sizeof(NFACCT_NAME_MOD) +
471                 3*MAX_DEC_SIZE(int) + 4];
472         resourced_ret_c ret = RESOURCED_ERROR_NONE;
473         pid_t pid = 0;
474
475         /* income part */
476         if (iotype & NFACCT_COUNTER_IN) {
477                 rule->quota = rcv_limit;
478                 rule->iotype = NFACCT_COUNTER_IN;
479                 generate_counter_name(rule);
480
481                 /* to support quated counter we need nfacct,
482                  *      don't use it in case of just block without a limit
483                  *      iow, send_limit = 0 and rcv_limit 0 */
484                 if (action != NFACCT_ACTION_DELETE) {
485                         ret = nfacct_send_new(rule);
486                         ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
487                                 "can't set nfacct counter");
488                 }
489
490                 /* we have a counter, let's key in a rule, drop in case of
491                  *  send_limit/rcv_limit */
492                 ret = snprintf(nfacct_buf, sizeof(nfacct_buf), NFACCT_NAME_MOD,
493                         rule->name);
494                 ret = exec_app_cmd(RULE_APP_IN, set_cmd, nfacct_buf,
495                         jump_cmd, rule->classid, choose_iftype_name(rule), &pid);
496                 ret_value_msg_if(ret != RESOURCED_ERROR_NONE,
497                         RESOURCED_ERROR_FAIL, "Can't set conditional block for ingress"
498                                 " traffic, for classid %u, cmd %s, j %s",
499                                 rule->classid, set_cmd, jump_cmd);
500
501                 /* remove in any case */
502                 if (action != NFACCT_ACTION_APPEND) {
503                         /* TODO here and everywhere should be not just a del,
504                          *      here should be get counted value and than
505                          *      set new counter with that value, but it's minor issue,
506                          *      due it's not clear when actual counters was stored,
507                          *      and based on which value settings made such decition */
508                         wait_for_rule_cmd(rule, pid);
509                         ret = nfacct_send_del(rule);
510                         ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
511                                 "can't set nfacct counter");
512                 }
513         }
514
515         if (iotype & NFACCT_COUNTER_OUT) {
516                 /* outcome part */
517                 rule->iotype = NFACCT_COUNTER_OUT;
518                 rule->quota = send_limit;
519                 generate_counter_name(rule);
520                 if (action != NFACCT_ACTION_DELETE) {
521                         ret = nfacct_send_new(rule);
522                         ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
523                                 "can't set quota counter");
524                 }
525
526                 ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
527                         "can't set counter");
528
529                 ret = snprintf(nfacct_buf, sizeof(nfacct_buf), NFACCT_NAME_MOD,
530                         rule->name);
531                 ret = exec_app_cmd(RULE_APP_OUT, set_cmd, nfacct_buf,
532                         jump_cmd, rule->classid, choose_iftype_name(rule), &pid);
533                 ret_value_msg_if(ret != RESOURCED_ERROR_NONE,
534                         RESOURCED_ERROR_FAIL, "Can't set conditional block for engress"
535                                 " traffic, for classid %u, cmd %s, j %s",
536                                 rule->classid, set_cmd, jump_cmd);
537                 if (action != NFACCT_ACTION_APPEND) {
538                         wait_for_rule_cmd(rule, pid);
539                         ret = nfacct_send_del(rule);
540                         ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
541                                 "can't del nfacct counter");
542                 }
543         }
544         return RESOURCED_ERROR_NONE;
545 }
546
547 static resourced_ret_c produce_iface_rule(struct nfacct_rule *rule,
548                         const int send_limit, const int rcv_limit,
549                         const nfacct_rule_action action,
550                         const nfacct_rule_jump jump,
551                         const nfacct_rule_direction iotype)
552 {
553         char *set_cmd = get_iptables_cmd(action);
554         char *jump_cmd = get_iptables_jump(jump);
555         char nfacct_buf[sizeof(NFACCT_NAME_MOD) +
556                 3*MAX_DEC_SIZE(int) + 4];
557         resourced_ret_c ret;
558         pid_t pid = 0;
559
560         if (iotype & NFACCT_COUNTER_IN) {
561                 /* income part */
562                 rule->quota = rcv_limit;
563                 rule->iotype = NFACCT_COUNTER_IN;
564                 generate_counter_name(rule);
565
566                 if (action != NFACCT_ACTION_DELETE) {
567                         ret = nfacct_send_new(rule);
568                         ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
569                                 "can't set quota counter");
570                 }
571
572                 ret = snprintf(nfacct_buf, sizeof(nfacct_buf),
573                         NFACCT_NAME_MOD, rule->name);
574                 ret_value_msg_if(ret < 0, RESOURCED_ERROR_FAIL,
575                                 "Not enought buffer");
576
577                 ret = exec_iface_cmd(RULE_IFACE_IN, set_cmd, nfacct_buf,
578                         jump_cmd, choose_iftype_name(rule), &pid);
579                 ret_value_msg_if(ret != RESOURCED_ERROR_NONE,
580                         RESOURCED_ERROR_NONE, "Can't set conditional block for ingress"
581                                 " traffic, for iftype %d, cmd %s, j %s",
582                                 rule->iftype, set_cmd, jump_cmd);
583
584                 if (action != NFACCT_ACTION_APPEND) {
585                         wait_for_rule_cmd(rule, pid);
586                         ret = nfacct_send_del(rule);
587                         ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
588                                 "can't set quota counter");
589                 }
590         }
591
592         if (iotype & NFACCT_COUNTER_OUT) {
593                 /* outcome part */
594                 rule->iotype = NFACCT_COUNTER_OUT;
595                 rule->quota = send_limit;
596                 generate_counter_name(rule);
597
598                 if (action != NFACCT_ACTION_DELETE) {
599                         ret = nfacct_send_new(rule);
600                         ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
601                                 "can't set quota counter");
602                 }
603
604                 ret = snprintf(nfacct_buf, sizeof(nfacct_buf),
605                                 NFACCT_NAME_MOD, rule->name);
606                 ret_value_msg_if(ret < 0, RESOURCED_ERROR_FAIL,
607                                 "Not enough buffer");
608
609                 ret = exec_iface_cmd(RULE_IFACE_OUT, set_cmd, nfacct_buf,
610                         jump_cmd, choose_iftype_name(rule), &pid);
611                 ret_value_msg_if(ret != RESOURCED_ERROR_NONE,
612                         RESOURCED_ERROR_FAIL, "Can't set conditional block for "
613                                 " engress traffic, for iftype %d, cmd %s, j %s",
614                                 rule->iftype, set_cmd, jump_cmd);
615
616                 if (action != NFACCT_ACTION_APPEND) {
617                         wait_for_rule_cmd(rule, pid);
618                         ret = nfacct_send_del(rule);
619                         ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
620                                 "can't set quota counter");
621                 }
622         }
623         return RESOURCED_ERROR_NONE;
624 }
625
626 resourced_ret_c produce_net_rule(struct nfacct_rule *rule,
627                         const int send_limit, const int rcv_limit,
628                         const nfacct_rule_action action,
629                         const nfacct_rule_jump jump,
630                         const nfacct_rule_direction iotype)
631 {
632         resourced_ret_c ret = RESOURCED_ERROR_NONE;
633
634         if (action == NFACCT_ACTION_APPEND && rule->intend == NFACCT_WARN
635                 && !send_limit && !rcv_limit)
636                 return RESOURCED_ERROR_NONE;
637
638         if (rule->classid != RESOURCED_ALL_APP_CLASSID)
639                 ret = produce_app_rule(rule, send_limit,
640                                        rcv_limit, action, jump,
641                                        iotype);
642         else
643                 ret = produce_iface_rule(rule, send_limit, rcv_limit,
644                                          action, jump, iotype);
645
646         return ret;
647 }
648
649 void generate_counter_name(struct nfacct_rule *counter)
650 {
651         char warn_symbol = 'c';
652         char *iftype_name = get_iftype_name(counter->iftype);
653         ret_msg_if(iftype_name == NULL, "Can't get interface name!");
654         STRING_SAVE_COPY(counter->ifname, iftype_name);
655
656         if (counter->intend  == NFACCT_WARN)
657                 warn_symbol = 'w';
658         else if (counter->intend  == NFACCT_BLOCK)
659                 warn_symbol = 'r';
660         if (counter->classid != RESOURCED_ALL_APP_CLASSID)
661                 snprintf(counter->name, MAX_NAME_LENGTH, "%c%d_%d_%d_%s",
662                         warn_symbol, counter->iotype, counter->iftype,
663                         counter->classid, counter->ifname);
664         else
665                 snprintf(counter->name, MAX_NAME_LENGTH, "%c%d_%d_%s",
666                         warn_symbol, counter->iotype, counter->iftype,
667                         counter->ifname);
668
669         }
670