diff --git a/bridge/fdb.c b/bridge/fdb.c index df55e86d..be849f98 100644 --- a/bridge/fdb.c +++ b/bridge/fdb.c @@ -27,7 +27,7 @@ #include "rt_names.h" #include "utils.h" -static unsigned int filter_index; +static unsigned int filter_index, filter_vlan; static void usage(void) { @@ -35,7 +35,7 @@ static void usage(void) " [ self ] [ master ] [ use ] [ router ]\n" " [ local | static | dynamic ] [ dst IPADDR ] [ vlan VID ]\n" " [ port PORT] [ vni VNI ] [ via DEV ]\n"); - fprintf(stderr, " bridge fdb [ show [ br BRDEV ] [ brport DEV ] ]\n"); + fprintf(stderr, " bridge fdb [ show [ br BRDEV ] [ brport DEV ] [ vlan VID ] ]\n"); exit(-1); } @@ -65,6 +65,7 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) struct ndmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[NDA_MAX+1]; + __u16 vid = 0; if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH) { fprintf(stderr, "Not RTM_NEWNEIGH: %08x %08x %08x\n", @@ -88,6 +89,12 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) parse_rtattr(tb, NDA_MAX, NDA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); + if (tb[NDA_VLAN]) + vid = rta_getattr_u16(tb[NDA_VLAN]); + + if (filter_vlan && filter_vlan != vid) + return 0; + if (n->nlmsg_type == RTM_DELNEIGH) fprintf(fp, "Deleted "); @@ -115,11 +122,8 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) RTA_DATA(tb[NDA_DST]))); } - if (tb[NDA_VLAN]) { - __u16 vid = rta_getattr_u16(tb[NDA_VLAN]); - + if (vid) fprintf(fp, "vlan %hu ", vid); - } if (tb[NDA_PORT]) fprintf(fp, "port %d ", ntohs(rta_getattr_u16(tb[NDA_PORT]))); @@ -190,6 +194,11 @@ static int fdb_show(int argc, char **argv) } else if (strcmp(*argv, "br") == 0) { NEXT_ARG(); br = *argv; + } else if (strcmp(*argv, "vlan") == 0) { + NEXT_ARG(); + if (filter_vlan) + duparg("vlan", *argv); + filter_vlan = atoi(*argv); } else { if (matches(*argv, "help") == 0) usage(); diff --git a/bridge/mdb.c b/bridge/mdb.c index 842536ec..6c904f8e 100644 --- a/bridge/mdb.c +++ b/bridge/mdb.c @@ -24,12 +24,12 @@ ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct br_port_msg)))) #endif -static unsigned int filter_index; +static unsigned int filter_index, filter_vlan; static void usage(void) { fprintf(stderr, "Usage: bridge mdb { add | del } dev DEV port PORT grp GROUP [permanent | temp] [vid VID]\n"); - fprintf(stderr, " bridge mdb {show} [ dev DEV ]\n"); + fprintf(stderr, " bridge mdb {show} [ dev DEV ] [ vid VID ]\n"); exit(-1); } @@ -92,6 +92,8 @@ static void print_mdb_entry(FILE *f, int ifindex, struct br_mdb_entry *e, const void *src; int af; + if (filter_vlan && e->vid != filter_vlan) + return; af = e->addr.proto == htons(ETH_P_IP) ? AF_INET : AF_INET6; src = af == AF_INET ? (const void *)&e->addr.u.ip4 : (const void *)&e->addr.u.ip6; @@ -195,6 +197,11 @@ static int mdb_show(int argc, char **argv) if (filter_dev) duparg("dev", *argv); filter_dev = *argv; + } else if (strcmp(*argv, "vid") == 0) { + NEXT_ARG(); + if (filter_vlan) + duparg("vid", *argv); + filter_vlan = atoi(*argv); } argc--; argv++; } diff --git a/bridge/vlan.c b/bridge/vlan.c index ae588323..717025ae 100644 --- a/bridge/vlan.c +++ b/bridge/vlan.c @@ -13,13 +13,13 @@ #include "br_common.h" #include "utils.h" -static unsigned int filter_index; +static unsigned int filter_index, filter_vlan; static void usage(void) { fprintf(stderr, "Usage: bridge vlan { add | del } vid VLAN_ID dev DEV [ pvid] [ untagged ]\n"); fprintf(stderr, " [ self ] [ master ]\n"); - fprintf(stderr, " bridge vlan { show } [ dev DEV ]\n"); + fprintf(stderr, " bridge vlan { show } [ dev DEV ] [ vid VLAN_ID ]\n"); exit(-1); } @@ -138,6 +138,26 @@ static int vlan_modify(int cmd, int argc, char **argv) return 0; } +/* In order to use this function for both filtering and non-filtering cases + * we need to make it a tristate: + * return -1 - if filtering we've gone over so don't continue + * return 0 - skip entry and continue (applies to range start or to entries + * which are less than filter_vlan) + * return 1 - print the entry and continue + */ +static int filter_vlan_check(struct bridge_vlan_info *vinfo) +{ + /* if we're filtering we should stop on the first greater entry */ + if (filter_vlan && vinfo->vid > filter_vlan && + !(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END)) + return -1; + if ((vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) || + vinfo->vid < filter_vlan) + return 0; + + return 1; +} + static int print_vlan(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) @@ -169,26 +189,40 @@ static int print_vlan(const struct sockaddr_nl *who, /* if AF_SPEC isn't there, vlan table is not preset for this port */ if (!tb[IFLA_AF_SPEC]) { - fprintf(fp, "%s\tNone\n", ll_index_to_name(ifm->ifi_index)); + if (!filter_vlan) + fprintf(fp, "%s\tNone\n", + ll_index_to_name(ifm->ifi_index)); return 0; } else { struct rtattr *i, *list = tb[IFLA_AF_SPEC]; int rem = RTA_PAYLOAD(list); + __u16 last_vid_start = 0; - fprintf(fp, "%s", ll_index_to_name(ifm->ifi_index)); + if (!filter_vlan) + fprintf(fp, "%s", ll_index_to_name(ifm->ifi_index)); for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { struct bridge_vlan_info *vinfo; + int vcheck_ret; if (i->rta_type != IFLA_BRIDGE_VLAN_INFO) continue; vinfo = RTA_DATA(i); - 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) + + if (!(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END)) + last_vid_start = vinfo->vid; + vcheck_ret = filter_vlan_check(vinfo); + if (vcheck_ret == -1) + break; + else if (vcheck_ret == 0) continue; + + if (filter_vlan) + fprintf(fp, "%s", + ll_index_to_name(ifm->ifi_index)); + fprintf(fp, "\t %hu", last_vid_start); + if (last_vid_start != vinfo->vid) + fprintf(fp, "-%hu", vinfo->vid); if (vinfo->flags & BRIDGE_VLAN_INFO_PVID) fprintf(fp, " PVID"); if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED) @@ -196,7 +230,8 @@ static int print_vlan(const struct sockaddr_nl *who, fprintf(fp, "\n"); } } - fprintf(fp, "\n"); + if (!filter_vlan) + fprintf(fp, "\n"); fflush(fp); return 0; } @@ -211,6 +246,11 @@ static int vlan_show(int argc, char **argv) if (filter_dev) duparg("dev", *argv); filter_dev = *argv; + } else if (strcmp(*argv, "vid") == 0) { + NEXT_ARG(); + if (filter_vlan) + duparg("vid", *argv); + filter_vlan = atoi(*argv); } argc--; argv++; } diff --git a/examples/bpf/bpf_cyclic.c b/examples/bpf/bpf_cyclic.c index 36745a3c..11d1c061 100644 --- a/examples/bpf/bpf_cyclic.c +++ b/examples/bpf/bpf_cyclic.c @@ -6,7 +6,14 @@ */ #define JMP_MAP_ID 0xabccba -BPF_PROG_ARRAY(jmp_tc, JMP_MAP_ID, PIN_OBJECT_NS, 1); +struct bpf_elf_map __section_maps jmp_tc = { + .type = BPF_MAP_TYPE_PROG_ARRAY, + .id = JMP_MAP_ID, + .size_key = sizeof(uint32_t), + .size_value = sizeof(uint32_t), + .pinning = PIN_OBJECT_NS, + .max_elem = 1, +}; __section_tail(JMP_MAP_ID, 0) int cls_loop(struct __sk_buff *skb) diff --git a/examples/bpf/bpf_graft.c b/examples/bpf/bpf_graft.c index 20784ff4..07113d4a 100644 --- a/examples/bpf/bpf_graft.c +++ b/examples/bpf/bpf_graft.c @@ -33,7 +33,13 @@ * [...] */ -BPF_PROG_ARRAY(jmp_tc, 0, PIN_GLOBAL_NS, 1); +struct bpf_elf_map __section_maps jmp_tc = { + .type = BPF_MAP_TYPE_PROG_ARRAY, + .size_key = sizeof(uint32_t), + .size_value = sizeof(uint32_t), + .pinning = PIN_GLOBAL_NS, + .max_elem = 1, +}; __section("aaa") int cls_aaa(struct __sk_buff *skb) diff --git a/examples/bpf/bpf_prog.c b/examples/bpf/bpf_prog.c index f15e876c..d6caf374 100644 --- a/examples/bpf/bpf_prog.c +++ b/examples/bpf/bpf_prog.c @@ -192,6 +192,7 @@ struct bpf_elf_map __section("maps") map_proto = { .size_key = sizeof(uint8_t), .size_value = sizeof(struct count_tuple), .max_elem = 256, + .flags = BPF_F_NO_PREALLOC, }; struct bpf_elf_map __section("maps") map_queue = { @@ -200,6 +201,7 @@ struct bpf_elf_map __section("maps") map_queue = { .size_key = sizeof(uint32_t), .size_value = sizeof(struct count_queue), .max_elem = 1024, + .flags = BPF_F_NO_PREALLOC, }; struct bpf_elf_map __section("maps") map_drops = { diff --git a/examples/bpf/bpf_shared.c b/examples/bpf/bpf_shared.c index 7fe9ef30..21fe6f1e 100644 --- a/examples/bpf/bpf_shared.c +++ b/examples/bpf/bpf_shared.c @@ -18,7 +18,13 @@ * instance is being created. */ -BPF_ARRAY4(map_sh, 0, PIN_OBJECT_NS, 1); /* or PIN_GLOBAL_NS, or PIN_NONE */ +struct bpf_elf_map __section_maps map_sh = { + .type = BPF_MAP_TYPE_ARRAY, + .size_key = sizeof(uint32_t), + .size_value = sizeof(uint32_t), + .pinning = PIN_OBJECT_NS, /* or PIN_GLOBAL_NS, or PIN_NONE */ + .max_elem = 1, +}; __section("egress") int emain(struct __sk_buff *skb) diff --git a/examples/bpf/bpf_tailcall.c b/examples/bpf/bpf_tailcall.c index f545430f..1a30426c 100644 --- a/examples/bpf/bpf_tailcall.c +++ b/examples/bpf/bpf_tailcall.c @@ -26,10 +26,31 @@ * classifier behaviour. */ -BPF_PROG_ARRAY(jmp_tc, FOO, PIN_OBJECT_NS, MAX_JMP_SIZE); -BPF_PROG_ARRAY(jmp_ex, BAR, PIN_OBJECT_NS, 1); +struct bpf_elf_map __section_maps jmp_tc = { + .type = BPF_MAP_TYPE_PROG_ARRAY, + .id = FOO, + .size_key = sizeof(uint32_t), + .size_value = sizeof(uint32_t), + .pinning = PIN_OBJECT_NS, + .max_elem = MAX_JMP_SIZE, +}; -BPF_ARRAY4(map_sh, 0, PIN_OBJECT_NS, 1); +struct bpf_elf_map __section_maps jmp_ex = { + .type = BPF_MAP_TYPE_PROG_ARRAY, + .id = BAR, + .size_key = sizeof(uint32_t), + .size_value = sizeof(uint32_t), + .pinning = PIN_OBJECT_NS, + .max_elem = 1, +}; + +struct bpf_elf_map __section_maps map_sh = { + .type = BPF_MAP_TYPE_ARRAY, + .size_key = sizeof(uint32_t), + .size_value = sizeof(uint32_t), + .pinning = PIN_OBJECT_NS, + .max_elem = 1, +}; __section_tail(FOO, ENTRY_0) int cls_case1(struct __sk_buff *skb) diff --git a/include/bpf_api.h b/include/bpf_api.h index 4b16d25c..1b250d2e 100644 --- a/include/bpf_api.h +++ b/include/bpf_api.h @@ -99,51 +99,6 @@ char ____license[] __section_license = NAME #endif -#ifndef __BPF_MAP -# define __BPF_MAP(NAME, TYPE, ID, SIZE_KEY, SIZE_VALUE, PIN, MAX_ELEM) \ - struct bpf_elf_map __section_maps NAME = { \ - .type = (TYPE), \ - .id = (ID), \ - .size_key = (SIZE_KEY), \ - .size_value = (SIZE_VALUE), \ - .pinning = (PIN), \ - .max_elem = (MAX_ELEM), \ - } -#endif - -#ifndef BPF_HASH -# define BPF_HASH(NAME, ID, SIZE_KEY, SIZE_VALUE, PIN, MAX_ELEM) \ - __BPF_MAP(NAME, BPF_MAP_TYPE_HASH, ID, SIZE_KEY, SIZE_VALUE, \ - PIN, MAX_ELEM) -#endif - -#ifndef BPF_ARRAY -# define BPF_ARRAY(NAME, ID, SIZE_VALUE, PIN, MAX_ELEM) \ - __BPF_MAP(NAME, BPF_MAP_TYPE_ARRAY, ID, sizeof(uint32_t), \ - SIZE_VALUE, PIN, MAX_ELEM) -#endif - -#ifndef BPF_ARRAY2 -# define BPF_ARRAY2(NAME, ID, PIN, MAX_ELEM) \ - BPF_ARRAY(NAME, ID, sizeof(uint16_t), PIN, MAX_ELEM) -#endif - -#ifndef BPF_ARRAY4 -# define BPF_ARRAY4(NAME, ID, PIN, MAX_ELEM) \ - BPF_ARRAY(NAME, ID, sizeof(uint32_t), PIN, MAX_ELEM) -#endif - -#ifndef BPF_ARRAY8 -# define BPF_ARRAY8(NAME, ID, PIN, MAX_ELEM) \ - BPF_ARRAY(NAME, ID, sizeof(uint64_t), PIN, MAX_ELEM) -#endif - -#ifndef BPF_PROG_ARRAY -# define BPF_PROG_ARRAY(NAME, ID, PIN, MAX_ELEM) \ - __BPF_MAP(NAME, BPF_MAP_TYPE_PROG_ARRAY, ID, sizeof(uint32_t), \ - sizeof(uint32_t), PIN, MAX_ELEM) -#endif - /** Classifier helper */ #ifndef BPF_H_DEFAULT @@ -212,6 +167,8 @@ static int BPF_FUNC(l3_csum_replace, struct __sk_buff *skb, uint32_t off, uint32_t from, uint32_t to, uint32_t flags); static int BPF_FUNC(l4_csum_replace, struct __sk_buff *skb, uint32_t off, uint32_t from, uint32_t to, uint32_t flags); +static int BPF_FUNC(csum_diff, const void *from, uint32_t from_size, + const void *to, uint32_t to_size, uint32_t seed); /* Packet vlan encap/decap */ static int BPF_FUNC(skb_vlan_push, struct __sk_buff *skb, uint16_t proto, @@ -225,6 +182,11 @@ static int BPF_FUNC(skb_set_tunnel_key, struct __sk_buff *skb, const struct bpf_tunnel_key *from, uint32_t size, uint32_t flags); +static int BPF_FUNC(skb_get_tunnel_opt, struct __sk_buff *skb, + void *to, uint32_t size); +static int BPF_FUNC(skb_set_tunnel_opt, struct __sk_buff *skb, + const void *from, uint32_t size); + /** LLVM built-ins, mem*() routines work for constant size */ #ifndef lock_xadd diff --git a/include/bpf_elf.h b/include/bpf_elf.h index 31a89743..36cc9882 100644 --- a/include/bpf_elf.h +++ b/include/bpf_elf.h @@ -32,6 +32,7 @@ struct bpf_elf_map { __u32 size_key; __u32 size_value; __u32 max_elem; + __u32 flags; __u32 id; __u32 pinning; }; diff --git a/ip/ipaddress.c b/ip/ipaddress.c index 3998d8ce..aac7970e 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -326,7 +326,7 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo) * this kernel. */ tmp = (struct rtattr *)((char *)vf[IFLA_VF_TX_RATE] + - vf[IFLA_VF_TX_RATE]->rta_len); + vf[IFLA_VF_TX_RATE]->rta_len); if (tmp->rta_type != IFLA_VF_SPOOFCHK) vf_spoofchk = NULL; @@ -338,7 +338,7 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo) * this kernel. */ tmp = (struct rtattr *)((char *)vf[IFLA_VF_SPOOFCHK] + - vf[IFLA_VF_SPOOFCHK]->rta_len); + vf[IFLA_VF_SPOOFCHK]->rta_len); if (tmp->rta_type != IFLA_VF_LINK_STATE) vf_linkstate = NULL; @@ -349,7 +349,7 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo) fprintf(fp, "%s vf %d MAC %s", _SL_, vf_mac->vf, ll_addr_n2a((unsigned char *)&vf_mac->mac, - ETH_ALEN, 0, b1, sizeof(b1))); + ETH_ALEN, 0, b1, sizeof(b1))); if (vf_vlan->vlan) fprintf(fp, ", vlan %d", vf_vlan->vlan); if (vf_vlan->qos) @@ -380,6 +380,13 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo) else fprintf(fp, ", link-state disable"); } + if (vf[IFLA_VF_TRUST]) { + struct ifla_vf_trust *vf_trust = RTA_DATA(vf[IFLA_VF_TRUST]); + + if (vf_trust->setting != -1) + fprintf(fp, ", trust %s", + vf_trust->setting ? "on" : "off"); + } if (vf[IFLA_VF_STATS] && show_stats) print_vf_stats64(fp, vf[IFLA_VF_STATS]); } @@ -782,7 +789,7 @@ int print_linkinfo(const struct sockaddr_nl *who, fprintf(fp, "%d: ", ifi->ifi_index); color_fprintf(fp, COLOR_IFNAME, "%s", - tb[IFLA_IFNAME] ? rta_getattr_str(tb[IFLA_IFNAME]) : ""); + tb[IFLA_IFNAME] ? rta_getattr_str(tb[IFLA_IFNAME]) : ""); if (tb[IFLA_LINK]) { SPRINT_BUF(b1); @@ -813,22 +820,6 @@ int print_linkinfo(const struct sockaddr_nl *who, fprintf(fp, "master %s ", ll_idx_n2a(*(int *)RTA_DATA(tb[IFLA_MASTER]), b1)); } - if (tb[IFLA_PHYS_PORT_ID]) { - SPRINT_BUF(b1); - fprintf(fp, "portid %s ", - hexstring_n2a(RTA_DATA(tb[IFLA_PHYS_PORT_ID]), - RTA_PAYLOAD(tb[IFLA_PHYS_PORT_ID]), - b1, sizeof(b1))); - } - - if (tb[IFLA_PHYS_SWITCH_ID]) { - SPRINT_BUF(b1); - fprintf(fp, "switchid %s ", - hexstring_n2a(RTA_DATA(tb[IFLA_PHYS_SWITCH_ID]), - RTA_PAYLOAD(tb[IFLA_PHYS_SWITCH_ID]), - b1, sizeof(b1))); - } - if (tb[IFLA_OPERSTATE]) print_operstate(fp, rta_getattr_u8(tb[IFLA_OPERSTATE])); @@ -852,10 +843,10 @@ int print_linkinfo(const struct sockaddr_nl *who, if (tb[IFLA_ADDRESS]) { color_fprintf(fp, COLOR_MAC, "%s", - ll_addr_n2a(RTA_DATA(tb[IFLA_ADDRESS]), - RTA_PAYLOAD(tb[IFLA_ADDRESS]), - ifi->ifi_type, - b1, sizeof(b1))); + ll_addr_n2a(RTA_DATA(tb[IFLA_ADDRESS]), + RTA_PAYLOAD(tb[IFLA_ADDRESS]), + ifi->ifi_type, + b1, sizeof(b1))); } if (tb[IFLA_BROADCAST]) { if (ifi->ifi_flags&IFF_POINTOPOINT) @@ -863,10 +854,10 @@ int print_linkinfo(const struct sockaddr_nl *who, else fprintf(fp, " brd "); color_fprintf(fp, COLOR_MAC, "%s", - ll_addr_n2a(RTA_DATA(tb[IFLA_BROADCAST]), - RTA_PAYLOAD(tb[IFLA_BROADCAST]), - ifi->ifi_type, - b1, sizeof(b1))); + ll_addr_n2a(RTA_DATA(tb[IFLA_BROADCAST]), + RTA_PAYLOAD(tb[IFLA_BROADCAST]), + ifi->ifi_type, + b1, sizeof(b1))); } } @@ -884,15 +875,46 @@ int print_linkinfo(const struct sockaddr_nl *who, fprintf(fp, " protodown on "); } - if (tb[IFLA_PROMISCUITY] && show_details) - fprintf(fp, " promiscuity %u ", - *(int *)RTA_DATA(tb[IFLA_PROMISCUITY])); + if (show_details) { + if (tb[IFLA_PROMISCUITY]) + fprintf(fp, " promiscuity %u ", + *(int *)RTA_DATA(tb[IFLA_PROMISCUITY])); - if (tb[IFLA_LINKINFO] && show_details) - print_linktype(fp, tb[IFLA_LINKINFO]); + if (tb[IFLA_LINKINFO]) + print_linktype(fp, tb[IFLA_LINKINFO]); + + if (do_link && tb[IFLA_AF_SPEC]) + print_af_spec(fp, tb[IFLA_AF_SPEC]); + + if (tb[IFLA_NUM_TX_QUEUES]) + fprintf(fp, "numtxqueues %u ", + rta_getattr_u32(tb[IFLA_NUM_TX_QUEUES])); + + if (tb[IFLA_NUM_RX_QUEUES]) + fprintf(fp, "numrxqueues %u ", + rta_getattr_u32(tb[IFLA_NUM_RX_QUEUES])); + + if (tb[IFLA_PHYS_PORT_NAME]) + fprintf(fp, "portname %s ", + rta_getattr_str(tb[IFLA_PHYS_PORT_NAME])); + + if (tb[IFLA_PHYS_PORT_ID]) { + SPRINT_BUF(b1); + fprintf(fp, "portid %s ", + hexstring_n2a(RTA_DATA(tb[IFLA_PHYS_PORT_ID]), + RTA_PAYLOAD(tb[IFLA_PHYS_PORT_ID]), + b1, sizeof(b1))); + } + + if (tb[IFLA_PHYS_SWITCH_ID]) { + SPRINT_BUF(b1); + fprintf(fp, "switchid %s ", + hexstring_n2a(RTA_DATA(tb[IFLA_PHYS_SWITCH_ID]), + RTA_PAYLOAD(tb[IFLA_PHYS_SWITCH_ID]), + b1, sizeof(b1))); + } + } - if (do_link && tb[IFLA_AF_SPEC] && show_details) - print_af_spec(fp, tb[IFLA_AF_SPEC]); if ((do_link || show_details) && tb[IFLA_IFALIAS]) { fprintf(fp, "%s alias %s", _SL_, diff --git a/tc/tc_bpf.c b/tc/tc_bpf.c index d94af828..86c6069b 100644 --- a/tc/tc_bpf.c +++ b/tc/tc_bpf.c @@ -20,6 +20,7 @@ #include #include #include +#include #ifdef HAVE_ELF #include @@ -184,7 +185,7 @@ static int bpf_ops_parse(int argc, char **argv, struct sock_filter *bpf_ops, } if (i != bpf_len) { - fprintf(stderr, "Parsed program length is less than encodedlength parameter!\n"); + fprintf(stderr, "Parsed program length is less than encoded length parameter!\n"); ret = -EINVAL; goto out; } @@ -214,6 +215,30 @@ void bpf_print_ops(FILE *f, struct rtattr *bpf_ops, __u16 len) ops[i].jf, ops[i].k); } +static void bpf_map_pin_report(const struct bpf_elf_map *pin, + const struct bpf_elf_map *obj) +{ + fprintf(stderr, "Map specification differs from pinned file!\n"); + + if (obj->type != pin->type) + fprintf(stderr, " - Type: %u (obj) != %u (pin)\n", + obj->type, pin->type); + if (obj->size_key != pin->size_key) + fprintf(stderr, " - Size key: %u (obj) != %u (pin)\n", + obj->size_key, pin->size_key); + if (obj->size_value != pin->size_value) + fprintf(stderr, " - Size value: %u (obj) != %u (pin)\n", + obj->size_value, pin->size_value); + if (obj->max_elem != pin->max_elem) + fprintf(stderr, " - Max elems: %u (obj) != %u (pin)\n", + obj->max_elem, pin->max_elem); + if (obj->flags != pin->flags) + fprintf(stderr, " - Flags: %#x (obj) != %#x (pin)\n", + obj->flags, pin->flags); + + fprintf(stderr, "\n"); +} + static int bpf_map_selfcheck_pinned(int fd, const struct bpf_elf_map *map, int length) { @@ -240,6 +265,8 @@ static int bpf_map_selfcheck_pinned(int fd, const struct bpf_elf_map *map, tmp.size_value = val; else if (sscanf(buff, "max_entries:\t%u", &val) == 1) tmp.max_elem = val; + else if (sscanf(buff, "map_flags:\t%i", &val) == 1) + tmp.flags = val; } fclose(fp); @@ -256,7 +283,7 @@ static int bpf_map_selfcheck_pinned(int fd, const struct bpf_elf_map *map, if (!memcmp(&tmp, &zero, length)) return 0; - fprintf(stderr, "Map specs from pinned file differ!\n"); + bpf_map_pin_report(&tmp, map); return -EINVAL; } } @@ -735,7 +762,19 @@ bpf_dump_error(struct bpf_elf_ctx *ctx, const char *format, ...) va_end(vl); if (ctx->log && ctx->log[0]) { - fprintf(stderr, "%s\n", ctx->log); + if (ctx->verbose) { + fprintf(stderr, "%s\n", ctx->log); + } else { + unsigned int off = 0, len = strlen(ctx->log); + + if (len > BPF_MAX_LOG) { + off = len - BPF_MAX_LOG; + fprintf(stderr, "Skipped %u bytes, use \'verb\' option for the full verbose log.\n[...]\n", + off); + } + fprintf(stderr, "%s\n", ctx->log + off); + } + memset(ctx->log, 0, ctx->log_size); } } @@ -763,8 +802,9 @@ static int bpf_log_realloc(struct bpf_elf_ctx *ctx) return 0; } -static int bpf_map_create(enum bpf_map_type type, unsigned int size_key, - unsigned int size_value, unsigned int max_elem) +static int bpf_map_create(enum bpf_map_type type, uint32_t size_key, + uint32_t size_value, uint32_t max_elem, + uint32_t flags) { union bpf_attr attr; @@ -773,6 +813,7 @@ static int bpf_map_create(enum bpf_map_type type, unsigned int size_key, attr.key_size = size_key; attr.value_size = size_value; attr.max_entries = max_elem; + attr.map_flags = flags; return bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); } @@ -1055,14 +1096,16 @@ static void bpf_prog_report(int fd, const char *section, const struct bpf_elf_prog *prog, struct bpf_elf_ctx *ctx) { - fprintf(stderr, "Prog section \'%s\' %s%s (%d)!\n", section, + unsigned int insns = prog->size / sizeof(struct bpf_insn); + + fprintf(stderr, "\nProg section \'%s\' %s%s (%d)!\n", section, fd < 0 ? "rejected: " : "loaded", fd < 0 ? strerror(errno) : "", fd < 0 ? errno : fd); fprintf(stderr, " - Type: %u\n", prog->type); - fprintf(stderr, " - Instructions: %zu\n", - prog->size / sizeof(struct bpf_insn)); + fprintf(stderr, " - Instructions: %u (%u over limit)\n", + insns, insns > BPF_MAXINSNS ? insns - BPF_MAXINSNS : 0); fprintf(stderr, " - License: %s\n\n", prog->license); bpf_dump_error(ctx, "Verifier analysis:\n\n"); @@ -1112,7 +1155,8 @@ static void bpf_map_report(int fd, const char *name, fprintf(stderr, " - Pinning: %u\n", map->pinning); fprintf(stderr, " - Size key: %u\n", map->size_key); fprintf(stderr, " - Size value: %u\n", map->size_value); - fprintf(stderr, " - Max elems: %u\n\n", map->max_elem); + fprintf(stderr, " - Max elems: %u\n", map->max_elem); + fprintf(stderr, " - Flags: %#x\n\n", map->flags); } static int bpf_map_attach(const char *name, const struct bpf_elf_map *map, @@ -1139,7 +1183,7 @@ static int bpf_map_attach(const char *name, const struct bpf_elf_map *map, errno = 0; fd = bpf_map_create(map->type, map->size_key, map->size_value, - map->max_elem); + map->max_elem, map->flags); if (fd < 0 || ctx->verbose) { bpf_map_report(fd, name, map, ctx); if (fd < 0) @@ -1283,6 +1327,11 @@ static int bpf_fetch_strtab(struct bpf_elf_ctx *ctx, int section, return 0; } +static bool bpf_has_map_data(const struct bpf_elf_ctx *ctx) +{ + return ctx->sym_tab && ctx->str_tab && ctx->sec_maps; +} + static int bpf_fetch_ancillary(struct bpf_elf_ctx *ctx) { struct bpf_elf_sec_data data; @@ -1306,13 +1355,13 @@ static int bpf_fetch_ancillary(struct bpf_elf_ctx *ctx) !strcmp(data.sec_name, ".strtab")) ret = bpf_fetch_strtab(ctx, i, &data); if (ret < 0) { - fprintf(stderr, "Error parsing section %d! Perhapscheck with readelf -a?\n", + fprintf(stderr, "Error parsing section %d! Perhaps check with readelf -a?\n", i); break; } } - if (ctx->sym_tab && ctx->str_tab && ctx->sec_maps) { + if (bpf_has_map_data(ctx)) { ret = bpf_maps_attach_all(ctx); if (ret < 0) { fprintf(stderr, "Error loading maps into kernel!\n"); @@ -1348,7 +1397,7 @@ static int bpf_fetch_prog(struct bpf_elf_ctx *ctx, const char *section) fd = bpf_prog_attach(section, &prog, ctx); if (fd < 0) - continue; + break; ctx->sec_done[i] = true; break; @@ -1412,7 +1461,8 @@ static int bpf_apply_relo_data(struct bpf_elf_ctx *ctx, return 0; } -static int bpf_fetch_prog_relo(struct bpf_elf_ctx *ctx, const char *section) +static int bpf_fetch_prog_relo(struct bpf_elf_ctx *ctx, const char *section, + bool *lderr) { struct bpf_elf_sec_data data_relo, data_insn; struct bpf_elf_prog prog; @@ -1442,8 +1492,10 @@ static int bpf_fetch_prog_relo(struct bpf_elf_ctx *ctx, const char *section) prog.license = ctx->license; fd = bpf_prog_attach(section, &prog, ctx); - if (fd < 0) - continue; + if (fd < 0) { + *lderr = true; + break; + } ctx->sec_done[i] = true; ctx->sec_done[idx] = true; @@ -1455,11 +1507,12 @@ static int bpf_fetch_prog_relo(struct bpf_elf_ctx *ctx, const char *section) static int bpf_fetch_prog_sec(struct bpf_elf_ctx *ctx, const char *section) { + bool lderr = false; int ret = -1; - if (ctx->sym_tab) - ret = bpf_fetch_prog_relo(ctx, section); - if (ret < 0) + if (bpf_has_map_data(ctx)) + ret = bpf_fetch_prog_relo(ctx, section, &lderr); + if (ret < 0 && !lderr) ret = bpf_fetch_prog(ctx, section); return ret; @@ -1504,8 +1557,12 @@ static int bpf_fill_prog_arrays(struct bpf_elf_ctx *ctx) ret = bpf_map_update(ctx->map_fds[idx], &key_id, &fd, BPF_ANY); - if (ret < 0) - return -ENOENT; + if (ret < 0) { + if (errno == E2BIG) + fprintf(stderr, "Tail call key %u for map %u out of bounds?\n", + key_id, map_id); + return -errno; + } ctx->sec_done[i] = true; } diff --git a/tc/tc_bpf.h b/tc/tc_bpf.h index 93f7f0e2..30306dea 100644 --- a/tc/tc_bpf.h +++ b/tc/tc_bpf.h @@ -33,6 +33,10 @@ enum { #define BPF_ENV_UDS "TC_BPF_UDS" #define BPF_ENV_MNT "TC_BPF_MNT" +#ifndef BPF_MAX_LOG +# define BPF_MAX_LOG 4096 +#endif + #ifndef BPF_FS_MAGIC # define BPF_FS_MAGIC 0xcafe4a11 #endif