sctp: fully support for dscp and flowlabel per transport
Subsystems (4)
Xin Long
maintainerv2 cover sctp: fully support for dscp and flowlabel per transport
Now dscp and flowlabel are set from sock when sending the packets, but being multi-homing, sctp also supports for dscp and flowlabel per transport, which is described in section 8.1.12 in RFC6458.
v1->v2:
- define ip_queue_xmit as inline in net/ip.h, instead of exporting it in Patch 1/5 according to David's suggestion.
- fix the param len check in sctp_s/getsockopt_peer_addr_params() in Patch 3/5 to guarantee that an old app built with old kernel headers could work on the newer kernel per Marcelo's point.
Xin Long (5):
ipv4: add __ip_queue_xmit() that supports tos param
sctp: add support for dscp and flowlabel per transport
sctp: add spp_ipv6_flowlabel and spp_dscp for sctp_paddrparams
sctp: add support for setting flowlabel when adding a transport
sctp: check for ipv6_pinfo legal sndflow with flowlabel in
sctp_v6_get_dst
include/linux/sctp.h | 7 ++ include/net/ip.h | 9 ++- include/net/sctp/structs.h | 9 +++ include/uapi/linux/sctp.h | 4 + net/ipv4/ip_output.c | 9 ++- net/sctp/associola.c | 15 ++++ net/sctp/ipv6.c | 20 ++++- net/sctp/protocol.c | 16 +++- net/sctp/socket.c | 182 +++++++++++++++++++++++++++++++++++++++++++-- 9 files changed, 254 insertions(+), 17 deletions(-)
Signature · 1 line
2.1.0
Xin Long
maintainerPATCH v2 1/5 ipv4: add __ip_queue_xmit() that supports tos param
This patch introduces __ip_queue_xmit(), through which the callers can pass tos param into it without having to set inet->tos. For ipv6, ip6_xmit() already allows passing tclass parameter.
It's needed when some transport protocol doesn't use inet->tos, like sctp's per transport dscp, which will be added in next patch.
--- include/net/ip.h | 9 ++++++++- net/ipv4/ip_output.c | 9 +++++---- 2 files changed, 13 insertions(+), 5 deletions(-)
include/net/ip.h +8 -1
@@ -148,7 +148,8 @@ void ip_send_check(struct iphdr *ip);int __ip_local_out (struct net *net,struct sock *sk,struct sk_buff *skb);int ip_local_out (struct net *net,struct sock *sk,struct sk_buff *skb); -int ip_queue_xmit (struct sock *sk,struct sk_buff *skb,struct flowi *fl); +int __ip_queue_xmit (struct sock *sk,struct sk_buff *skb,struct flowi *fl, +__u8 tos);void ip_init (void ); int ip_append_data(struct sock *sk, struct flowi4 *fl4, int getfrag(void *from, char *to, int offset, int len,
@@ -174,6 +175,12 @@ struct sk_buff *ip_make_skb(struct sock *sk, struct flowi4 *fl4, struct ipcm_cookie *ipc, struct rtable **rtp, struct inet_cork *cork, unsigned int flags); +static inline int ip_queue_xmit (struct sock *sk,struct sk_buff *skb, +struct flowi *fl) +{ +return __ip_queue_xmit (sk, skb, fl,inet_sk (sk)->tos); +} +static inline struct sk_buff *ip_finish_skb (struct sock *sk,struct flowi4 *fl4) {return __ip_make_skb (sk, fl4, &sk->sk_write_queue, &inet_sk (sk)->cork.base);
net/ipv4/ip_output.c +5 -4
@@ -423,7 +423,8 @@ static void ip_copy_addrs(struct iphdr *iph, const struct flowi4 *fl4) }/* Note: skb->sk can be different from sk, in case of tunnels */ -int ip_queue_xmit (struct sock *sk,struct sk_buff *skb,struct flowi *fl) +int __ip_queue_xmit (struct sock *sk,struct sk_buff *skb,struct flowi *fl, +__u8 tos) {struct inet_sock *inet =inet_sk (sk);struct net *net =sock_net (sk);
@@ -462,7 +463,7 @@ int ip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl) inet->inet_dport, inet->inet_sport, sk->sk_protocol, -RT_CONN_FLAGS (sk), +RT_CONN_FLAGS_TOS (sk, tos), sk->sk_bound_dev_if);if (IS_ERR (rt)) goto no_route;
@@ -478,7 +479,7 @@ int ip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl)skb_push (skb,sizeof (struct iphdr ) + (inet_opt ? inet_opt->opt.optlen :0 ));skb_reset_network_header (skb); iph =ip_hdr (skb); - *((__be16 *)iph) =htons ((4 <<12 ) | (5 <<8 ) | (inet->tos &0xff )); + *((__be16 *)iph) =htons ((4 <<12 ) | (5 <<8 ) | (tos &0xff ));if (ip_dont_fragment (sk, &rt->dst) && !skb->ignore_df) iph->frag_off =htons (IP_DF );else
@@ -511,7 +512,7 @@ int ip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl)kfree_skb (skb);return -EHOSTUNREACH ; } -EXPORT_SYMBOL (ip_queue_xmit); +EXPORT_SYMBOL (__ip_queue_xmit);static void ip_copy_metadata (struct sk_buff *to,struct sk_buff *from) {
Signature · 1 line
2.1.0
Xin Long
maintainerPATCH v2 2/5 sctp: add support for dscp and flowlabel per transport
Like some other per transport params, flowlabel and dscp are added in transport, asoc and sctp_sock. By default, transport sets its value from asoc's, and asoc does it from sctp_sock. flowlabel only works for ipv6 transport.
Other than that they need to be passed down in sctp_xmit, flow4/6 also needs to set them before looking up route in get_dst.
Note that it uses '& 0x100000' to check if flowlabel is set and '& 0x1' (tos 1st bit is unused) to check if dscp is set by users, so that they could be set to 0 by sockopt in next patch.
--- include/linux/sctp.h | 7 +++++++ include/net/sctp/structs.h | 9 +++++++++ net/sctp/associola.c | 7 +++++++ net/sctp/ipv6.c | 11 +++++++++-- net/sctp/protocol.c | 16 ++++++++++++---- 5 files changed, 44 insertions(+), 6 deletions(-)
include/linux/sctp.h +7 -0
@@ -801,4 +801,11 @@ struct sctp_strreset_resptsn { __be32 receivers_next_tsn; }; +enum { +SCTP_DSCP_SET_MASK =0x1 , +SCTP_DSCP_VAL_MASK =0xfc , +SCTP_FLOWLABEL_SET_MASK =0x100000 , +SCTP_FLOWLABEL_VAL_MASK =0xfffff +}; +#endif /* __LINUX_SCTP_H__ */
include/net/sctp/structs.h +9 -0
@@ -193,6 +193,9 @@ struct sctp_sock {/* This is the max_retrans value for new associations. */ __u16 pathmaxrxt; +__u32 flowlabel; +__u8 dscp; +/* The initial Path MTU to use for new associations. */ __u32 pathmtu;
@@ -895,6 +898,9 @@ struct sctp_transport {*/ __u16 pathmaxrxt; +__u32 flowlabel; +__u8 dscp; +/* This is the partially failed retrans value for the transport * and will be initialized from the assocs value. This can be changed * using the SCTP_PEER_ADDR_THLDS socket option
@@ -1772,6 +1778,9 @@ struct sctp_association {*/ __u16 pathmaxrxt; +__u32 flowlabel; +__u8 dscp; +/* Flag that path mtu update is pending */ __u8 pmtu_pending;
net/sctp/associola.c +7 -0
@@ -115,6 +115,9 @@ static struct sctp_association *sctp_association_init(/* Initialize path max retrans value. */ asoc->pathmaxrxt = sp->pathmaxrxt; + asoc->flowlabel = sp->flowlabel; + asoc->dscp = sp->dscp; +/* Initialize default path MTU. */ asoc->pathmtu = sp->pathmtu;
@@ -647,6 +650,10 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, peer->sackdelay = asoc->sackdelay; peer->sackfreq = asoc->sackfreq; +if (addr->sa.sa_family =AF_INET6 ) + peer->flowlabel = asoc->flowlabel; + peer->dscp = asoc->dscp; +/* Enable/disable heartbeat, SACK delay, and path MTU discovery * based on association setting. */
net/sctp/ipv6.c +9 -2
@@ -209,12 +209,17 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport)struct sock *sk = skb->sk;struct ipv6_pinfo *np =inet6_sk (sk);struct flowi6 *fl6 = &transport->fl.u.ip6; +__u8 tclass = np->tclass;int res;pr_debug ("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n" , __func__, skb, skb->len, &fl6->saddr, &fl6->daddr); -IP6_ECN_flow_xmit (sk, fl6->flowlabel); +if (transport->dscp &SCTP_DSCP_SET_MASK ) + tclass = transport->dscp &SCTP_DSCP_VAL_MASK ; + +if (INET_ECN_is_capable (tclass)) +IP6_ECN_flow_xmit (sk, fl6->flowlabel);if (!(transport->param_flags &SPP_PMTUD_ENABLE )) skb->ignore_df =1 ;
@@ -223,7 +228,7 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport)rcu_read_lock (); res =ip6_xmit (sk, skb, fl6, sk->sk_mark,rcu_dereference (np->opt), - np->tclass); + tclass);rcu_read_unlock ();return res; }
@@ -254,6 +259,8 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, fl6->flowi6_oif = daddr->v6.sin6_scope_id; else if (asoc) fl6->flowi6_oif = asoc->base.sk->sk_bound_dev_if; + if (t->flowlabel & SCTP_FLOWLABEL_SET_MASK) + fl6->flowlabel = htonl(t->flowlabel & SCTP_FLOWLABEL_VAL_MASK); pr_debug("%s: dst=%pI6 ", __func__, &fl6->daddr);
net/sctp/protocol.c +12 -4
@@ -426,13 +426,16 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr,struct dst_entry *dst =NULL ;union sctp_addr *daddr = &t->ipaddr;union sctp_addr dst_saddr; +__u8 tos =inet_sk (sk)->tos; +if (t->dscp &SCTP_DSCP_SET_MASK ) + tos = t->dscp &SCTP_DSCP_VAL_MASK ;memset (fl4,0x0 ,sizeof (struct flowi4 )); fl4->daddr = daddr->v4.sin_addr.s_addr; fl4->fl4_dport = daddr->v4.sin_port; fl4->flowi4_proto =IPPROTO_SCTP ;if (asoc) { - fl4->flowi4_tos =RT_CONN_FLAGS (asoc->base.sk); + fl4->flowi4_tos =RT_CONN_FLAGS_TOS (asoc->base.sk, tos); fl4->flowi4_oif = asoc->base.sk->sk_bound_dev_if; fl4->fl4_sport =htons (asoc->base.bind_addr.port); }
@@ -495,7 +498,7 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr, fl4->fl4_sport = laddr->a.v4.sin_port;flowi4_update_output (fl4, asoc->base.sk->sk_bound_dev_if, -RT_CONN_FLAGS (asoc->base.sk), +RT_CONN_FLAGS_TOS (asoc->base.sk, tos), daddr->v4.sin_addr.s_addr, laddr->a.v4.sin_addr.s_addr);
@@ -971,16 +974,21 @@ static inline int sctp_v4_xmit(struct sk_buff *skb, struct sctp_transport *transport) {struct inet_sock *inet =inet_sk (skb->sk); +__u8 dscp = inet->tos;pr_debug ("%s: skb:%p, len:%d, src:%pI4, dst:%pI4\n" , __func__, skb, - skb->len, &transport->fl.u.ip4.saddr, &transport->fl.u.ip4.daddr); + skb->len, &transport->fl.u.ip4.saddr, + &transport->fl.u.ip4.daddr); + +if (transport->dscp &SCTP_DSCP_SET_MASK ) + dscp = transport->dscp &SCTP_DSCP_VAL_MASK ; inet->pmtudisc = transport->param_flags &SPP_PMTUD_ENABLE ?IP_PMTUDISC_DO :IP_PMTUDISC_DONT ;SCTP_INC_STATS (sock_net (&inet->sk),SCTP_MIB_OUTSCTPPACKS ); -return ip_queue_xmit (&inet->sk, skb, &transport->fl); +return __ip_queue_xmit (&inet->sk, skb, &transport->fl, dscp); }static struct sctp_af sctp_af_inet;
Signature · 1 line
2.1.0
Xin Long
maintainerPATCH v2 3/5 sctp: add spp_ipv6_flowlabel and spp_dscp for sctp_paddrparams
spp_ipv6_flowlabel and spp_dscp are added in sctp_paddrparams in this patch so that users could set sctp_sock/asoc/transport dscp and flowlabel with spp_flags SPP_IPV6_FLOWLABEL or SPP_DSCP by SCTP_PEER_ADDR_PARAMS , as described section 8.1.12 in RFC6458.
As said in last patch, it uses '| 0x100000' or '|0x1' to mark flowlabel or dscp is set, so that their values could be set to 0.
Note that to guarantee that an old app built with old kernel headers could work on the newer kernel, the param's check in sctp_g/setsockopt_peer_addr_params() is also improved, which follows the way that sctp_g/setsockopt_delayed_ack() or some other sockopts' process that accept two types of params does.
--- include/uapi/linux/sctp.h | 4 ++ net/sctp/socket.c | 177 ++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 175 insertions(+), 6 deletions(-)
include/uapi/linux/sctp.h +4 -0
@@ -763,6 +763,8 @@ enum sctp_spp_flags {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 */ +SPP_IPV6_FLOWLABEL =1 <<8 , + SPP_DSCP = 1<<9, }; struct sctp_paddrparams {
@@ -773,6 +775,8 @@ struct sctp_paddrparams {__u32 spp_pathmtu;__u32 spp_sackdelay;__u32 spp_flags; +__u32 spp_ipv6_flowlabel; +__u8 spp_dscp; } __attribute__((packed, aligned(4)));/*
net/sctp/socket.c +171 -6
233 lines not on this page · raw message
Signature · 1 line
2.1.0
Xin Long
maintainerPATCH v2 4/5 sctp: add support for setting flowlabel when adding a transport
Struct sockaddr_in6 has the member sin6_flowinfo that includes the ipv6 flowlabel, it should also support for setting flowlabel when adding a transport whose ipaddr is from userspace.
Note that addrinfo in sctp_sendmsg is using struct in6_addr for the secondary addrs, which doesn't contain sin6_flowinfo, and it needs to copy sin6_flowinfo from the primary addr.
--- net/sctp/associola.c | 12 ++++++++++-- net/sctp/socket.c | 5 +++++ 2 files changed, 15 insertions(+), 2 deletions(-)
net/sctp/associola.c +10 -2
@@ -650,8 +650,16 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, peer->sackdelay = asoc->sackdelay; peer->sackfreq = asoc->sackfreq; -if (addr->sa.sa_family =AF_INET6 ) - peer->flowlabel = asoc->flowlabel; +if (addr->sa.sa_family =AF_INET6 ) { +__be32 info = addr->v6.sin6_flowinfo; + +if (info) { + peer->flowlabel =ntohl (info &IPV6_FLOWLABEL_MASK ); + peer->flowlabel |=SCTP_FLOWLABEL_SET_MASK ; + }else { + peer->flowlabel = asoc->flowlabel; + } + } peer->dscp = asoc->dscp;/* Enable/disable heartbeat, SACK delay, and path MTU discovery
net/sctp/socket.c +5 -0
@@ -1697,6 +1697,7 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags,struct sctp_association *asoc;enum sctp_scope scope;struct cmsghdr *cmsg; +__be32 flowinfo =0 ;struct sctp_af *af;int err;
@@ -1781,6 +1782,9 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags,if (!cmsgs->addrs_msg)return 0 ; +if (daddr->sa.sa_family =AF_INET6 ) + flowinfo = daddr->v6.sin6_flowinfo; +/* sendv addr list parse */ for_each_cmsghdr (cmsg, cmsgs->addrs_msg) {struct sctp_transport *transport;
@@ -1813,6 +1817,7 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags, } dlen =sizeof (struct in6_addr ); + daddr->v6.sin6_flowinfo = flowinfo; daddr->v6.sin6_family =AF_INET6 ; daddr->v6.sin6_port =htons (asoc->peer.port);memcpy (&daddr->v6.sin6_addr,CMSG_DATA (cmsg), dlen);
Signature · 1 line
2.1.0
Xin Long
maintainerPATCH v2 5/5 sctp: check for ipv6_pinfo legal sndflow with flowlabel in sctp_v6_get_dst
The transport with illegal flowlabel should not be allowed to send packets. Other transport protocols already denies this.
--- net/sctp/ipv6.c | 9 +++++++++ 1 file changed, 9 insertions(+)
net/sctp/ipv6.c +9 -0
@@ -262,6 +262,15 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,if (t->flowlabel &SCTP_FLOWLABEL_SET_MASK ) fl6->flowlabel =htonl (t->flowlabel &SCTP_FLOWLABEL_VAL_MASK ); +if (np->sndflow && (fl6->flowlabel &IPV6_FLOWLABEL_MASK )) { +struct ip6_flowlabel *flowlabel; + + flowlabel =fl6_sock_lookup (sk, fl6->flowlabel); +if (!flowlabel) + goto out; +fl6_sock_release (flowlabel); + } +pr_debug ("%s: dst=%pI6 " , __func__, &fl6->daddr);if (asoc)
Signature · 1 line
2.1.0
Quoted 11 lines · Xin Long
Now dscp and flowlabel are set from sock when sending the packets, but being multi-homing, sctp also supports for dscp and flowlabel per transport, which is described in section 8.1.12 in RFC6458.
v1->v2:
- defineip_queue_xmitas inline innet/ip.h, instead of exporting it in Patch 1/5 according to David's suggestion.
- fix the param len check in sctp_s/getsockopt_peer_addr_params() in Patch 3/5 to guarantee that an old app built with old kernel headers could work on the newer kernel per Marcelo's point.
Quoted 7 lines
Xin Long (5):
ipv4: add__ip_queue_xmit()that supports tos param
sctp: add support for dscp and flowlabel per transport
sctp: addspp_ipv6_flowlabelandspp_dscpforsctp_paddrparams
sctp: add support for setting flowlabel when adding a transport
sctp: check foripv6_pinfolegal sndflow with flowlabel insctp_v6_get_dst
Series
Quoted 19 lines · Xin Long
Now dscp and flowlabel are set from sock when sending the packets, but being multi-homing, sctp also supports for dscp and flowlabel per transport, which is described in section 8.1.12 in RFC6458.
v1->v2:
- defineip_queue_xmitas inline innet/ip.h, instead of exporting it in Patch 1/5 according to David's suggestion.
- fix the param len check in sctp_s/getsockopt_peer_addr_params() in Patch 3/5 to guarantee that an old app built with old kernel headers could work on the newer kernel per Marcelo's point.Xin Long (5):
ipv4: add__ip_queue_xmit()that supports tos param
sctp: add support for dscp and flowlabel per transport
sctp: addspp_ipv6_flowlabelandspp_dscpforsctp_paddrparams
sctp: add support for setting flowlabel when adding a transport
sctp: check foripv6_pinfolegal sndflow with flowlabel insctp_v6_get_dst
Quoted 15 lines
include/linux/sctp.h | 7 ++ include/net/ip.h | 9 ++- include/net/sctp/structs.h | 9 +++ include/uapi/linux/sctp.h | 4 + net/ipv4/ip_output.c | 9 ++- net/sctp/associola.c | 15 ++++ net/sctp/ipv6.c | 20 ++++- net/sctp/protocol.c | 16 +++- net/sctp/socket.c | 182 +++++++++++++++++++++++++++++++++++++++++++-- 9 files changed, 254 insertions(+), 17 deletions(-)Signature · 1 line
2.1.0
For the Series