This patch adds the possibility to use textual names to set the chain priority
to standard values so that numeric values do not need to be learnt any more for
basic usage.

Basic arithmetic can also be done with them to ease the addition of
relatively higher/lower priority chains.
Addition and substraction is possible.

Values are also printed with their friendly name within the range of
<basicprio> +- 10.

Also numeric printing is supported in case of -nnn option
(numeric == NFT_NUMERIC_ALL)

Not all names apply to every family. The supported names are based on
the tables they have in their x_tableas implementation.
These are the following:
        ip,ip6,inet
                filter
                nat (dstnat, srcnat)
                mangle
                raw
                security
        arp, netdev, flowtables
                filter
        bridge
                filter
                nat (dstnat, srcnat)
                broute (no corresponding priority value)

Example:
nft> add table ip x
nft> add chain ip x y { type filter hook prerouting priority raw; }
nft> add chain ip x z { type filter hook prerouting priority mangle + 1; }
nft> add chain ip x w { type filter hook prerouting priority dstnat - 5; }
nft> add chain ip x r { type filter hook prerouting priority filter + 10; }
nft> add chain ip x t { type filter hook prerouting priority security; }
nft> add chain ip x q { type filter hook prerouting priority srcnat + 11; }
nft> add chain ip x h { type filter hook prerouting priority 15; }
nft>
nft> add flowtable ip x y { hook ingress priority filter + 5 ; devices = 
{enp0s31f6}; }
nft>
nft> add table arp x
nft> add chain arp x y { type filter hook input priority filter + 5; }
nft>
nft> list ruleset
table ip x {
        flowtable y {
                hook ingress priority filter + 5
                devices = { enp0s31f6 }
        }

        chain y {
                type filter hook prerouting priority raw; policy accept;
        }

        chain z {
                type filter hook prerouting priority mangle + 1; policy accept;
        }

        chain w {
                type filter hook prerouting priority dstnat - 5; policy accept;
        }

        chain r {
                type filter hook prerouting priority filter + 10; policy accept;
        }

        chain t {
                type filter hook prerouting priority security; policy accept;
        }

        chain q {
                type filter hook prerouting priority 111; policy accept;
        }

        chain h {
                type filter hook prerouting priority 15; policy accept;
        }
}
table arp x {
        chain y {
                type filter hook input priority filter + 5; policy accept;
        }
}
nft>
nft> add chain ip x h { type filter hook prerouting priority first; }
Error: 'first' is invalid for priority in this context.
add chain ip x h { type filter hook prerouting priority first; }
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
nft> add chain arp x y { type filter hook input priority raw; }
Error: 'raw' is invalid for priority in this context.
add chain arp x y { type filter hook input priority raw; }
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
nft> add flowtable ip x y { hook ingress priority magle; devices = {enp0s31f6}; 
}
Error: 'magle' is invalid for priority.
add flowtable ip x y { hook ingress priority magle; devices = {enp0s31f6}; }
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Signed-off-by: Máté Eckl <[email protected]>
---
v4:
 - fix snat and dnat conflict with existing tokens
 - remove static char array from chain_prio2str
 - make numerical priority printing available via -nnn nft flag
 - add docs about priority names
 - check compatibility of standard prio names and table family
 - handle flowtables

 doc/nft.xml        |  68 ++++++++++++++++++++++--
 include/rule.h     |   5 ++
 src/evaluate.c     |  56 ++++++++++++++++++++
 src/parser_bison.y |  36 ++++++++++---
 src/rule.c         | 129 ++++++++++++++++++++++++++++++++++++++++++---
 src/scanner.l      |   2 +
 6 files changed, 281 insertions(+), 15 deletions(-)

diff --git a/doc/nft.xml b/doc/nft.xml
index dc93a8c..01cc1d1 100644
--- a/doc/nft.xml
+++ b/doc/nft.xml
@@ -109,7 +109,7 @@ vi:ts=4 sw=4
                                                Show data numerically. When 
used once (the default behaviour), skip
                                                lookup of addresses to symbolic 
names. Use twice to also show Internet
                                                services (port numbers) 
