diff options
| author | Florent Fourcot <florent.fourcot@enst-bretagne.fr> | 2013-11-07 11:53:12 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2013-11-08 13:42:57 -0500 |
| commit | 3fdfa5ff50aee5b524fb22b6e0e511b73752a257 (patch) | |
| tree | 8f29df0bc744c02169588a0719bb67a306705c8e | |
| parent | 3797d3e8462efdaadb64164ca540626b55fe8336 (diff) | |
ipv6: enable IPV6_FLOWLABEL_MGR for getsockopt
It is already possible to set/put/renew a label
with IPV6_FLOWLABEL_MGR and setsockopt. This patch
add the possibility to get information about this
label (current value, time before expiration, etc).
It helps application to take decision for a renew
or a release of the label.
v2:
* Add spin_lock to prevent race condition
* return -ENOENT if no result found
* check if flr_action is GET
v3:
* move the spin_lock to protect only the
relevant code
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/net/ipv6.h | 1 | ||||
| -rw-r--r-- | net/ipv6/ip6_flowlabel.c | 26 | ||||
| -rw-r--r-- | net/ipv6/ipv6_sockglue.c | 28 |
3 files changed, 55 insertions, 0 deletions
diff --git a/include/net/ipv6.h b/include/net/ipv6.h index dd96638ab8ff..2a5f668cd683 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h | |||
| @@ -250,6 +250,7 @@ struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions *opt_space, | |||
| 250 | struct ipv6_txoptions *fopt); | 250 | struct ipv6_txoptions *fopt); |
| 251 | void fl6_free_socklist(struct sock *sk); | 251 | void fl6_free_socklist(struct sock *sk); |
| 252 | int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen); | 252 | int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen); |
| 253 | int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq); | ||
| 253 | int ip6_flowlabel_init(void); | 254 | int ip6_flowlabel_init(void); |
| 254 | void ip6_flowlabel_cleanup(void); | 255 | void ip6_flowlabel_cleanup(void); |
| 255 | 256 | ||
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 819578e92499..4a06ed01d0c3 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c | |||
| @@ -475,6 +475,32 @@ static inline void fl_link(struct ipv6_pinfo *np, struct ipv6_fl_socklist *sfl, | |||
| 475 | spin_unlock_bh(&ip6_sk_fl_lock); | 475 | spin_unlock_bh(&ip6_sk_fl_lock); |
| 476 | } | 476 | } |
| 477 | 477 | ||
| 478 | int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq) | ||
| 479 | { | ||
| 480 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
| 481 | struct ipv6_fl_socklist *sfl; | ||
| 482 | |||
| 483 | rcu_read_lock_bh(); | ||
| 484 | |||
| 485 | for_each_sk_fl_rcu(np, sfl) { | ||
| 486 | if (sfl->fl->label == (np->flow_label & IPV6_FLOWLABEL_MASK)) { | ||
| 487 | spin_lock_bh(&ip6_fl_lock); | ||
| 488 | freq->flr_label = sfl->fl->label; | ||
| 489 | freq->flr_dst = sfl->fl->dst; | ||
| 490 | freq->flr_share = sfl->fl->share; | ||
| 491 | freq->flr_expires = (sfl->fl->expires - jiffies) / HZ; | ||
| 492 | freq->flr_linger = sfl->fl->linger / HZ; | ||
| 493 | |||
| 494 | spin_unlock_bh(&ip6_fl_lock); | ||
| 495 | rcu_read_unlock_bh(); | ||
| 496 | return 0; | ||
| 497 | } | ||
| 498 | } | ||
| 499 | rcu_read_unlock_bh(); | ||
| 500 | |||
| 501 | return -ENOENT; | ||
| 502 | } | ||
| 503 | |||
| 478 | int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) | 504 | int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) |
| 479 | { | 505 | { |
| 480 | int uninitialized_var(err); | 506 | int uninitialized_var(err); |
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 4919a8e6063e..1c6ce3119ff8 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
| @@ -1212,6 +1212,34 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
| 1212 | val = np->sndflow; | 1212 | val = np->sndflow; |
| 1213 | break; | 1213 | break; |
| 1214 | 1214 | ||
| 1215 | case IPV6_FLOWLABEL_MGR: | ||
| 1216 | { | ||
| 1217 | struct in6_flowlabel_req freq; | ||
| 1218 | |||
| 1219 | if (len < sizeof(freq)) | ||
| 1220 | return -EINVAL; | ||
| 1221 | |||
| 1222 | if (copy_from_user(&freq, optval, sizeof(freq))) | ||
| 1223 | return -EFAULT; | ||
| 1224 | |||
| 1225 | if (freq.flr_action != IPV6_FL_A_GET) | ||
| 1226 | return -EINVAL; | ||
| 1227 | |||
| 1228 | len = sizeof(freq); | ||
| 1229 | memset(&freq, 0, sizeof(freq)); | ||
| 1230 | |||
| 1231 | val = ipv6_flowlabel_opt_get(sk, &freq); | ||
| 1232 | if (val < 0) | ||
| 1233 | return val; | ||
| 1234 | |||
| 1235 | if (put_user(len, optlen)) | ||
| 1236 | return -EFAULT; | ||
| 1237 | if (copy_to_user(optval, &freq, len)) | ||
| 1238 | return -EFAULT; | ||
| 1239 | |||
| 1240 | return 0; | ||
| 1241 | } | ||
| 1242 | |||
| 1215 | case IPV6_ADDR_PREFERENCES: | 1243 | case IPV6_ADDR_PREFERENCES: |
| 1216 | val = 0; | 1244 | val = 0; |
| 1217 | 1245 | ||
