Merge branch 'master' into net-next

This commit is contained in:
Stephen Hemminger 2017-11-28 09:53:28 -08:00
commit f6351157b9
144 changed files with 1133 additions and 588 deletions

View File

@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
# Top level Makefile for iproute2 # Top level Makefile for iproute2
ifeq ($(VERBOSE),0) ifeq ($(VERBOSE),0)

View File

@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
BROBJ = bridge.o fdb.o monitor.o link.o mdb.o vlan.o BROBJ = bridge.o fdb.o monitor.o link.o mdb.o vlan.o
include ../config.mk include ../config.mk

View File

@ -1,3 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0 */
#define MDB_RTA(r) \ #define MDB_RTA(r) \
((struct rtattr *)(((char *)(r)) + RTA_ALIGN(sizeof(struct br_mdb_entry)))) ((struct rtattr *)(((char *)(r)) + RTA_ALIGN(sizeof(struct br_mdb_entry))))

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* /*
* Get/set/delete bridge with netlink * Get/set/delete bridge with netlink
* *

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* /*
* Get/set/delete fdb table with netlink * Get/set/delete fdb table with netlink
* *

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* /*
* Get mdb table with netlink * Get mdb table with netlink
*/ */

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>

1
configure vendored
View File

@ -1,4 +1,5 @@
#! /bin/bash #! /bin/bash
# SPDX-License-Identifier: GPL-2.0
# This is not an autoconf generated configure # This is not an autoconf generated configure
# #
INCLUDE=${1:-"$PWD/include"} INCLUDE=${1:-"$PWD/include"}

View File

@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
include ../config.mk include ../config.mk
ifeq ($(HAVE_MNL),y) ifeq ($(HAVE_MNL),y)

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include "../../include/bpf_api.h" #include "../../include/bpf_api.h"
#define ENTRY_INIT 3 #define ENTRY_INIT 3

View File

@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
GENLOBJ=genl.o GENLOBJ=genl.o
include ../config.mk include ../config.mk

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _TC_UTIL_H_ #ifndef _TC_UTIL_H_
#define _TC_UTIL_H_ 1 #define _TC_UTIL_H_ 1

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* /*
* This file creates a dummy version of dynamic loading * This file creates a dummy version of dynamic loading
* for environments where dynamic linking * for environments where dynamic linking

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __BPF_API__ #ifndef __BPF_API__
#define __BPF_API__ #define __BPF_API__

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __BPF_ELF__ #ifndef __BPF_ELF__
#define __BPF_ELF__ #define __BPF_ELF__

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __BPF_SCM__ #ifndef __BPF_SCM__
#define __BPF_SCM__ #define __BPF_SCM__

View File

@ -56,13 +56,29 @@ struct bpf_cfg_ops {
void (*ebpf_cb)(void *nl, int fd, const char *annotation); void (*ebpf_cb)(void *nl, int fd, const char *annotation);
}; };
enum bpf_mode {
CBPF_BYTECODE,
CBPF_FILE,
EBPF_OBJECT,
EBPF_PINNED,
BPF_MODE_MAX,
};
struct bpf_cfg_in { struct bpf_cfg_in {
const char *object; const char *object;
const char *section; const char *section;
const char *uds; const char *uds;
enum bpf_prog_type type;
enum bpf_mode mode;
__u32 ifindex;
bool verbose;
int argc; int argc;
char **argv; char **argv;
struct sock_filter *ops; struct sock_filter opcodes[BPF_MAXINSNS];
union {
int n_opcodes;
int prog_fd;
};
}; };
/* ALU ops on registers, bpf_add|sub|...: dst_reg += src_reg */ /* ALU ops on registers, bpf_add|sub|...: dst_reg += src_reg */
@ -244,8 +260,11 @@ struct bpf_cfg_in {
.off = 0, \ .off = 0, \
.imm = 0 }) .imm = 0 })
int bpf_parse_common(enum bpf_prog_type type, struct bpf_cfg_in *cfg, int bpf_parse_common(struct bpf_cfg_in *cfg, const struct bpf_cfg_ops *ops);
const struct bpf_cfg_ops *ops, void *nl); int bpf_load_common(struct bpf_cfg_in *cfg, const struct bpf_cfg_ops *ops,
void *nl);
int bpf_parse_and_load_common(struct bpf_cfg_in *cfg,
const struct bpf_cfg_ops *ops, void *nl);
const char *bpf_prog_to_default_section(enum bpf_prog_type type); const char *bpf_prog_to_default_section(enum bpf_prog_type type);

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __COLOR_H__ #ifndef __COLOR_H__
#define __COLOR_H__ 1 #define __COLOR_H__ 1

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* /*
* Stub dlfcn implementation for systems that lack shared library support * Stub dlfcn implementation for systems that lack shared library support
* but obviously can still reference compiled-in symbols. * but obviously can still reference compiled-in symbols.

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _IP6TABLES_USER_H #ifndef _IP6TABLES_USER_H
#define _IP6TABLES_USER_H #define _IP6TABLES_USER_H

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _IPTABLES_USER_H #ifndef _IPTABLES_USER_H
#define _IPTABLES_USER_H #define _IPTABLES_USER_H

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef IPTABLES_INTERNAL_H #ifndef IPTABLES_INTERNAL_H
#define IPTABLES_INTERNAL_H 1 #define IPTABLES_INTERNAL_H 1

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __LIBGENL_H__ #ifndef __LIBGENL_H__
#define __LIBGENL_H__ #define __LIBGENL_H__

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* This is the userspace/kernel interface for Generic IP Chains, /* This is the userspace/kernel interface for Generic IP Chains,
required for libc6. */ required for libc6. */
#ifndef _FWCHAINS_KERNEL_HEADERS_H #ifndef _FWCHAINS_KERNEL_HEADERS_H

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LIBIP6TC_H #ifndef _LIBIP6TC_H
#define _LIBIP6TC_H #define _LIBIP6TC_H
/* Library which manipulates firewall rules. Version 0.2. */ /* Library which manipulates firewall rules. Version 0.2. */

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LIBIPTC_H #ifndef _LIBIPTC_H
#define _LIBIPTC_H #define _LIBIPTC_H
/* Library which manipulates filtering rules. */ /* Library which manipulates filtering rules. */

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LIBXTC_H #ifndef _LIBXTC_H
#define _LIBXTC_H #define _LIBXTC_H
/* Library which manipulates filtering rules. */ /* Library which manipulates filtering rules. */

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LIBXTC_SHARED_H #ifndef _LIBXTC_SHARED_H
#define _LIBXTC_SHARED_H 1 #define _LIBXTC_SHARED_H 1

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __LIBNETLINK_H__ #ifndef __LIBNETLINK_H__
#define __LIBNETLINK_H__ 1 #define __LIBNETLINK_H__ 1

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __LIST_H__ #ifndef __LIST_H__
#define __LIST_H__ 1 #define __LIST_H__ 1
/* List and hash list stuff from kernel */ /* List and hash list stuff from kernel */

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __LL_MAP_H__ #ifndef __LL_MAP_H__
#define __LL_MAP_H__ 1 #define __LL_MAP_H__ 1

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef DB_NAMES_H_ #ifndef DB_NAMES_H_
#define DB_NAMES_H_ 1 #define DB_NAMES_H_ 1

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __NAMESPACE_H__ #ifndef __NAMESPACE_H__
#define __NAMESPACE_H__ 1 #define __NAMESPACE_H__ 1

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef RT_NAMES_H_ #ifndef RT_NAMES_H_
#define RT_NAMES_H_ 1 #define RT_NAMES_H_ 1

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __RTM_MAP_H__ #ifndef __RTM_MAP_H__
#define __RTM_MAP_H__ 1 #define __RTM_MAP_H__ 1

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __UTILS_H__ #ifndef __UTILS_H__
#define __UTILS_H__ 1 #define __UTILS_H__ 1
@ -88,6 +89,8 @@ int get_prefix(inet_prefix *dst, char *arg, int family);
int mask2bits(__u32 netmask); int mask2bits(__u32 netmask);
int get_addr_ila(__u64 *val, const char *arg); int get_addr_ila(__u64 *val, const char *arg);
int read_prop(const char *dev, char *prop, long *value);
int parse_percent(double *val, const char *str);
int get_hex(char c); int get_hex(char c);
int get_integer(int *val, const char *arg, int base); int get_integer(int *val, const char *arg, int base);
int get_unsigned(unsigned *val, const char *arg, int base); int get_unsigned(unsigned *val, const char *arg, int base);

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _XTABLES_INTERNAL_H #ifndef _XTABLES_INTERNAL_H
#define _XTABLES_INTERNAL_H 1 #define _XTABLES_INTERNAL_H 1

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _XTABLES_H #ifndef _XTABLES_H
#define _XTABLES_H #define _XTABLES_H

View File

@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o ipnetns.o \ IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o ipnetns.o \
rtm_map.o iptunnel.o ip6tunnel.o tunnel.o ipneigh.o ipntable.o iplink.o \ rtm_map.o iptunnel.o ip6tunnel.o tunnel.o ipneigh.o ipntable.o iplink.o \
ipmaddr.o ipmonitor.o ipmroute.o ipprefix.o iptuntap.o iptoken.o \ ipmaddr.o ipmonitor.o ipmroute.o ipprefix.o iptuntap.o iptoken.o \

View File

@ -1,4 +1,5 @@
#! /bin/bash #! /bin/bash
# SPDX-License-Identifier: GPL-2.0
CheckForwarding () { CheckForwarding () {
local sbase fwd local sbase fwd

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ILA_COMMON_H_ #ifndef _ILA_COMMON_H_
#define _ILA_COMMON_H_ #define _ILA_COMMON_H_

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _IP_COMMON_H_ #ifndef _IP_COMMON_H_
#define _IP_COMMON_H_ #define _IP_COMMON_H_

View File

@ -631,8 +631,8 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
bool offload = strcmp(*argv, "xdpoffload") == 0; bool offload = strcmp(*argv, "xdpoffload") == 0;
NEXT_ARG(); NEXT_ARG();
if (xdp_parse(&argc, &argv, req, generic, drv, if (xdp_parse(&argc, &argv, req, dev_index,
offload)) generic, drv, offload))
exit(-1); exit(-1);
} else if (strcmp(*argv, "netns") == 0) { } else if (strcmp(*argv, "netns") == 0) {
NEXT_ARG(); NEXT_ARG();

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>

View File

@ -345,7 +345,7 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
return -1; return -1;
} }
if (!metadata && !VXLAN_ATTRSET(attrs, IFLA_VXLAN_ID)) { if (!metadata && !VXLAN_ATTRSET(attrs, IFLA_VXLAN_ID) && !set_op) {
fprintf(stderr, "vxlan: missing virtual network identifier\n"); fprintf(stderr, "vxlan: missing virtual network identifier\n");
return -1; return -1;
} }
@ -367,7 +367,8 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
"Use 'dstport 0' to get default and quiet this message\n"); "Use 'dstport 0' to get default and quiet this message\n");
} }
addattr32(n, 1024, IFLA_VXLAN_ID, vni); if (VXLAN_ATTRSET(attrs, IFLA_VXLAN_ID))
addattr32(n, 1024, IFLA_VXLAN_ID, vni);
if (gaddr) if (gaddr)
addattr_l(n, 1024, IFLA_VXLAN_GROUP, &gaddr, 4); addattr_l(n, 1024, IFLA_VXLAN_GROUP, &gaddr, 4);
else if (daddr) else if (daddr)

View File

@ -48,10 +48,11 @@ static int xdp_delete(struct xdp_req *xdp)
return 0; return 0;
} }
int xdp_parse(int *argc, char ***argv, struct iplink_req *req, bool generic, int xdp_parse(int *argc, char ***argv, struct iplink_req *req, __u32 ifindex,
bool drv, bool offload) bool generic, bool drv, bool offload)
{ {
struct bpf_cfg_in cfg = { struct bpf_cfg_in cfg = {
.type = BPF_PROG_TYPE_XDP,
.argc = *argc, .argc = *argc,
.argv = *argv, .argv = *argv,
}; };
@ -59,6 +60,12 @@ int xdp_parse(int *argc, char ***argv, struct iplink_req *req, bool generic,
.req = req, .req = req,
}; };
if (offload) {
if (!ifindex)
incomplete_command();
cfg.ifindex = ifindex;
}
if (!force) if (!force)
xdp.flags |= XDP_FLAGS_UPDATE_IF_NOEXIST; xdp.flags |= XDP_FLAGS_UPDATE_IF_NOEXIST;
if (generic) if (generic)
@ -74,7 +81,7 @@ int xdp_parse(int *argc, char ***argv, struct iplink_req *req, bool generic,
return xdp_delete(&xdp); return xdp_delete(&xdp);
} }
if (bpf_parse_common(BPF_PROG_TYPE_XDP, &cfg, &bpf_cb_ops, &xdp)) if (bpf_parse_and_load_common(&cfg, &bpf_cb_ops, &xdp))
return -1; return -1;
*argc = cfg.argc; *argc = cfg.argc;

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#define _ATFILE_SOURCE #define _ATFILE_SOURCE
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>

View File

