]> git.proxmox.com Git - mirror_iproute2.git/blobdiff - tc/m_action.c
libnetlink: add size argument to rtnl_talk
[mirror_iproute2.git] / tc / m_action.c
index dc303065f262d3c0cfcf41a4782169284c4a0f16..d363d273068f23eb5a428d8d56fed15ebb4306cc 100644 (file)
@@ -6,8 +6,8 @@
  *             as published by the Free Software Foundation; either version
  *             2 of the License, or (at your option) any later version.
  *
- * Authors:  J Hadi Salim (hadi@cyberus.ca) 
- * 
+ * Authors:  J Hadi Salim (hadi@cyberus.ca)
+ *
  * TODO:
  * - parse to be passed a filedescriptor for logging purposes
  *
 #include <dlfcn.h>
 
 #include "utils.h"
+#include "tc_common.h"
 #include "tc_util.h"
 
-void *aBODY;
-
-
 static struct action_util * action_list;
 #ifdef CONFIG_GACT
 int gact_ld = 0 ; //fuckin backward compatibility
 #endif
-int batch_c = 0;
 int tab_flush = 0;
 
-void act_usage(void)
+static void act_usage(void)
 {
-       fprintf (stderr, "action usage improper\n");
+       /*XXX: In the near future add a action->print_help to improve
+        * usability
+        * This would mean new tc will not be backward compatible
+        * with any action .so from the old days. But if someone really
+        * does that, they would know how to fix this ..
+        *
+       */
+       fprintf (stderr, "usage: tc actions <ACTSPECOP>*\n");
+       fprintf(stderr,
+               "Where: \tACTSPECOP := ACR | GD | FL\n"
+                       "\tACR := add | change | replace <ACTSPEC>* \n"
+                       "\tGD := get | delete | <ACTISPEC>*\n"
+                       "\tFL := ls | list | flush | <ACTNAMESPEC>\n"
+                       "\tACTNAMESPEC :=  action <ACTNAME>\n"
+                       "\tACTISPEC := <ACTNAMESPEC> <INDEXSPEC>\n"
+                       "\tACTSPEC := action <ACTDETAIL> [INDEXSPEC]\n"
+                       "\tINDEXSPEC := index <32 bit indexvalue>\n"
+                       "\tACTDETAIL := <ACTNAME> <ACTPARAMS>\n"
+                       "\t\tExample ACTNAME is gact, mirred, bpf, etc\n"
+                       "\t\tEach action has its own parameters (ACTPARAMS)\n"
+                       "\n");
+
+       exit(-1);
 }
 
 static int print_noaopt(struct action_util *au, FILE *f, struct rtattr *opt)
 {
        if (opt && RTA_PAYLOAD(opt))
-               fprintf(f, "[Unknown action, optlen=%u] ", 
+               fprintf(f, "[Unknown action, optlen=%u] ",
                        (unsigned) RTA_PAYLOAD(opt));
        return 0;
 }
@@ -63,8 +82,9 @@ static int parse_noaopt(struct action_util *au, int *argc_p, char ***argv_p, int
        return -1;
 }
 
-struct action_util *get_action_kind(char *str)
+static struct action_util *get_action_kind(char *str)
 {
+       static void *aBODY;
        void *dlh;
        char buf[256];
        struct action_util *a;
@@ -77,8 +97,8 @@ restart_s:
                        return a;
        }
 
-       snprintf(buf, sizeof(buf), "m_%s.so", str);
-       dlh = dlopen(buf, RTLD_LAZY);
+       snprintf(buf, sizeof(buf), "%s/m_%s.so", get_tc_lib(), str);
+       dlh = dlopen(buf, RTLD_LAZY | RTLD_GLOBAL);
        if (dlh == NULL) {
                dlh = aBODY;
                if (dlh == NULL) {
@@ -117,12 +137,13 @@ noexist:
        return a;
 }
 
-int
-new_cmd(char **argv) 
+static int
+new_cmd(char **argv)
 {
        if ((matches(*argv, "change") == 0) ||
                (matches(*argv, "replace") == 0)||
                (matches(*argv, "delete") == 0)||
+               (matches(*argv, "get") == 0)||
                (matches(*argv, "add") == 0))
                        return 1;
 
@@ -146,8 +167,7 @@ parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
        if (argc <= 0)
                return -1;
 
-       tail = tail2 =
-           (struct rtattr *) (((void *) n) + NLMSG_ALIGN(n->nlmsg_len));
+       tail = tail2 = NLMSG_TAIL(n);
 
        addattr_l(n, MAX_MSG, tca_id, NULL, 0);
 
@@ -165,6 +185,10 @@ parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
                        }
 #endif
                        continue;
+               } else if (strcmp(*argv, "flowid") == 0) {
+                       break;
+               } else if (strcmp(*argv, "classid") == 0) {
+                       break;
                } else if (strcmp(*argv, "help") == 0) {
                        return -1;
                } else if (new_cmd(argv)) {
@@ -183,13 +207,11 @@ done0:
                                        goto done;
                        }
 
-                       if (NULL == a) { 
+                       if (NULL == a) {
                                goto bad_val;
                        }
 
-                       tail =
-                           (struct rtattr *) (((void *) n) +
-                                      NLMSG_ALIGN(n->nlmsg_len));
+                       tail = NLMSG_TAIL(n);
                        addattr_l(n, MAX_MSG, ++prio, NULL, 0);
                        addattr_l(n, MAX_MSG, TCA_ACT_KIND, k, strlen(k) + 1);
 
@@ -199,9 +221,7 @@ done0:
                                fprintf(stderr,"bad action parsing\n");
                                goto bad_val;
                        }
-                       tail->rta_len =
-                           (((void *) n) + NLMSG_ALIGN(n->nlmsg_len)) -
-                           (void *) tail;
+                       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
                        ok++;
                }
 
