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>
This commit is contained in:
parent
3797d3e846
commit
3fdfa5ff50
3 changed files with 55 additions and 0 deletions
|
@ -250,6 +250,7 @@ struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions *opt_space,
|
|||
struct ipv6_txoptions *fopt);
|
||||
void fl6_free_socklist(struct sock *sk);
|
||||
int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen);
|
||||
int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq);
|
||||
int ip6_flowlabel_init(void);
|
||||
void ip6_flowlabel_cleanup(void);
|
||||
|
||||
|
|
|
@ -475,6 +475,32 @@ static inline void fl_link(struct ipv6_pinfo *np, struct ipv6_fl_socklist *sfl,
|
|||
spin_unlock_bh(&ip6_sk_fl_lock);
|
||||
}
|
||||
|
||||
int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq)
|
||||
{
|
||||
struct ipv6_pinfo *np = inet6_sk(sk);
|
||||
struct ipv6_fl_socklist *sfl;
|
||||
|
||||
rcu_read_lock_bh();
|
||||
|
||||
for_each_sk_fl_rcu(np, sfl) {
|
||||
if (sfl->fl->label == (np->flow_label & IPV6_FLOWLABEL_MASK)) {
|
||||
spin_lock_bh(&ip6_fl_lock);
|
||||
freq->flr_label = sfl->fl->label;
|
||||
freq->flr_dst = sfl->fl->dst;
|
||||
freq->flr_share = sfl->fl->share;
|
||||
freq->flr_expires = (sfl->fl->expires - jiffies) / HZ;
|
||||
freq->flr_linger = sfl->fl->linger / HZ;
|
||||
|
||||
spin_unlock_bh(&ip6_fl_lock);
|
||||
rcu_read_unlock_bh();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock_bh();
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen)
|
||||
{
|
||||
int uninitialized_var(err);
|
||||
|
|
|
@ -1212,6 +1212,34 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
|
|||
val = np->sndflow;
|
||||
break;
|
||||
|
||||
case IPV6_FLOWLABEL_MGR:
|
||||
{
|
||||
struct in6_flowlabel_req freq;
|
||||
|
||||
if (len < sizeof(freq))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(&freq, optval, sizeof(freq)))
|
||||
return -EFAULT;
|
||||
|
||||
if (freq.flr_action != IPV6_FL_A_GET)
|
||||
return -EINVAL;
|
||||
|
||||
len = sizeof(freq);
|
||||
memset(&freq, 0, sizeof(freq));
|
||||
|
||||
val = ipv6_flowlabel_opt_get(sk, &freq);
|
||||
if (val < 0)
|
||||
return val;
|
||||
|
||||
if (put_user(len, optlen))
|
||||
return -EFAULT;
|
||||
if (copy_to_user(optval, &freq, len))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
case IPV6_ADDR_PREFERENCES:
|
||||
val = 0;
|
||||
|
||||
|
|
Loading…
Reference in a new issue