diff options
author | Xin Long <lucien.xin@gmail.com> | 2018-07-02 06:21:12 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-07-03 22:36:54 -0400 |
commit | 8a9c58d28d0f66569737a3295116710ed24573cd (patch) | |
tree | 4d530788207cca98e68faee6d5a4145d5d8befc4 | |
parent | 69b9e1e07d98b57b972df3c44647ca8795284d39 (diff) |
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>
-rw-r--r-- | include/linux/sctp.h | 7 | ||||
-rw-r--r-- | include/net/sctp/structs.h | 9 | ||||
-rw-r--r-- | net/sctp/associola.c | 7 | ||||
-rw-r--r-- | net/sctp/ipv6.c | 11 | ||||
-rw-r--r-- | net/sctp/protocol.c | 16 |
5 files changed, 44 insertions, 6 deletions
diff --git a/include/linux/sctp.h b/include/linux/sctp.h index b36c76635f18..83d94341e003 100644 --- a/include/linux/sctp.h +++ b/include/linux/sctp.h | |||
@@ -801,4 +801,11 @@ struct sctp_strreset_resptsn { | |||
801 | __be32 receivers_next_tsn; | 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 | #endif /* __LINUX_SCTP_H__ */ | 811 | #endif /* __LINUX_SCTP_H__ */ |
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 701a51736fa5..ab869e0d8326 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h | |||
@@ -193,6 +193,9 @@ struct sctp_sock { | |||
193 | /* This is the max_retrans value for new associations. */ | 193 | /* This is the max_retrans value for new associations. */ |
194 | __u16 pathmaxrxt; | 194 | __u16 pathmaxrxt; |
195 | 195 | ||
196 | __u32 flowlabel; | ||
197 | __u8 dscp; | ||
198 | |||
196 | /* The initial Path MTU to use for new associations. */ | 199 | /* The initial Path MTU to use for new associations. */ |
197 | __u32 pathmtu; | 200 | __u32 pathmtu; |
198 | 201 | ||
@@ -895,6 +898,9 @@ struct sctp_transport { | |||
895 | */ | 898 | */ |
896 | __u16 pathmaxrxt; | 899 | __u16 pathmaxrxt; |
897 | 900 | ||
901 | __u32 flowlabel; | ||
902 | __u8 dscp; | ||
903 | |||
898 | /* This is the partially failed retrans value for the transport | 904 | /* This is the partially failed retrans value for the transport |
899 | * and will be initialized from the assocs value. This can be changed | 905 | * and will be initialized from the assocs value. This can be changed |
900 | * using the SCTP_PEER_ADDR_THLDS socket option | 906 | * using the SCTP_PEER_ADDR_THLDS socket option |
@@ -1772,6 +1778,9 @@ struct sctp_association { | |||
1772 | */ | 1778 | */ |
1773 | __u16 pathmaxrxt; | 1779 | __u16 pathmaxrxt; |
1774 | 1780 | ||
1781 | __u32 flowlabel; | ||
1782 | __u8 dscp; | ||
1783 | |||
1775 | /* Flag that path mtu update is pending */ | 1784 | /* Flag that path mtu update is pending */ |
1776 | __u8 pmtu_pending; | 1785 | __u8 pmtu_pending; |
1777 | 1786 | ||
diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 5d5a16204d50..16ecfbc95614 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c | |||
@@ -115,6 +115,9 @@ static struct sctp_association *sctp_association_init( | |||
115 | /* Initialize path max retrans value. */ | 115 | /* Initialize path max retrans value. */ |
116 | asoc->pathmaxrxt = sp->pathmaxrxt; | 116 | asoc->pathmaxrxt = sp->pathmaxrxt; |
117 | 117 | ||
118 | asoc->flowlabel = sp->flowlabel; | ||
119 | asoc->dscp = sp->dscp; | ||
120 | |||
118 | /* Initialize default path MTU. */ | 121 | /* Initialize default path MTU. */ |
119 | asoc->pathmtu = sp->pathmtu; | 122 | asoc->pathmtu = sp->pathmtu; |
120 | 123 | ||
@@ -647,6 +650,10 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, | |||
647 | peer->sackdelay = asoc->sackdelay; | 650 | peer->sackdelay = asoc->sackdelay; |
648 | peer->sackfreq = asoc->sackfreq; | 651 | peer->sackfreq = asoc->sackfreq; |
649 | 652 | ||
653 | if (addr->sa.sa_family == AF_INET6) | ||
654 | peer->flowlabel = asoc->flowlabel; | ||
655 | peer->dscp = asoc->dscp; | ||
656 | |||
650 | /* Enable/disable heartbeat, SACK delay, and path MTU discovery | 657 | /* Enable/disable heartbeat, SACK delay, and path MTU discovery |
651 | * based on association setting. | 658 | * based on association setting. |
652 | */ | 659 | */ |
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 0cd2e764f47f..38102bf7f13e 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c | |||
@@ -209,12 +209,17 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport) | |||
209 | struct sock *sk = skb->sk; | 209 | struct sock *sk = skb->sk; |
210 | struct ipv6_pinfo *np = inet6_sk(sk); | 210 | struct ipv6_pinfo *np = inet6_sk(sk); |
211 | struct flowi6 *fl6 = &transport->fl.u.ip6; | 211 | struct flowi6 *fl6 = &transport->fl.u.ip6; |
212 | __u8 tclass = np->tclass; | ||
212 | int res; | 213 | int res; |
213 | 214 | ||
214 | pr_debug("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n", __func__, skb, | 215 | pr_debug("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n", __func__, skb, |
215 | skb->len, &fl6->saddr, &fl6->daddr); | 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 | if (!(transport->param_flags & SPP_PMTUD_ENABLE)) | 224 | if (!(transport->param_flags & SPP_PMTUD_ENABLE)) |
220 | skb->ignore_df = 1; | 225 | skb->ignore_df = 1; |
@@ -223,7 +228,7 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport) | |||
223 | 228 | ||
224 | rcu_read_lock(); | 229 | rcu_read_lock(); |
225 | res = ip6_xmit(sk, skb, fl6, sk->sk_mark, rcu_dereference(np->opt), | 230 | res = ip6_xmit(sk, skb, fl6, sk->sk_mark, rcu_dereference(np->opt), |
226 | np->tclass); | 231 | tclass); |
227 | rcu_read_unlock(); | 232 | rcu_read_unlock(); |
228 | return res; | 233 | return res; |
229 | } | 234 | } |
@@ -254,6 +259,8 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, | |||
254 | fl6->flowi6_oif = daddr->v6.sin6_scope_id; | 259 | fl6->flowi6_oif = daddr->v6.sin6_scope_id; |
255 | else if (asoc) | 260 | else if (asoc) |
256 | fl6->flowi6_oif = asoc->base.sk->sk_bound_dev_if; | 261 | fl6->flowi6_oif = asoc->base.sk->sk_bound_dev_if; |
262 | if (t->flowlabel & SCTP_FLOWLABEL_SET_MASK) | ||
263 | fl6->flowlabel = htonl(t->flowlabel & SCTP_FLOWLABEL_VAL_MASK); | ||
257 | 264 | ||
258 | pr_debug("%s: dst=%pI6 ", __func__, &fl6->daddr); | 265 | pr_debug("%s: dst=%pI6 ", __func__, &fl6->daddr); |
259 | 266 | ||
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 67f73d3a1356..e948db29ab53 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c | |||
@@ -426,13 +426,16 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr, | |||
426 | struct dst_entry *dst = NULL; | 426 | struct dst_entry *dst = NULL; |
427 | union sctp_addr *daddr = &t->ipaddr; | 427 | union sctp_addr *daddr = &t->ipaddr; |
428 | union sctp_addr dst_saddr; | 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 | memset(fl4, 0x0, sizeof(struct flowi4)); | 433 | memset(fl4, 0x0, sizeof(struct flowi4)); |
431 | fl4->daddr = daddr->v4.sin_addr.s_addr; | 434 | fl4->daddr = daddr->v4.sin_addr.s_addr; |
432 | fl4->fl4_dport = daddr->v4.sin_port; | 435 | fl4->fl4_dport = daddr->v4.sin_port; |
433 | fl4->flowi4_proto = IPPROTO_SCTP; | 436 | fl4->flowi4_proto = IPPROTO_SCTP; |
434 | if (asoc) { | 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 | fl4->flowi4_oif = asoc->base.sk->sk_bound_dev_if; | 439 | fl4->flowi4_oif = asoc->base.sk->sk_bound_dev_if; |
437 | fl4->fl4_sport = htons(asoc->base.bind_addr.port); | 440 | fl4->fl4_sport = htons(asoc->base.bind_addr.port); |
438 | } | 441 | } |
@@ -495,7 +498,7 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr, | |||
495 | fl4->fl4_sport = laddr->a.v4.sin_port; | 498 | fl4->fl4_sport = laddr->a.v4.sin_port; |
496 | flowi4_update_output(fl4, | 499 | flowi4_update_output(fl4, |
497 | asoc->base.sk->sk_bound_dev_if, | 500 | asoc->base.sk->sk_bound_dev_if, |
498 | RT_CONN_FLAGS(asoc->base.sk), | 501 | RT_CONN_FLAGS_TOS(asoc->base.sk, tos), |
499 | daddr->v4.sin_addr.s_addr, | 502 | daddr->v4.sin_addr.s_addr, |
500 | laddr->a.v4.sin_addr.s_addr); | 503 | laddr->a.v4.sin_addr.s_addr); |
501 | 504 | ||
@@ -971,16 +974,21 @@ static inline int sctp_v4_xmit(struct sk_buff *skb, | |||
971 | struct sctp_transport *transport) | 974 | struct sctp_transport *transport) |
972 | { | 975 | { |
973 | struct inet_sock *inet = inet_sk(skb->sk); | 976 | struct inet_sock *inet = inet_sk(skb->sk); |
977 | __u8 dscp = inet->tos; | ||
974 | 978 | ||
975 | pr_debug("%s: skb:%p, len:%d, src:%pI4, dst:%pI4\n", __func__, skb, | 979 | pr_debug("%s: skb:%p, len:%d, src:%pI4, dst:%pI4\n", __func__, skb, |
976 | skb->len, &transport->fl.u.ip4.saddr, &transport->fl.u.ip4.daddr); | 980 | skb->len, &transport->fl.u.ip4.saddr, |
981 | &transport->fl.u.ip4.daddr); | ||
982 | |||
983 | if (transport->dscp & SCTP_DSCP_SET_MASK) | ||
984 | dscp = transport->dscp & SCTP_DSCP_VAL_MASK; | ||
977 | 985 | ||
978 | inet->pmtudisc = transport->param_flags & SPP_PMTUD_ENABLE ? | 986 | inet->pmtudisc = transport->param_flags & SPP_PMTUD_ENABLE ? |
979 | IP_PMTUDISC_DO : IP_PMTUDISC_DONT; | 987 | IP_PMTUDISC_DO : IP_PMTUDISC_DONT; |
980 | 988 | ||
981 | SCTP_INC_STATS(sock_net(&inet->sk), SCTP_MIB_OUTSCTPPACKS); | 989 | SCTP_INC_STATS(sock_net(&inet->sk), SCTP_MIB_OUTSCTPPACKS); |
982 | 990 | ||
983 | return ip_queue_xmit(&inet->sk, skb, &transport->fl); | 991 | return __ip_queue_xmit(&inet->sk, skb, &transport->fl, dscp); |
984 | } | 992 | } |
985 | 993 | ||
986 | static struct sctp_af sctp_af_inet; | 994 | static struct sctp_af sctp_af_inet; |