aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorent Fourcot <florent.fourcot@enst-bretagne.fr>2014-01-17 11:15:03 -0500
committerDavid S. Miller <davem@davemloft.net>2014-01-19 20:12:31 -0500
commitdf3687ffc6653e4d32168338b4dee20c164ed7c9 (patch)
tree5600a02ddadc63d45a49964db3f9ac02f34e29e6
parent3acfa1e73c2a2cbf1fda7aef0c6c2c9281ce9db2 (diff)
ipv6: add the IPV6_FL_F_REFLECT flag to IPV6_FL_A_GET
With this option, the socket will reply with the flow label value read on received packets. The goal is to have a connection with the same flow label in both direction of the communication. Changelog of V4: * Do not erase the flow label on the listening socket. Use pktopts to store the received value Signed-off-by: Florent Fourcot <florent.fourcot@enst-bretagne.fr> Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/ipv6.h1
-rw-r--r--include/uapi/linux/in6.h1
-rw-r--r--net/ipv6/ip6_flowlabel.c21
-rw-r--r--net/ipv6/tcp_ipv6.c12
4 files changed, 34 insertions, 1 deletions
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 7e1ded0d8e45..1084304fd75a 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -191,6 +191,7 @@ struct ipv6_pinfo {
191 /* sockopt flags */ 191 /* sockopt flags */
192 __u16 recverr:1, 192 __u16 recverr:1,
193 sndflow:1, 193 sndflow:1,
194 repflow:1,
194 pmtudisc:3, 195 pmtudisc:3,
195 ipv6only:1, 196 ipv6only:1,
196 srcprefs:3, /* 001: prefer temporary address 197 srcprefs:3, /* 001: prefer temporary address
diff --git a/include/uapi/linux/in6.h b/include/uapi/linux/in6.h
index f94f1d013bf2..02c0cd685a27 100644
--- a/include/uapi/linux/in6.h
+++ b/include/uapi/linux/in6.h
@@ -85,6 +85,7 @@ struct in6_flowlabel_req {
85 85
86#define IPV6_FL_F_CREATE 1 86#define IPV6_FL_F_CREATE 1
87#define IPV6_FL_F_EXCL 2 87#define IPV6_FL_F_EXCL 2
88#define IPV6_FL_F_REFLECT 4
88 89
89#define IPV6_FL_S_NONE 0 90#define IPV6_FL_S_NONE 0
90#define IPV6_FL_S_EXCL 1 91#define IPV6_FL_S_EXCL 1
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index cbc93517b455..55823f187446 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -486,6 +486,11 @@ int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq)
486 struct ipv6_pinfo *np = inet6_sk(sk); 486 struct ipv6_pinfo *np = inet6_sk(sk);
487 struct ipv6_fl_socklist *sfl; 487 struct ipv6_fl_socklist *sfl;
488 488
489 if (np->repflow) {
490 freq->flr_label = np->flow_label;
491 return 0;
492 }
493
489 rcu_read_lock_bh(); 494 rcu_read_lock_bh();
490 495
491 for_each_sk_fl_rcu(np, sfl) { 496 for_each_sk_fl_rcu(np, sfl) {
@@ -527,6 +532,15 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen)
527 532
528 switch (freq.flr_action) { 533 switch (freq.flr_action) {
529 case IPV6_FL_A_PUT: 534 case IPV6_FL_A_PUT:
535 if (freq.flr_flags & IPV6_FL_F_REFLECT) {
536 if (sk->sk_protocol != IPPROTO_TCP)
537 return -ENOPROTOOPT;
538 if (!np->repflow)
539 return -ESRCH;
540 np->flow_label = 0;
541 np->repflow = 0;
542 return 0;
543 }
530 spin_lock_bh(&ip6_sk_fl_lock); 544 spin_lock_bh(&ip6_sk_fl_lock);
531 for (sflp = &np->ipv6_fl_list; 545 for (sflp = &np->ipv6_fl_list;
532 (sfl = rcu_dereference(*sflp))!=NULL; 546 (sfl = rcu_dereference(*sflp))!=NULL;
@@ -567,6 +581,13 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen)
567 return -ESRCH; 581 return -ESRCH;
568 582
569 case IPV6_FL_A_GET: 583 case IPV6_FL_A_GET:
584 if (freq.flr_flags & IPV6_FL_F_REFLECT) {
585 if (sk->sk_protocol != IPPROTO_TCP)
586 return -ENOPROTOOPT;
587 np->repflow = 1;
588 return 0;
589 }
590
570 if (freq.flr_label & ~IPV6_FLOWLABEL_MASK) 591 if (freq.flr_label & ~IPV6_FLOWLABEL_MASK)
571 return -EINVAL; 592 return -EINVAL;
572 593
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index b5512696e9ed..b61fa8bac3bd 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -483,6 +483,9 @@ static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst,
483 &ireq->ir_v6_rmt_addr); 483 &ireq->ir_v6_rmt_addr);
484 484
485 fl6->daddr = ireq->ir_v6_rmt_addr; 485 fl6->daddr = ireq->ir_v6_rmt_addr;
486 if (np->repflow && (ireq->pktopts != NULL))
487 fl6->flowlabel = ip6_flowlabel(ipv6_hdr(ireq->pktopts));
488
486 skb_set_queue_mapping(skb, queue_mapping); 489 skb_set_queue_mapping(skb, queue_mapping);
487 err = ip6_xmit(sk, skb, fl6, np->opt, np->tclass); 490 err = ip6_xmit(sk, skb, fl6, np->opt, np->tclass);
488 err = net_xmit_eval(err); 491 err = net_xmit_eval(err);
@@ -1018,7 +1021,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
1018 if (!isn) { 1021 if (!isn) {
1019 if (ipv6_opt_accepted(sk, skb) || 1022 if (ipv6_opt_accepted(sk, skb) ||
1020 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || 1023 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
1021 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { 1024 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim ||
1025 np->repflow) {
1022 atomic_inc(&skb->users); 1026 atomic_inc(&skb->users);
1023 ireq->pktopts = skb; 1027 ireq->pktopts = skb;
1024 } 1028 }
@@ -1143,6 +1147,8 @@ static struct sock *tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
1143 newnp->mcast_oif = inet6_iif(skb); 1147 newnp->mcast_oif = inet6_iif(skb);
1144 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; 1148 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
1145 newnp->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(skb)); 1149 newnp->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(skb));
1150 if (np->repflow)
1151 newnp->flow_label = ip6_flowlabel(ipv6_hdr(skb));
1146 1152
1147 /* 1153 /*
1148 * No need to charge this sock to the relevant IPv6 refcnt debug socks count 1154 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
@@ -1223,6 +1229,8 @@ static struct sock *tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
1223 newnp->mcast_oif = inet6_iif(skb); 1229 newnp->mcast_oif = inet6_iif(skb);
1224 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; 1230 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
1225 newnp->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(skb)); 1231 newnp->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(skb));
1232 if (np->repflow)
1233 newnp->flow_label = ip6_flowlabel(ipv6_hdr(skb));
1226 1234
1227 /* Clone native IPv6 options from listening socket (if any) 1235 /* Clone native IPv6 options from listening socket (if any)
1228 1236
@@ -1434,6 +1442,8 @@ ipv6_pktoptions:
1434 np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit; 1442 np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit;
1435 if (np->rxopt.bits.rxflow || np->rxopt.bits.rxtclass) 1443 if (np->rxopt.bits.rxflow || np->rxopt.bits.rxtclass)
1436 np->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(opt_skb)); 1444 np->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(opt_skb));
1445 if (np->repflow)
1446 np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb));
1437 if (ipv6_opt_accepted(sk, opt_skb)) { 1447 if (ipv6_opt_accepted(sk, opt_skb)) {
1438 skb_set_owner_r(opt_skb, sk); 1448 skb_set_owner_r(opt_skb, sk);
1439 opt_skb = xchg(&np->pktoptions, opt_skb); 1449 opt_skb = xchg(&np->pktoptions, opt_skb);