]> rtime.felk.cvut.cz Git - lisovros/iproute2_canprio.git/commitdiff
Merge branch 'master' into net-2.6.25
authorStephen Hemminger <shemminger@linux-foundation.org>
Tue, 11 Dec 2007 18:04:33 +0000 (10:04 -0800)
committerStephen Hemminger <shemminger@linux-foundation.org>
Tue, 11 Dec 2007 18:04:33 +0000 (10:04 -0800)
doc/ip-cref.tex
include/linux/tc_act/tc_nat.h [new file with mode: 0644]
lib/libnetlink.c
lib/utils.c
tc/Makefile
tc/f_fw.c
tc/m_nat.c [new file with mode: 0644]

index 5eaa4a896eb15ebf743d71b5b091c570c0234d47..fe38f998a8dd7bc82263d9c12a88e3fc95dfd702 100644 (file)
@@ -298,9 +298,9 @@ Do not use it, if you do not understand what this operation really does.
 
 \vskip 1mm
 \begin{NB}
-The {\tt ip} utility does not change the \verb|PROMISC| 
-or \verb|ALLMULTI| flags. These flags are considered
-obsolete and should not be changed administratively.
+The \verb|PROMISC| and \verb|ALLMULTI| flags are considered
+obsolete and should not be changed administratively, though
+the {\tt ip} utility will allow that.
 \end{NB}
 
 \paragraph{Warning:} If multiple parameter changes are requested,
@@ -450,13 +450,6 @@ or not implemented (\verb|DEBUG|) or specific to some devices
 (\verb|MASTER|, \verb|AUTOMEDIA| and \verb|PORTSEL|). We do not discuss
 them here.
 \end{NB}
-\begin{NB}
-The values of \verb|PROMISC| and \verb|ALLMULTI| flags
-shown by the \verb|ifconfig| utility and by the \verb|ip| utility
-are {\em different\/}. \verb|ip link ls| shows the true device state,
-while \verb|ifconfig| shows the virtual state which was set with
-\verb|ifconfig| itself.
-\end{NB}
 
 
 The second line contains information on the link layer addresses
diff --git a/include/linux/tc_act/tc_nat.h b/include/linux/tc_act/tc_nat.h
new file mode 100644 (file)
index 0000000..e7cf31e
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef __LINUX_TC_NAT_H
+#define __LINUX_TC_NAT_H
+
+#include <linux/pkt_cls.h>
+#include <linux/types.h>
+
+#define TCA_ACT_NAT 9
+
+enum
+{
+       TCA_NAT_UNSPEC,
+       TCA_NAT_PARMS,
+       TCA_NAT_TM,
+       __TCA_NAT_MAX
+};
+#define TCA_NAT_MAX (__TCA_NAT_MAX - 1)
+
+#define TCA_NAT_FLAG_EGRESS 1
+
+struct tc_nat
+{
+       tc_gen;
+       __be32 old_addr;
+       __be32 new_addr;
+       __be32 mask;
+       __u32 flags;
+};
+
+#endif
index 12883fe11f66c4bf709e98e81fcfb83e8b2e34ea..d13596fa2d9b406309bca462f9e189a438afaeea 100644 (file)
@@ -632,6 +632,6 @@ int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rt
                rta = RTA_DATA(rta) + RTA_ALIGN(len);
                return parse_rtattr_nested(tb, max, rta);
        }
-       memset(tb, 0, sizeof(struct rtattr *) * max);
+       memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
        return 0;
 }
index ffef6fed91481bbeca0995e7d9904d6f2d517e2d..84948513d7da43703035d18b209713a16c15c35c 100644 (file)
@@ -47,6 +47,48 @@ int get_integer(int *val, const char *arg, int base)
        return 0;
 }
 
