diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index b9a63672..4bbe7e5d 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -75,6 +75,11 @@ struct bpf_lpm_trie_key { __u8 data[0]; /* Arbitrary size */ }; +struct bpf_cgroup_storage_key { + __u64 cgroup_inode_id; /* cgroup inode id */ + __u32 attach_type; /* program attach type */ +}; + /* BPF syscall commands, see bpf(2) man-page for details. */ enum bpf_cmd { BPF_MAP_CREATE, @@ -120,6 +125,7 @@ enum bpf_map_type { BPF_MAP_TYPE_CPUMAP, BPF_MAP_TYPE_XSKMAP, BPF_MAP_TYPE_SOCKHASH, + BPF_MAP_TYPE_CGROUP_STORAGE, }; enum bpf_prog_type { @@ -1371,6 +1377,20 @@ union bpf_attr { * A 8-byte long non-decreasing number on success, or 0 if the * socket field is missing inside *skb*. * + * u64 bpf_get_socket_cookie(struct bpf_sock_addr *ctx) + * Description + * Equivalent to bpf_get_socket_cookie() helper that accepts + * *skb*, but gets socket from **struct bpf_sock_addr** contex. + * Return + * A 8-byte long non-decreasing number. + * + * u64 bpf_get_socket_cookie(struct bpf_sock_ops *ctx) + * Description + * Equivalent to bpf_get_socket_cookie() helper that accepts + * *skb*, but gets socket from **struct bpf_sock_ops** contex. + * Return + * A 8-byte long non-decreasing number. + * * u32 bpf_get_socket_uid(struct sk_buff *skb) * Return * The owner UID of the socket associated to *skb*. If the socket @@ -2075,6 +2095,24 @@ union bpf_attr { * Return * A 64-bit integer containing the current cgroup id based * on the cgroup within which the current task is running. + * + * void* get_local_storage(void *map, u64 flags) + * Description + * Get the pointer to the local storage area. + * The type and the size of the local storage is defined + * by the *map* argument. + * The *flags* meaning is specific for each map type, + * and has to be 0 for cgroup local storage. + * + * Depending on the bpf program type, a local storage area + * can be shared between multiple instances of the bpf program, + * running simultaneously. + * + * A user should care about the synchronization by himself. + * For example, by using the BPF_STX_XADD instruction to alter + * the shared data. + * Return + * Pointer to the local storage area. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -2157,7 +2195,8 @@ union bpf_attr { FN(rc_repeat), \ FN(rc_keydown), \ FN(skb_cgroup_id), \ - FN(get_current_cgroup_id), + FN(get_current_cgroup_id), \ + FN(get_local_storage), /* integer value in 'imm' field of BPF_CALL instruction selects which helper * function eBPF program intends to call diff --git a/include/uapi/linux/btf.h b/include/uapi/linux/btf.h index 5dd580a6..8d2a8ffa 100644 --- a/include/uapi/linux/btf.h +++ b/include/uapi/linux/btf.h @@ -76,7 +76,7 @@ struct btf_type { */ #define BTF_INT_ENCODING(VAL) (((VAL) & 0x0f000000) >> 24) #define BTF_INT_OFFSET(VAL) (((VAL & 0x00ff0000)) >> 16) -#define BTF_INT_BITS(VAL) ((VAL) & 0x0000ffff) +#define BTF_INT_BITS(VAL) ((VAL) & 0x000000ff) /* Attributes stored in the BTF_INT_ENCODING */ #define BTF_INT_SIGNED (1 << 0) diff --git a/include/uapi/linux/can.h b/include/uapi/linux/can.h index 4d1ab8e7..9009f0b6 100644 --- a/include/uapi/linux/can.h +++ b/include/uapi/linux/can.h @@ -77,7 +77,7 @@ typedef __u32 canid_t; /* * Controller Area Network Error Message Frame Mask structure * - * bit 0-28 : error class mask (see include/linux/can/error.h) + * bit 0-28 : error class mask (see include/uapi/linux/can/error.h) * bit 29-31 : set to zero */ typedef __u32 can_err_mask_t; diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 8456ff25..f4a97151 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -460,6 +460,16 @@ enum { #define IFLA_MACSEC_MAX (__IFLA_MACSEC_MAX - 1) +/* XFRM section */ +enum { + IFLA_XFRM_UNSPEC, + IFLA_XFRM_LINK, + IFLA_XFRM_IF_ID, + __IFLA_XFRM_MAX +}; + +#define IFLA_XFRM_MAX (__IFLA_XFRM_MAX - 1) + enum macsec_validation_type { MACSEC_VALIDATE_DISABLED = 0, MACSEC_VALIDATE_CHECK = 1, diff --git a/include/uapi/linux/ip.h b/include/uapi/linux/ip.h index 883fd334..f4ecd2fa 100644 --- a/include/uapi/linux/ip.h +++ b/include/uapi/linux/ip.h @@ -168,6 +168,7 @@ enum IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN, IPV4_DEVCONF_DROP_UNICAST_IN_L2_MULTICAST, IPV4_DEVCONF_DROP_GRATUITOUS_ARP, + IPV4_DEVCONF_BC_FORWARDING, __IPV4_DEVCONF_MAX }; diff --git a/include/uapi/linux/l2tp.h b/include/uapi/linux/l2tp.h index 1fe52a7d..131c3a26 100644 --- a/include/uapi/linux/l2tp.h +++ b/include/uapi/linux/l2tp.h @@ -60,14 +60,14 @@ struct sockaddr_l2tpip6 { /* * Commands. * Valid TLVs of each command are:- - * TUNNEL_CREATE - CONN_ID, pw_type, netns, ifname, ipinfo, udpinfo, udpcsum, vlanid + * TUNNEL_CREATE - CONN_ID, pw_type, netns, ifname, ipinfo, udpinfo, udpcsum * TUNNEL_DELETE - CONN_ID * TUNNEL_MODIFY - CONN_ID, udpcsum * TUNNEL_GETSTATS - CONN_ID, (stats) * TUNNEL_GET - CONN_ID, (...) - * SESSION_CREATE - SESSION_ID, PW_TYPE, data_seq, cookie, peer_cookie, l2spec + * SESSION_CREATE - SESSION_ID, PW_TYPE, cookie, peer_cookie, l2spec * SESSION_DELETE - SESSION_ID - * SESSION_MODIFY - SESSION_ID, data_seq + * SESSION_MODIFY - SESSION_ID * SESSION_GET - SESSION_ID, (...) * SESSION_GETSTATS - SESSION_ID, (stats) * @@ -95,7 +95,7 @@ enum { L2TP_ATTR_PW_TYPE, /* u16, enum l2tp_pwtype */ L2TP_ATTR_ENCAP_TYPE, /* u16, enum l2tp_encap_type */ L2TP_ATTR_OFFSET, /* u16 (not used) */ - L2TP_ATTR_DATA_SEQ, /* u16 */ + L2TP_ATTR_DATA_SEQ, /* u16 (not used) */ L2TP_ATTR_L2SPEC_TYPE, /* u8, enum l2tp_l2spec_type */ L2TP_ATTR_L2SPEC_LEN, /* u8 (not used) */ L2TP_ATTR_PROTO_VERSION, /* u8 */ @@ -105,7 +105,7 @@ enum { L2TP_ATTR_SESSION_ID, /* u32 */ L2TP_ATTR_PEER_SESSION_ID, /* u32 */ L2TP_ATTR_UDP_CSUM, /* u8 */ - L2TP_ATTR_VLAN_ID, /* u16 */ + L2TP_ATTR_VLAN_ID, /* u16 (not used) */ L2TP_ATTR_COOKIE, /* 0, 4 or 8 bytes */ L2TP_ATTR_PEER_COOKIE, /* 0, 4 or 8 bytes */ L2TP_ATTR_DEBUG, /* u32, enum l2tp_debug_flags */ @@ -119,8 +119,8 @@ enum { L2TP_ATTR_IP_DADDR, /* u32 */ L2TP_ATTR_UDP_SPORT, /* u16 */ L2TP_ATTR_UDP_DPORT, /* u16 */ - L2TP_ATTR_MTU, /* u16 */ - L2TP_ATTR_MRU, /* u16 */ + L2TP_ATTR_MTU, /* u16 (not used) */ + L2TP_ATTR_MRU, /* u16 (not used) */ L2TP_ATTR_STATS, /* nested */ L2TP_ATTR_IP6_SADDR, /* struct in6_addr */ L2TP_ATTR_IP6_DADDR, /* struct in6_addr */ @@ -169,6 +169,7 @@ enum l2tp_encap_type { L2TP_ENCAPTYPE_IP, }; +/* For L2TP_ATTR_DATA_SEQ. Unused. */ enum l2tp_seqmode { L2TP_SEQ_NONE = 0, L2TP_SEQ_IP = 1, diff --git a/include/uapi/linux/netconf.h b/include/uapi/linux/netconf.h index 86ac1eb4..229e8851 100644 --- a/include/uapi/linux/netconf.h +++ b/include/uapi/linux/netconf.h @@ -18,6 +18,7 @@ enum { NETCONFA_PROXY_NEIGH, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, NETCONFA_INPUT, + NETCONFA_BC_FORWARDING, __NETCONFA_MAX }; #define NETCONFA_MAX (__NETCONFA_MAX - 1) diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h index b4512254..be382fb0 100644 --- a/include/uapi/linux/pkt_cls.h +++ b/include/uapi/linux/pkt_cls.h @@ -45,6 +45,7 @@ enum { * the skb and act like everything * is alright. */ +#define TC_ACT_VALUE_MAX TC_ACT_TRAP /* There is a special kind of actions called "extended actions", * which need a value parameter. These have a local opcode located in @@ -55,11 +56,12 @@ enum { #define __TC_ACT_EXT_SHIFT 28 #define __TC_ACT_EXT(local) ((local) << __TC_ACT_EXT_SHIFT) #define TC_ACT_EXT_VAL_MASK ((1 << __TC_ACT_EXT_SHIFT) - 1) -#define TC_ACT_EXT_CMP(combined, opcode) \ - (((combined) & (~TC_ACT_EXT_VAL_MASK)) == opcode) +#define TC_ACT_EXT_OPCODE(combined) ((combined) & (~TC_ACT_EXT_VAL_MASK)) +#define TC_ACT_EXT_CMP(combined, opcode) (TC_ACT_EXT_OPCODE(combined) == opcode) #define TC_ACT_JUMP __TC_ACT_EXT(1) #define TC_ACT_GOTO_CHAIN __TC_ACT_EXT(2) +#define TC_ACT_EXT_OPCODE_MAX TC_ACT_GOTO_CHAIN /* Action type identifiers*/ enum { @@ -478,11 +480,37 @@ enum { TCA_FLOWER_KEY_ENC_IP_TTL, /* u8 */ TCA_FLOWER_KEY_ENC_IP_TTL_MASK, /* u8 */ + TCA_FLOWER_KEY_ENC_OPTS, + TCA_FLOWER_KEY_ENC_OPTS_MASK, + __TCA_FLOWER_MAX, }; #define TCA_FLOWER_MAX (__TCA_FLOWER_MAX - 1) +enum { + TCA_FLOWER_KEY_ENC_OPTS_UNSPEC, + TCA_FLOWER_KEY_ENC_OPTS_GENEVE, /* Nested + * TCA_FLOWER_KEY_ENC_OPT_GENEVE_ + * attributes + */ + __TCA_FLOWER_KEY_ENC_OPTS_MAX, +}; + +#define TCA_FLOWER_KEY_ENC_OPTS_MAX (__TCA_FLOWER_KEY_ENC_OPTS_MAX - 1) + +enum { + TCA_FLOWER_KEY_ENC_OPT_GENEVE_UNSPEC, + TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS, /* u16 */ + TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE, /* u8 */ + TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA, /* 4 to 128 bytes */ + + __TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX, +}; + +#define TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX \ + (__TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX - 1) + enum { TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT = (1 << 0), TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST = (1 << 1), diff --git a/include/uapi/linux/tcp.h b/include/uapi/linux/tcp.h index 99e329b7..6ec77662 100644 --- a/include/uapi/linux/tcp.h +++ b/include/uapi/linux/tcp.h @@ -235,6 +235,11 @@ struct tcp_info { __u32 tcpi_delivered; __u32 tcpi_delivered_ce; + + __u64 tcpi_bytes_sent; /* RFC4898 tcpEStatsPerfHCDataOctetsOut */ + __u64 tcpi_bytes_retrans; /* RFC4898 tcpEStatsPerfOctetsRetrans */ + __u32 tcpi_dsack_dups; /* RFC4898 tcpEStatsStackDSACKDups */ + __u32 tcpi_reord_seen; /* reordering events seen */ }; /* netlink attributes types for SCM_TIMESTAMPING_OPT_STATS */ @@ -257,7 +262,10 @@ enum { TCP_NLA_SND_SSTHRESH, /* Slow start size threshold */ TCP_NLA_DELIVERED, /* Data pkts delivered incl. out-of-order */ TCP_NLA_DELIVERED_CE, /* Like above but only ones w/ CE marks */ - + TCP_NLA_BYTES_SENT, /* Data bytes sent including retransmission */ + TCP_NLA_BYTES_RETRANS, /* Data bytes retransmitted */ + TCP_NLA_DSACK_DUPS, /* DSACK blocks received */ + TCP_NLA_REORD_SEEN, /* reordering events seen */ }; /* for TCP_MD5SIG socket option */ diff --git a/include/uapi/linux/xfrm.h b/include/uapi/linux/xfrm.h index 93fb1920..5cdda9d3 100644 --- a/include/uapi/linux/xfrm.h +++ b/include/uapi/linux/xfrm.h @@ -305,9 +305,12 @@ enum xfrm_attr_type_t { XFRMA_ADDRESS_FILTER, /* struct xfrm_address_filter */ XFRMA_PAD, XFRMA_OFFLOAD_DEV, /* struct xfrm_state_offload */ - XFRMA_OUTPUT_MARK, /* __u32 */ + XFRMA_SET_MARK, /* __u32 */ + XFRMA_SET_MARK_MASK, /* __u32 */ + XFRMA_IF_ID, /* __u32 */ __XFRMA_MAX +#define XFRMA_OUTPUT_MARK XFRMA_SET_MARK /* Compatibility */ #define XFRMA_MAX (__XFRMA_MAX - 1) }; diff --git a/ip/ipaddress.c b/ip/ipaddress.c index 85958e1a..c94ddba8 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -49,9 +49,9 @@ static void usage(void) __attribute__((noreturn)); static void usage(void) { - if (do_link) { + if (do_link) iplink_usage(); - } + fprintf(stderr, "Usage: ip address {add|change|replace} IFADDR dev IFNAME [ LIFETIME ]\n"); fprintf(stderr, " [ CONFFLAG-LIST ]\n"); fprintf(stderr, " ip address del IFADDR dev IFNAME [mngtmpaddr]\n"); @@ -77,7 +77,7 @@ static void usage(void) fprintf(stderr, " bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan | lowpan |\n"); fprintf(stderr, " gre | gretap | erspan | ip6gre | ip6gretap | ip6erspan | vti |\n"); fprintf(stderr, " nlmon | can | bond_slave | ipvlan | geneve | bridge_slave |\n"); - fprintf(stderr, " hsr | macsec | netdevsim\n"); + fprintf(stderr, " hsr | macsec | netdevsim }\n"); exit(-1); } @@ -1946,7 +1946,7 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action) exit(1); } delete_json_obj(); - exit(0); + goto out; } if (filter.family != AF_PACKET) { diff --git a/ip/ipl2tp.c b/ip/ipl2tp.c index 05e96387..5e7f0390 100644 --- a/ip/ipl2tp.c +++ b/ip/ipl2tp.c @@ -53,14 +53,11 @@ struct l2tp_parm { inet_prefix peer_ip; uint16_t pw_type; - uint16_t mtu; unsigned int udp6_csum_tx:1; unsigned int udp6_csum_rx:1; unsigned int udp_csum:1; unsigned int recv_seq:1; unsigned int send_seq:1; - unsigned int lns_mode:1; - unsigned int data_seq:2; unsigned int tunnel:1; unsigned int session:1; int reorder_timeout; @@ -159,16 +156,10 @@ static int create_session(struct l2tp_parm *p) addattr8(&req.n, 1024, L2TP_ATTR_L2SPEC_TYPE, p->l2spec_type); addattr8(&req.n, 1024, L2TP_ATTR_L2SPEC_LEN, p->l2spec_len); - if (p->mtu) - addattr16(&req.n, 1024, L2TP_ATTR_MTU, p->mtu); if (p->recv_seq) addattr8(&req.n, 1024, L2TP_ATTR_RECV_SEQ, 1); if (p->send_seq) addattr8(&req.n, 1024, L2TP_ATTR_SEND_SEQ, 1); - if (p->lns_mode) - addattr(&req.n, 1024, L2TP_ATTR_LNS_MODE); - if (p->data_seq) - addattr8(&req.n, 1024, L2TP_ATTR_DATA_SEQ, p->data_seq); if (p->reorder_timeout) addattr64(&req.n, 1024, L2TP_ATTR_RECV_TIMEOUT, p->reorder_timeout); @@ -359,8 +350,6 @@ static int get_response(struct nlmsghdr *n, void *arg) p->pw_type = rta_getattr_u16(attrs[L2TP_ATTR_PW_TYPE]); if (attrs[L2TP_ATTR_ENCAP_TYPE]) p->encap = rta_getattr_u16(attrs[L2TP_ATTR_ENCAP_TYPE]); - if (attrs[L2TP_ATTR_DATA_SEQ]) - p->data_seq = rta_getattr_u16(attrs[L2TP_ATTR_DATA_SEQ]); if (attrs[L2TP_ATTR_CONN_ID]) p->tunnel_id = rta_getattr_u32(attrs[L2TP_ATTR_CONN_ID]); if (attrs[L2TP_ATTR_PEER_CONN_ID]) @@ -418,8 +407,6 @@ static int get_response(struct nlmsghdr *n, void *arg) p->local_udp_port = rta_getattr_u16(attrs[L2TP_ATTR_UDP_SPORT]); if (attrs[L2TP_ATTR_UDP_DPORT]) p->peer_udp_port = rta_getattr_u16(attrs[L2TP_ATTR_UDP_DPORT]); - if (attrs[L2TP_ATTR_MTU]) - p->mtu = rta_getattr_u16(attrs[L2TP_ATTR_MTU]); if (attrs[L2TP_ATTR_IFNAME]) p->ifname = rta_getattr_str(attrs[L2TP_ATTR_IFNAME]); diff --git a/lib/namespace.c b/lib/namespace.c index 43e0fe34..06ae0a48 100644 --- a/lib/namespace.c +++ b/lib/namespace.c @@ -82,19 +82,13 @@ int netns_switch(char *name) /* Mount a version of /sys that describes the network namespace */ - if (statvfs("/sys", &fsstat) < 0) { - fprintf(stderr, "could not stat /sys (not mounted?): %s\n",strerror(errno)); - return -1; - } - if (fsstat.f_flag & ST_RDONLY) { - /* If /sys is not writable (e.g. in a container), we can't - * unmount the old /sys instance, but we can still mount a new - * read-only instance over it. */ - mountflags = MS_RDONLY; - } else { - if (umount2("/sys", MNT_DETACH) < 0) { - fprintf(stderr, "umount of /sys failed: %s\n", strerror(errno)); - return -1; + if (umount2("/sys", MNT_DETACH) < 0) { + /* If this fails, perhaps there wasn't a sysfs instance mounted. Good. */ + if (statvfs("/sys", &fsstat) == 0) { + /* We couldn't umount the sysfs, we'll attempt to overlay it. + * A read-only instance can't be shadowed with a read-write one. */ + if (fsstat.f_flag & ST_RDONLY) + mountflags = MS_RDONLY; } } if (mount(name, "/sys", "sysfs", mountflags, NULL) < 0) { diff --git a/man/man8/tc-cake.8 b/man/man8/tc-cake.8 index bc595c9c..c1e751d6 100644 --- a/man/man8/tc-cake.8 +++ b/man/man8/tc-cake.8 @@ -73,6 +73,12 @@ TIME | ] .br [ +.BR split-gso* +| +.BR no-split-gso +] +.br +[ .BR ack-filter | .BR ack-filter-aggressive @@ -546,6 +552,23 @@ If you are shaping inbound, and cannot trust the diffserv markings (as is the case for Comcast Cable, among others), it is best to use a single queue "besteffort" mode with wash. +.PP +.B split-gso + +.br + This option controls whether CAKE will split General Segmentation +Offload (GSO) super-packets into their on-the-wire components and +dequeue them individually. + +.br +Super-packets are created by the networking stack to improve efficiency. +However, because they are larger they take longer to dequeue, which +translates to higher latency for competing flows, especially at lower +bandwidths. CAKE defaults to splitting GSO packets to achieve the lowest +possible latency. At link speeds higher than 10 Gbps, setting the +no-split-gso parameter can increase the maximum achievable throughput by +retaining the full GSO packets. + .SH EXAMPLES # tc qdisc delete root dev eth0 .br diff --git a/tc/f_flower.c b/tc/f_flower.c index 9a3fd775..59e5f572 100644 --- a/tc/f_flower.c +++ b/tc/f_flower.c @@ -1189,7 +1189,7 @@ static void flower_print_ip_proto(__u8 *p_ip_proto, *p_ip_proto = ip_proto; } -static void flower_print_ip_attr(char *name, struct rtattr *key_attr, +static void flower_print_ip_attr(const char *name, struct rtattr *key_attr, struct rtattr *mask_attr) { SPRINT_BUF(namefrm); @@ -1199,11 +1199,12 @@ static void flower_print_ip_attr(char *name, struct rtattr *key_attr, if (!key_attr) return; - done = sprintf(out, "%x", rta_getattr_u8(key_attr)); + done = sprintf(out, "0x%x", rta_getattr_u8(key_attr)); if (mask_attr) sprintf(out + done, "/%x", rta_getattr_u8(mask_attr)); - sprintf(namefrm, "\n %s %%s", name); + print_string(PRINT_FP, NULL, "%s ", _SL_); + sprintf(namefrm, "%s %%s", name); print_string(PRINT_ANY, name, namefrm, out); } @@ -1308,7 +1309,7 @@ static void flower_print_port(char *name, struct rtattr *attr) print_hu(PRINT_ANY, name, namefrm, rta_getattr_be16(attr)); } -static void flower_print_tcp_flags(char *name, struct rtattr *flags_attr, +static void flower_print_tcp_flags(const char *name, struct rtattr *flags_attr, struct rtattr *mask_attr) { SPRINT_BUF(namefrm); @@ -1318,11 +1319,12 @@ static void flower_print_tcp_flags(char *name, struct rtattr *flags_attr, if (!flags_attr) return; - done = sprintf(out, "%x", rta_getattr_be16(flags_attr)); + done = sprintf(out, "0x%x", rta_getattr_be16(flags_attr)); if (mask_attr) - sprintf(out + done, "%x", rta_getattr_be16(flags_attr)); + sprintf(out + done, "/%x", rta_getattr_be16(mask_attr)); - sprintf(namefrm, "\n %s %%s", name); + print_string(PRINT_FP, NULL, "%s ", _SL_); + sprintf(namefrm, "%s %%s", name); print_string(PRINT_ANY, name, namefrm, out); } diff --git a/tc/q_cake.c b/tc/q_cake.c index f1e232a6..50de46a7 100644 --- a/tc/q_cake.c +++ b/tc/q_cake.c @@ -79,6 +79,7 @@ static void explain(void) " dual-srchost | dual-dsthost | triple-isolate* ]\n" " [ nat | nonat* ]\n" " [ wash | nowash* ]\n" +" [ split-gso* | no-split-gso ]\n" " [ ack-filter | ack-filter-aggressive | no-ack-filter* ]\n" " [ memlimit LIMIT ]\n" " [ ptm | atm | noatm* ] [ overhead N | conservative | raw* ]\n" @@ -99,6 +100,7 @@ static int cake_parse_opt(struct qdisc_util *qu, int argc, char **argv, __u64 bandwidth = 0; int ack_filter = -1; struct rtattr *tail; + int split_gso = -1; int unlimited = 0; int flowmode = -1; int autorate = -1; @@ -155,6 +157,10 @@ static int cake_parse_opt(struct qdisc_util *qu, int argc, char **argv, wash = 0; } else if (strcmp(*argv, "wash") == 0) { wash = 1; + } else if (strcmp(*argv, "split-gso") == 0) { + split_gso = 1; + } else if (strcmp(*argv, "no-split-gso") == 0) { + split_gso = 0; } else if (strcmp(*argv, "flowblind") == 0) { flowmode = CAKE_FLOW_NONE; } else if (strcmp(*argv, "srchost") == 0) { @@ -374,6 +380,9 @@ static int cake_parse_opt(struct qdisc_util *qu, int argc, char **argv, addattr_l(n, 1024, TCA_CAKE_NAT, &nat, sizeof(nat)); if (wash != -1) addattr_l(n, 1024, TCA_CAKE_WASH, &wash, sizeof(wash)); + if (split_gso != -1) + addattr_l(n, 1024, TCA_CAKE_SPLIT_GSO, &split_gso, + sizeof(split_gso)); if (ingress != -1) addattr_l(n, 1024, TCA_CAKE_INGRESS, &ingress, sizeof(ingress)); if (ack_filter != -1) diff --git a/tc/tc.c b/tc/tc.c index fbc23dd9..a5a654f8 100644 --- a/tc/tc.c +++ b/tc/tc.c @@ -405,6 +405,7 @@ static int batch(const char *name) err = do_cmd(largc, largv, tail == NULL ? NULL : tail->buf, tail == NULL ? 0 : sizeof(tail->buf)); + fflush(stdout); if (err != 0) { fprintf(stderr, "Command failed %s:%d\n", name, cmdlineno - 1);