numerically. Use three times to also show
-                                               protocols and UIDs/GIDs 
numerically.
+                                               protocols, UIDs/GIDs and 
priorities numerically.
                                        </para>
                                </listitem>
                        </varlistentry>
@@ -856,10 +856,68 @@ add table inet mytable
                        </itemizedlist>
                </para>
                <para>
-                       The <literal>priority</literal> parameter accepts a 
signed integer value which specifies the order in which chains with same 
<literal>hook</literal> value are traversed. The ordering is ascending, i.e. 
lower priority values have precedence over higher ones.
+                       The <literal>priority</literal> parameter accepts a 
signed integer value
+                       or a standard priority name which specifies the order 
in which chains
+                       with same <literal>hook</literal> value are traversed. 
The ordering is
+                       ascending, i.e. lower priority values have precedence 
over higher ones.
+                       <table frame="all">
+                               <title>Standard priority names, values and 
families they are supported in</title>
+                               <tgroup cols="3" align="left" colsep="1" 
rowsep="1">
+                                       <colspec colname="c1"/>
+                                       <colspec colname="c2" align="right"/>
+                                       <colspec colname="c3"/>
+                                       <thead>
+                                               <row>
+                                                       <entry>Name</entry>
+                                                       <entry>Value</entry>
+                                                       <entry>Families</entry>
+                                               </row>
+                                       </thead>
+                                       <tbody>
+                                               <row>
+                                                       <entry>raw</entry>
+                                                       <entry>-300</entry>
+                                                       <entry>ip, ip6, 
inet</entry>
+                                               </row>
+                                               <row>
+                                                       <entry>mangle</entry>
+                                                       <entry>-150</entry>
+                                                       <entry>ip, ip6, 
inet</entry>
+                                               </row>
+                                               <row>
+                                                       <entry>dstnat</entry>
+                                                       <entry>-100</entry>
+                                                       <entry>ip, ip6, inet, 
bridge</entry>
+                                               </row>
+                                               <row>
+                                                       <entry>filter</entry>
+                                                       <entry>0</entry>
+                                                       <entry>ip, ip6, inet, 
arp, bridge, netdev</entry>
+                                               </row>
+                                               <row>
+                                                       <entry>security</entry>
+                                                       <entry>50</entry>
+                                                       <entry>ip, ip6, 
inet</entry>
+                                               </row>
+                                               <row>
+                                                       <entry>srcnat</entry>
+                                                       <entry>100</entry>
+                                                       <entry>ip, ip6, inet, 
bridge</entry>
+                                               </row>
+                                       </tbody>
+                               </tgroup>
+                       </table>
+                       Basic arithmetic expressions (addition and 
substraction) can also
+                       be achieved with these standard names to ease relative 
prioritizing,
+                       eg. <literal>mangle - 5</literal> stands for 
<literal>-155</literal>.
+                       Values will also be printid like this untill the value 
is not further
+                       than 10 form the standard value.
                </para>
                <para>
-                       Base chains also allow to set the chain's 
<literal>policy</literal>, i.e. what happens to packets not explicitly accepted 
or refused in contained rules. Supported policy values are 
<literal>accept</literal> (which is the default) or <literal>drop</literal>.
+                       Base chains also allow to set the chain's 
<literal>policy</literal>, i.e.
+                       what happens to packets not explicitly accepted or 
refused in contained
+                       rules. Supported policy values are 
<literal>accept</literal> (which is
+                       the default) or <literal>drop</literal>.
                </para>
        </refsect1>
 
