tizen 2.3 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
216         switch (cnt_name[0]) {
217         case 'c':
218                 cnt->intend  = NFACCT_COUNTER;
219                 break;
220         case 'w':
221                 cnt->intend  = NFACCT_WARN;
222                 break;
223         case 'r':
224                 cnt->intend  = NFACCT_BLOCK;
225                 break;
226         default:
227                 return false;
228         }
229
230         io_part = strtok(cnt_name, "_");
231         if (io_part != NULL)
232                 cnt->iotype = convert_to_iotype(atoi(io_part + 1));
233         else
234                 return false;
235
236         iftype_part = strtok(NULL, "_");
237         if (iftype_part != NULL)
238                 cnt->iftype = convert_to_iftype(atoi(iftype_part));
239         else
240                 return false;
241
242         classid_part = strtok(NULL, "_");
243         if (classid_part != NULL)
244                 cnt->classid = atoi(classid_part);
245         else {
246                 cnt->classid = RESOURCED_ALL_APP_CLASSID;
247                 return cnt->intend == NFACCT_BLOCK ? true : false;
248         }
249
250         ifname_part = strtok(NULL, "\0");
251         if (ifname_part != NULL)
252                 STRING_SAVE_COPY(cnt->ifname, ifname_part);
253         else
254                 return false;
255
256         return true;
257 }
258
259 static void _process_answer(struct netlink_serialization_params *params)
260 {
261         struct rtattr *na;
262         struct rtattr *attr_list[__NFACCT_MAX] = {0};
263         struct counter_arg *carg = params->carg;
264         struct genl *ans = params->ans;;
265         struct nlmsghdr *nlhdr = &ans->n;
266         int len = GENLMSG_PAYLOAD(nlhdr);
267         int ans_len = carg->ans_len;
268
269         if (len == 0)
270                 return;
271
272         /* parse reply message */
273         na = (struct rtattr *)GENLMSG_DATA(ans);
274
275         while (NLMSG_OK(nlhdr, ans_len )) {
276
277                 fill_attribute_list(attr_list, NFACCT_MAX,
278                         na, len);
279                 if (!attr_list[NFACCT_NAME] ||
280                         !attr_list[NFACCT_BYTES])
281                         goto next;
282                 params->eval_attr(attr_list, carg);
283
284 next:
285                 nlhdr = NLMSG_NEXT(nlhdr, ans_len);
286                 if (ans_len < 0)
287                         break;
288                 na = (struct rtattr *)GENLMSG_DATA(nlhdr);
289         }
290
291         if (params->post_eval_attr)
292                 params->post_eval_attr(carg);
293 }
294
295 netlink_serialization_command *netlink_create_command(
296         struct netlink_serialization_params *params)
297 {
298         static netlink_serialization_command command = {0,};
299         command.deserialize_answer = _process_answer;
300         command.params = *params;
301         return &command;
302 }
303
304 static unsigned int get_args_number(const char *cmd_buf)
305 {
306         char *str;
307         unsigned int count = 0;
308
309         for (str = (char *)cmd_buf; *str != '\0'; ++str) {
310                 if (*str == ' ')
311                         ++count;
312         }
313         return count;
314 }
315
316 static void wait_for_rule_cmd(struct nfacct_rule *rule, pid_t pid)
317 {
318         int status;
319         pid_t ret_pid = waitpid(pid, &status, 0);
320         if (ret_pid < 0)
321                 _D("can't wait for a pid %d %d %s", pid, status, strerror(errno));
322 }
323
324 static char* get_cmd_pos(const char *cmd_buf)
325 {
326         char *cmd_pos = strstr(cmd_buf, APPEND);
327         if (!cmd_pos)
328                 cmd_pos = strstr(cmd_buf, INSERT);
329
330         return cmd_pos;
331 }
332
333 static bool is_rule_exists(const char *cmd_buf)
334 {
335         size_t buf_len;
336         char *exec_buf;
337         char *cmd_pos = get_cmd_pos(cmd_buf);
338         bool ret = false;
339         if (!cmd_pos)
340                 return false;
341
342         buf_len = strlen(cmd_buf) + 1;
343         exec_buf = (char *)malloc(buf_len);
344         if (!exec_buf)
345                 return false;
346
347         strncpy(exec_buf, cmd_buf, buf_len);
348         strncpy(exec_buf + (cmd_pos - cmd_buf), IPTABLES_CHECK,
349                 sizeof(IPTABLES_CHECK) - 1);
350         _D("check rule %s", exec_buf);
351         ret = system(exec_buf) == 0;
352         free(exec_buf);
353         return ret;
354 }
355
356 resourced_ret_c exec_iptables_cmd(const char *cmd_buf, pid_t *cmd_pid)
357 {
358         pid_t pid = fork();
359
360         if (pid == 0) {
361                 char *cmd;
362                 unsigned int i;
363                 const size_t args_number = get_args_number(cmd_buf);
364                 char *args[args_number + 2];
365                 int ret;
366
367                 _D("executing iptables cmd %s in forked process", cmd_buf);
368                 ret_value_msg_if(args_number == 0, RESOURCED_ERROR_FAIL, "no arguments");
369
370                 if (is_rule_exists(cmd_buf)) {
371                         _D("Rule %s already exists", cmd_buf);
372                         exit(0);
373                 }
374                 args[0] = "iptables";
375                 cmd = strtok((char *)cmd_buf, " ");
376                 for (i = 1; i <= args_number; ++i) {
377                         args[i] = strtok(NULL, " ");
378                 }
379                 args[i] = NULL;
380
381                 ret = execv(cmd, args);
382                 if (ret)
383                         _E("Can't execute %s: %s",
384                                 cmd_buf, strerror(errno));
385                 exit(ret);
386         }
387
388         *cmd_pid = pid;
389         return RESOURCED_ERROR_NONE;
390 }
391
392 static char *choose_iftype_name(struct nfacct_rule *rule)
393 {
394         return strlen(rule->ifname) != 0 ? rule->ifname :
395                         get_iftype_name(rule->iftype);
396 }
397
398 static resourced_ret_c exec_iface_cmd(const char *pattern, const char *cmd,
399                 const char *nfacct, const char *jump,
400                 char *iftype_name, pid_t *pid)
401 {
402         char block_buf[MAX_PATH_LENGTH];
403         int ret;
404
405         ret_value_msg_if(iftype_name == NULL, RESOURCED_ERROR_FAIL,
406                 "Invalid network interface name argument");
407
408         ret = sprintf(block_buf, pattern, IPTABLES, cmd,
409                 iftype_name, nfacct, jump);
410         ret_value_msg_if(ret > sizeof(block_buf), RESOURCED_ERROR_NONE,
411                 "Not enough buffer");
412         return exec_iptables_cmd(block_buf, pid);
413 }
414
415 static resourced_ret_c exec_app_cmd(const char *pattern, const char *cmd,
416                 const char *nfacct, const char *jump,
417                 const u_int32_t classid, char *iftype_name,
418                 pid_t *pid)
419 {
420         char block_buf[MAX_PATH_LENGTH];
421         int ret;
422         ret_value_msg_if(iftype_name == NULL, RESOURCED_ERROR_FAIL,
423                 "Invalid network interface name argument");
424         ret = sprintf(block_buf, pattern, IPTABLES, cmd,
425                 iftype_name, classid, nfacct, jump);
426         ret_value_msg_if(ret > sizeof(block_buf), RESOURCED_ERROR_NONE,
427                 "Not enough buffer");
428         return exec_iptables_cmd(block_buf, pid);
429 }
430
431 static char *get_iptables_cmd(const nfacct_rule_action action)
432 {
433         if (action == NFACCT_ACTION_APPEND)
434                 return APPEND;
435         else if(action == NFACCT_ACTION_DELETE)
436                 return DELETE;
437         else if (action == NFACCT_ACTION_INSERT)
438                 return INSERT;
439
440         return "";
441 }
442
443 static char *get_iptables_jump(const nfacct_rule_jump jump)
444 {
445         if (jump == NFACCT_JUMP_ACCEPT)
446                 return ACCEPT_RULE;
447         else if (jump == NFACCT_JUMP_REJECT)
448                 return REJECT_RULE;
449
450         return "";
451 }
452
453 static resourced_ret_c produce_app_rule(struct nfacct_rule *rule,
454                         const int send_limit, const int rcv_limit,
455                         const nfacct_rule_action action,
456                         const nfacct_rule_jump jump,
457                         const nfacct_rule_direction iotype)
458 {
459         char *set_cmd = get_iptables_cmd(action);
460         char *jump_cmd = get_iptables_jump(jump);
461         char nfacct_buf[sizeof(NFACCT_NAME_MOD) +
462                 3*MAX_DEC_SIZE(int) + 4];
463         resourced_ret_c ret = RESOURCED_ERROR_NONE;
464         pid_t pid = 0;
465
466         /* income part */
467         if (iotype & NFACCT_COUNTER_IN) {
468                 rule->quota = rcv_limit;
469                 rule->iotype = NFACCT_COUNTER_IN;
470                 generate_counter_name(rule);
471
472                 /* to support quated counter we need nfacct,
473                  *      don't use it in case of just block without a limit
474                  *      iow, send_limit = 0 and rcv_limit 0 */
475                 if (action != NFACCT_ACTION_DELETE) {
476                         ret = nfacct_send_new(rule);
477                         ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
478                                 "can't set nfacct counter");
479                 }
480
481                 /* we have a counter, let's key in a rule, drop in case of
482                  *  send_limit/rcv_limit */
483                 ret = snprintf(nfacct_buf, sizeof(nfacct_buf), NFACCT_NAME_MOD,
484                         rule->name);
485                 ret = exec_app_cmd(RULE_APP_IN, set_cmd, nfacct_buf,
486                         jump_cmd, rule->classid, choose_iftype_name(rule), &pid);
487                 ret_value_msg_if(ret != RESOURCED_ERROR_NONE,
488                         RESOURCED_ERROR_FAIL, "Can't set conditional block for ingress"
489                                 " traffic, for classid %u, cmd %s, j %s",
490                                 rule->classid, set_cmd, jump_cmd);
491
492                 /* remove in any case */
493                 if (action != NFACCT_ACTION_APPEND) {
494                         /* TODO here and everywhere should be not just a del,
495                          *      here should be get counted value and than
496                          *      set new counter with that value, but it's minor issue,
497                          *      due it's not clear when actual counters was stored,
498                          *      and based on which value settings made such decition */
499                         wait_for_rule_cmd(rule, pid);
500                         ret = nfacct_send_del(rule);
501                         ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
502                                 "can't set nfacct counter");
503                 }
504         }
505
506         if (iotype & NFACCT_COUNTER_OUT) {
507                 /* outcome part */
508                 rule->iotype = NFACCT_COUNTER_OUT;
509                 rule->quota = send_limit;
510                 generate_counter_name(rule);
511                 if (action != NFACCT_ACTION_DELETE) {
512                         ret = nfacct_send_new(rule);
513                         ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
514                                 "can't set quota counter");
515                 }
516
517                 ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
518                         "can't set counter");
519
520                 ret = snprintf(nfacct_buf, sizeof(nfacct_buf), NFACCT_NAME_MOD,
521                         rule->name);
522                 ret = exec_app_cmd(RULE_APP_OUT, set_cmd, nfacct_buf,
523                         jump_cmd, rule->classid, choose_iftype_name(rule), &pid);
524                 ret_value_msg_if(ret != RESOURCED_ERROR_NONE,
525                         RESOURCED_ERROR_FAIL, "Can't set conditional block for engress"
526                                 " traffic, for classid %u, cmd %s, j %s",
527                                 rule->classid, set_cmd, jump_cmd);
528                 if (action != NFACCT_ACTION_APPEND) {
529                         wait_for_rule_cmd(rule, pid);
530                         ret = nfacct_send_del(rule);
531                         ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
532                                 "can't del nfacct counter");
533                 }
534         }
535         return RESOURCED_ERROR_NONE;
536 }
537
538 static resourced_ret_c produce_iface_rule(struct nfacct_rule *rule,
539                         const int send_limit, const int rcv_limit,
540                         const nfacct_rule_action action,
541                         const nfacct_rule_jump jump,
542                         const nfacct_rule_direction iotype)
543 {
544         char *set_cmd = get_iptables_cmd(action);
545         char *jump_cmd = get_iptables_jump(jump);
546         char nfacct_buf[sizeof(NFACCT_NAME_MOD) +
547                 3*MAX_DEC_SIZE(int) + 4];
548         resourced_ret_c ret;
549         pid_t pid = 0;
550
551         if (iotype & NFACCT_COUNTER_IN) {
552                 /* income part */
553                 rule->quota = rcv_limit;
554                 rule->iotype = NFACCT_COUNTER_IN;
555                 generate_counter_name(rule);
556
557                 if (action != NFACCT_ACTION_DELETE) {
558                         ret = nfacct_send_new(rule);
559                         ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
560                                 "can't set quota counter");
561                 }
562
563                 ret = snprintf(nfacct_buf, sizeof(nfacct_buf),
564                         NFACCT_NAME_MOD, rule->name);
565                 ret_value_msg_if(ret < 0, RESOURCED_ERROR_FAIL,
566                                 "Not enought buffer");
567
568                 ret = exec_iface_cmd(RULE_IFACE_IN, set_cmd, nfacct_buf,
569                         jump_cmd, choose_iftype_name(rule), &pid);
570                 ret_value_msg_if(ret != RESOURCED_ERROR_NONE,
571                         RESOURCED_ERROR_NONE, "Can't set conditional block for ingress"
572                                 " traffic, for iftype %d, cmd %s, j %s",
573                                 rule->iftype, set_cmd, jump_cmd);
574
575                 if (action != NFACCT_ACTION_APPEND) {
576                         wait_for_rule_cmd(rule, pid);
577                         ret = nfacct_send_del(rule);
578                         ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
579                                 "can't set quota counter");
580                 }
581         }
582
583         if (iotype & NFACCT_COUNTER_OUT) {
584                 /* outcome part */
585                 rule->iotype = NFACCT_COUNTER_OUT;
586                 rule->quota = send_limit;
587                 generate_counter_name(rule);
588
589                 if (action != NFACCT_ACTION_DELETE) {
590                         ret = nfacct_send_new(rule);
591                         ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
592                                 "can't set quota counter");
593                 }
594
595                 ret = snprintf(nfacct_buf, sizeof(nfacct_buf),
596                                 NFACCT_NAME_MOD, rule->name);
597                 ret_value_msg_if(ret < 0, RESOURCED_ERROR_FAIL,
598                                 "Not enough buffer");
599
600                 ret = exec_iface_cmd(RULE_IFACE_OUT, set_cmd, nfacct_buf,
601                         jump_cmd, choose_iftype_name(rule), &pid);
602                 ret_value_msg_if(ret != RESOURCED_ERROR_NONE,
603                         RESOURCED_ERROR_FAIL, "Can't set conditional block for "
604                                 " engress traffic, for iftype %d, cmd %s, j %s",
605                                 rule->iftype, set_cmd, jump_cmd);
606
607                 if (action != NFACCT_ACTION_APPEND) {
608                         wait_for_rule_cmd(rule, pid);
609                         ret = nfacct_send_del(rule);
610                         ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
611                                 "can't set quota counter");
612                 }
613         }
614         return RESOURCED_ERROR_NONE;
615 }
616
617 resourced_ret_c produce_net_rule(struct nfacct_rule *rule,
618                         const int send_limit, const int rcv_limit,
619                         const nfacct_rule_action action,
620                         const nfacct_rule_jump jump,
621                         const nfacct_rule_direction iotype)
622 {
623         resourced_ret_c ret = RESOURCED_ERROR_NONE;
624
625         if (action == NFACCT_ACTION_APPEND && rule->intend == NFACCT_WARN
626                 && !send_limit && !rcv_limit)
627                 return RESOURCED_ERROR_NONE;
628
629         if (rule->classid != RESOURCED_ALL_APP_CLASSID)
630                 ret = produce_app_rule(rule, send_limit,
631                                        rcv_limit, action, jump,
632                                        iotype);
633         else
634                 ret = produce_iface_rule(rule, send_limit, rcv_limit,
635                                          action, jump, iotype);
636
637         return ret;
638 }
639
640 void generate_counter_name(struct nfacct_rule *counter)
641 {
642         char warn_symbol = 'c';
643         char *iftype_name = get_iftype_name(counter->iftype);
644         ret_msg_if(iftype_name == NULL, "Can't get interface name!");
645         STRING_SAVE_COPY(counter->ifname, iftype_name);
646
647         if (counter->intend  == NFACCT_WARN)
648                 warn_symbol = 'w';
649         else if (counter->intend  == NFACCT_BLOCK)
650                 warn_symbol = 'r';
651         if (counter->classid != RESOURCED_ALL_APP_CLASSID)
652                 snprintf(counter->name, MAX_NAME_LENGTH, "%c%d_%d_%d_%s",
653                         warn_symbol, counter->iotype, counter->iftype,
654                         counter->classid, counter->ifname);
655         else
656                 snprintf(counter->name, MAX_NAME_LENGTH, "%c%d_%d_%s",
657                         warn_symbol, counter->iotype, counter->iftype,
658                         counter->ifname);
659
660         }
661