From 8ae2c5382bd9d98a8f7ddcb1faad1a978d773909 Mon Sep 17 00:00:00 2001 From: "stefan@datenfreihafen.org" Date: Fri, 28 Oct 2016 11:42:03 +0200 Subject: [PATCH 01/36] ip: update link types to show 6lowpan and ieee802.15.4 monitor Both types have been missing here and thus ip always showed only the numbers. Based on a suggestion from Alexander Aring. Signed-off-by: Stefan Schmidt --- lib/ll_types.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/ll_types.c b/lib/ll_types.c index 2c5bf8b5..eca617f3 100644 --- a/lib/ll_types.c +++ b/lib/ll_types.c @@ -100,11 +100,13 @@ __PF(IEEE80211,ieee802.11) __PF(IEEE80211_PRISM,ieee802.11/prism) __PF(IEEE80211_RADIOTAP,ieee802.11/radiotap) __PF(IEEE802154, ieee802.15.4) +__PF(IEEE802154_MONITOR, ieee802.15.4/monitor) __PF(PHONET, phonet) __PF(PHONET_PIPE, phonet_pipe) __PF(CAIF, caif) __PF(IP6GRE, gre6) __PF(NETLINK, netlink) +__PF(6LOWPAN, 6lowpan) __PF(NONE, none) __PF(VOID,void) From 878dadc79d247aa37b67fb30608e58ef1f9ab9ff Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Sat, 29 Oct 2016 22:20:19 +0300 Subject: [PATCH 02/36] iproute2: ss: escape all null bytes in abstract unix domain socket Abstract unix domain socket may embed null characters, these should be translated to '@' when printed by ss the same way the null prefix is currently being translated. Signed-off-by: Isaac Boukris --- misc/ss.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/misc/ss.c b/misc/ss.c index dd77b815..0e28998f 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -2895,7 +2895,9 @@ static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh, memcpy(name, RTA_DATA(tb[UNIX_DIAG_NAME]), len); name[len] = '\0'; if (name[0] == '\0') - name[0] = '@'; + for (int i = 0; i < len; i++) + if (name[i] == '\0') + name[i] = '@'; stat.name = &name[0]; memcpy(stat.local.data, &stat.name, sizeof(stat.name)); } From d9c3995ab7ce7fb523d50ca513283393066219ca Mon Sep 17 00:00:00 2001 From: Paul Blakey Date: Wed, 2 Nov 2016 17:09:58 +0200 Subject: [PATCH 03/36] tc: flower: Fix usage message Remove left over usage from removal of eth_type argument. Fixes: 488b41d020fb ('tc: flower no need to specify the ethertype') Signed-off-by: Paul Blakey Reviewed-by: Simon Horman --- man/man8/tc-flower.8 | 9 --------- tc/f_flower.c | 3 +-- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/man/man8/tc-flower.8 b/man/man8/tc-flower.8 index 74f76647..16ef2617 100644 --- a/man/man8/tc-flower.8 +++ b/man/man8/tc-flower.8 @@ -23,8 +23,6 @@ flower \- flow based traffic control filter .R " | { " .BR dst_mac " | " src_mac " } " .IR mac_address " | " -.BR eth_type " { " ipv4 " | " ipv6 " | " 802.1Q " | " -.IR ETH_TYPE " } | " .B vlan_id .IR VID " | " .B vlan_prio @@ -75,13 +73,6 @@ Do not process filter by hardware. .BI src_mac " mac_address" Match on source or destination MAC address. .TP -.BI eth_type " ETH_TYPE" -Match on the next protocol. -.I ETH_TYPE -may be either -.BR ipv4 , ipv6 , 802.1Q , -or an unsigned 16bit value in hexadecimal format. -.TP .BI vlan_id " VID" Match on vlan tag id. .I VID diff --git a/tc/f_flower.c b/tc/f_flower.c index 2d31d1aa..f39b1f7f 100644 --- a/tc/f_flower.c +++ b/tc/f_flower.c @@ -36,7 +36,6 @@ static void explain(void) fprintf(stderr, " vlan_ethtype [ ipv4 | ipv6 | ETH-TYPE ] |\n"); fprintf(stderr, " dst_mac MAC-ADDR |\n"); fprintf(stderr, " src_mac MAC-ADDR |\n"); - fprintf(stderr, " [ipv4 | ipv6 ] |\n"); fprintf(stderr, " ip_proto [tcp | udp | IP-PROTO ] |\n"); fprintf(stderr, " dst_ip [ IPV4-ADDR | IPV6-ADDR ] |\n"); fprintf(stderr, " src_ip [ IPV4-ADDR | IPV6-ADDR ] |\n"); @@ -45,7 +44,7 @@ static void explain(void) fprintf(stderr, " FILTERID := X:Y:Z\n"); fprintf(stderr, " ACTION-SPEC := ... look at individual actions\n"); fprintf(stderr, "\n"); - fprintf(stderr, "NOTE: CLASSID, ETH-TYPE, IP-PROTO are parsed as hexadecimal input.\n"); + fprintf(stderr, "NOTE: CLASSID, IP-PROTO are parsed as hexadecimal input.\n"); fprintf(stderr, "NOTE: There can be only used one mask per one prio. If user needs\n"); fprintf(stderr, " to specify different mask, he has to use different prio.\n"); } From 5dec02d7b4b70128a661bab1ff991c605ba28b3f Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 9 Nov 2016 12:12:23 +0100 Subject: [PATCH 04/36] include: Add linux/sctp.h Add sanitized UAPI linux/sctp.h header file. Signed-off-by: Phil Sutter --- include/linux/sctp.h | 1005 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1005 insertions(+) create mode 100644 include/linux/sctp.h diff --git a/include/linux/sctp.h b/include/linux/sctp.h new file mode 100644 index 00000000..eee08c06 --- /dev/null +++ b/include/linux/sctp.h @@ -0,0 +1,1005 @@ +/* SCTP kernel implementation + * (C) Copyright IBM Corp. 2001, 2004 + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2002 Intel Corp. + * + * This file is part of the SCTP kernel implementation + * + * This header represents the structures and constants needed to support + * the SCTP Extension to the Sockets API. + * + * This SCTP implementation is free software; + * you can redistribute it and/or modify it under the terms of + * the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This SCTP implementation is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * ************************ + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU CC; see the file COPYING. If not, see + * . + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * R. Stewart + * K. Morneau + * Q. Xie + * Karl Knutson + * Jon Grimm + * Daisy Chang + * Ryan Layer + * Ardelle Fan + * Sridhar Samudrala + * Inaky Perez-Gonzalez + * Vlad Yasevich + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#ifndef _SCTP_H +#define _SCTP_H + +#include +#include + +typedef __s32 sctp_assoc_t; + +/* The following symbols come from the Sockets API Extensions for + * SCTP . + */ +#define SCTP_RTOINFO 0 +#define SCTP_ASSOCINFO 1 +#define SCTP_INITMSG 2 +#define SCTP_NODELAY 3 /* Get/set nodelay option. */ +#define SCTP_AUTOCLOSE 4 +#define SCTP_SET_PEER_PRIMARY_ADDR 5 +#define SCTP_PRIMARY_ADDR 6 +#define SCTP_ADAPTATION_LAYER 7 +#define SCTP_DISABLE_FRAGMENTS 8 +#define SCTP_PEER_ADDR_PARAMS 9 +#define SCTP_DEFAULT_SEND_PARAM 10 +#define SCTP_EVENTS 11 +#define SCTP_I_WANT_MAPPED_V4_ADDR 12 /* Turn on/off mapped v4 addresses */ +#define SCTP_MAXSEG 13 /* Get/set maximum fragment. */ +#define SCTP_STATUS 14 +#define SCTP_GET_PEER_ADDR_INFO 15 +#define SCTP_DELAYED_ACK_TIME 16 +#define SCTP_DELAYED_ACK SCTP_DELAYED_ACK_TIME +#define SCTP_DELAYED_SACK SCTP_DELAYED_ACK_TIME +#define SCTP_CONTEXT 17 +#define SCTP_FRAGMENT_INTERLEAVE 18 +#define SCTP_PARTIAL_DELIVERY_POINT 19 /* Set/Get partial delivery point */ +#define SCTP_MAX_BURST 20 /* Set/Get max burst */ +#define SCTP_AUTH_CHUNK 21 /* Set only: add a chunk type to authenticate */ +#define SCTP_HMAC_IDENT 22 +#define SCTP_AUTH_KEY 23 +#define SCTP_AUTH_ACTIVE_KEY 24 +#define SCTP_AUTH_DELETE_KEY 25 +#define SCTP_PEER_AUTH_CHUNKS 26 /* Read only */ +#define SCTP_LOCAL_AUTH_CHUNKS 27 /* Read only */ +#define SCTP_GET_ASSOC_NUMBER 28 /* Read only */ +#define SCTP_GET_ASSOC_ID_LIST 29 /* Read only */ +#define SCTP_AUTO_ASCONF 30 +#define SCTP_PEER_ADDR_THLDS 31 +#define SCTP_RECVRCVINFO 32 +#define SCTP_RECVNXTINFO 33 +#define SCTP_DEFAULT_SNDINFO 34 + +/* Internal Socket Options. Some of the sctp library functions are + * implemented using these socket options. + */ +#define SCTP_SOCKOPT_BINDX_ADD 100 /* BINDX requests for adding addrs */ +#define SCTP_SOCKOPT_BINDX_REM 101 /* BINDX requests for removing addrs. */ +#define SCTP_SOCKOPT_PEELOFF 102 /* peel off association. */ +/* Options 104-106 are deprecated and removed. Do not use this space */ +#define SCTP_SOCKOPT_CONNECTX_OLD 107 /* CONNECTX old requests. */ +#define SCTP_GET_PEER_ADDRS 108 /* Get all peer address. */ +#define SCTP_GET_LOCAL_ADDRS 109 /* Get all local address. */ +#define SCTP_SOCKOPT_CONNECTX 110 /* CONNECTX requests. */ +#define SCTP_SOCKOPT_CONNECTX3 111 /* CONNECTX requests (updated) */ +#define SCTP_GET_ASSOC_STATS 112 /* Read only */ +#define SCTP_PR_SUPPORTED 113 +#define SCTP_DEFAULT_PRINFO 114 +#define SCTP_PR_ASSOC_STATUS 115 + +/* PR-SCTP policies */ +#define SCTP_PR_SCTP_NONE 0x0000 +#define SCTP_PR_SCTP_TTL 0x0010 +#define SCTP_PR_SCTP_RTX 0x0020 +#define SCTP_PR_SCTP_PRIO 0x0030 +#define SCTP_PR_SCTP_MAX SCTP_PR_SCTP_PRIO +#define SCTP_PR_SCTP_MASK 0x0030 + +#define __SCTP_PR_INDEX(x) ((x >> 4) - 1) +#define SCTP_PR_INDEX(x) __SCTP_PR_INDEX(SCTP_PR_SCTP_ ## x) + +#define SCTP_PR_POLICY(x) ((x) & SCTP_PR_SCTP_MASK) +#define SCTP_PR_SET_POLICY(flags, x) \ + do { \ + flags &= ~SCTP_PR_SCTP_MASK; \ + flags |= x; \ + } while (0) + +#define SCTP_PR_TTL_ENABLED(x) (SCTP_PR_POLICY(x) == SCTP_PR_SCTP_TTL) +#define SCTP_PR_RTX_ENABLED(x) (SCTP_PR_POLICY(x) == SCTP_PR_SCTP_RTX) +#define SCTP_PR_PRIO_ENABLED(x) (SCTP_PR_POLICY(x) == SCTP_PR_SCTP_PRIO) + +/* These are bit fields for msghdr->msg_flags. See section 5.1. */ +/* On user space Linux, these live in as an enum. */ +enum sctp_msg_flags { + MSG_NOTIFICATION = 0x8000, +#define MSG_NOTIFICATION MSG_NOTIFICATION +}; + +/* 5.3.1 SCTP Initiation Structure (SCTP_INIT) + * + * This cmsghdr structure provides information for initializing new + * SCTP associations with sendmsg(). The SCTP_INITMSG socket option + * uses this same data structure. This structure is not used for + * recvmsg(). + * + * cmsg_level cmsg_type cmsg_data[] + * ------------ ------------ ---------------------- + * IPPROTO_SCTP SCTP_INIT struct sctp_initmsg + */ +struct sctp_initmsg { + __u16 sinit_num_ostreams; + __u16 sinit_max_instreams; + __u16 sinit_max_attempts; + __u16 sinit_max_init_timeo; +}; + +/* 5.3.2 SCTP Header Information Structure (SCTP_SNDRCV) + * + * This cmsghdr structure specifies SCTP options for sendmsg() and + * describes SCTP header information about a received message through + * recvmsg(). + * + * cmsg_level cmsg_type cmsg_data[] + * ------------ ------------ ---------------------- + * IPPROTO_SCTP SCTP_SNDRCV struct sctp_sndrcvinfo + */ +struct sctp_sndrcvinfo { + __u16 sinfo_stream; + __u16 sinfo_ssn; + __u16 sinfo_flags; + __u32 sinfo_ppid; + __u32 sinfo_context; + __u32 sinfo_timetolive; + __u32 sinfo_tsn; + __u32 sinfo_cumtsn; + sctp_assoc_t sinfo_assoc_id; +}; + +/* 5.3.4 SCTP Send Information Structure (SCTP_SNDINFO) + * + * This cmsghdr structure specifies SCTP options for sendmsg(). + * + * cmsg_level cmsg_type cmsg_data[] + * ------------ ------------ ------------------- + * IPPROTO_SCTP SCTP_SNDINFO struct sctp_sndinfo + */ +struct sctp_sndinfo { + __u16 snd_sid; + __u16 snd_flags; + __u32 snd_ppid; + __u32 snd_context; + sctp_assoc_t snd_assoc_id; +}; + +/* 5.3.5 SCTP Receive Information Structure (SCTP_RCVINFO) + * + * This cmsghdr structure describes SCTP receive information + * about a received message through recvmsg(). + * + * cmsg_level cmsg_type cmsg_data[] + * ------------ ------------ ------------------- + * IPPROTO_SCTP SCTP_RCVINFO struct sctp_rcvinfo + */ +struct sctp_rcvinfo { + __u16 rcv_sid; + __u16 rcv_ssn; + __u16 rcv_flags; + __u32 rcv_ppid; + __u32 rcv_tsn; + __u32 rcv_cumtsn; + __u32 rcv_context; + sctp_assoc_t rcv_assoc_id; +}; + +/* 5.3.6 SCTP Next Receive Information Structure (SCTP_NXTINFO) + * + * This cmsghdr structure describes SCTP receive information + * of the next message that will be delivered through recvmsg() + * if this information is already available when delivering + * the current message. + * + * cmsg_level cmsg_type cmsg_data[] + * ------------ ------------ ------------------- + * IPPROTO_SCTP SCTP_NXTINFO struct sctp_nxtinfo + */ +struct sctp_nxtinfo { + __u16 nxt_sid; + __u16 nxt_flags; + __u32 nxt_ppid; + __u32 nxt_length; + sctp_assoc_t nxt_assoc_id; +}; + +/* + * sinfo_flags: 16 bits (unsigned integer) + * + * This field may contain any of the following flags and is composed of + * a bitwise OR of these values. + */ +enum sctp_sinfo_flags { + SCTP_UNORDERED = (1 << 0), /* Send/receive message unordered. */ + SCTP_ADDR_OVER = (1 << 1), /* Override the primary destination. */ + SCTP_ABORT = (1 << 2), /* Send an ABORT message to the peer. */ + SCTP_SACK_IMMEDIATELY = (1 << 3), /* SACK should be sent without delay. */ + SCTP_NOTIFICATION = MSG_NOTIFICATION, /* Next message is not user msg but notification. */ + SCTP_EOF = MSG_FIN, /* Initiate graceful shutdown process. */ +}; + +typedef union { + __u8 raw; + struct sctp_initmsg init; + struct sctp_sndrcvinfo sndrcv; +} sctp_cmsg_data_t; + +/* These are cmsg_types. */ +typedef enum sctp_cmsg_type { + SCTP_INIT, /* 5.2.1 SCTP Initiation Structure */ +#define SCTP_INIT SCTP_INIT + SCTP_SNDRCV, /* 5.2.2 SCTP Header Information Structure */ +#define SCTP_SNDRCV SCTP_SNDRCV + SCTP_SNDINFO, /* 5.3.4 SCTP Send Information Structure */ +#define SCTP_SNDINFO SCTP_SNDINFO + SCTP_RCVINFO, /* 5.3.5 SCTP Receive Information Structure */ +#define SCTP_RCVINFO SCTP_RCVINFO + SCTP_NXTINFO, /* 5.3.6 SCTP Next Receive Information Structure */ +#define SCTP_NXTINFO SCTP_NXTINFO +} sctp_cmsg_t; + +/* + * 5.3.1.1 SCTP_ASSOC_CHANGE + * + * Communication notifications inform the ULP that an SCTP association + * has either begun or ended. The identifier for a new association is + * provided by this notificaion. The notification information has the + * following format: + * + */ +struct sctp_assoc_change { + __u16 sac_type; + __u16 sac_flags; + __u32 sac_length; + __u16 sac_state; + __u16 sac_error; + __u16 sac_outbound_streams; + __u16 sac_inbound_streams; + sctp_assoc_t sac_assoc_id; + __u8 sac_info[0]; +}; + +/* + * sac_state: 32 bits (signed integer) + * + * This field holds one of a number of values that communicate the + * event that happened to the association. They include: + * + * Note: The following state names deviate from the API draft as + * the names clash too easily with other kernel symbols. + */ +enum sctp_sac_state { + SCTP_COMM_UP, + SCTP_COMM_LOST, + SCTP_RESTART, + SCTP_SHUTDOWN_COMP, + SCTP_CANT_STR_ASSOC, +}; + +/* + * 5.3.1.2 SCTP_PEER_ADDR_CHANGE + * + * When a destination address on a multi-homed peer encounters a change + * an interface details event is sent. The information has the + * following structure: + */ +struct sctp_paddr_change { + __u16 spc_type; + __u16 spc_flags; + __u32 spc_length; + struct sockaddr_storage spc_aaddr; + int spc_state; + int spc_error; + sctp_assoc_t spc_assoc_id; +} __attribute__((packed, aligned(4))); + +/* + * spc_state: 32 bits (signed integer) + * + * This field holds one of a number of values that communicate the + * event that happened to the address. They include: + */ +enum sctp_spc_state { + SCTP_ADDR_AVAILABLE, + SCTP_ADDR_UNREACHABLE, + SCTP_ADDR_REMOVED, + SCTP_ADDR_ADDED, + SCTP_ADDR_MADE_PRIM, + SCTP_ADDR_CONFIRMED, +}; + + +/* + * 5.3.1.3 SCTP_REMOTE_ERROR + * + * A remote peer may send an Operational Error message to its peer. + * This message indicates a variety of error conditions on an + * association. The entire error TLV as it appears on the wire is + * included in a SCTP_REMOTE_ERROR event. Please refer to the SCTP + * specification [SCTP] and any extensions for a list of possible + * error formats. SCTP error TLVs have the format: + */ +struct sctp_remote_error { + __u16 sre_type; + __u16 sre_flags; + __u32 sre_length; + __u16 sre_error; + sctp_assoc_t sre_assoc_id; + __u8 sre_data[0]; +}; + + +/* + * 5.3.1.4 SCTP_SEND_FAILED + * + * If SCTP cannot deliver a message it may return the message as a + * notification. + */ +struct sctp_send_failed { + __u16 ssf_type; + __u16 ssf_flags; + __u32 ssf_length; + __u32 ssf_error; + struct sctp_sndrcvinfo ssf_info; + sctp_assoc_t ssf_assoc_id; + __u8 ssf_data[0]; +}; + +/* + * ssf_flags: 16 bits (unsigned integer) + * + * The flag value will take one of the following values + * + * SCTP_DATA_UNSENT - Indicates that the data was never put on + * the wire. + * + * SCTP_DATA_SENT - Indicates that the data was put on the wire. + * Note that this does not necessarily mean that the + * data was (or was not) successfully delivered. + */ +enum sctp_ssf_flags { + SCTP_DATA_UNSENT, + SCTP_DATA_SENT, +}; + +/* + * 5.3.1.5 SCTP_SHUTDOWN_EVENT + * + * When a peer sends a SHUTDOWN, SCTP delivers this notification to + * inform the application that it should cease sending data. + */ +struct sctp_shutdown_event { + __u16 sse_type; + __u16 sse_flags; + __u32 sse_length; + sctp_assoc_t sse_assoc_id; +}; + +/* + * 5.3.1.6 SCTP_ADAPTATION_INDICATION + * + * When a peer sends a Adaptation Layer Indication parameter , SCTP + * delivers this notification to inform the application + * that of the peers requested adaptation layer. + */ +struct sctp_adaptation_event { + __u16 sai_type; + __u16 sai_flags; + __u32 sai_length; + __u32 sai_adaptation_ind; + sctp_assoc_t sai_assoc_id; +}; + +/* + * 5.3.1.7 SCTP_PARTIAL_DELIVERY_EVENT + * + * When a receiver is engaged in a partial delivery of a + * message this notification will be used to indicate + * various events. + */ +struct sctp_pdapi_event { + __u16 pdapi_type; + __u16 pdapi_flags; + __u32 pdapi_length; + __u32 pdapi_indication; + sctp_assoc_t pdapi_assoc_id; +}; + +enum { SCTP_PARTIAL_DELIVERY_ABORTED=0, }; + +/* + * 5.3.1.8. SCTP_AUTHENTICATION_EVENT + * + * When a receiver is using authentication this message will provide + * notifications regarding new keys being made active as well as errors. + */ +struct sctp_authkey_event { + __u16 auth_type; + __u16 auth_flags; + __u32 auth_length; + __u16 auth_keynumber; + __u16 auth_altkeynumber; + __u32 auth_indication; + sctp_assoc_t auth_assoc_id; +}; + +enum { SCTP_AUTH_NEWKEY = 0, }; + +/* + * 6.1.9. SCTP_SENDER_DRY_EVENT + * + * When the SCTP stack has no more user data to send or retransmit, this + * notification is given to the user. Also, at the time when a user app + * subscribes to this event, if there is no data to be sent or + * retransmit, the stack will immediately send up this notification. + */ +struct sctp_sender_dry_event { + __u16 sender_dry_type; + __u16 sender_dry_flags; + __u32 sender_dry_length; + sctp_assoc_t sender_dry_assoc_id; +}; + +/* + * Described in Section 7.3 + * Ancillary Data and Notification Interest Options + */ +struct sctp_event_subscribe { + __u8 sctp_data_io_event; + __u8 sctp_association_event; + __u8 sctp_address_event; + __u8 sctp_send_failure_event; + __u8 sctp_peer_error_event; + __u8 sctp_shutdown_event; + __u8 sctp_partial_delivery_event; + __u8 sctp_adaptation_layer_event; + __u8 sctp_authentication_event; + __u8 sctp_sender_dry_event; +}; + +/* + * 5.3.1 SCTP Notification Structure + * + * The notification structure is defined as the union of all + * notification types. + * + */ +union sctp_notification { + struct { + __u16 sn_type; /* Notification type. */ + __u16 sn_flags; + __u32 sn_length; + } sn_header; + struct sctp_assoc_change sn_assoc_change; + struct sctp_paddr_change sn_paddr_change; + struct sctp_remote_error sn_remote_error; + struct sctp_send_failed sn_send_failed; + struct sctp_shutdown_event sn_shutdown_event; + struct sctp_adaptation_event sn_adaptation_event; + struct sctp_pdapi_event sn_pdapi_event; + struct sctp_authkey_event sn_authkey_event; + struct sctp_sender_dry_event sn_sender_dry_event; +}; + +/* Section 5.3.1 + * All standard values for sn_type flags are greater than 2^15. + * Values from 2^15 and down are reserved. + */ + +enum sctp_sn_type { + SCTP_SN_TYPE_BASE = (1<<15), + SCTP_ASSOC_CHANGE, +#define SCTP_ASSOC_CHANGE SCTP_ASSOC_CHANGE + SCTP_PEER_ADDR_CHANGE, +#define SCTP_PEER_ADDR_CHANGE SCTP_PEER_ADDR_CHANGE + SCTP_SEND_FAILED, +#define SCTP_SEND_FAILED SCTP_SEND_FAILED + SCTP_REMOTE_ERROR, +#define SCTP_REMOTE_ERROR SCTP_REMOTE_ERROR + SCTP_SHUTDOWN_EVENT, +#define SCTP_SHUTDOWN_EVENT SCTP_SHUTDOWN_EVENT + SCTP_PARTIAL_DELIVERY_EVENT, +#define SCTP_PARTIAL_DELIVERY_EVENT SCTP_PARTIAL_DELIVERY_EVENT + SCTP_ADAPTATION_INDICATION, +#define SCTP_ADAPTATION_INDICATION SCTP_ADAPTATION_INDICATION + SCTP_AUTHENTICATION_EVENT, +#define SCTP_AUTHENTICATION_INDICATION SCTP_AUTHENTICATION_EVENT + SCTP_SENDER_DRY_EVENT, +#define SCTP_SENDER_DRY_EVENT SCTP_SENDER_DRY_EVENT +}; + +/* Notification error codes used to fill up the error fields in some + * notifications. + * SCTP_PEER_ADDRESS_CHAGE : spc_error + * SCTP_ASSOC_CHANGE : sac_error + * These names should be potentially included in the draft 04 of the SCTP + * sockets API specification. + */ +typedef enum sctp_sn_error { + SCTP_FAILED_THRESHOLD, + SCTP_RECEIVED_SACK, + SCTP_HEARTBEAT_SUCCESS, + SCTP_RESPONSE_TO_USER_REQ, + SCTP_INTERNAL_ERROR, + SCTP_SHUTDOWN_GUARD_EXPIRES, + SCTP_PEER_FAULTY, +} sctp_sn_error_t; + +/* + * 7.1.1 Retransmission Timeout Parameters (SCTP_RTOINFO) + * + * The protocol parameters used to initialize and bound retransmission + * timeout (RTO) are tunable. See [SCTP] for more information on how + * these parameters are used in RTO calculation. + */ +struct sctp_rtoinfo { + sctp_assoc_t srto_assoc_id; + __u32 srto_initial; + __u32 srto_max; + __u32 srto_min; +}; + +/* + * 7.1.2 Association Parameters (SCTP_ASSOCINFO) + * + * This option is used to both examine and set various association and + * endpoint parameters. + */ +struct sctp_assocparams { + sctp_assoc_t sasoc_assoc_id; + __u16 sasoc_asocmaxrxt; + __u16 sasoc_number_peer_destinations; + __u32 sasoc_peer_rwnd; + __u32 sasoc_local_rwnd; + __u32 sasoc_cookie_life; +}; + +/* + * 7.1.9 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR) + * + * Requests that the peer mark the enclosed address as the association + * primary. The enclosed address must be one of the association's + * locally bound addresses. The following structure is used to make a + * set primary request: + */ +struct sctp_setpeerprim { + sctp_assoc_t sspp_assoc_id; + struct sockaddr_storage sspp_addr; +} __attribute__((packed, aligned(4))); + +/* + * 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) + * + * Requests that the local SCTP stack use the enclosed peer address as + * the association primary. The enclosed address must be one of the + * association peer's addresses. The following structure is used to + * make a set peer primary request: + */ +struct sctp_prim { + sctp_assoc_t ssp_assoc_id; + struct sockaddr_storage ssp_addr; +} __attribute__((packed, aligned(4))); + +/* For backward compatibility use, define the old name too */ +#define sctp_setprim sctp_prim + +/* + * 7.1.11 Set Adaptation Layer Indicator (SCTP_ADAPTATION_LAYER) + * + * Requests that the local endpoint set the specified Adaptation Layer + * Indication parameter for all future INIT and INIT-ACK exchanges. + */ +struct sctp_setadaptation { + __u32 ssb_adaptation_ind; +}; + +/* + * 7.1.13 Peer Address Parameters (SCTP_PEER_ADDR_PARAMS) + * + * Applications can enable or disable heartbeats for any peer address + * of an association, modify an address's heartbeat interval, force a + * heartbeat to be sent immediately, and adjust the address's maximum + * number of retransmissions sent before an address is considered + * unreachable. The following structure is used to access and modify an + * address's parameters: + */ +enum sctp_spp_flags { + SPP_HB_ENABLE = 1<<0, /*Enable heartbeats*/ + SPP_HB_DISABLE = 1<<1, /*Disable heartbeats*/ + SPP_HB = SPP_HB_ENABLE | SPP_HB_DISABLE, + SPP_HB_DEMAND = 1<<2, /*Send heartbeat immediately*/ + SPP_PMTUD_ENABLE = 1<<3, /*Enable PMTU discovery*/ + SPP_PMTUD_DISABLE = 1<<4, /*Disable PMTU discovery*/ + SPP_PMTUD = SPP_PMTUD_ENABLE | SPP_PMTUD_DISABLE, + SPP_SACKDELAY_ENABLE = 1<<5, /*Enable SACK*/ + SPP_SACKDELAY_DISABLE = 1<<6, /*Disable SACK*/ + SPP_SACKDELAY = SPP_SACKDELAY_ENABLE | SPP_SACKDELAY_DISABLE, + SPP_HB_TIME_IS_ZERO = 1<<7, /* Set HB delay to 0 */ +}; + +struct sctp_paddrparams { + sctp_assoc_t spp_assoc_id; + struct sockaddr_storage spp_address; + __u32 spp_hbinterval; + __u16 spp_pathmaxrxt; + __u32 spp_pathmtu; + __u32 spp_sackdelay; + __u32 spp_flags; +} __attribute__((packed, aligned(4))); + +/* + * 7.1.18. Add a chunk that must be authenticated (SCTP_AUTH_CHUNK) + * + * This set option adds a chunk type that the user is requesting to be + * received only in an authenticated way. Changes to the list of chunks + * will only effect future associations on the socket. + */ +struct sctp_authchunk { + __u8 sauth_chunk; +}; + +/* + * 7.1.19. Get or set the list of supported HMAC Identifiers (SCTP_HMAC_IDENT) + * + * This option gets or sets the list of HMAC algorithms that the local + * endpoint requires the peer to use. + */ +/* This here is only used by user space as is. It might not be a good idea + * to export/reveal the whole structure with reserved fields etc. + */ +enum { + SCTP_AUTH_HMAC_ID_SHA1 = 1, + SCTP_AUTH_HMAC_ID_SHA256 = 3, +}; + +struct sctp_hmacalgo { + __u32 shmac_num_idents; + __u16 shmac_idents[]; +}; + +/* Sadly, user and kernel space have different names for + * this structure member, so this is to not break anything. + */ +#define shmac_number_of_idents shmac_num_idents + +/* + * 7.1.20. Set a shared key (SCTP_AUTH_KEY) + * + * This option will set a shared secret key which is used to build an + * association shared key. + */ +struct sctp_authkey { + sctp_assoc_t sca_assoc_id; + __u16 sca_keynumber; + __u16 sca_keylength; + __u8 sca_key[]; +}; + +/* + * 7.1.21. Get or set the active shared key (SCTP_AUTH_ACTIVE_KEY) + * + * This option will get or set the active shared key to be used to build + * the association shared key. + */ + +struct sctp_authkeyid { + sctp_assoc_t scact_assoc_id; + __u16 scact_keynumber; +}; + + +/* + * 7.1.23. Get or set delayed ack timer (SCTP_DELAYED_SACK) + * + * This option will effect the way delayed acks are performed. This + * option allows you to get or set the delayed ack time, in + * milliseconds. It also allows changing the delayed ack frequency. + * Changing the frequency to 1 disables the delayed sack algorithm. If + * the assoc_id is 0, then this sets or gets the endpoints default + * values. If the assoc_id field is non-zero, then the set or get + * effects the specified association for the one to many model (the + * assoc_id field is ignored by the one to one model). Note that if + * sack_delay or sack_freq are 0 when setting this option, then the + * current values will remain unchanged. + */ +struct sctp_sack_info { + sctp_assoc_t sack_assoc_id; + uint32_t sack_delay; + uint32_t sack_freq; +}; + +struct sctp_assoc_value { + sctp_assoc_t assoc_id; + uint32_t assoc_value; +}; + +/* + * 7.2.2 Peer Address Information + * + * Applications can retrieve information about a specific peer address + * of an association, including its reachability state, congestion + * window, and retransmission timer values. This information is + * read-only. The following structure is used to access this + * information: + */ +struct sctp_paddrinfo { + sctp_assoc_t spinfo_assoc_id; + struct sockaddr_storage spinfo_address; + __s32 spinfo_state; + __u32 spinfo_cwnd; + __u32 spinfo_srtt; + __u32 spinfo_rto; + __u32 spinfo_mtu; +} __attribute__((packed, aligned(4))); + +/* Peer addresses's state. */ +/* UNKNOWN: Peer address passed by the upper layer in sendmsg or connect[x] + * calls. + * UNCONFIRMED: Peer address received in INIT/INIT-ACK address parameters. + * Not yet confirmed by a heartbeat and not available for data + * transfers. + * ACTIVE : Peer address confirmed, active and available for data transfers. + * INACTIVE: Peer address inactive and not available for data transfers. + */ +enum sctp_spinfo_state { + SCTP_INACTIVE, + SCTP_PF, + SCTP_ACTIVE, + SCTP_UNCONFIRMED, + SCTP_UNKNOWN = 0xffff /* Value used for transport state unknown */ +}; + +/* + * 7.2.1 Association Status (SCTP_STATUS) + * + * Applications can retrieve current status information about an + * association, including association state, peer receiver window size, + * number of unacked data chunks, and number of data chunks pending + * receipt. This information is read-only. The following structure is + * used to access this information: + */ +struct sctp_status { + sctp_assoc_t sstat_assoc_id; + __s32 sstat_state; + __u32 sstat_rwnd; + __u16 sstat_unackdata; + __u16 sstat_penddata; + __u16 sstat_instrms; + __u16 sstat_outstrms; + __u32 sstat_fragmentation_point; + struct sctp_paddrinfo sstat_primary; +}; + +/* + * 7.2.3. Get the list of chunks the peer requires to be authenticated + * (SCTP_PEER_AUTH_CHUNKS) + * + * This option gets a list of chunks for a specified association that + * the peer requires to be received authenticated only. + */ +struct sctp_authchunks { + sctp_assoc_t gauth_assoc_id; + __u32 gauth_number_of_chunks; + uint8_t gauth_chunks[]; +}; + +/* The broken spelling has been released already in lksctp-tools header, + * so don't break anyone, now that it's fixed. + */ +#define guth_number_of_chunks gauth_number_of_chunks + +/* Association states. */ +enum sctp_sstat_state { + SCTP_EMPTY = 0, + SCTP_CLOSED = 1, + SCTP_COOKIE_WAIT = 2, + SCTP_COOKIE_ECHOED = 3, + SCTP_ESTABLISHED = 4, + SCTP_SHUTDOWN_PENDING = 5, + SCTP_SHUTDOWN_SENT = 6, + SCTP_SHUTDOWN_RECEIVED = 7, + SCTP_SHUTDOWN_ACK_SENT = 8, +}; + +/* + * 8.2.6. Get the Current Identifiers of Associations + * (SCTP_GET_ASSOC_ID_LIST) + * + * This option gets the current list of SCTP association identifiers of + * the SCTP associations handled by a one-to-many style socket. + */ +struct sctp_assoc_ids { + __u32 gaids_number_of_ids; + sctp_assoc_t gaids_assoc_id[]; +}; + +/* + * 8.3, 8.5 get all peer/local addresses in an association. + * This parameter struct is used by SCTP_GET_PEER_ADDRS and + * SCTP_GET_LOCAL_ADDRS socket options used internally to implement + * sctp_getpaddrs() and sctp_getladdrs() API. + */ +struct sctp_getaddrs_old { + sctp_assoc_t assoc_id; + int addr_num; + struct sockaddr *addrs; +}; + +struct sctp_getaddrs { + sctp_assoc_t assoc_id; /*input*/ + __u32 addr_num; /*output*/ + __u8 addrs[0]; /*output, variable size*/ +}; + +/* A socket user request obtained via SCTP_GET_ASSOC_STATS that retrieves + * association stats. All stats are counts except sas_maxrto and + * sas_obs_rto_ipaddr. maxrto is the max observed rto + transport since + * the last call. Will return 0 when RTO was not update since last call + */ +struct sctp_assoc_stats { + sctp_assoc_t sas_assoc_id; /* Input */ + /* Transport of observed max RTO */ + struct sockaddr_storage sas_obs_rto_ipaddr; + __u64 sas_maxrto; /* Maximum Observed RTO for period */ + __u64 sas_isacks; /* SACKs received */ + __u64 sas_osacks; /* SACKs sent */ + __u64 sas_opackets; /* Packets sent */ + __u64 sas_ipackets; /* Packets received */ + __u64 sas_rtxchunks; /* Retransmitted Chunks */ + __u64 sas_outofseqtsns;/* TSN received > next expected */ + __u64 sas_idupchunks; /* Dups received (ordered+unordered) */ + __u64 sas_gapcnt; /* Gap Acknowledgements Received */ + __u64 sas_ouodchunks; /* Unordered data chunks sent */ + __u64 sas_iuodchunks; /* Unordered data chunks received */ + __u64 sas_oodchunks; /* Ordered data chunks sent */ + __u64 sas_iodchunks; /* Ordered data chunks received */ + __u64 sas_octrlchunks; /* Control chunks sent */ + __u64 sas_ictrlchunks; /* Control chunks received */ +}; + +/* + * 8.1 sctp_bindx() + * + * The flags parameter is formed from the bitwise OR of zero or more of the + * following currently defined flags: + */ +#define SCTP_BINDX_ADD_ADDR 0x01 +#define SCTP_BINDX_REM_ADDR 0x02 + +/* This is the structure that is passed as an argument(optval) to + * getsockopt(SCTP_SOCKOPT_PEELOFF). + */ +typedef struct { + sctp_assoc_t associd; + int sd; +} sctp_peeloff_arg_t; + +/* + * Peer Address Thresholds socket option + */ +struct sctp_paddrthlds { + sctp_assoc_t spt_assoc_id; + struct sockaddr_storage spt_address; + __u16 spt_pathmaxrxt; + __u16 spt_pathpfthld; +}; + +/* + * Socket Option for Getting the Association/Stream-Specific PR-SCTP Status + */ +struct sctp_prstatus { + sctp_assoc_t sprstat_assoc_id; + __u16 sprstat_sid; + __u16 sprstat_policy; + __u64 sprstat_abandoned_unsent; + __u64 sprstat_abandoned_sent; +}; + +struct sctp_default_prinfo { + sctp_assoc_t pr_assoc_id; + __u32 pr_value; + __u16 pr_policy; +}; + +struct sctp_info { + __u32 sctpi_tag; + __u32 sctpi_state; + __u32 sctpi_rwnd; + __u16 sctpi_unackdata; + __u16 sctpi_penddata; + __u16 sctpi_instrms; + __u16 sctpi_outstrms; + __u32 sctpi_fragmentation_point; + __u32 sctpi_inqueue; + __u32 sctpi_outqueue; + __u32 sctpi_overall_error; + __u32 sctpi_max_burst; + __u32 sctpi_maxseg; + __u32 sctpi_peer_rwnd; + __u32 sctpi_peer_tag; + __u8 sctpi_peer_capable; + __u8 sctpi_peer_sack; + __u16 __reserved1; + + /* assoc status info */ + __u64 sctpi_isacks; + __u64 sctpi_osacks; + __u64 sctpi_opackets; + __u64 sctpi_ipackets; + __u64 sctpi_rtxchunks; + __u64 sctpi_outofseqtsns; + __u64 sctpi_idupchunks; + __u64 sctpi_gapcnt; + __u64 sctpi_ouodchunks; + __u64 sctpi_iuodchunks; + __u64 sctpi_oodchunks; + __u64 sctpi_iodchunks; + __u64 sctpi_octrlchunks; + __u64 sctpi_ictrlchunks; + + /* primary transport info */ + struct sockaddr_storage sctpi_p_address; + __s32 sctpi_p_state; + __u32 sctpi_p_cwnd; + __u32 sctpi_p_srtt; + __u32 sctpi_p_rto; + __u32 sctpi_p_hbinterval; + __u32 sctpi_p_pathmaxrxt; + __u32 sctpi_p_sackdelay; + __u32 sctpi_p_sackfreq; + __u32 sctpi_p_ssthresh; + __u32 sctpi_p_partial_bytes_acked; + __u32 sctpi_p_flight_size; + __u16 sctpi_p_error; + __u16 __reserved2; + + /* sctp sock info */ + __u32 sctpi_s_autoclose; + __u32 sctpi_s_adaptation_ind; + __u32 sctpi_s_pd_point; + __u8 sctpi_s_nodelay; + __u8 sctpi_s_disable_fragments; + __u8 sctpi_s_v4mapped; + __u8 sctpi_s_frag_interleave; + __u32 sctpi_s_type; + __u32 __reserved3; +}; + +#endif /* _SCTP_H */ From f89d46ad63f6f606f777da964205bc53b2197cfa Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 9 Nov 2016 12:12:24 +0100 Subject: [PATCH 05/36] ss: Add support for SCTP protocol This makes use of the sctp_diag interface recently added to the kernel. Joint work with Xin Long who provided the PoC implementation which I merely polished up a bit. Signed-off-by: Phil Sutter --- man/man8/ss.8 | 3 + misc/ss.c | 212 ++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 207 insertions(+), 8 deletions(-) diff --git a/man/man8/ss.8 b/man/man8/ss.8 index 8911976f..4ef11523 100644 --- a/man/man8/ss.8 +++ b/man/man8/ss.8 @@ -122,6 +122,9 @@ Display RAW sockets. .B \-x, \-\-unix Display Unix domain sockets (alias for -f unix). .TP +.B \-S, \-\-sctp +Display SCTP sockets. +.TP .B \-f FAMILY, \-\-family=FAMILY Display sockets of type FAMILY. Currently the following families are supported: unix, inet, inet6, link, netlink. diff --git a/misc/ss.c b/misc/ss.c index 0e28998f..a9654ee4 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -43,6 +43,7 @@ #include #include #include +#include #define MAGIC_SEQ 123456 @@ -102,6 +103,7 @@ int show_header = 1; /* If show_users & show_proc_ctx only do user_ent_hash_build() once */ int user_ent_hash_build_init; int follow_events; +int sctp_ino; int netid_width; int state_width; @@ -111,6 +113,7 @@ int serv_width; int screen_width; static const char *TCP_PROTO = "tcp"; +static const char *SCTP_PROTO = "sctp"; static const char *UDP_PROTO = "udp"; static const char *RAW_PROTO = "raw"; static const char *dg_proto; @@ -126,13 +129,14 @@ enum { PACKET_DG_DB, PACKET_R_DB, NETLINK_DB, + SCTP_DB, MAX_DB }; #define PACKET_DBM ((1<ino) + return false; + return true; +} + static void sock_state_print(struct sockstat *s, const char *sock_name) { if (netid_width) - printf("%-*s ", netid_width, sock_name); - if (state_width) - printf("%-*s ", state_width, sstate_name[s->state]); + printf("%-*s ", netid_width, + is_sctp_assoc(s, sock_name) ? "" : sock_name); + if (state_width) { + if (is_sctp_assoc(s, sock_name)) + printf("`- %-*s ", state_width - 3, + sctp_sstate_name[s->state]); + else + printf("%-*s ", state_width, sstate_name[s->state]); + } printf("%-6d %-6d ", s->rq, s->wq); } @@ -908,6 +957,8 @@ static void init_service_resolver(void) c->proto = TCP_PROTO; else if (strcmp(proto, UDP_PROTO) == 0) c->proto = UDP_PROTO; + else if (strcmp(proto, SCTP_PROTO) == 0) + c->proto = SCTP_PROTO; else c->proto = NULL; c->next = rlist; @@ -1679,6 +1730,8 @@ static char *proto_name(int protocol) return "udp"; case IPPROTO_TCP: return "tcp"; + case IPPROTO_SCTP: + return "sctp"; case IPPROTO_DCCP: return "dccp"; } @@ -1771,6 +1824,56 @@ static char *sprint_bw(char *buf, double bw) return buf; } +static void sctp_stats_print(struct sctp_info *s) +{ + if (s->sctpi_tag) + printf(" tag:%x", s->sctpi_tag); + if (s->sctpi_state) + printf(" state:%s", sctp_sstate_name[s->sctpi_state]); + if (s->sctpi_rwnd) + printf(" rwnd:%d", s->sctpi_rwnd); + if (s->sctpi_unackdata) + printf(" unackdata:%d", s->sctpi_unackdata); + if (s->sctpi_penddata) + printf(" penddata:%d", s->sctpi_penddata); + if (s->sctpi_instrms) + printf(" instrms:%d", s->sctpi_instrms); + if (s->sctpi_outstrms) + printf(" outstrms:%d", s->sctpi_outstrms); + if (s->sctpi_inqueue) + printf(" inqueue:%d", s->sctpi_inqueue); + if (s->sctpi_outqueue) + printf(" outqueue:%d", s->sctpi_outqueue); + if (s->sctpi_overall_error) + printf(" overerr:%d", s->sctpi_overall_error); + if (s->sctpi_max_burst) + printf(" maxburst:%d", s->sctpi_max_burst); + if (s->sctpi_maxseg) + printf(" maxseg:%d", s->sctpi_maxseg); + if (s->sctpi_peer_rwnd) + printf(" prwnd:%d", s->sctpi_peer_rwnd); + if (s->sctpi_peer_tag) + printf(" ptag:%x", s->sctpi_peer_tag); + if (s->sctpi_peer_capable) + printf(" pcapable:%d", s->sctpi_peer_capable); + if (s->sctpi_peer_sack) + printf(" psack:%d", s->sctpi_peer_sack); + if (s->sctpi_s_autoclose) + printf(" autoclose:%d", s->sctpi_s_autoclose); + if (s->sctpi_s_adaptation_ind) + printf(" adapind:%d", s->sctpi_s_adaptation_ind); + if (s->sctpi_s_pd_point) + printf(" pdpoint:%d", s->sctpi_s_pd_point); + if (s->sctpi_s_nodelay) + printf(" nodealy:%d", s->sctpi_s_nodelay); + if (s->sctpi_s_disable_fragments) + printf(" nofrag:%d", s->sctpi_s_disable_fragments); + if (s->sctpi_s_v4mapped) + printf(" v4mapped:%d", s->sctpi_s_v4mapped); + if (s->sctpi_s_frag_interleave) + printf(" fraginl:%d", s->sctpi_s_frag_interleave); +} + static void tcp_stats_print(struct tcpstat *s) { char b1[64]; @@ -1902,6 +2005,13 @@ static void tcp_timer_print(struct tcpstat *s) } } +static void sctp_timer_print(struct tcpstat *s) +{ + if (s->timer) + printf(" timer:(T3_RTX,%s,%d)", + print_ms_timer(s->timeout), s->retrans); +} + static int tcp_show_line(char *line, const struct filter *f, int family) { int rto = 0, ato = 0; @@ -2168,6 +2278,64 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r, } } +static const char *format_host_sa(struct sockaddr_storage *sa) +{ + union { + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } *saddr = (void *)sa; + + switch (sa->ss_family) { + case AF_INET: + return format_host(AF_INET, 4, &saddr->sin.sin_addr); + case AF_INET6: + return format_host(AF_INET6, 16, &saddr->sin6.sin6_addr); + default: + return ""; + } +} + +static void sctp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r, + struct rtattr *tb[]) +{ + struct sockaddr_storage *sa; + int len; + + print_skmeminfo(tb, INET_DIAG_SKMEMINFO); + + if (tb[INET_DIAG_LOCALS]) { + len = RTA_PAYLOAD(tb[INET_DIAG_LOCALS]); + sa = RTA_DATA(tb[INET_DIAG_LOCALS]); + + printf("locals:%s", format_host_sa(sa)); + for (sa++, len -= sizeof(*sa); len > 0; sa++, len -= sizeof(*sa)) + printf(",%s", format_host_sa(sa)); + + } + if (tb[INET_DIAG_PEERS]) { + len = RTA_PAYLOAD(tb[INET_DIAG_PEERS]); + sa = RTA_DATA(tb[INET_DIAG_PEERS]); + + printf(" peers:%s", format_host_sa(sa)); + for (sa++, len -= sizeof(*sa); len > 0; sa++, len -= sizeof(*sa)) + printf(",%s", format_host_sa(sa)); + } + if (tb[INET_DIAG_INFO]) { + struct sctp_info *info; + len = RTA_PAYLOAD(tb[INET_DIAG_INFO]); + + /* workaround for older kernels with less fields */ + if (len < sizeof(*info)) { + info = alloca(sizeof(*info)); + memcpy(info, RTA_DATA(tb[INET_DIAG_INFO]), len); + memset((char *)info + len, 0, sizeof(*info) - len); + } else + info = RTA_DATA(tb[INET_DIAG_INFO]); + + sctp_stats_print(info); + } +} + static void parse_diag_msg(struct nlmsghdr *nlh, struct sockstat *s) { struct rtattr *tb[INET_DIAG_MAX+1]; @@ -2221,7 +2389,10 @@ static int inet_show_sock(struct nlmsghdr *nlh, t.timer = r->idiag_timer; t.timeout = r->idiag_expires; t.retrans = r->idiag_retrans; - tcp_timer_print(&t); + if (protocol == IPPROTO_SCTP) + sctp_timer_print(&t); + else + tcp_timer_print(&t); } if (show_details) { @@ -2242,8 +2413,12 @@ static int inet_show_sock(struct nlmsghdr *nlh, if (show_mem || show_tcpinfo) { printf("\n\t"); - tcp_show_info(nlh, r, tb); + if (protocol == IPPROTO_SCTP) + sctp_show_info(nlh, r, tb); + else + tcp_show_info(nlh, r, tb); } + sctp_ino = s->ino; printf("\n"); return 0; @@ -2627,6 +2802,17 @@ outerr: } while (0); } +static int sctp_show(struct filter *f) +{ + if (!filter_af_get(f, AF_INET) && !filter_af_get(f, AF_INET6)) + return 0; + + if (!getenv("PROC_NET_SCTP") && !getenv("PROC_ROOT") + && inet_show_netlink(f, NULL, IPPROTO_SCTP) == 0) + return 0; + + return 0; +} static int dgram_show_line(char *line, const struct filter *f, int family) { @@ -3740,6 +3926,7 @@ static void _usage(FILE *dest) " -6, --ipv6 display only IP version 6 sockets\n" " -0, --packet display PACKET sockets\n" " -t, --tcp display only TCP sockets\n" +" -S, --sctp display only SCTP sockets\n" " -u, --udp display only UDP sockets\n" " -d, --dccp display only DCCP sockets\n" " -w, --raw display only RAW sockets\n" @@ -3822,6 +4009,7 @@ static const struct option long_opts[] = { { "events", 0, 0, 'E' }, { "dccp", 0, 0, 'd' }, { "tcp", 0, 0, 't' }, + { "sctp", 0, 0, 'S' }, { "udp", 0, 0, 'u' }, { "raw", 0, 0, 'w' }, { "unix", 0, 0, 'x' }, @@ -3857,7 +4045,7 @@ int main(int argc, char *argv[]) int ch; int state_filter = 0; - while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spbEf:miA:D:F:vVzZN:KH", + while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spbEf:miA:D:F:vVzZN:KHS", long_opts, NULL)) != EOF) { switch (ch) { case 'n': @@ -3896,6 +4084,9 @@ int main(int argc, char *argv[]) case 't': filter_db_set(¤t_filter, TCP_DB); break; + case 'S': + filter_db_set(¤t_filter, SCTP_DB); + break; case 'u': filter_db_set(¤t_filter, UDP_DB); break; @@ -3960,6 +4151,7 @@ int main(int argc, char *argv[]) filter_db_set(¤t_filter, UDP_DB); filter_db_set(¤t_filter, DCCP_DB); filter_db_set(¤t_filter, TCP_DB); + filter_db_set(¤t_filter, SCTP_DB); filter_db_set(¤t_filter, RAW_DB); } else if (strcmp(p, "udp") == 0) { filter_db_set(¤t_filter, UDP_DB); @@ -3967,6 +4159,8 @@ int main(int argc, char *argv[]) filter_db_set(¤t_filter, DCCP_DB); } else if (strcmp(p, "tcp") == 0) { filter_db_set(¤t_filter, TCP_DB); + } else if (strcmp(p, "sctp") == 0) { + filter_db_set(¤t_filter, SCTP_DB); } else if (strcmp(p, "raw") == 0) { filter_db_set(¤t_filter, RAW_DB); } else if (strcmp(p, "unix") == 0) { @@ -4091,7 +4285,7 @@ int main(int argc, char *argv[]) filter_merge_defaults(¤t_filter); if (resolve_services && resolve_hosts && - (current_filter.dbs&(UNIX_DBM|(1< Date: Sun, 13 Nov 2016 09:59:15 +0300 Subject: [PATCH 06/36] ss: break really long lines --- misc/ss.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/misc/ss.c b/misc/ss.c index a9654ee4..07dcd8c2 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -136,7 +136,8 @@ enum { #define PACKET_DBM ((1< Date: Tue, 8 Nov 2016 22:29:11 +0100 Subject: [PATCH 07/36] ipaddress: Simplify vf_info parsing Commit 7b8179c780a1a ("iproute2: Add new command to ip link to enable/disable VF spoof check") tried to add support for IFLA_VF_SPOOFCHK in a backwards-compatible manner, but aparently overdid it: parse_rtattr_nested() handles missing attributes perfectly fine in that it will leave the relevant field unassigned so calling code can just compare against NULL. There is no need to layback from the previous (IFLA_VF_TX_RATE) attribute to the next to check if IFLA_VF_SPOOFCHK is present or not. To the contrary, it establishes a potentially incorrect assumption of these two attributes directly following each other which may not be the case (although up to now, kernel aligns them this way). This patch cleans up the code to adhere to the common way of checking for attribute existence. It has been tested to return correct results regardless of whether the kernel exports IFLA_VF_SPOOFCHK or not. Signed-off-by: Phil Sutter Reviewed-by: Greg Rose --- ip/ipaddress.c | 44 ++++++++++---------------------------------- 1 file changed, 10 insertions(+), 34 deletions(-) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index 7f05258f..df0f1b9c 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -322,10 +322,7 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo) { struct ifla_vf_mac *vf_mac; struct ifla_vf_tx_rate *vf_tx_rate; - struct ifla_vf_spoofchk *vf_spoofchk; - struct ifla_vf_link_state *vf_linkstate; struct rtattr *vf[IFLA_VF_MAX + 1] = {}; - struct rtattr *tmp; SPRINT_BUF(b1); @@ -339,31 +336,6 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo) vf_mac = RTA_DATA(vf[IFLA_VF_MAC]); vf_tx_rate = RTA_DATA(vf[IFLA_VF_TX_RATE]); - /* Check if the spoof checking vf info type is supported by - * this kernel. - */ - tmp = (struct rtattr *)((char *)vf[IFLA_VF_TX_RATE] + - vf[IFLA_VF_TX_RATE]->rta_len); - - if (tmp->rta_type != IFLA_VF_SPOOFCHK) - vf_spoofchk = NULL; - else - vf_spoofchk = RTA_DATA(vf[IFLA_VF_SPOOFCHK]); - - if (vf_spoofchk) { - /* Check if the link state vf info type is supported by - * this kernel. - */ - tmp = (struct rtattr *)((char *)vf[IFLA_VF_SPOOFCHK] + - vf[IFLA_VF_SPOOFCHK]->rta_len); - - if (tmp->rta_type != IFLA_VF_LINK_STATE) - vf_linkstate = NULL; - else - vf_linkstate = RTA_DATA(vf[IFLA_VF_LINK_STATE]); - } else - vf_linkstate = NULL; - 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))); @@ -407,14 +379,18 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo) if (vf_rate->min_tx_rate) fprintf(fp, ", min_tx_rate %dMbps", vf_rate->min_tx_rate); } + if (vf[IFLA_VF_SPOOFCHK]) { + struct ifla_vf_spoofchk *vf_spoofchk = + RTA_DATA(vf[IFLA_VF_SPOOFCHK]); - if (vf_spoofchk && vf_spoofchk->setting != -1) { - if (vf_spoofchk->setting) - fprintf(fp, ", spoof checking on"); - else - fprintf(fp, ", spoof checking off"); + if (vf_spoofchk->setting != -1) + fprintf(fp, ", spoof checking %s", + vf_spoofchk->setting ? "on" : "off"); } - if (vf_linkstate) { + if (vf[IFLA_VF_LINK_STATE]) { + struct ifla_vf_link_state *vf_linkstate = + RTA_DATA(vf[IFLA_VF_LINK_STATE]); + if (vf_linkstate->link_state == IFLA_VF_LINK_STATE_AUTO) fprintf(fp, ", link-state auto"); else if (vf_linkstate->link_state == IFLA_VF_LINK_STATE_ENABLE) From 468fa020f17d1e4a91af799d8d031b7b904b39d7 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 14 Nov 2016 09:28:09 +0100 Subject: [PATCH 08/36] ip: style cleanup Make code more inline with current kernel style --- ip/ipaddress.c | 56 +++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index df0f1b9c..b9cd255f 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -148,11 +148,11 @@ static void print_operstate(FILE *f, __u8 state) fprintf(f, "state %#x ", state); } else if (brief) { color_fprintf(f, oper_state_color(state), - "%-14s ", oper_states[state]); + "%-14s ", oper_states[state]); } else { fprintf(f, "state "); color_fprintf(f, oper_state_color(state), - "%s ", oper_states[state]); + "%s ", oper_states[state]); } } @@ -385,7 +385,7 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo) if (vf_spoofchk->setting != -1) fprintf(fp, ", spoof checking %s", - vf_spoofchk->setting ? "on" : "off"); + vf_spoofchk->setting ? "on" : "off"); } if (vf[IFLA_VF_LINK_STATE]) { struct ifla_vf_link_state *vf_linkstate = @@ -403,7 +403,7 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo) if (vf_trust->setting != -1) fprintf(fp, ", trust %s", - vf_trust->setting ? "on" : "off"); + vf_trust->setting ? "on" : "off"); } if (vf[IFLA_VF_STATS] && show_stats) print_vf_stats64(fp, vf[IFLA_VF_STATS]); @@ -424,7 +424,8 @@ static void print_num(FILE *fp, unsigned int width, uint64_t count) } /* increase value by a factor of 1000/1024 and print - * if result is something a human can read */ + * if result is something a human can read + */ for (;;) { powi *= base; if (count / base < powi) @@ -667,9 +668,9 @@ int print_linkinfo_brief(const struct sockaddr_nl *who, return -1; parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); - if (tb[IFLA_IFNAME] == NULL) { + if (tb[IFLA_IFNAME] == NULL) fprintf(stderr, "BUG: device with ifindex %d has nil ifname\n", ifi->ifi_index); - } + if (filter.label && (!filter.family || filter.family == AF_PACKET) && fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0)) @@ -763,9 +764,9 @@ int print_linkinfo(const struct sockaddr_nl *who, return 0; parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); - if (tb[IFLA_IFNAME] == NULL) { + if (tb[IFLA_IFNAME] == NULL) fprintf(stderr, "BUG: device with ifindex %d has nil ifname\n", ifi->ifi_index); - } + if (filter.label && (!filter.family || filter.family == AF_PACKET) && fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0)) @@ -1094,16 +1095,16 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, if (rta_tb[IFA_LOCAL]) { color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s", - format_host_rta(ifa->ifa_family, - rta_tb[IFA_LOCAL])); + format_host_rta(ifa->ifa_family, + rta_tb[IFA_LOCAL])); if (rta_tb[IFA_ADDRESS] && memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), - RTA_DATA(rta_tb[IFA_LOCAL]), - ifa->ifa_family == AF_INET ? 4 : 16)) { + RTA_DATA(rta_tb[IFA_LOCAL]), + ifa->ifa_family == AF_INET ? 4 : 16)) { fprintf(fp, " peer "); color_fprintf(fp, ifa_family_color(ifa->ifa_family), - "%s", format_host_rta(ifa->ifa_family, - rta_tb[IFA_ADDRESS])); + "%s", format_host_rta(ifa->ifa_family, + rta_tb[IFA_ADDRESS])); } fprintf(fp, "/%d ", ifa->ifa_prefixlen); } @@ -1114,14 +1115,14 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, if (rta_tb[IFA_BROADCAST]) { fprintf(fp, "brd "); color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s ", - format_host_rta(ifa->ifa_family, - rta_tb[IFA_BROADCAST])); + format_host_rta(ifa->ifa_family, + rta_tb[IFA_BROADCAST])); } if (rta_tb[IFA_ANYCAST]) { fprintf(fp, "any "); color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s ", - format_host_rta(ifa->ifa_family, - rta_tb[IFA_ANYCAST])); + format_host_rta(ifa->ifa_family, + rta_tb[IFA_ANYCAST])); } fprintf(fp, "scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1, sizeof(b1))); if (ifa_flags & IFA_F_SECONDARY) { @@ -1160,9 +1161,9 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, ifa_flags &= ~IFA_F_MCAUTOJOIN; fprintf(fp, "autojoin "); } - if (!(ifa_flags & IFA_F_PERMANENT)) { + if (!(ifa_flags & IFA_F_PERMANENT)) fprintf(fp, "dynamic "); - } else + else ifa_flags &= ~IFA_F_PERMANENT; if (ifa_flags & IFA_F_DADFAILED) { ifa_flags &= ~IFA_F_DADFAILED; @@ -1648,9 +1649,9 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action) filter.kind = *argv; } } else { - if (strcmp(*argv, "dev") == 0) { + if (strcmp(*argv, "dev") == 0) NEXT_ARG(); - } else if (matches(*argv, "help") == 0) + else if (matches(*argv, "help") == 0) usage(); if (filter_dev) duparg2("dev", *argv); @@ -1955,9 +1956,8 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv) } else if (strcmp(*argv, "autojoin") == 0) { ifa_flags |= IFA_F_MCAUTOJOIN; } else { - if (strcmp(*argv, "local") == 0) { + if (strcmp(*argv, "local") == 0) NEXT_ARG(); - } if (matches(*argv, "help") == 0) usage(); if (local_len) @@ -1988,9 +1988,9 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv) if (peer_len == 0 && local_len) { if (cmd == RTM_DELADDR && lcl.family == AF_INET && !(lcl.flags & PREFIXLEN_SPECIFIED)) { fprintf(stderr, - "Warning: Executing wildcard deletion to stay compatible with old scripts.\n" \ - " Explicitly specify the prefix length (%s/%d) to avoid this warning.\n" \ - " This special behaviour is likely to disappear in further releases,\n" \ + "Warning: Executing wildcard deletion to stay compatible with old scripts.\n" + " Explicitly specify the prefix length (%s/%d) to avoid this warning.\n" + " This special behaviour is likely to disappear in further releases,\n" " fix your scripts!\n", lcl_arg, local_len*8); } else { peer = lcl; From 7bdcc0d942dcdde75a3e57fd9a58c9f7578716e2 Mon Sep 17 00:00:00 2001 From: Roman Mashak Date: Sun, 6 Nov 2016 21:27:38 -0500 Subject: [PATCH 09/36] tc: updated man page to reflect GET command to retrieve a single filter. Signed-off-by: Roman Mashak Signed-off-by: Jamal Hadi Salim --- man/man8/tc.8 | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/man/man8/tc.8 b/man/man8/tc.8 index 7ee1c9c9..8a47a2b9 100644 --- a/man/man8/tc.8 +++ b/man/man8/tc.8 @@ -28,7 +28,7 @@ class-id ] qdisc .B tc .RI "[ " OPTIONS " ]" -.B filter [ add | change | replace | delete ] dev +.B filter [ add | change | replace | delete | get ] dev DEV .B [ parent qdisc-id @@ -575,6 +575,14 @@ replace Performs a nearly atomic remove/add on an existing node id. If the node does not exist yet it is created. +.TP +get +Displays a single filter given the interface, parent ID, priority, protocol and handle ID. + +.TP +show +Displays all filters attached to the given interface. A valid parent ID must be passed. + .TP link Only available for qdiscs and performs a replace where the node From 4fb4a10e120b16c292c215791decccc47dc14604 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 14 Nov 2016 09:29:54 +0100 Subject: [PATCH 10/36] ipaddress: Print IFLA_VF_QUERY_RSS_EN setting Signed-off-by: Phil Sutter --- ip/ipaddress.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index b9cd255f..50897e6c 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -405,6 +405,22 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo) fprintf(fp, ", trust %s", vf_trust->setting ? "on" : "off"); } + if (vf[IFLA_VF_RSS_QUERY_EN]) { + struct ifla_vf_rss_query_en *rss_query = + RTA_DATA(vf[IFLA_VF_RSS_QUERY_EN]); + + if (rss_query->setting != -1) + fprintf(fp, ", query_rss %s", + rss_query->setting ? "on" : "off"); + } + if (vf[IFLA_VF_RSS_QUERY_EN]) { + struct ifla_vf_rss_query_en *rss_query = + RTA_DATA(vf[IFLA_VF_RSS_QUERY_EN]); + + if (rss_query->setting != -1) + fprintf(fp, ", query_rss %s", + rss_query->setting ? "on" : "off"); + } if (vf[IFLA_VF_STATS] && show_stats) print_vf_stats64(fp, vf[IFLA_VF_STATS]); } From 4b5451c4cde3f41cb9829ee53405393d8d91a555 Mon Sep 17 00:00:00 2001 From: Roman Mashak Date: Thu, 10 Nov 2016 11:02:57 -0500 Subject: [PATCH 11/36] tc: improved usage help for fw classifier. Signed-off-by: Roman Mashak Signed-off-by: Jamal Hadi Salim --- tc/f_fw.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/tc/f_fw.c b/tc/f_fw.c index 29c98549..790bef96 100644 --- a/tc/f_fw.c +++ b/tc/f_fw.c @@ -25,10 +25,19 @@ static void explain(void) { - fprintf(stderr, "Usage: ... fw [ classid CLASSID ] [ action ACTION_SPEC ]\n"); - fprintf(stderr, " ACTION_SPEC := ... look at individual actions\n"); - fprintf(stderr, " CLASSID := X:Y\n"); - fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n"); + fprintf(stderr, + "Usage: ... fw [ classid CLASSID ] [ indev DEV ] [ action ACTION_SPEC ]\n"); + fprintf(stderr, + " CLASSID := Push matching packets to the class identified by CLASSID with format X:Y\n"); + fprintf(stderr, + " CLASSID is parsed as hexadecimal input.\n"); + fprintf(stderr, + " DEV := specify device for incoming device classification.\n"); + fprintf(stderr, + " ACTION_SPEC := Apply an action on matching packets.\n"); + fprintf(stderr, + " NOTE: handle is represented as HANDLE[/FWMASK].\n"); + fprintf(stderr, " FWMASK is 0xffffffff by default.\n"); } static int fw_parse_opt(struct filter_util *qu, char *handle, int argc, char **argv, struct nlmsghdr *n) From d42e1444f2c0f48df0f1a188dcbe677d1a134710 Mon Sep 17 00:00:00 2001 From: Roman Mashak Date: Mon, 14 Nov 2016 17:59:20 -0500 Subject: [PATCH 12/36] tc: print raw qdisc handle. This is v2 patch with fixed code indentation. Signed-off-by: Roman Mashak Signed-off-by: Jamal Hadi Salim --- tc/tc_qdisc.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tc/tc_qdisc.c b/tc/tc_qdisc.c index 93c9a4c1..51320bd4 100644 --- a/tc/tc_qdisc.c +++ b/tc/tc_qdisc.c @@ -231,7 +231,14 @@ int print_qdisc(const struct sockaddr_nl *who, if (n->nlmsg_type == RTM_DELQDISC) fprintf(fp, "deleted "); - fprintf(fp, "qdisc %s %x: ", rta_getattr_str(tb[TCA_KIND]), t->tcm_handle>>16); + if (show_raw) + fprintf(fp, "qdisc %s %x:[%08x] ", + rta_getattr_str(tb[TCA_KIND]), + t->tcm_handle >> 16, t->tcm_handle); + else + fprintf(fp, "qdisc %s %x: ", rta_getattr_str(tb[TCA_KIND]), + t->tcm_handle >> 16); + if (filter_ifindex == 0) fprintf(fp, "dev %s ", ll_index_to_name(t->tcm_ifindex)); if (t->tcm_parent == TC_H_ROOT) From b932e6f3727598380dbff9d6941b379c058f23aa Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 15 Nov 2016 10:29:09 -0800 Subject: [PATCH 13/36] tc: cleanup style of qdisc code Get rid of lingering mismatches with kernel style. --- tc/tc_qdisc.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/tc/tc_qdisc.c b/tc/tc_qdisc.c index 51320bd4..3a3701c2 100644 --- a/tc/tc_qdisc.c +++ b/tc/tc_qdisc.c @@ -182,7 +182,8 @@ static int tc_qdisc_modify(int cmd, unsigned int flags, int argc, char **argv) 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); return 1; } @@ -198,8 +199,7 @@ static int tc_qdisc_modify(int cmd, unsigned int flags, int argc, char **argv) static int filter_ifindex; int print_qdisc(const struct sockaddr_nl *who, - struct nlmsghdr *n, - void *arg) + struct nlmsghdr *n, void *arg) { FILE *fp = (FILE *)arg; struct tcmsg *t = NLMSG_DATA(n); @@ -241,18 +241,19 @@ int print_qdisc(const struct sockaddr_nl *who, if (filter_ifindex == 0) fprintf(fp, "dev %s ", ll_index_to_name(t->tcm_ifindex)); + if (t->tcm_parent == TC_H_ROOT) fprintf(fp, "root "); else if (t->tcm_parent) { print_tc_classid(abuf, sizeof(abuf), t->tcm_parent); fprintf(fp, "parent %s ", abuf); } - if (t->tcm_info != 1) { - fprintf(fp, "refcnt %d ", t->tcm_info); - } - /* pfifo_fast is generic enough to warrant the hardcoding --JHS */ - if (0 == strcmp("pfifo_fast", RTA_DATA(tb[TCA_KIND]))) + if (t->tcm_info != 1) + fprintf(fp, "refcnt %d ", t->tcm_info); + + /* pfifo_fast is generic enough to warrant the hardcoding --JHS */ + if (strcmp("pfifo_fast", RTA_DATA(tb[TCA_KIND])) == 0) q = get_qdisc_kind("prio"); else q = get_qdisc_kind(RTA_DATA(tb[TCA_KIND])); @@ -264,10 +265,12 @@ int print_qdisc(const struct sockaddr_nl *who, fprintf(fp, "[cannot parse qdisc parameters]"); } fprintf(fp, "\n"); + if (show_details && tb[TCA_STAB]) { print_size_table(fp, " ", tb[TCA_STAB]); fprintf(fp, "\n"); } + if (show_stats) { struct rtattr *xstats = NULL; @@ -296,11 +299,11 @@ static int tc_qdisc_list(int argc, char **argv) strncpy(d, *argv, sizeof(d)-1); } else if (strcmp(*argv, "ingress") == 0 || strcmp(*argv, "clsact") == 0) { - if (t.tcm_parent) { - fprintf(stderr, "Duplicate parent ID\n"); - usage(); - } - t.tcm_parent = TC_H_INGRESS; + if (t.tcm_parent) { + fprintf(stderr, "Duplicate parent ID\n"); + usage(); + } + t.tcm_parent = TC_H_INGRESS; } else if (matches(*argv, "help") == 0) { usage(); } else { @@ -314,7 +317,8 @@ static int tc_qdisc_list(int argc, char **argv) ll_init_map(&rth); if (d[0]) { - if ((t.tcm_ifindex = ll_name_to_index(d)) == 0) { + t.tcm_ifindex = ll_name_to_index(d); + if (t.tcm_ifindex == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", d); return 1; } From 6e2e71e16ec53b5fa1d229588fe03ffe6e93902e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 29 Nov 2016 11:36:47 -0800 Subject: [PATCH 14/36] update headers based on 4.9-rc7 --- include/linux/rtnetlink.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 2d2e3e6c..45aedafc 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -350,7 +350,7 @@ struct rtnexthop { #define RTNH_F_OFFLOAD 8 /* offloaded route */ #define RTNH_F_LINKDOWN 16 /* carrier-down on nexthop */ -#define RTNH_COMPARE_MASK (RTNH_F_DEAD | RTNH_F_LINKDOWN) +#define RTNH_COMPARE_MASK (RTNH_F_DEAD | RTNH_F_LINKDOWN | RTNH_F_OFFLOAD) /* Macros to handle hexthops */ From aa1b44ca773d10067f64594032cd2bf810892e03 Mon Sep 17 00:00:00 2001 From: "michael-dev@fami-braun.de" Date: Tue, 22 Nov 2016 11:59:13 +0100 Subject: [PATCH 15/36] iproute2: macvlan: add "source" mode Adjusting iproute2 utility to support new macvlan link type mode called "source". Example of commands that can be applied: ip link add link eth0 name macvlan0 type macvlan mode source ip link set link dev macvlan0 type macvlan macaddr add 00:11:11:11:11:11 ip link set link dev macvlan0 type macvlan macaddr del 00:11:11:11:11:11 ip link set link dev macvlan0 type macvlan macaddr flush ip -details link show dev macvlan0 Based on previous work of Stefan Gula Signed-off-by: Michael Braun Cc: steweg@gmail.com v5: - rebase and fix checkpatch v4: - add MACADDR_SET support - skip FLAG_UNICAST / FLAG_UNICAST_ALL as this is not upstream - fix man page --- ip/iplink_macvlan.c | 124 ++++++++++++++++++++++++++++++++++++++++-- man/man8/ip-link.8.in | 42 +++++++++++++- 2 files changed, 158 insertions(+), 8 deletions(-) diff --git a/ip/iplink_macvlan.c b/ip/iplink_macvlan.c index 83ff961b..b9a146f2 100644 --- a/ip/iplink_macvlan.c +++ b/ip/iplink_macvlan.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "rt_names.h" #include "utils.h" @@ -29,7 +30,11 @@ static void print_explain(struct link_util *lu, FILE *f) { fprintf(f, - "Usage: ... %s mode { private | vepa | bridge | passthru [nopromisc] }\n", + "Usage: ... %s mode MODE [flag MODE_FLAG] MODE_OPTS\n" + "MODE: private | vepa | bridge | passthru | source\n" + "MODE_FLAG: null | nopromisc\n" + "MODE_OPTS: for mode \"source\":\n" + "\tmacaddr { { add | del } | set [ [ ... ] ] | flush }\n", lu->id ); } @@ -43,7 +48,15 @@ static void explain(struct link_util *lu) static int mode_arg(const char *arg) { fprintf(stderr, - "Error: argument of \"mode\" must be \"private\", \"vepa\", \"bridge\" or \"passthru\", not \"%s\"\n", + "Error: argument of \"mode\" must be \"private\", \"vepa\", \"bridge\", \"passthru\" or \"source\", not \"%s\"\n", + arg); + return -1; +} + +static int flag_arg(const char *arg) +{ + fprintf(stderr, + "Error: argument of \"flag\" must be \"nopromisc\" or \"null\", not \"%s\"\n", arg); return -1; } @@ -53,6 +66,10 @@ static int macvlan_parse_opt(struct link_util *lu, int argc, char **argv, { __u32 mode = 0; __u16 flags = 0; + __u32 mac_mode = 0; + int has_flags = 0; + char mac[ETH_ALEN]; + struct rtattr *nmac; while (argc > 0) { if (matches(*argv, "mode") == 0) { @@ -66,10 +83,72 @@ static int macvlan_parse_opt(struct link_util *lu, int argc, char **argv, mode = MACVLAN_MODE_BRIDGE; else if (strcmp(*argv, "passthru") == 0) mode = MACVLAN_MODE_PASSTHRU; + else if (strcmp(*argv, "source") == 0) + mode = MACVLAN_MODE_SOURCE; else return mode_arg(*argv); + } else if (matches(*argv, "flag") == 0) { + NEXT_ARG(); + + if (strcmp(*argv, "nopromisc") == 0) + flags |= MACVLAN_FLAG_NOPROMISC; + else if (strcmp(*argv, "null") == 0) + flags |= 0; + else + return flag_arg(*argv); + + has_flags = 1; + + } else if (matches(*argv, "macaddr") == 0) { + NEXT_ARG(); + + if (strcmp(*argv, "add") == 0) { + mac_mode = MACVLAN_MACADDR_ADD; + } else if (strcmp(*argv, "del") == 0) { + mac_mode = MACVLAN_MACADDR_DEL; + } else if (strcmp(*argv, "set") == 0) { + mac_mode = MACVLAN_MACADDR_SET; + } else if (strcmp(*argv, "flush") == 0) { + mac_mode = MACVLAN_MACADDR_FLUSH; + } else { + explain(lu); + return -1; + } + + addattr32(n, 1024, IFLA_MACVLAN_MACADDR_MODE, mac_mode); + + if (mac_mode == MACVLAN_MACADDR_ADD || + mac_mode == MACVLAN_MACADDR_DEL) { + NEXT_ARG(); + + if (ll_addr_a2n(mac, sizeof(mac), + *argv) != ETH_ALEN) + return -1; + + addattr_l(n, 1024, IFLA_MACVLAN_MACADDR, &mac, + ETH_ALEN); + } + + if (mac_mode == MACVLAN_MACADDR_SET) { + nmac = addattr_nest(n, 1024, + IFLA_MACVLAN_MACADDR_DATA); + while (NEXT_ARG_OK()) { + NEXT_ARG_FWD(); + + if (ll_addr_a2n(mac, sizeof(mac), + *argv) != ETH_ALEN) { + PREV_ARG(); + break; + } + + addattr_l(n, 1024, IFLA_MACVLAN_MACADDR, + &mac, ETH_ALEN); + } + addattr_nest_end(n, nmac); + } } else if (matches(*argv, "nopromisc") == 0) { flags |= MACVLAN_FLAG_NOPROMISC; + has_flags = 1; } else if (matches(*argv, "help") == 0) { explain(lu); return -1; @@ -84,7 +163,7 @@ static int macvlan_parse_opt(struct link_util *lu, int argc, char **argv, if (mode) addattr32(n, 1024, IFLA_MACVLAN_MODE, mode); - if (flags) { + if (has_flags) { if (flags & MACVLAN_FLAG_NOPROMISC && mode != MACVLAN_MODE_PASSTHRU) { pfx_err(lu, "nopromisc flag only valid in passthru mode"); @@ -100,6 +179,10 @@ static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[] { __u32 mode; __u16 flags; + __u32 count; + unsigned char *addr; + int len; + struct rtattr *rta; if (!tb) return; @@ -109,20 +192,49 @@ static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[] return; mode = rta_getattr_u32(tb[IFLA_MACVLAN_MODE]); - fprintf(f, " mode %s ", + fprintf(f, "mode %s ", mode == MACVLAN_MODE_PRIVATE ? "private" : mode == MACVLAN_MODE_VEPA ? "vepa" : mode == MACVLAN_MODE_BRIDGE ? "bridge" : mode == MACVLAN_MODE_PASSTHRU ? "passthru" + : mode == MACVLAN_MODE_SOURCE ? "source" : "unknown"); if (!tb[IFLA_MACVLAN_FLAGS] || RTA_PAYLOAD(tb[IFLA_MACVLAN_FLAGS]) < sizeof(__u16)) - return; + flags = 0; + else + flags = rta_getattr_u16(tb[IFLA_MACVLAN_FLAGS]); - flags = rta_getattr_u16(tb[IFLA_MACVLAN_FLAGS]); if (flags & MACVLAN_FLAG_NOPROMISC) fprintf(f, "nopromisc "); + + /* in source mode, there are more options to print */ + + if (mode != MACVLAN_MODE_SOURCE) + return; + + if (!tb[IFLA_MACVLAN_MACADDR_COUNT] || + RTA_PAYLOAD(tb[IFLA_MACVLAN_MACADDR_COUNT]) < sizeof(__u32)) + return; + + count = rta_getattr_u32(tb[IFLA_MACVLAN_MACADDR_COUNT]); + fprintf(f, "remotes (%d) ", count); + + if (!tb[IFLA_MACVLAN_MACADDR_DATA]) + return; + + rta = RTA_DATA(tb[IFLA_MACVLAN_MACADDR_DATA]); + len = RTA_PAYLOAD(tb[IFLA_MACVLAN_MACADDR_DATA]); + + for (; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { + if (rta->rta_type != IFLA_MACVLAN_MACADDR || + RTA_PAYLOAD(rta) < 6) + continue; + addr = RTA_DATA(rta); + fprintf(f, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x ", addr[0], + addr[1], addr[2], addr[3], addr[4], addr[5]); + } } static void macvlan_print_help(struct link_util *lu, int argc, char **argv, diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index ee1159da..18e94171 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -135,7 +135,12 @@ ip-link \- network device configuration .IR NAME " ]" .br .RB "[ " addrgenmode " { " eui64 " | " none " | " stable_secret " | " random " } ]" - +.br +.RB "[ " macaddr " { " flush " | { " add " | " del " } " +.IR MACADDR " | set [ " +.IR MACADDR " [ " +.IR MACADDR " [ ... ] ] ] } ]" +.br .ti -8 .B ip link show @@ -882,7 +887,7 @@ the following additional arguments are supported: .BI "ip link add link " DEVICE " name " NAME .BR type " { " macvlan " | " macvtap " } " .BR mode " { " private " | " vepa " | " bridge " | " passthru -.RB " [ " nopromisc " ] } " +.RB " [ " nopromisc " ] | " source " } " .in +8 .sp @@ -919,6 +924,13 @@ the interface or create vlan interfaces on top of it. By default, this mode forces the underlying interface into promiscuous mode. Passing the .BR nopromisc " flag prevents this, so the promisc flag may be controlled " using standard tools. + +.B mode source +- allows one to set a list of allowed mac address, which is used to match +against source mac address from received frames on underlying interface. This +allows creating mac based VLAN associations, instead of standard port or tag +based. The feature is useful to deploy 802.1x mac based behavior, +where drivers of underlying interfaces doesn't allows that. .in -8 .TP @@ -1468,6 +1480,32 @@ the following additional arguments are supported: .in -8 +.TP +MACVLAN and MACVTAP Support +Modify list of allowed macaddr for link in source mode. + +.B "ip link set type { macvlan | macvap } " +[ +.BI macaddr " " "" COMMAND " " MACADDR " ..." +] + +Commands: +.in +8 +.B add +- add MACADDR to allowed list +.sp +.B set +- replace allowed list +.sp +.B del +- remove MACADDR from allowed list +.sp +.B flush +- flush whole allowed list +.sp +.in -8 + + .SS ip link show - display device attributes .TP From 8be295581630b01a2b8ec718ccde2d158fcff4c8 Mon Sep 17 00:00:00 2001 From: david decotigny Date: Fri, 11 Nov 2016 10:55:36 -0800 Subject: [PATCH 16/36] iproute2: avoid exit in case of error. Be consistent with how non-0 print_route() return values are handled elesewhere: return -1. --- ip/iproute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ip/iproute.c b/ip/iproute.c index 98bfad6c..dae793b7 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -1743,7 +1743,7 @@ static int iproute_get(int argc, char **argv) if (print_route(NULL, &req.n, (void *)stdout) < 0) { fprintf(stderr, "An error :-)\n"); - exit(1); + return -1; } if (req.n.nlmsg_type != RTM_NEWROUTE) { From ba7b97776e3a2e019de8d840f9714db89da60a94 Mon Sep 17 00:00:00 2001 From: david decotigny Date: Fri, 11 Nov 2016 10:55:37 -0800 Subject: [PATCH 17/36] iproute2: a non-expected rtnl message is an error --- ip/iproute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ip/iproute.c b/ip/iproute.c index dae793b7..10d0afe7 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -320,7 +320,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) { fprintf(stderr, "Not a route: %08x %08x %08x\n", n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); - return 0; + return -1; } if (filter.flushb && n->nlmsg_type != RTM_NEWROUTE) return 0; From 2d98dd482149aa1a2bf509122af089249644a89f Mon Sep 17 00:00:00 2001 From: Zhang Shengju Date: Fri, 18 Nov 2016 09:12:53 +0800 Subject: [PATCH 18/36] iproute2: fix the link group name getting error In the situation where more than one entry live in the same hash bucket, loop to get the correct one. Before: $ cat /etc/iproute2/group 0 default 256 test $ sudo ip link set group test dummy1 $ ip link show type dummy 11: dummy0: mtu 1500 qdisc noop state DOWN mode DEFAULT group 0 qlen 1000 link/ether 4e:3b:d3:6c:f0:e6 brd ff:ff:ff:ff:ff:ff 12: dummy1: mtu 1500 qdisc noop state DOWN mode DEFAULT group test qlen 1000 link/ether d6:9c:a4:1f:e7:e5 brd ff:ff:ff:ff:ff:ff After: $ ip link show type dummy 11: dummy0: mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 4e:3b:d3:6c:f0:e6 brd ff:ff:ff:ff:ff:ff 12: dummy1: mtu 1500 qdisc noop state DOWN mode DEFAULT group test qlen 1000 link/ether d6:9c:a4:1f:e7:e5 brd ff:ff:ff:ff:ff:ff Signed-off-by: Zhang Shengju --- lib/rt_names.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/rt_names.c b/lib/rt_names.c index b665d3e9..c66cb1e4 100644 --- a/lib/rt_names.c +++ b/lib/rt_names.c @@ -559,8 +559,12 @@ const char *rtnl_group_n2a(int id, char *buf, int len) for (i = 0; i < 256; i++) { entry = rtnl_group_hash[i]; - if (entry && entry->id == id) - return entry->name; + + while (entry) { + if (entry->id == id) + return entry->name; + entry = entry->next; + } } snprintf(buf, len, "%d", id); From 1b109a30bf711833da0f674e46da8aaafa6a9e4f Mon Sep 17 00:00:00 2001 From: Zhang Shengju Date: Sat, 19 Nov 2016 23:50:13 +0800 Subject: [PATCH 19/36] libnetlink: reduce size of message sent to kernel Fixes commit 246f57c4086d99fa ("ip link: Add support for kernel side filtering"). This patch reduce the size of message sent to kernel space. Before this patch, for command: 'ip link show', we will sent 1056 bytes. With this patch, we only need to send 40 bytes. Signed-off-by: Zhang Shengju --- lib/libnetlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/libnetlink.c b/lib/libnetlink.c index 22799355..7f2a0d44 100644 --- a/lib/libnetlink.c +++ b/lib/libnetlink.c @@ -149,7 +149,7 @@ int rtnl_wilddump_req_filter_fn(struct rtnl_handle *rth, int family, int type, if (err) return err; - return send(rth->fd, (void*)&req, sizeof(req), 0); + return send(rth->fd, &req, req.nlh.nlmsg_len, 0); } int rtnl_wilddump_stats_req_filter(struct rtnl_handle *rth, int fam, int type, From 2c500a4dc25047e3737ea6e9cc0afc5f12089626 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 29 Nov 2016 13:15:08 -0800 Subject: [PATCH 20/36] libnetlink: style cleanups Follow kernel style related cleanups: * break long lines * remove unnecessary void * cast --- lib/libnetlink.c | 119 +++++++++++++++++++++++++++++------------------ 1 file changed, 75 insertions(+), 44 deletions(-) diff --git a/lib/libnetlink.c b/lib/libnetlink.c index 7f2a0d44..21a76363 100644 --- a/lib/libnetlink.c +++ b/lib/libnetlink.c @@ -43,7 +43,7 @@ void rtnl_close(struct rtnl_handle *rth) } } -int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions, +int rtnl_open_byproto(struct rtnl_handle *rth, unsigned int subscriptions, int protocol) { socklen_t addr_len; @@ -58,12 +58,14 @@ int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions, return -1; } - if (setsockopt(rth->fd,SOL_SOCKET,SO_SNDBUF,&sndbuf,sizeof(sndbuf)) < 0) { + if (setsockopt(rth->fd, SOL_SOCKET, SO_SNDBUF, + &sndbuf, sizeof(sndbuf)) < 0) { perror("SO_SNDBUF"); return -1; } - if (setsockopt(rth->fd,SOL_SOCKET,SO_RCVBUF,&rcvbuf,sizeof(rcvbuf)) < 0) { + if (setsockopt(rth->fd, SOL_SOCKET, SO_RCVBUF, + &rcvbuf, sizeof(rcvbuf)) < 0) { perror("SO_RCVBUF"); return -1; } @@ -72,12 +74,14 @@ int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions, rth->local.nl_family = AF_NETLINK; rth->local.nl_groups = subscriptions; - if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) { + if (bind(rth->fd, (struct sockaddr *)&rth->local, + sizeof(rth->local)) < 0) { perror("Cannot bind netlink socket"); return -1; } addr_len = sizeof(rth->local); - if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) { + if (getsockname(rth->fd, (struct sockaddr *)&rth->local, + &addr_len) < 0) { perror("Cannot getsockname"); return -1; } @@ -86,14 +90,15 @@ int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions, return -1; } if (rth->local.nl_family != AF_NETLINK) { - fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family); + fprintf(stderr, "Wrong address family %d\n", + rth->local.nl_family); return -1; } rth->seq = time(NULL); return 0; } -int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions) +int rtnl_open(struct rtnl_handle *rth, unsigned int subscriptions) { return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE); } @@ -123,7 +128,7 @@ int rtnl_wilddump_req_filter(struct rtnl_handle *rth, int family, int type, .ext_filter_mask = filt_mask, }; - return send(rth->fd, (void*)&req, sizeof(req), 0); + return send(rth->fd, &req, sizeof(req), 0); } int rtnl_wilddump_req_filter_fn(struct rtnl_handle *rth, int family, int type, @@ -169,7 +174,7 @@ int rtnl_wilddump_stats_req_filter(struct rtnl_handle *rth, int fam, int type, req.ifsm.family = fam; req.ifsm.filter_mask = filt_mask; - return send(rth->fd, (void *)&req, sizeof(req), 0); + return send(rth->fd, &req, sizeof(req), 0); } int rtnl_send(struct rtnl_handle *rth, const void *buf, int len) @@ -198,7 +203,8 @@ int rtnl_send_check(struct rtnl_handle *rth, const void *buf, int len) for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, status); h = NLMSG_NEXT(h, status)) { if (h->nlmsg_type == NLMSG_ERROR) { - struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); + struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h); + if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) fprintf(stderr, "ERROR truncated\n"); else @@ -237,7 +243,7 @@ int rtnl_dump_request_n(struct rtnl_handle *rth, struct nlmsghdr *n) { struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; struct iovec iov = { - .iov_base = (void*) n, + .iov_base = n, .iov_len = n->nlmsg_len }; struct msghdr msg = { @@ -295,7 +301,8 @@ int rtnl_dump_filter_l(struct rtnl_handle *rth, fwrite(buf, 1, NLMSG_ALIGN(status), rth->dump_fp); for (a = arg; a->filter; a++) { - struct nlmsghdr *h = (struct nlmsghdr*)buf; + struct nlmsghdr *h = (struct nlmsghdr *)buf; + msglen = status; while (NLMSG_OK(h, msglen)) { @@ -316,7 +323,8 @@ int rtnl_dump_filter_l(struct rtnl_handle *rth, break; /* process next filter */ } if (h->nlmsg_type == NLMSG_ERROR) { - struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); + struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h); + if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { fprintf(stderr, "ERROR truncated\n"); @@ -377,11 +385,11 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, struct nlmsghdr *answer, size_t maxlen) { int status; - unsigned seq; + unsigned int seq; struct nlmsghdr *h; struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; struct iovec iov = { - .iov_base = (void*) n, + .iov_base = n, .iov_len = n->nlmsg_len }; struct msghdr msg = { @@ -420,19 +428,23 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, return -1; } if (msg.msg_namelen != sizeof(nladdr)) { - fprintf(stderr, "sender address length == %d\n", msg.msg_namelen); + fprintf(stderr, + "sender address length == %d\n", + msg.msg_namelen); exit(1); } - for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) { + for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) { int len = h->nlmsg_len; int l = len - sizeof(*h); - if (l < 0 || len>status) { + if (l < 0 || len > status) { if (msg.msg_flags & MSG_TRUNC) { fprintf(stderr, "Truncated message\n"); return -1; } - fprintf(stderr, "!!!malformed message: len=%d\n", len); + fprintf(stderr, + "!!!malformed message: len=%d\n", + len); exit(1); } @@ -441,12 +453,13 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, h->nlmsg_seq != seq) { /* Don't forget to skip that message. */ status -= NLMSG_ALIGN(len); - h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); + h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len)); continue; } if (h->nlmsg_type == NLMSG_ERROR) { - struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); + struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h); + if (l < sizeof(struct nlmsgerr)) { fprintf(stderr, "ERROR truncated\n"); } else if (!err->error) { @@ -473,7 +486,7 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, fprintf(stderr, "Unexpected reply!!!\n"); status -= NLMSG_ALIGN(len); - h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); + h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len)); } if (msg.msg_flags & MSG_TRUNC) { @@ -545,7 +558,9 @@ int rtnl_listen(struct rtnl_handle *rtnl, return -1; } if (msg.msg_namelen != sizeof(nladdr)) { - fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen); + fprintf(stderr, + "Sender address length == %d\n", + msg.msg_namelen); exit(1); } @@ -563,17 +578,19 @@ int rtnl_listen(struct rtnl_handle *rtnl, } } - for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) { + for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) { int err; int len = h->nlmsg_len; int l = len - sizeof(*h); - if (l<0 || len>status) { + if (l < 0 || len > status) { if (msg.msg_flags & MSG_TRUNC) { fprintf(stderr, "Truncated message\n"); return -1; } - fprintf(stderr, "!!!malformed message: len=%d\n", len); + fprintf(stderr, + "!!!malformed message: len=%d\n", + len); exit(1); } @@ -582,7 +599,7 @@ int rtnl_listen(struct rtnl_handle *rtnl, return err; status -= NLMSG_ALIGN(len); - h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); + h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len)); } if (msg.msg_flags & MSG_TRUNC) { fprintf(stderr, "Message truncated\n"); @@ -600,8 +617,8 @@ int rtnl_from_file(FILE *rtnl, rtnl_listen_filter_t handler, { int status; struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; - char buf[16384]; - struct nlmsghdr *h = (void*)buf; + char buf[16384]; + struct nlmsghdr *h = (struct nlmsghdr *)buf; while (1) { int err, len; @@ -621,7 +638,7 @@ int rtnl_from_file(FILE *rtnl, rtnl_listen_filter_t handler, len = h->nlmsg_len; l = len - sizeof(*h); - if (l<0 || len>sizeof(buf)) { + if (l < 0 || len > sizeof(buf)) { fprintf(stderr, "!!!malformed message: len=%d @%lu\n", len, ftell(rtnl)); return -1; @@ -681,7 +698,9 @@ int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, struct rtattr *rta; if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) { - fprintf(stderr, "addattr_l ERROR: message exceeded bound of %d\n",maxlen); + fprintf(stderr, + "addattr_l ERROR: message exceeded bound of %d\n", + maxlen); return -1; } rta = NLMSG_TAIL(n); @@ -695,7 +714,9 @@ int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len) { if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) { - fprintf(stderr, "addraw_l ERROR: message exceeded bound of %d\n",maxlen); + fprintf(stderr, + "addraw_l ERROR: message exceeded bound of %d\n", + maxlen); return -1; } @@ -744,10 +765,12 @@ int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data) struct rtattr *subrta; if (RTA_ALIGN(rta->rta_len) + len > maxlen) { - fprintf(stderr,"rta_addattr32: Error! max allowed bound %d exceeded\n",maxlen); + fprintf(stderr, + "rta_addattr32: Error! max allowed bound %d exceeded\n", + maxlen); return -1; } - subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); + subrta = (struct rtattr *)(((char *)rta) + RTA_ALIGN(rta->rta_len)); subrta->rta_type = type; subrta->rta_len = len; memcpy(RTA_DATA(subrta), &data, 4); @@ -762,10 +785,12 @@ int rta_addattr_l(struct rtattr *rta, int maxlen, int type, int len = RTA_LENGTH(alen); if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) { - fprintf(stderr,"rta_addattr_l: Error! max allowed bound %d exceeded\n",maxlen); + fprintf(stderr, + "rta_addattr_l: Error! max allowed bound %d exceeded\n", + maxlen); return -1; } - subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); + subrta = (struct rtattr *)(((char *)rta) + RTA_ALIGN(rta->rta_len)); subrta->rta_type = type; subrta->rta_len = len; memcpy(RTA_DATA(subrta), data, alen); @@ -819,14 +844,16 @@ int parse_rtattr_flags(struct rtattr *tb[], int max, struct rtattr *rta, type = rta->rta_type & ~flags; if ((type <= max) && (!tb[type])) tb[type] = rta; - rta = RTA_NEXT(rta,len); + rta = RTA_NEXT(rta, len); } if (len) - fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len); + fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", + len, rta->rta_len); return 0; } -int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len) +int parse_rtattr_byindex(struct rtattr *tb[], int max, + struct rtattr *rta, int len) { int i = 0; @@ -834,10 +861,11 @@ int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int l while (RTA_OK(rta, len)) { if (rta->rta_type <= max && i < max) tb[i++] = rta; - rta = RTA_NEXT(rta,len); + rta = RTA_NEXT(rta, len); } if (len) - fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len); + fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", + len, rta->rta_len); return i; } @@ -848,13 +876,16 @@ struct rtattr *parse_rtattr_one(int type, struct rtattr *rta, int len) return rta; rta = RTA_NEXT(rta, len); } + if (len) - fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len); + fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", + len, rta->rta_len); return NULL; } -int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta, - int len) +int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, + struct rtattr *rta, + int len) { if (RTA_PAYLOAD(rta) < len) return -1; From eca7a7421963a7f254282e13e505be9ebeaf9c9a Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 15 Nov 2016 22:34:14 -0500 Subject: [PATCH 21/36] ifstat/nstat: fix help output alignment Some lines use tabs while others use spaces. Use spaces everywhere. Signed-off-by: Mike Frysinger --- misc/ifstat.c | 24 ++++++++++++------------ misc/nstat.c | 22 +++++++++++----------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/misc/ifstat.c b/misc/ifstat.c index d5519737..92d67b0c 100644 --- a/misc/ifstat.c +++ b/misc/ifstat.c @@ -662,18 +662,18 @@ static void usage(void) { fprintf(stderr, "Usage: ifstat [OPTION] [ PATTERN [ PATTERN ] ]\n" -" -h, --help this message\n" -" -a, --ignore ignore history\n" -" -d, --scan=SECS sample every statistics every SECS\n" -" -e, --errors show errors\n" -" -j, --json format output in JSON\n" -" -n, --nooutput do history only\n" -" -p, --pretty pretty print\n" -" -r, --reset reset history\n" -" -s, --noupdate don\'t update history\n" -" -t, --interval=SECS report average over the last SECS\n" -" -V, --version output version information\n" -" -z, --zeros show entries with zero activity\n"); +" -h, --help this message\n" +" -a, --ignore ignore history\n" +" -d, --scan=SECS sample every statistics every SECS\n" +" -e, --errors show errors\n" +" -j, --json format output in JSON\n" +" -n, --nooutput do history only\n" +" -p, --pretty pretty print\n" +" -r, --reset reset history\n" +" -s, --noupdate don't update history\n" +" -t, --interval=SECS report average over the last SECS\n" +" -V, --version output version information\n" +" -z, --zeros show entries with zero activity\n"); exit(-1); } diff --git a/misc/nstat.c b/misc/nstat.c index 1cb6c7ee..1212b1f2 100644 --- a/misc/nstat.c +++ b/misc/nstat.c @@ -526,17 +526,17 @@ static void usage(void) { fprintf(stderr, "Usage: nstat [OPTION] [ PATTERN [ PATTERN ] ]\n" -" -h, --help this message\n" -" -a, --ignore ignore history\n" -" -d, --scan=SECS sample every statistics every SECS\n" -" -j, --json format output in JSON\n" -" -n, --nooutput do history only\n" -" -p, --pretty pretty print\n" -" -r, --reset reset history\n" -" -s, --noupdate don\'t update history\n" -" -t, --interval=SECS report average over the last SECS\n" -" -V, --version output version information\n" -" -z, --zeros show entries with zero activity\n"); +" -h, --help this message\n" +" -a, --ignore ignore history\n" +" -d, --scan=SECS sample every statistics every SECS\n" +" -j, --json format output in JSON\n" +" -n, --nooutput do history only\n" +" -p, --pretty pretty print\n" +" -r, --reset reset history\n" +" -s, --noupdate don't update history\n" +" -t, --interval=SECS report average over the last SECS\n" +" -V, --version output version information\n" +" -z, --zeros show entries with zero activity\n"); exit(-1); } From 3a4df0391367c2e8f0e037f0e91384c5def0c2af Mon Sep 17 00:00:00 2001 From: Daniel Hopf Date: Tue, 29 Nov 2016 13:22:12 -0800 Subject: [PATCH 22/36] macsec: Nr. of packets and octets for macsec tx stats were swapped Acked-by: Rami Rosen Acked-by: Sabrina Dubroca Signed-off-by: Daniel Hopf --- ip/ipmacsec.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ip/ipmacsec.c b/ip/ipmacsec.c index c9252bb2..aa89a00f 100644 --- a/ip/ipmacsec.c +++ b/ip/ipmacsec.c @@ -634,10 +634,10 @@ static void print_one_stat(const char **names, struct rtattr **attr, int idx, } static const char *txsc_stats_names[NUM_MACSEC_TXSC_STATS_ATTR] = { - [MACSEC_TXSC_STATS_ATTR_OUT_PKTS_PROTECTED] = "OutOctetsProtected", - [MACSEC_TXSC_STATS_ATTR_OUT_PKTS_ENCRYPTED] = "OutOctetsEncrypted", - [MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_PROTECTED] = "OutPktsProtected", - [MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_ENCRYPTED] = "OutPktsEncrypted", + [MACSEC_TXSC_STATS_ATTR_OUT_PKTS_PROTECTED] = "OutPktsProtected", + [MACSEC_TXSC_STATS_ATTR_OUT_PKTS_ENCRYPTED] = "OutPktsEncrypted", + [MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_PROTECTED] = "OutOctetsProtected", + [MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_ENCRYPTED] = "OutOctetsEncrypted", }; static void print_txsc_stats(const char *prefix, struct rtattr *attr) From 98df0c81dac41bcd4ccad67ec6886dab25825be0 Mon Sep 17 00:00:00 2001 From: Roman Mashak Date: Wed, 16 Nov 2016 17:30:20 -0500 Subject: [PATCH 23/36] tc: distinguish Add/Replace filter operations Signed-off-by: Roman Mashak Signed-off-by: Jamal Hadi Salim --- tc/tc_filter.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tc/tc_filter.c b/tc/tc_filter.c index 932677a0..ff8713b9 100644 --- a/tc/tc_filter.c +++ b/tc/tc_filter.c @@ -226,6 +226,16 @@ int print_filter(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (n->nlmsg_type == RTM_DELTFILTER) fprintf(fp, "deleted "); + if (n->nlmsg_type == RTM_NEWTFILTER && + (n->nlmsg_flags & NLM_F_CREATE) && + !(n->nlmsg_flags & NLM_F_EXCL)) + fprintf(fp, "replaced "); + + if (n->nlmsg_type == RTM_NEWTFILTER && + (n->nlmsg_flags & NLM_F_CREATE) && + (n->nlmsg_flags & NLM_F_EXCL)) + fprintf(fp, "added "); + fprintf(fp, "filter "); if (!filter_ifindex || filter_ifindex != t->tcm_ifindex) fprintf(fp, "dev %s ", ll_index_to_name(t->tcm_ifindex)); From 222c4dab8e37f77a9e8834b72ce0b02e5d928f5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?= Date: Wed, 16 Nov 2016 22:45:18 +0000 Subject: [PATCH 24/36] man: ip-l2tp.8: fix l2spec_type documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Asbjørn Sloth Tønnesen --- man/man8/ip-l2tp.8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/man8/ip-l2tp.8 b/man/man8/ip-l2tp.8 index 5b7041f9..4a3bb20a 100644 --- a/man/man8/ip-l2tp.8 +++ b/man/man8/ip-l2tp.8 @@ -239,7 +239,7 @@ find in received L2TP packets. Default is to use no cookie. set the layer2specific header type of the session. .br Valid values are: -.BR none ", " udp "." +.BR none ", " default "." .TP .BI offset " OFFSET" sets the byte offset from the L2TP header where user data starts in From d0baf5cac8730469050cef4034bd0f82c18965ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?= Date: Wed, 16 Nov 2016 22:45:19 +0000 Subject: [PATCH 25/36] man: ip-l2tp.8: remove non-existent tunnel parameter name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The name parameter is only valid for sessions, not tunnels. Signed-off-by: Asbjørn Sloth Tønnesen --- man/man8/ip-l2tp.8 | 3 --- 1 file changed, 3 deletions(-) diff --git a/man/man8/ip-l2tp.8 b/man/man8/ip-l2tp.8 index 4a3bb20a..991d0973 100644 --- a/man/man8/ip-l2tp.8 +++ b/man/man8/ip-l2tp.8 @@ -154,9 +154,6 @@ tunnels and sessions to be established and provides for detecting and acting upon network failures. .SS ip l2tp add tunnel - add a new tunnel .TP -.BI name " NAME " -sets the session network interface name. Default is l2tpethN. -.TP .BI tunnel_id " ID" set the tunnel id, which is a 32-bit integer value. Uniquely identifies the tunnel. The value used must match the peer_tunnel_id From 31f63e7c426f8b7098f87a9391748e8325dff3c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?= Date: Wed, 16 Nov 2016 22:45:20 +0000 Subject: [PATCH 26/36] l2tp: fix integers with too few significant bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit udp6_csum_{tx,rx}, tunnel and session are the only ones currently used. recv_seq, send_seq, lns_mode and data_seq are partially implemented in a useless way. Signed-off-by: Asbjørn Sloth Tønnesen --- ip/ipl2tp.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ip/ipl2tp.c b/ip/ipl2tp.c index d3338ace..2e0e9c74 100644 --- a/ip/ipl2tp.c +++ b/ip/ipl2tp.c @@ -56,15 +56,15 @@ struct l2tp_parm { uint16_t pw_type; uint16_t mtu; - int udp6_csum_tx:1; - int udp6_csum_rx:1; - int udp_csum:1; - int recv_seq:1; - int send_seq:1; - int lns_mode:1; - int data_seq:2; - int tunnel:1; - int session:1; + 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; const char *ifname; uint8_t l2spec_type; From 4d51b3331eae9cbd77e22272903f6f0efd0b4847 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?= Date: Wed, 16 Nov 2016 22:45:21 +0000 Subject: [PATCH 27/36] l2tp: fix L2TP_ATTR_{RECV,SEND}_SEQ handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit L2TP_ATTR_RECV_SEQ and L2TP_ATTR_SEND_SEQ are declared as NLA_U8 attributes in the kernel, so let's threat them accordingly. Signed-off-by: Asbjørn Sloth Tønnesen --- ip/ipl2tp.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ip/ipl2tp.c b/ip/ipl2tp.c index 2e0e9c74..a7cbd669 100644 --- a/ip/ipl2tp.c +++ b/ip/ipl2tp.c @@ -160,8 +160,8 @@ static int create_session(struct l2tp_parm *p) 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) addattr(&req.n, 1024, L2TP_ATTR_RECV_SEQ); - if (p->send_seq) addattr(&req.n, 1024, L2TP_ATTR_SEND_SEQ); + 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, @@ -304,8 +304,10 @@ static int get_response(struct nlmsghdr *n, void *arg) memcpy(p->peer_cookie, RTA_DATA(attrs[L2TP_ATTR_PEER_COOKIE]), p->peer_cookie_len = RTA_PAYLOAD(attrs[L2TP_ATTR_PEER_COOKIE])); - p->recv_seq = !!attrs[L2TP_ATTR_RECV_SEQ]; - p->send_seq = !!attrs[L2TP_ATTR_SEND_SEQ]; + if (attrs[L2TP_ATTR_RECV_SEQ]) + p->recv_seq = !!rta_getattr_u8(attrs[L2TP_ATTR_RECV_SEQ]); + if (attrs[L2TP_ATTR_SEND_SEQ]) + p->send_seq = !!rta_getattr_u8(attrs[L2TP_ATTR_SEND_SEQ]); if (attrs[L2TP_ATTR_RECV_TIMEOUT]) p->reorder_timeout = rta_getattr_u64(attrs[L2TP_ATTR_RECV_TIMEOUT]); From c73fad78603e130b80a10a498582ff701ac93515 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?= Date: Wed, 16 Nov 2016 22:45:22 +0000 Subject: [PATCH 28/36] l2tp: fix L2TP_ATTR_UDP_CSUM handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit L2TP_ATTR_UDP_CSUM is read by the kernel as a NLA_FLAG value, but is validated as a NLA_U8, so we will write it as an u8, but the value isn't actually being read by the kernel. It is written by the kernel as a NLA_U8, so we will read as such. Signed-off-by: Asbjørn Sloth Tønnesen --- ip/ipl2tp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ip/ipl2tp.c b/ip/ipl2tp.c index a7cbd669..03ca0cc4 100644 --- a/ip/ipl2tp.c +++ b/ip/ipl2tp.c @@ -120,7 +120,7 @@ static int create_tunnel(struct l2tp_parm *p) addattr16(&req.n, 1024, L2TP_ATTR_UDP_SPORT, p->local_udp_port); addattr16(&req.n, 1024, L2TP_ATTR_UDP_DPORT, p->peer_udp_port); if (p->udp_csum) - addattr(&req.n, 1024, L2TP_ATTR_UDP_CSUM); + addattr8(&req.n, 1024, L2TP_ATTR_UDP_CSUM, 1); if (!p->udp6_csum_tx) addattr(&req.n, 1024, L2TP_ATTR_UDP_ZERO_CSUM6_TX); if (!p->udp6_csum_rx) @@ -289,7 +289,9 @@ static int get_response(struct nlmsghdr *n, void *arg) if (attrs[L2TP_ATTR_L2SPEC_LEN]) p->l2spec_len = rta_getattr_u8(attrs[L2TP_ATTR_L2SPEC_LEN]); - p->udp_csum = !!attrs[L2TP_ATTR_UDP_CSUM]; + if (attrs[L2TP_ATTR_UDP_CSUM]) + p->udp_csum = !!rta_getattr_u8(attrs[L2TP_ATTR_UDP_CSUM]); + /* * Not fetching from L2TP_ATTR_UDP_ZERO_CSUM6_{T,R}X because the * kernel doesn't send it so just leave it as default value. From 35cc6ded4f1520de8db2169abdcb0a6fb034781c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?= Date: Wed, 16 Nov 2016 22:45:23 +0000 Subject: [PATCH 29/36] l2tp: read IPv6 UDP checksum attributes from kernel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In case of an older kernel that doesn't set L2TP_ATTR_UDP_ZERO_CSUM6_{RX,TX} the old hard-coded value is being preserved, since the attribute flag will be missing. Signed-off-by: Asbjørn Sloth Tønnesen --- ip/ipl2tp.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/ip/ipl2tp.c b/ip/ipl2tp.c index 03ca0cc4..f5d41139 100644 --- a/ip/ipl2tp.c +++ b/ip/ipl2tp.c @@ -292,12 +292,9 @@ static int get_response(struct nlmsghdr *n, void *arg) if (attrs[L2TP_ATTR_UDP_CSUM]) p->udp_csum = !!rta_getattr_u8(attrs[L2TP_ATTR_UDP_CSUM]); - /* - * Not fetching from L2TP_ATTR_UDP_ZERO_CSUM6_{T,R}X because the - * kernel doesn't send it so just leave it as default value. - */ - p->udp6_csum_tx = 1; - p->udp6_csum_rx = 1; + p->udp6_csum_tx = !attrs[L2TP_ATTR_UDP_ZERO_CSUM6_TX]; + p->udp6_csum_rx = !attrs[L2TP_ATTR_UDP_ZERO_CSUM6_RX]; + if (attrs[L2TP_ATTR_COOKIE]) memcpy(p->cookie, RTA_DATA(attrs[L2TP_ATTR_COOKIE]), p->cookie_len = RTA_PAYLOAD(attrs[L2TP_ATTR_COOKIE])); From 8a11421a5d8ae95ba03453a56611b9b09e32c0b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?= Date: Wed, 16 Nov 2016 22:45:24 +0000 Subject: [PATCH 30/36] l2tp: support sequence numbering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch implement and documents the user interface for sequence numbering. Signed-off-by: Asbjørn Sloth Tønnesen --- ip/ipl2tp.c | 23 +++++++++++++++++++++++ man/man8/ip-l2tp.8 | 15 +++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/ip/ipl2tp.c b/ip/ipl2tp.c index f5d41139..ab35023e 100644 --- a/ip/ipl2tp.c +++ b/ip/ipl2tp.c @@ -246,6 +246,12 @@ static void print_session(struct l2tp_data *data) printf(" reorder timeout: %u\n", p->reorder_timeout); else printf("\n"); + if (p->send_seq || p->recv_seq) { + printf(" sequence numbering:"); + if (p->send_seq) printf(" send"); + if (p->recv_seq) printf(" recv"); + printf("\n"); + } } static int get_response(struct nlmsghdr *n, void *arg) @@ -482,6 +488,7 @@ static void usage(void) fprintf(stderr, " session_id ID peer_session_id ID\n"); fprintf(stderr, " [ cookie HEXSTR ] [ peer_cookie HEXSTR ]\n"); fprintf(stderr, " [ offset OFFSET ] [ peer_offset OFFSET ]\n"); + fprintf(stderr, " [ seq { none | send | recv | both } ]\n"); fprintf(stderr, " [ l2spec_type L2SPEC ]\n"); fprintf(stderr, " ip l2tp del tunnel tunnel_id ID\n"); fprintf(stderr, " ip l2tp del session tunnel_id ID session_id ID\n"); @@ -652,6 +659,22 @@ static int parse_args(int argc, char **argv, int cmd, struct l2tp_parm *p) fprintf(stderr, "Unknown layer2specific header type \"%s\"\n", *argv); exit(-1); } + } else if (strcmp(*argv, "seq") == 0) { + NEXT_ARG(); + if (strcasecmp(*argv, "both") == 0) { + p->recv_seq = 1; + p->send_seq = 1; + } else if (strcasecmp(*argv, "recv") == 0) { + p->recv_seq = 1; + } else if (strcasecmp(*argv, "send") == 0) { + p->send_seq = 1; + } else if (strcasecmp(*argv, "none") == 0) { + p->recv_seq = 0; + p->send_seq = 0; + } else { + fprintf(stderr, "Unknown seq value \"%s\"\n", *argv); + exit(-1); + } } else if (strcmp(*argv, "tunnel") == 0) { p->tunnel = 1; } else if (strcmp(*argv, "session") == 0) { diff --git a/man/man8/ip-l2tp.8 b/man/man8/ip-l2tp.8 index 991d0973..d4e7270f 100644 --- a/man/man8/ip-l2tp.8 +++ b/man/man8/ip-l2tp.8 @@ -51,6 +51,8 @@ ip-l2tp - L2TPv3 static unmanaged tunnel configuration .br .RB "[ " l2spec_type " { " none " | " default " } ]" .br +.RB "[ " seq " { " none " | " send " | " recv " | " both " } ]" +.br .RB "[ " offset .IR OFFSET .RB " ] [ " peer_offset @@ -238,6 +240,19 @@ set the layer2specific header type of the session. Valid values are: .BR none ", " default "." .TP +.BI seq " SEQ" +controls sequence numbering to prevent or detect out of order packets. +.B send +puts a sequence number in the default layer2specific header of each +outgoing packet. +.B recv +reorder packets if they are received out of order. +Default is +.BR none "." +.br +Valid values are: +.BR none ", " send ", " recv ", " both "." +.TP .BI offset " OFFSET" sets the byte offset from the L2TP header where user data starts in transmitted L2TP data packets. This is hardly ever used. If set, the From f7982f5c9574358c443e6175295dc36b29085003 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?= Date: Wed, 16 Nov 2016 22:45:25 +0000 Subject: [PATCH 31/36] l2tp: show tunnel: expose UDP checksum state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Asbjørn Sloth Tønnesen --- ip/ipl2tp.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/ip/ipl2tp.c b/ip/ipl2tp.c index ab35023e..f2bbc0c3 100644 --- a/ip/ipl2tp.c +++ b/ip/ipl2tp.c @@ -218,9 +218,24 @@ static void print_tunnel(const struct l2tp_data *data) printf(" Peer tunnel %u\n", p->peer_tunnel_id); - if (p->encap == L2TP_ENCAPTYPE_UDP) + if (p->encap == L2TP_ENCAPTYPE_UDP) { printf(" UDP source / dest ports: %hu/%hu\n", p->local_udp_port, p->peer_udp_port); + + switch (p->local_ip.family) { + case AF_INET: + printf(" UDP checksum: %s\n", + p->udp_csum ? "enabled" : "disabled"); + break; + case AF_INET6: + printf(" UDP checksum: %s%s%s%s\n", + p->udp6_csum_tx && p->udp6_csum_rx ? "enabled" : "", + p->udp6_csum_tx && !p->udp6_csum_rx ? "tx" : "", + !p->udp6_csum_tx && p->udp6_csum_rx ? "rx" : "", + !p->udp6_csum_tx && !p->udp6_csum_rx ? "disabled" : ""); + break; + } + } } static void print_session(struct l2tp_data *data) From 51a9d01aaa760a0e0887a7c3c701e5f180604950 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?= Date: Wed, 16 Nov 2016 22:45:26 +0000 Subject: [PATCH 32/36] man: ip-l2tp.8: document UDP checksum options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Asbjørn Sloth Tønnesen --- man/man8/ip-l2tp.8 | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/man/man8/ip-l2tp.8 b/man/man8/ip-l2tp.8 index d4e7270f..8ce630a6 100644 --- a/man/man8/ip-l2tp.8 +++ b/man/man8/ip-l2tp.8 @@ -30,6 +30,12 @@ ip-l2tp - L2TPv3 static unmanaged tunnel configuration .IR PORT .RB " ]" .br +.RB "[ " udp_csum " { " on " | " off " } ]" +.br +.RB "[ " udp6_csum_tx " { " on " | " off " } ]" +.br +.RB "[ " udp6_csum_rx " { " on " | " off " } ]" +.br .ti -8 .BR "ip l2tp add session" .RB "[ " name @@ -190,6 +196,33 @@ selected. set the UDP destination port to be used for the tunnel. Must be present when udp encapsulation is selected. Ignored when ip encapsulation is selected. +.TP +.BI udp_csum " STATE" +(IPv4 only) control if IPv4 UDP checksums should be calculated and checked for the +encapsulating UDP packets, when UDP encapsulating is selected. +Default is +.BR off "." +.br +Valid values are: +.BR on ", " off "." +.TP +.BI udp6_csum_tx " STATE" +(IPv6 only) control if IPv6 UDP checksums should be calculated for encapsulating +UDP packets, when UDP encapsulating is selected. +Default is +.BR on "." +.br +Valid values are: +.BR on ", " off "." +.TP +.BI udp6_csum_rx " STATE" +(IPv6 only) control if IPv6 UDP checksums should be checked for the encapsulating +UDP packets, when UDP encapsulating is selected. +Default is +.BR on "." +.br +Valid values are: +.BR on ", " off "." .SS ip l2tp del tunnel - destroy a tunnel .TP .BI tunnel_id " ID" From 281db53ff8be75b2b3590b24d0602774aa80fef4 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 29 Nov 2016 13:40:06 -0800 Subject: [PATCH 33/36] l2tp: style cleanup Make l2tp conform to kernel style guidelines --- ip/ipl2tp.c | 139 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 84 insertions(+), 55 deletions(-) diff --git a/ip/ipl2tp.c b/ip/ipl2tp.c index f2bbc0c3..0f91aebf 100644 --- a/ip/ipl2tp.c +++ b/ip/ipl2tp.c @@ -110,11 +110,13 @@ static int create_tunnel(struct l2tp_parm *p) if (p->local_ip.family == AF_INET6) local_attr = L2TP_ATTR_IP6_SADDR; - addattr_l(&req.n, 1024, local_attr, &p->local_ip.data, p->local_ip.bytelen); + addattr_l(&req.n, 1024, local_attr, &p->local_ip.data, + p->local_ip.bytelen); if (p->peer_ip.family == AF_INET6) peer_attr = L2TP_ATTR_IP6_DADDR; - addattr_l(&req.n, 1024, peer_attr, &p->peer_ip.data, p->peer_ip.bytelen); + addattr_l(&req.n, 1024, peer_attr, &p->peer_ip.data, + p->peer_ip.bytelen); if (p->encap == L2TP_ENCAPTYPE_UDP) { addattr16(&req.n, 1024, L2TP_ATTR_UDP_SPORT, p->local_udp_port); @@ -159,18 +161,27 @@ 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, + 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); - if (p->offset) addattr16(&req.n, 1024, L2TP_ATTR_OFFSET, p->offset); - if (p->cookie_len) addattr_l(&req.n, 1024, L2TP_ATTR_COOKIE, - p->cookie, p->cookie_len); - if (p->peer_cookie_len) addattr_l(&req.n, 1024, L2TP_ATTR_PEER_COOKIE, - p->peer_cookie, p->peer_cookie_len); + if (p->offset) + addattr16(&req.n, 1024, L2TP_ATTR_OFFSET, p->offset); + if (p->cookie_len) + addattr_l(&req.n, 1024, L2TP_ATTR_COOKIE, + p->cookie, p->cookie_len); + if (p->peer_cookie_len) + addattr_l(&req.n, 1024, L2TP_ATTR_PEER_COOKIE, + p->peer_cookie, p->peer_cookie_len); if (p->ifname && p->ifname[0]) addattrstrz(&req.n, 1024, L2TP_ATTR_IFNAME, p->ifname); @@ -213,8 +224,12 @@ static void print_tunnel(const struct l2tp_data *data) p->tunnel_id, p->encap == L2TP_ENCAPTYPE_UDP ? "UDP" : p->encap == L2TP_ENCAPTYPE_IP ? "IP" : "??"); - printf(" From %s ", inet_ntop(p->local_ip.family, p->local_ip.data, buf, sizeof(buf))); - printf("to %s\n", inet_ntop(p->peer_ip.family, p->peer_ip.data, buf, sizeof(buf))); + printf(" From %s ", + inet_ntop(p->local_ip.family, p->local_ip.data, + buf, sizeof(buf))); + printf("to %s\n", + inet_ntop(p->peer_ip.family, p->peer_ip.data, + buf, sizeof(buf))); printf(" Peer tunnel %u\n", p->peer_tunnel_id); @@ -229,10 +244,14 @@ static void print_tunnel(const struct l2tp_data *data) break; case AF_INET6: printf(" UDP checksum: %s%s%s%s\n", - p->udp6_csum_tx && p->udp6_csum_rx ? "enabled" : "", - p->udp6_csum_tx && !p->udp6_csum_rx ? "tx" : "", - !p->udp6_csum_tx && p->udp6_csum_rx ? "rx" : "", - !p->udp6_csum_tx && !p->udp6_csum_rx ? "disabled" : ""); + p->udp6_csum_tx && p->udp6_csum_rx + ? "enabled" : "", + p->udp6_csum_tx && !p->udp6_csum_rx + ? "tx" : "", + !p->udp6_csum_tx && p->udp6_csum_rx + ? "rx" : "", + !p->udp6_csum_tx && !p->udp6_csum_rx + ? "disabled" : ""); break; } } @@ -247,9 +266,9 @@ static void print_session(struct l2tp_data *data) printf(" Peer session %u, tunnel %u\n", p->peer_session_id, p->peer_tunnel_id); - if (p->ifname != NULL) { + if (p->ifname != NULL) printf(" interface name: %s\n", p->ifname); - } + printf(" offset %u, peer offset %u\n", p->offset, p->peer_offset); if (p->cookie_len > 0) @@ -263,8 +282,10 @@ static void print_session(struct l2tp_data *data) printf("\n"); if (p->send_seq || p->recv_seq) { printf(" sequence numbering:"); - if (p->send_seq) printf(" send"); - if (p->recv_seq) printf(" recv"); + if (p->send_seq) + printf(" send"); + if (p->recv_seq) + printf(" recv"); printf("\n"); } } @@ -391,7 +412,8 @@ static int get_response(struct nlmsghdr *n, void *arg) return 0; } -static int session_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) +static int session_nlmsg(const struct sockaddr_nl *who, + struct nlmsghdr *n, void *arg) { int ret = get_response(n, arg); @@ -411,7 +433,8 @@ static int get_session(struct l2tp_data *p) if (p->config.tunnel_id && p->config.session_id) { addattr32(&req.n, 128, L2TP_ATTR_CONN_ID, p->config.tunnel_id); - addattr32(&req.n, 128, L2TP_ATTR_SESSION_ID, p->config.session_id); + addattr32(&req.n, 128, L2TP_ATTR_SESSION_ID, + p->config.session_id); } if (rtnl_send(&genl_rth, &req, req.n.nlmsg_len) < 0) @@ -425,7 +448,8 @@ static int get_session(struct l2tp_data *p) return 0; } -static int tunnel_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) +static int tunnel_nlmsg(const struct sockaddr_nl *who, + struct nlmsghdr *n, void *arg) { int ret = get_response(n, arg); @@ -490,32 +514,33 @@ static void usage(void) __attribute__((noreturn)); static void usage(void) { - fprintf(stderr, "Usage: ip l2tp add tunnel\n"); - fprintf(stderr, " remote ADDR local ADDR\n"); - fprintf(stderr, " tunnel_id ID peer_tunnel_id ID\n"); - fprintf(stderr, " [ encap { ip | udp } ]\n"); - fprintf(stderr, " [ udp_sport PORT ] [ udp_dport PORT ]\n"); - fprintf(stderr, " [ udp_csum { on | off } ]\n"); - fprintf(stderr, " [ udp6_csum_tx { on | off } ]\n"); - fprintf(stderr, " [ udp6_csum_rx { on | off } ]\n"); - fprintf(stderr, "Usage: ip l2tp add session [ name NAME ]\n"); - fprintf(stderr, " tunnel_id ID\n"); - fprintf(stderr, " session_id ID peer_session_id ID\n"); - fprintf(stderr, " [ cookie HEXSTR ] [ peer_cookie HEXSTR ]\n"); - fprintf(stderr, " [ offset OFFSET ] [ peer_offset OFFSET ]\n"); - fprintf(stderr, " [ seq { none | send | recv | both } ]\n"); - fprintf(stderr, " [ l2spec_type L2SPEC ]\n"); - fprintf(stderr, " ip l2tp del tunnel tunnel_id ID\n"); - fprintf(stderr, " ip l2tp del session tunnel_id ID session_id ID\n"); - fprintf(stderr, " ip l2tp show tunnel [ tunnel_id ID ]\n"); - fprintf(stderr, " ip l2tp show session [ tunnel_id ID ] [ session_id ID ]\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "Where: NAME := STRING\n"); - fprintf(stderr, " ADDR := { IP_ADDRESS | any }\n"); - fprintf(stderr, " PORT := { 0..65535 }\n"); - fprintf(stderr, " ID := { 1..4294967295 }\n"); - fprintf(stderr, " HEXSTR := { 8 or 16 hex digits (4 / 8 bytes) }\n"); - fprintf(stderr, " L2SPEC := { none | default }\n"); + fprintf(stderr, "Usage: ip l2tp add tunnel\n" + " remote ADDR local ADDR\n" + " tunnel_id ID peer_tunnel_id ID\n" + " [ encap { ip | udp } ]\n" + " [ udp_sport PORT ] [ udp_dport PORT ]\n" + " [ udp_csum { on | off } ]\n" + " [ udp6_csum_tx { on | off } ]\n" + " [ udp6_csum_rx { on | off } ]\n" + "Usage: ip l2tp add session [ name NAME ]\n" + " tunnel_id ID\n" + " session_id ID peer_session_id ID\n" + " [ cookie HEXSTR ] [ peer_cookie HEXSTR ]\n" + " [ offset OFFSET ] [ peer_offset OFFSET ]\n" + " [ seq { none | send | recv | both } ]\n" + " [ l2spec_type L2SPEC ]\n" + " ip l2tp del tunnel tunnel_id ID\n" + " ip l2tp del session tunnel_id ID session_id ID\n" + " ip l2tp show tunnel [ tunnel_id ID ]\n" + " ip l2tp show session [ tunnel_id ID ] [ session_id ID ]\n" + "\n" + "Where: NAME := STRING\n" + " ADDR := { IP_ADDRESS | any }\n" + " PORT := { 0..65535 }\n" + " ID := { 1..4294967295 }\n" + " HEXSTR := { 8 or 16 hex digits (4 / 8 bytes) }\n" + " L2SPEC := { none | default }\n"); + exit(-1); } @@ -671,7 +696,9 @@ static int parse_args(int argc, char **argv, int cmd, struct l2tp_parm *p) p->l2spec_type = L2TP_L2SPECTYPE_NONE; p->l2spec_len = 0; } else { - fprintf(stderr, "Unknown layer2specific header type \"%s\"\n", *argv); + fprintf(stderr, + "Unknown layer2specific header type \"%s\"\n", + *argv); exit(-1); } } else if (strcmp(*argv, "seq") == 0) { @@ -687,7 +714,8 @@ static int parse_args(int argc, char **argv, int cmd, struct l2tp_parm *p) p->recv_seq = 0; p->send_seq = 0; } else { - fprintf(stderr, "Unknown seq value \"%s\"\n", *argv); + fprintf(stderr, + "Unknown seq value \"%s\"\n", *argv); exit(-1); } } else if (strcmp(*argv, "tunnel") == 0) { @@ -818,6 +846,7 @@ int do_ipl2tp(int argc, char **argv) matches(*argv, "list") == 0) return do_show(argc-1, argv+1); - fprintf(stderr, "Command \"%s\" is unknown, try \"ip l2tp help\".\n", *argv); + fprintf(stderr, + "Command \"%s\" is unknown, try \"ip l2tp help\".\n", *argv); exit(-1); } From 6bd1ea28c53fd7b7d59a656796230c28c9dae65e Mon Sep 17 00:00:00 2001 From: Zhang Shengju Date: Fri, 25 Nov 2016 22:01:29 +0800 Subject: [PATCH 34/36] link: add team and team_slave link type Add missing team and team_slave link type. Signed-off-by: Zhang Shengju --- ip/iplink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ip/iplink.c b/ip/iplink.c index a8b49c52..1e603e70 100644 --- a/ip/iplink.c +++ b/ip/iplink.c @@ -98,8 +98,8 @@ void iplink_usage(void) fprintf(stderr, " ip link help [ TYPE ]\n\n" "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap |\n" - " bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |\n" - " gre | gretap | ip6gre | ip6gretap | vti | nlmon |\n" + " bridge | bond | team | ipoib | ip6tnl | ipip | sit | vxlan |\n" + " gre | gretap | ip6gre | ip6gretap | vti | nlmon | team_slave |\n" " bond_slave | ipvlan | geneve | bridge_slave | vrf | macsec }\n"); } exit(-1); From 11f4cd31d2776bbffecceb6775d0210fe16cc04e Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Sun, 27 Nov 2016 13:21:02 +0200 Subject: [PATCH 35/36] devlink: Add usage help for eswitch subcommand Add missing usage help for devlink dev eswitch subcommand. Signed-off-by: Roi Dayan Reviewed-by: Or Gerlitz --- devlink/devlink.c | 7 ++++++- man/man8/devlink-dev.8 | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/devlink/devlink.c b/devlink/devlink.c index ccca0fb3..673234fa 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -963,6 +963,8 @@ static bool dl_dump_filter(struct dl *dl, struct nlattr **tb) static void cmd_dev_help(void) { pr_err("Usage: devlink dev show [ DEV ]\n"); + pr_err(" devlink dev eswitch set DEV [ mode { legacy | switchdev } ]\n"); + pr_err(" devlink dev eswitch show DEV\n"); } static bool cmp_arr_last_handle(struct dl *dl, const char *bus_name, @@ -1259,7 +1261,10 @@ static int cmd_dev_eswitch_set(struct dl *dl) static int cmd_dev_eswitch(struct dl *dl) { - if (dl_argv_match(dl, "set")) { + if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { + cmd_dev_help(); + return 0; + } else if (dl_argv_match(dl, "set")) { dl_arg_inc(dl); return cmd_dev_eswitch_set(dl); } else if (dl_argv_match(dl, "show")) { diff --git a/man/man8/devlink-dev.8 b/man/man8/devlink-dev.8 index 9ce31937..931e334d 100644 --- a/man/man8/devlink-dev.8 +++ b/man/man8/devlink-dev.8 @@ -54,7 +54,7 @@ BUS_NAME/BUS_ADDRESS .TP .BR mode " { " legacy " | " switchdev " } " -set eswitch mode +Set eswitch mode .I legacy - Legacy SRIOV From b9dcf9c2826cc193937e5c337dee96a4c111e56a Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Sun, 27 Nov 2016 13:21:03 +0200 Subject: [PATCH 36/36] devlink: Add option to set and show eswitch inline mode This is needed for some HWs to do proper macthing and steering. Possible values are none, link, network, transport. Signed-off-by: Roi Dayan Reviewed-by: Or Gerlitz --- devlink/devlink.c | 82 ++++++++++++++++++++++++++++++++++++++++- include/linux/devlink.h | 8 ++++ man/man8/devlink-dev.8 | 19 ++++++++++ 3 files changed, 108 insertions(+), 1 deletion(-) diff --git a/devlink/devlink.c b/devlink/devlink.c index 673234fa..23db9e7c 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -28,6 +28,10 @@ #define ESWITCH_MODE_LEGACY "legacy" #define ESWITCH_MODE_SWITCHDEV "switchdev" +#define ESWITCH_INLINE_MODE_NONE "none" +#define ESWITCH_INLINE_MODE_LINK "link" +#define ESWITCH_INLINE_MODE_NETWORK "network" +#define ESWITCH_INLINE_MODE_TRANSPORT "transport" #define pr_err(args...) fprintf(stderr, ##args) #define pr_out(args...) fprintf(stdout, ##args) @@ -132,6 +136,7 @@ static void ifname_map_free(struct ifname_map *ifname_map) #define DL_OPT_SB_TH BIT(9) #define DL_OPT_SB_TC BIT(10) #define DL_OPT_ESWITCH_MODE BIT(11) +#define DL_OPT_ESWITCH_INLINE_MODE BIT(12) struct dl_opts { uint32_t present; /* flags of present items */ @@ -148,6 +153,7 @@ struct dl_opts { uint32_t sb_threshold; uint16_t sb_tc_index; enum devlink_eswitch_mode eswitch_mode; + enum devlink_eswitch_inline_mode eswitch_inline_mode; }; struct dl { @@ -305,6 +311,9 @@ static int attr_cb(const struct nlattr *attr, void *data) if (type == DEVLINK_ATTR_ESWITCH_MODE && mnl_attr_validate(attr, MNL_TYPE_U16) < 0) return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_ESWITCH_INLINE_MODE && + mnl_attr_validate(attr, MNL_TYPE_U8) < 0) + return MNL_CB_ERROR; tb[type] = attr; return MNL_CB_OK; } @@ -682,6 +691,24 @@ static int eswitch_mode_get(const char *typestr, return 0; } +static int eswitch_inline_mode_get(const char *typestr, + enum devlink_eswitch_inline_mode *p_mode) +{ + if (strcmp(typestr, ESWITCH_INLINE_MODE_NONE) == 0) { + *p_mode = DEVLINK_ESWITCH_INLINE_MODE_NONE; + } else if (strcmp(typestr, ESWITCH_INLINE_MODE_LINK) == 0) { + *p_mode = DEVLINK_ESWITCH_INLINE_MODE_LINK; + } else if (strcmp(typestr, ESWITCH_INLINE_MODE_NETWORK) == 0) { + *p_mode = DEVLINK_ESWITCH_INLINE_MODE_NETWORK; + } else if (strcmp(typestr, ESWITCH_INLINE_MODE_TRANSPORT) == 0) { + *p_mode = DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT; + } else { + pr_err("Unknown eswitch inline mode \"%s\"\n", typestr); + return -EINVAL; + } + return 0; +} + static int dl_argv_parse(struct dl *dl, uint32_t o_required, uint32_t o_optional) { @@ -803,6 +830,19 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, if (err) return err; o_found |= DL_OPT_ESWITCH_MODE; + } else if (dl_argv_match(dl, "inline-mode") && + (o_all & DL_OPT_ESWITCH_INLINE_MODE)) { + const char *typestr; + + dl_arg_inc(dl); + err = dl_argv_str(dl, &typestr); + if (err) + return err; + err = eswitch_inline_mode_get( + typestr, &opts->eswitch_inline_mode); + if (err) + return err; + o_found |= DL_OPT_ESWITCH_INLINE_MODE; } else { pr_err("Unknown option \"%s\"\n", dl_argv(dl)); return -EINVAL; @@ -863,6 +903,12 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, return -EINVAL; } + if ((o_required & DL_OPT_ESWITCH_INLINE_MODE) && + !(o_found & DL_OPT_ESWITCH_INLINE_MODE)) { + pr_err("E-Switch inline-mode option expected.\n"); + return -EINVAL; + } + return 0; } @@ -909,6 +955,9 @@ static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl) if (opts->present & DL_OPT_ESWITCH_MODE) mnl_attr_put_u16(nlh, DEVLINK_ATTR_ESWITCH_MODE, opts->eswitch_mode); + if (opts->present & DL_OPT_ESWITCH_INLINE_MODE) + mnl_attr_put_u8(nlh, DEVLINK_ATTR_ESWITCH_INLINE_MODE, + opts->eswitch_inline_mode); } static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl, @@ -964,6 +1013,7 @@ static void cmd_dev_help(void) { pr_err("Usage: devlink dev show [ DEV ]\n"); pr_err(" devlink dev eswitch set DEV [ mode { legacy | switchdev } ]\n"); + pr_err(" [ inline-mode { none | link | network | transport } ]\n"); pr_err(" devlink dev eswitch show DEV\n"); } @@ -1203,6 +1253,22 @@ static const char *eswitch_mode_name(uint32_t mode) } } +static const char *eswitch_inline_mode_name(uint32_t mode) +{ + switch (mode) { + case DEVLINK_ESWITCH_INLINE_MODE_NONE: + return ESWITCH_INLINE_MODE_NONE; + case DEVLINK_ESWITCH_INLINE_MODE_LINK: + return ESWITCH_INLINE_MODE_LINK; + case DEVLINK_ESWITCH_INLINE_MODE_NETWORK: + return ESWITCH_INLINE_MODE_NETWORK; + case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT: + return ESWITCH_INLINE_MODE_TRANSPORT; + default: + return ""; + } +} + static void pr_out_eswitch(struct dl *dl, struct nlattr **tb) { __pr_out_handle_start(dl, tb, true, false); @@ -1210,6 +1276,12 @@ static void pr_out_eswitch(struct dl *dl, struct nlattr **tb) if (tb[DEVLINK_ATTR_ESWITCH_MODE]) pr_out_str(dl, "mode", eswitch_mode_name(mnl_attr_get_u16(tb[DEVLINK_ATTR_ESWITCH_MODE]))); + + if (tb[DEVLINK_ATTR_ESWITCH_INLINE_MODE]) + pr_out_str(dl, "inline-mode", + eswitch_inline_mode_name(mnl_attr_get_u8( + tb[DEVLINK_ATTR_ESWITCH_INLINE_MODE]))); + pr_out_handle_end(dl); } @@ -1252,10 +1324,18 @@ static int cmd_dev_eswitch_set(struct dl *dl) nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_ESWITCH_MODE_SET, NLM_F_REQUEST | NLM_F_ACK); - err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_ESWITCH_MODE, 0); + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, + DL_OPT_ESWITCH_MODE | + DL_OPT_ESWITCH_INLINE_MODE); + if (err) return err; + if (dl->opts.present == 1) { + pr_err("Need to set at least one option\n"); + return -ENOENT; + } + return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); } diff --git a/include/linux/devlink.h b/include/linux/devlink.h index b7c1a069..7c14d773 100644 --- a/include/linux/devlink.h +++ b/include/linux/devlink.h @@ -102,6 +102,13 @@ enum devlink_eswitch_mode { DEVLINK_ESWITCH_MODE_SWITCHDEV, }; +enum devlink_eswitch_inline_mode { + DEVLINK_ESWITCH_INLINE_MODE_NONE, + DEVLINK_ESWITCH_INLINE_MODE_LINK, + DEVLINK_ESWITCH_INLINE_MODE_NETWORK, + DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT, +}; + enum devlink_attr { /* don't change the order or add anything between, this is ABI! */ DEVLINK_ATTR_UNSPEC, @@ -133,6 +140,7 @@ enum devlink_attr { DEVLINK_ATTR_SB_OCC_CUR, /* u32 */ DEVLINK_ATTR_SB_OCC_MAX, /* u32 */ DEVLINK_ATTR_ESWITCH_MODE, /* u16 */ + DEVLINK_ATTR_ESWITCH_INLINE_MODE, /* u8 */ /* add new attributes above here, update the policy in devlink.c */ diff --git a/man/man8/devlink-dev.8 b/man/man8/devlink-dev.8 index 931e334d..6bfe66f8 100644 --- a/man/man8/devlink-dev.8 +++ b/man/man8/devlink-dev.8 @@ -31,6 +31,9 @@ devlink-dev \- devlink device configuration .RI "[ " .BR mode " { " legacy " | " switchdev " } " .RI "]" +.RI "[ " +.BR inline-mode " { " none " | " link " | " network " | " transport " } " +.RI "]" .ti -8 .BR "devlink dev eswitch show" @@ -62,6 +65,22 @@ Set eswitch mode .I switchdev - SRIOV switchdev offloads +.TP +.BR inline-mode " { " none " | " link " | " network " | " transport " } " +Some HWs need the VF driver to put part of the packet headers on the TX descriptor so the e-switch can do proper matching and steering. + +.I none +- None + +.I link +- L2 mode + +.I network +- L3 mode + +.I transport +- L4 mode + .SH "EXAMPLES" .PP devlink dev show