]> git.proxmox.com Git - mirror_iproute2.git/commitdiff
Merge branch 'master' into net-next
authorStephen Hemminger <shemming@brocade.com>
Thu, 5 Feb 2015 18:56:06 +0000 (10:56 -0800)
committerStephen Hemminger <shemming@brocade.com>
Thu, 5 Feb 2015 18:56:06 +0000 (10:56 -0800)
19 files changed:
bridge/br_common.h
bridge/bridge.c
bridge/vlan.c
include/linux/if_bridge.h
include/linux/if_link.h
include/linux/l2tp.h
include/linux/libc-compat.h
include/linux/neighbour.h
include/linux/rtnetlink.h
include/linux/tc_act/tc_bpf.h [new file with mode: 0644]
ip/iplink_vxlan.c
ip/iproute.c
man/man8/ip-link.8.in
man/man8/ip-route.8.in
tc/Makefile
tc/f_bpf.c
tc/m_bpf.c [new file with mode: 0644]
tc/tc_bpf.c [new file with mode: 0644]
tc/tc_bpf.h [new file with mode: 0644]

index 12fce3ef007a49362a450314beaf28e7c0afcd92..169a162d0c0100aa5be83aa48811fb1c6aa1ad37 100644 (file)
@@ -16,4 +16,5 @@ extern int preferred_family;
 extern int show_stats;
 extern int show_details;
 extern int timestamp;
+extern int compress_vlans;
 extern struct rtnl_handle rth;
index 5fcc552b1f5dee21d04909c422e294868d189072..88469ca28a25d688c0b690957a18abb1c5cc8a7b 100644 (file)
@@ -21,6 +21,7 @@ int resolve_hosts;
 int oneline = 0;
 int show_stats;
 int show_details;
+int compress_vlans;
 int timestamp;
 char * _SL_ = NULL;
 
@@ -32,7 +33,8 @@ static void usage(void)
 "Usage: bridge [ OPTIONS ] OBJECT { COMMAND | help }\n"
 "where  OBJECT := { link | fdb | mdb | vlan | monitor }\n"
 "       OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] |\n"
-"                    -o[neline] | -t[imestamp] | -n[etns] name }\n");
+"                    -o[neline] | -t[imestamp] | -n[etns] name |\n"
+"                    -c[ompressvlans] }\n");
        exit(-1);
 }
 
@@ -117,6 +119,8 @@ main(int argc, char **argv)
                        NEXT_ARG();
                        if (netns_switch(argv[1]))
                                exit(-1);
+               } else if (matches(opt, "-compressvlans") == 0) {
+                       ++compress_vlans;
                } else {
                        fprintf(stderr, "Option \"%s\" is unknown, try \"bridge help\".\n", opt);
                        exit(-1);
index 3bd7b0db5090d37b5f144ec3cfb732e820234f7e..9f6c84eeb6afb778668e574724cf431651d83282 100644 (file)
@@ -32,6 +32,7 @@ static int vlan_modify(int cmd, int argc, char **argv)
        } req;
        char *d = NULL;
        short vid = -1;
+       short vid_end = -1;
        struct rtattr *afspec;
        struct bridge_vlan_info vinfo;
        unsigned short flags = 0;
@@ -49,8 +50,18 @@ static int vlan_modify(int cmd, int argc, char **argv)
                        NEXT_ARG();
                        d = *argv;
                } else if (strcmp(*argv, "vid") == 0) {
+                       char *p;
                        NEXT_ARG();
-                       vid = atoi(*argv);
+                       p = strchr(*argv, '-');
+                       if (p) {
+                               *p = '\0';
+                               p++;
+                               vid = atoi(*argv);
+                               vid_end = atoi(p);
+                               vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN;
+                       } else {
+                               vid = atoi(*argv);
+                       }
                } else if (strcmp(*argv, "self") == 0) {
                        flags |= BRIDGE_FLAGS_SELF;
                } else if (strcmp(*argv, "master") == 0) {
@@ -83,15 +94,40 @@ static int vlan_modify(int cmd, int argc, char **argv)
                return -1;
        }
 
-       vinfo.vid = vid;
+       if (vinfo.flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
+               if (vid_end == -1 || vid_end >= 4096 || vid >= vid_end) {
+                       fprintf(stderr, "Invalid VLAN range \"%hu-%hu\"\n",
+                               vid, vid_end);
+                       return -1;
+               }
+               if (vinfo.flags & BRIDGE_VLAN_INFO_PVID) {
+                       fprintf(stderr,
+                               "pvid cannot be configured for a vlan range\n");
+                       return -1;
+               }
+       }
 
        afspec = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC);
 
        if (flags)
                addattr16(&req.n, sizeof(req), IFLA_BRIDGE_FLAGS, flags);
 