@ -886,6 +886,7 @@ static int lwt_parse_bpf(struct rtattr *rta, size_t len,
int attr, const enum bpf_prog_type bpf_type) int attr, const enum bpf_prog_type bpf_type)
{ {
struct bpf_cfg_in cfg = { struct bpf_cfg_in cfg = {
.type = bpf_type,
.argc = *argcp, .argc = *argcp,
.argv = *argvp, .argv = *argvp,
}; };
@ -897,7 +898,7 @@ static int lwt_parse_bpf(struct rtattr *rta, size_t len,
int err; int err;
nest = rta_nest(rta, len, attr); nest = rta_nest(rta, len, attr);
err = bpf_parse_common(bpf_type, &cfg, &bpf_cb_ops, &x); err = bpf_parse_and_load_common(&cfg, &bpf_cb_ops, &x);
if (err < 0) { if (err < 0) {
fprintf(stderr, "Failed to parse eBPF program: %s\n", fprintf(stderr, "Failed to parse eBPF program: %s\n",
strerror(-err)); strerror(-err));

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __LWTUNNEL_H__ #ifndef __LWTUNNEL_H__
#define __LETUNNEL_H__ 1 #define __LETUNNEL_H__ 1

View File

@ -223,38 +223,6 @@ static int do_del(int argc, char **argv)
return tap_del_ioctl(&ifr); return tap_del_ioctl(&ifr);
} }
static int read_prop(char *dev, char *prop, long *value)
{
char fname[IFNAMSIZ+25], buf[80], *endp;
ssize_t len;
int fd;
long result;
sprintf(fname, "/sys/class/net/%s/%s", dev, prop);
fd = open(fname, O_RDONLY);
if (fd < 0) {
if (strcmp(prop, "tun_flags"))
fprintf(stderr, "open %s: %s\n", fname,
strerror(errno));
return -1;
}
len = read(fd, buf, sizeof(buf)-1);
close(fd);
if (len < 0) {
fprintf(stderr, "read %s: %s", fname, strerror(errno));
return -1;
}
buf[len] = 0;
result = strtol(buf, &endp, 0);
if (*endp != '\n') {
fprintf(stderr, "Failed to parse %s\n", fname);
return -1;
}
*value = result;
return 0;
}
static void print_flags(long flags) static void print_flags(long flags)
{ {
if (flags & IFF_TUN) if (flags & IFF_TUN)

View File

@ -276,7 +276,8 @@ get_failed:
if (uval > 255) if (uval > 255)
invarg("TTL must be <= 255\n", *argv); invarg("TTL must be <= 255\n", *argv);
ttl = uval; ttl = uval;
} } else
ttl = 0;
} else if (!matches(*argv, "tos") || } else if (!matches(*argv, "tos") ||
!matches(*argv, "tclass") || !matches(*argv, "tclass") ||
!matches(*argv, "dsfield")) { !matches(*argv, "dsfield")) {

View File

@ -372,7 +372,7 @@ get_failed:
} else { } else {
__u8 uval; __u8 uval;
if (get_u8(&uval, *argv, 0) < -1) if (get_u8(&uval, *argv, 0))
invarg("invalid ELIM", *argv); invarg("invalid ELIM", *argv);
encap_limit = uval; encap_limit = uval;
flags &= ~IP6_TNL_F_IGN_ENCAP_LIMIT; flags &= ~IP6_TNL_F_IGN_ENCAP_LIMIT;

View File

@ -1,4 +1,5 @@
#! /bin/sh #! /bin/sh
# SPDX-License-Identifier: GPL-2.0
if [ -z "$*" ] ; then if [ -z "$*" ] ; then
exec ip -4 ro flush scope global type unicast exec ip -4 ro flush scope global type unicast

View File

@ -1,5 +1,5 @@
#!/bin/sh #!/bin/sh
#$Id$ # SPDX-License-Identifier: GPL-2.0
# #
# Script created by: Stephen R. van den Berg <srb@cuci.nl>, 1999/04/18 # Script created by: Stephen R. van den Berg <srb@cuci.nl>, 1999/04/18

View File

@ -1,4 +1,5 @@
#! /bin/bash #! /bin/bash
# SPDX-License-Identifier: GPL-2.0
exec tr "[\\\\]" "[ exec tr "[\\\\]" "[
]" ]"

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* /*
* This file creates a dummy version of dynamic loading * This file creates a dummy version of dynamic loading
* for environments where dynamic linking * for environments where dynamic linking

View File

@ -1,10 +1,11 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __XDP__ #ifndef __XDP__
#define __XDP__ #define __XDP__
#include "utils.h" #include "utils.h"
int xdp_parse(int *argc, char ***argv, struct iplink_req *req, bool generic, int xdp_parse(int *argc, char ***argv, struct iplink_req *req, __u32 ifindex,
bool drv, bool offload); bool generic, bool drv, bool offload);
void xdp_dump(FILE *fp, struct rtattr *tb, bool link, bool details); void xdp_dump(FILE *fp, struct rtattr *tb, bool link, bool details);
#endif /* __XDP__ */ #endif /* __XDP__ */

View File

@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
include ../config.mk include ../config.mk
CFLAGS += -fPIC CFLAGS += -fPIC

155
lib/bpf.c
View File

@ -113,10 +113,10 @@ const char *bpf_prog_to_default_section(enum bpf_prog_type type)
#ifdef HAVE_ELF #ifdef HAVE_ELF
static int bpf_obj_open(const char *path, enum bpf_prog_type type, static int bpf_obj_open(const char *path, enum bpf_prog_type type,
const char *sec, bool verbose); const char *sec, __u32 ifindex, bool verbose);
#else #else
static int bpf_obj_open(const char *path, enum bpf_prog_type type, static int bpf_obj_open(const char *path, enum bpf_prog_type type,
const char *sec, bool verbose) const char *sec, __u32 ifindex, bool verbose)
{ {
fprintf(stderr, "No ELF library support compiled in.\n"); fprintf(stderr, "No ELF library support compiled in.\n");
errno = ENOSYS; errno = ENOSYS;
@ -805,16 +805,7 @@ static int bpf_obj_pinned(const char *pathname, enum bpf_prog_type type)
return prog_fd; return prog_fd;
} }
enum bpf_mode { static int bpf_do_parse(struct bpf_cfg_in *cfg, const bool *opt_tbl)
CBPF_BYTECODE,
CBPF_FILE,
EBPF_OBJECT,
EBPF_PINNED,
BPF_MODE_MAX,
};
static int bpf_parse(enum bpf_prog_type *type, enum bpf_mode *mode,
struct bpf_cfg_in *cfg, const bool *opt_tbl)
{ {
const char *file, *section, *uds_name; const char *file, *section, *uds_name;
bool verbose = false; bool verbose = false;
@ -827,20 +818,20 @@ static int bpf_parse(enum bpf_prog_type *type, enum bpf_mode *mode,
if (opt_tbl[CBPF_BYTECODE] && if (opt_tbl[CBPF_BYTECODE] &&
(matches(*argv, "bytecode") == 0 || (matches(*argv, "bytecode") == 0 ||
strcmp(*argv, "bc") == 0)) { strcmp(*argv, "bc") == 0)) {
*mode = CBPF_BYTECODE; cfg->mode = CBPF_BYTECODE;
} else if (opt_tbl[CBPF_FILE] && } else if (opt_tbl[CBPF_FILE] &&
(matches(*argv, "bytecode-file") == 0 || (matches(*argv, "bytecode-file") == 0 ||
strcmp(*argv, "bcf") == 0)) { strcmp(*argv, "bcf") == 0)) {
*mode = CBPF_FILE; cfg->mode = CBPF_FILE;
} else if (opt_tbl[EBPF_OBJECT] && } else if (opt_tbl[EBPF_OBJECT] &&
(matches(*argv, "object-file") == 0 || (matches(*argv, "object-file") == 0 ||
strcmp(*argv, "obj") == 0)) { strcmp(*argv, "obj") == 0)) {
*mode = EBPF_OBJECT; cfg->mode = EBPF_OBJECT;
} else if (opt_tbl[EBPF_PINNED] && } else if (opt_tbl[EBPF_PINNED] &&
(matches(*argv, "object-pinned") == 0 || (matches(*argv, "object-pinned") == 0 ||
matches(*argv, "pinned") == 0 || matches(*argv, "pinned") == 0 ||
matches(*argv, "fd") == 0)) { matches(*argv, "fd") == 0)) {
*mode = EBPF_PINNED; cfg->mode = EBPF_PINNED;
} else { } else {
fprintf(stderr, "What mode is \"%s\"?\n", *argv); fprintf(stderr, "What mode is \"%s\"?\n", *argv);
return -1; return -1;
@ -848,11 +839,11 @@ static int bpf_parse(enum bpf_prog_type *type, enum bpf_mode *mode,
NEXT_ARG(); NEXT_ARG();
file = section = uds_name = NULL; file = section = uds_name = NULL;
if (*mode == EBPF_OBJECT || *mode == EBPF_PINNED) { if (cfg->mode == EBPF_OBJECT || cfg->mode == EBPF_PINNED) {
file = *argv; file = *argv;
NEXT_ARG_FWD(); NEXT_ARG_FWD();
if (*type == BPF_PROG_TYPE_UNSPEC) { if (cfg->type == BPF_PROG_TYPE_UNSPEC) {
if (argc > 0 && matches(*argv, "type") == 0) { if (argc > 0 && matches(*argv, "type") == 0) {
NEXT_ARG(); NEXT_ARG();
for (i = 0; i < ARRAY_SIZE(__bpf_prog_meta); for (i = 0; i < ARRAY_SIZE(__bpf_prog_meta);
@ -861,30 +852,30 @@ static int bpf_parse(enum bpf_prog_type *type, enum bpf_mode *mode,
continue; continue;
if (!matches(*argv, if (!matches(*argv,
__bpf_prog_meta[i].type)) { __bpf_prog_meta[i].type)) {
*type = i; cfg->type = i;
break; break;
} }
} }
if (*type == BPF_PROG_TYPE_UNSPEC) { if (cfg->type == BPF_PROG_TYPE_UNSPEC) {
fprintf(stderr, "What type is \"%s\"?\n", fprintf(stderr, "What type is \"%s\"?\n",
*argv); *argv);
return -1; return -1;
} }
NEXT_ARG_FWD(); NEXT_ARG_FWD();
} else { } else {
*type = BPF_PROG_TYPE_SCHED_CLS; cfg->type = BPF_PROG_TYPE_SCHED_CLS;
} }
} }
section = bpf_prog_to_default_section(*type); section = bpf_prog_to_default_section(cfg->type);
if (argc > 0 && matches(*argv, "section") == 0) { if (argc > 0 && matches(*argv, "section") == 0) {
NEXT_ARG(); NEXT_ARG();
section = *argv; section = *argv;
NEXT_ARG_FWD(); NEXT_ARG_FWD();
} }
if (__bpf_prog_meta[*type].may_uds_export) { if (__bpf_prog_meta[cfg->type].may_uds_export) {
uds_name = getenv(BPF_ENV_UDS); uds_name = getenv(BPF_ENV_UDS);
if (argc > 0 && !uds_name && if (argc > 0 && !uds_name &&
matches(*argv, "export") == 0) { matches(*argv, "export") == 0) {
@ -902,53 +893,63 @@ static int bpf_parse(enum bpf_prog_type *type, enum bpf_mode *mode,
PREV_ARG(); PREV_ARG();
} }
if (*mode == CBPF_BYTECODE || *mode == CBPF_FILE) if (cfg->mode == CBPF_BYTECODE || cfg->mode == CBPF_FILE) {
ret = bpf_ops_parse(argc, argv, cfg->ops, *mode == CBPF_FILE); ret = bpf_ops_parse(argc, argv, cfg->opcodes,
else if (*mode == EBPF_OBJECT) cfg->mode == CBPF_FILE);
ret = bpf_obj_open(file, *type, section, verbose); cfg->n_opcodes = ret;
else if (*mode == EBPF_PINNED) } else if (cfg->mode == EBPF_OBJECT) {
ret = bpf_obj_pinned(file, *type); ret = 0; /* program will be loaded by load stage */
else } else if (cfg->mode == EBPF_PINNED) {
ret = bpf_obj_pinned(file, cfg->type);
cfg->prog_fd = ret;
} else {
return -1; return -1;
}
cfg->object = file; cfg->object = file;
cfg->section = section; cfg->section = section;
cfg->uds = uds_name; cfg->uds = uds_name;
cfg->argc = argc; cfg->argc = argc;
cfg->argv = argv; cfg->argv = argv;
cfg->verbose = verbose;
return ret; return ret;
} }
static int bpf_parse_opt_tbl(enum bpf_prog_type type, struct bpf_cfg_in *cfg, static int bpf_do_load(struct bpf_cfg_in *cfg)
const struct bpf_cfg_ops *ops, void *nl, {
const bool *opt_tbl) if (cfg->mode == EBPF_OBJECT) {
cfg->prog_fd = bpf_obj_open(cfg->object, cfg->type,
cfg->section, cfg->ifindex,
cfg->verbose);
return cfg->prog_fd;
}
return 0;
}
int bpf_load_common(struct bpf_cfg_in *cfg, const struct bpf_cfg_ops *ops,
void *nl)
{ {
struct sock_filter opcodes[BPF_MAXINSNS];
char annotation[256]; char annotation[256];
enum bpf_mode mode;
int ret; int ret;
cfg->ops = opcodes; ret = bpf_do_load(cfg);
ret = bpf_parse(&type, &mode, cfg, opt_tbl);
cfg->ops = NULL;
if (ret < 0) if (ret < 0)
return ret; return ret;
if (mode == CBPF_BYTECODE || mode == CBPF_FILE) if (cfg->mode == CBPF_BYTECODE || cfg->mode == CBPF_FILE)
ops->cbpf_cb(nl, opcodes, ret); ops->cbpf_cb(nl, cfg->opcodes, cfg->n_opcodes);
if (mode == EBPF_OBJECT || mode == EBPF_PINNED) { if (cfg->mode == EBPF_OBJECT || cfg->mode == EBPF_PINNED) {
snprintf(annotation, sizeof(annotation), "%s:[%s]", snprintf(annotation, sizeof(annotation), "%s:[%s]",
basename(cfg->object), mode == EBPF_PINNED ? basename(cfg->object), cfg->mode == EBPF_PINNED ?
"*fsobj" : cfg->section); "*fsobj" : cfg->section);
ops->ebpf_cb(nl, ret, annotation); ops->ebpf_cb(nl, cfg->prog_fd, annotation);
} }
return 0; return 0;
} }
int bpf_parse_common(enum bpf_prog_type type, struct bpf_cfg_in *cfg, int bpf_parse_common(struct bpf_cfg_in *cfg, const struct bpf_cfg_ops *ops)
const struct bpf_cfg_ops *ops, void *nl)
{ {
bool opt_tbl[BPF_MODE_MAX] = {}; bool opt_tbl[BPF_MODE_MAX] = {};
@ -962,12 +963,23 @@ int bpf_parse_common(enum bpf_prog_type type, struct bpf_cfg_in *cfg,
opt_tbl[EBPF_PINNED] = true; opt_tbl[EBPF_PINNED] = true;
} }
return bpf_parse_opt_tbl(type, cfg, ops, nl, opt_tbl); return bpf_do_parse(cfg, opt_tbl);
}
int bpf_parse_and_load_common(struct bpf_cfg_in *cfg,
const struct bpf_cfg_ops *ops, void *nl)
{
int ret;
ret = bpf_parse_common(cfg, ops);
if (ret < 0)
return ret;
return bpf_load_common(cfg, ops, nl);
} }
int bpf_graft_map(const char *map_path, uint32_t *key, int argc, char **argv) int bpf_graft_map(const char *map_path, uint32_t *key, int argc, char **argv)
{ {
enum bpf_prog_type type = BPF_PROG_TYPE_UNSPEC;
const bool opt_tbl[BPF_MODE_MAX] = { const bool opt_tbl[BPF_MODE_MAX] = {
[EBPF_OBJECT] = true, [EBPF_OBJECT] = true,
[EBPF_PINNED] = true, [EBPF_PINNED] = true,
@ -978,17 +990,24 @@ int bpf_graft_map(const char *map_path, uint32_t *key, int argc, char **argv)
.size_value = sizeof(int), .size_value = sizeof(int),
}; };
struct bpf_cfg_in cfg = { struct bpf_cfg_in cfg = {
.type = BPF_PROG_TYPE_UNSPEC,
.argc = argc, .argc = argc,
.argv = argv, .argv = argv,
}; };
struct bpf_map_ext ext = {}; struct bpf_map_ext ext = {};
int ret, prog_fd, map_fd; int ret, prog_fd, map_fd;
enum bpf_mode mode;
uint32_t map_key; uint32_t map_key;
prog_fd = bpf_parse(&type, &mode, &cfg, opt_tbl); ret = bpf_do_parse(&cfg, opt_tbl);
if (prog_fd < 0) if (ret < 0)
return prog_fd; return ret;
ret = bpf_do_load(&cfg);
if (ret < 0)
return ret;
prog_fd = cfg.prog_fd;
if (key) { if (key) {
map_key = *key; map_key = *key;
} else { } else {
@ -1000,7 +1019,7 @@ int bpf_graft_map(const char *map_path, uint32_t *key, int argc, char **argv)
} }
} }
map_fd = bpf_obj_get(map_path, type); map_fd = bpf_obj_get(map_path, cfg.type);
if (map_fd < 0) { if (map_fd < 0) {
fprintf(stderr, "Couldn\'t retrieve pinned map \'%s\': %s\n", fprintf(stderr, "Couldn\'t retrieve pinned map \'%s\': %s\n",
map_path, strerror(errno)); map_path, strerror(errno));
@ -1010,7 +1029,7 @@ int bpf_graft_map(const char *map_path, uint32_t *key, int argc, char **argv)
ret = bpf_map_selfcheck_pinned(map_fd, &test, &ext, ret = bpf_map_selfcheck_pinned(map_fd, &test, &ext,
offsetof(struct bpf_elf_map, max_elem), offsetof(struct bpf_elf_map, max_elem),
type); cfg.type);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "Map \'%s\' self-check failed!\n", map_path); fprintf(stderr, "Map \'%s\' self-check failed!\n", map_path);
goto out_map; goto out_map;
@ -1047,9 +1066,10 @@ int bpf_prog_detach_fd(int target_fd, enum bpf_attach_type type)
return bpf(BPF_PROG_DETACH, &attr, sizeof(attr)); return bpf(BPF_PROG_DETACH, &attr, sizeof(attr));
} }
int bpf_prog_load(enum bpf_prog_type type, const struct bpf_insn *insns, static int bpf_prog_load_dev(enum bpf_prog_type type,
size_t size_insns, const char *license, char *log, const struct bpf_insn *insns, size_t size_insns,
size_t size_log) const char *license, __u32 ifindex,
char *log, size_t size_log)
{ {
union bpf_attr attr = {}; union bpf_attr attr = {};
@ -1057,6 +1077,7 @@ int bpf_prog_load(enum bpf_prog_type type, const struct bpf_insn *insns,
attr.insns = bpf_ptr_to_u64(insns); attr.insns = bpf_ptr_to_u64(insns);
attr.insn_cnt = size_insns / sizeof(struct bpf_insn); attr.insn_cnt = size_insns / sizeof(struct bpf_insn);
attr.license = bpf_ptr_to_u64(license); attr.license = bpf_ptr_to_u64(license);
attr.prog_ifindex = ifindex;
if (size_log > 0) { if (size_log > 0) {
attr.log_buf = bpf_ptr_to_u64(log); attr.log_buf = bpf_ptr_to_u64(log);
@ -1067,6 +1088,14 @@ int bpf_prog_load(enum bpf_prog_type type, const struct bpf_insn *insns,
return bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); return bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
} }
int bpf_prog_load(enum bpf_prog_type type, const struct bpf_insn *insns,
size_t size_insns, const char *license, char *log,
size_t size_log)
{
return bpf_prog_load_dev(type, insns, size_insns, license, 0,
log, size_log);
}
#ifdef HAVE_ELF #ifdef HAVE_ELF
struct bpf_elf_prog { struct bpf_elf_prog {
enum bpf_prog_type type; enum bpf_prog_type type;
@ -1102,6 +1131,7 @@ struct bpf_elf_ctx {
int sec_maps; int sec_maps;
char license[ELF_MAX_LICENSE_LEN]; char license[ELF_MAX_LICENSE_LEN];
enum bpf_prog_type type; enum bpf_prog_type type;
__u32 ifindex;
bool verbose; bool verbose;
struct bpf_elf_st stat; struct bpf_elf_st stat;
struct bpf_hash_entry *ht[256]; struct bpf_hash_entry *ht[256];
@ -1474,8 +1504,9 @@ static int bpf_prog_attach(const char *section,
int tries = 0, fd; int tries = 0, fd;
retry: retry:
errno = 0; errno = 0;
fd = bpf_prog_load(prog->type, prog->insns, prog->size, fd = bpf_prog_load_dev(prog->type, prog->insns, prog->size,
prog->license, ctx->log, ctx->log_size); prog->license, ctx->ifindex,
ctx->log, ctx->log_size);
if (fd < 0 || ctx->verbose) { if (fd < 0 || ctx->verbose) {
/* The verifier log is pretty chatty, sometimes so chatty /* The verifier log is pretty chatty, sometimes so chatty
* on larger programs, that we could fail to dump everything * on larger programs, that we could fail to dump everything
@ -2403,7 +2434,8 @@ static void bpf_get_cfg(struct bpf_elf_ctx *ctx)
} }
static int bpf_elf_ctx_init(struct bpf_elf_ctx *ctx, const char *pathname, static int bpf_elf_ctx_init(struct bpf_elf_ctx *ctx, const char *pathname,
enum bpf_prog_type type, bool verbose) enum bpf_prog_type type, __u32 ifindex,
bool verbose)
{ {
int ret = -EINVAL; int ret = -EINVAL;
@ -2415,6 +2447,7 @@ static int bpf_elf_ctx_init(struct bpf_elf_ctx *ctx, const char *pathname,
bpf_get_cfg(ctx); bpf_get_cfg(ctx);
ctx->verbose = verbose; ctx->verbose = verbose;
ctx->type = type; ctx->type = type;
ctx->ifindex = ifindex;
ctx->obj_fd = open(pathname, O_RDONLY); ctx->obj_fd = open(pathname, O_RDONLY);
if (ctx->obj_fd < 0) if (ctx->obj_fd < 0)
@ -2506,12 +2539,12 @@ static void bpf_elf_ctx_destroy(struct bpf_elf_ctx *ctx, bool failure)
static struct bpf_elf_ctx __ctx; static struct bpf_elf_ctx __ctx;
static int bpf_obj_open(const char *pathname, enum bpf_prog_type type, static int bpf_obj_open(const char *pathname, enum bpf_prog_type type,
const char *section, bool verbose) const char *section, __u32 ifindex, bool verbose)
{ {
struct bpf_elf_ctx *ctx = &__ctx; struct bpf_elf_ctx *ctx = &__ctx;
int fd = 0, ret; int fd = 0, ret;
ret = bpf_elf_ctx_init(ctx, pathname, type, verbose); ret = bpf_elf_ctx_init(ctx, pathname, type, ifindex, verbose);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "Cannot initialize ELF context!\n"); fprintf(stderr, "Cannot initialize ELF context!\n");
return ret; return ret;

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <sys/wait.h> #include <sys/wait.h>
#include <stdio.h> #include <stdio.h>
#include <errno.h> #include <errno.h>

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <errno.h> #include <errno.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* /*
* libgenl.c GENL library * libgenl.c GENL library
*/ */

View File

@ -1,3 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>

View File

@ -1,3 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>

View File

@ -38,6 +38,74 @@
int resolve_hosts; int resolve_hosts;
int timestamp_short; int timestamp_short;
int read_prop(const char *dev, char *prop, long *value)
{
char fname[128], buf[80], *endp, *nl;
FILE *fp;
long result;
int ret;
ret = snprintf(fname, sizeof(fname), "/sys/class/net/%s/%s",
dev, prop);
if (ret <= 0 || ret >= sizeof(fname)) {
fprintf(stderr, "could not build pathname for property\n");
return -1;
}
fp = fopen(fname, "r");
if (fp == NULL) {
fprintf(stderr, "fopen %s: %s\n", fname, strerror(errno));
return -1;
}
if (!fgets(buf, sizeof(buf), fp)) {
fprintf(stderr, "property \"%s\" in file %s is currently unknown\n", prop, fname);
fclose(fp);
goto out;
}
nl = strchr(buf, '\n');
if (nl)
*nl = '\0';
fclose(fp);
result = strtol(buf, &endp, 0);
if (*endp || buf == endp) {
fprintf(stderr, "value \"%s\" in file %s is not a number\n",
buf, fname);
goto out;
}
if ((result == LONG_MAX || result == LONG_MIN) && errno == ERANGE) {
fprintf(stderr, "strtol %s: %s", fname, strerror(errno));
goto out;
}
*value = result;
return 0;
out:
fprintf(stderr, "Failed to parse %s\n", fname);
return -1;
}
/* Parse a percent e.g: '30%'
* return: 0 = ok, -1 = error, 1 = out of range
*/
int parse_percent(double *val, const char *str)
{
char *p;
*val = strtod(str, &p) / 100.;
if (*val == HUGE_VALF || *val == HUGE_VALL)
return 1;
if (*val == 0.0 || (*p && strcmp(p, "%")))
return -1;
return 0;
}
int get_hex(char c) int get_hex(char c)
{ {
if (c >= 'A' && c <= 'F') if (c >= 'A' && c <= 'F')

View File

@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
INSTALL=install INSTALL=install
INSTALLDIR=install -m 0755 -d INSTALLDIR=install -m 0755 -d
INSTALLMAN=install -m 0644 INSTALLMAN=install -m 0644

View File

@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
MAN3PAGES = $(wildcard *.3) MAN3PAGES = $(wildcard *.3)
all: all:

View File

@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
MAN7PAGES = $(wildcard *.7) MAN7PAGES = $(wildcard *.7)
all: all:

View File

@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
TARGETS = ip-address.8 ip-link.8 ip-route.8 TARGETS = ip-address.8 ip-link.8 ip-route.8
MAN8PAGES = $(TARGETS) $(filter-out $(TARGETS),$(wildcard *.8)) MAN8PAGES = $(TARGETS) $(filter-out $(TARGETS),$(wildcard *.8))

View File

@ -74,7 +74,8 @@ tc \- show / manipulate traffic control settings
\fB\-r\fR[\fIaw\fR] | \fB\-r\fR[\fIaw\fR] |
\fB\-p\fR[\fIretty\fR] | \fB\-p\fR[\fIretty\fR] |
\fB\-i\fR[\fIec\fR] | \fB\-i\fR[\fIec\fR] |
\fB\-g\fR[\fIraph\fR] } \fB\-g\fR[\fIraph\fR] |
\fB\-j\fR[\fIjson\fR] }
.SH DESCRIPTION .SH DESCRIPTION
.B Tc .B Tc
@ -443,7 +444,10 @@ see the man pages for individual qdiscs.
RATES RATES
Bandwidths or rates. Bandwidths or rates.
These parameters accept a floating point number, possibly followed by These parameters accept a floating point number, possibly followed by
a unit (both SI and IEC units supported). either a unit (both SI and IEC units supported), or a float followed by a '%'
character to specify the rate as a percentage of the device's speed
(e.g. 5%, 99.5%). Warning: specifying the rate as a percentage means a fraction
of the current speed; if the speed changes, the value will not be recalculated.
.RS .RS
.TP .TP
bit or a bare number bit or a bare number
@ -658,6 +662,10 @@ option was specified. Classes can be filtered only by
.BR "dev" .BR "dev"
option. option.
.TP
.BR "\-j", " \-json"
Display results in JSON format.
.TP .TP
.BR "\-nm" , " \-name" .BR "\-nm" , " \-name"
resolve class name from resolve class name from

View File

@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
SSOBJ=ss.o ssfilter.o SSOBJ=ss.o ssfilter.o
LNSTATOBJ=lnstat.o lnstat_util.o LNSTATOBJ=lnstat.o lnstat_util.o

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LNSTAT_H #ifndef _LNSTAT_H
#define _LNSTAT_H #define _LNSTAT_H

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#define SSF_DCOND 0 #define SSF_DCOND 0
#define SSF_SCOND 1 #define SSF_SCOND 1
#define SSF_OR 2 #define SSF_OR 2

View File

@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
include ../config.mk include ../config.mk
DISTGEN = maketable normal pareto paretonormal DISTGEN = maketable normal pareto paretonormal

View File

@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
include ../config.mk include ../config.mk
ifeq ($(HAVE_MNL),y) ifeq ($(HAVE_MNL),y)

View File

@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
TCOBJ= tc.o tc_qdisc.o tc_class.o tc_filter.o tc_util.o tc_monitor.o \ TCOBJ= tc.o tc_qdisc.o tc_class.o tc_filter.o tc_util.o tc_monitor.o \
tc_exec.o m_police.o m_estimator.o m_action.o m_ematch.o \ tc_exec.o m_police.o m_estimator.o m_action.o m_ematch.o \
emp_ematch.yacc.o emp_ematch.lex.o emp_ematch.yacc.o emp_ematch.lex.o

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
%{ %{
#include "emp_ematch.yacc.h" #include "emp_ematch.yacc.h"
#include "m_ematch.h" #include "m_ematch.h"

View File

@ -82,6 +82,7 @@ static int bpf_parse_opt(struct filter_util *qu, char *handle,
unsigned int bpf_flags = 0; unsigned int bpf_flags = 0;
struct bpf_cfg_in cfg = {}; struct bpf_cfg_in cfg = {};
bool seen_run = false; bool seen_run = false;
bool skip_sw = false;
struct rtattr *tail; struct rtattr *tail;
int ret = 0; int ret = 0;
@ -101,13 +102,20 @@ static int bpf_parse_opt(struct filter_util *qu, char *handle,
while (argc > 0) { while (argc > 0) {
if (matches(*argv, "run") == 0) { if (matches(*argv, "run") == 0) {
NEXT_ARG(); NEXT_ARG();
if (seen_run)
duparg("run", *argv);
opt_bpf: opt_bpf:
seen_run = true; seen_run = true;
cfg.type = bpf_type;
cfg.argc = argc; cfg.argc = argc;
cfg.argv = argv; cfg.argv = argv;
if (bpf_parse_common(bpf_type, &cfg, &bpf_cb_ops, n)) if (bpf_parse_common(&cfg, &bpf_cb_ops) < 0) {
fprintf(stderr,
"Unable to parse bpf command line\n");
return -1; return -1;
}
argc = cfg.argc; argc = cfg.argc;
argv = cfg.argv; argv = cfg.argv;
@ -131,6 +139,7 @@ opt_bpf:
bpf_gen_flags |= TCA_CLS_FLAGS_SKIP_HW; bpf_gen_flags |= TCA_CLS_FLAGS_SKIP_HW;
} else if (matches(*argv, "skip_sw") == 0) { } else if (matches(*argv, "skip_sw") == 0) {
bpf_gen_flags |= TCA_CLS_FLAGS_SKIP_SW; bpf_gen_flags |= TCA_CLS_FLAGS_SKIP_SW;
skip_sw = true;
} else if (matches(*argv, "action") == 0) { } else if (matches(*argv, "action") == 0) {
NEXT_ARG(); NEXT_ARG();
if (parse_action(&argc, &argv, TCA_BPF_ACT, n)) { if (parse_action(&argc, &argv, TCA_BPF_ACT, n)) {
@ -160,6 +169,13 @@ opt_bpf:
NEXT_ARG_FWD(); NEXT_ARG_FWD();
} }
if (skip_sw)
cfg.ifindex = t->tcm_ifindex;
if (bpf_load_common(&cfg, &bpf_cb_ops, n) < 0) {
fprintf(stderr, "Unable to load program\n");
return -1;
}
if (bpf_gen_flags) if (bpf_gen_flags)
addattr32(n, MAX_MSG, TCA_BPF_FLAGS_GEN, bpf_gen_flags); addattr32(n, MAX_MSG, TCA_BPF_FLAGS_GEN, bpf_gen_flags);
if (bpf_flags) if (bpf_flags)

View File

@ -1037,89 +1037,105 @@ static int __mask_bits(char *addr, size_t len)
return bits; return bits;
} }
static void flower_print_eth_addr(FILE *f, char *name, static void flower_print_eth_addr(char *name, struct rtattr *addr_attr,
struct rtattr *addr_attr,
struct rtattr *mask_attr) struct rtattr *mask_attr)
{ {
SPRINT_BUF(namefrm);
SPRINT_BUF(out);
SPRINT_BUF(b1); SPRINT_BUF(b1);
size_t done;
int bits; int bits;
if (!addr_attr || RTA_PAYLOAD(addr_attr) != ETH_ALEN) if (!addr_attr || RTA_PAYLOAD(addr_attr) != ETH_ALEN)
return; return;
fprintf(f, "\n %s %s", name, ll_addr_n2a(RTA_DATA(addr_attr), ETH_ALEN, done = sprintf(out, "%s",
0, b1, sizeof(b1))); ll_addr_n2a(RTA_DATA(addr_attr), ETH_ALEN,
if (!mask_attr || RTA_PAYLOAD(mask_attr) != ETH_ALEN) 0, b1, sizeof(b1)));
return; if (mask_attr && RTA_PAYLOAD(mask_attr) == ETH_ALEN) {
bits = __mask_bits(RTA_DATA(mask_attr), ETH_ALEN); bits = __mask_bits(RTA_DATA(mask_attr), ETH_ALEN);
if (bits < 0) if (bits < 0)
fprintf(f, "/%s", ll_addr_n2a(RTA_DATA(mask_attr), ETH_ALEN, sprintf(out + done, "/%s",
0, b1, sizeof(b1))); ll_addr_n2a(RTA_DATA(mask_attr), ETH_ALEN,
else if (bits < ETH_ALEN * 8) 0, b1, sizeof(b1)));
fprintf(f, "/%d", bits); else if (bits < ETH_ALEN * 8)
sprintf(out + done, "/%d", bits);
}
sprintf(namefrm, "\n %s %%s", name);
print_string(PRINT_ANY, name, namefrm, out);
} }
static void flower_print_eth_type(FILE *f, __be16 *p_eth_type, static void flower_print_eth_type(__be16 *p_eth_type,
struct rtattr *eth_type_attr) struct rtattr *eth_type_attr)
{ {
SPRINT_BUF(out);
__be16 eth_type; __be16 eth_type;
if (!eth_type_attr) if (!eth_type_attr)
return; return;
eth_type = rta_getattr_u16(eth_type_attr); eth_type = rta_getattr_u16(eth_type_attr);
fprintf(f, "\n eth_type ");
if (eth_type == htons(ETH_P_IP)) if (eth_type == htons(ETH_P_IP))
fprintf(f, "ipv4"); sprintf(out, "ipv4");
else if (eth_type == htons(ETH_P_IPV6)) else if (eth_type == htons(ETH_P_IPV6))
fprintf(f, "ipv6"); sprintf(out, "ipv6");
else if (eth_type == htons(ETH_P_ARP)) else if (eth_type == htons(ETH_P_ARP))
fprintf(f, "arp"); sprintf(out, "arp");
else if (eth_type == htons(ETH_P_RARP)) else if (eth_type == htons(ETH_P_RARP))
fprintf(f, "rarp"); sprintf(out, "rarp");
else else
fprintf(f, "%04x", ntohs(eth_type)); sprintf(out, "%04x", ntohs(eth_type));
print_string(PRINT_ANY, "eth_type", "\n eth_type %s", out);
*p_eth_type = eth_type; *p_eth_type = eth_type;
} }
static void flower_print_ip_proto(FILE *f, __u8 *p_ip_proto, static void flower_print_ip_proto(__u8 *p_ip_proto,
struct rtattr *ip_proto_attr) struct rtattr *ip_proto_attr)
{ {
SPRINT_BUF(out);
__u8 ip_proto; __u8 ip_proto;
if (!ip_proto_attr) if (!ip_proto_attr)
return; return;
ip_proto = rta_getattr_u8(ip_proto_attr); ip_proto = rta_getattr_u8(ip_proto_attr);
fprintf(f, "\n ip_proto ");
if (ip_proto == IPPROTO_TCP) if (ip_proto == IPPROTO_TCP)
fprintf(f, "tcp"); sprintf(out, "tcp");
else if (ip_proto == IPPROTO_UDP) else if (ip_proto == IPPROTO_UDP)
fprintf(f, "udp"); sprintf(out, "udp");
else if (ip_proto == IPPROTO_SCTP) else if (ip_proto == IPPROTO_SCTP)
fprintf(f, "sctp"); sprintf(out, "sctp");
else if (ip_proto == IPPROTO_ICMP) else if (ip_proto == IPPROTO_ICMP)
fprintf(f, "icmp"); sprintf(out, "icmp");
else if (ip_proto == IPPROTO_ICMPV6) else if (ip_proto == IPPROTO_ICMPV6)
fprintf(f, "icmpv6"); sprintf(out, "icmpv6");
else else
fprintf(f, "%02x", ip_proto); sprintf(out, "%02x", ip_proto);
print_string(PRINT_ANY, "ip_proto", "\n ip_proto %s", out);
*p_ip_proto = ip_proto; *p_ip_proto = ip_proto;
} }
static void flower_print_ip_attr(FILE *f, char *name, static void flower_print_ip_attr(char *name, struct rtattr *key_attr,
struct rtattr *key_attr,
struct rtattr *mask_attr) struct rtattr *mask_attr)
{ {
SPRINT_BUF(namefrm);
SPRINT_BUF(out);
size_t done;
if (!key_attr) if (!key_attr)
return; return;
fprintf(f, "\n %s %x", name, rta_getattr_u8(key_attr)); done = sprintf(out, "%x", rta_getattr_u8(key_attr));
if (!mask_attr) if (mask_attr)
return; sprintf(out + done, "/%x", rta_getattr_u8(mask_attr));
fprintf(f, "/%x", rta_getattr_u8(mask_attr));
sprintf(namefrm, "\n %s %%x", name);
print_string(PRINT_ANY, name, namefrm, out);
} }
static void flower_print_matching_flags(FILE *f, char *name, static void flower_print_matching_flags(char *name,
enum flower_matching_flags type, enum flower_matching_flags type,
struct rtattr *attr, struct rtattr *attr,
struct rtattr *mask_attr) struct rtattr *mask_attr)
@ -1139,20 +1155,28 @@ static void flower_print_matching_flags(FILE *f, char *name,
if (type != flags_str[i].type) if (type != flags_str[i].type)
continue; continue;
if (mtf_mask & flags_str[i].flag) { if (mtf_mask & flags_str[i].flag) {
if (++count == 1) if (++count == 1) {
fprintf(f, "\n %s ", name); print_string(PRINT_FP, NULL, "\n %s ", name);
else open_json_object(name);
fprintf(f, "/"); } else {
print_string(PRINT_FP, NULL, "/", NULL);
}
print_bool(PRINT_JSON, flags_str[i].string, NULL,
mtf & flags_str[i].flag);
if (mtf & flags_str[i].flag) if (mtf & flags_str[i].flag)
fprintf(f, "%s", flags_str[i].string); print_string(PRINT_FP, NULL, "%s",
flags_str[i].string);
else else
fprintf(f, "no%s", flags_str[i].string); print_string(PRINT_FP, NULL, "no%s",
flags_str[i].string);
} }
} }
if (count)
close_json_object();
} }
static void flower_print_ip_addr(FILE *f, char *name, __be16 eth_type, static void flower_print_ip_addr(char *name, __be16 eth_type,
struct rtattr *addr4_attr, struct rtattr *addr4_attr,
struct rtattr *mask4_attr, struct rtattr *mask4_attr,
struct rtattr *addr6_attr, struct rtattr *addr6_attr,
@ -1160,6 +1184,9 @@ static void flower_print_ip_addr(FILE *f, char *name, __be16 eth_type,
{ {
struct rtattr *addr_attr; struct rtattr *addr_attr;
struct rtattr *mask_attr; struct rtattr *mask_attr;
SPRINT_BUF(namefrm);
SPRINT_BUF(out);
size_t done;
int family; int family;
size_t len; size_t len;
int bits; int bits;
@ -1179,56 +1206,75 @@ static void flower_print_ip_addr(FILE *f, char *name, __be16 eth_type,
} }
if (!addr_attr || RTA_PAYLOAD(addr_attr) != len) if (!addr_attr || RTA_PAYLOAD(addr_attr) != len)
return; return;
fprintf(f, "\n %s %s", name, rt_addr_n2a_rta(family, addr_attr));
if (!mask_attr || RTA_PAYLOAD(mask_attr) != len) if (!mask_attr || RTA_PAYLOAD(mask_attr) != len)
return; return;
done = sprintf(out, "%s", rt_addr_n2a_rta(family, addr_attr));
bits = __mask_bits(RTA_DATA(mask_attr), len); bits = __mask_bits(RTA_DATA(mask_attr), len);
if (bits < 0) if (bits < 0)
fprintf(f, "/%s", rt_addr_n2a_rta(family, mask_attr)); sprintf(out + done, "/%s", rt_addr_n2a_rta(family, mask_attr));
else if (bits < len * 8) else if (bits < len * 8)
fprintf(f, "/%d", bits); sprintf(out + done, "/%d", bits);
sprintf(namefrm, "\n %s %%s", name);
print_string(PRINT_ANY, name, namefrm, out);
} }
static void flower_print_ip4_addr(FILE *f, char *name, static void flower_print_ip4_addr(char *name, struct rtattr *addr_attr,
struct rtattr *addr_attr,
struct rtattr *mask_attr) struct rtattr *mask_attr)
{ {
return flower_print_ip_addr(f, name, htons(ETH_P_IP), return flower_print_ip_addr(name, htons(ETH_P_IP),
addr_attr, mask_attr, 0, 0); addr_attr, mask_attr, 0, 0);
} }
static void flower_print_port(FILE *f, char *name, struct rtattr *attr) static void flower_print_port(char *name, struct rtattr *attr)
{ {
if (attr) SPRINT_BUF(namefrm);
fprintf(f, "\n %s %d", name, rta_getattr_be16(attr));
if (!attr)
return;
sprintf(namefrm,"\n %s %%u", name);
print_uint(PRINT_ANY, name, namefrm, rta_getattr_be16(attr));
} }
static void flower_print_tcp_flags(FILE *f, char *name, static void flower_print_tcp_flags(char *name, struct rtattr *flags_attr,
struct rtattr *flags_attr, struct rtattr *mask_attr)
struct rtattr *mask_attr)
{ {
SPRINT_BUF(namefrm);
SPRINT_BUF(out);
size_t done;
if (!flags_attr) if (!flags_attr)
return; return;
fprintf(f, "\n %s %x", name, rta_getattr_be16(flags_attr));
if (!mask_attr) done = sprintf(out, "%x", rta_getattr_be16(flags_attr));
return; if (mask_attr)
fprintf(f, "/%x", rta_getattr_be16(mask_attr)); sprintf(out + done, "%x", rta_getattr_be16(flags_attr));
sprintf(namefrm, "\n %s %%s", name);
print_string(PRINT_ANY, name, namefrm, out);
} }
static void flower_print_key_id(FILE *f, const char *name, static void flower_print_key_id(const char *name, struct rtattr *attr)
struct rtattr *attr)
{ {
if (attr) SPRINT_BUF(namefrm);
fprintf(f, "\n %s %d", name, rta_getattr_be32(attr));
if (!attr)
return;
sprintf(namefrm,"\n %s %%u", name);
print_uint(PRINT_ANY, name, namefrm, rta_getattr_be32(attr));
} }
static void flower_print_masked_u8(FILE *f, const char *name, static void flower_print_masked_u8(const char *name, struct rtattr *attr,
struct rtattr *attr,
struct rtattr *mask_attr, struct rtattr *mask_attr,
const char *(*value_to_str)(__u8 value)) const char *(*value_to_str)(__u8 value))
{ {
const char *value_str = NULL; const char *value_str = NULL;
__u8 value, mask; __u8 value, mask;
SPRINT_BUF(namefrm);
SPRINT_BUF(out);
size_t done;
if (!attr) if (!attr)
return; return;
@ -1238,39 +1284,39 @@ static void flower_print_masked_u8(FILE *f, const char *name,
if (mask == UINT8_MAX && value_to_str) if (mask == UINT8_MAX && value_to_str)
value_str = value_to_str(value); value_str = value_to_str(value);
fprintf(f, "\n %s ", name);
if (value_str) if (value_str)
fputs(value_str, f); done = sprintf(out, "%s", value_str);
else else
fprintf(f, "%d", value); done = sprintf(out, "%d", value);
if (mask != UINT8_MAX) if (mask != UINT8_MAX)
fprintf(f, "/%d", mask); sprintf(out + done, "/%d", mask);
sprintf(namefrm,"\n %s %%s", name);
print_string(PRINT_ANY, name, namefrm, out);
} }
static void flower_print_u8(FILE *f, const char *name, struct rtattr *attr) static void flower_print_u8(const char *name, struct rtattr *attr)
{ {
flower_print_masked_u8(f, name, attr, NULL, NULL); flower_print_masked_u8(name, attr, NULL, NULL);
} }
static void flower_print_u32(FILE *f, const char *name, struct rtattr *attr) static void flower_print_u32(const char *name, struct rtattr *attr)
{ {
__u32 value; SPRINT_BUF(namefrm);
if (!attr) if (!attr)
return; return;
value = rta_getattr_u32(attr); sprintf(namefrm,"\n %s %%u", name);
print_uint(PRINT_ANY, name, namefrm, rta_getattr_u32(attr));
fprintf(f, "\n %s %d", name, value);
} }
static void flower_print_arp_op(FILE *f, const char *name, static void flower_print_arp_op(const char *name,
struct rtattr *op_attr, struct rtattr *op_attr,
struct rtattr *mask_attr) struct rtattr *mask_attr)
{ {
flower_print_masked_u8(f, name, op_attr, mask_attr, flower_print_masked_u8(name, op_attr, mask_attr,
flower_print_arp_op_to_name); flower_print_arp_op_to_name);
} }
@ -1288,7 +1334,7 @@ static int flower_print_opt(struct filter_util *qu, FILE *f,
parse_rtattr_nested(tb, TCA_FLOWER_MAX, opt); parse_rtattr_nested(tb, TCA_FLOWER_MAX, opt);
if (handle) if (handle)
fprintf(f, "handle 0x%x ", handle); print_uint(PRINT_ANY, "handle", "handle 0x%x ", handle);
if (tb[TCA_FLOWER_CLASSID]) { if (tb[TCA_FLOWER_CLASSID]) {
__u32 h = rta_getattr_u32(tb[TCA_FLOWER_CLASSID]); __u32 h = rta_getattr_u32(tb[TCA_FLOWER_CLASSID]);
@ -1296,56 +1342,62 @@ static int flower_print_opt(struct filter_util *qu, FILE *f,
if (TC_H_MIN(h) < TC_H_MIN_PRIORITY || if (TC_H_MIN(h) < TC_H_MIN_PRIORITY ||
TC_H_MIN(h) > (TC_H_MIN_PRIORITY + TC_QOPT_MAX_QUEUE - 1)) { TC_H_MIN(h) > (TC_H_MIN_PRIORITY + TC_QOPT_MAX_QUEUE - 1)) {
SPRINT_BUF(b1); SPRINT_BUF(b1);
fprintf(f, "classid %s ", sprint_tc_classid(h, b1)); print_string(PRINT_ANY, "classid", "classid %s ",
sprint_tc_classid(h, b1));
} else { } else {
fprintf(f, "hw_tc %u ", print_uint(PRINT_ANY, "hw_tc", "hw_tc %u ",
TC_H_MIN(h) - TC_H_MIN_PRIORITY); TC_H_MIN(h) - TC_H_MIN_PRIORITY);
} }
} }
if (tb[TCA_FLOWER_INDEV]) { if (tb[TCA_FLOWER_INDEV]) {
struct rtattr *attr = tb[TCA_FLOWER_INDEV]; struct rtattr *attr = tb[TCA_FLOWER_INDEV];
fprintf(f, "\n indev %s", rta_getattr_str(attr)); print_string(PRINT_ANY, "indev", "\n indev %s",
rta_getattr_str(attr));
} }
open_json_object("keys");
if (tb[TCA_FLOWER_KEY_VLAN_ID]) { if (tb[TCA_FLOWER_KEY_VLAN_ID]) {
struct rtattr *attr = tb[TCA_FLOWER_KEY_VLAN_ID]; struct rtattr *attr = tb[TCA_FLOWER_KEY_VLAN_ID];
fprintf(f, "\n vlan_id %d", rta_getattr_u16(attr)); print_uint(PRINT_ANY, "vlan_id", "\n vlan_id %u",
rta_getattr_u16(attr));
} }
if (tb[TCA_FLOWER_KEY_VLAN_PRIO]) { if (tb[TCA_FLOWER_KEY_VLAN_PRIO]) {
struct rtattr *attr = tb[TCA_FLOWER_KEY_VLAN_PRIO]; struct rtattr *attr = tb[TCA_FLOWER_KEY_VLAN_PRIO];
fprintf(f, "\n vlan_prio %d", rta_getattr_u8(attr)); print_uint(PRINT_ANY, "vlan_prio", "\n vlan_prio %d",
rta_getattr_u8(attr));
} }
flower_print_eth_addr(f, "dst_mac", tb[TCA_FLOWER_KEY_ETH_DST], flower_print_eth_addr("dst_mac", tb[TCA_FLOWER_KEY_ETH_DST],
tb[TCA_FLOWER_KEY_ETH_DST_MASK]); tb[TCA_FLOWER_KEY_ETH_DST_MASK]);
flower_print_eth_addr(f, "src_mac", tb[TCA_FLOWER_KEY_ETH_SRC], flower_print_eth_addr("src_mac", tb[TCA_FLOWER_KEY_ETH_SRC],
tb[TCA_FLOWER_KEY_ETH_SRC_MASK]); tb[TCA_FLOWER_KEY_ETH_SRC_MASK]);
flower_print_eth_type(f, &eth_type, tb[TCA_FLOWER_KEY_ETH_TYPE]); flower_print_eth_type(&eth_type, tb[TCA_FLOWER_KEY_ETH_TYPE]);
flower_print_ip_proto(f, &ip_proto, tb[TCA_FLOWER_KEY_IP_PROTO]); flower_print_ip_proto(&ip_proto, tb[TCA_FLOWER_KEY_IP_PROTO]);
flower_print_ip_attr(f, "ip_tos", tb[TCA_FLOWER_KEY_IP_TOS], flower_print_ip_attr("ip_tos", tb[TCA_FLOWER_KEY_IP_TOS],
tb[TCA_FLOWER_KEY_IP_TOS_MASK]); tb[TCA_FLOWER_KEY_IP_TOS_MASK]);
flower_print_ip_attr(f, "ip_ttl", tb[TCA_FLOWER_KEY_IP_TTL], flower_print_ip_attr("ip_ttl", tb[TCA_FLOWER_KEY_IP_TTL],
tb[TCA_FLOWER_KEY_IP_TTL_MASK]); tb[TCA_FLOWER_KEY_IP_TTL_MASK]);
flower_print_u32(f, "mpls_label", tb[TCA_FLOWER_KEY_MPLS_LABEL]); flower_print_u32("mpls_label", tb[TCA_FLOWER_KEY_MPLS_LABEL]);
flower_print_u8(f, "mpls_tc", tb[TCA_FLOWER_KEY_MPLS_TC]); flower_print_u8("mpls_tc", tb[TCA_FLOWER_KEY_MPLS_TC]);
flower_print_u8(f, "mpls_bos", tb[TCA_FLOWER_KEY_MPLS_BOS]); flower_print_u8("mpls_bos", tb[TCA_FLOWER_KEY_MPLS_BOS]);
flower_print_u8(f, "mpls_ttl", tb[TCA_FLOWER_KEY_MPLS_TTL]); flower_print_u8("mpls_ttl", tb[TCA_FLOWER_KEY_MPLS_TTL]);
flower_print_ip_addr(f, "dst_ip", eth_type, flower_print_ip_addr("dst_ip", eth_type,
tb[TCA_FLOWER_KEY_IPV4_DST], tb[TCA_FLOWER_KEY_IPV4_DST],
tb[TCA_FLOWER_KEY_IPV4_DST_MASK], tb[TCA_FLOWER_KEY_IPV4_DST_MASK],
tb[TCA_FLOWER_KEY_IPV6_DST], tb[TCA_FLOWER_KEY_IPV6_DST],
tb[TCA_FLOWER_KEY_IPV6_DST_MASK]); tb[TCA_FLOWER_KEY_IPV6_DST_MASK]);
flower_print_ip_addr(f, "src_ip", eth_type, flower_print_ip_addr("src_ip", eth_type,
tb[TCA_FLOWER_KEY_IPV4_SRC], tb[TCA_FLOWER_KEY_IPV4_SRC],
tb[TCA_FLOWER_KEY_IPV4_SRC_MASK], tb[TCA_FLOWER_KEY_IPV4_SRC_MASK],
tb[TCA_FLOWER_KEY_IPV6_SRC], tb[TCA_FLOWER_KEY_IPV6_SRC],
@ -1353,12 +1405,12 @@ static int flower_print_opt(struct filter_util *qu, FILE *f,
nl_type = flower_port_attr_type(ip_proto, FLOWER_ENDPOINT_DST); nl_type = flower_port_attr_type(ip_proto, FLOWER_ENDPOINT_DST);
if (nl_type >= 0) if (nl_type >= 0)
flower_print_port(f, "dst_port", tb[nl_type]); flower_print_port("dst_port", tb[nl_type]);
nl_type = flower_port_attr_type(ip_proto, FLOWER_ENDPOINT_SRC); nl_type = flower_port_attr_type(ip_proto, FLOWER_ENDPOINT_SRC);
if (nl_type >= 0) if (nl_type >= 0)
flower_print_port(f, "src_port", tb[nl_type]); flower_print_port("src_port", tb[nl_type]);
flower_print_tcp_flags(f, "tcp_flags", tb[TCA_FLOWER_KEY_TCP_FLAGS], flower_print_tcp_flags("tcp_flags", tb[TCA_FLOWER_KEY_TCP_FLAGS],
tb[TCA_FLOWER_KEY_TCP_FLAGS_MASK]); tb[TCA_FLOWER_KEY_TCP_FLAGS_MASK]);
nl_type = flower_icmp_attr_type(eth_type, ip_proto, nl_type = flower_icmp_attr_type(eth_type, ip_proto,
@ -1366,7 +1418,7 @@ static int flower_print_opt(struct filter_util *qu, FILE *f,
nl_mask_type = flower_icmp_attr_mask_type(eth_type, ip_proto, nl_mask_type = flower_icmp_attr_mask_type(eth_type, ip_proto,
FLOWER_ICMP_FIELD_TYPE); FLOWER_ICMP_FIELD_TYPE);
if (nl_type >= 0 && nl_mask_type >= 0) if (nl_type >= 0 && nl_mask_type >= 0)
flower_print_masked_u8(f, "icmp_type", tb[nl_type], flower_print_masked_u8("icmp_type", tb[nl_type],
tb[nl_mask_type], NULL); tb[nl_mask_type], NULL);
nl_type = flower_icmp_attr_type(eth_type, ip_proto, nl_type = flower_icmp_attr_type(eth_type, ip_proto,
@ -1374,21 +1426,21 @@ static int flower_print_opt(struct filter_util *qu, FILE *f,
nl_mask_type = flower_icmp_attr_mask_type(eth_type, ip_proto, nl_mask_type = flower_icmp_attr_mask_type(eth_type, ip_proto,
FLOWER_ICMP_FIELD_CODE); FLOWER_ICMP_FIELD_CODE);
if (nl_type >= 0 && nl_mask_type >= 0) if (nl_type >= 0 && nl_mask_type >= 0)
flower_print_masked_u8(f, "icmp_code", tb[nl_type], flower_print_masked_u8("icmp_code", tb[nl_type],
tb[nl_mask_type], NULL); tb[nl_mask_type], NULL);
flower_print_ip4_addr(f, "arp_sip", tb[TCA_FLOWER_KEY_ARP_SIP], flower_print_ip4_addr("arp_sip", tb[TCA_FLOWER_KEY_ARP_SIP],
tb[TCA_FLOWER_KEY_ARP_SIP_MASK]); tb[TCA_FLOWER_KEY_ARP_SIP_MASK]);
flower_print_ip4_addr(f, "arp_tip", tb[TCA_FLOWER_KEY_ARP_TIP], flower_print_ip4_addr("arp_tip", tb[TCA_FLOWER_KEY_ARP_TIP],
tb[TCA_FLOWER_KEY_ARP_TIP_MASK]); tb[TCA_FLOWER_KEY_ARP_TIP_MASK]);
flower_print_arp_op(f, "arp_op", tb[TCA_FLOWER_KEY_ARP_OP], flower_print_arp_op("arp_op", tb[TCA_FLOWER_KEY_ARP_OP],
tb[TCA_FLOWER_KEY_ARP_OP_MASK]); tb[TCA_FLOWER_KEY_ARP_OP_MASK]);
flower_print_eth_addr(f, "arp_sha", tb[TCA_FLOWER_KEY_ARP_SHA], flower_print_eth_addr("arp_sha", tb[TCA_FLOWER_KEY_ARP_SHA],
tb[TCA_FLOWER_KEY_ARP_SHA_MASK]); tb[TCA_FLOWER_KEY_ARP_SHA_MASK]);
flower_print_eth_addr(f, "arp_tha", tb[TCA_FLOWER_KEY_ARP_THA], flower_print_eth_addr("arp_tha", tb[TCA_FLOWER_KEY_ARP_THA],
tb[TCA_FLOWER_KEY_ARP_THA_MASK]); tb[TCA_FLOWER_KEY_ARP_THA_MASK]);
flower_print_ip_addr(f, "enc_dst_ip", flower_print_ip_addr("enc_dst_ip",
tb[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] ? tb[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] ?
htons(ETH_P_IP) : htons(ETH_P_IPV6), htons(ETH_P_IP) : htons(ETH_P_IPV6),
tb[TCA_FLOWER_KEY_ENC_IPV4_DST], tb[TCA_FLOWER_KEY_ENC_IPV4_DST],
@ -1396,7 +1448,7 @@ static int flower_print_opt(struct filter_util *qu, FILE *f,
tb[TCA_FLOWER_KEY_ENC_IPV6_DST], tb[TCA_FLOWER_KEY_ENC_IPV6_DST],
tb[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK]); tb[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK]);
flower_print_ip_addr(f, "enc_src_ip", flower_print_ip_addr("enc_src_ip",
tb[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] ? tb[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] ?
htons(ETH_P_IP) : htons(ETH_P_IPV6), htons(ETH_P_IP) : htons(ETH_P_IPV6),
tb[TCA_FLOWER_KEY_ENC_IPV4_SRC], tb[TCA_FLOWER_KEY_ENC_IPV4_SRC],
@ -1404,29 +1456,28 @@ static int flower_print_opt(struct filter_util *qu, FILE *f,
tb[TCA_FLOWER_KEY_ENC_IPV6_SRC], tb[TCA_FLOWER_KEY_ENC_IPV6_SRC],
tb[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK]); tb[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK]);
flower_print_key_id(f, "enc_key_id", flower_print_key_id("enc_key_id", tb[TCA_FLOWER_KEY_ENC_KEY_ID]);
tb[TCA_FLOWER_KEY_ENC_KEY_ID]);
flower_print_port(f, "enc_dst_port", flower_print_port("enc_dst_port", tb[TCA_FLOWER_KEY_ENC_UDP_DST_PORT]);
tb[TCA_FLOWER_KEY_ENC_UDP_DST_PORT]);
flower_print_matching_flags(f, "ip_flags", flower_print_matching_flags("ip_flags", FLOWER_IP_FLAGS,
FLOWER_IP_FLAGS,
tb[TCA_FLOWER_KEY_FLAGS], tb[TCA_FLOWER_KEY_FLAGS],
tb[TCA_FLOWER_KEY_FLAGS_MASK]); tb[TCA_FLOWER_KEY_FLAGS_MASK]);
close_json_object();
if (tb[TCA_FLOWER_FLAGS]) { if (tb[TCA_FLOWER_FLAGS]) {
__u32 flags = rta_getattr_u32(tb[TCA_FLOWER_FLAGS]); __u32 flags = rta_getattr_u32(tb[TCA_FLOWER_FLAGS]);
if (flags & TCA_CLS_FLAGS_SKIP_HW) if (flags & TCA_CLS_FLAGS_SKIP_HW)
fprintf(f, "\n skip_hw"); print_bool(PRINT_ANY, "skip_hw", "\n skip_hw", true);
if (flags & TCA_CLS_FLAGS_SKIP_SW) if (flags & TCA_CLS_FLAGS_SKIP_SW)
fprintf(f, "\n skip_sw"); print_bool(PRINT_ANY, "skip_sw", "\n skip_sw", true);
if (flags & TCA_CLS_FLAGS_IN_HW) if (flags & TCA_CLS_FLAGS_IN_HW)
fprintf(f, "\n in_hw"); print_bool(PRINT_ANY, "in_hw", "\n in_hw", true);
else if (flags & TCA_CLS_FLAGS_NOT_IN_HW) else if (flags & TCA_CLS_FLAGS_NOT_IN_HW)
fprintf(f, "\n not_in_hw"); print_bool(PRINT_ANY, "not_in_hw", "\n not_in_hw", true);
} }
if (tb[TCA_FLOWER_ACT]) if (tb[TCA_FLOWER_ACT])

View File

@ -121,11 +121,11 @@ static int matchall_print_opt(struct filter_util *qu, FILE *f,
parse_rtattr_nested(tb, TCA_MATCHALL_MAX, opt); parse_rtattr_nested(tb, TCA_MATCHALL_MAX, opt);
if (handle) if (handle)
fprintf(f, "handle 0x%x ", handle); print_uint(PRINT_ANY, "handle", "handle 0x%x ", handle);
if (tb[TCA_MATCHALL_CLASSID]) { if (tb[TCA_MATCHALL_CLASSID]) {
SPRINT_BUF(b1); SPRINT_BUF(b1);
fprintf(f, "flowid %s ", print_string(PRINT_ANY, "flowid", "flowid %s ",
sprint_tc_classid(rta_getattr_u32(tb[TCA_MATCHALL_CLASSID]), b1)); sprint_tc_classid(rta_getattr_u32(tb[TCA_MATCHALL_CLASSID]), b1));
} }
@ -133,14 +133,14 @@ static int matchall_print_opt(struct filter_util *qu, FILE *f,
__u32 flags = rta_getattr_u32(tb[TCA_MATCHALL_FLAGS]); __u32 flags = rta_getattr_u32(tb[TCA_MATCHALL_FLAGS]);
if (flags & TCA_CLS_FLAGS_SKIP_HW) if (flags & TCA_CLS_FLAGS_SKIP_HW)
fprintf(f, "\n skip_hw"); print_bool(PRINT_ANY, "skip_hw", "\n skip_hw", true);
if (flags & TCA_CLS_FLAGS_SKIP_SW) if (flags & TCA_CLS_FLAGS_SKIP_SW)
fprintf(f, "\n skip_sw"); print_bool(PRINT_ANY, "skip_sw", "\n skip_sw", true);
if (flags & TCA_CLS_FLAGS_IN_HW) if (flags & TCA_CLS_FLAGS_IN_HW)
fprintf(f, "\n in_hw"); print_bool(PRINT_ANY, "in_hw", "\n in_hw", true);
else if (flags & TCA_CLS_FLAGS_NOT_IN_HW) else if (flags & TCA_CLS_FLAGS_NOT_IN_HW)
fprintf(f, "\n not_in_hw"); print_bool(PRINT_ANY, "not_in_hw", "\n not_in_hw", true);
} }
if (tb[TCA_MATCHALL_ACT]) if (tb[TCA_MATCHALL_ACT])

View File

@ -169,7 +169,8 @@ done:
} }
static int rsvp_parse_opt(struct filter_util *qu, char *handle, int argc, char **argv, struct nlmsghdr *n) static int rsvp_parse_opt(struct filter_util *qu, char *handle, int argc,
char **argv, struct nlmsghdr *n)
{ {
int family = strcmp(qu->id, "rsvp") == 0 ? AF_INET : AF_INET6; int family = strcmp(qu->id, "rsvp") == 0 ? AF_INET : AF_INET6;
struct tc_rsvp_pinfo pinfo = {}; struct tc_rsvp_pinfo pinfo = {};

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* /*
* f_tcindex.c Traffic control index filter * f_tcindex.c Traffic control index filter
* *

View File

@ -11,10 +11,11 @@
* TODO: * TODO:
* - parse to be passed a filedescriptor for logging purposes * - parse to be passed a filedescriptor for logging purposes
* *
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/socket.h> #include <sys/socket.h>
@ -41,7 +42,7 @@ static void act_usage(void)
* with any action .so from the old days. But if someone really * with any action .so from the old days. But if someone really
* does that, they would know how to fix this .. * does that, they would know how to fix this ..
* *
*/ */
fprintf(stderr, "usage: tc actions <ACTSPECOP>*\n"); fprintf(stderr, "usage: tc actions <ACTSPECOP>*\n");
fprintf(stderr, fprintf(stderr,
"Where: \tACTSPECOP := ACR | GD | FL\n" "Where: \tACTSPECOP := ACR | GD | FL\n"
@ -68,16 +69,19 @@ static int print_noaopt(struct action_util *au, FILE *f, struct rtattr *opt)
return 0; return 0;
} }
static int parse_noaopt(struct action_util *au, int *argc_p, char ***argv_p, int code, struct nlmsghdr *n) static int parse_noaopt(struct action_util *au, int *argc_p,
char ***argv_p, int code, struct nlmsghdr *n)
{ {
int argc = *argc_p; int argc = *argc_p;
char **argv = *argv_p; char **argv = *argv_p;
if (argc) { if (argc)
fprintf(stderr, "Unknown action \"%s\", hence option \"%s\" is unparsable\n", au->id, *argv); fprintf(stderr,
} else { "Unknown action \"%s\", hence option \"%s\" is unparsable\n",
au->id, *argv);
else
fprintf(stderr, "Unknown action \"%s\"\n", au->id); fprintf(stderr, "Unknown action \"%s\"\n", au->id);
}
return -1; return -1;
} }
@ -135,18 +139,14 @@ noexist:
return a; return a;
} }
static int static bool
new_cmd(char **argv) new_cmd(char **argv)
{ {
if ((matches(*argv, "change") == 0) || return (matches(*argv, "change") == 0) ||
(matches(*argv, "replace") == 0) || (matches(*argv, "replace") == 0) ||
(matches(*argv, "delete") == 0) || (matches(*argv, "delete") == 0) ||
(matches(*argv, "get") == 0) || (matches(*argv, "get") == 0) ||
(matches(*argv, "add") == 0)) (matches(*argv, "add") == 0);
return 1;
return 0;
} }
int parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) int parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
@ -154,7 +154,7 @@ int parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
int argc = *argc_p; int argc = *argc_p;
char **argv = *argv_p; char **argv = *argv_p;
struct rtattr *tail, *tail2; struct rtattr *tail, *tail2;
char k[16]; char k[FILTER_NAMESZ];
int act_ck_len = 0; int act_ck_len = 0;
int ok = 0; int ok = 0;
int eap = 0; /* expect action parameters */ int eap = 0; /* expect action parameters */
@ -179,9 +179,8 @@ int parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
argv++; argv++;
eap = 1; eap = 1;
#ifdef CONFIG_GACT #ifdef CONFIG_GACT
if (!gact_ld) { if (!gact_ld)
get_action_kind("gact"); get_action_kind("gact");
}
#endif #endif
continue; continue;
} else if (strcmp(*argv, "flowid") == 0) { } else if (strcmp(*argv, "flowid") == 0) {
@ -207,9 +206,9 @@ done0:
goto done; goto done;
} }
if (a == NULL) { if (a == NULL)
goto bad_val; goto bad_val;
}
tail = NLMSG_TAIL(n); tail = NLMSG_TAIL(n);
addattr_l(n, MAX_MSG, ++prio, NULL, 0); addattr_l(n, MAX_MSG, ++prio, NULL, 0);
@ -268,7 +267,8 @@ done:
return 0; return 0;
bad_val: bad_val:
/* no need to undo things, returning from here should /* no need to undo things, returning from here should
* cause enough pain */ * cause enough pain
*/
fprintf(stderr, "parse_action: bad value (%d:%s)!\n", argc, *argv); fprintf(stderr, "parse_action: bad value (%d:%s)!\n", argc, *argv);
return -1; return -1;
} }
@ -301,18 +301,19 @@ static int tc_print_one_action(FILE *f, struct rtattr *arg)
return err; return err;
if (show_stats && tb[TCA_ACT_STATS]) { if (show_stats && tb[TCA_ACT_STATS]) {
print_string(PRINT_FP, NULL, "\tAction statistics:\n", NULL);
fprintf(f, "\tAction statistics:\n"); open_json_object("stats");
print_tcstats2_attr(f, tb[TCA_ACT_STATS], "\t", NULL); print_tcstats2_attr(f, tb[TCA_ACT_STATS], "\t", NULL);
if (tb[TCA_ACT_COOKIE]) { close_json_object();
int strsz = RTA_PAYLOAD(tb[TCA_ACT_COOKIE]); print_string(PRINT_FP, NULL, "\n", NULL);
char b1[strsz * 2 + 1]; }
if (tb[TCA_ACT_COOKIE]) {
int strsz = RTA_PAYLOAD(tb[TCA_ACT_COOKIE]);
char b1[strsz * 2 + 1];
fprintf(f, "\n\tcookie len %d %s ", strsz, print_string(PRINT_ANY, "cookie", "\tcookie %s\n",
hexstring_n2a(RTA_DATA(tb[TCA_ACT_COOKIE]), hexstring_n2a(RTA_DATA(tb[TCA_ACT_COOKIE]),
strsz, b1, sizeof(b1))); strsz, b1, sizeof(b1)));
}
fprintf(f, "\n");
} }
return 0; return 0;
@ -363,15 +364,21 @@ tc_print_action(FILE *f, const struct rtattr *arg, unsigned short tot_acts)
if (tab_flush && NULL != tb[0] && NULL == tb[1]) if (tab_flush && NULL != tb[0] && NULL == tb[1])
return tc_print_action_flush(f, tb[0]); return tc_print_action_flush(f, tb[0]);
open_json_array(PRINT_JSON, "actions");
for (i = 0; i < tot_acts; i++) { for (i = 0; i < tot_acts; i++) {
if (tb[i]) { if (tb[i]) {
fprintf(f, "\n\taction order %d: ", i); open_json_object(NULL);
print_uint(PRINT_ANY, "order",
"\n\taction order %u: ", i);
if (tc_print_one_action(f, tb[i]) < 0) { if (tc_print_one_action(f, tb[i]) < 0) {
fprintf(f, "Error printing action\n"); print_string(PRINT_FP, NULL,
"Error printing action\n", NULL);
} }
close_json_object();
} }
} }
close_json_object();
return 0; return 0;
} }
@ -429,9 +436,10 @@ int print_action(const struct sockaddr_nl *who,
return 0; return 0;
} }
static int tc_action_gd(int cmd, unsigned int flags, int *argc_p, char ***argv_p) static int tc_action_gd(int cmd, unsigned int flags,
int *argc_p, char ***argv_p)
{ {
char k[16]; char k[FILTER_NAMESZ];
struct action_util *a = NULL; struct action_util *a = NULL;
int argc = *argc_p; int argc = *argc_p;
char **argv = *argv_p; char **argv = *argv_p;
@ -485,7 +493,8 @@ static int tc_action_gd(int cmd, unsigned int flags, int *argc_p, char ***argv_p
argc -= 1; argc -= 1;
argv += 1; argv += 1;
if (argc <= 0) { if (argc <= 0) {
fprintf(stderr, "Error: no index specified action: %s\n", k); fprintf(stderr,
"Error: no index specified action: %s\n", k);
ret = -1; ret = -1;
goto bad_val; goto bad_val;
} }
@ -500,7 +509,8 @@ static int tc_action_gd(int cmd, unsigned int flags, int *argc_p, char ***argv_p
argc -= 1; argc -= 1;
argv += 1; argv += 1;
} else { } else {
fprintf(stderr, "Error: no index specified action: %s\n", k); fprintf(stderr,
"Error: no index specified action: %s\n", k);
ret = -1; ret = -1;
goto bad_val; goto bad_val;
} }
@ -536,7 +546,8 @@ bad_val:
return ret; return ret;
} }
static int tc_action_modify(int cmd, unsigned int flags, int *argc_p, char ***argv_p) static int tc_action_modify(int cmd, unsigned int flags,
int *argc_p, char ***argv_p)
{ {
int argc = *argc_p; int argc = *argc_p;
char **argv = *argv_p; char **argv = *argv_p;
@ -581,7 +592,7 @@ static int tc_act_list_or_flush(int *argc_p, char ***argv_p, int event)
char **argv = *argv_p; char **argv = *argv_p;
__u32 msec_since = 0; __u32 msec_since = 0;
int argc = *argc_p; int argc = *argc_p;
char k[16]; char k[FILTER_NAMESZ];
struct { struct {
struct nlmsghdr n; struct nlmsghdr n;
struct tcamsg t; struct tcamsg t;
@ -597,9 +608,9 @@ static int tc_act_list_or_flush(int *argc_p, char ***argv_p, int event)
strncpy(k, *argv, sizeof(k) - 1); strncpy(k, *argv, sizeof(k) - 1);
#ifdef CONFIG_GACT #ifdef CONFIG_GACT
if (!gact_ld) { if (!gact_ld)
get_action_kind("gact"); get_action_kind("gact");
}
#endif #endif
a = get_action_kind(k); a = get_action_kind(k);
if (a == NULL) { if (a == NULL) {
@ -637,10 +648,12 @@ static int tc_act_list_or_flush(int *argc_p, char ***argv_p, int event)
addattr32(&req.n, MAX_MSG, TCA_ROOT_TIME_DELTA, msec_since); addattr32(&req.n, MAX_MSG, TCA_ROOT_TIME_DELTA, msec_since);
tail4->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail4; tail4->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail4;
} }
msg_size = NLMSG_ALIGN(req.n.nlmsg_len) - NLMSG_ALIGN(sizeof(struct nlmsghdr)); msg_size = NLMSG_ALIGN(req.n.nlmsg_len)
- NLMSG_ALIGN(sizeof(struct nlmsghdr));
if (event == RTM_GETACTION) { if (event == RTM_GETACTION) {
if (rtnl_dump_request(&rth, event, (void *)&req.t, msg_size) < 0) { if (rtnl_dump_request(&rth, event,
(void *)&req.t, msg_size) < 0) {
perror("Cannot send dump request"); perror("Cannot send dump request");
return 1; return 1;
} }
@ -674,10 +687,14 @@ int do_action(int argc, char **argv)
while (argc > 0) { while (argc > 0) {
if (matches(*argv, "add") == 0) { if (matches(*argv, "add") == 0) {
ret = tc_action_modify(RTM_NEWACTION, NLM_F_EXCL|NLM_F_CREATE, &argc, &argv); ret = tc_action_modify(RTM_NEWACTION,
NLM_F_EXCL | NLM_F_CREATE,
&argc, &argv);
} else if (matches(*argv, "change") == 0 || } else if (matches(*argv, "change") == 0 ||
matches(*argv, "replace") == 0) { matches(*argv, "replace") == 0) {
ret = tc_action_modify(RTM_NEWACTION, NLM_F_CREATE|NLM_F_REPLACE, &argc, &argv); ret = tc_action_modify(RTM_NEWACTION,
NLM_F_CREATE | NLM_F_REPLACE,
&argc, &argv);
} else if (matches(*argv, "delete") == 0) { } else if (matches(*argv, "delete") == 0) {
argc -= 1; argc -= 1;
argv += 1; argv += 1;
@ -686,8 +703,9 @@ int do_action(int argc, char **argv)
argc -= 1; argc -= 1;
argv += 1; argv += 1;
ret = tc_action_gd(RTM_GETACTION, 0, &argc, &argv); ret = tc_action_gd(RTM_GETACTION, 0, &argc, &argv);
} else if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0 } else if (matches(*argv, "list") == 0 ||
|| matches(*argv, "lst") == 0) { matches(*argv, "show") == 0 ||
matches(*argv, "lst") == 0) {
if (argc <= 2) { if (argc <= 2) {
act_usage(); act_usage();
return -1; return -1;
@ -711,7 +729,9 @@ int do_action(int argc, char **argv)
act_usage(); act_usage();
return -1; return -1;
} else { } else {
fprintf(stderr, "Command \"%s\" is unknown, try \"tc actions help\".\n", *argv); fprintf(stderr,
"Command \"%s\" is unknown, try \"tc actions help\".\n",
*argv);
return -1; return -1;
} }

View File

@ -96,12 +96,16 @@ static int bpf_parse_opt(struct action_util *a, int *ptr_argc, char ***ptr_argv,
while (argc > 0) { while (argc > 0) {
if (matches(*argv, "run") == 0) { if (matches(*argv, "run") == 0) {
NEXT_ARG(); NEXT_ARG();
if (seen_run)
duparg("run", *argv);
opt_bpf: opt_bpf:
seen_run = true; seen_run = true;
cfg.type = bpf_type;
cfg.argc = argc; cfg.argc = argc;
cfg.argv = argv; cfg.argv = argv;
if (bpf_parse_common(bpf_type, &cfg, &bpf_cb_ops, n)) if (bpf_parse_and_load_common(&cfg, &bpf_cb_ops, n))
return -1; return -1;
argc = cfg.argc; argc = cfg.argc;

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __TC_EMATCH_H_ #ifndef __TC_EMATCH_H_
#define __TC_EMATCH_H_ #define __TC_EMATCH_H_

View File

@ -115,17 +115,21 @@ parse_gact(struct action_util *a, int *argc_p, char ***argv_p,
&pp.paction, false) == -1) &pp.paction, false) == -1)
usage(); usage();
if (get_u16(&pp.pval, *argv, 10)) { if (get_u16(&pp.pval, *argv, 10)) {
fprintf(stderr, "Illegal probability val 0x%x\n", pp.pval); fprintf(stderr,
"Illegal probability val 0x%x\n",
pp.pval);
return -1; return -1;
} }
if (pp.pval > 10000) { if (pp.pval > 10000) {
fprintf(stderr, "Illegal probability val 0x%x\n", pp.pval); fprintf(stderr,
"Illegal probability val 0x%x\n",
pp.pval);
return -1; return -1;
} }
argc--; argc--;
argv++; argv++;
} else if (matches(*argv, "help") == 0) { } else if (matches(*argv, "help") == 0) {
usage(); usage();
} }
} }
#endif #endif
@ -140,7 +144,7 @@ parse_gact(struct action_util *a, int *argc_p, char ***argv_p,
argc--; argc--;
argv++; argv++;
} else if (matches(*argv, "help") == 0) { } else if (matches(*argv, "help") == 0) {
usage(); usage();
} }
} }
@ -148,9 +152,8 @@ parse_gact(struct action_util *a, int *argc_p, char ***argv_p,
addattr_l(n, MAX_MSG, tca_id, NULL, 0); addattr_l(n, MAX_MSG, tca_id, NULL, 0);
addattr_l(n, MAX_MSG, TCA_GACT_PARMS, &p, sizeof(p)); addattr_l(n, MAX_MSG, TCA_GACT_PARMS, &p, sizeof(p));
#ifdef CONFIG_GACT_PROB #ifdef CONFIG_GACT_PROB
if (rd) { if (rd)
addattr_l(n, MAX_MSG, TCA_GACT_PROB, &pp, sizeof(pp)); addattr_l(n, MAX_MSG, TCA_GACT_PROB, &pp, sizeof(pp));
}
#endif #endif
tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
@ -160,7 +163,7 @@ parse_gact(struct action_util *a, int *argc_p, char ***argv_p,
} }
static int static int
print_gact(struct action_util *au, FILE * f, struct rtattr *arg) print_gact(struct action_util *au, FILE *f, struct rtattr *arg)
{ {
#ifdef CONFIG_GACT_PROB #ifdef CONFIG_GACT_PROB
struct tc_gact_p *pp = NULL; struct tc_gact_p *pp = NULL;
@ -175,12 +178,12 @@ print_gact(struct action_util *au, FILE * f, struct rtattr *arg)
parse_rtattr_nested(tb, TCA_GACT_MAX, arg); parse_rtattr_nested(tb, TCA_GACT_MAX, arg);
if (tb[TCA_GACT_PARMS] == NULL) { if (tb[TCA_GACT_PARMS] == NULL) {
fprintf(f, "[NULL gact parameters]"); print_string(PRINT_FP, NULL, "%s", "[NULL gact parameters]");
return -1; return -1;
} }
p = RTA_DATA(tb[TCA_GACT_PARMS]); p = RTA_DATA(tb[TCA_GACT_PARMS]);
fprintf(f, "gact "); print_string(PRINT_ANY, "kind", "%s ", "gact");
print_action_control(f, "action ", p->action, ""); print_action_control(f, "action ", p->action, "");
#ifdef CONFIG_GACT_PROB #ifdef CONFIG_GACT_PROB
if (tb[TCA_GACT_PROB] != NULL) { if (tb[TCA_GACT_PROB] != NULL) {
@ -190,12 +193,16 @@ print_gact(struct action_util *au, FILE * f, struct rtattr *arg)
memset(&pp_dummy, 0, sizeof(pp_dummy)); memset(&pp_dummy, 0, sizeof(pp_dummy));
pp = &pp_dummy; pp = &pp_dummy;
} }
fprintf(f, "\n\t random type %s", prob_n2a(pp->ptype)); open_json_object("prob");
print_string(PRINT_ANY, "random_type", "\n\t random type %s",
prob_n2a(pp->ptype));
print_action_control(f, " ", pp->paction, " "); print_action_control(f, " ", pp->paction, " ");
fprintf(f, "val %d", pp->pval); print_int(PRINT_ANY, "val", "val %d", pp->pval);
close_json_object();
#endif #endif
fprintf(f, "\n\t index %u ref %d bind %d", p->index, p->refcnt, print_uint(PRINT_ANY, "index", "\n\t index %u", p->index);
p->bindcnt); print_int(PRINT_ANY, "ref", " ref %d", p->refcnt);
print_int(PRINT_ANY, "bind", " bind %d", p->bindcnt);
if (show_stats) { if (show_stats) {
if (tb[TCA_GACT_TM]) { if (tb[TCA_GACT_TM]) {
struct tcf_t *tm = RTA_DATA(tb[TCA_GACT_TM]); struct tcf_t *tm = RTA_DATA(tb[TCA_GACT_TM]);
@ -203,7 +210,7 @@ print_gact(struct action_util *au, FILE * f, struct rtattr *arg)
print_tm(f, tm); print_tm(f, tm);
} }
} }
fprintf(f, "\n "); print_string(PRINT_FP, NULL, "%s", "\n");
return 0; return 0;
} }

View File

@ -286,7 +286,7 @@ static int parse_ipt(struct action_util *a, int *argc_p,
int rargc = *argc_p; int rargc = *argc_p;
char **argv = *argv_p; char **argv = *argv_p;
int argc = 0, iargc = 0; int argc = 0, iargc = 0;
char k[16]; char k[FILTER_NAMESZ];
int size = 0; int size = 0;
int iok = 0, ok = 0; int iok = 0, ok = 0;
__u32 hook = 0, index = 0; __u32 hook = 0, index = 0;

View File

@ -28,13 +28,13 @@
static void static void
explain(void) explain(void)
{ {
fprintf(stderr, "Usage: mirred <DIRECTION> <ACTION> [index INDEX] <dev DEVICENAME>\n"); fprintf(stderr,
fprintf(stderr, "where:\n"); "Usage: mirred <DIRECTION> <ACTION> [index INDEX] <dev DEVICENAME>\n"
fprintf(stderr, "\tDIRECTION := <ingress | egress>\n"); "where:\n"
fprintf(stderr, "\tACTION := <mirror | redirect>\n"); "\tDIRECTION := <ingress | egress>\n"
fprintf(stderr, "\tINDEX is the specific policy instance id\n"); "\tACTION := <mirror | redirect>\n"
fprintf(stderr, "\tDEVICENAME is the devicename\n"); "\tINDEX is the specific policy instance id\n"
"\tDEVICENAME is the devicename\n");
} }
static void static void
@ -60,6 +60,34 @@ static const char *mirred_n2a(int action)
} }
} }
static const char *mirred_direction(int action)
{
switch (action) {
case TCA_EGRESS_REDIR:
case TCA_EGRESS_MIRROR:
return "egress";
case TCA_INGRESS_REDIR:
case TCA_INGRESS_MIRROR:
return "ingress";
default:
return "unknown";
}
}
static const char *mirred_action(int action)
{
switch (action) {
case TCA_EGRESS_REDIR:
case TCA_INGRESS_REDIR:
return "redirect";
case TCA_EGRESS_MIRROR:
case TCA_INGRESS_MIRROR:
return "mirror";
default:
return "unknown";
}
}
static int static int
parse_direction(struct action_util *a, int *argc_p, char ***argv_p, parse_direction(struct action_util *a, int *argc_p, char ***argv_p,
int tca_id, struct nlmsghdr *n) int tca_id, struct nlmsghdr *n)
@ -70,7 +98,7 @@ parse_direction(struct action_util *a, int *argc_p, char ***argv_p,
int ok = 0, iok = 0, mirror = 0, redir = 0, ingress = 0, egress = 0; int ok = 0, iok = 0, mirror = 0, redir = 0, ingress = 0, egress = 0;
struct tc_mirred p = {}; struct tc_mirred p = {};
struct rtattr *tail; struct rtattr *tail;
char d[16] = {}; char d[IFNAMSIZ] = {};
while (argc > 0) { while (argc > 0) {
@ -79,7 +107,8 @@ parse_direction(struct action_util *a, int *argc_p, char ***argv_p,
} else if (!egress && matches(*argv, "egress") == 0) { } else if (!egress && matches(*argv, "egress") == 0) {
egress = 1; egress = 1;
if (ingress) { if (ingress) {
fprintf(stderr, "Can't have both egress and ingress\n"); fprintf(stderr,
"Can't have both egress and ingress\n");
return -1; return -1;
} }
NEXT_ARG(); NEXT_ARG();
@ -88,7 +117,8 @@ parse_direction(struct action_util *a, int *argc_p, char ***argv_p,
} else if (!ingress && matches(*argv, "ingress") == 0) { } else if (!ingress && matches(*argv, "ingress") == 0) {
ingress = 1; ingress = 1;
if (egress) { if (egress) {
fprintf(stderr, "Can't have both ingress and egress\n"); fprintf(stderr,
"Can't have both ingress and egress\n");
return -1; return -1;
} }
NEXT_ARG(); NEXT_ARG();
@ -109,30 +139,35 @@ parse_direction(struct action_util *a, int *argc_p, char ***argv_p,
break; break;
} }
} else if (!ok) { } else if (!ok) {
fprintf(stderr, "was expecting egress or ingress (%s)\n", *argv); fprintf(stderr,
"was expecting egress or ingress (%s)\n",
*argv);
break; break;
} else if (!mirror && matches(*argv, "mirror") == 0) { } else if (!mirror && matches(*argv, "mirror") == 0) {
mirror = 1; mirror = 1;
if (redir) { if (redir) {
fprintf(stderr, "Can't have both mirror and redir\n"); fprintf(stderr,
"Can't have both mirror and redir\n");
return -1; return -1;
} }
p.eaction = egress ? TCA_EGRESS_MIRROR : p.eaction = egress ? TCA_EGRESS_MIRROR :
TCA_INGRESS_MIRROR; TCA_INGRESS_MIRROR;
p.action = TC_ACT_PIPE; p.action = TC_ACT_PIPE;
ok++; ok++;
} else if (!redir && matches(*argv, "redirect") == 0) { } else if (!redir && matches(*argv, "redirect") == 0) {
redir = 1; redir = 1;
if (mirror) { if (mirror) {
fprintf(stderr, "Can't have both mirror and redir\n"); fprintf(stderr,
"Can't have both mirror and redir\n");
return -1; return -1;
} }
p.eaction = egress ? TCA_EGRESS_REDIR : p.eaction = egress ? TCA_EGRESS_REDIR :
TCA_INGRESS_REDIR; TCA_INGRESS_REDIR;
p.action = TC_ACT_STOLEN; p.action = TC_ACT_STOLEN;
ok++; ok++;
} else if ((redir || mirror) && matches(*argv, "dev") == 0) { } else if ((redir || mirror) &&
matches(*argv, "dev") == 0) {
NEXT_ARG(); NEXT_ARG();
if (strlen(d)) if (strlen(d))
duparg("dev", *argv); duparg("dev", *argv);
@ -149,18 +184,16 @@ parse_direction(struct action_util *a, int *argc_p, char ***argv_p,
NEXT_ARG(); NEXT_ARG();
} }
if (!ok && !iok) { if (!ok && !iok)
return -1; return -1;
}
if (d[0]) { if (d[0]) {
int idx; int idx;
ll_init_map(&rth); ll_init_map(&rth);
if ((idx = ll_name_to_index(d)) == 0) { idx = ll_name_to_index(d);
if (idx == 0) {
fprintf(stderr, "Cannot find device \"%s\"\n", d); fprintf(stderr, "Cannot find device \"%s\"\n", d);
return -1; return -1;
} }
@ -176,16 +209,17 @@ parse_direction(struct action_util *a, int *argc_p, char ***argv_p,
if (iok && matches(*argv, "index") == 0) { if (iok && matches(*argv, "index") == 0) {
fprintf(stderr, "mirred: Illegal double index\n"); fprintf(stderr, "mirred: Illegal double index\n");
return -1; return -1;
} else { }
if (matches(*argv, "index") == 0) {
NEXT_ARG(); if (matches(*argv, "index") == 0) {
if (get_u32(&p.index, *argv, 10)) { NEXT_ARG();
fprintf(stderr, "mirred: Illegal \"index\"\n"); if (get_u32(&p.index, *argv, 10)) {
return -1; fprintf(stderr,
} "mirred: Illegal \"index\"\n");
argc--; return -1;
argv++;
} }
argc--;
argv++;
} }
} }
@ -242,7 +276,7 @@ parse_mirred(struct action_util *a, int *argc_p, char ***argv_p,
} }
static int static int
print_mirred(struct action_util *au, FILE * f, struct rtattr *arg) print_mirred(struct action_util *au, FILE *f, struct rtattr *arg)
{ {
struct tc_mirred *p; struct tc_mirred *p;
struct rtattr *tb[TCA_MIRRED_MAX + 1]; struct rtattr *tb[TCA_MIRRED_MAX + 1];
@ -254,27 +288,29 @@ print_mirred(struct action_util *au, FILE * f, struct rtattr *arg)
parse_rtattr_nested(tb, TCA_MIRRED_MAX, arg); parse_rtattr_nested(tb, TCA_MIRRED_MAX, arg);
if (tb[TCA_MIRRED_PARMS] == NULL) { if (tb[TCA_MIRRED_PARMS] == NULL) {
fprintf(f, "[NULL mirred parameters]"); print_string(PRINT_FP, NULL, "%s", "[NULL mirred parameters]");
return -1; return -1;
} }
p = RTA_DATA(tb[TCA_MIRRED_PARMS]); p = RTA_DATA(tb[TCA_MIRRED_PARMS]);
/* dev = ll_index_to_name(p->ifindex);
ll_init_map(&rth); if (dev == 0) {
*/
if ((dev = ll_index_to_name(p->ifindex)) == 0) {
fprintf(stderr, "Cannot find device %d\n", p->ifindex); fprintf(stderr, "Cannot find device %d\n", p->ifindex);
return -1; return -1;
} }
fprintf(f, "mirred (%s to device %s)", mirred_n2a(p->eaction), dev); print_string(PRINT_ANY, "kind", "%s ", "mirred");
print_string(PRINT_FP, NULL, "(%s", mirred_n2a(p->eaction));
print_string(PRINT_JSON, "mirred_action", NULL,
mirred_action(p->eaction));
print_string(PRINT_JSON, "direction", NULL,
mirred_direction(p->eaction));
print_string(PRINT_ANY, "to_dev", " to device %s)", dev);
print_action_control(f, " ", p->action, ""); print_action_control(f, " ", p->action, "");
fprintf(f, "\n "); print_uint(PRINT_ANY, "index", "\n \tindex %u", p->index);
fprintf(f, "\tindex %u ref %d bind %d", p->index, p->refcnt, print_int(PRINT_ANY, "ref", " ref %d", p->refcnt);
p->bindcnt); print_int(PRINT_ANY, "bind", " bind %d", p->bindcnt);
if (show_stats) { if (show_stats) {
if (tb[TCA_MIRRED_TM]) { if (tb[TCA_MIRRED_TM]) {
@ -283,7 +319,7 @@ print_mirred(struct action_util *au, FILE * f, struct rtattr *arg)
print_tm(f, tm); print_tm(f, tm);
} }
} }
fprintf(f, "\n "); print_string(PRINT_FP, NULL, "%s", "\n ");
return 0; return 0;
} }

View File

@ -524,7 +524,7 @@ static int parse_munge(int *argc_p, char ***argv_p, struct m_pedit_sel *sel)
res = parse_offset(&argc, &argv, sel, &tkey); res = parse_offset(&argc, &argv, sel, &tkey);
goto done; goto done;
} else { } else {
char k[16]; char k[FILTER_NAMESZ];
struct m_pedit_util *p = NULL; struct m_pedit_util *p = NULL;
strncpy(k, *argv, sizeof(k) - 1); strncpy(k, *argv, sizeof(k) - 1);

View File

@ -27,13 +27,14 @@ static const char * const action_names[] = {
static void explain(void) static void explain(void)
{ {
fprintf(stderr, "Usage: vlan pop\n"); fprintf(stderr,
fprintf(stderr, " vlan push [ protocol VLANPROTO ] id VLANID [ priority VLANPRIO ] [CONTROL]\n"); "Usage: vlan pop\n"
fprintf(stderr, " vlan modify [ protocol VLANPROTO ] id VLANID [ priority VLANPRIO ] [CONTROL]\n"); " vlan push [ protocol VLANPROTO ] id VLANID [ priority VLANPRIO ] [CONTROL]\n"
fprintf(stderr, " VLANPROTO is one of 802.1Q or 802.1AD\n"); " vlan modify [ protocol VLANPROTO ] id VLANID [ priority VLANPRIO ] [CONTROL]\n"
fprintf(stderr, " with default: 802.1Q\n"); " VLANPROTO is one of 802.1Q or 802.1AD\n"
fprintf(stderr, " CONTROL := reclassify | pipe | drop | continue | pass |\n"); " with default: 802.1Q\n"
fprintf(stderr, " goto chain <CHAIN_INDEX>\n"); " CONTROL := reclassify | pipe | drop | continue | pass |\n"
" goto chain <CHAIN_INDEX>\n");
} }
static void usage(void) static void usage(void)
@ -47,6 +48,14 @@ static bool has_push_attribs(int action)
return action == TCA_VLAN_ACT_PUSH || action == TCA_VLAN_ACT_MODIFY; return action == TCA_VLAN_ACT_PUSH || action == TCA_VLAN_ACT_MODIFY;
} }
static void unexpected(const char *arg)
{
fprintf(stderr,
"unexpected \"%s\" - action already specified\n",
arg);
explain();
}
static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p, static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p,
int tca_id, struct nlmsghdr *n) int tca_id, struct nlmsghdr *n)
{ {
@ -70,57 +79,42 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p,
while (argc > 0) { while (argc > 0) {
if (matches(*argv, "pop") == 0) { if (matches(*argv, "pop") == 0) {
if (action) { if (action) {
fprintf(stderr, "unexpected \"%s\" - action already specified\n", unexpected(*argv);
*argv);
explain();
return -1; return -1;
} }
action = TCA_VLAN_ACT_POP; action = TCA_VLAN_ACT_POP;
} else if (matches(*argv, "push") == 0) { } else if (matches(*argv, "push") == 0) {
if (action) { if (action) {
fprintf(stderr, "unexpected \"%s\" - action already specified\n", unexpected(*argv);
*argv);
explain();
return -1; return -1;
} }
action = TCA_VLAN_ACT_PUSH; action = TCA_VLAN_ACT_PUSH;
} else if (matches(*argv, "modify") == 0) { } else if (matches(*argv, "modify") == 0) {
if (action) { if (action) {
fprintf(stderr, "unexpected \"%s\" - action already specified\n", unexpected(*argv);
*argv);
explain();
return -1; return -1;
} }
action = TCA_VLAN_ACT_MODIFY; action = TCA_VLAN_ACT_MODIFY;
} else if (matches(*argv, "id") == 0) { } else if (matches(*argv, "id") == 0) {
if (!has_push_attribs(action)) { if (!has_push_attribs(action))
fprintf(stderr, "\"%s\" is only valid for push/modify\n", invarg("only valid for push/modify", *argv);
*argv);
explain();
return -1;
}
NEXT_ARG(); NEXT_ARG();
if (get_u16(&id, *argv, 0)) if (get_u16(&id, *argv, 0))
invarg("id is invalid", *argv); invarg("id is invalid", *argv);
id_set = 1; id_set = 1;
} else if (matches(*argv, "protocol") == 0) { } else if (matches(*argv, "protocol") == 0) {
if (!has_push_attribs(action)) { if (!has_push_attribs(action))
fprintf(stderr, "\"%s\" is only valid for push/modify\n", invarg("only valid for push/modify", *argv);
*argv);
explain();
return -1;
}
NEXT_ARG(); NEXT_ARG();
if (ll_proto_a2n(&proto, *argv)) if (ll_proto_a2n(&proto, *argv))
invarg("protocol is invalid", *argv); invarg("protocol is invalid", *argv);
proto_set = 1; proto_set = 1;
} else if (matches(*argv, "priority") == 0) { } else if (matches(*argv, "priority") == 0) {
if (!has_push_attribs(action)) { if (!has_push_attribs(action))
fprintf(stderr, "\"%s\" is only valid for push/modify\n", invarg("only valid for push/modify", *argv);
*argv);
explain();
return -1;
}
NEXT_ARG(); NEXT_ARG();
if (get_u8(&prio, *argv, 0) || (prio & ~0x7)) if (get_u8(&prio, *argv, 0) || (prio & ~0x7))
invarg("prio is invalid", *argv); invarg("prio is invalid", *argv);
@ -195,39 +189,40 @@ static int print_vlan(struct action_util *au, FILE *f, struct rtattr *arg)
parse_rtattr_nested(tb, TCA_VLAN_MAX, arg); parse_rtattr_nested(tb, TCA_VLAN_MAX, arg);
if (!tb[TCA_VLAN_PARMS]) { if (!tb[TCA_VLAN_PARMS]) {
fprintf(f, "[NULL vlan parameters]"); print_string(PRINT_FP, NULL, "%s", "[NULL vlan parameters]");
return -1; return -1;
} }
parm = RTA_DATA(tb[TCA_VLAN_PARMS]); parm = RTA_DATA(tb[TCA_VLAN_PARMS]);
fprintf(f, " vlan"); print_string(PRINT_ANY, "kind", "%s ", "vlan");
print_string(PRINT_ANY, "vlan_action", " %s",
action_names[parm->v_action]);
switch (parm->v_action) { switch (parm->v_action) {
case TCA_VLAN_ACT_POP:
fprintf(f, " pop");
break;
case TCA_VLAN_ACT_PUSH: case TCA_VLAN_ACT_PUSH:
case TCA_VLAN_ACT_MODIFY: case TCA_VLAN_ACT_MODIFY:
fprintf(f, " %s", action_names[parm->v_action]);
if (tb[TCA_VLAN_PUSH_VLAN_ID]) { if (tb[TCA_VLAN_PUSH_VLAN_ID]) {
val = rta_getattr_u16(tb[TCA_VLAN_PUSH_VLAN_ID]); val = rta_getattr_u16(tb[TCA_VLAN_PUSH_VLAN_ID]);
fprintf(f, " id %u", val); print_uint(PRINT_ANY, "id", " id %u", val);
} }
if (tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]) { if (tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]) {
fprintf(f, " protocol %s", __u16 proto;
ll_proto_n2a(rta_getattr_u16(tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]),
b1, sizeof(b1))); proto = rta_getattr_u16(tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]);
print_string(PRINT_ANY, "protocol", " protocol %s",
ll_proto_n2a(proto, b1, sizeof(b1)));
} }
if (tb[TCA_VLAN_PUSH_VLAN_PRIORITY]) { if (tb[TCA_VLAN_PUSH_VLAN_PRIORITY]) {
val = rta_getattr_u8(tb[TCA_VLAN_PUSH_VLAN_PRIORITY]); val = rta_getattr_u8(tb[TCA_VLAN_PUSH_VLAN_PRIORITY]);
fprintf(f, " priority %u", val); print_uint(PRINT_ANY, "priority", " priority %u", val);
} }
break; break;
} }
print_action_control(f, " ", parm->action, ""); print_action_control(f, " ", parm->action, "");
fprintf(f, "\n\t index %u ref %d bind %d", parm->index, parm->refcnt, print_uint(PRINT_ANY, "index", "\n\t index %u", parm->index);
parm->bindcnt); print_int(PRINT_ANY, "ref", " ref %d", parm->refcnt);
print_int(PRINT_ANY, "bind", " bind %d", parm->bindcnt);
if (show_stats) { if (show_stats) {
if (tb[TCA_VLAN_TM]) { if (tb[TCA_VLAN_TM]) {
@ -237,7 +232,7 @@ static int print_vlan(struct action_util *au, FILE *f, struct rtattr *arg)
} }
} }
fprintf(f, "\n "); print_string(PRINT_FP, NULL, "%s", "\n");
return 0; return 0;
} }

View File

@ -154,7 +154,7 @@ static int parse_ipt(struct action_util *a, int *argc_p,
int c; int c;
char **argv = *argv_p; char **argv = *argv_p;
int argc; int argc;
char k[16]; char k[FILTER_NAMESZ];
int size = 0; int size = 0;
int iok = 0, ok = 0; int iok = 0, ok = 0;
__u32 hook = 0, index = 0; __u32 hook = 0, index = 0;

Some files were not shown because too many files have changed in this diff Show More