Skip to content

Commit 2bdea15

Browse files
committed
Merge branch 'sctp-fully-support-for-dscp-and-flowlabel-per-transport'
Xin Long says: ==================== 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. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
2 parents 05bd97f + 0999f02 commit 2bdea15

File tree

9 files changed

+254
-17
lines changed

9 files changed

+254
-17
lines changed

include/linux/sctp.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -801,4 +801,11 @@ struct sctp_strreset_resptsn {
801801
__be32 receivers_next_tsn;
802802
};
803803

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+
804811
#endif /* __LINUX_SCTP_H__ */

include/net/ip.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,8 @@ void ip_send_check(struct iphdr *ip);
148148
int __ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb);
149149
int ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb);
150150

151-
int ip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl);
151+
int __ip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
152+
__u8 tos);
152153
void ip_init(void);
153154
int ip_append_data(struct sock *sk, struct flowi4 *fl4,
154155
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,
174175
struct ipcm_cookie *ipc, struct rtable **rtp,
175176
struct inet_cork *cork, unsigned int flags);
176177

178+
static inline int ip_queue_xmit(struct sock *sk, struct sk_buff *skb,
179+
struct flowi *fl)
180+
{
181+
return __ip_queue_xmit(sk, skb, fl, inet_sk(sk)->tos);
182+
}
183+
177184
static inline struct sk_buff *ip_finish_skb(struct sock *sk, struct flowi4 *fl4)
178185
{
179186
return __ip_make_skb(sk, fl4, &sk->sk_write_queue, &inet_sk(sk)->cork.base);

include/net/sctp/structs.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,9 @@ struct sctp_sock {
193193
/* This is the max_retrans value for new associations. */
194194
__u16 pathmaxrxt;
195195

196+
__u32 flowlabel;
197+
__u8 dscp;
198+
196199
/* The initial Path MTU to use for new associations. */
197200
__u32 pathmtu;
198201

@@ -895,6 +898,9 @@ struct sctp_transport {
895898
*/
896899
__u16 pathmaxrxt;
897900

901+
__u32 flowlabel;
902+
__u8 dscp;
903+
898904
/* This is the partially failed retrans value for the transport
899905
* and will be initialized from the assocs value. This can be changed
900906
* using the SCTP_PEER_ADDR_THLDS socket option
@@ -1772,6 +1778,9 @@ struct sctp_association {
17721778
*/
17731779
__u16 pathmaxrxt;
17741780

1781+
__u32 flowlabel;
1782+
__u8 dscp;
1783+
17751784
/* Flag that path mtu update is pending */
17761785
__u8 pmtu_pending;
17771786

include/uapi/linux/sctp.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,8 @@ enum sctp_spp_flags {
763763
SPP_SACKDELAY_DISABLE = 1<<6, /*Disable SACK*/
764764
SPP_SACKDELAY = SPP_SACKDELAY_ENABLE | SPP_SACKDELAY_DISABLE,
765765
SPP_HB_TIME_IS_ZERO = 1<<7, /* Set HB delay to 0 */
766+
SPP_IPV6_FLOWLABEL = 1<<8,
767+
SPP_DSCP = 1<<9,
766768
};
767769

768770
struct sctp_paddrparams {
@@ -773,6 +775,8 @@ struct sctp_paddrparams {
773775
__u32 spp_pathmtu;
774776
__u32 spp_sackdelay;
775777
__u32 spp_flags;
778+
__u32 spp_ipv6_flowlabel;
779+
__u8 spp_dscp;
776780
} __attribute__((packed, aligned(4)));
777781

778782
/*

net/ipv4/ip_output.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,8 @@ static void ip_copy_addrs(struct iphdr *iph, const struct flowi4 *fl4)
423423
}
424424

425425
/* Note: skb->sk can be different from sk, in case of tunnels */
426-
int ip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl)
426+
int __ip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
427+
__u8 tos)
427428
{
428429
struct inet_sock *inet = inet_sk(sk);
429430
struct net *net = sock_net(sk);
@@ -462,7 +463,7 @@ int ip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl)
462463
inet->inet_dport,
463464
inet->inet_sport,
464465
sk->sk_protocol,
465-
RT_CONN_FLAGS(sk),
466+
RT_CONN_FLAGS_TOS(sk, tos),
466467
sk->sk_bound_dev_if);
467468
if (IS_ERR(rt))
468469
goto no_route;
@@ -478,7 +479,7 @@ int ip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl)
478479
skb_push(skb, sizeof(struct iphdr) + (inet_opt ? inet_opt->opt.optlen : 0));
479480
skb_reset_network_header(skb);
480481
iph = ip_hdr(skb);
481-
*((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff));
482+
*((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (tos & 0xff));
482483
if (ip_dont_fragment(sk, &rt->dst) && !skb->ignore_df)
483484
iph->frag_off = htons(IP_DF);
484485
else
@@ -511,7 +512,7 @@ int ip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl)
511512
kfree_skb(skb);
512513
return -EHOSTUNREACH;
513514
}
514-
EXPORT_SYMBOL(ip_queue_xmit);
515+
EXPORT_SYMBOL(__ip_queue_xmit);
515516