-       addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo,
-                 sizeof(vinfo));
+       vinfo.vid = vid;
+       if (vid_end != -1) {
+               /* send vlan range start */
+               addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo,
+                         sizeof(vinfo));
+               vinfo.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN;
+
+               /* Now send the vlan range end */
+               vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_END;
+               vinfo.vid = vid_end;
+               addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo,
+                         sizeof(vinfo));
+       } else {
+               addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo,
+                         sizeof(vinfo));
+       }
 
        addattr_nest_end(&req.n, afspec);
 
@@ -146,7 +182,12 @@ static int print_vlan(const struct sockaddr_nl *who,
                                continue;
 
                        vinfo = RTA_DATA(i);
-                       fprintf(fp, "\t %hu", vinfo->vid);
+                       if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END)
+                               fprintf(fp, "-%hu", vinfo->vid);
+                       else
+                               fprintf(fp, "\t %hu", vinfo->vid);
+                       if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN)
+                               continue;
                        if (vinfo->flags & BRIDGE_VLAN_INFO_PVID)
                                fprintf(fp, " PVID");
                        if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED)
@@ -182,7 +223,9 @@ static int vlan_show(int argc, char **argv)
        }
 
        if (rtnl_wilddump_req_filter(&rth, PF_BRIDGE, RTM_GETLINK,
-                                    RTEXT_FILTER_BRVLAN) < 0) {
+                                   (compress_vlans ?
+                                   RTEXT_FILTER_BRVLAN_COMPRESSED :
+                                   RTEXT_FILTER_BRVLAN)) < 0) {
                perror("Cannont send dump request");
                exit(1);
        }