@@ -212,21 +232,20 @@ done0:
                goto bad_val;
        }
 
-       tail2->rta_len =
-           (((void *) n) + NLMSG_ALIGN(n->nlmsg_len)) - (void *) tail2;
+       tail2->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail2;
 
 done:
        *argc_p = argc;
        *argv_p = argv;
        return 0;
 bad_val:
-       /* no need to undo things, returning from here should 
+       /* no need to undo things, returning from here should
         * cause enough pain */
        fprintf(stderr, "parse_action: bad value (%d:%s)!\n",argc,*argv);
        return -1;
 }
 
-int
+static int
 tc_print_one_action(FILE * f, struct rtattr *arg)
 {
 
@@ -237,8 +256,8 @@ tc_print_one_action(FILE * f, struct rtattr *arg)
        if (arg == NULL)
                return -1;
 
-       memset(tb, 0, sizeof (tb));
-       parse_rtattr(tb, TCA_ACT_MAX, RTA_DATA(arg), RTA_PAYLOAD(arg));
+       parse_rtattr_nested(tb, TCA_ACT_MAX, arg);
+
        if (tb[TCA_ACT_KIND] == NULL) {
                fprintf(stderr, "NULL Action!\n");
                return -1;
@@ -249,29 +268,48 @@ tc_print_one_action(FILE * f, struct rtattr *arg)
        if (NULL == a)
                return err;
 
-       if (tab_flush) {
-               fprintf(f," %s \n", a->id);
-               tab_flush = 0;
-               return 0;
-       }
-
-       err = a->print_aopt(a,f,tb[TCA_ACT_OPTIONS]);
-
+       err = a->print_aopt(a, f, tb[TCA_ACT_OPTIONS]);
 
        if (0 > err)
                return err;
 
-       if (show_stats && tb[TCA_STATS]) {
-               fprintf(f, "\t");
-               print_tcstats_attr(f, tb[TCA_STATS]);
+       if (show_stats && tb[TCA_ACT_STATS]) {
+               fprintf(f, "\tAction statistics:\n");
+               print_tcstats2_attr(f, tb[TCA_ACT_STATS], "\t", NULL);
                fprintf(f, "\n");
        }
 
        return 0;
 }
 
+static int
+tc_print_action_flush(FILE *f, const struct rtattr *arg)
+{
+
+       struct rtattr *tb[TCA_MAX + 1];
+       int err = 0;
+       struct action_util *a = NULL;
+       __u32 *delete_count = 0;
+
+       parse_rtattr_nested(tb, TCA_MAX, arg);
+
+       if (tb[TCA_KIND] == NULL) {
+               fprintf(stderr, "NULL Action!\n");
+               return -1;
+       }
+
+       a = get_action_kind(RTA_DATA(tb[TCA_KIND]));
+       if (NULL == a)
+               return err;
+
+       delete_count = RTA_DATA(tb[TCA_FCNT]);
+       fprintf(f," %s (%d entries)\n", a->id, *delete_count);
+       tab_flush = 0;
+       return 0;
+}
+
 int
-tc_print_action(FILE * f, const struct rtattr *arg)
+tc_print_action(FILE *f, const struct rtattr *arg)
 {
 
        int i;
@@ -280,17 +318,14 @@ tc_print_action(FILE * f, const struct rtattr *arg)
        if (arg == NULL)
                return 0;
 
-       memset(tb, 0, sizeof (tb));
-       parse_rtattr(tb, TCA_ACT_MAX_PRIO, RTA_DATA(arg), RTA_PAYLOAD(arg));
+       parse_rtattr_nested(tb, TCA_ACT_MAX_PRIO, arg);
 
-       if (tab_flush && NULL != tb[0]  && NULL == tb[1]) {
-               int ret = tc_print_one_action(f, tb[0]);
-               return ret;
-       }
+       if (tab_flush && NULL != tb[0]  && NULL == tb[1])
+               return tc_print_action_flush(f, tb[0]);
 
        for (i = 0; i < TCA_ACT_MAX_PRIO; i++) {
                if (tb[i]) {
-                       fprintf(f, "\n\taction order %d: ", i + batch_c);
+                       fprintf(f, "\n\taction order %d: ", i);
                        if (0 > tc_print_one_action(f, tb[i])) {
                                fprintf(f, "Error printing action\n");
                        }
@@ -298,11 +333,10 @@ tc_print_action(FILE * f, const struct rtattr *arg)
 
        }
 
-       batch_c+=TCA_ACT_MAX_PRIO ;
        return 0;
 }
 
-static int do_print_action(const struct sockaddr_nl *who,
+int print_action(const struct sockaddr_nl *who,
                           struct nlmsghdr *n,
                           void *arg)
 {
@@ -318,18 +352,17 @@ static int do_print_action(const struct sockaddr_nl *who,
                return -1;
        }
 
-       memset(tb, 0, sizeof(tb));
        parse_rtattr(tb, TCAA_MAX, TA_RTA(t), len);
 
        if (NULL == tb[TCA_ACT_TAB]) {
                if (n->nlmsg_type != RTM_GETACTION)
-                       fprintf(stderr, "do_print_action: NULL kind\n");
+                       fprintf(stderr, "print_action: NULL kind\n");
                return -1;
-       }     
+       }
 
        if (n->nlmsg_type == RTM_DELACTION) {
                if (n->nlmsg_flags & NLM_F_ROOT) {
-                       fprintf(fp, "Flushed table "); 
+                       fprintf(fp, "Flushed table ");
                        tab_flush = 1;
                } else {
                        fprintf(fp, "deleted action ");
@@ -343,7 +376,7 @@ static int do_print_action(const struct sockaddr_nl *who,
        return 0;
 }
 
-int tc_action_gd(int cmd, unsigned flags, int *argc_p, char ***argv_p)
+static int tc_action_gd(int cmd, unsigned flags, int *argc_p, char ***argv_p)
 {
        char k[16];
        struct action_util *a = NULL;
@@ -352,7 +385,6 @@ int tc_action_gd(int cmd, unsigned flags, int *argc_p, char ***argv_p)
        int prio = 0;
        int ret = 0;
        __u32 i;
-       struct rtnl_handle rth;
        struct sockaddr_nl nladdr;
        struct rtattr *tail;
        struct rtattr *tail2;
@@ -378,8 +410,7 @@ int tc_action_gd(int cmd, unsigned flags, int *argc_p, char ***argv_p)
        argv +=1;
 
 
-       tail = (struct rtattr*)(((void*)&req.n)+NLMSG_ALIGN(req.n.nlmsg_len));
-
+       tail = NLMSG_TAIL(&req.n);
        addattr_l(&req.n, MAX_MSG, TCA_ACT_TAB, NULL, 0);
 
        while (argc > 0) {
@@ -393,7 +424,7 @@ int tc_action_gd(int cmd, unsigned flags, int *argc_p, char ***argv_p)
 
                strncpy(k, *argv, sizeof (k) - 1);
                a = get_action_kind(k);
-               if (NULL == a) { 
+               if (NULL == a) {
                        fprintf(stderr, "Error: non existent action: %s\n",k);
                        ret = -1;
                        goto bad_val;
@@ -427,52 +458,42 @@ int tc_action_gd(int cmd, unsigned flags, int *argc_p, char ***argv_p)
                        goto bad_val;
                }
 
-       tail2 =
-          (struct rtattr *) (((void *) &req.n) + NLMSG_ALIGN(req.n.nlmsg_len));
-       addattr_l(&req.n, MAX_MSG, ++prio, NULL, 0);
-       addattr_l(&req.n, MAX_MSG, TCA_ACT_KIND, k, strlen(k) + 1);
-       addattr32(&req.n, MAX_MSG, TCA_ACT_INDEX, i);
-       tail2->rta_len =
-           (((void *) &req.n) + NLMSG_ALIGN(req.n.nlmsg_len)) - (void *) tail2;
+               tail2 = NLMSG_TAIL(&req.n);
+               addattr_l(&req.n, MAX_MSG, ++prio, NULL, 0);
+               addattr_l(&req.n, MAX_MSG, TCA_ACT_KIND, k, strlen(k) + 1);
+               addattr32(&req.n, MAX_MSG, TCA_ACT_INDEX, i);
+               tail2->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail2;
 
        }
 
-       tail->rta_len = (((void*)&req.n)+ NLMSG_ALIGN(req.n.nlmsg_len)) - (void*)tail;
-
-       if (rtnl_open(&rth, 0) < 0) {
-               fprintf(stderr, "Cannot open rtnetlink\n");
-               exit(1);
-       }
+       tail->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail;
 
        req.n.nlmsg_seq = rth.dump = ++rth.seq;
        if (cmd == RTM_GETACTION)
                ans = &req.n;
-       if (rtnl_talk(&rth, &req.n, 0, 0, ans, NULL, NULL) < 0) {
+
+       if (rtnl_talk(&rth, &req.n, ans, MAX_MSG) < 0) {
                fprintf(stderr, "We have an error talking to the kernel\n");
-               rtnl_close(&rth);
-               exit (1);
+               return 1;
        }
 
-       if (ans && do_print_action(NULL, &req.n, (void*)stdout) < 0) {
+       if (ans && print_action(NULL, &req.n, (void*)stdout) < 0) {
                fprintf(stderr, "Dump terminated\n");
-               rtnl_close(&rth);
-               exit(1);
+               return 1;
        }
 
        *argc_p = argc;
        *argv_p = argv;
-       rtnl_close(&rth);
 bad_val:
        return ret;
 }
 
-int tc_action_modify(int cmd, unsigned flags, int *argc_p, char ***argv_p)
+static int tc_action_modify(int cmd, unsigned flags, int *argc_p, char ***argv_p)
 {
        int argc = *argc_p;
        char **argv = *argv_p;
        int ret = 0;
 
-       struct rtnl_handle rth;
        struct rtattr *tail;
        struct {
                struct nlmsghdr         n;
@@ -487,37 +508,30 @@ int tc_action_modify(int cmd, unsigned flags, int *argc_p, char ***argv_p)
        req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg));
        req.n.nlmsg_flags = NLM_F_REQUEST|flags;
        req.n.nlmsg_type = cmd;
-       tail = (struct rtattr*)(((void*)&req.n)+NLMSG_ALIGN(req.n.nlmsg_len));
+       tail = NLMSG_TAIL(&req.n);
        argc -=1;
        argv +=1;
        if (parse_action(&argc, &argv, TCA_ACT_TAB, &req.n)) {
                fprintf(stderr, "Illegal \"action\"\n");
                return -1;
        }
-       tail->rta_len = (((void*)&req.n)+req.n.nlmsg_len) - (void*)tail;
-
-       if (rtnl_open(&rth, 0) < 0) {
-               fprintf(stderr, "Cannot open rtnetlink\n");
-               exit(1);
-       }
+       tail->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail;
 
-
-       if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) {
+       if (rtnl_talk(&rth, &req.n, NULL, 0) < 0) {
                fprintf(stderr, "We have an error talking to the kernel\n");
                ret = -1;
        }
 
        *argc_p = argc;
        *argv_p = argv;
-       rtnl_close(&rth);
+
        return ret;
 }
 
-int tc_act_list_or_flush(int argc, char **argv, int event)
+static int tc_act_list_or_flush(int argc, char **argv, int event)
 {
        int ret = 0, prio = 0, msg_size = 0;
        char k[16];
-       struct rtnl_handle rth;
        struct rtattr *tail,*tail2;
        struct action_util *a = NULL;
        struct {
@@ -532,11 +546,9 @@ int tc_act_list_or_flush(int argc, char **argv, int event)
 
        req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg));
 
-       tail = (struct rtattr*)(((void*)&req.n)+NLMSG_ALIGN(req.n.nlmsg_len));
-
+       tail = NLMSG_TAIL(&req.n);
        addattr_l(&req.n, MAX_MSG, TCA_ACT_TAB, NULL, 0);
-       tail2 =
-          (struct rtattr *) (((void *) &req.n) + NLMSG_ALIGN(req.n.nlmsg_len));
+       tail2 = NLMSG_TAIL(&req.n);
 
        strncpy(k, *argv, sizeof (k) - 1);
 #ifdef CONFIG_GACT
@@ -545,7 +557,7 @@ int tc_act_list_or_flush(int argc, char **argv, int event)
        }
 #endif
        a = get_action_kind(k);
-       if (NULL == a) { 
+       if (NULL == a) {
                fprintf(stderr,"bad action %s\n",k);
                goto bad_val;
        }
@@ -557,42 +569,33 @@ int tc_act_list_or_flush(int argc, char **argv, int event)
 
        addattr_l(&req.n, MAX_MSG, ++prio, NULL, 0);
        addattr_l(&req.n, MAX_MSG, TCA_ACT_KIND, k, strlen(k) + 1);
-       tail2->rta_len =
-           (((void *) &req.n) + NLMSG_ALIGN(req.n.nlmsg_len)) - (void *) tail2;
-       tail->rta_len = (((void*)&req.n)+NLMSG_ALIGN(req.n.nlmsg_len)) - (void*)tail;
-
-
-       if (rtnl_open(&rth, 0) < 0) {
-               fprintf(stderr, "Cannot open rtnetlink\n");
-               exit(1);
-       }
+       tail2->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail2;
+       tail->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail;
 
        msg_size = NLMSG_ALIGN(req.n.nlmsg_len) - NLMSG_ALIGN(sizeof(struct nlmsghdr));
 
-       if (event == RTM_GETACTION) { 
+       if (event == RTM_GETACTION) {
                if (rtnl_dump_request(&rth, event, (void *)&req.t, msg_size) < 0) {
                        perror("Cannot send dump request");
-                       exit(1);
+                       return 1;
                }
-               ret = rtnl_dump_filter(&rth, do_print_action, stdout, NULL, NULL);
+               ret = rtnl_dump_filter(&rth, print_action, stdout);
        }
 
-       if (event == RTM_DELACTION) { 
+       if (event == RTM_DELACTION) {
                req.n.nlmsg_len = NLMSG_ALIGN(req.n.nlmsg_len);
                req.n.nlmsg_type = RTM_DELACTION;
                req.n.nlmsg_flags |= NLM_F_ROOT;
                req.n.nlmsg_flags |= NLM_F_REQUEST;
-               if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) {
+               if (rtnl_talk(&rth, &req.n, NULL, 0) < 0) {
                        fprintf(stderr, "We have an error flushing\n");
-                       rtnl_close(&rth);
-                       exit (1);
+                       return 1;
                }
 
        }
 
 bad_val:
 
-       rtnl_close(&rth);
        return ret;
 }
 
@@ -638,7 +641,7 @@ int do_action(int argc, char **argv)
                }
 
                if (ret < 0) {
-                       fprintf(stderr, "Command \"%s\" is unknown, try \"tc action help\".\n", *argv);
+                       fprintf(stderr, "Command \"%s\" is unknown, try \"tc actions help\".\n", *argv);
                        return -1;
                }
        }