516517
static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
517518
{

net/sctp/associola.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ static struct sctp_association *sctp_association_init(
115115
/* Initialize path max retrans value. */
116116
asoc->pathmaxrxt = sp->pathmaxrxt;
117117

118+
asoc->flowlabel = sp->flowlabel;
119+
asoc->dscp = sp->dscp;
120+
118121
/* Initialize default path MTU. */
119122
asoc->pathmtu = sp->pathmtu;
120123

@@ -647,6 +650,18 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
647650
peer->sackdelay = asoc->sackdelay;
648651
peer->sackfreq = asoc->sackfreq;
649652

653+
if (addr->sa.sa_family == AF_INET6) {
654+
__be32 info = addr->v6.sin6_flowinfo;
655+
656+
if (info) {
657+
peer->flowlabel = ntohl(info & IPV6_FLOWLABEL_MASK);
658+
peer->flowlabel |= SCTP_FLOWLABEL_SET_MASK;
659+
} else {
660+
peer->flowlabel = asoc->flowlabel;
661+
}
662+
}
663+
peer->dscp = asoc->dscp;
664+
650665
/* Enable/disable heartbeat, SACK delay, and path MTU discovery
651666
* based on association setting.
652667
*/

net/sctp/ipv6.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,12 +209,17 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport)
209209
struct sock *sk = skb->sk;
210210
struct ipv6_pinfo *np = inet6_sk(sk);
211211
struct flowi6 *fl6 = &transport->fl.u.ip6;
212+
__u8 tclass = np->tclass;
212213
int res;
213214

214215
pr_debug("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n", __func__, skb,
215216
skb->len, &fl6->saddr, &fl6->daddr);
216217

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);
218223

219224
if (!(transport->param_flags & SPP_PMTUD_ENABLE))
220225
skb->ignore_df = 1;
@@ -223,7 +228,7 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport)
223228

224229
rcu_read_lock();
225230
res = ip6_xmit(sk, skb, fl6, sk->sk_mark, rcu_dereference(np->opt),
226-
np->tclass);
231+
tclass);
227232
rcu_read_unlock();
228233
return res;
229234
}
@@ -254,6 +259,17 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
254259
fl6->flowi6_oif = daddr->v6.sin6_scope_id;
255260
else if (asoc)
256261
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);
264+
265+
if (np->sndflow && (fl6->flowlabel & IPV6_FLOWLABEL_MASK)) {
266+
struct ip6_flowlabel *flowlabel;
267+
268+
flowlabel = fl6_sock_lookup(sk, fl6->flowlabel);
269+
if (!flowlabel)
270+
goto out;
271+
fl6_sock_release(flowlabel);
272+
}
257273

258274
pr_debug("%s: dst=%pI6 ", __func__, &fl6->daddr);
259275

net/sctp/protocol.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -426,13 +426,16 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
426426
struct dst_entry *dst = NULL;
427427
union sctp_addr *daddr = &t->ipaddr;
428428
union sctp_addr dst_saddr;
429+
__u8 tos = inet_sk(sk)->tos;
429430

431+
if (t->dscp & SCTP_DSCP_SET_MASK)
432+
tos = t->dscp & SCTP_DSCP_VAL_MASK;
430433
memset(fl4, 0x0, sizeof(struct flowi4));
431434
fl4->daddr = daddr->v4.sin_addr.s_addr;
432435
fl4->fl4_dport = daddr->v4.sin_port;
433436
fl4->flowi4_proto = IPPROTO_SCTP;
434437
if (asoc) {
435-
fl4->flowi4_tos = RT_CONN_FLAGS(asoc->base.sk);
438+
fl4->flowi4_tos = RT_CONN_FLAGS_TOS(asoc->base.sk, tos);
436439
fl4->flowi4_oif = asoc->base.sk->sk_bound_dev_if;
437440
fl4->fl4_sport = htons(asoc->base.bind_addr.port);
438441
}
@@ -495,7 +498,7 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
495498
fl4->fl4_sport = laddr->a.v4.sin_port;
496499
flowi4_update_output(fl4,
497500
asoc->base.sk->sk_bound_dev_if,
498-
RT_CONN_FLAGS(asoc->base.sk),
501+
RT_CONN_FLAGS_TOS(asoc->base.sk, tos),
499502
daddr->v4.sin_addr.s_addr,
500503
laddr->a.v4.sin_addr.s_addr);
501504

@@ -971,16 +974,21 @@ static inline int sctp_v4_xmit(struct sk_buff *skb,
971974
struct sctp_transport *transport)
972975
{
973976
struct inet_sock *inet = inet_sk(skb->sk);
977+
__u8 dscp = inet->tos;
974978

975979
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;
977985

978986
inet->pmtudisc = transport->param_flags & SPP_PMTUD_ENABLE ?
979987
IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
980988

981989
SCTP_INC_STATS(sock_net(&inet->sk), SCTP_MIB_OUTSCTPPACKS);
982990

983-
return ip_queue_xmit(&inet->sk, skb, &transport->fl);
991+
return __ip_queue_xmit(&inet->sk, skb, &transport->fl, dscp);
984992
}
985993

986994
static struct sctp_af sctp_af_inet;

0 commit comments

Comments
 (0)