]> git.ipfire.org Git - thirdparty/libnl.git/commitdiff
nl-cls-* tools
authorThomas Graf <tgraf@suug.ch>
Tue, 26 Oct 2010 20:30:02 +0000 (22:30 +0200)
committerThomas Graf <tgraf@suug.ch>
Tue, 26 Oct 2010 20:30:02 +0000 (22:30 +0200)
cli based tools to add/update/list/delete classifiers

include/netlink/cli/cls.h [new file with mode: 0644]
lib/Makefile.am
lib/cli/cls/basic.c [new file with mode: 0644]
lib/route/cls/basic.c
src/.gitignore
src/Makefile.am
src/lib/Makefile.am
src/lib/cls.c [new file with mode: 0644]
src/nl-cls-add.c
src/nl-cls-delete.c
src/nl-cls-list.c

diff --git a/include/netlink/cli/cls.h b/include/netlink/cli/cls.h
new file mode 100644 (file)
index 0000000..85e5ffe
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * netlink/cli/cls.h           CLI Classifier Helpers
+ *
+ *     This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU Lesser General Public
+ *     License as published by the Free Software Foundation version 2.1
+ *     of the License.
+ *
+ * Copyright (c) 2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef __NETLINK_CLI_CLS_H_
+#define __NETLINK_CLI_CLS_H_
+
+#include <netlink/route/classifier.h>
+#include <netlink/route/classifier-modules.h>
+#include <netlink/cli/tc.h>
+
+struct nl_cli_cls_module
+{
+       const char *            cm_name;
+       struct rtnl_cls_ops *   cm_ops;
+       int                   (*cm_parse_argv)(struct rtnl_cls *, int, char **);
+       struct nl_list_head     cm_list;
+};
+
+extern struct rtnl_cls *       nl_cli_cls_alloc(void);
+extern struct nl_cache *       nl_cli_cls_alloc_cache(struct nl_sock *,
+                                                      int, uint32_t);
+extern void                    nl_cli_cls_parse_kind(struct rtnl_cls *, char *);
+extern void                    nl_cli_cls_parse_proto(struct rtnl_cls *, char *);
+
+extern struct nl_cli_cls_module *nl_cli_cls_lookup(struct rtnl_cls_ops *);
+extern void                    nl_cli_cls_register(struct nl_cli_cls_module *);
+extern void                    nl_cli_cls_unregister(struct nl_cli_cls_module *);
+
+
+#endif
index 386e02ce97b733adb4fe4f20a27582b3cca79bf0..52660ec38877c7e00cba6d69b262e4629a7434e1 100644 (file)
@@ -41,7 +41,7 @@ libnl_route_la_SOURCES = \
        route/qdisc_api.c route/qdisc_obj.c route/route.c route/route_obj.c \
        route/route_utils.c route/rtnl.c route/rule.c route/tc.c route/classid.c \
        \
-       route/cls/fw.c route/cls/police.c route/cls/u32.c \
+       route/cls/fw.c route/cls/police.c route/cls/u32.c route/cls/basic.c \
        \
        route/link/api.c route/link/vlan.c \
        \
@@ -59,10 +59,12 @@ nobase_pkglib_LTLIBRARIES = \
        cli/qdisc/htb.la \
        cli/qdisc/blackhole.la \
        cli/qdisc/pfifo.la \
-       cli/qdisc/bfifo.la
+       cli/qdisc/bfifo.la \
+       cli/cls/basic.la
 
 cli_qdisc_htb_la_LDFLAGS = -module -version-info 0:0:0
 cli_qdisc_blackhole_la_LDFLAGS = -module -version-info 0:0:0
 cli_qdisc_pfifo_la_LDFLAGS = -module -version-info 0:0:0
 cli_qdisc_bfifo_la_LDFLAGS = -module -version-info 0:0:0
+cli_cls_basic_la_LDFLAGS = -module -version-info 0:0:0
 endif