@@ -1379,6 +1437,10 @@ table inet filter {
                        hybrid IPv4/IPv6 tables.
 
                        When no address family is specified, 
<literal>ip</literal> is used by default.
+
+                       The <literal>priority</literal> can be a signed integer 
or <literal>filter</literal>
+                       which stands for 0. Addition and substraction can be 
used to set relative priority
+                       eg. filter + 5 equals to 5.
                </para>
 
                <variablelist>
diff --git a/include/rule.h b/include/rule.h
index 909ff36..cee9832 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -171,6 +171,7 @@ enum chain_flags {
  * @flags:     chain flags
  * @hookstr:   unified and human readable hook name (base chains)
  * @hooknum:   hook number (base chains)
+ * @priostr:   hook priority for standard priority name use (base chains)
  * @priority:  hook priority (base chains)
  * @policy:    default chain policy (base chains)
  * @type:      chain type
@@ -185,6 +186,7 @@ struct chain {
        uint32_t                flags;
        const char              *hookstr;
        unsigned int            hooknum;
+       const char              *priostr;
        int                     priority;
        int                     policy;
        const char              *type;
@@ -193,6 +195,8 @@ struct chain {
        struct list_head        rules;
 };
 
+#define STD_PRIO_BUFSIZE 100
+extern int std_prio_lookup(const char *std_prio_name, int family);
 extern const char *chain_type_name_lookup(const char *name);
 extern const char *chain_hookname_lookup(const char *name);
 extern struct chain *chain_alloc(const char *name);
@@ -357,6 +361,7 @@ struct flowtable {
        struct location         location;
        const char *            hookstr;
        unsigned int            hooknum;
+       const char              *priostr;
        int                     priority;
        const char              **dev_array;
        struct expr             *dev_expr;
diff --git a/src/evaluate.c b/src/evaluate.c
index c4ee3cc..c6de5e7 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -17,6 +17,7 @@
 #include <linux/netfilter.h>
 #include <linux/netfilter_arp.h>
 #include <linux/netfilter/nf_tables.h>
+#include <linux/netfilter_ipv4.h>
 #include <netinet/ip_icmp.h>
 #include <netinet/icmp6.h>
 #include <net/ethernet.h>
@@ -2868,6 +2869,46 @@ static int set_evaluate(struct eval_ctx *ctx, struct set 
*set)
        return 0;
 }
 
+static bool parse_evaluate_priority(const char *priostr, int *prioptr,
+                                   int family) {
+       char *endptr = NULL, *numstart = NULL;
+       int priority;
+
+       priority = (int)strtol(priostr, &endptr, 10);
+       /* prio_spec */
+       if (priostr != endptr) {
+               *prioptr = priority;
+               return true;
+       }
+
+       /* STRING */
+       priority = std_prio_lookup(priostr, family);
+       if (priority != NF_IP_PRI_LAST) {
+               *prioptr = priority;
+               return true;
+       }
+
+       /* STRUNG PLUS NUM | STRING DASH NUM */
+       numstart = strchr(priostr, '+');
+       if (!numstart)
+               numstart = strchr(priostr, '-');
+       if (numstart) {
+               char prioname[STD_PRIO_BUFSIZE];
+
+               snprintf(prioname, numstart - priostr + 1, "%s", priostr);
+               priority = std_prio_lookup(prioname, family);
+               if (priority != NF_IP_PRI_LAST) {
+                       priority += (int)strtol(numstart, &endptr, 10);
+                       if (endptr == priostr + strlen(priostr)) {
+                               *prioptr = priority;
+                               return true;
+                       }
+               }
+       }
+
+       return false;
+}
+
 static uint32_t str2hooknum(uint32_t family, const char *hook);
 
 static int flowtable_evaluate(struct eval_ctx *ctx, struct flowtable *ft)
@@ -2884,6 +2925,13 @@ static int flowtable_evaluate(struct eval_ctx *ctx, 
struct flowtable *ft)
        if (ft->hooknum == NF_INET_NUMHOOKS)
                return chain_error(ctx, ft, "invalid hook %s", ft->hookstr);
 
+       if (!ft->priostr)
+               return chain_error(ctx, ft,
+                                  "flowtable priority must be specified.");
+       if (!parse_evaluate_priority(ft->priostr, &ft->priority, 
NFPROTO_NETDEV))
+               return chain_error(ctx, ft, "'%s' is invalid priority.",
+                                  ft->priostr);
+
        if (!ft->dev_expr)
                return chain_error(ctx, ft, "Unbound flowtable not allowed 
(must specify devices)");
 
@@ -3038,6 +3086,14 @@ static int chain_evaluate(struct eval_ctx *ctx, struct 
chain *chain)
                                           chain->hookstr);
        }
 
+       if (!chain->priostr)
+               return chain_error(ctx, chain, "chain priority must be 
specified.");
+       if (!parse_evaluate_priority(chain->priostr, &chain->priority,
+                                    chain->handle.family))
+               return chain_error(ctx, chain,
+                                  "'%s' is invalid priority in this context.",
+                                  chain->priostr);
+
        list_for_each_entry(rule, &chain->rules, list) {
                handle_merge(&rule->handle, &chain->handle);
                if (rule_evaluate(ctx, rule) < 0)
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 98bfeba..2b7d7cc 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -182,6 +182,8 @@ int nft_lex(void *, void *, void *);
 %token AT                      "@"
 %token VMAP                    "vmap"
 
+%token PLUS                    "+"
+
 %token INCLUDE                 "include"
 %token DEFINE                  "define"
 %token REDEFINE                        "redefine"
@@ -522,6 +524,7 @@ int nft_lex(void *, void *, void *);
 %type <handle>                 set_spec setid_spec set_identifier 
flowtable_identifier obj_spec objid_spec obj_identifier
 %destructor { handle_free(&$$); } set_spec setid_spec set_identifier obj_spec 
objid_spec obj_identifier
 %type <val>                    family_spec family_spec_explicit chain_policy 
prio_spec
+%type <string>         str_prio_spec
 
 %type <string>                 dev_spec quota_unit
 %destructor { xfree($$); }     dev_spec quota_unit
@@ -1633,7 +1636,7 @@ flowtable_block_alloc     :       /* empty */
 flowtable_block                :       /* empty */     { $$ = $<flowtable>-1; }
                        |       flowtable_block common_block
                        |       flowtable_block stmt_separator
-                       |       flowtable_block HOOK            STRING  
PRIORITY        prio_spec       stmt_separator
+                       |       flowtable_block HOOK            STRING  
PRIORITY    str_prio_spec       stmt_separator
                        {
                                $$->hookstr     = chain_hookname_lookup($3);
                                if ($$->hookstr == NULL) {
@@ -1644,7 +1647,7 @@ flowtable_block           :       /* empty */     { $$ = 
$<flowtable>-1; }
                                }
                                xfree($3);
 
-                               $$->priority = $5;
+                               $$->priostr = $5;
                        }
                        |       flowtable_block DEVICES         '='     
flowtable_expr  stmt_separator
                        {
@@ -1766,7 +1769,7 @@ type_identifier           :       STRING  { $$ = $1; }
                        |       CLASSID { $$ = xstrdup("classid"); }
                        ;
 
-hook_spec              :       TYPE            STRING          HOOK            
STRING          dev_spec        PRIORITY        prio_spec
+hook_spec              :       TYPE            STRING          HOOK            
STRING          dev_spec        PRIORITY        str_prio_spec
                        {
                                const char *chain_type = 
chain_type_name_lookup($2);
 
@@ -1789,13 +1792,34 @@ hook_spec               :       TYPE            STRING  
        HOOK            STRING          dev_spec        PRIORITY        
prio_spec
                                xfree($4);
 
                                $<chain>0->dev          = $5;
-                               $<chain>0->priority     = $7;
+                               $<chain>0->priostr      = $7;
                                $<chain>0->flags        |= CHAIN_F_BASECHAIN;
                        }
                        ;
 
-prio_spec              :       NUM                     { $$ = $1; }
-                       |       DASH    NUM             { $$ = -$2; }
+str_prio_spec  :       prio_spec
+                       {
+                               char buf[STD_PRIO_BUFSIZE];
+                               snprintf(buf, STD_PRIO_BUFSIZE, "%d", (int)$1);
+                               $$ = xstrdup(buf);
+                       }
+                       |       STRING  { $$ = xstrdup($1); }
+                       |       STRING PLUS NUM
+                       {
+                               char buf[STD_PRIO_BUFSIZE];
+                               snprintf(buf, STD_PRIO_BUFSIZE, "%s+%d",$1, 
(int)$3);
+                               $$ = xstrdup(buf);
+                       }
+                       |       STRING DASH NUM
+                       {
+                               char buf[STD_PRIO_BUFSIZE];
+                               snprintf(buf, STD_PRIO_BUFSIZE, "%s-%d", $1, 
(int)$3);
+                               $$ = xstrdup(buf);
+                       }
+                       ;
+
+prio_spec              :       NUM                 { $$ =   $1; }
+                       |       DASH    NUM             { $$ =  -$2; }
                        ;
 
 dev_spec               :       DEVICE  STRING          { $$ = $2; }
diff --git a/src/rule.c b/src/rule.c
index 56b956a..c2222fe 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -28,6 +28,7 @@
 #include <netinet/ip.h>
 #include <linux/netfilter.h>
 #include <linux/netfilter_arp.h>
+#include <linux/netfilter_ipv4.h>
 
 void handle_free(struct handle *h)
 {
@@ -671,6 +672,7 @@ void chain_free(struct chain *chain)
        xfree(chain->type);
        if (chain->dev != NULL)
                xfree(chain->dev);
+       xfree(chain->priostr);
        xfree(chain);
 }
 
@@ -769,9 +771,112 @@ const char *chain_policy2str(uint32_t policy)
        return "unknown";
 }
 
+struct prio_tag {
+       int val;
+       const char *str;
+};
+
+const static struct prio_tag std_prios[] = {
+       { NF_IP_PRI_RAW,      "raw" },
+       { NF_IP_PRI_MANGLE,   "mangle" },
+       { NF_IP_PRI_NAT_DST,  "dstnat" },
+       { NF_IP_PRI_FILTER,   "filter" },
+       { NF_IP_PRI_SECURITY, "security" },
+       { NF_IP_PRI_NAT_SRC,  "srcnat" },
+};
+
+static bool std_prio_family_compat(int prio, int family)
+{
+       switch(prio) {
+       case NF_IP_PRI_FILTER:
+               switch(family) {
+               case NFPROTO_INET:
+               case NFPROTO_IPV4:
+               case NFPROTO_IPV6:
+               case NFPROTO_ARP:
+               case NFPROTO_BRIDGE:
+               case NFPROTO_NETDEV:
+                       return true;
+               default:
+                       return false;
+               }
+       case NF_IP_PRI_RAW:
+       case NF_IP_PRI_MANGLE:
+       case NF_IP_PRI_SECURITY:
+               switch(family) {
+               case NFPROTO_INET:
+               case NFPROTO_IPV4:
+               case NFPROTO_IPV6:
+                       return true;
+               default:
+                       return false;
+               }
+       case NF_IP_PRI_NAT_DST:
+       case NF_IP_PRI_NAT_SRC:
+               switch(family) {
+               case NFPROTO_INET:
+               case NFPROTO_IPV4:
+               case NFPROTO_IPV6:
+               case NFPROTO_BRIDGE:
+                       return true;
+               default:
+                       return false;
+               }
+       default:
+               return false;
+       }
+}
+
+int std_prio_lookup(const char *std_prio_name, int family)
+{
+       long unsigned int i;
+
+       for (i = 0; i < array_size(std_prios); ++i) {
+               if (strcmp(std_prios[i].str, std_prio_name) == 0 &&
+                   std_prio_family_compat(std_prios[i].val, family))
+                       return std_prios[i].val;
+       }
+       return NF_IP_PRI_LAST;
+}
+
+static const char *prio2str(char *buf, size_t bufsize, int family,
+                                 int prio, int numeric)
+{
+       const int reach = 10;
+       size_t i;
+       int std_prio, offset;
+       const char *std_prio_str;
+
+       if (numeric != NFT_NUMERIC_ALL) {
+               for (i = 0; i < array_size(std_prios); ++i) {
+                       std_prio = std_prios[i].val;
+                       std_prio_str = std_prios[i].str;
+                       if (abs(prio - std_prio) <= reach) {
+                               if (!std_prio_family_compat(std_prio, family))
+                                       break;
+                               offset = prio - std_prio;
+                               strncpy(buf, std_prio_str, bufsize);
+                               if (offset > 0)
+                                       snprintf(buf + strlen(buf),
+                                                bufsize - strlen(buf), " + %d",
+                                                offset);
+                               else if (offset < 0)
+                                       snprintf(buf + strlen(buf),
+                                                bufsize - strlen(buf), " - %d",
+                                                -offset);
+                               return buf;
+                       }
+               }
+       }
+       snprintf(buf, bufsize, "%d", prio);
+       return buf;
+}
+
 static void chain_print_declaration(const struct chain *chain,
                                    struct output_ctx *octx)
 {
+       char priobuf[STD_PRIO_BUFSIZE];
+
        nft_print(octx, "\tchain %s {", chain->handle.chain.name);
        if (octx->handle > 0)
                nft_print(octx, " # handle %" PRIu64, chain->handle.handle.id);
@@ -781,8 +886,11 @@ static void chain_print_declaration(const struct chain 
*chain,
                          hooknum2str(chain->handle.family, chain->hooknum));
                if (chain->dev != NULL)
                        nft_print(octx, " device %s", chain->dev);
-               nft_print(octx, " priority %d; policy %s;\n",
-                         chain->priority, chain_policy2str(chain->policy));
+               nft_print(octx, " priority %s; policy %s;\n",
+                         prio2str(priobuf, sizeof(priobuf),
+                                  chain->handle.family,
+                                  chain->priority, octx->numeric),
+                         chain_policy2str(chain->policy));
        }
 }
 
@@ -802,13 +910,18 @@ static void chain_print(const struct chain *chain, struct 
output_ctx *octx)
 
 void chain_print_plain(const struct chain *chain, struct output_ctx *octx)
 {
+       char priobuf[STD_PRIO_BUFSIZE];
+
        nft_print(octx, "chain %s %s %s", family2str(chain->handle.family),
                  chain->handle.table.name, chain->handle.chain.name);
 
        if (chain->flags & CHAIN_F_BASECHAIN) {
-               nft_print(octx, " { type %s hook %s priority %d; policy %s; }",
+               nft_print(octx, " { type %s hook %s priority %s; policy %s; }",
                          chain->type, chain->hookstr,
-                         chain->priority, chain_policy2str(chain->policy));
+                         prio2str(priobuf, sizeof(priobuf),
+                                  chain->handle.family,
+                                  chain->priority, octx->numeric),
+                         chain_policy2str(chain->policy));
        }
        if (octx->handle > 0)
                nft_print(octx, " # handle %" PRIu64, chain->handle.handle.id);
@@ -1636,6 +1749,7 @@ void flowtable_free(struct flowtable *flowtable)
        if (--flowtable->refcnt > 0)
                return;
        handle_free(&flowtable->handle);
+       xfree(flowtable->priostr);
        xfree(flowtable);
 }
 
@@ -1648,6 +1762,7 @@ static void flowtable_print_declaration(const struct 
flowtable *flowtable,
                                        struct print_fmt_options *opts,
                                        struct output_ctx *octx)
 {
+       char priobuf[STD_PRIO_BUFSIZE];
        int i;
 
        nft_print(octx, "%sflowtable", opts->tab);
@@ -1660,10 +1775,12 @@ static void flowtable_print_declaration(const struct 
flowtable *flowtable,
 
        nft_print(octx, " %s {%s", flowtable->handle.flowtable, opts->nl);
 
-       nft_print(octx, "%s%shook %s priority %d%s",
+       nft_print(octx, "%s%shook %s priority %s%s",
                  opts->tab, opts->tab,
                  hooknum2str(NFPROTO_NETDEV, flowtable->hooknum),
-                 flowtable->priority, opts->stmt_separator);
+                 prio2str(priobuf, sizeof(priobuf), NFPROTO_NETDEV,
+                          flowtable->priority, octx->numeric),
+                 opts->stmt_separator);
 
        nft_print(octx, "%s%sdevices = { ", opts->tab, opts->tab);
        for (i = 0; i < flowtable->dev_array_len; i++) {
diff --git a/src/scanner.l b/src/scanner.l
index ed01b5e..4fb3a39 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -232,6 +232,8 @@ addrstring  ({macaddr}|{ip4addr}|{ip6addr})
 "="                    { return '='; }
 "vmap"                 { return VMAP; }
 
+"+"            { return PLUS; }
+
 "include"              { return INCLUDE; }
 "define"               { return DEFINE; }
 "redefine"             { return REDEFINE; }
-- 
ecklm

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to