Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Xin Long and committed by
David S. Miller
8a9c58d2 69b9e1e0

+44 -6
+7
include/linux/sctp.h
··· 801 801 __be32 receivers_next_tsn; 802 802 }; 803 803 804 + enum { 805 + SCTP_DSCP_SET_MASK = 0x1, 806 + SCTP_DSCP_VAL_MASK = 0xfc, 807 + SCTP_FLOWLABEL_SET_MASK = 0x100000, 808 + SCTP_FLOWLABEL_VAL_MASK = 0xfffff 809 + }; 810 + 804 811 #endif /* __LINUX_SCTP_H__ */
+9
include/net/sctp/structs.h
··· 193 193 /* This is the max_retrans value for new associations. */ 194 194 __u16 pathmaxrxt; 195 195 196 + __u32 flowlabel; 197 + __u8 dscp; 198 + 196 199 /* The initial Path MTU to use for new associations. */ 197 200 __u32 pathmtu; 198 201 ··· 897 894 * using the SCTP_SET_PEER_ADDR_PARAMS socket option. 898 895 */ 899 896 __u16 pathmaxrxt; 897 + 898 + __u32 flowlabel; 899 + __u8 dscp; 900 900 901 901 /* This is the partially failed retrans value for the transport 902 902 * and will be initialized from the assocs value. This can be changed ··· 1777 1771 * association. 1778 1772 */ 1779 1773 __u16 pathmaxrxt; 1774 + 1775 + __u32 flowlabel; 1776 + __u8 dscp; 1780 1777 1781 1778 /* Flag that path mtu update is pending */ 1782 1779 __u8 pmtu_pending;
+7
net/sctp/associola.c
··· 115 115 /* Initialize path max retrans value. */ 116 116 asoc->pathmaxrxt = sp->pathmaxrxt; 117 117 118 + asoc->flowlabel = sp->flowlabel; 119 + asoc->dscp = sp->dscp; 120 + 118 121 /* Initialize default path MTU. */ 119 122 asoc->pathmtu = sp->pathmtu; 120 123 ··· 649 646 */ 650 647 peer->sackdelay = asoc->sackdelay; 651 648 peer->sackfreq = asoc->sackfreq; 649 + 650 + if (addr->sa.sa_family == AF_INET6) 651 + peer->flowlabel = asoc->flowlabel; 652 + peer->dscp = asoc->dscp; 652 653 653 654 /* Enable/disable heartbeat, SACK delay, and path MTU discovery 654 655 * based on association setting.
+9 -2
net/sctp/ipv6.c
··· 209 209 struct sock *sk = skb->sk; 210 210 struct ipv6_pinfo *np = inet6_sk(sk); 211 211 struct flowi6 *fl6 = &transport->fl.u.ip6; 212 + __u8 tclass = np->tclass; 212 213 int res; 213 214 214 215 pr_debug("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n", __func__, skb, 215 216 skb->len, &fl6->saddr, &fl6->daddr); 216 217 217 - IP6_ECN_flow_xmit(sk, fl6->flowlabel); 218 + if (transport->dscp & SCTP_DSCP_SET_MASK) 219 + tclass = transport->dscp & SCTP_DSCP_VAL_MASK; 220 + 221 + if (INET_ECN_is_capable(tclass)) 222 + IP6_ECN_flow_xmit(sk, fl6->flowlabel); 218 223 219 224 if (!(transport->param_flags & SPP_PMTUD_ENABLE)) 220 225 skb->ignore_df = 1; ··· 228 223 229 224 rcu_read_lock(); 230 225 res = ip6_xmit(sk, skb, fl6, sk->sk_mark, rcu_dereference(np->opt), 231 - np->tclass); 226 + tclass); 232 227 rcu_read_unlock(); 233 228 return res; 234 229 } ··· 259 254 fl6->flowi6_oif = daddr->v6.sin6_scope_id; 260 255 else if (asoc) 261 256 fl6->flowi6_oif = asoc->base.sk->sk_bound_dev_if; 257 + if (t->flowlabel & SCTP_FLOWLABEL_SET_MASK) 258 + fl6->flowlabel = htonl(t->flowlabel & SCTP_FLOWLABEL_VAL_MASK); 262 259 263 260 pr_debug("%s: dst=%pI6 ", __func__, &fl6->daddr); 264 261
+12 -4
net/sctp/protocol.c
··· 426 426 struct dst_entry *dst = NULL; 427 427 union sctp_addr *daddr = &t->ipaddr; 428 428 union sctp_addr dst_saddr; 429 + __u8 tos = inet_sk(sk)->tos; 429 430 431 + if (t->dscp & SCTP_DSCP_SET_MASK) 432 + tos = t->dscp & SCTP_DSCP_VAL_MASK; 430 433 memset(fl4, 0x0, sizeof(struct flowi4)); 431 434 fl4->daddr = daddr->v4.sin_addr.s_addr; 432 435 fl4->fl4_dport = daddr->v4.sin_port; 433 436 fl4->flowi4_proto = IPPROTO_SCTP; 434 437 if (asoc) { 435 - fl4->flowi4_tos = RT_CONN_FLAGS(asoc->base.sk); 438 + fl4->flowi4_tos = RT_CONN_FLAGS_TOS(asoc->base.sk, tos); 436 439 fl4->flowi4_oif = asoc->base.sk->sk_bound_dev_if; 437 440 fl4->fl4_sport = htons(asoc->base.bind_addr.port); 438 441 } ··· 498 495 fl4->fl4_sport = laddr->a.v4.sin_port; 499 496 flowi4_update_output(fl4, 500 497 asoc->base.sk->sk_bound_dev_if, 501 - RT_CONN_FLAGS(asoc->base.sk), 498 + RT_CONN_FLAGS_TOS(asoc->base.sk, tos), 502 499 daddr->v4.sin_addr.s_addr, 503 500 laddr->a.v4.sin_addr.s_addr); 504 501 ··· 974 971 struct sctp_transport *transport) 975 972 { 976 973 struct inet_sock *inet = inet_sk(skb->sk); 974 + __u8 dscp = inet->tos; 977 975 978 976 pr_debug("%s: skb:%p, len:%d, src:%pI4, dst:%pI4\n", __func__, skb, 979 - skb->len, &transport->fl.u.ip4.saddr, &transport->fl.u.ip4.daddr); 977 + skb->len, &transport->fl.u.ip4.saddr, 978 + &transport->fl.u.ip4.daddr); 979 + 980 + if (transport->dscp & SCTP_DSCP_SET_MASK) 981 + dscp = transport->dscp & SCTP_DSCP_VAL_MASK; 980 982 981 983 inet->pmtudisc = transport->param_flags & SPP_PMTUD_ENABLE ? 982 984 IP_PMTUDISC_DO : IP_PMTUDISC_DONT; 983 985 984 986 SCTP_INC_STATS(sock_net(&inet->sk), SCTP_MIB_OUTSCTPPACKS); 985 987 986 - return ip_queue_xmit(&inet->sk, skb, &transport->fl); 988 + return __ip_queue_xmit(&inet->sk, skb, &transport->fl, dscp); 987 989 } 988 990 989 991 static struct sctp_af sctp_af_inet;