index 19ff22af9f8e5027764576108cb95f95748df657..913bd8e3d406b9bd88dd4b25d108ab71f39f0193 100644 (file)
@@ -125,6 +125,8 @@ enum {
 #define BRIDGE_VLAN_INFO_MASTER        (1<<0)  /* Operate on Bridge device as well */
 #define BRIDGE_VLAN_INFO_PVID  (1<<1)  /* VLAN is PVID, ingress untagged */
 #define BRIDGE_VLAN_INFO_UNTAGGED      (1<<2)  /* VLAN egresses untagged */
+#define BRIDGE_VLAN_INFO_RANGE_BEGIN   (1<<3) /* VLAN is start of vlan range */
+#define BRIDGE_VLAN_INFO_RANGE_END     (1<<4) /* VLAN is end of vlan range */
 
 struct bridge_vlan_info {
        __u16 flags;
index 167ec34bab73ba280ff9e2aee43213a118470ef8..ac64724c94254f6543d1fbf8150a25463ba85c56 100644 (file)
@@ -146,6 +146,7 @@ enum {
        IFLA_PHYS_PORT_ID,
        IFLA_CARRIER_CHANGES,
        IFLA_PHYS_SWITCH_ID,
+       IFLA_LINK_NETNSID,
        __IFLA_MAX
 };
 
@@ -368,6 +369,9 @@ enum {
        IFLA_VXLAN_UDP_CSUM,
        IFLA_VXLAN_UDP_ZERO_CSUM6_TX,
        IFLA_VXLAN_UDP_ZERO_CSUM6_RX,
+       IFLA_VXLAN_REMCSUM_TX,
+       IFLA_VXLAN_REMCSUM_RX,
+       IFLA_VXLAN_GBP,
        __IFLA_VXLAN_MAX
 };
 #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1)
index c0e116a4073ae65f75a27b251c6be29e24061ffe..5b0e36d0f62b99a922da2796da56f3239a6d9c32 100644 (file)
@@ -176,5 +176,6 @@ enum l2tp_seqmode {
  */
 #define L2TP_GENL_NAME         "l2tp"
 #define L2TP_GENL_VERSION      0x1
+#define L2TP_GENL_MCGROUP       "l2tp"
 
 #endif /* _LINUX_L2TP_H_ */
index 9e860a0c81206f4a7d9027d1726039bb6653484a..990332e061aa510c9e3bb6940c0ceb710df3fc71 100644 (file)
@@ -70,6 +70,8 @@
 #define __UAPI_DEF_IPV6_MREQ           0
 #define __UAPI_DEF_IPPROTO_V6          0
 #define __UAPI_DEF_IPV6_OPTIONS                0
+#define __UAPI_DEF_IN6_PKTINFO         0
+#define __UAPI_DEF_IP6_MTUINFO         0
 
 #else
 
@@ -84,6 +86,8 @@
 #define __UAPI_DEF_IPV6_MREQ           1
 #define __UAPI_DEF_IPPROTO_V6          1
 #define __UAPI_DEF_IPV6_OPTIONS                1
+#define __UAPI_DEF_IN6_PKTINFO         1
+#define __UAPI_DEF_IP6_MTUINFO         1
 
 #endif /* _NETINET_IN_H */
 
 #define __UAPI_DEF_IPV6_MREQ           1
 #define __UAPI_DEF_IPPROTO_V6          1
 #define __UAPI_DEF_IPV6_OPTIONS                1
+#define __UAPI_DEF_IN6_PKTINFO         1
+#define __UAPI_DEF_IP6_MTUINFO         1
 
 /* Definitions for xattr.h */
 #define __UAPI_DEF_XATTR               1
index f3d77f9f1e0bb582b1f1ca02fd8bd99ff60729dd..3873a35509aad201f4d5ddb31346077a89641b78 100644 (file)
@@ -25,6 +25,7 @@ enum {
        NDA_VNI,
        NDA_IFINDEX,
        NDA_MASTER,
+       NDA_LINK_NETNSID,
        __NDA_MAX
 };
 
index 9aa5c2f93dba048a8c673f7786febf6205f49adf..3eb78105399be8c377591ee76af993e07e8d5226 100644 (file)
@@ -132,6 +132,11 @@ enum {
        RTM_GETMDB = 86,
 #define RTM_GETMDB RTM_GETMDB
 
+       RTM_NEWNSID = 88,
+#define RTM_NEWNSID RTM_NEWNSID
+       RTM_GETNSID = 90,
+#define RTM_GETNSID RTM_GETNSID
+
        __RTM_MAX,
 #define RTM_MAX                (((__RTM_MAX + 3) & ~3) - 1)
 };
@@ -389,6 +394,8 @@ enum {
 #define RTAX_INITRWND RTAX_INITRWND
        RTAX_QUICKACK,
 #define RTAX_QUICKACK RTAX_QUICKACK
+       RTAX_CC_ALGO,
+#define RTAX_CC_ALGO RTAX_CC_ALGO
        __RTAX_MAX
 };
 
@@ -632,6 +639,7 @@ struct tcamsg {
 /* New extended info filters for IFLA_EXT_MASK */
 #define RTEXT_FILTER_VF                (1 << 0)
 #define RTEXT_FILTER_BRVLAN    (1 << 1)
+#define RTEXT_FILTER_BRVLAN_COMPRESSED (1 << 2)
 
 /* End of information exported to user level */
 
diff --git a/include/linux/tc_act/tc_bpf.h b/include/linux/tc_act/tc_bpf.h
new file mode 100644 (file)
index 0000000..5288bd7
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2015 Jiri Pirko <jiri@resnulli.us>
+ *
+ * This program is free software; you can redistribute 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.
+ */
+
+#ifndef __LINUX_TC_BPF_H
+#define __LINUX_TC_BPF_H
+
+#include <linux/pkt_cls.h>
+
+#define TCA_ACT_BPF 13
+
+struct tc_act_bpf {
+       tc_gen;
+};
+
+enum {
+       TCA_ACT_BPF_UNSPEC,
+       TCA_ACT_BPF_TM,
+       TCA_ACT_BPF_PARMS,
+       TCA_ACT_BPF_OPS_LEN,
+       TCA_ACT_BPF_OPS,
+       __TCA_ACT_BPF_MAX,
+};
+#define TCA_ACT_BPF_MAX (__TCA_ACT_BPF_MAX - 1)
+
+#endif
index 9cc3ec3802118bb4345c6782aa5fe4cb4b2930af..473ff97a41098e358dcb85cbccd9b3d35a9fac40 100644 (file)
@@ -30,6 +30,7 @@ static void print_explain(FILE *f)
        fprintf(f, "                 [ [no]l2miss ] [ [no]l3miss ]\n");
        fprintf(f, "                 [ ageing SECONDS ] [ maxaddress NUMBER ]\n");
        fprintf(f, "                 [ [no]udpcsum ] [ [no]udp6zerocsumtx ] [ [no]udp6zerocsumrx ]\n");
+       fprintf(f, "                 [ gbp ]\n");
        fprintf(f, "\n");
        fprintf(f, "Where: VNI := 0-16777215\n");
        fprintf(f, "       ADDR := { IP_ADDRESS | any }\n");
@@ -68,6 +69,7 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
        __u8 udpcsum = 0;
        __u8 udp6zerocsumtx = 0;
        __u8 udp6zerocsumrx = 0;
+       __u8 gbp = 0;
        int dst_port_set = 0;
        struct ifla_vxlan_port_range range = { 0, 0 };
 
@@ -197,6 +199,8 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
                        udp6zerocsumrx = 1;
                } else if (!matches(*argv, "noudp6zerocsumrx")) {
                        udp6zerocsumrx = 0;
+               } else if (!matches(*argv, "gbp")) {
+                       gbp = 1;
                } else if (matches(*argv, "help") == 0) {
                        explain();
                        return -1;
@@ -268,6 +272,10 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
        if (dstport)
                addattr16(n, 1024, IFLA_VXLAN_PORT, htons(dstport));
 
+       if (gbp)
+               addattr_l(n, 1024, IFLA_VXLAN_GBP, NULL, 0);
+
+
        return 0;
 }
 
@@ -398,6 +406,9 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
        if (tb[IFLA_VXLAN_UDP_ZERO_CSUM6_RX] &&
            rta_getattr_u8(tb[IFLA_VXLAN_UDP_ZERO_CSUM6_RX]))
                fputs("udp6zerocsumrx ", f);
+
+       if (tb[IFLA_VXLAN_GBP])
+               fputs("gbp ", f);
 }
 
 static void vxlan_print_help(struct link_util *lu, int argc, char **argv,
index 5a496a91216fb908a7c3f68e870ea7579ffa7a8a..76d8e36ccc2b05df239e4ed7356b3fb3baf004c0 100644 (file)
@@ -53,6 +53,7 @@ static const char *mx_names[RTAX_MAX+1] = {
        [RTAX_RTO_MIN]  = "rto_min",
        [RTAX_INITRWND] = "initrwnd",
        [RTAX_QUICKACK] = "quickack",
+       [RTAX_CC_ALGO]  = "congctl",
 };
 static void usage(void) __attribute__((noreturn));
 
@@ -80,8 +81,7 @@ static void usage(void)
        fprintf(stderr, "           [ window NUMBER] [ cwnd NUMBER ] [ initcwnd NUMBER ]\n");
        fprintf(stderr, "           [ ssthresh NUMBER ] [ realms REALM ] [ src ADDRESS ]\n");
        fprintf(stderr, "           [ rto_min TIME ] [ hoplimit NUMBER ] [ initrwnd NUMBER ]\n");
-       fprintf(stderr, "           [ features FEATURES ]\n");
-       fprintf(stderr, "           [ quickack BOOL ]\n");
+       fprintf(stderr, "           [ features FEATURES ] [ quickack BOOL ] [ congctl NAME ]\n");
        fprintf(stderr, "TYPE := [ unicast | local | broadcast | multicast | throw |\n");
        fprintf(stderr, "          unreachable | prohibit | blackhole | nat ]\n");
        fprintf(stderr, "TABLE_ID := [ local | main | default | all | NUMBER ]\n");
@@ -536,7 +536,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
                        mxlock = *(unsigned*)RTA_DATA(mxrta[RTAX_LOCK]);
 
                for (i=2; i<= RTAX_MAX; i++) {
-                       unsigned val;
+                       __u32 val;
 
                        if (mxrta[i] == NULL)
                                continue;
@@ -545,10 +545,12 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
                                fprintf(fp, " %s", mx_names[i]);
                        else
                                fprintf(fp, " metric %d", i);
+
                        if (mxlock & (1<<i))
                                fprintf(fp, " lock");
+                       if (i != RTAX_CC_ALGO)
+                               val = rta_getattr_u32(mxrta[i]);
 
-                       val = *(unsigned*)RTA_DATA(mxrta[i]);
                        switch (i) {
                        case RTAX_FEATURES:
                                print_rtax_features(fp, val);
@@ -573,6 +575,10 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
                                        fprintf(fp, " %gs", val/1e3);
                                else
                                        fprintf(fp, " %ums", val);
+                               break;
+                       case RTAX_CC_ALGO:
+                               fprintf(fp, " %s", rta_getattr_str(mxrta[i]));
+                               break;
                        }
                }
        }
@@ -925,6 +931,14 @@ static int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
                        if (quickack != 1 && quickack != 0)
                                invarg("\"quickack\" value should be 0 or 1\n", *argv);
                        rta_addattr32(mxrta, sizeof(mxbuf), RTAX_QUICKACK, quickack);
+               } else if (matches(*argv, "congctl") == 0) {
+                       NEXT_ARG();
+                       if (strcmp(*argv, "lock") == 0) {
+                               mxlock |= 1 << RTAX_CC_ALGO;
+                               NEXT_ARG();
+                       }
+                       rta_addattr_l(mxrta, sizeof(mxbuf), RTAX_CC_ALGO, *argv,
+                                     strlen(*argv));
                } else if (matches(*argv, "rttvar") == 0) {
                        unsigned win;
                        NEXT_ARG();
index 239f76494905690bd764479a091b3cc911a4f548..057125b5aa19df8af35da479e61646a142ec2d25 100644 (file)
@@ -276,6 +276,8 @@ the following additional arguments are supported:
 .BI ageing " SECONDS "
 .R " ] [ "
 .BI maxaddress " NUMBER "
+.R " ] [ "
+.B gbp
 .R " ]"
 
 .in +8
@@ -348,6 +350,49 @@ are entered into the VXLAN device forwarding database.
 .BI maxaddress " NUMBER"
 - specifies the maximum number of FDB entries.
 
+.sp
+.B gbp
+- enables the Group Policy extension (VXLAN-GBP).
+
+.in +4
+Allows to transport group policy context across VXLAN network peers.
+If enabled, includes the mark of a packet in the VXLAN header for outgoing
+packets and fills the packet mark based on the information found in the
+VXLAN header for incomming packets.
+
+Format of upper 16 bits of packet mark (flags);
+
+.in +2
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.br
+|-|-|-|-|-|-|-|-|-|D|-|-|A|-|-|-|
+.br
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+.B D :=
+Don't Learn bit. When set, this bit indicates that the egress
+VTEP MUST NOT learn the source address of the encapsulated frame.
+
+.B A :=
+Indicates that the group policy has already been applied to
+this packet. Policies MUST NOT be applied by devices when the A bit is set.
+.in -2
+
+Format of lower 16 bits of packet mark (policy ID):
+
+.in +2
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.br
+|        Group Policy ID        |
+.br
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in -2
+
+Example:
+  iptables -A OUTPUT [...] -j MARK --set-mark 0x800FF
+
+.in -4
+
 .in -8
 
 .TP
index 89960c1462d8a4b82533635a45a2ad2a1a6cbaa2..2b1583d5a30c50fa576cfa1326f55baf8452a449 100644 (file)
@@ -116,7 +116,9 @@ replace " } "
 .B  features
 .IR FEATURES " ] [ "
 .B  quickack
-.IR BOOL " ]"
+.IR BOOL " ] [ "
+.B  congctl
+.IR NAME " ]"
 
 .ti -8
 .IR TYPE " := [ "
@@ -432,6 +434,21 @@ sysctl is set to 0.
 .BI quickack " BOOL " "(3.11+ only)"
 Enable or disable quick ack for connections to this destination.
 
+.TP
+.BI congctl " NAME " "(3.20+ only)"
+.TP
+.BI "congctl lock" " NAME " "(3.20+ only)"
+Sets a specific TCP congestion control algorithm only for a given destination.
+If not specified, Linux keeps the current global default TCP congestion control
+algorithm, or the one set from the application. If the modifier
+.B lock
+is not used, an application may nevertheless overwrite the suggested congestion
+control algorithm for that destination. If the modifier
+.B lock
+is used, then an application is not allowed to overwrite the specified congestion
+control algorithm for that destination, thus it will be enforced/guaranteed to
+use the proposed algorithm.
+
 .TP
 .BI advmss " NUMBER " "(2.3.15+ only)"
 the MSS ('Maximal Segment Size') to advertise to these
index 9412094fd175461802b862dd620e0afd2f5ed116..d831a1535337def32bb5e410c5982b843f429a4d 100644 (file)
@@ -1,5 +1,5 @@
 TCOBJ= tc.o tc_qdisc.o tc_class.o tc_filter.o tc_util.o \
-       tc_monitor.o m_police.o m_estimator.o m_action.o \
+       tc_monitor.o tc_bpf.o m_police.o m_estimator.o m_action.o \
        m_ematch.o emp_ematch.yacc.o emp_ematch.lex.o
 
 include ../Config
@@ -46,6 +46,7 @@ TCMODULES += m_skbedit.o
 TCMODULES += m_csum.o
 TCMODULES += m_simple.o
 TCMODULES += m_vlan.o
+TCMODULES += m_bpf.o
 TCMODULES += p_ip.o
 TCMODULES += p_icmp.o
 TCMODULES += p_tcp.o
index 48635a70629bf6fd1dbb3e8ed7dba4e85b7569f7..e2af94e3de396dcddd89a3b09c492a49f01deeda 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "utils.h"
 #include "tc_util.h"
+#include "tc_bpf.h"
 
 static void explain(void)
 {
@@ -44,130 +45,6 @@ static void explain(void)
        fprintf(stderr, "NOTE: CLASSID is parsed as hexadecimal input.\n");
 }
 
-static int bpf_parse_string(char *arg, bool from_file, __u16 *bpf_len,
-                           char **bpf_string, bool *need_release,
-                           const char separator)
-{
-       char sp;
-
-       if (from_file) {
-               size_t tmp_len, op_len = sizeof("65535 255 255 4294967295,");
-               char *tmp_string;
-               FILE *fp;
-
-               tmp_len = sizeof("4096,") + BPF_MAXINSNS * op_len;
-               tmp_string = malloc(tmp_len);
-               if (tmp_string == NULL)
-                       return -ENOMEM;
-
-               memset(tmp_string, 0, tmp_len);
-
-               fp = fopen(arg, "r");
-               if (fp == NULL) {
-                       perror("Cannot fopen");
-                       free(tmp_string);
-                       return -ENOENT;
-               }
-
-               if (!fgets(tmp_string, tmp_len, fp)) {
-                       free(tmp_string);
-                       fclose(fp);
-                       return -EIO;
-               }
-
-               fclose(fp);
-
-               *need_release = true;
-               *bpf_string = tmp_string;
-       } else {
-               *need_release = false;
-               *bpf_string = arg;
-       }
-
-       if (sscanf(*bpf_string, "%hu%c", bpf_len, &sp) != 2 ||
-           sp != separator) {
-               if (*need_release)
-                       free(*bpf_string);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int bpf_parse_ops(int argc, char **argv, struct nlmsghdr *n,
-                        bool from_file)
-{
-       char *bpf_string, *token, separator = ',';
-       struct sock_filter bpf_ops[BPF_MAXINSNS];
-       int ret = 0, i = 0;
-       bool need_release;
-       __u16 bpf_len = 0;
-
-       if (argc < 1)
-               return -EINVAL;
-       if (bpf_parse_string(argv[0], from_file, &bpf_len, &bpf_string,
-                            &need_release, separator))
-               return -EINVAL;
-       if (bpf_len == 0 || bpf_len > BPF_MAXINSNS) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       token = bpf_string;
-       while ((token = strchr(token, separator)) && (++token)[0]) {
-               if (i >= bpf_len) {
-                       fprintf(stderr, "Real program length exceeds encoded "
-                               "length parameter!\n");
-                       ret = -EINVAL;
-                       goto out;
-               }
-
-               if (sscanf(token, "%hu %hhu %hhu %u,",
-                          &bpf_ops[i].code, &bpf_ops[i].jt,
-                          &bpf_ops[i].jf, &bpf_ops[i].k) != 4) {
-                       fprintf(stderr, "Error at instruction %d!\n", i);
-                       ret = -EINVAL;
-                       goto out;
-               }
-
-               i++;
-       }
-
-       if (i != bpf_len) {
-               fprintf(stderr, "Parsed program length is less than encoded"
-                       "length parameter!\n");
-               ret = -EINVAL;
-               goto out;
-       }
-
-       addattr_l(n, MAX_MSG, TCA_BPF_OPS_LEN, &bpf_len, sizeof(bpf_len));
-       addattr_l(n, MAX_MSG, TCA_BPF_OPS, &bpf_ops,
-                 bpf_len * sizeof(struct sock_filter));
-out:
-       if (need_release)
-               free(bpf_string);
-
-       return ret;
-}
-
-static void bpf_print_ops(FILE *f, struct rtattr *bpf_ops, __u16 len)
-{
-       struct sock_filter *ops = (struct sock_filter *) RTA_DATA(bpf_ops);
-       int i;
-
-       if (len == 0)
-               return;
-
-       fprintf(f, "bytecode \'%u,", len);
-
-       for (i = 0; i < len - 1; i++)
-               fprintf(f, "%hu %hhu %hhu %u,", ops[i].code, ops[i].jt,
-                       ops[i].jf, ops[i].k);
-
-       fprintf(f, "%hu %hhu %hhu %u\'\n", ops[i].code, ops[i].jt,
-               ops[i].jf, ops[i].k);
-}
-
 static int bpf_parse_opt(struct filter_util *qu, char *handle,
                         int argc, char **argv, struct nlmsghdr *n)
 {
@@ -195,6 +72,10 @@ static int bpf_parse_opt(struct filter_util *qu, char *handle,
        while (argc > 0) {
                if (matches(*argv, "run") == 0) {
                        bool from_file;
+                       struct sock_filter bpf_ops[BPF_MAXINSNS];
+                       __u16 bpf_len;
+                       int ret;
+
                        NEXT_ARG();
                        if (strcmp(*argv, "bytecode-file") == 0) {
                                from_file = true;
@@ -206,10 +87,15 @@ static int bpf_parse_opt(struct filter_util *qu, char *handle,
                                return -1;
                        }
                        NEXT_ARG();
-                       if (bpf_parse_ops(argc, argv, n, from_file)) {
+                       ret = bpf_parse_ops(argc, argv, bpf_ops, from_file);
+                       if (ret < 0) {
                                fprintf(stderr, "Illegal \"bytecode\"\n");
                                return -1;
                        }
+                       bpf_len = ret;
+                       addattr16(n, MAX_MSG, TCA_BPF_OPS_LEN, bpf_len);
+                       addattr_l(n, MAX_MSG, TCA_BPF_OPS, &bpf_ops,
+                                 bpf_len * sizeof(struct sock_filter));
                } else if (matches(*argv, "classid") == 0 ||
                           strcmp(*argv, "flowid") == 0) {
                        unsigned handle;
diff --git a/tc/m_bpf.c b/tc/m_bpf.c
new file mode 100644 (file)
index 0000000..611135e
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * m_bpf.c     BFP based action module
+ *
+ *              This program is free software; you can redistribute 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:     Jiri Pirko <jiri@resnulli.us>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdbool.h>
+#include <linux/tc_act/tc_bpf.h>
+
+#include "utils.h"
+#include "rt_names.h"
+#include "tc_util.h"
+#include "tc_bpf.h"
+
+static void explain(void)
+{
+       fprintf(stderr, "Usage: ... bpf ...\n");
+       fprintf(stderr, "\n");
+       fprintf(stderr, " [inline]:     run bytecode BPF_BYTECODE\n");
+       fprintf(stderr, " [from file]:  run bytecode-file FILE\n");
+       fprintf(stderr, "\n");
+       fprintf(stderr, "Where BPF_BYTECODE := \'s,c t f k,c t f k,c t f k,...\'\n");
+       fprintf(stderr, "      c,t,f,k and s are decimals; s denotes number of 4-tuples\n");
+       fprintf(stderr, "Where FILE points to a file containing the BPF_BYTECODE string\n");
+       fprintf(stderr, "\nACTION_SPEC := ... look at individual actions\n");
+       fprintf(stderr, "NOTE: CLASSID is parsed as hexadecimal input.\n");
+}
+
+static void usage(void)
+{
+       explain();
+       exit(-1);
+}
+
+static int parse_bpf(struct action_util *a, int *argc_p, char ***argv_p,
+                    int tca_id, struct nlmsghdr *n)
+{
+       int argc = *argc_p;
+       char **argv = *argv_p;
+       struct rtattr *tail;
+       struct tc_act_bpf parm = { 0 };
+       struct sock_filter bpf_ops[BPF_MAXINSNS];
+       __u16 bpf_len = 0;
+
+       if (matches(*argv, "bpf") != 0)
+               return -1;
+
+       NEXT_ARG();
+
+       while (argc > 0) {
+               if (matches(*argv, "run") == 0) {
+                       bool from_file;
+                       int ret;
+
+                       NEXT_ARG();
+                       if (strcmp(*argv, "bytecode-file") == 0) {
+                               from_file = true;
+                       } else if (strcmp(*argv, "bytecode") == 0) {
+                               from_file = false;
+                       } else {
+                               fprintf(stderr, "unexpected \"%s\"\n", *argv);
+                               explain();
+                               return -1;
+                       }
+                       NEXT_ARG();
+                       ret = bpf_parse_ops(argc, argv, bpf_ops, from_file);
+                       if (ret < 0) {
+                               fprintf(stderr, "Illegal \"bytecode\"\n");
+                               return -1;
+                       }
+                       bpf_len = ret;
+               } else if (matches(*argv, "help") == 0) {
+                       usage();
+               } else {
+                       break;
+               }
+               argc--;
+               argv++;
+       }
+
+       parm.action = TC_ACT_PIPE;
+       if (argc) {
+               if (matches(*argv, "reclassify") == 0) {
+                       parm.action = TC_ACT_RECLASSIFY;
+                       NEXT_ARG();
+               } else if (matches(*argv, "pipe") == 0) {
+                       parm.action = TC_ACT_PIPE;
+                       NEXT_ARG();
+               } else if (matches(*argv, "drop") == 0 ||
+                          matches(*argv, "shot") == 0) {
+                       parm.action = TC_ACT_SHOT;
+                       NEXT_ARG();
+               } else if (matches(*argv, "continue") == 0) {
+                       parm.action = TC_ACT_UNSPEC;
+                       NEXT_ARG();
+               } else if (matches(*argv, "pass") == 0) {
+                       parm.action = TC_ACT_OK;
+                       NEXT_ARG();
+               }
+       }
+
+       if (argc) {
+               if (matches(*argv, "index") == 0) {
+                       NEXT_ARG();
+                       if (get_u32(&parm.index, *argv, 10)) {
+                               fprintf(stderr, "bpf: Illegal \"index\"\n");
+                               return -1;
+                       }
+                       argc--;
+                       argv++;
+               }
+       }
+
+       if (!bpf_len) {
+               fprintf(stderr, "bpf: Bytecode needs to be passed\n");
+               explain();
+               return -1;
+       }
+
+       tail = NLMSG_TAIL(n);
+       addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+       addattr_l(n, MAX_MSG, TCA_ACT_BPF_PARMS, &parm, sizeof(parm));
+       addattr16(n, MAX_MSG, TCA_ACT_BPF_OPS_LEN, bpf_len);
+       addattr_l(n, MAX_MSG, TCA_ACT_BPF_OPS, &bpf_ops,
+                 bpf_len * sizeof(struct sock_filter));
+       tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
+
+       *argc_p = argc;
+       *argv_p = argv;
+       return 0;
+}
+
+static int print_bpf(struct action_util *au, FILE *f, struct rtattr *arg)
+{
+       struct rtattr *tb[TCA_ACT_BPF_MAX + 1];
+       struct tc_act_bpf *parm;
+
+       if (arg == NULL)
+               return -1;
+
+       parse_rtattr_nested(tb, TCA_ACT_BPF_MAX, arg);
+
+       if (!tb[TCA_ACT_BPF_PARMS]) {
+               fprintf(f, "[NULL bpf parameters]");
+               return -1;
+       }
+       parm = RTA_DATA(tb[TCA_ACT_BPF_PARMS]);
+
+       fprintf(f, " bpf ");
+
+       if (tb[TCA_ACT_BPF_OPS] && tb[TCA_ACT_BPF_OPS_LEN])
+               bpf_print_ops(f, tb[TCA_ACT_BPF_OPS],
+                             rta_getattr_u16(tb[TCA_ACT_BPF_OPS_LEN]));
+
+       fprintf(f, "\n\tindex %d ref %d bind %d", parm->index, parm->refcnt,
+               parm->bindcnt);
+
+       if (show_stats) {
+               if (tb[TCA_ACT_BPF_TM]) {
+                       struct tcf_t *tm = RTA_DATA(tb[TCA_ACT_BPF_TM]);
+                       print_tm(f, tm);
+               }
+       }
+
+       fprintf(f, "\n ");
+
+       return 0;
+}
+
+struct action_util bpf_action_util = {
+       .id = "bpf",
+       .parse_aopt = parse_bpf,
+       .print_aopt = print_bpf,
+};
diff --git a/tc/tc_bpf.c b/tc/tc_bpf.c
new file mode 100644 (file)
index 0000000..c6901d6
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * tc_bpf.c    BPF common code
+ *
+ *             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:    Daniel Borkmann <dborkman@redhat.com>
+ *             Jiri Pirko <jiri@resnulli.us>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <linux/filter.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include "utils.h"
+#include "tc_util.h"
+#include "tc_bpf.h"
+
+int bpf_parse_string(char *arg, bool from_file, __u16 *bpf_len,
+                    char **bpf_string, bool *need_release,
+                    const char separator)
+{
+       char sp;
+
+       if (from_file) {
+               size_t tmp_len, op_len = sizeof("65535 255 255 4294967295,");
+               char *tmp_string;
+               FILE *fp;
+
+               tmp_len = sizeof("4096,") + BPF_MAXINSNS * op_len;
+               tmp_string = malloc(tmp_len);
+               if (tmp_string == NULL)
+                       return -ENOMEM;
+
+               memset(tmp_string, 0, tmp_len);
+
+               fp = fopen(arg, "r");
+               if (fp == NULL) {
+                       perror("Cannot fopen");
+                       free(tmp_string);
+                       return -ENOENT;
+               }
+
+               if (!fgets(tmp_string, tmp_len, fp)) {
+                       free(tmp_string);
+                       fclose(fp);
+                       return -EIO;
+               }
+
+               fclose(fp);
+
+               *need_release = true;
+               *bpf_string = tmp_string;
+       } else {
+               *need_release = false;
+               *bpf_string = arg;
+       }
+
+       if (sscanf(*bpf_string, "%hu%c", bpf_len, &sp) != 2 ||
+           sp != separator) {
+               if (*need_release)
+                       free(*bpf_string);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int bpf_parse_ops(int argc, char **argv, struct sock_filter *bpf_ops,
+                 bool from_file)
+{
+       char *bpf_string, *token, separator = ',';
+       int ret = 0, i = 0;
+       bool need_release;
+       __u16 bpf_len = 0;
+
+       if (argc < 1)
+               return -EINVAL;
+       if (bpf_parse_string(argv[0], from_file, &bpf_len, &bpf_string,
+                            &need_release, separator))
+               return -EINVAL;
+       if (bpf_len == 0 || bpf_len > BPF_MAXINSNS) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       token = bpf_string;
+       while ((token = strchr(token, separator)) && (++token)[0]) {
+               if (i >= bpf_len) {
+                       fprintf(stderr, "Real program length exceeds encoded "
+                               "length parameter!\n");
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               if (sscanf(token, "%hu %hhu %hhu %u,",
+                          &bpf_ops[i].code, &bpf_ops[i].jt,
+                          &bpf_ops[i].jf, &bpf_ops[i].k) != 4) {
+                       fprintf(stderr, "Error at instruction %d!\n", i);
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               i++;
+       }
+
+       if (i != bpf_len) {
+               fprintf(stderr, "Parsed program length is less than encoded"
+                       "length parameter!\n");
+               ret = -EINVAL;
+               goto out;
+       }
+       ret = bpf_len;
+
+out:
+       if (need_release)
+               free(bpf_string);
+
+       return ret;
+}
+
+void bpf_print_ops(FILE *f, struct rtattr *bpf_ops, __u16 len)
+{
+       struct sock_filter *ops = (struct sock_filter *) RTA_DATA(bpf_ops);
+       int i;
+
+       if (len == 0)
+               return;
+
+       fprintf(f, "bytecode \'%u,", len);
+
+       for (i = 0; i < len - 1; i++)
+               fprintf(f, "%hu %hhu %hhu %u,", ops[i].code, ops[i].jt,
+                       ops[i].jf, ops[i].k);
+
+       fprintf(f, "%hu %hhu %hhu %u\'\n", ops[i].code, ops[i].jt,
+               ops[i].jf, ops[i].k);
+}
diff --git a/tc/tc_bpf.h b/tc/tc_bpf.h
new file mode 100644 (file)
index 0000000..08cca92
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * tc_bpf.h    BPF common code
+ *
+ *             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:    Daniel Borkmann <dborkman@redhat.com>
+ *             Jiri Pirko <jiri@resnulli.us>
+ */
+
+#ifndef _TC_BPF_H_
+#define _TC_BPF_H_ 1
+
+#include <stdio.h>
+#include <linux/filter.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+int bpf_parse_string(char *arg, bool from_file, __u16 *bpf_len,
+                    char **bpf_string, bool *need_release,
+                    const char separator);
+int bpf_parse_ops(int argc, char **argv, struct sock_filter *bpf_ops,
+                 bool from_file);
+void bpf_print_ops(FILE *f, struct rtattr *bpf_ops, __u16 len);
+
+#endif