diff --git a/lib/cli/cls/basic.c b/lib/cli/cls/basic.c
new file mode 100644 (file)
index 0000000..fbe2173
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * lib/cli/cls/basic.c         basic classifier module for CLI lib
+ *
+ *     This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU Lesser General Public
+ *     License as published by the Free Software Foundation version 2.1
+ *     of the License.
+ *
+ * Copyright (c) 2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/cls.h>
+#include <netlink/route/cls/basic.h>
+
+static void print_usage(void)
+{
+       printf(
+"Usage: nl-cls-add [...] basic [OPTIONS]...\n"
+"\n"
+"OPTIONS\n"
+" -h, --help                Show this help text.\n"
+" -t, --target=ID           Target class to send matching packets to\n"
+"\n"
+"EXAMPLE"
+"    # Create a \"catch-all\" classifier, attached to \"q_root\", classyfing\n"
+"    # all not yet classified packets to class \"c_default\"\n"
+"    nl-cls-add --dev=eth0 --parent=q_root basic --target=c_default\n");
+}
+
+static int parse_argv(struct rtnl_cls *cls, int argc, char **argv)
+{
+       uint32_t target;
+       int err;
+
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_TARGET = 257,
+                       ARG_DEFAULT = 258,
+               };
+               static struct option long_opts[] = {
+                       { "help", 0, 0, 'h' },
+                       { "target", 1, 0, 't' },
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "ht:", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'h':
+                       print_usage();
+                       exit(0);
+
+               case 't':
+                       if ((err = rtnl_tc_str2handle(optarg, &target)) < 0)
+                               nl_cli_fatal(err, "Unable to parse target \"%s\":",
+                                       optarg, nl_geterror(err));
+
+                       rtnl_basic_set_classid(cls, target);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static struct nl_cli_cls_module basic_module =
+{
+       .cm_name                = "basic",
+       .cm_parse_argv          = parse_argv,
+};
+
+static void __init basic_init(void)
+{
+       nl_cli_cls_register(&basic_module);
+}
+
+static void __exit basic_exit(void)
+{
+       nl_cli_cls_unregister(&basic_module);
+}
index f15180723ec191bee9eff363bef947dce9259495..b4772d25e588368f67b06b2e2e642044aafbaeb3 100644 (file)
@@ -6,7 +6,7 @@
  *     License as published by the Free Software Foundation version 2.1
  *     of the License.
  *
- * Copyright (c) 2008-2009 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2008-2010 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
 #include <netlink/route/classifier.h>
 #include <netlink/route/classifier-modules.h>
 #include <netlink/route/cls/basic.h>
-#include <netlink/route/cls/ematch.h>
 
 struct rtnl_basic
 {
        uint32_t                        b_classid;
-       struct rtnl_ematch_tree *       b_ematch;
        int                             b_mask;
 };
 
@@ -42,7 +40,7 @@ struct rtnl_basic
 #define BASIC_ATTR_EMATCH      0x002
 /** @endcond */
 
-static struct nla_policy basic_policy[TCA_FW_MAX+1] = {
+static struct nla_policy basic_policy[TCA_BASIC_MAX+1] = {
        [TCA_BASIC_CLASSID]     = { .type = NLA_U32 },
        [TCA_BASIC_EMATCHES]    = { .type = NLA_NESTED },
        [TCA_BASIC_ACT]         = { .type = NLA_NESTED },
@@ -56,9 +54,11 @@ static int basic_clone(struct rtnl_cls *_dst, struct rtnl_cls *_src)
 
 static void basic_free_data(struct rtnl_cls *cls)
 {
+#if 0
        struct rtnl_basic *basic = rtnl_cls_data(cls);
 
        rtnl_ematch_tree_free(basic->b_ematch);
+#endif
 }
 
 static int basic_msg_parser(struct rtnl_cls *cls)
@@ -77,12 +77,14 @@ static int basic_msg_parser(struct rtnl_cls *cls)
        }
 
        if (tb[TCA_BASIC_EMATCHES]) {
+#if 0
                if ((err = rtnl_ematch_parse(tb[TCA_BASIC_EMATCHES],
                                             &basic->b_ematch)) < 0)
                        return err;
 
                if (basic->b_ematch)
                        basic->b_mask |= BASIC_ATTR_EMATCH;
+#endif
        }
 
        if (tb[TCA_BASIC_ACT]) {
@@ -101,18 +103,21 @@ static void basic_dump_line(struct rtnl_cls *cls, struct nl_dump_params *p)
        struct rtnl_basic *b = rtnl_cls_data(cls);
        char buf[32];
 
+#if 0
        if (b->b_mask & BASIC_ATTR_EMATCH)
                nl_dump(p, " ematch");
        else
                nl_dump(p, " match-all");
+#endif
 
        if (b->b_mask & BASIC_ATTR_CLASSID)
-               nl_dump(p, " classify-to %s",
+               nl_dump(p, " target %s",
                        rtnl_tc_handle2str(b->b_classid, buf, sizeof(buf)));
 }
 
 static void basic_dump_details(struct rtnl_cls *cls, struct nl_dump_params *p)
 {
+#if 0
        struct rtnl_basic *b = rtnl_cls_data(cls);
 
        if (b->b_mask & BASIC_ATTR_EMATCH) {
@@ -120,6 +125,7 @@ static void basic_dump_details(struct rtnl_cls *cls, struct nl_dump_params *p)
                nl_dump_line(p, "    ematch ");
                rtnl_ematch_tree_dump(b->b_ematch, p);
        } else
+#endif
                nl_dump(p, "no options.\n");
 }
 
@@ -160,6 +166,7 @@ uint32_t rtnl_basic_get_classid(struct rtnl_cls *cls)
        return b->b_classid;
 }
 
+#if 0
 int rtnl_basic_set_ematch(struct rtnl_cls *cls, struct rtnl_ematch_tree *tree)
 {
        struct rtnl_basic *b = rtnl_cls_data(cls);
@@ -182,6 +189,7 @@ struct rtnl_ematch_tree *rtnl_basic_get_ematch(struct rtnl_cls *cls)
        struct rtnl_basic *b = rtnl_cls_data(cls);
        return b->b_ematch;
 }
+#endif
 
 /** @} */
 
index a815b6fe5f477950704575fa8097e05cd11e4ea0..e7f47649311ab0095e72a4cb0a0242fafa6a0938 100644 (file)
@@ -24,6 +24,9 @@ nl-qdisc-list
 nl-class-add
 nl-class-delete
 nl-class-list
+nl-cls-add
+nl-cls-delete
+nl-cls-list
 nl-route-add
 nl-route-delete
 nl-route-list
index 1dc9cebd0600fbff153fd998bc2e4940619096c5..6ea3fee8d2eace62c6bb10289cd5fb0ef8ca2b5b 100644 (file)
@@ -8,6 +8,7 @@ AM_LDFLAGS = -L${top_builddir}/lib -L${top_builddir}/src/lib -lnl-cli
 sbin_PROGRAMS = \
        nl-qdisc-add nl-qdisc-list nl-qdisc-delete \
        nl-class-add nl-class-list nl-class-delete \
+       nl-cls-add nl-cls-list nl-cls-delete \
        nl-classid-lookup
 
 noinst_PROGRAMS = \
@@ -84,6 +85,13 @@ nl_class_delete_LDADD = -lnl-route
 nl_class_list_SOURCES = nl-class-list.c
 nl_class_list_LDADD = -lnl-route
 
+nl_cls_add_SOURCES = nl-cls-add.c
+nl_cls_add_LDADD = -lnl-route
+nl_cls_list_SOURCES = nl-cls-list.c
+nl_cls_list_LDADD = -lnl-route
+nl_cls_delete_SOURCES = nl-cls-delete.c
+nl_cls_delete_LDADD = -lnl-route
+
 nl_route_add_SOURCES = nl-route-add.c
 nl_route_add_LDADD = -lnl-route
 nl_route_delete_SOURCES = nl-route-delete.c
index e806633ea0152ed101109e1c5bd87c9a46070f65..3236dbe037f0288b4ac24d4debd3ed1958f61214 100644 (file)
@@ -34,6 +34,7 @@ libnl_cli_la_LIBADD  = ${top_builddir}/lib/libnl.la \
                       ${top_builddir}/lib/libnl-genl.la
 
 libnl_cli_la_SOURCES = \
-       utils.c addr.c ct.c link.c neigh.c tc.c qdisc.c class.c rule.c route.c
+       utils.c addr.c ct.c link.c neigh.c rule.c route.c \
+       tc.c qdisc.c class.c cls.c
 #      cls/ematch_syntax.c cls/ematch_grammar.c cls/ematch.c
 #      cls/pktloc_syntax.c cls/pktloc_grammar.c cls/utils.c
diff --git a/src/lib/cls.c b/src/lib/cls.c
new file mode 100644 (file)
index 0000000..95997f5
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * src/lib/cls.c       CLI Classifier Helpers
+ *
+ *     This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU Lesser General Public
+ *     License as published by the Free Software Foundation version 2.1
+ *     of the License.
+ *
+ * Copyright (c) 2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup cli
+ * @defgroup cli_cls Classifiers
+ * @{
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/cls.h>
+
+struct rtnl_cls *nl_cli_cls_alloc(void)
+{
+       struct rtnl_cls *cls;
+
+       cls = rtnl_cls_alloc();
+       if (!cls)
+               nl_cli_fatal(ENOMEM, "Unable to allocate classifier object");
+
+       return cls;
+}
+
+struct nl_cache *nl_cli_cls_alloc_cache(struct nl_sock *sock, int ifindex,
+                                       uint32_t parent)
+{
+       struct nl_cache *cache;
+       int err;
+
+       if ((err = rtnl_cls_alloc_cache(sock, ifindex, parent, &cache)) < 0)
+               nl_cli_fatal(err, "Unable to allocate classifier cache: %s",
+                            nl_geterror(err));
+
+       return cache;
+}
+
+void nl_cli_cls_parse_kind(struct rtnl_cls *cls, char *arg)
+{
+       rtnl_cls_set_kind(cls, arg);
+}
+
+void nl_cli_cls_parse_proto(struct rtnl_cls *cls, char *arg)
+{
+       int proto;
+
+       if ((proto = nl_str2ether_proto(arg)) < 0)
+               nl_cli_fatal(proto, "Unknown protocol \"%s\".", arg);
+
+       rtnl_cls_set_protocol(cls, proto);
+}
+
+static NL_LIST_HEAD(cls_modules);
+
+struct nl_cli_cls_module *__nl_cli_cls_lookup(struct rtnl_cls_ops *ops)
+{
+       struct nl_cli_cls_module *cm;
+
+       nl_list_for_each_entry(cm, &cls_modules, cm_list)
+               if (cm->cm_ops == ops)
+                       return cm;
+
+       return NULL;
+}
+
+struct nl_cli_cls_module *nl_cli_cls_lookup(struct rtnl_cls_ops *ops)
+{
+       struct nl_cli_cls_module *cm;
+
+       if ((cm = __nl_cli_cls_lookup(ops)))
+               return cm;
+
+       nl_cli_load_module("cli/cls", ops->co_kind);
+
+       if (!(cm = __nl_cli_cls_lookup(ops)))  {
+               nl_cli_fatal(EINVAL, "Application bug: The shared library for "
+                       "the classifier \"%s\" was successfully loaded but it "
+                       "seems that module did not register itself");
+       }
+
+       return cm;
+}
+
+void nl_cli_cls_register(struct nl_cli_cls_module *cm)
+{
+       struct rtnl_cls_ops *ops;
+
+       if (!(ops = __rtnl_cls_lookup_ops(cm->cm_name))) {
+               nl_cli_fatal(ENOENT, "Unable to register CLI classifier module "
+               "\"%s\": No matching libnl cls module found.", cm->cm_name);
+       }
+
+       if (__nl_cli_cls_lookup(ops)) {
+               nl_cli_fatal(EEXIST, "Unable to register CLI classifier module "
+               "\"%s\": Module already registered.", cm->cm_name);
+       }
+
+       cm->cm_ops = ops;
+
+       nl_list_add_tail(&cm->cm_list, &cls_modules);
+}
+
+void nl_cli_cls_unregister(struct nl_cli_cls_module *cm)
+{
+       nl_list_del(&cm->cm_list);
+}
+
+/** @} */
index 997f02f82ad5ae8b40e10fc36260955f562a1161..5e2c2dc55fd5aac92d1da10f408c9605ef5f26c2 100644 (file)
@@ -5,29 +5,43 @@
  *     modify it under the terms of the GNU General Public License as
  *     published by the Free Software Foundation version 2 of the License.
  *
- * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2010 Thomas Graf <tgraf@suug.ch>
  */
 
-#include "cls/utils.h"
+#include <netlink/cli/utils.h>
+#include <netlink/cli/tc.h>
+#include <netlink/cli/cls.h>
+#include <netlink/cli/link.h>
 
 static int quiet = 0;
 
 static void print_usage(void)
 {
        printf(
-"Usage: nl-cls-add [OPTION]... [CLASSIFIER] TYPE [TYPE OPTIONS]...\n"
+"Usage: nl-cls-add [OPTIONS]... classifier [CONFIGURATION]...\n"
 "\n"
-"Options\n"
+"OPTIONS\n"
 " -q, --quiet               Do not print informal notifications.\n"
-" -h, --help                Show this help.\n"
+" -h, --help                Show this help text.\n"
 " -v, --version             Show versioning information.\n"
+"     --update              Update classifier if it exists.\n"
+"     --update-only         Only update classifier, never create it.\n"
+" -d, --dev=DEV             Network device the classifier should be attached to.\n"
+" -i, --id=ID               ID of new classifier (default: auto-generated)\n"
+" -p, --parent=ID           ID of parent { root | ingress | class-ID }\n"
+"     --protocol=PROTO      Protocol to match (default: all)\n"
+"     --prio=PRIO           Priority (default: 0)\n"
+"     --mtu=SIZE            Overwrite MTU (default: MTU of network device)\n"
+"     --mpu=SIZE            Minimum packet size on the link (default: 0).\n"
+"     --overhead=SIZE       Overhead in bytes per packet (default: 0).\n"
+"     --linktype=TYPE       Overwrite linktype (default: type of network device)\n"
+"\n"
+"CONFIGURATION\n"
+" -h, --help                Show help text of classifier specific options.\n"
+"\n"
+"EXAMPLE\n"
+"   $ nl-cls-add --dev=eth1 --parent=q_root basic --target c_www\n"
 "\n"
-"Classifier Options\n"
-" -d, --dev=DEV             Device the classifier should be assigned to.\n"
-" -p, --parent=HANDLE       Parent QDisc\n"
-"     --proto=PROTO         Protocol (default=IPv4)\n"
-"     --prio=NUM            Priority (0..256)\n"
-"     --id=HANDLE           Unique identifier\n"
        );
        exit(0);
 }
@@ -36,27 +50,36 @@ int main(int argc, char *argv[])
 {
        struct nl_sock *sock;
        struct rtnl_cls *cls;
+       struct rtnl_tc *tc;
        struct nl_cache *link_cache;
-       struct rtnl_cls_ops *ops;
-       struct cls_module *mod;
        struct nl_dump_params dp = {
                .dp_type = NL_DUMP_DETAILS,
                .dp_fd = stdout,
        };
+       struct nl_cli_cls_module *cm;
+       struct rtnl_cls_ops *ops;
+       int err, flags = NLM_F_CREATE | NLM_F_EXCL;
        char *kind;
-       int err, nlflags = NLM_F_CREATE;
  
-       sock = nlt_alloc_socket();
-       nlt_connect(sock, NETLINK_ROUTE);
-       link_cache = nlt_alloc_link_cache(sock);
-       cls = nlt_alloc_cls();
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+
+       link_cache = nl_cli_link_alloc_cache(sock);
 
+       cls = nl_cli_cls_alloc();
+       tc = (struct rtnl_tc *) cls;
        for (;;) {
                int c, optidx = 0;
                enum {
-                       ARG_PROTO = 257,
-                       ARG_PRIO = 258,
-                       ARG_ID,
+                       ARG_UPDATE = 257,
+                       ARG_UPDATE_ONLY = 258,
+                       ARG_MTU,
+                       ARG_MPU,
+                       ARG_OVERHEAD,
+                       ARG_LINKTYPE,
+                       ARG_PROTO,
+                       ARG_PRIO,
                };
                static struct option long_opts[] = {
                        { "quiet", 0, 0, 'q' },
@@ -64,54 +87,71 @@ int main(int argc, char *argv[])
                        { "version", 0, 0, 'v' },
                        { "dev", 1, 0, 'd' },
                        { "parent", 1, 0, 'p' },
+                       { "id", 1, 0, 'i' },
                        { "proto", 1, 0, ARG_PROTO },
                        { "prio", 1, 0, ARG_PRIO },
-                       { "id", 1, 0, ARG_ID },
+                       { "update", 0, 0, ARG_UPDATE },
+                       { "update-only", 0, 0, ARG_UPDATE_ONLY },
+                       { "mtu", 1, 0, ARG_MTU },
+                       { "mpu", 1, 0, ARG_MPU },
+                       { "overhead", 1, 0, ARG_OVERHEAD },
+                       { "linktype", 1, 0, ARG_LINKTYPE },
                        { 0, 0, 0, 0 }
                };
        
-               c = getopt_long(argc, argv, "+qhva:d:", long_opts, &optidx);
+               c = getopt_long(argc, argv, "+qhvd:p:i:",
+                               long_opts, &optidx);
                if (c == -1)
                        break;
 
                switch (c) {
-               case '?': exit(NLE_INVAL);
                case 'q': quiet = 1; break;
                case 'h': print_usage(); break;
-               case 'v': nlt_print_version(); break;
-               case 'd': parse_dev(cls, link_cache, optarg); break;
-               case 'p': parse_parent(cls, optarg); break;
-               case ARG_PRIO: parse_prio(cls, optarg); break;
-               case ARG_ID: parse_handle(cls, optarg); break;
-               case ARG_PROTO: parse_proto(cls, optarg); break;
+               case 'v': nl_cli_print_version(); break;
+               case 'd': nl_cli_tc_parse_dev(tc, link_cache, optarg); break;
+               case 'p': nl_cli_tc_parse_parent(tc, optarg); break;
+               case 'i': nl_cli_tc_parse_handle(tc, optarg); break;
+               case ARG_UPDATE: flags = NLM_F_CREATE; break;
+               case ARG_UPDATE_ONLY: flags = 0; break;
+               case ARG_MTU: nl_cli_tc_parse_mtu(tc, optarg); break;
+               case ARG_MPU: nl_cli_tc_parse_mpu(tc, optarg); break;
+               case ARG_OVERHEAD: nl_cli_tc_parse_overhead(tc, optarg); break;
+               case ARG_LINKTYPE: nl_cli_tc_parse_linktype(tc, optarg); break;
+               case ARG_PROTO: nl_cli_cls_parse_proto(cls, optarg); break;
+               case ARG_PRIO:
+                       rtnl_cls_set_prio(cls, nl_cli_parse_u32(optarg));
+                       break;
                }
        }
 
-       if (optind >= argc) {
+       if (optind >= argc)
                print_usage();
-               fatal(EINVAL, "Missing classifier type");
-       }
+
+       if (!rtnl_tc_get_ifindex(tc))
+               nl_cli_fatal(EINVAL, "You must specify a network device (--dev=XXX)");
+
+       if (!rtnl_tc_get_parent(tc))
+               nl_cli_fatal(EINVAL, "You must specify a parent (--parent=XXX)");
 
        kind = argv[optind++];
-       if ((err = rtnl_cls_set_kind(cls, kind)) < 0)
-               fatal(ENOENT, "Unknown classifier type \"%s\".", kind);
-       
-       ops = rtnl_cls_get_ops(cls);
-       if (!(mod = lookup_cls_mod(ops)))
-               fatal(ENOTSUP, "Classifier type \"%s\" not supported.", kind);
+       rtnl_cls_set_kind(cls, kind);
 
-       mod->parse_argv(cls, argc, argv);
+       if (!(ops = rtnl_cls_lookup_ops(cls)))
+               nl_cli_fatal(ENOENT, "Unknown classifier \"%s\".", kind);
 
-       printf("Adding ");
-       nl_object_dump(OBJ_CAST(cls), &dp);
+       if (!(cm = nl_cli_cls_lookup(ops)))
+               nl_cli_fatal(ENOTSUP, "Classifier type \"%s\" not supported.", kind);
 
-       if ((err = rtnl_cls_add(sock, cls, nlflags)) < 0)
-               fatal(err, "Unable to add classifier: %s", nl_geterror(err));
+       if ((err = cm->cm_parse_argv(cls, argc, argv)) < 0)
+               nl_cli_fatal(err, "Unable to parse classifier options");
 
        if (!quiet) {
-               printf("Added ");
+               printf("Adding ");
                nl_object_dump(OBJ_CAST(cls), &dp);
        }
 
+       if ((err = rtnl_cls_add(sock, cls, flags)) < 0)
+               nl_cli_fatal(EINVAL, "Unable to add classifier: %s", nl_geterror(err));
+
        return 0;
 }
index cfdc17090682b29502e84504eeaba3c78d609c02..0ffffb2b44bef8e847f66c22df24bdfe8993306f 100644 (file)
@@ -6,52 +6,59 @@
  *     License as published by the Free Software Foundation version 2.1
  *     of the License.
  *
- * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2008-2010 Thomas Graf <tgraf@suug.ch>
  */
 
-#include "cls/utils.h"
+#include <netlink/cli/utils.h>
+#include <netlink/cli/cls.h>
+#include <netlink/cli/link.h>
 
-static int interactive = 0, default_yes = 0, quiet = 0;
-static int deleted = 0;
-static struct nl_sock *sock;
+static int quiet = 0, default_yes = 0, deleted = 0, interactive = 0;
+struct nl_sock *sock;
 
 static void print_usage(void)
 {
        printf(
-       "Usage: nl-cls-list [OPTION]... [CLASSIFIER]\n"
-       "\n"
-       "Options\n"
-       " -i, --interactive     Run interactively\n"
-       "     --yes             Set default answer to yes\n"
-       " -q, --quiet           Do not print informal notifications\n"
-       " -h, --help            Show this help\n"
-       " -v, --version         Show versioning information\n"
-       "\n"
-       "Classifier Options\n"
-       " -d, --dev=DEV         Device the classifier should be assigned to.\n"
-       " -p, --parent=HANDLE   Parent qdisc/class\n"
-       "     --proto=PROTO     Protocol\n"
-       "     --prio=NUM        Priority (0..256)\n"
-       "     --id=HANDLE       Unique identifier\n"
+"Usage: nl-cls-delete [OPTION]... [class]\n"
+"\n"
+"OPTIONS\n"
+"     --interactive         Run interactively.\n"
+"     --yes                 Set default answer to yes.\n"
+" -q, --quiet               Do not print informal notifications.\n"
+" -h, --help                Show this help text and exit.\n"
+" -v, --version             Show versioning information and exit.\n"
+"\n"
+" -d, --dev=DEV             Device the classifer is attached to.\n"
+" -p, --parent=ID           Identifier of parent qdisc/class.\n"
+" -i, --id=ID               Identifier\n"
+" -k, --kind=NAME           Kind of classifier (e.g. basic, u32, fw)\n"
+"     --protocol=PROTO      Protocol to match (default: all)\n"
+"     --prio=PRIO           Priority (default: 0)\n"
+"\n"
+"EXAMPLE\n"
+"    # Delete all classifiers on eth0 attached to parent q_root:\n"
+"    $ nl-cls-delete --dev eth0 --parent q_root:\n"
+"\n"
        );
+
        exit(0);
 }
 
 static void delete_cb(struct nl_object *obj, void *arg)
 {
-       struct rtnl_cls *cls = (struct rtnl_cls *) obj;
+       struct rtnl_cls *cls = nl_object_priv(obj);
        struct nl_dump_params params = {
                .dp_type = NL_DUMP_LINE,
                .dp_fd = stdout,
        };
        int err;
 
-       if (interactive && !nlt_confirm(obj, &params, default_yes))
+       if (interactive && !nl_cli_confirm(obj, &params, default_yes))
                return;
 
        if ((err = rtnl_cls_delete(sock, cls, 0)) < 0)
-               fatal(err, "Unable to delete classifier: %s",
-                     nl_geterror(err));
+               nl_cli_fatal(err, "Unable to delete classifier: %s\n",
+                               nl_geterror(err));
 
        if (!quiet) {
                printf("Deleted ");
@@ -61,73 +68,88 @@ static void delete_cb(struct nl_object *obj, void *arg)
        deleted++;
 }
 
-int main(int argc, char *argv[])
+static void __delete_link(int ifindex, struct rtnl_cls *filter)
 {
-       struct nl_cache *link_cache, *cls_cache;
-       struct rtnl_cls *cls;
-       int nf = 0, err;
+       struct nl_cache *cache;
+       uint32_t parent = rtnl_tc_get_parent((struct rtnl_tc *) filter);
+
+       cache = nl_cli_cls_alloc_cache(sock, ifindex, parent);
+       nl_cache_foreach_filter(cache, OBJ_CAST(filter), delete_cb, NULL);
+       nl_cache_free(cache);
+}
+
+static void delete_link(struct nl_object *obj, void *arg)
+{
+       struct rtnl_link *link = nl_object_priv(obj);
 
-       sock = nlt_alloc_socket();
-       nlt_connect(sock, NETLINK_ROUTE);
-       link_cache = nlt_alloc_link_cache(sock);
-       cls = nlt_alloc_cls();
+       __delete_link(rtnl_link_get_ifindex(link), arg);
+}
 
+int main(int argc, char *argv[])
+{
+       struct rtnl_cls *cls;
+       struct rtnl_tc *tc;
+       struct nl_cache *link_cache;
+       int ifindex;
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+       link_cache = nl_cli_link_alloc_cache(sock);
+       cls = nl_cli_cls_alloc();
+       tc = (struct rtnl_tc *) cls;
        for (;;) {
                int c, optidx = 0;
                enum {
-                       ARG_PRIO = 257,
-                       ARG_PROTO = 258,
-                       ARG_ID,
-                       ARG_YES,
+                       ARG_YES = 257,
+                       ARG_INTERACTIVE = 258,
+                       ARG_PROTO,
+                       ARG_PRIO,
                };
                static struct option long_opts[] = {
-                       { "interactive", 0, 0, 'i' },
+                       { "interactive", 0, 0, ARG_INTERACTIVE },
                        { "yes", 0, 0, ARG_YES },
                        { "quiet", 0, 0, 'q' },
                        { "help", 0, 0, 'h' },
                        { "version", 0, 0, 'v' },
                        { "dev", 1, 0, 'd' },
                        { "parent", 1, 0, 'p' },
+                       { "id", 1, 0, 'i' },
+                       { "kind", 1, 0, 'k' },
                        { "proto", 1, 0, ARG_PROTO },
                        { "prio", 1, 0, ARG_PRIO },
-                       { "id", 1, 0, ARG_ID },
                        { 0, 0, 0, 0 }
                };
        
-               c = getopt_long(argc, argv, "iqhvd:p:", long_opts, &optidx);
+               c = getopt_long(argc, argv, "qhvd:p:i:k:", long_opts, &optidx);
                if (c == -1)
                        break;
 
                switch (c) {
-               case 'i': interactive = 1; break;
+               case '?': nl_cli_fatal(EINVAL, "Invalid options");
+               case ARG_INTERACTIVE: interactive = 1; break;
                case ARG_YES: default_yes = 1; break;
                case 'q': quiet = 1; break;
                case 'h': print_usage(); break;
-               case 'v': nlt_print_version(); break;
-               case 'd': nf++; parse_dev(cls, link_cache, optarg); break;
-               case 'p': nf++; parse_parent(cls, optarg); break;
-               case ARG_PRIO: nf++; parse_prio(cls, optarg); break;
-               case ARG_ID: nf++; parse_handle(cls, optarg); break;
-               case ARG_PROTO: nf++; parse_proto(cls, optarg); break;
+               case 'v': nl_cli_print_version(); break;
+               case 'd': nl_cli_tc_parse_dev(tc, link_cache, optarg); break;
+               case 'p': nl_cli_tc_parse_parent(tc, optarg); break;
+               case 'i': nl_cli_tc_parse_handle(tc, optarg); break;
+               case 'k': nl_cli_cls_parse_kind(cls, optarg); break;
+               case ARG_PROTO: nl_cli_cls_parse_proto(cls, optarg); break;
+               case ARG_PRIO:
+                       rtnl_cls_set_prio(cls, nl_cli_parse_u32(optarg));
+                       break;
                }
-       }
-
-       if (nf == 0 && !interactive && !default_yes) {
-               fprintf(stderr, "You attempted to delete all classifiers in "
-                       "non-interactive mode, aborting.\n");
-               exit(0);
-       }
-
-       err = rtnl_cls_alloc_cache(sock, rtnl_cls_get_ifindex(cls),
-                                  rtnl_cls_get_parent(cls), &cls_cache);
-       if (err < 0)
-               fatal(err, "Unable to allocate classifier cache: %s",
-                     nl_geterror(err));
+       }
 
-       nl_cache_foreach_filter(cls_cache, OBJ_CAST(cls), delete_cb, NULL);
+       if ((ifindex = rtnl_tc_get_ifindex(tc)))
+               __delete_link(ifindex, cls);
+        else
+               nl_cache_foreach(link_cache, delete_link, cls);
 
        if (!quiet)
-               printf("Deleted %d classifiers\n", deleted);
+               printf("Deleted %d classs\n", deleted);
 
        return 0;
 }
index 9121d5238455a721bc0f9ebd17099506eaf134c1..a0220f819558a92517f32ef33299d1c815bb1035 100644 (file)
  *     License as published by the Free Software Foundation version 2.1
  *     of the License.
  *
- * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2008-2010 Thomas Graf <tgraf@suug.ch>
  */
 
-#include "cls/utils.h"
+#include <netlink/cli/utils.h>
+#include <netlink/cli/tc.h>
+#include <netlink/cli/cls.h>
+#include <netlink/cli/link.h>
 
-static struct nl_sock *sock;
-static struct rtnl_cls *cls;
-static struct nl_dump_params params = {
+struct nl_sock *sock;
+
+struct nl_dump_params params = {
        .dp_type = NL_DUMP_LINE,
 };
 
 static void print_usage(void)
 {
        printf(
-       "Usage: nl-cls-list [OPTION]... [CLASSIFIER]\n"
-       "\n"
-       "Options\n"
-       " -f, --format=TYPE     Output format { brief | details | stats }\n"
-       " -h, --help            Show this help text.\n"
-       " -v, --version         Show versioning information.\n"
-       "\n"
-       "Classifier Options\n"
-       " -d, --dev=DEV         Device the classifier should be assigned to.\n"
-       " -p, --parent=HANDLE   Parent qdisc/class\n"
-       "     --proto=PROTO     Protocol\n"
-       "     --prio=NUM        Priority\n"
-       "     --id=NUM          Identifier\n"
+"Usage: nl-cls-list [OPTION]...\n"
+"\n"
+"OPTIONS\n"
+"     --details             Show details\n"
+"     --stats               Show statistics\n"
+" -h, --help                Show this help\n"
+" -v, --version             Show versioning information\n"
+"\n"
+" -d, --dev=DEV             Device the classifier is attached to. (default: all)\n"
+" -p, --parent=ID           Identifier of parent class.\n"
+" -i, --id=ID               Identifier.\n"
+" -k, --kind=NAME           Kind of classifier (e.g. basic, u32, fw)\n"
+"     --protocol=PROTO      Protocol to match (default: all)\n"
+"     --prio=PRIO           Priority (default: 0)\n"
+"\n"
+"EXAMPLE\n"
+"    # Display statistics of all classes on eth0\n"
+"    $ nl-cls-list --stats --dev=eth0\n"
+"\n"
        );
        exit(0);
 }
 
-static void print_cls(struct nl_object *obj, void *arg)
+static void __dump_link(int ifindex, struct rtnl_cls *filter)
 {
-       struct nl_cache *cls_cache;
-       int err, ifindex;
+       struct nl_cache *cache;
+       uint32_t parent = rtnl_tc_get_parent((struct rtnl_tc *) filter);
 
-       if (obj)
-               ifindex = rtnl_link_get_ifindex((struct rtnl_link *) obj);
-       else
-               ifindex = rtnl_cls_get_ifindex(cls);
+       cache = nl_cli_cls_alloc_cache(sock, ifindex, parent);
+       nl_cache_dump_filter(cache, &params, OBJ_CAST(filter));
+       nl_cache_free(cache);
+}
 
-       err = rtnl_cls_alloc_cache(sock, ifindex, rtnl_cls_get_parent(cls),
-                                  &cls_cache);
-       if (err < 0)
-               fatal(err, "Unable to allocate classifier cache: %s",
-                     nl_geterror(err));
+static void dump_link(struct nl_object *obj, void *arg)
+{
+       struct rtnl_link *link = nl_object_priv(obj);
 
-       nl_cache_dump_filter(cls_cache, &params, OBJ_CAST(cls));
-       nl_cache_free(cls_cache);
+       __dump_link(rtnl_link_get_ifindex(link), arg);
 }
 
 int main(int argc, char *argv[])
 {
+       struct rtnl_cls *cls;
+       struct rtnl_tc *tc;
        struct nl_cache *link_cache;
-       int dev = 0;
+       int ifindex;
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+       link_cache = nl_cli_link_alloc_cache(sock);
+       cls = nl_cli_cls_alloc();
+       tc = (struct rtnl_tc *) cls;
 
        params.dp_fd = stdout;
-       sock = nlt_alloc_socket();
-       nlt_connect(sock, NETLINK_ROUTE);
-       link_cache = nlt_alloc_link_cache(sock);
-       cls = nlt_alloc_cls();
-
        for (;;) {
                int c, optidx = 0;
                enum {
-                       ARG_PROTO = 257,
-                       ARG_PRIO = 258,
-                       ARG_ID,
+                       ARG_DETAILS = 257,
+                       ARG_STATS = 258,
+                       ARG_PROTO,
+                       ARG_PRIO,
                };
                static struct option long_opts[] = {
-                       { "format", 1, 0, 'f' },
+                       { "details", 0, 0, ARG_DETAILS },
+                       { "stats", 0, 0, ARG_STATS },
                        { "help", 0, 0, 'h' },
                        { "version", 0, 0, 'v' },
                        { "dev", 1, 0, 'd' },
                        { "parent", 1, 0, 'p' },
+                       { "id", 1, 0, 'i' },
+                       { "kind", 1, 0, 'k' },
                        { "proto", 1, 0, ARG_PROTO },
                        { "prio", 1, 0, ARG_PRIO },
-                       { "id", 1, 0, ARG_ID },
                        { 0, 0, 0, 0 }
                };
        
-               c = getopt_long(argc, argv, "+f:qhva:d:", long_opts, &optidx);
+               c = getopt_long(argc, argv, "hvd:p:i:k:", long_opts, &optidx);
                if (c == -1)
                        break;
 
                switch (c) {
-               case '?': exit(NLE_INVAL);
-               case 'f': params.dp_type = nlt_parse_dumptype(optarg); break;
+               case ARG_DETAILS: params.dp_type = NL_DUMP_DETAILS; break;
+               case ARG_STATS: params.dp_type = NL_DUMP_STATS; break;
                case 'h': print_usage(); break;
-               case 'v': nlt_print_version(); break;
-               case 'd': dev = 1; parse_dev(cls, link_cache, optarg); break;
-               case 'p': parse_parent(cls, optarg); break;
-               case ARG_PRIO: parse_prio(cls, optarg); break;
-               case ARG_ID: parse_handle(cls, optarg); break;
-               case ARG_PROTO: parse_proto(cls, optarg); break;
+               case 'v': nl_cli_print_version(); break;
+               case 'd': nl_cli_tc_parse_dev(tc, link_cache, optarg); break;
+               case 'p': nl_cli_tc_parse_parent(tc, optarg); break;
+               case 'i': nl_cli_tc_parse_handle(tc, optarg); break;
+               case 'k': nl_cli_cls_parse_kind(cls, optarg); break;
+               case ARG_PROTO: nl_cli_cls_parse_proto(cls, optarg); break;
+               case ARG_PRIO:
+                       rtnl_cls_set_prio(cls, nl_cli_parse_u32(optarg));
+                       break;
                }
        }
 
-       if (!dev)
-               nl_cache_foreach(link_cache, print_cls, NULL);
-       else
-               print_cls(NULL, NULL);
+       if ((ifindex = rtnl_tc_get_ifindex(tc)))
+               __dump_link(ifindex, cls);
+        else
+               nl_cache_foreach(link_cache, dump_link, cls);
 
        return 0;
 }