+/* a valid netmask must be 2^n - 1 */
+static int is_valid_netmask(const inet_prefix *addr)
+{
+        uint32_t host;
+
+        if (addr->family != AF_INET)
+                return 0;
+
+        host = ~ntohl(addr->data[0]);
+
+        return (host & (host + 1)) == 0;
+}
+
+static unsigned cidr(const inet_prefix *addr)
+{
+       unsigned bits = 0;
+       u_int32_t mask;
+
+       for (mask = ntohl(addr->data[0]); mask; mask <<= 1)
+               ++bits;
+
+       return bits;
+}
+
+static int get_netmask(unsigned *val, const char *arg, int base)
+{
+       inet_prefix addr;
+
+       if (!get_unsigned(val, arg, base))
+               return 0;
+
+       /* try coverting dotted quad to CIDR */
+       if (!get_addr_1(&addr, arg, AF_INET)) {
+               if (is_valid_netmask(&addr))
+                       return 0;
+
+               *val = cidr(&addr);
+       }
+
+       return -1;
+}
+
 int get_unsigned(unsigned *val, const char *arg, int base)
 {
        unsigned long res;
@@ -304,7 +346,8 @@ int get_prefix_1(inet_prefix *dst, char *arg, int family)
                                dst->bitlen = 32;
                }
                if (slash) {
-                       if (get_unsigned(&plen, slash+1, 0) || plen > dst->bitlen) {
+                       if (get_netmask(&plen, slash+1, 0)
+                                       || plen > dst->bitlen) {
                                err = -1;
                                goto done;
                        }
index a71556677a13f4a9faf6ac68c74114da68a9eb71..0facc8805f2a3b2d4ea9c6049739465ee2a1de65 100644 (file)
@@ -27,6 +27,7 @@ TCMODULES += q_htb.o
 TCMODULES += m_gact.o
 TCMODULES += m_mirred.o
 TCMODULES += m_ipt.o
+TCMODULES += m_nat.o
 TCMODULES += m_pedit.o
 TCMODULES += p_ip.o
 TCMODULES += p_icmp.o
index 046f61468c041cd8176cf7d4a15e089cb59edd31..6d1490b46a16c00bda68ff92fcac7a919c386de3 100644 (file)
--- a/tc/f_fw.c
+++ b/tc/f_fw.c
@@ -40,19 +40,30 @@ static int fw_parse_opt(struct filter_util *qu, char *handle, int argc, char **a
 
        memset(&tp, 0, sizeof(tp));
 
+       tail = NLMSG_TAIL(n);
+       addattr_l(n, 4096, TCA_OPTIONS, NULL, 0);
+
        if (handle) {
+               char *slash;
+               __u32 mask = 0;
+               if ((slash = strchr(handle, '/')) != NULL)
+                       *slash = '\0';
                if (get_u32(&t->tcm_handle, handle, 0)) {
                        fprintf(stderr, "Illegal \"handle\"\n");
                        return -1;
                }
+               if (slash) {
+                       if (get_u32(&mask, slash+1, 0)) {
+                               fprintf(stderr, "Illegal \"handle\" mask\n");
+                               return -1;
+                       }
+                       addattr32(n, MAX_MSG, TCA_FW_MASK, mask);
+               }
        }
 
        if (argc == 0)
                return 0;
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 4096, TCA_OPTIONS, NULL, 0);
-
        while (argc > 0) {
                if (matches(*argv, "classid") == 0 ||
                    matches(*argv, "flowid") == 0) {
@@ -111,8 +122,16 @@ static int fw_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u
 
        parse_rtattr_nested(tb, TCA_FW_MAX, opt);
 
-       if (handle)
-               fprintf(f, "handle 0x%x ", handle);
+       if (handle || tb[TCA_FW_MASK]) {
+               __u32 mark = 0, mask = 0;
+               if(handle)
+                       mark = handle;
+               if(tb[TCA_FW_MASK] &&
+                   (mask = *(__u32*)RTA_DATA(tb[TCA_FW_MASK])) != 0xFFFFFFFF)
+                       fprintf(f, "handle 0x%x/0x%x ", mark, mask);
+               else
+                       fprintf(f, "handle 0x%x ", handle);
+       }
 
        if (tb[TCA_FW_CLASSID]) {
                SPRINT_BUF(b1);
diff --git a/tc/m_nat.c b/tc/m_nat.c
new file mode 100644 (file)
index 0000000..6e7fd05
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * m_nat.c             NAT module
+ *
+ *             This program is free software; you can distribute it and/or
+ *             modify it under the terms of the GNU General Public License
+ *             as published by the Free Software Foundation; either version
+ *             2 of the License, or (at your option) any later version.
+ *
+ * Authors:    Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <dlfcn.h>
+#include "utils.h"
+#include "tc_util.h"
+#include <linux/tc_act/tc_nat.h>
+
+static void
+explain(void)
+{
+       fprintf(stderr, "Usage: ... nat NAT\n"
+                       "NAT := DIRECTION OLD NEW\n"
+                       "DIRECTION := { ingress | egress }\n"
+                       "OLD := PREFIX\n"
+                       "NEW := ADDRESS\n");
+}
+
+static void
+usage(void)
+{
+       explain();
+       exit(-1);
+}
+
+static int
+parse_nat_args(int *argc_p, char ***argv_p,struct tc_nat *sel)
+{
+       int argc = *argc_p;
+       char **argv = *argv_p;
+       inet_prefix addr;
+
+       if (argc <= 0)
+               return -1;
+
+       if (matches(*argv, "egress") == 0)
+               sel->flags |= TCA_NAT_FLAG_EGRESS;
+       else if (matches(*argv, "ingress") != 0)
+               goto bad_val;
+
+       NEXT_ARG();
+
+       if (get_prefix_1(&addr, *argv, AF_INET))
+               goto bad_val;
+
+       sel->old_addr = addr.data[0];
+       sel->mask = htonl(~0u << (32 - addr.bitlen));
+
+       NEXT_ARG();
+
+       if (get_prefix_1(&addr, *argv, AF_INET))
+               goto bad_val;
+
+       sel->new_addr = addr.data[0];
+
+       argc--;
+       argv++;
+
+       *argc_p = argc;
+       *argv_p = argv;
+       return 0;
+
+bad_val:
+       return -1;
+}
+
+static int
+parse_nat(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
+{
+       struct tc_nat sel;
+
+       int argc = *argc_p;
+       char **argv = *argv_p;
+       int ok = 0;
+       struct rtattr *tail;
+
+       memset(&sel, 0, sizeof(sel));
+
+       while (argc > 0) {
+               if (matches(*argv, "nat") == 0) {
+                       NEXT_ARG();
+                       if (parse_nat_args(&argc, &argv, &sel)) {
+                               fprintf(stderr, "Illegal nat construct (%s) \n",
+                                       *argv);
+                               explain();
+                               return -1;
+                       }
+                       ok++;
+                       continue;
+               } else if (matches(*argv, "help") == 0) {
+                       usage();
+               } else {
+                       break;
+               }
+
+       }
+
+       if (!ok) {
+               explain();
+               return -1;
+       }
+
+       if (argc) {
+               if (matches(*argv, "reclassify") == 0) {
+                       sel.action = TC_ACT_RECLASSIFY;
+                       argc--;
+                       argv++;
+               } else if (matches(*argv, "pipe") == 0) {
+                       sel.action = TC_ACT_PIPE;
+                       argc--;
+                       argv++;
+               } else if (matches(*argv, "drop") == 0 ||
+                       matches(*argv, "shot") == 0) {
+                       sel.action = TC_ACT_SHOT;
+                       argc--;
+                       argv++;
+               } else if (matches(*argv, "continue") == 0) {
+                       sel.action = TC_ACT_UNSPEC;
+                       argc--;
+                       argv++;
+               } else if (matches(*argv, "pass") == 0) {
+                       sel.action = TC_ACT_OK;
+                       argc--;
+                       argv++;
+               }
+       }
+
+       if (argc) {
+               if (matches(*argv, "index") == 0) {
+                       NEXT_ARG();
+                       if (get_u32(&sel.index, *argv, 10)) {
+                               fprintf(stderr, "Pedit: Illegal \"index\"\n");
+                               return -1;
+                       }
+                       argc--;
+                       argv++;
+               }
+       }
+
+       tail = NLMSG_TAIL(n);
+       addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+       addattr_l(n, MAX_MSG, TCA_NAT_PARMS, &sel, sizeof(sel));
+       tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
+
+       *argc_p = argc;
+       *argv_p = argv;
+       return 0;
+}
+
+static int
+print_nat(struct action_util *au,FILE * f, struct rtattr *arg)
+{
+       struct tc_nat *sel;
+       struct rtattr *tb[TCA_NAT_MAX + 1];
+       char buf1[256];
+       char buf2[256];
+       SPRINT_BUF(buf3);
+       int len;
+
+       if (arg == NULL)
+               return -1;
+
+       parse_rtattr_nested(tb, TCA_NAT_MAX, arg);
+
+       if (tb[TCA_NAT_PARMS] == NULL) {
+               fprintf(f, "[NULL nat parameters]");
+               return -1;
+       }
+       sel = RTA_DATA(tb[TCA_NAT_PARMS]);
+
+       len = ffs(sel->mask);
+       len = len ? 33 - len : 0;
+
+       fprintf(f, " nat %s %s/%d %s %s", sel->flags & TCA_NAT_FLAG_EGRESS ?
+                                         "egress" : "ingress",
+               format_host(AF_INET, 4, &sel->old_addr, buf1, sizeof(buf1)),
+               len,
+               format_host(AF_INET, 4, &sel->new_addr, buf2, sizeof(buf2)),
+               action_n2a(sel->action, buf3, sizeof (buf3)));
+
+       if (show_stats) {
+               if (tb[TCA_NAT_TM]) {
+                       struct tcf_t *tm = RTA_DATA(tb[TCA_NAT_TM]);
+                       print_tm(f,tm);
+               }
+       }
+
+       return 0;
+}
+
+struct action_util nat_action_util = {
+       .id = "nat",
+       .parse_aopt = parse_nat,
+       .print_aopt = print_nat,
+};