Release 4.11 net/xfrm/xfrm_policy.c
/*
* xfrm_policy.c
*
* Changes:
* Mitsuru KANDA @USAGI
* Kazunori MIYAZAWA @USAGI
* Kunihiro Ishiguro <kunihiro@ipinfusion.com>
* IPv6 support
* Kazunori MIYAZAWA @USAGI
* YOSHIFUJI Hideaki
* Split up af-specific portion
* Derek Atkins <derek@ihtfp.com> Add the post_input processor
*
*/
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/kmod.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/notifier.h>
#include <linux/netdevice.h>
#include <linux/netfilter.h>
#include <linux/module.h>
#include <linux/cache.h>
#include <linux/audit.h>
#include <net/dst.h>
#include <net/flow.h>
#include <net/xfrm.h>
#include <net/ip.h>
#ifdef CONFIG_XFRM_STATISTICS
#include <net/snmp.h>
#endif
#include "xfrm_hash.h"
#define XFRM_QUEUE_TMO_MIN ((unsigned)(HZ/10))
#define XFRM_QUEUE_TMO_MAX ((unsigned)(60*HZ))
#define XFRM_MAX_QUEUE_LEN 100
struct xfrm_flo {
struct dst_entry *dst_orig;
u8 flags;
};
static DEFINE_SPINLOCK(xfrm_policy_afinfo_lock);
static struct xfrm_policy_afinfo const __rcu *xfrm_policy_afinfo[AF_INET6 + 1]
__read_mostly;
static struct kmem_cache *xfrm_dst_cache __read_mostly;
static __read_mostly seqcount_t xfrm_policy_hash_generation;
static void xfrm_init_pmtu(struct dst_entry *dst);
static int stale_bundle(struct dst_entry *dst);
static int xfrm_bundle_ok(struct xfrm_dst *xdst);
static void xfrm_policy_queue_process(unsigned long arg);
static void __xfrm_policy_link(struct xfrm_policy *pol, int dir);
static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
int dir);
static inline bool xfrm_pol_hold_rcu(struct xfrm_policy *policy)
{
return atomic_inc_not_zero(&policy->refcnt);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Florian Westphal | 21 | 100.00% | 1 | 100.00% |
Total | 21 | 100.00% | 1 | 100.00% |
static inline bool
__xfrm4_selector_match(const struct xfrm_selector *sel, const struct flowi *fl)
{
const struct flowi4 *fl4 = &fl->u.ip4;
return addr4_match(fl4->daddr, sel->daddr.a4, sel->prefixlen_d) &&
addr4_match(fl4->saddr, sel->saddr.a4, sel->prefixlen_s) &&
!((xfrm_flowi_dport(fl, &fl4->uli) ^ sel->dport) & sel->dport_mask) &&
!((xfrm_flowi_sport(fl, &fl4->uli) ^ sel->sport) & sel->sport_mask) &&
(fl4->flowi4_proto == sel->proto || !sel->proto) &&
(fl4->flowi4_oif == sel->ifindex || !sel->ifindex);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andrew Morton | 103 | 72.03% | 1 | 12.50% |
David S. Miller | 34 | 23.78% | 6 | 75.00% |
Alexey Dobriyan | 6 | 4.20% | 1 | 12.50% |
Total | 143 | 100.00% | 8 | 100.00% |
static inline bool
__xfrm6_selector_match(const struct xfrm_selector *sel, const struct flowi *fl)
{
const struct flowi6 *fl6 = &fl->u.ip6;
return addr_match(&fl6->daddr, &sel->daddr, sel->prefixlen_d) &&
addr_match(&fl6->saddr, &sel->saddr, sel->prefixlen_s) &&
!((xfrm_flowi_dport(fl, &fl6->uli) ^ sel->dport) & sel->dport_mask) &&
!((xfrm_flowi_sport(fl, &fl6->uli) ^ sel->sport) & sel->sport_mask) &&
(fl6->flowi6_proto == sel->proto || !sel->proto) &&
(fl6->flowi6_oif == sel->ifindex || !sel->ifindex);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andrew Morton | 109 | 76.22% | 1 | 14.29% |
David S. Miller | 34 | 23.78% | 6 | 85.71% |
Total | 143 | 100.00% | 7 | 100.00% |
bool xfrm_selector_match(const struct xfrm_selector *sel, const struct flowi *fl,
unsigned short family)
{
switch (family) {
case AF_INET:
return __xfrm4_selector_match(sel, fl);
case AF_INET6:
return __xfrm6_selector_match(sel, fl);
}
return false;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Herbert Xu | 38 | 73.08% | 2 | 33.33% |
Andrew Morton | 10 | 19.23% | 1 | 16.67% |
David S. Miller | 4 | 7.69% | 3 | 50.00% |
Total | 52 | 100.00% | 6 | 100.00% |
static const struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family)
{
const struct xfrm_policy_afinfo *afinfo;
if (unlikely(family >= ARRAY_SIZE(xfrm_policy_afinfo)))
return NULL;
rcu_read_lock();
afinfo = rcu_dereference(xfrm_policy_afinfo[family]);
if (unlikely(!afinfo))
rcu_read_unlock();
return afinfo;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Eric Dumazet | 55 | 90.16% | 1 | 50.00% |
Florian Westphal | 6 | 9.84% | 1 | 50.00% |
Total | 61 | 100.00% | 2 | 100.00% |
static inline struct dst_entry *__xfrm_dst_lookup(struct net *net,
int tos, int oif,
const xfrm_address_t *saddr,
const xfrm_address_t *daddr,
int family)
{
const struct xfrm_policy_afinfo *afinfo;
struct dst_entry *dst;
afinfo = xfrm_policy_get_afinfo(family);
if (unlikely(afinfo == NULL))
return ERR_PTR(-EAFNOSUPPORT);
dst = afinfo->dst_lookup(net, tos, oif, saddr, daddr);
rcu_read_unlock();
return dst;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hideaki Yoshifuji / 吉藤英明 | 73 | 81.11% | 1 | 16.67% |
Alexey Dobriyan | 7 | 7.78% | 1 | 16.67% |
David Ahern | 5 | 5.56% | 1 | 16.67% |
Florian Westphal | 3 | 3.33% | 2 | 33.33% |
David S. Miller | 2 | 2.22% | 1 | 16.67% |
Total | 90 | 100.00% | 6 | 100.00% |
static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x,
int tos, int oif,
xfrm_address_t *prev_saddr,
xfrm_address_t *prev_daddr,
int family)
{
struct net *net = xs_net(x);
xfrm_address_t *saddr = &x->props.saddr;
xfrm_address_t *daddr = &x->id.daddr;
struct dst_entry *dst;
if (x->type->flags & XFRM_TYPE_LOCAL_COADDR) {
saddr = x->coaddr;
daddr = prev_daddr;
}
if (x->type->flags & XFRM_TYPE_REMOTE_COADDR) {
saddr = prev_saddr;
daddr = x->coaddr;
}
dst = __xfrm_dst_lookup(net, tos, oif, saddr, daddr, family);
if (!IS_ERR(dst)) {
if (prev_saddr != saddr)
memcpy(prev_saddr, saddr, sizeof(*prev_saddr));
if (prev_daddr != daddr)
memcpy(prev_daddr, daddr, sizeof(*prev_daddr));
}
return dst;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Herbert Xu | 101 | 56.11% | 4 | 57.14% |
Hideaki Yoshifuji / 吉藤英明 | 62 | 34.44% | 1 | 14.29% |
Alexey Dobriyan | 12 | 6.67% | 1 | 14.29% |
David Ahern | 5 | 2.78% | 1 | 14.29% |
Total | 180 | 100.00% | 7 | 100.00% |
static inline unsigned long make_jiffies(long secs)
{
if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ)
return MAX_SCHEDULE_TIMEOUT-1;
else
return secs*HZ;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hideaki Yoshifuji / 吉藤英明 | 21 | 61.76% | 1 | 50.00% |
Kazunori Miyazawa | 13 | 38.24% | 1 | 50.00% |
Total | 34 | 100.00% | 2 | 100.00% |
static void xfrm_policy_timer(unsigned long data)
{
struct xfrm_policy *xp = (struct xfrm_policy *)data;
unsigned long now = get_seconds();
long next = LONG_MAX;
int warn = 0;
int dir;
read_lock(&xp->lock);
if (unlikely(xp->walk.dead))
goto out;
dir = xfrm_policy_id2dir(xp->index);
if (xp->lft.hard_add_expires_seconds) {
long tmo = xp->lft.hard_add_expires_seconds +
xp->curlft.add_time - now;
if (tmo <= 0)
goto expired;
if (tmo < next)
next = tmo;
}
if (xp->lft.hard_use_expires_seconds) {
long tmo = xp->lft.hard_use_expires_seconds +
(xp->curlft.use_time ? : xp->curlft.add_time) - now;
if (tmo <= 0)
goto expired;
if (tmo < next)
next = tmo;
}
if (xp->lft.soft_add_expires_seconds) {
long tmo = xp->lft.soft_add_expires_seconds +
xp->curlft.add_time - now;
if (tmo <= 0) {
warn = 1;
tmo = XFRM_KM_TIMEOUT;
}
if (tmo < next)
next = tmo;
}
if (xp->lft.soft_use_expires_seconds) {
long tmo = xp->lft.soft_use_expires_seconds +
(xp->curlft.use_time ? : xp->curlft.add_time) - now;
if (tmo <= 0) {
warn = 1;
tmo = XFRM_KM_TIMEOUT;
}
if (tmo < next)
next = tmo;
}
if (warn)
km_policy_expired(xp, dir, 0, 0);
if (next != LONG_MAX &&
!mod_timer(&xp->timer, jiffies + make_jiffies(next)))
xfrm_pol_hold(xp);
out:
read_unlock(&xp->lock);
xfrm_pol_put(xp);
return;
expired:
read_unlock(&xp->lock);
if (!xfrm_policy_delete(xp, dir))
km_policy_expired(xp, dir, 1, 0);
xfrm_pol_put(xp);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Herbert Xu | 240 | 62.66% | 6 | 42.86% |
Hideaki Yoshifuji / 吉藤英明 | 83 | 21.67% | 1 | 7.14% |
Alexey Kuznetsov | 27 | 7.05% | 1 | 7.14% |
David S. Miller | 17 | 4.44% | 1 | 7.14% |
Kazunori Miyazawa | 6 | 1.57% | 1 | 7.14% |
Jamal Hadi Salim | 4 | 1.04% | 1 | 7.14% |
Timo Teräs | 3 | 0.78% | 1 | 7.14% |
James Morris | 3 | 0.78% | 2 | 14.29% |
Total | 383 | 100.00% | 14 | 100.00% |
static struct flow_cache_object *xfrm_policy_flo_get(struct flow_cache_object *flo)
{
struct xfrm_policy *pol = container_of(flo, struct xfrm_policy, flo);
if (unlikely(pol->walk.dead))
flo = NULL;
else
xfrm_pol_hold(pol);
return flo;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Timo Teräs | 52 | 100.00% | 1 | 100.00% |
Total | 52 | 100.00% | 1 | 100.00% |
static int xfrm_policy_flo_check(struct flow_cache_object *flo)
{
struct xfrm_policy *pol = container_of(flo, struct xfrm_policy, flo);
return !pol->walk.dead;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Timo Teräs | 34 | 100.00% | 1 | 100.00% |
Total | 34 | 100.00% | 1 | 100.00% |
static void xfrm_policy_flo_delete(struct flow_cache_object *flo)
{
xfrm_pol_put(container_of(flo, struct xfrm_policy, flo));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Timo Teräs | 24 | 100.00% | 1 | 100.00% |
Total | 24 | 100.00% | 1 | 100.00% |
static const struct flow_cache_ops xfrm_policy_fc_ops = {
.get = xfrm_policy_flo_get,
.check = xfrm_policy_flo_check,
.delete = xfrm_policy_flo_delete,
};
/* Allocate xfrm_policy. Not used here, it is supposed to be used by pfkeyv2
* SPD calls.
*/
struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp)
{
struct xfrm_policy *policy;
policy = kzalloc(sizeof(struct xfrm_policy), gfp);
if (policy) {
write_pnet(&policy->xp_net, net);
INIT_LIST_HEAD(&policy->walk.all);
INIT_HLIST_NODE(&policy->bydst);
INIT_HLIST_NODE(&policy->byidx);
rwlock_init(&policy->lock);
atomic_set(&policy->refcnt, 1);
skb_queue_head_init(&policy->polq.hold_queue);
setup_timer(&policy->timer, xfrm_policy_timer,
(unsigned long)policy);
setup_timer(&policy->polq.hold_timer, xfrm_policy_queue_process,
(unsigned long)policy);
policy->flo.ops = &xfrm_policy_fc_ops;
}
return policy;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Alexey Kuznetsov | 56 | 37.58% | 4 | 28.57% |
Steffen Klassert | 28 | 18.79% | 1 | 7.14% |
David S. Miller | 20 | 13.42% | 1 | 7.14% |
Timo Teräs | 16 | 10.74% | 2 | 14.29% |
Alexey Dobriyan | 15 | 10.07% | 1 | 7.14% |
Pavel Emelyanov | 5 | 3.36% | 1 | 7.14% |
Andrew Morton | 4 | 2.68% | 1 | 7.14% |
Herbert Xu | 3 | 2.01% | 1 | 7.14% |
Panagiotis Issaris | 1 | 0.67% | 1 | 7.14% |
Al Viro | 1 | 0.67% | 1 | 7.14% |
Total | 149 | 100.00% | 14 | 100.00% |
EXPORT_SYMBOL(xfrm_policy_alloc);
static void xfrm_policy_destroy_rcu(struct rcu_head *head)
{
struct xfrm_policy *policy = container_of(head, struct xfrm_policy, rcu);
security_xfrm_policy_free(policy->security);
kfree(policy);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Eric Dumazet | 38 | 100.00% | 1 | 100.00% |
Total | 38 | 100.00% | 1 | 100.00% |
/* Destroy xfrm_policy: descendant resources must be released to this moment. */
void xfrm_policy_destroy(struct xfrm_policy *policy)
{
BUG_ON(!policy->walk.dead);
if (del_timer(&policy->timer) || del_timer(&policy->polq.hold_timer))
BUG();
call_rcu(&policy->rcu, xfrm_policy_destroy_rcu);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Alexey Kuznetsov | 29 | 54.72% | 2 | 22.22% |
Fan Du | 10 | 18.87% | 1 | 11.11% |
Eric Dumazet | 5 | 9.43% | 1 | 11.11% |
Kris Katterjohn | 3 | 5.66% | 1 | 11.11% |
Trent Jaeger | 2 | 3.77% | 1 | 11.11% |
Herbert Xu | 2 | 3.77% | 1 | 11.11% |
Paul Moore | 1 | 1.89% | 1 | 11.11% |
Américo Wang | 1 | 1.89% | 1 | 11.11% |
Total | 53 | 100.00% | 9 | 100.00% |
EXPORT_SYMBOL(xfrm_policy_destroy);
/* Rule must be locked. Release descendant resources, announce
* entry dead. The rule must be unlinked from lists to the moment.
*/
static void xfrm_policy_kill(struct xfrm_policy *policy)
{
policy->walk.dead = 1;
atomic_inc(&policy->genid);
if (del_timer(&policy->polq.hold_timer))
xfrm_pol_put(policy);
skb_queue_purge(&policy->polq.hold_queue);
if (del_timer(&policy->timer))
xfrm_pol_put(policy);
xfrm_pol_put(policy);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Herbert Xu | 29 | 39.19% | 3 | 33.33% |
Steffen Klassert | 26 | 35.14% | 2 | 22.22% |
Timo Teräs | 13 | 17.57% | 1 | 11.11% |
Alexey Kuznetsov | 4 | 5.41% | 1 | 11.11% |
Li RongQing | 1 | 1.35% | 1 | 11.11% |
Christoph Hellwig | 1 | 1.35% | 1 | 11.11% |
Total | 74 | 100.00% | 9 | 100.00% |
static unsigned int xfrm_policy_hashmax __read_mostly = 1 * 1024 * 1024;
static inline unsigned int idx_hash(struct net *net, u32 index)
{
return __idx_hash(index, net->xfrm.policy_idx_hmask);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 17 | 60.71% | 1 | 25.00% |
Alexey Dobriyan | 10 | 35.71% | 2 | 50.00% |
Masahide Nakamura | 1 | 3.57% | 1 | 25.00% |
Total | 28 | 100.00% | 4 | 100.00% |
/* calculate policy hash thresholds */
static void __get_hash_thresh(struct net *net,
unsigned short family, int dir,
u8 *dbits, u8 *sbits)
{
switch (family) {
case AF_INET:
*dbits = net->xfrm.policy_bydst[dir].dbits4;
*sbits = net->xfrm.policy_bydst[dir].sbits4;
break;
case AF_INET6:
*dbits = net->xfrm.policy_bydst[dir].dbits6;
*sbits = net->xfrm.policy_bydst[dir].sbits6;
break;
default:
*dbits = 0;
*sbits = 0;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Christophe Gouault | 107 | 100.00% | 1 | 100.00% |
Total | 107 | 100.00% | 1 | 100.00% |
static struct hlist_head *policy_hash_bysel(struct net *net,
const struct xfrm_selector *sel,
unsigned short family, int dir)
{
unsigned int hmask = net->xfrm.policy_bydst[dir].hmask;
unsigned int hash;
u8 dbits;
u8 sbits;
__get_hash_thresh(net, family, dir, &dbits, &sbits);
hash = __sel_hash(sel, family, hmask, dbits, sbits);
if (hash == hmask + 1)
return &net->xfrm.policy_inexact[dir];
return rcu_dereference_check(net->xfrm.policy_bydst[dir].table,
lockdep_is_held(&net->xfrm.xfrm_policy_lock)) + hash;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 59 | 46.46% | 2 | 28.57% |
Christophe Gouault | 29 | 22.83% | 1 | 14.29% |
Alexey Dobriyan | 20 | 15.75% | 3 | 42.86% |
Florian Westphal | 19 | 14.96% | 1 | 14.29% |
Total | 127 | 100.00% | 7 | 100.00% |
static struct hlist_head *policy_hash_direct(struct net *net,
const xfrm_address_t *daddr,
const xfrm_address_t *saddr,
unsigned short family, int dir)
{
unsigned int hmask = net->xfrm.policy_bydst[dir].hmask;
unsigned int hash;
u8 dbits;
u8 sbits;
__get_hash_thresh(net, family, dir, &dbits, &sbits);
hash = __addr_hash(daddr, saddr, family, hmask, dbits, sbits);
return rcu_dereference_check(net->xfrm.policy_bydst[dir].table,
lockdep_is_held(&net->xfrm.xfrm_policy_lock)) + hash;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 57 | 50.00% | 2 | 33.33% |
Christophe Gouault | 29 | 25.44% | 1 | 16.67% |
Alexey Dobriyan | 15 | 13.16% | 2 | 33.33% |
Florian Westphal | 13 | 11.40% | 1 | 16.67% |
Total | 114 | 100.00% | 6 | 100.00% |
static void xfrm_dst_hash_transfer(struct net *net,
struct hlist_head *list,
struct hlist_head *ndsttable,
unsigned int nhashmask,
int dir)
{
struct hlist_node *tmp, *entry0 = NULL;
struct xfrm_policy *pol;
unsigned int h0 = 0;
u8 dbits;
u8 sbits;
redo:
hlist_for_each_entry_safe(pol, tmp, list, bydst) {
unsigned int h;
__get_hash_thresh(net, pol->family, dir, &dbits, &sbits);
h = __addr_hash(&pol->selector.daddr, &pol->selector.saddr,
pol->family, nhashmask, dbits, sbits);
if (!entry0) {
hlist_del_rcu(&pol->bydst);
hlist_add_head_rcu(&pol->bydst, ndsttable + h);
h0 = h;
} else {
if (h != h0)
continue;
hlist_del_rcu(&pol->bydst);
hlist_add_behind_rcu(&pol->bydst, entry0);
}
entry0 = &pol->bydst;
}
if (!hlist_empty(list)) {
entry0 = NULL;
goto redo;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 82 | 40.59% | 1 | 16.67% |
Hideaki Yoshifuji / 吉藤英明 | 67 | 33.17% | 1 | 16.67% |
Christophe Gouault | 35 | 17.33% | 1 | 16.67% |
Sasha Levin | 12 | 5.94% | 1 | 16.67% |
Florian Westphal | 4 | 1.98% | 1 | 16.67% |
Ken Helias | 2 | 0.99% | 1 | 16.67% |
Total | 202 | 100.00% | 6 | 100.00% |
static void xfrm_idx_hash_transfer(struct hlist_head *list,
struct hlist_head *nidxtable,
unsigned int nhashmask)
{
struct hlist_node *tmp;
struct xfrm_policy *pol;
hlist_for_each_entry_safe(pol, tmp, list, byidx) {
unsigned int h;
h = __idx_hash(pol->index, nhashmask);
hlist_add_head(&pol->byidx, nidxtable+h);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 69 | 100.00% | 1 | 100.00% |
Total | 69 | 100.00% | 1 | 100.00% |
static unsigned long xfrm_new_hash_mask(unsigned int old_hmask)
{
return ((old_hmask + 1) << 1) - 1;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 24 | 100.00% | 1 | 100.00% |
Total | 24 | 100.00% | 1 | 100.00% |
static void xfrm_bydst_resize(struct net *net, int dir)
{
unsigned int hmask = net->xfrm.policy_bydst[dir].hmask;
unsigned int nhashmask = xfrm_new_hash_mask(hmask);
unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head);
struct hlist_head *ndst = xfrm_hash_alloc(nsize);
struct hlist_head *odst;
int i;
if (!ndst)
return;
spin_lock_bh(&net->xfrm.xfrm_policy_lock);
write_seqcount_begin(&xfrm_policy_hash_generation);
odst = rcu_dereference_protected(net->xfrm.policy_bydst[dir].table,
lockdep_is_held(&net->xfrm.xfrm_policy_lock));
odst = rcu_dereference_protected(net->xfrm.policy_bydst[dir].table,
lockdep_is_held(&net->xfrm.xfrm_policy_lock));
for (i = hmask; i >= 0; i--)
xfrm_dst_hash_transfer(net, odst + i, ndst, nhashmask, dir);
rcu_assign_pointer(net->xfrm.policy_bydst[dir].table, ndst);
net->xfrm.policy_bydst[dir].hmask = nhashmask;
write_seqcount_end(&xfrm_policy_hash_generation);
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
synchronize_rcu();
xfrm_hash_free(odst, (hmask + 1) * sizeof(struct hlist_head));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 129 | 53.97% | 2 | 22.22% |
Florian Westphal | 78 | 32.64% | 3 | 33.33% |
Alexey Dobriyan | 20 | 8.37% | 2 | 22.22% |
Fan Du | 8 | 3.35% | 1 | 11.11% |
Christophe Gouault | 4 | 1.67% | 1 | 11.11% |
Total | 239 | 100.00% | 9 | 100.00% |
static void xfrm_byidx_resize(struct net *net, int total)
{
unsigned int hmask = net->xfrm.policy_idx_hmask;
unsigned int nhashmask = xfrm_new_hash_mask(hmask);
unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head);
struct hlist_head *oidx = net->xfrm.policy_byidx;
struct hlist_head *nidx = xfrm_hash_alloc(nsize);
int i;
if (!nidx)
return;
spin_lock_bh(&net->xfrm.xfrm_policy_lock);
for (i = hmask; i >= 0; i--)
xfrm_idx_hash_transfer(oidx + i, nidx, nhashmask);
net->xfrm.policy_byidx = nidx;
net->xfrm.policy_idx_hmask = nhashmask;
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
xfrm_hash_free(oidx, (hmask + 1) * sizeof(struct hlist_head));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 121 | 77.56% | 2 | 28.57% |
Alexey Dobriyan | 25 | 16.03% | 3 | 42.86% |
Fan Du | 8 | 5.13% | 1 | 14.29% |
Florian Westphal | 2 | 1.28% | 1 | 14.29% |
Total | 156 | 100.00% | 7 | 100.00% |
static inline int xfrm_bydst_should_resize(struct net *net, int dir, int *total)
{
unsigned int cnt = net->xfrm.policy_count[dir];
unsigned int hmask = net->xfrm.policy_bydst[dir].hmask;
if (total)
*total += cnt;
if ((hmask + 1) < xfrm_policy_hashmax &&
cnt > hmask)
return 1;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 61 | 80.26% | 1 | 25.00% |
Alexey Dobriyan | 15 | 19.74% | 3 | 75.00% |
Total | 76 | 100.00% | 4 | 100.00% |
static inline int xfrm_byidx_should_resize(struct net *net, int total)
{
unsigned int hmask = net->xfrm.policy_idx_hmask;
if ((hmask + 1) < xfrm_policy_hashmax &&
total > hmask)
return 1;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 35 | 77.78% | 1 | 33.33% |
Alexey Dobriyan | 10 | 22.22% | 2 | 66.67% |
Total | 45 | 100.00% | 3 | 100.00% |
void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si)
{
si->incnt = net->xfrm.policy_count[XFRM_POLICY_IN];
si->outcnt = net->xfrm.policy_count[XFRM_POLICY_OUT];
si->fwdcnt = net->xfrm.policy_count[XFRM_POLICY_FWD];
si->inscnt = net->xfrm.policy_count[XFRM_POLICY_IN+XFRM_POLICY_MAX];
si->outscnt = net->xfrm.policy_count[XFRM_POLICY_OUT+XFRM_POLICY_MAX];
si->fwdscnt = net->xfrm.policy_count[XFRM_POLICY_FWD+XFRM_POLICY_MAX];
si->spdhcnt = net->xfrm.policy_idx_hmask;
si->spdhmcnt = xfrm_policy_hashmax;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jamal Hadi Salim | 75 | 65.22% | 2 | 40.00% |
Alexey Dobriyan | 40 | 34.78% | 3 | 60.00% |
Total | 115 | 100.00% | 5 | 100.00% |
EXPORT_SYMBOL(xfrm_spd_getinfo);
static DEFINE_MUTEX(hash_resize_mutex);
static void xfrm_hash_resize(struct work_struct *work)
{
struct net *net = container_of(work, struct net, xfrm.policy_hash_work);
int dir, total;
mutex_lock(&hash_resize_mutex);
total = 0;
for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
if (xfrm_bydst_should_resize(net, dir, &total))
xfrm_bydst_resize(net, dir);
}
if (xfrm_byidx_should_resize(net, total))
xfrm_byidx_resize(net, total);
mutex_unlock(&hash_resize_mutex);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 68 | 68.69% | 1 | 20.00% |
Alexey Dobriyan | 26 | 26.26% | 1 | 20.00% |
Masahide Nakamura | 2 | 2.02% | 1 | 20.00% |
David Howells | 2 | 2.02% | 1 | 20.00% |
Alexey Kuznetsov | 1 | 1.01% | 1 | 20.00% |
Total | 99 | 100.00% | 5 | 100.00% |
static void xfrm_hash_rebuild(struct work_struct *work)
{
struct net *net = container_of(work, struct net,
xfrm.policy_hthresh.work);
unsigned int hmask;
struct xfrm_policy *pol;
struct xfrm_policy *policy;
struct hlist_head *chain;
struct hlist_head *odst;
struct hlist_node *newpos;
int i;
int dir;
unsigned seq;
u8 lbits4, rbits4, lbits6, rbits6;
mutex_lock(&hash_resize_mutex);
/* read selector prefixlen thresholds */
do {
seq = read_seqbegin(&net->xfrm.policy_hthresh.lock);
lbits4 = net->xfrm.policy_hthresh.lbits4;
rbits4 = net->xfrm.policy_hthresh.rbits4;
lbits6 = net->xfrm.policy_hthresh.lbits6;
rbits6 = net->xfrm.policy_hthresh.rbits6;
} while (read_seqretry(&net->xfrm.policy_hthresh.lock, seq));
spin_lock_bh(&net->xfrm.xfrm_policy_lock);
/* reset the bydst and inexact table in all directions */
for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]);
hmask = net->xfrm.policy_bydst[dir].hmask;
odst = net->xfrm.policy_bydst[dir].table;
for (i = hmask; i >= 0; i--)
INIT_HLIST_HEAD(odst + i);
if ((dir & XFRM_POLICY_MASK) == XFRM_POLICY_OUT) {
/* dir out => dst = remote, src = local */
net->xfrm.policy_bydst[dir].dbits4 = rbits4;
net->xfrm.policy_bydst[dir].sbits4 = lbits4;
net->xfrm.policy_bydst[dir].dbits6 = rbits6;
net->xfrm.policy_bydst[dir].sbits6 = lbits6;
} else {
/* dir in/fwd => dst = local, src = remote */
net->xfrm.policy_bydst[dir].dbits4 = lbits4;
net->xfrm.policy_bydst[dir].sbits4 = rbits4;
net->xfrm.policy_bydst[dir].dbits6 = lbits6;
net->xfrm.policy_bydst[dir].sbits6 = rbits6;
}
}
/* re-insert all policies by order of creation */
list_for_each_entry_reverse(policy, &net->xfrm.policy_all, walk.all) {
if (xfrm_policy_id2dir(policy->index) >= XFRM_POLICY_MAX) {
/* skip socket policies */
continue;
}
newpos = NULL;
chain = policy_hash_bysel(net, &policy->selector,
policy->family,
xfrm_policy_id2dir(policy->index));
hlist_for_each_entry(pol, chain, bydst) {
if (policy->priority >= pol->priority)
newpos = &pol->bydst;
else
break;
}
if (newpos)
hlist_add_behind(&policy->bydst, newpos);
else
hlist_add_head(&policy->bydst, chain);
}
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
mutex_unlock(&hash_resize_mutex);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Christophe Gouault | 449 | 92.20% | 1 | 14.29% |
Tobias Brunner | 15 | 3.08% | 1 | 14.29% |
Jamal Hadi Salim | 11 | 2.26% | 1 | 14.29% |
Fan Du | 4 | 0.82% | 1 | 14.29% |
David S. Miller | 4 | 0.82% | 1 | 14.29% |
Alexey Dobriyan | 2 | 0.41% | 1 | 14.29% |
Florian Westphal | 2 | 0.41% | 1 | 14.29% |
Total | 487 | 100.00% | 7 | 100.00% |
void xfrm_policy_hash_rebuild(struct net *net)
{
schedule_work(&net->xfrm.policy_hthresh.work);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Christophe Gouault | 9 | 40.91% | 1 | 20.00% |
David S. Miller | 7 | 31.82% | 1 | 20.00% |
Alexey Dobriyan | 4 | 18.18% | 1 | 20.00% |
Masahide Nakamura | 1 | 4.55% | 1 | 20.00% |
David Howells | 1 | 4.55% | 1 | 20.00% |
Total | 22 | 100.00% | 5 | 100.00% |
EXPORT_SYMBOL(xfrm_policy_hash_rebuild);
/* Generate new index... KAME seems to generate them ordered by cost
* of an absolute inpredictability of ordering of rules. This will not pass. */
static u32 xfrm_gen_index(struct net *net, int dir, u32 index)
{
static u32 idx_generator;
for (;;) {
struct hlist_head *list;
struct xfrm_policy *p;
u32 idx;
int found;
if (!index) {
idx = (idx_generator | dir);
idx_generator += 8;
} else {
idx = index;
index = 0;
}
if (idx == 0)
idx = 8;
list = net->xfrm.policy_byidx + idx_hash(net, idx);
found = 0;
hlist_for_each_entry(p, list, byidx) {
if (p->index == idx) {
found = 1;
break;
}
}
if (!found)
return idx;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 88 | 64.71% | 1 | 16.67% |
Fan Du | 21 | 15.44% | 1 | 16.67% |
Alexey Kuznetsov | 15 | 11.03% | 1 | 16.67% |
Alexey Dobriyan | 12 | 8.82% | 3 | 50.00% |
Total | 136 | 100.00% | 6 | 100.00% |
static inline int selector_cmp(struct xfrm_selector *s1, struct xfrm_selector *s2)
{
u32 *p1 = (u32 *) s1;
u32 *p2 = (u32 *) s2;
int len = sizeof(struct xfrm_selector) / sizeof(u32);
int i;
for (i = 0; i < len; i++) {
if (p1[i] != p2[i])
return 1;
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 80 | 91.95% | 1 | 50.00% |
Alexey Kuznetsov | 7 | 8.05% | 1 | 50.00% |
Total | 87 | 100.00% | 2 | 100.00% |
static void xfrm_policy_requeue(struct xfrm_policy *old,
struct xfrm_policy *new)
{
struct xfrm_policy_queue *pq = &old->polq;
struct sk_buff_head list;
if (skb_queue_empty(&pq->hold_queue))
return;
__skb_queue_head_init(&list);
spin_lock_bh(&pq->hold_queue.lock);
skb_queue_splice_init(&pq->hold_queue, &list);
if (del_timer(&pq->hold_timer))
xfrm_pol_put(old);
spin_unlock_bh(&pq->hold_queue.lock);
pq = &new->polq;
spin_lock_bh(&pq->hold_queue.lock);
skb_queue_splice(&list, &pq->hold_queue);
pq->timeout = XFRM_QUEUE_TMO_MIN;
if (!mod_timer(&pq->hold_timer, jiffies))
xfrm_pol_hold(new);
spin_unlock_bh(&pq->hold_queue.lock);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Steffen Klassert | 105 | 67.74% | 2 | 22.22% |
Alexey Kuznetsov | 12 | 7.74% | 1 | 11.11% |
Li RongQing | 11 | 7.10% | 1 | 11.11% |
David S. Miller | 8 | 5.16% | 1 | 11.11% |
Jamal Hadi Salim | 7 | 4.52% | 1 | 11.11% |
Trent Jaeger | 4 | 2.58% | 1 | 11.11% |
Herbert Xu | 4 | 2.58% | 1 | 11.11% |
Masahide Nakamura | 4 | 2.58% | 1 | 11.11% |
Total | 155 | 100.00% | 9 | 100.00% |
static bool xfrm_policy_mark_match(struct xfrm_policy *policy,
struct xfrm_policy *pol)
{
u32 mark = policy->mark.v & policy->mark.m;
if (policy->mark.v == pol->mark.v && policy->mark.m == pol->mark.m)
return true;
if ((mark & pol->mark.m) == pol->mark.v &&
policy->priority == pol->priority)
return true;
return false;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Steffen Klassert | 92 | 100.00% | 1 | 100.00% |
Total | 92 | 100.00% | 1 | 100.00% |
int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
{
struct net *net = xp_net(policy);
struct xfrm_policy *pol;
struct xfrm_policy *delpol;
struct hlist_head *chain;
struct hlist_node *newpos;
spin_lock_bh(&net->xfrm.xfrm_policy_lock);
chain = policy_hash_bysel(net, &policy->selector, policy->family, dir);
delpol = NULL;
newpos = NULL;
hlist_for_each_entry(pol, chain, bydst) {
if (pol->type == policy->type &&
!selector_cmp(&pol->selector, &policy->selector) &&
xfrm_policy_mark_match(policy, pol) &&
xfrm_sec_ctx_match(pol->security, policy->security) &&
!WARN_ON(delpol)) {
if (excl) {
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
return -EEXIST;
}
delpol = pol;
if (policy->priority > pol->priority)
continue;
} else if (policy->priority >= pol->priority) {
newpos = &pol->bydst;
continue;
}
if (delpol)
break;
}
if (newpos)
hlist_add_behind(&policy->bydst, newpos);
else
hlist_add_head(&policy->bydst, chain);
__xfrm_policy_link(policy, dir);
atomic_inc(&net->xfrm.flow_cache_genid);
/* After previous checking, family can either be AF_INET or AF_INET6 */
if (policy->family == AF_INET)
rt_genid_bump_ipv4(net);
else
rt_genid_bump_ipv6(net);
if (delpol) {
xfrm_policy_requeue(delpol, policy);
__xfrm_policy_unlink(delpol, dir);
}
policy->index = delpol ? delpol->index : xfrm_gen_index(net, dir, policy->index);
hlist_add_head(&policy->byidx, net->xfrm.policy_byidx+idx_hash(net, policy->index));
policy->curlft.add_time = get_seconds();
policy->curlft.use_time = 0;
if (!mod_timer(&policy->timer, jiffies + HZ))
xfrm_pol_hold(policy);
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
if (delpol)
xfrm_policy_kill(delpol);
else if (xfrm_bydst_should_resize(net, dir, NULL))
schedule_work(&net->xfrm.policy_hash_work);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Alexey Kuznetsov | 134 | 32.68% | 4 | 13.79% |
David S. Miller | 100 | 24.39% | 2 | 6.90% |
Herbert Xu | 64 | 15.61% | 4 | 13.79% |
Fan Du | 36 | 8.78% | 4 | 13.79% |
Alexey Dobriyan | 28 | 6.83% | 4 | 13.79% |
Steffen Klassert | 14 | 3.41% | 2 | 6.90% |
Trent Jaeger | 11 | 2.68% | 1 | 3.45% |
Masahide Nakamura | 5 | 1.22% | 1 | 3.45% |
Nicolas Dichtel | 4 | 0.98% | 1 | 3.45% |
Florian Westphal | 3 | 0.73% | 1 | 3.45% |
James Morris | 3 | 0.73% | 2 | 6.90% |
Wei Yongjun | 3 | 0.73% | 1 | 3.45% |
Ken Helias | 3 | 0.73% | 1 | 3.45% |
Jamal Hadi Salim | 2 | 0.49% | 1 | 3.45% |
Total | 410 | 100.00% | 29 | 100.00% |
EXPORT_SYMBOL(xfrm_policy_insert);
struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type,
int dir, struct xfrm_selector *sel,
struct xfrm_sec_ctx *ctx, int delete,
int *err)
{
struct xfrm_policy *pol, *ret;
struct hlist_head *chain;
*err = 0;
spin_lock_bh(&net->xfrm.xfrm_policy_lock);
chain = policy_hash_bysel(net, sel, sel->family, dir);
ret = NULL;
hlist_for_each_entry(pol, chain, bydst) {
if (pol->type == type &&
(mark & pol->mark.m) == pol->mark.v &&
!selector_cmp(sel, &pol->selector) &&
xfrm_sec_ctx_match(ctx, pol->security)) {
xfrm_pol_hold(pol);
if (delete) {
*err = security_xfrm_policy_delete(
pol->security);
if (*err) {
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
return pol;
}
__xfrm_policy_unlink(pol, dir);
}
ret = pol;
break;
}
}
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
if (ret && delete)
xfrm_policy_kill(ret);
return ret;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Alexey Kuznetsov | 51 | 23.39% | 1 | 6.25% |
David S. Miller | 43 | 19.72% | 1 | 6.25% |
Eric Paris | 32 | 14.68% | 1 | 6.25% |
Herbert Xu | 25 | 11.47% | 3 | 18.75% |
Jamal Hadi Salim | 19 | 8.72% | 2 | 12.50% |
Trent Jaeger | 15 | 6.88% | 1 | 6.25% |
Fan Du | 12 | 5.50% | 1 | 6.25% |
Alexey Dobriyan | 7 | 3.21% | 2 | 12.50% |
Masahide Nakamura | 6 | 2.75% | 1 | 6.25% |
Florian Westphal | 3 | 1.38% | 1 | 6.25% |
Wei Yongjun | 3 | 1.38% | 1 | 6.25% |
Paul Moore | 2 | 0.92% | 1 | 6.25% |
Total | 218 | 100.00% | 16 | 100.00% |
EXPORT_SYMBOL(xfrm_policy_bysel_ctx);
struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type,
int dir, u32 id, int delete, int *err)
{
struct xfrm_policy *pol, *ret;
struct hlist_head *chain;
*err = -ENOENT;
if (xfrm_policy_id2dir(id) != dir)
return NULL;
*err = 0;
spin_lock_bh(&net->xfrm.xfrm_policy_lock);
chain = net->xfrm.policy_byidx + idx_hash(net, id);
ret = NULL;
hlist_for_each_entry(pol, chain, byidx) {
if (pol->type == type && pol->index == id &&
(mark & pol->mark.m) == pol->mark.v) {
xfrm_pol_hold(pol);
if (delete) {
*err = security_xfrm_policy_delete(
pol->security);
if (*err) {
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
return pol;
}
__xfrm_policy_unlink(pol, dir);
}
ret = pol;
break;
}
}
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
if (ret && delete)
xfrm_policy_kill(ret);
return ret;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Alexey Kuznetsov | 57 | 26.51% | 1 | 6.25% |
David S. Miller | 38 | 17.67% | 1 | 6.25% |
Herbert Xu | 32 | 14.88% | 3 | 18.75% |
Eric Paris | 32 | 14.88% | 1 | 6.25% |
Jamal Hadi Salim | 19 | 8.84% | 2 | 12.50% |
Alexey Dobriyan | 12 | 5.58% | 3 | 18.75% |
Fan Du | 12 | 5.58% | 1 | 6.25% |
Masahide Nakamura | 5 | 2.33% | 1 | 6.25% |
Florian Westphal | 3 | 1.40% | 1 | 6.25% |
Wei Yongjun | 3 | 1.40% | 1 | 6.25% |
Paul Moore | 2 | 0.93% | 1 | 6.25% |
Total | 215 | 100.00% | 16 | 100.00% |
EXPORT_SYMBOL(xfrm_policy_byid);
#ifdef CONFIG_SECURITY_NETWORK_XFRM
static inline int
xfrm_policy_flush_secctx_check(struct net *net, u8 type, bool task_valid)
{
int dir, err = 0;
for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
struct xfrm_policy *pol;
int i;
hlist_for_each_entry(pol,
&net->xfrm.policy_inexact[dir], bydst) {
if (pol->type != type)
continue;
err = security_xfrm_policy_delete(pol->security);
if (err) {
xfrm_audit_policy_delete(pol, 0, task_valid);
return err;
}
}
for (i = net->xfrm.policy_bydst[dir].hmask; i >= 0; i--) {
hlist_for_each_entry(pol,
net->xfrm.policy_bydst[dir].table + i,
bydst) {
if (pol->type != type)
continue;
err = security_xfrm_policy_delete(
pol->security);
if (err) {
xfrm_audit_policy_delete(pol, 0,
task_valid);
return err;
}
}
}
}
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Joy Latten | 147 | 88.02% | 2 | 33.33% |
Alexey Dobriyan | 12 | 7.19% | 2 | 33.33% |
Paul Moore | 4 | 2.40% | 1 | 16.67% |
Tetsuo Handa | 4 | 2.40% | 1 | 16.67% |
Total | 167 | 100.00% | 6 | 100.00% |
#else
static inline int
xfrm_policy_flush_secctx_check(struct net *net, u8 type, bool task_valid)
{
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Joy Latten | 14 | 66.67% | 1 | 33.33% |
Alexey Dobriyan | 5 | 23.81% | 1 | 33.33% |
Tetsuo Handa | 2 | 9.52% | 1 | 33.33% |
Total | 21 | 100.00% | 3 | 100.00% |
#endif
int xfrm_policy_flush(struct net *net, u8 type, bool task_valid)
{
int dir, err = 0, cnt = 0;
spin_lock_bh(&net->xfrm.xfrm_policy_lock);
err = xfrm_policy_flush_secctx_check(net, type, task_valid);
if (err)
goto out;
for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
struct xfrm_policy *pol;
int i;
again1:
hlist_for_each_entry(pol,
&net->xfrm.policy_inexact[dir], bydst) {
if (pol->type != type)
continue;
__xfrm_policy_unlink(pol, dir);
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
cnt++;
xfrm_audit_policy_delete(pol, 1, task_valid);
xfrm_policy_kill(pol);
spin_lock_bh(&net->xfrm.xfrm_policy_lock);
goto again1;
}
for (i = net->xfrm.policy_bydst[dir].hmask; i >= 0; i--) {
again2:
hlist_for_each_entry(pol,
net->xfrm.policy_bydst[dir].table + i,
bydst) {
if (pol->type != type)
continue;
__xfrm_policy_unlink(pol, dir);
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
cnt++;
xfrm_audit_policy_delete(pol, 1, task_valid);
xfrm_policy_kill(pol);
spin_lock_bh(&net->xfrm.xfrm_policy_lock);
goto again2;
}
}
}
if (!cnt)
err = -ESRCH;
out:
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
if (cnt)
xfrm_garbage_collect(net);
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 84 | 30.88% | 1 | 5.56% |
Alexey Kuznetsov | 51 | 18.75% | 1 | 5.56% |
Joy Latten | 42 | 15.44% | 3 | 16.67% |
Fan Du | 24 | 8.82% | 1 | 5.56% |
Jamal Hadi Salim | 21 | 7.72% | 1 | 5.56% |
Alexey Dobriyan | 14 | 5.15% | 2 | 11.11% |
Wei Yongjun | 10 | 3.68% | 2 | 11.11% |
Xin Long | 9 | 3.31% | 1 | 5.56% |
Florian Westphal | 5 | 1.84% | 1 | 5.56% |
Tetsuo Handa | 5 | 1.84% | 1 | 5.56% |
Herbert Xu | 2 | 0.74% | 1 | 5.56% |
Masahide Nakamura | 2 | 0.74% | 1 | 5.56% |
Linus Torvalds | 2 | 0.74% | 1 | 5.56% |
Steffen Klassert | 1 | 0.37% | 1 | 5.56% |
Total | 272 | 100.00% | 18 | 100.00% |
EXPORT_SYMBOL(xfrm_policy_flush);
int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk,
int (*func)(struct xfrm_policy *, int, int, void*),
void *data)
{
struct xfrm_policy *pol;
struct xfrm_policy_walk_entry *x;
int error = 0;
if (walk->type >= XFRM_POLICY_TYPE_MAX &&
walk->type != XFRM_POLICY_TYPE_ANY)
return -EINVAL;
if (list_empty(&walk->walk.all) && walk->seq != 0)
return 0;
spin_lock_bh(&net->xfrm.xfrm_policy_lock);
if (list_empty(&walk->walk.all))
x = list_first_entry(&net->xfrm.policy_all, struct xfrm_policy_walk_entry, all);
else
x = list_first_entry(&walk->walk.all,
struct xfrm_policy_walk_entry, all);
list_for_each_entry_from(x, &net->xfrm.policy_all, all) {
if (x->dead)
continue;
pol = container_of(x, struct xfrm_policy, walk);
if (walk->type != XFRM_POLICY_TYPE_ANY &&
walk->type != pol->type)
continue;
error = func(pol, xfrm_policy_id2dir(pol->index),
walk->seq, data);
if (error) {
list_move_tail(&walk->walk.all, &x->all);
goto out;
}
walk->seq++;
}
if (walk->seq == 0) {
error = -ENOENT;
goto out;
}
list_del_init(&walk->walk.all);
out:
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
return error;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Herbert Xu | 91 | 31.82% | 1 | 8.33% |
Timo Teräs | 63 | 22.03% | 1 | 8.33% |
David S. Miller | 43 | 15.03% | 1 | 8.33% |
Alexey Kuznetsov | 39 | 13.64% | 2 | 16.67% |
Jamal Hadi Salim | 24 | 8.39% | 1 | 8.33% |
Alexey Dobriyan | 11 | 3.85% | 2 | 16.67% |
Fan Du | 8 | 2.80% | 1 | 8.33% |
Masahide Nakamura | 4 | 1.40% | 1 | 8.33% |
Florian Westphal | 2 | 0.70% | 1 | 8.33% |
Li RongQing | 1 | 0.35% | 1 | 8.33% |
Total | 286 | 100.00% | 12 | 100.00% |
EXPORT_SYMBOL(xfrm_policy_walk);
void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type)
{
INIT_LIST_HEAD(&walk->walk.all);
walk->walk.dead = 1;
walk->type = type;
walk->seq = 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Herbert Xu | 43 | 100.00% | 1 | 100.00% |
Total | 43 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL(xfrm_policy_walk_init);
void xfrm_policy_walk_done(struct xfrm_policy_walk *walk, struct net *net)
{
if (list_empty(&walk->walk.all))
return;
spin_lock_bh(&net->xfrm.xfrm_policy_lock); /*FIXME where is net? */
list_del(&walk->walk.all);
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Herbert Xu | 36 | 61.02% | 1 | 20.00% |
Fan Du | 14 | 23.73% | 1 | 20.00% |
Timo Teräs | 6 | 10.17% | 1 | 20.00% |
Florian Westphal | 2 | 3.39% | 1 | 20.00% |
David S. Miller | 1 | 1.69% | 1 | 20.00% |
Total | 59 | 100.00% | 5 | 100.00% |
EXPORT_SYMBOL(xfrm_policy_walk_done);
/*
* Find policy to apply to this flow.
*
* Returns 0 if policy found, else an -errno.
*/
static int xfrm_policy_match(const struct xfrm_policy *pol,
const struct flowi *fl,
u8 type, u16 family, int dir)
{
const struct xfrm_selector *sel = &pol->selector;
int ret = -ESRCH;
bool match;
if (pol->family != family ||
(fl->flowi_mark & pol->mark.m) != pol->mark.v ||
pol->type != type)
return ret;
match = xfrm_selector_match(sel, fl, family);
if (match)
ret = security_xfrm_policy_lookup(pol->security, fl->flowi_secid,
dir);
return ret;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 73 | 63.48% | 5 | 50.00% |
Jamal Hadi Salim | 17 | 14.78% | 1 | 10.00% |
Alexey Kuznetsov | 14 | 12.17% | 2 | 20.00% |
James Morris | 9 | 7.83% | 1 | 10.00% |
Paul Moore | 2 | 1.74% | 1 | 10.00% |
Total | 115 | 100.00% | 10 | 100.00% |
static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type,
const struct flowi *fl,
u16 family, u8 dir)
{
int err;
struct xfrm_policy *pol, *ret;
const xfrm_address_t *daddr, *saddr;
struct hlist_head *chain;
unsigned int sequence;
u32 priority;
daddr = xfrm_flowi_daddr(fl, family);
saddr = xfrm_flowi_saddr(fl, family);
if (unlikely(!daddr || !saddr))
return NULL;
rcu_read_lock();
retry:
do {
sequence = read_seqcount_begin(&xfrm_policy_hash_generation);
chain = policy_hash_direct(net, daddr, saddr, family, dir);
} while (read_seqcount_retry(&xfrm_policy_hash_generation, sequence));
priority = ~0U;
ret = NULL;
hlist_for_each_entry_rcu(pol, chain, bydst) {
err = xfrm_policy_match(pol, fl, type, family, dir);
if (err) {
if (err == -ESRCH)
continue;
else {
ret = ERR_PTR(err);
goto fail;
}
} else {
ret = pol;
priority = ret->priority;
break;
}
}
chain = &net->xfrm.policy_inexact[dir];
hlist_for_each_entry_rcu(pol, chain, bydst) {
if ((pol->priority >= priority) && ret)
break;
err = xfrm_policy_match(pol, fl, type, family, dir);
if (err) {
if (err == -ESRCH)
continue;
else {
ret = ERR_PTR(err);
goto fail;
}
} else {
ret = pol;
break;
}
}
if (read_seqcount_retry(&xfrm_policy_hash_generation, sequence))
goto retry;
if (ret && !xfrm_pol_hold_rcu(ret))
goto retry;
fail:
rcu_read_unlock();
return ret;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 124 | 37.92% | 5 | 23.81% |
James Morris | 65 | 19.88% | 1 | 4.76% |
Florian Westphal | 62 | 18.96% | 4 | 19.05% |
Alexey Kuznetsov | 24 | 7.34% | 1 | 4.76% |
Li RongQing | 14 | 4.28% | 1 | 4.76% |
Masahide Nakamura | 13 | 3.98% | 1 | 4.76% |
Alexey Dobriyan | 12 | 3.67% | 3 | 14.29% |
Trent Jaeger | 7 | 2.14% | 1 | 4.76% |
Hideaki Yoshifuji / 吉藤英明 | 2 | 0.61% | 1 | 4.76% |
Kazunori Miyazawa | 2 | 0.61% | 1 | 4.76% |
Herbert Xu | 1 | 0.31% | 1 | 4.76% |
Venkat Yekkirala | 1 | 0.31% | 1 | 4.76% |
Total | 327 | 100.00% | 21 | 100.00% |
static struct xfrm_policy *
__xfrm_policy_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir)
{
#ifdef CONFIG_XFRM_SUB_POLICY
struct xfrm_policy *pol;
pol = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_SUB, fl, family, dir);
if (pol != NULL)
return pol;
#endif
return xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN, fl, family, dir);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Masahide Nakamura | 46 | 63.01% | 1 | 16.67% |
Timo Teräs | 14 | 19.18% | 2 | 33.33% |
Alexey Dobriyan | 9 | 12.33% | 1 | 16.67% |
James Morris | 3 | 4.11% | 1 | 16.67% |
David S. Miller | 1 | 1.37% | 1 | 16.67% |
Total | 73 | 100.00% | 6 | 100.00% |
static int flow_to_policy_dir(int dir)
{
if (XFRM_POLICY_IN == FLOW_DIR_IN &&
XFRM_POLICY_OUT == FLOW_DIR_OUT &&
XFRM_POLICY_FWD == FLOW_DIR_FWD)
return dir;
switch (dir) {
default:
case FLOW_DIR_IN:
return XFRM_POLICY_IN;
case FLOW_DIR_OUT:
return XFRM_POLICY_OUT;
case FLOW_DIR_FWD:
return XFRM_POLICY_FWD;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Baker Zhang | 51 | 100.00% | 1 | 100.00% |
Total | 51 | 100.00% | 1 | 100.00% |
static struct flow_cache_object *
xfrm_policy_lookup(struct net *net, const struct flowi *fl, u16 family,
u8 dir, struct flow_cache_object *old_obj, void *ctx)
{
struct xfrm_policy *pol;
if (old_obj)
xfrm_pol_put(container_of(old_obj, struct xfrm_policy, flo));
pol = __xfrm_policy_lookup(net, fl, family, flow_to_policy_dir(dir));
if (IS_ERR_OR_NULL(pol))
return ERR_CAST(pol);
/* Resolver returns two references:
* one for cache and one for caller of flow_cache_lookup() */
xfrm_pol_hold(pol);
return &pol->flo;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Timo Teräs | 88 | 90.72% | 2 | 28.57% |
David S. Miller | 3 | 3.09% | 2 | 28.57% |
Baker Zhang | 3 | 3.09% | 1 | 14.29% |
James Morris | 2 | 2.06% | 1 | 14.29% |
Alexey Kuznetsov | 1 | 1.03% | 1 | 14.29% |
Total | 97 | 100.00% | 7 | 100.00% |
static inline int policy_to_flow_dir(int dir)
{
if (XFRM_POLICY_IN == FLOW_DIR_IN &&
XFRM_POLICY_OUT == FLOW_DIR_OUT &&
XFRM_POLICY_FWD == FLOW_DIR_FWD)
return dir;
switch (dir) {
default:
case XFRM_POLICY_IN:
return FLOW_DIR_IN;
case XFRM_POLICY_OUT:
return FLOW_DIR_OUT;
case XFRM_POLICY_FWD:
return FLOW_DIR_FWD;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trent Jaeger | 52 | 100.00% | 1 | 100.00% |
Total | 52 | 100.00% | 1 | 100.00% |
static struct xfrm_policy *xfrm_sk_policy_lookup(const struct sock *sk, int dir,
const struct flowi *fl, u16 family)
{
struct xfrm_policy *pol;
rcu_read_lock();
again:
pol = rcu_dereference(sk->sk_policy[dir]);
if (pol != NULL) {
bool match = xfrm_selector_match(&pol->selector, fl, family);
int err = 0;
if (match) {
if ((sk->sk_mark & pol->mark.m) != pol->mark.v) {
pol = NULL;
goto out;
}
err = security_xfrm_policy_lookup(pol->security,
fl->flowi_secid,
policy_to_flow_dir(dir));
if (!err) {
if (!xfrm_pol_hold_rcu(pol))
goto again;
} else if (err == -ESRCH) {
pol = NULL;
} else {
pol = ERR_PTR(err);
}
} else
pol = NULL;
}
out:
rcu_read_unlock();
return pol;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Alexey Kuznetsov | 51 | 27.72% | 2 | 10.53% |
Jamal Hadi Salim | 31 | 16.85% | 1 | 5.26% |
Trent Jaeger | 24 | 13.04% | 1 | 5.26% |
Venkat Yekkirala | 24 | 13.04% | 2 | 10.53% |
Florian Westphal | 17 | 9.24% | 2 | 10.53% |
Eric Dumazet | 14 | 7.61% | 2 | 10.53% |
Kazunori Miyazawa | 9 | 4.89% | 1 | 5.26% |
Steffen Klassert | 4 | 2.17% | 1 | 5.26% |
David S. Miller | 3 | 1.63% | 3 | 15.79% |
Arnaldo Carvalho de Melo | 3 | 1.63% | 1 | 5.26% |
Paul Moore | 2 | 1.09% | 1 | 5.26% |
Adrian Bunk | 1 | 0.54% | 1 | 5.26% |
Hideaki Yoshifuji / 吉藤英明 | 1 | 0.54% | 1 | 5.26% |
Total | 184 | 100.00% | 19 | 100.00% |
static void __xfrm_policy_link(struct xfrm_policy *pol, int dir)
{
struct net *net = xp_net(pol);
list_add(&pol->walk.all, &net->xfrm.policy_all);
net->xfrm.policy_count[dir]++;
xfrm_pol_hold(pol);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Alexey Kuznetsov | 20 | 35.71% | 1 | 10.00% |
Alexey Dobriyan | 19 | 33.93% | 3 | 30.00% |
Herbert Xu | 14 | 25.00% | 3 | 30.00% |
James Morris | 1 | 1.79% | 1 | 10.00% |
David S. Miller | 1 | 1.79% | 1 | 10.00% |
Masahide Nakamura | 1 | 1.79% | 1 | 10.00% |
Total | 56 | 100.00% | 10 | 100.00% |
static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
int dir)
{
struct net *net = xp_net(pol);
if (list_empty(&pol->walk.all))
return NULL;
/* Socket policies are not hashed. */
if (!hlist_unhashed(&pol->bydst)) {
hlist_del_rcu(&pol->bydst);
hlist_del(&pol->byidx);
}
list_del_init(&pol->walk.all);
net->xfrm.policy_count[dir]--;
return pol;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Herbert Xu | 37 | 39.36% | 3 | 33.33% |
David S. Miller | 21 | 22.34% | 1 | 11.11% |
Alexey Kuznetsov | 16 | 17.02% | 1 | 11.11% |
Alexey Dobriyan | 15 | 15.96% | 2 | 22.22% |
Masahide Nakamura | 4 | 4.26% | 1 | 11.11% |
Florian Westphal | 1 | 1.06% | 1 | 11.11% |
Total | 94 | 100.00% | 9 | 100.00% |
static void xfrm_sk_policy_link(struct xfrm_policy *pol, int dir)
{
__xfrm_policy_link(pol, XFRM_POLICY_MAX + dir);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Herbert Xu | 23 | 100.00% | 1 | 100.00% |
Total | 23 | 100.00% | 1 | 100.00% |
static void xfrm_sk_policy_unlink(struct xfrm_policy *pol, int dir)
{
__xfrm_policy_unlink(pol, XFRM_POLICY_MAX + dir);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Herbert Xu | 23 | 100.00% | 1 | 100.00% |
Total | 23 | 100.00% | 1 | 100.00% |
int xfrm_policy_delete(struct xfrm_policy *pol, int dir)
{
struct net *net = xp_net(pol);
spin_lock_bh(&net->xfrm.xfrm_policy_lock);
pol = __xfrm_policy_unlink(pol, dir);
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
if (pol) {
xfrm_policy_kill(pol);
return 0;
}
return -ENOENT;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Herbert Xu | 47 | 67.14% | 2 | 33.33% |
Fan Du | 18 | 25.71% | 1 | 16.67% |
Eugene Surovegin | 2 | 2.86% | 1 | 16.67% |
Florian Westphal | 2 | 2.86% | 1 | 16.67% |
Alexey Kuznetsov | 1 | 1.43% | 1 | 16.67% |
Total | 70 | 100.00% | 6 | 100.00% |
EXPORT_SYMBOL(xfrm_policy_delete);
int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
{
struct net *net = xp_net(pol);
struct xfrm_policy *old_pol;
#ifdef CONFIG_XFRM_SUB_POLICY
if (pol && pol->type != XFRM_POLICY_TYPE_MAIN)
return -EINVAL;
#endif
spin_lock_bh(&net->xfrm.xfrm_policy_lock);
old_pol = rcu_dereference_protected(sk->sk_policy[dir],
lockdep_is_held(&net->xfrm.xfrm_policy_lock));
if (pol) {
pol->curlft.add_time = get_seconds();
pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir, 0);
xfrm_sk_policy_link(pol, dir);
}
rcu_assign_pointer(sk->sk_policy[dir], pol);
if (old_pol) {
if (pol)
xfrm_policy_requeue(old_pol, pol);
/* Unlinking succeeds always. This is the only function
* allowed to delete or replace socket policy.
*/
xfrm_sk_policy_unlink(old_pol, dir);
}
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
if (old_pol) {
xfrm_policy_kill(old_pol);
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Alexey Kuznetsov | 96 | 52.75% | 2 | 15.38% |
Eric Dumazet | 24 | 13.19% | 1 | 7.69% |
Masahide Nakamura | 19 | 10.44% | 1 | 7.69% |
Steffen Klassert | 13 | 7.14% | 1 | 7.69% |
Alexey Dobriyan | 12 | 6.59% | 1 | 7.69% |
Fan Du | 10 | 5.49% | 2 | 15.38% |
Florian Westphal | 2 | 1.10% | 1 | 7.69% |
James Morris | 2 | 1.10% | 1 | 7.69% |
Herbert Xu | 2 | 1.10% | 1 | 7.69% |
Timo Teräs | 1 | 0.55% | 1 | 7.69% |
Arnaldo Carvalho de Melo | 1 | 0.55% | 1 | 7.69% |
Total | 182 | 100.00% | 13 | 100.00% |
static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir)
{
struct xfrm_policy *newp = xfrm_policy_alloc(xp_net(old), GFP_ATOMIC);
struct net *net = xp_net(old);
if (newp) {
newp->selector = old->selector;
if (security_xfrm_policy_clone(old->security,
&newp->security)) {
kfree(newp);
return NULL; /* ENOMEM */
}
newp->lft = old->lft;
newp->curlft = old->curlft;
newp->mark = old->mark;
newp->action = old->action;
newp->flags = old->flags;
newp->xfrm_nr = old->xfrm_nr;
newp->index = old->index;
newp->type = old->type;
memcpy(newp->xfrm_vec, old->xfrm_vec,
newp->xfrm_nr*sizeof(struct xfrm_tmpl));
spin_lock_bh(&net->xfrm.xfrm_policy_lock);
xfrm_sk_policy_link(newp, dir);
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
xfrm_pol_put(newp);
}
return newp;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Alexey Kuznetsov | 123 | 61.19% | 4 | 28.57% |
Trent Jaeger | 20 | 9.95% | 1 | 7.14% |
Fan Du | 18 | 8.96% | 1 | 7.14% |
Masahide Nakamura | 13 | 6.47% | 1 | 7.14% |
Jamal Hadi Salim | 8 | 3.98% | 1 | 7.14% |
Herbert Xu | 6 | 2.99% | 2 | 14.29% |
Alexey Dobriyan | 5 | 2.49% | 1 | 7.14% |
Paul Moore | 5 | 2.49% | 1 | 7.14% |
Florian Westphal | 2 | 1.00% | 1 | 7.14% |
David S. Miller | 1 | 0.50% | 1 | 7.14% |
Total | 201 | 100.00% | 14 | 100.00% |
int __xfrm_sk_clone_policy(struct sock *sk, const struct sock *osk)
{
const struct xfrm_policy *p;
struct xfrm_policy *np;
int i, ret = 0;
rcu_read_lock();
for (i = 0; i < 2; i++) {
p = rcu_dereference(osk->sk_policy[i]);
if (p) {
np = clone_policy(p, i);
if (unlikely(!np)) {
ret = -ENOMEM;
break;
}
rcu_assign_pointer(sk->sk_policy[i], np);
}
}
rcu_read_unlock();
return ret;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Eric Dumazet | 71 | 62.83% | 1 | 20.00% |
Alexey Kuznetsov | 37 | 32.74% | 3 | 60.00% |
Arnaldo Carvalho de Melo | 5 | 4.42% | 1 | 20.00% |
Total | 113 | 100.00% | 5 | 100.00% |
static int
xfrm_get_saddr(struct net *net, int oif, xfrm_address_t *local,
xfrm_address_t *remote, unsigned short family)
{
int err;
const struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
if (unlikely(afinfo == NULL))
return -EINVAL;
err = afinfo->get_saddr(net, oif, local, remote);
rcu_read_unlock();
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick McHardy | 59 | 79.73% | 1 | 20.00% |
Alexey Dobriyan | 7 | 9.46% | 1 | 20.00% |
David Ahern | 5 | 6.76% | 1 | 20.00% |
Florian Westphal | 3 | 4.05% | 2 | 40.00% |
Total | 74 | 100.00% | 5 | 100.00% |
/* Resolve list of templates for the flow, given policy. */
static int
xfrm_tmpl_resolve_one(struct xfrm_policy *policy, const struct flowi *fl,
struct xfrm_state **xfrm, unsigned short family)
{
struct net *net = xp_net(policy);
int nx;
int i, error;
xfrm_address_t *daddr = xfrm_flowi_daddr(fl, family);
xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family);
xfrm_address_t tmp;
for (nx = 0, i = 0; i < policy->xfrm_nr; i++) {
struct xfrm_state *x;
xfrm_address_t *remote = daddr;
xfrm_address_t *local = saddr;
struct xfrm_tmpl *tmpl = &policy->xfrm_vec[i];
if (tmpl->mode == XFRM_MODE_TUNNEL ||
tmpl->mode == XFRM_MODE_BEET) {
remote = &tmpl->id.daddr;
local = &tmpl->saddr;
if (xfrm_addr_any(local, tmpl->encap_family)) {
error = xfrm_get_saddr(net, fl->flowi_oif,
&tmp, remote,
tmpl->encap_family);
if (error)
goto fail;
local = &tmp;
}
}
x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, family);
if (x && x->km.state == XFRM_STATE_VALID) {
xfrm[nx++] = x;
daddr = remote;
saddr = local;
continue;
}
if (x) {
error = (x->km.state == XFRM_STATE_ERROR ?
-EINVAL : -EAGAIN);
xfrm_state_put(x);
} else if (error == -ESRCH) {
error = -EAGAIN;
}
if (!tmpl->optional)
goto fail;
}
return nx;
fail:
for (nx--; nx >= 0; nx--)
xfrm_state_put(xfrm[nx]);
return error;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Alexey Kuznetsov | 221 | 66.77% | 3 | 21.43% |
Patrick McHardy | 36 | 10.88% | 1 | 7.14% |
Hideaki Yoshifuji / 吉藤英明 | 27 | 8.16% | 1 | 7.14% |
Fernando Luis Vázquez Cao | 13 | 3.93% | 1 | 7.14% |
Alexey Dobriyan | 12 | 3.63% | 1 | 7.14% |
Joakim Koskela | 6 | 1.81% | 1 | 7.14% |
Thomas Egerer | 6 | 1.81% | 1 | 7.14% |
David Ahern | 4 | 1.21% | 1 | 7.14% |
Masahide Nakamura | 3 | 0.91% | 2 | 14.29% |
Weilong Chen | 2 | 0.60% | 1 | 7.14% |
David S. Miller | 1 | 0.30% | 1 | 7.14% |
Total | 331 | 100.00% | 14 | 100.00% |
static int
xfrm_tmpl_resolve(struct xfrm_policy **pols, int npols, const struct flowi *fl,
struct xfrm_state **xfrm, unsigned short family)
{
struct xfrm_state *tp[XFRM_MAX_DEPTH];
struct xfrm_state **tpp = (npols > 1) ? tp : xfrm;
int cnx = 0;
int error;
int ret;
int i;
for (i = 0; i < npols; i++) {
if (cnx + pols[i]->xfrm_nr >= XFRM_MAX_DEPTH) {
error = -ENOBUFS;
goto fail;
}
ret = xfrm_tmpl_resolve_one(pols[i], fl, &tpp[cnx], family);
if (ret < 0) {
error = ret;
goto fail;
} else
cnx += ret;
}
/* found states are sorted for outbound processing */
if (npols > 1)
xfrm_state_sort(xfrm, tpp, cnx, family);
return cnx;
fail:
for (cnx--; cnx >= 0; cnx--)
xfrm_state_put(tpp[cnx]);
return error;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Masahide Nakamura | 192 | 99.48% | 2 | 66.67% |
David S. Miller | 1 | 0.52% | 1 | 33.33% |
Total | 193 | 100.00% | 3 | 100.00% |
static int xfrm_get_tos(const struct flowi *fl, int family)
{
const struct xfrm_policy_afinfo *afinfo;
int tos = 0;
afinfo = xfrm_policy_get_afinfo(family);
tos = afinfo ? afinfo->get_tos(fl) : 0;
rcu_read_unlock();
return tos;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Florian Westphal | 15 | 28.85% | 3 | 33.33% |
Hideaki Yoshifuji / 吉藤英明 | 14 | 26.92% | 1 | 11.11% |
Alexey Kuznetsov | 11 | 21.15% | 2 | 22.22% |
Timo Teräs | 9 | 17.31% | 1 | 11.11% |
Kazunori Miyazawa | 2 | 3.85% | 1 | 11.11% |
David S. Miller | 1 | 1.92% | 1 | 11.11% |
Total | 52 | 100.00% | 9 | 100.00% |
static struct flow_cache_object *xfrm_bundle_flo_get(struct flow_cache_object *flo)
{
struct xfrm_dst *xdst = container_of(flo, struct xfrm_dst, flo);
struct dst_entry *dst = &xdst->u.dst;
if (xdst->route == NULL) {
/* Dummy bundle - if it has xfrms we were not
* able to build bundle as template resolution failed.
* It means we need to try again resolving. */
if (xdst->num_xfrms > 0)
return NULL;
} else if (dst->flags & DST_XFRM_QUEUE) {
return NULL;
} else {
/* Real bundle */
if (stale_bundle(dst))
return NULL;
}
dst_hold(dst);
return flo;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Timo Teräs | 58 | 59.18% | 1 | 14.29% |
Steffen Klassert | 14 | 14.29% | 1 | 14.29% |
Kazunori Miyazawa | 9 | 9.18% | 1 | 14.29% |
Hideaki Yoshifuji / 吉藤英明 | 9 | 9.18% | 1 | 14.29% |
Alexey Kuznetsov | 7 | 7.14% | 2 | 28.57% |
Herbert Xu | 1 | 1.02% | 1 | 14.29% |
Total | 98 | 100.00% | 7 | 100.00% |
static int xfrm_bundle_flo_check(struct flow_cache_object *flo)
{
struct xfrm_dst *xdst = container_of(flo, struct xfrm_dst, flo);
struct dst_entry *dst = &xdst->u.dst;
if (!xdst->route)
return 0;
if (stale_bundle(dst))
return 0;
return 1;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Timo Teräs | 40 | 65.57% | 1 | 25.00% |
Masahide Nakamura | 10 | 16.39% | 1 | 25.00% |
Herbert Xu | 9 | 14.75% | 1 | 25.00% |
Alexey Dobriyan | 2 | 3.28% | 1 | 25.00% |
Total | 61 | 100.00% | 4 | 100.00% |
static void xfrm_bundle_flo_delete(struct flow_cache_object *flo)
{
struct xfrm_dst *xdst = container_of(flo, struct xfrm_dst, flo);
struct dst_entry *dst = &xdst->u.dst;
dst_free(dst);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Timo Teräs | 43 | 100.00% | 1 | 100.00% |
Total | 43 | 100.00% | 1 | 100.00% |
static const struct flow_cache_ops xfrm_bundle_fc_ops = {
.get = xfrm_bundle_flo_get,
.check = xfrm_bundle_flo_check,
.delete = xfrm_bundle_flo_delete,
};
static inline struct xfrm_dst *xfrm_alloc_dst(struct net *net, int family)
{
const struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
struct dst_ops *dst_ops;
struct xfrm_dst *xdst;
if (!afinfo)
return ERR_PTR(-EINVAL);
switch (family) {
case AF_INET:
dst_ops = &net->xfrm.xfrm4_dst_ops;
break;
#if IS_ENABLED(CONFIG_IPV6)
case AF_INET6:
dst_ops = &net->xfrm.xfrm6_dst_ops;
break;
#endif
default:
BUG();
}
xdst = dst_alloc(dst_ops, NULL, 0, DST_OBSOLETE_NONE, 0);
if (likely(xdst)) {
struct dst_entry *dst = &xdst->u.dst;
memset(dst + 1, 0, sizeof(*xdst) - sizeof(*dst));
xdst->flo.ops = &xfrm_bundle_fc_ops;
} else
xdst = ERR_PTR(-ENOBUFS);
rcu_read_unlock();
return xdst;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Timo Teräs | 56 | 32.00% | 1 | 7.14% |
Alexey Dobriyan | 43 | 24.57% | 1 | 7.14% |
David S. Miller | 27 | 15.43% | 4 | 28.57% |
Steffen Klassert | 14 | 8.00% | 1 | 7.14% |
Madalin Bucur | 10 | 5.71% | 1 | 7.14% |
Hiroaki SHIMODA | 9 | 5.14% | 1 | 7.14% |
Herbert Xu | 7 | 4.00% | 1 | 7.14% |
Masahide Nakamura | 5 | 2.86% | 1 | 7.14% |
Florian Westphal | 3 | 1.71% | 2 | 14.29% |
Eric Dumazet | 1 | 0.57% | 1 | 7.14% |
Total | 175 | 100.00% | 14 | 100.00% |
static inline int xfrm_init_path(struct xfrm_dst *path, struct dst_entry *dst,
int nfheader_len)
{
const struct xfrm_policy_afinfo *afinfo =
xfrm_policy_get_afinfo(dst->ops->family);
int err;
if (!afinfo)
return -EINVAL;
err = afinfo->init_path(path, dst, nfheader_len);
rcu_read_unlock();
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Masahide Nakamura | 63 | 95.45% | 1 | 33.33% |
Florian Westphal | 3 | 4.55% | 2 | 66.67% |
Total | 66 | 100.00% | 3 | 100.00% |
static inline int xfrm_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
const struct flowi *fl)
{
const struct xfrm_policy_afinfo *afinfo =
xfrm_policy_get_afinfo(xdst->u.dst.ops->family);
int err;
if (!afinfo)
return -EINVAL;
err = afinfo->fill_dst(xdst, dev, fl);
rcu_read_unlock();
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Herbert Xu | 46 | 63.01% | 2 | 33.33% |
Masahide Nakamura | 23 | 31.51% | 1 | 16.67% |
Florian Westphal | 3 | 4.11% | 2 | 33.33% |
David S. Miller | 1 | 1.37% | 1 | 16.67% |
Total | 73 | 100.00% | 6 | 100.00% |
/* Allocate chain of dst_entry's, attach known xfrm's, calculate
* all the metrics... Shortly, bundle a bundle.
*/
static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
struct xfrm_state **xfrm, int nx,
const struct flowi *fl,
struct dst_entry *dst)
{
struct net *net = xp_net(policy);
unsigned long now = jiffies;
struct net_device *dev;
struct xfrm_mode *inner_mode;
struct dst_entry *dst_prev = NULL;
struct dst_entry *dst0 = NULL;
int i = 0;
int err;
int header_len = 0;
int nfheader_len = 0;
int trailer_len = 0;
int tos;
int family = policy->selector.family;
xfrm_address_t saddr, daddr;
xfrm_flowi_addr_get(fl, &saddr, &daddr, family);
tos = xfrm_get_tos(fl, family);
dst_hold(dst);
for (; i < nx; i++) {
struct xfrm_dst *xdst = xfrm_alloc_dst(net, family);
struct dst_entry *dst1 = &xdst->u.dst;
err = PTR_ERR(xdst);
if (IS_ERR(xdst)) {
dst_release(dst);
goto put_states;
}
if (xfrm[i]->sel.family == AF_UNSPEC) {
inner_mode = xfrm_ip2inner_mode(xfrm[i],
xfrm_af2proto(family));
if (!inner_mode) {
err = -EAFNOSUPPORT;
dst_release(dst);
goto put_states;
}
} else
inner_mode = xfrm[i]->inner_mode;
if (!dst_prev)
dst0 = dst1;
else {
dst_prev->child = dst_clone(dst1);
dst1->flags |= DST_NOHASH;
}
xdst->route = dst;
dst_copy_metrics(dst1, dst);
if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
family = xfrm[i]->props.family;
dst = xfrm_dst_lookup(xfrm[i], tos, fl->flowi_oif,
&saddr, &daddr, family);
err = PTR_ERR(dst);
if (IS_ERR(dst))
goto put_states;
} else
dst_hold(dst);
dst1->xfrm = xfrm[i];
xdst->xfrm_genid = xfrm[i]->genid;
dst1->obsolete = DST_OBSOLETE_FORCE_CHK;
dst1->flags |= DST_HOST;
dst1->lastuse = now;
dst1->input = dst_discard;
dst1->output = inner_mode->afinfo->output;
dst1->next = dst_prev;
dst_prev = dst1;
header_len += xfrm[i]->props.header_len;
if (xfrm[i]->type->flags & XFRM_TYPE_NON_FRAGMENT)
nfheader_len += xfrm[i]->props.header_len;
trailer_len += xfrm[i]->props.trailer_len;
}
dst_prev->child = dst;
dst0->path = dst;
err = -ENODEV;
dev = dst->dev;
if (!dev)
goto free_dst;
xfrm_init_path((struct xfrm_dst *)dst0, dst, nfheader_len);
xfrm_init_pmtu(dst_prev);
for (dst_prev = dst0; dst_prev != dst; dst_prev = dst_prev->child) {
struct xfrm_dst *xdst = (struct xfrm_dst *)dst_prev;
err = xfrm_fill_dst(xdst, dev, fl);
if (err)
goto free_dst;
dst_prev->header_len = header_len;
dst_prev->trailer_len = trailer_len;
header_len -= xdst->u.dst.xfrm->props.header_len;
trailer_len -= xdst->u.dst.xfrm->props.trailer_len;
}
out:
return dst0;
put_states:
for (; i < nx; i++)
xfrm_state_put(xfrm[i]);
free_dst:
if (dst0)
dst_free(dst0);
dst0 = ERR_PTR(err);
goto out;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Herbert Xu | 510 | 76.46% | 2 | 16.67% |
Steffen Klassert | 66 | 9.90% | 1 | 8.33% |
Masahide Nakamura | 47 | 7.05% | 2 | 16.67% |
Hideaki Yoshifuji / 吉藤英明 | 24 | 3.60% | 1 | 8.33% |
Alexey Dobriyan | 12 | 1.80% | 1 | 8.33% |
David Ahern | 4 | 0.60% | 1 | 8.33% |
David S. Miller | 3 | 0.45% | 3 | 25.00% |
Timo Teräs | 1 | 0.15% | 1 | 8.33% |
Total | 667 | 100.00% | 12 | 100.00% |
#ifdef CONFIG_XFRM_SUB_POLICY
static int xfrm_dst_alloc_copy(void **target, const void *src, int size)
{
if (!*target) {
*target = kmalloc(size, GFP_ATOMIC);
if (!*target)
return -ENOMEM;
}
memcpy(*target, src, size);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Herbert Xu | 59 | 98.33% | 1 | 50.00% |
David S. Miller | 1 | 1.67% | 1 | 50.00% |
Total | 60 | 100.00% | 2 | 100.00% |
#endif
static int xfrm_dst_update_parent(struct dst_entry *dst,
const struct xfrm_selector *sel)
{
#ifdef CONFIG_XFRM_SUB_POLICY
struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
return xfrm_dst_alloc_copy((void **)&(xdst->partner),
sel, sizeof(*sel));
#else
return 0;
#endif
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Herbert Xu | 62 | 98.41% | 1 | 50.00% |
David S. Miller | 1 | 1.59% | 1 | 50.00% |
Total | 63 | 100.00% | 2 | 100.00% |
static int xfrm_dst_update_origin(struct dst_entry *dst,
const struct flowi *fl)
{
#ifdef CONFIG_XFRM_SUB_POLICY
struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
return xfrm_dst_alloc_copy((void **)&(xdst->origin), fl, sizeof(*fl));
#else
return 0;
#endif
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Masahide Nakamura | 52 | 82.54% | 1 | 33.33% |
Herbert Xu | 10 | 15.87% | 1 | 33.33% |
David S. Miller | 1 | 1.59% | 1 | 33.33% |
Total | 63 | 100.00% | 3 | 100.00% |
static int xfrm_expand_policies(const struct flowi *fl, u16 family,
struct xfrm_policy **pols,
int *num_pols, int *num_xfrms)
{
int i;
if (*num_pols == 0 || !pols[0]) {
*num_pols = 0;
*num_xfrms = 0;
return 0;
}
if (IS_ERR(pols[0]))
return PTR_ERR(pols[0]);
*num_xfrms = pols[0]->xfrm_nr;
#ifdef CONFIG_XFRM_SUB_POLICY
if (pols[0] && pols[0]->action == XFRM_POLICY_ALLOW &&
pols[0]->type != XFRM_POLICY_TYPE_MAIN) {
pols[1] = xfrm_policy_lookup_bytype(xp_net(pols[0]),
XFRM_POLICY_TYPE_MAIN,
fl, family,
XFRM_POLICY_OUT);
if (pols[1]) {
if (IS_ERR(pols[1])) {
xfrm_pols_put(pols, *num_pols);
return PTR_ERR(pols[1]);
}
(*num_pols)++;
(*num_xfrms) += pols[1]->xfrm_nr;
}
}
#endif
for (i = 0; i < *num_pols; i++) {
if (pols[i]->action != XFRM_POLICY_ALLOW) {
*num_xfrms = -1;
break;
}
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Timo Teräs | 147 | 61.25% | 2 | 12.50% |
Masahide Nakamura | 35 | 14.58% | 3 | 18.75% |
Hideaki Yoshifuji / 吉藤英明 | 25 | 10.42% | 1 | 6.25% |
Kazunori Miyazawa | 16 | 6.67% | 1 | 6.25% |
James Morris | 6 | 2.50% | 1 | 6.25% |
Herbert Xu | 3 | 1.25% | 2 | 12.50% |
David S. Miller | 3 | 1.25% | 2 | 12.50% |
Alexey Dobriyan | 2 | 0.83% | 1 | 6.25% |
Patrick McHardy | 1 | 0.42% | 1 | 6.25% |
Alexey Kuznetsov | 1 | 0.42% | 1 | 6.25% |
Venkat Yekkirala | 1 | 0.42% | 1 | 6.25% |
Total | 240 | 100.00% | 16 | 100.00% |
static struct xfrm_dst *
xfrm_resolve_and_create_bundle(struct xfrm_policy **pols, int num_pols,
const struct flowi *fl, u16 family,
struct dst_entry *dst_orig)
{
struct net *net = xp_net(pols[0]);
struct xfrm_state *xfrm[XFRM_MAX_DEPTH];
struct dst_entry *dst;
struct xfrm_dst *xdst;
int err;
/* Try to instantiate a bundle */
err = xfrm_tmpl_resolve(pols, num_pols, fl, xfrm, family);
if (err <= 0) {
if (err != 0 && err != -EAGAIN)
XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR);
return ERR_PTR(err);
}
dst = xfrm_bundle_create(pols[0], xfrm, err, fl, dst_orig);
if (IS_ERR(dst)) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLEGENERROR);
return ERR_CAST(dst);
}
xdst = (struct xfrm_dst *)dst;
xdst->num_xfrms = err;
if (num_pols > 1)
err = xfrm_dst_update_parent(dst, &pols[1]->selector);
else
err = xfrm_dst_update_origin(dst, fl);
if (unlikely(err)) {
dst_free(dst);
XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLECHECKERROR);
return ERR_PTR(err);
}
xdst->num_pols = num_pols;
memcpy(xdst->pols, pols, sizeof(struct xfrm_policy *) * num_pols);
xdst->policy_genid = atomic_read(&pols[0]->genid);
return xdst;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Timo Teräs | 162 | 60.45% | 2 | 11.76% |
Masahide Nakamura | 46 | 17.16% | 3 | 17.65% |
Hideaki Yoshifuji / 吉藤英明 | 18 | 6.72% | 1 | 5.88% |
James Morris | 10 | 3.73% | 1 | 5.88% |
Alexey Kuznetsov | 10 | 3.73% | 2 | 11.76% |
Alexey Dobriyan | 9 | 3.36% | 2 | 11.76% |
David S. Miller | 8 | 2.99% | 3 | 17.65% |
Herbert Xu | 2 | 0.75% | 1 | 5.88% |
Kazunori Miyazawa | 2 | 0.75% | 1 | 5.88% |
Krishna Kumar | 1 | 0.37% | 1 | 5.88% |
Total | 268 | 100.00% | 17 | 100.00% |
static void xfrm_policy_queue_process(unsigned long arg)
{
struct sk_buff *skb;
struct sock *sk;
struct dst_entry *dst;
struct xfrm_policy *pol = (struct xfrm_policy *)arg;
struct net *net = xp_net(pol);
struct xfrm_policy_queue *pq = &pol->polq;
struct flowi fl;
struct sk_buff_head list;
spin_lock(&pq->hold_queue.lock);
skb = skb_peek(&pq->hold_queue);
if (!skb) {
spin_unlock(&pq->hold_queue.lock);
goto out;
}
dst = skb_dst(skb);
sk = skb->sk;
xfrm_decode_session(skb, &fl, dst->ops->family);
spin_unlock(&pq->hold_queue.lock);
dst_hold(dst->path);
dst = xfrm_lookup(net, dst->path, &fl, sk, 0);
if (IS_ERR(dst))
goto purge_queue;
if (dst->flags & DST_XFRM_QUEUE) {
dst_release(dst);
if (pq->timeout >= XFRM_QUEUE_TMO_MAX)
goto purge_queue;
pq->timeout = pq->timeout << 1;
if (!mod_timer(&pq->hold_timer, jiffies + pq->timeout))
xfrm_pol_hold(pol);
goto out;
}
dst_release(dst);
__skb_queue_head_init(&list);
spin_lock(&pq->hold_queue.lock);
pq->timeout = 0;
skb_queue_splice_init(&pq->hold_queue, &list);
spin_unlock(&pq->hold_queue.lock);
while (!skb_queue_empty(&list)) {
skb = __skb_dequeue(&list);
xfrm_decode_session(skb, &fl, skb_dst(skb)->ops->family);
dst_hold(skb_dst(skb)->path);
dst = xfrm_lookup(net, skb_dst(skb)->path, &fl, skb->sk, 0);
if (IS_ERR(dst)) {
kfree_skb(skb);
continue;
}
nf_reset(skb);
skb_dst_drop(skb);
skb_dst_set(skb, dst);
dst_output(net, skb->sk, skb);
}
out:
xfrm_pol_put(pol);
return;
purge_queue:
pq->timeout = 0;
skb_queue_purge(&pq->hold_queue);
xfrm_pol_put(pol);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Steffen Klassert | 401 | 93.91% | 3 | 37.50% |
Eric W. Biedermann | 18 | 4.22% | 3 | 37.50% |
Timo Teräs | 7 | 1.64% | 1 | 12.50% |
Li RongQing | 1 | 0.23% | 1 | 12.50% |
Total | 427 | 100.00% | 8 | 100.00% |
static int xdst_queue_output(struct net *net, struct sock *sk, struct sk_buff *skb)
{
unsigned long sched_next;
struct dst_entry *dst = skb_dst(skb);
struct xfrm_dst *xdst = (struct xfrm_dst *) dst;
struct xfrm_policy *pol = xdst->pols[0];
struct xfrm_policy_queue *pq = &pol->polq;
if (unlikely(skb_fclone_busy(sk, skb))) {
kfree_skb(skb);
return 0;
}
if (pq->hold_queue.qlen > XFRM_MAX_QUEUE_LEN) {
kfree_skb(skb);
return -EAGAIN;
}
skb_dst_force(skb);
spin_lock_bh(&pq->hold_queue.lock);
if (!pq->timeout)
pq->timeout = XFRM_QUEUE_TMO_MIN;
sched_next = jiffies + pq->timeout;
if (del_timer(&pq->hold_timer)) {
if (time_before(pq->hold_timer.expires, sched_next))
sched_next = pq->hold_timer.expires;
xfrm_pol_put(pol);
}
__skb_queue_tail(&pq->hold_queue, skb);
if (!mod_timer(&pq->hold_timer, sched_next))
xfrm_pol_hold(pol);
spin_unlock_bh(&pq->hold_queue.lock);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Steffen Klassert | 212 | 93.39% | 3 | 42.86% |
Eric Dumazet | 10 | 4.41% | 3 | 42.86% |
Eric W. Biedermann | 5 | 2.20% | 1 | 14.29% |
Total | 227 | 100.00% | 7 | 100.00% |
static struct xfrm_dst *xfrm_create_dummy_bundle(struct net *net,
struct xfrm_flo *xflo,
const struct flowi *fl,
int num_xfrms,
u16 family)
{
int err;
struct net_device *dev;
struct dst_entry *dst;
struct dst_entry *dst1;
struct xfrm_dst *xdst;
xdst = xfrm_alloc_dst(net, family);
if (IS_ERR(xdst))
return xdst;
if (!(xflo->flags & XFRM_LOOKUP_QUEUE) ||
net->xfrm.sysctl_larval_drop ||
num_xfrms <= 0)
return xdst;
dst = xflo->dst_orig;
dst1 = &xdst->u.dst;
dst_hold(dst);
xdst->route = dst;
dst_copy_metrics(dst1, dst);
dst1->obsolete = DST_OBSOLETE_FORCE_CHK;
dst1->flags |= DST_HOST | DST_XFRM_QUEUE;
dst1->lastuse = jiffies;
dst1->input = dst_discard;
dst1->output = xdst_queue_output;
dst_hold(dst);
dst1->child = dst;
dst1->path = dst;
xfrm_init_path((struct xfrm_dst *)dst1, dst, 0);
err = -ENODEV;
dev = dst->dev;
if (!dev)
goto free_dst;
err = xfrm_fill_dst(xdst, dev, fl);
if (err)
goto free_dst;
out:
return xdst;
free_dst:
dst_release(dst1);
xdst = ERR_PTR(err);
goto out;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Steffen Klassert | 198 | 78.88% | 2 | 15.38% |
Timo Teräs | 18 | 7.17% | 1 | 7.69% |
Masahide Nakamura | 17 | 6.77% | 2 | 15.38% |
James Morris | 6 | 2.39% | 1 | 7.69% |
Alexey Kuznetsov | 4 | 1.59% | 2 | 15.38% |
Hideaki Yoshifuji / 吉藤英明 | 2 | 0.80% | 1 | 7.69% |
Herbert Xu | 2 | 0.80% | 1 | 7.69% |
Alexey Dobriyan | 2 | 0.80% | 1 | 7.69% |
Kazunori Miyazawa | 1 | 0.40% | 1 | 7.69% |
David S. Miller | 1 | 0.40% | 1 | 7.69% |
Total | 251 | 100.00% | 13 | 100.00% |
static struct flow_cache_object *
xfrm_bundle_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir,
struct flow_cache_object *oldflo, void *ctx)
{
struct xfrm_flo *xflo = (struct xfrm_flo *)ctx;
struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
struct xfrm_dst *xdst, *new_xdst;
int num_pols = 0, num_xfrms = 0, i, err, pol_dead;
/* Check if the policies from old bundle are usable */
xdst = NULL;
if (oldflo) {
xdst = container_of(oldflo, struct xfrm_dst, flo);
num_pols = xdst->num_pols;
num_xfrms = xdst->num_xfrms;
pol_dead = 0;
for (i = 0; i < num_pols; i++) {
pols[i] = xdst->pols[i];
pol_dead |= pols[i]->walk.dead;
}
if (pol_dead) {
dst_free(&xdst->u.dst);
xdst = NULL;
num_pols = 0;
num_xfrms = 0;
oldflo = NULL;
}
}
/* Resolve policies to use if we couldn't get them from
* previous cache entry */
if (xdst == NULL) {
num_pols = 1;
pols[0] = __xfrm_policy_lookup(net, fl, family,
flow_to_policy_dir(dir));
err = xfrm_expand_policies(fl, family, pols,
&num_pols, &num_xfrms);
if (err < 0)
goto inc_error;
if (num_pols == 0)
return NULL;
if (num_xfrms <= 0)
goto make_dummy_bundle;
}
new_xdst = xfrm_resolve_and_create_bundle(pols, num_pols, fl, family,
xflo->dst_orig);
if (IS_ERR(new_xdst)) {
err = PTR_ERR(new_xdst);
if (err != -EAGAIN)
goto error;
if (oldflo == NULL)
goto make_dummy_bundle;
dst_hold(&xdst->u.dst);
return oldflo;
} else if (new_xdst == NULL) {
num_xfrms = 0;
if (oldflo == NULL)
goto make_dummy_bundle;
xdst->num_xfrms = 0;
dst_hold(&xdst->u.dst);
return oldflo;
}
/* Kill the previous bundle */
if (xdst) {
/* The policies were stolen for newly generated bundle */
xdst->num_pols = 0;
dst_free(&xdst->u.dst);
}
/* Flow cache does not have reference, it dst_free()'s,
* but we do need to return one reference for original caller */
dst_hold(&new_xdst->u.dst);
return &new_xdst->flo;
make_dummy_bundle:
/* We found policies, but there's no bundles to instantiate:
* either because the policy blocks, has no transformations or
* we could not build template (no xfrm_states).*/
xdst = xfrm_create_dummy_bundle(net, xflo, fl, num_xfrms, family);
if (IS_ERR(xdst)) {
xfrm_pols_put(pols, num_pols);
return ERR_CAST(xdst);
}
xdst->num_pols = num_pols;
xdst->num_xfrms = num_xfrms;
memcpy(xdst->pols, pols, sizeof(struct xfrm_policy *) * num_pols);
dst_hold(&xdst->u.dst);
return &xdst->flo;
inc_error:
XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR);
error:
if (xdst != NULL)
dst_free(&xdst->u.dst);
else
xfrm_pols_put(pols, num_pols);
return ERR_PTR(err);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Timo Teräs | 392 | 73.13% | 2 | 10.00% |
Masahide Nakamura | 60 | 11.19% | 3 | 15.00% |
Hideaki Yoshifuji / 吉藤英明 | 18 | 3.36% | 1 | 5.00% |
Alexey Kuznetsov | 17 | 3.17% | 1 | 5.00% |
Herbert Xu | 15 | 2.80% | 6 | 30.00% |
Steffen Klassert | 12 | 2.24% | 2 | 10.00% |
Kazunori Miyazawa | 12 | 2.24% | 1 | 5.00% |
Alexey Dobriyan | 4 | 0.75% | 1 | 5.00% |
Baker Zhang | 3 | 0.56% | 1 | 5.00% |
Krishna Kumar | 2 | 0.37% | 1 | 5.00% |
David S. Miller | 1 | 0.19% | 1 | 5.00% |
Total | 536 | 100.00% | 20 | 100.00% |
static struct dst_entry *make_blackhole(struct net *net, u16 family,
struct dst_entry *dst_orig)
{
const struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
struct dst_entry *ret;
if (!afinfo) {
dst_release(dst_orig);
return ERR_PTR(-EINVAL);
} else {
ret = afinfo->blackhole_route(net, dst_orig);
}
rcu_read_unlock();
return ret;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 71 | 93.42% | 1 | 25.00% |
Florian Westphal | 3 | 3.95% | 2 | 50.00% |
Li RongQing | 2 | 2.63% | 1 | 25.00% |
Total | 76 | 100.00% | 4 | 100.00% |
/* Main function: finds/creates a bundle for given flow.
*
* At the moment we eat a raw IP route. Mostly to speed up lookups
* on interfaces with disabled IPsec.
*/
struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
const struct flowi *fl,
const struct sock *sk, int flags)
{
struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
struct flow_cache_object *flo;
struct xfrm_dst *xdst;
struct dst_entry *dst, *route;
u16 family = dst_orig->ops->family;
u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT);
int i, err, num_pols, num_xfrms = 0, drop_pols = 0;
dst = NULL;
xdst = NULL;
route = NULL;
sk = sk_const_to_full_sk(sk);
if (sk && sk->sk_policy[XFRM_POLICY_OUT]) {
num_pols = 1;
pols[0] = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl, family);
err = xfrm_expand_policies(fl, family, pols,
&num_pols, &num_xfrms);
if (err < 0)
goto dropdst;
if (num_pols) {
if (num_xfrms <= 0) {
drop_pols = num_pols;
goto no_transform;
}
xdst = xfrm_resolve_and_create_bundle(
pols, num_pols, fl,
family, dst_orig);
if (IS_ERR(xdst)) {
xfrm_pols_put(pols, num_pols);
err = PTR_ERR(xdst);
goto dropdst;
} else if (xdst == NULL) {
num_xfrms = 0;
drop_pols = num_pols;
goto no_transform;
}
dst_hold(&xdst->u.dst);
xdst->u.dst.flags |= DST_NOCACHE;
route = xdst->route;
}
}
if (xdst == NULL) {
struct xfrm_flo xflo;
xflo.dst_orig = dst_orig;
xflo.flags = flags;
/* To accelerate a bit... */
if ((dst_orig->flags & DST_NOXFRM) ||
!net->xfrm.policy_count[XFRM_POLICY_OUT])
goto nopol;
flo = flow_cache_lookup(net, fl, family, dir,
xfrm_bundle_lookup, &xflo);
if (flo == NULL)
goto nopol;
if (IS_ERR(flo)) {
err = PTR_ERR(flo);
goto dropdst;
}
xdst = container_of(flo, struct xfrm_dst, flo);
num_pols = xdst->num_pols;
num_xfrms = xdst->num_xfrms;
memcpy(pols, xdst->pols, sizeof(struct xfrm_policy *) * num_pols);
route = xdst->route;
}
dst = &xdst->u.dst;
if (route == NULL && num_xfrms > 0) {
/* The only case when xfrm_bundle_lookup() returns a
* bundle with null route, is when the template could
* not be resolved. It means policies are there, but
* bundle could not be created, since we don't yet
* have the xfrm_state's. We need to wait for KM to
* negotiate new SA's or bail out with error.*/
if (net->xfrm.sysctl_larval_drop) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
err = -EREMOTE;
goto error;
}
err = -EAGAIN;
XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
goto error;
}
no_transform:
if (num_pols == 0)
goto nopol;
if ((flags & XFRM_LOOKUP_ICMP) &&
!(pols[0]->flags & XFRM_POLICY_ICMP)) {
err = -ENOENT;
goto error;
}
for (i = 0; i < num_pols; i++)
pols[i]->curlft.use_time = get_seconds();
if (num_xfrms < 0) {
/* Prohibit the flow */
XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLBLOCK);
err = -EPERM;
goto error;
} else if (num_xfrms > 0) {
/* Flow transformed */
dst_release(dst_orig);
} else {
/* Flow passes untransformed */
dst_release(dst);
dst = dst_orig;
}
ok:
xfrm_pols_put(pols, drop_pols);
if (dst && dst->xfrm &&
dst->xfrm->props.mode == XFRM_MODE_TUNNEL)
dst->flags |= DST_XFRM_TUNNEL;
return dst;
nopol:
if (!(flags & XFRM_LOOKUP_ICMP)) {
dst = dst_orig;
goto ok;
}
err = -ENOENT;
error:
dst_release(dst);
dropdst:
if (!(flags & XFRM_LOOKUP_KEEP_DST_REF))
dst_release(dst_orig);
xfrm_pols_put(pols, drop_pols);
return ERR_PTR(err);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Timo Teräs | 433 | 62.30% | 3 | 10.34% |
David S. Miller | 50 | 7.19% | 4 | 13.79% |
Alexey Kuznetsov | 43 | 6.19% | 2 | 6.90% |
Steffen Klassert | 42 | 6.04% | 4 | 13.79% |
Masahide Nakamura | 28 | 4.03% | 3 | 10.34% |
Gao Feng | 24 | 3.45% | 1 | 3.45% |
Herbert Xu | 20 | 2.88% | 1 | 3.45% |
Huaibin Wang | 15 | 2.16% | 1 | 3.45% |
Alexey Dobriyan | 8 | 1.15% | 2 | 6.90% |
Eric Dumazet | 8 | 1.15% | 2 | 6.90% |
Venkat Yekkirala | 7 | 1.01% | 1 | 3.45% |
Hideaki Yoshifuji / 吉藤英明 | 5 | 0.72% | 1 | 3.45% |
Patrick McHardy | 4 | 0.58% | 1 | 3.45% |
Adrian Bunk | 3 | 0.43% | 1 | 3.45% |
Kazunori Miyazawa | 3 | 0.43% | 1 | 3.45% |
Changli Gao | 2 | 0.29% | 1 | 3.45% |
Total | 695 | 100.00% | 29 | 100.00% |
EXPORT_SYMBOL(xfrm_lookup);
/* Callers of xfrm_lookup_route() must ensure a call to dst_output().
* Otherwise we may send out blackholed packets.
*/
struct dst_entry *xfrm_lookup_route(struct net *net, struct dst_entry *dst_orig,
const struct flowi *fl,
const struct sock *sk, int flags)
{
struct dst_entry *dst = xfrm_lookup(net, dst_orig, fl, sk,
flags | XFRM_LOOKUP_QUEUE |
XFRM_LOOKUP_KEEP_DST_REF);
if (IS_ERR(dst) && PTR_ERR(dst) == -EREMOTE)
return make_blackhole(net, dst_orig->ops->family, dst_orig);
return dst;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Steffen Klassert | 83 | 96.51% | 2 | 50.00% |
Huaibin Wang | 2 | 2.33% | 1 | 25.00% |
Eric Dumazet | 1 | 1.16% | 1 | 25.00% |
Total | 86 | 100.00% | 4 | 100.00% |
EXPORT_SYMBOL(xfrm_lookup_route);
static inline int
xfrm_secpath_reject(int idx, struct sk_buff *skb, const struct flowi *fl)
{
struct xfrm_state *x;
if (!skb->sp || idx < 0 || idx >= skb->sp->len)
return 0;
x = skb->sp->xvec[idx];
if (!x->type->reject)
return 0;
return x->type->reject(x, skb, fl);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Timo Teräs | 69 | 81.18% | 1 | 20.00% |
Masahide Nakamura | 12 | 14.12% | 1 | 20.00% |
Alexey Kuznetsov | 2 | 2.35% | 1 | 20.00% |
David S. Miller | 1 | 1.18% | 1 | 20.00% |
Alexey Dobriyan | 1 | 1.18% | 1 | 20.00% |
Total | 85 | 100.00% | 5 | 100.00% |
/* When skb is transformed back to its "native" form, we have to
* check policy restrictions. At the moment we make this in maximally
* stupid way. Shame on me. :-) Of course, connected sockets must
* have policy cached at them.
*/
static inline int
xfrm_state_ok(const struct xfrm_tmpl *tmpl, const struct xfrm_state *x,
unsigned short family)
{
if (xfrm_state_kern(x))
return tmpl->optional && !xfrm_state_addr_cmp(tmpl, x, tmpl->encap_family);
return x->id.proto == tmpl->id.proto &&
(x->id.spi == tmpl->id.spi || !tmpl->id.spi) &&
(x->props.reqid == tmpl->reqid || !tmpl->reqid) &&
x->props.mode == tmpl->mode &&
(tmpl->allalgs || (tmpl->aalgos & (1<<x->props.aalgo)) ||
!(xfrm_id_proto_match(tmpl->id.proto, IPSEC_PROTO_ANY))) &&
!(x->props.mode != XFRM_MODE_TRANSPORT &&
xfrm_state_addr_cmp(tmpl, x, family));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Timo Teräs | 148 | 90.24% | 1 | 14.29% |
James Morris | 6 | 3.66% | 1 | 14.29% |
Masahide Nakamura | 5 | 3.05% | 2 | 28.57% |
David S. Miller | 2 | 1.22% | 1 | 14.29% |
Alexey Kuznetsov | 2 | 1.22% | 1 | 14.29% |
Alexey Dobriyan | 1 | 0.61% | 1 | 14.29% |
Total | 164 | 100.00% | 7 | 100.00% |
/*
* 0 or more than 0 is returned when validation is succeeded (either bypass
* because of optional transport mode, or next index of the mathced secpath
* state with the template.
* -1 is returned when no matching template is found.
* Otherwise "-2 - errored_index" is returned.
*/
static inline int
xfrm_policy_ok(const struct xfrm_tmpl *tmpl, const struct sec_path *sp, int start,
unsigned short family)
{
int idx = start;
if (tmpl->optional) {
if (tmpl->mode == XFRM_MODE_TRANSPORT)
return start;
} else
start = -1;
for (; idx < sp->len; idx++) {
if (xfrm_state_ok(tmpl, sp->xvec[idx], family))
return ++idx;
if (sp->xvec[idx]->props.mode != XFRM_MODE_TRANSPORT) {
if (start == -1)
start = -2-idx;
break;
}
}
return start;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Timo Teräs | 84 | 67.20% | 1 | 12.50% |
Masahide Nakamura | 26 | 20.80% | 3 | 37.50% |
Alexey Kuznetsov | 12 | 9.60% | 2 | 25.00% |
David S. Miller | 2 | 1.60% | 1 | 12.50% |
Alexey Dobriyan | 1 | 0.80% | 1 | 12.50% |
Total | 125 | 100.00% | 8 | 100.00% |
int __xfrm_decode_session(struct sk_buff *skb, struct flowi *fl,
unsigned int family, int reverse)
{
const struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
int err;
if (unlikely(afinfo == NULL))
return -EAFNOSUPPORT;
afinfo->decode_session(skb, fl, reverse);
err = security_xfrm_decode_session(skb, &fl->flowi_secid);
rcu_read_unlock();
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Timo Teräs | 48 | 61.54% | 1 | 9.09% |
Masahide Nakamura | 13 | 16.67% | 2 | 18.18% |
Alexey Kuznetsov | 6 | 7.69% | 1 | 9.09% |
Herbert Xu | 5 | 6.41% | 2 | 18.18% |
Florian Westphal | 3 | 3.85% | 2 | 18.18% |
Hideaki Yoshifuji / 吉藤英明 | 1 | 1.28% | 1 | 9.09% |
David S. Miller | 1 | 1.28% | 1 | 9.09% |
Alexey Dobriyan | 1 | 1.28% | 1 | 9.09% |
Total | 78 | 100.00% | 11 | 100.00% |
EXPORT_SYMBOL(__xfrm_decode_session);
static inline int secpath_has_nontransport(const struct sec_path *sp, int k, int *idxp)
{
for (; k < sp->len; k++) {
if (sp->xvec[k]->props.mode != XFRM_MODE_TRANSPORT) {
*idxp = k;
return 1;
}
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Timo Teräs | 54 | 87.10% | 1 | 25.00% |
Alexey Kuznetsov | 6 | 9.68% | 1 | 25.00% |
Kazunori Miyazawa | 1 | 1.61% | 1 | 25.00% |
David S. Miller | 1 | 1.61% | 1 | 25.00% |
Total | 62 | 100.00% | 4 | 100.00% |
int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
unsigned short family)
{
struct net *net = dev_net(skb->dev);
struct xfrm_policy *pol;
struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
int npols = 0;
int xfrm_nr;
int pi;
int reverse;
struct flowi fl;
u8 fl_dir;
int xerr_idx = -1;
reverse = dir & ~XFRM_POLICY_MASK;
dir &= XFRM_POLICY_MASK;
fl_dir = policy_to_flow_dir(dir);
if (__xfrm_decode_session(skb, &fl, family, reverse) < 0) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR);
return 0;
}
nf_nat_decode_session(skb, &fl, family);
/* First, check used SA against their selectors. */
if (skb->sp) {
int i;
for (i = skb->sp->len-1; i >= 0; i--) {
struct xfrm_state *x = skb->sp->xvec[i];
if (!xfrm_selector_match(&x->sel, &fl, family)) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMISMATCH);
return 0;
}
}
}
pol = NULL;
sk = sk_to_full_sk(sk);
if (sk && sk->sk_policy[dir]) {
pol = xfrm_sk_policy_lookup(sk, dir, &fl, family);
if (IS_ERR(pol)) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR);
return 0;
}
}
if (!pol) {
struct flow_cache_object *flo;
flo = flow_cache_lookup(net, &fl, family, fl_dir,
xfrm_policy_lookup, NULL);
if (IS_ERR_OR_NULL(flo))
pol = ERR_CAST(flo);
else
pol = container_of(flo, struct xfrm_policy, flo);
}
if (IS_ERR(pol)) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR);
return 0;
}
if (!pol) {
if (skb->sp && secpath_has_nontransport(skb->sp, 0, &xerr_idx)) {
xfrm_secpath_reject(xerr_idx, skb, &fl);
XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOPOLS);
return 0;
}
return 1;
}
pol->curlft.use_time = get_seconds();
pols[0] = pol;
npols++;
#ifdef CONFIG_XFRM_SUB_POLICY
if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) {
pols[1] = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN,
&fl, family,
XFRM_POLICY_IN);
if (pols[1]) {
if (IS_ERR(pols[1])) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR);
return 0;
}
pols[1]->curlft.use_time = get_seconds();
npols++;
}
}
#endif
if (pol->action == XFRM_POLICY_ALLOW) {
struct sec_path *sp;
static struct sec_path dummy;
struct xfrm_tmpl *tp[XFRM_MAX_DEPTH];
struct xfrm_tmpl *stp[XFRM_MAX_DEPTH];
struct xfrm_tmpl **tpp = tp;
int ti = 0;
int i, k;
if ((sp = skb->sp) == NULL)
sp = &dummy;
for (pi = 0; pi < npols; pi++) {
if (pols[pi] != pol &&
pols[pi]->action != XFRM_POLICY_ALLOW) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLBLOCK);
goto reject;
}
if (ti + pols[pi]->xfrm_nr >= XFRM_MAX_DEPTH) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR);
goto reject_error;
}
for (i = 0; i < pols[pi]->xfrm_nr; i++)
tpp[ti++] = &pols[pi]->xfrm_vec[i];
}
xfrm_nr = ti;
if (npols > 1) {
xfrm_tmpl_sort(stp, tpp, xfrm_nr, family, net);
tpp = stp;
}
/* For each tunnel xfrm, find the first matching tmpl.
* For each tmpl before that, find corresponding xfrm.
* Order is _important_. Later we will implement
* some barriers, but at the moment barriers
* are implied between each two transformations.
*/
for (i = xfrm_nr-1, k = 0; i >= 0; i--) {
k = xfrm_policy_ok(tpp[i], sp, k, family);
if (k < 0) {
if (k < -1)
/* "-2 - errored_index" returned */
xerr_idx = -(2+k);
XFRM_INC_STATS(net, LINUX_MIB_XFRMINTMPLMISMATCH);
goto reject;
}
}
if (secpath_has_nontransport(sp, k, &xerr_idx)) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINTMPLMISMATCH);
goto reject;
}
xfrm_pols_put(pols, npols);
return 1;
}
XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLBLOCK);
reject:
xfrm_secpath_reject(xerr_idx, skb, &fl);
reject_error:
xfrm_pols_put(pols, npols);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Timo Teräs | 673 | 80.79% | 1 | 4.55% |
Hideaki Yoshifuji / 吉藤英明 | 54 | 6.48% | 2 | 9.09% |
Eric Dumazet | 22 | 2.64% | 2 | 9.09% |
Herbert Xu | 20 | 2.40% | 4 | 18.18% |
David S. Miller | 16 | 1.92% | 2 | 9.09% |
Alexey Dobriyan | 14 | 1.68% | 3 | 13.64% |
Alexey Kuznetsov | 11 | 1.32% | 1 | 4.55% |
Kazunori Miyazawa | 10 | 1.20% | 1 | 4.55% |
Masahide Nakamura | 7 | 0.84% | 2 | 9.09% |
Steffen Klassert | 2 | 0.24% | 1 | 4.55% |
Fan Du | 2 | 0.24% | 1 | 4.55% |
Venkat Yekkirala | 1 | 0.12% | 1 | 4.55% |
Adrian Bunk | 1 | 0.12% | 1 | 4.55% |
Total | 833 | 100.00% | 22 | 100.00% |
EXPORT_SYMBOL(__xfrm_policy_check);
int __xfrm_route_forward(struct sk_buff *skb, unsigned short family)
{
struct net *net = dev_net(skb->dev);
struct flowi fl;
struct dst_entry *dst;
int res = 1;
if (xfrm_decode_session(skb, &fl, family) < 0) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMFWDHDRERROR);
return 0;
}
skb_dst_force(skb);
dst = xfrm_lookup(net, skb_dst(skb), &fl, NULL, XFRM_LOOKUP_QUEUE);
if (IS_ERR(dst)) {
res = 0;
dst = NULL;
}
skb_dst_set(skb, dst);
return res;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Timo Teräs | 59 | 50.43% | 1 | 14.29% |
David S. Miller | 49 | 41.88% | 2 | 28.57% |
Eric Dumazet | 7 | 5.98% | 2 | 28.57% |
Steffen Klassert | 1 | 0.85% | 1 | 14.29% |
Alexey Dobriyan | 1 | 0.85% | 1 | 14.29% |
Total | 117 | 100.00% | 7 | 100.00% |
EXPORT_SYMBOL(__xfrm_route_forward);
/* Optimize later using cookies and generation ids. */
static struct dst_entry *xfrm_dst_check(struct dst_entry *dst, u32 cookie)
{
/* Code (such as __xfrm4_bundle_create()) sets dst->obsolete
* to DST_OBSOLETE_FORCE_CHK to force all XFRM destinations to
* get validated by dst_ops->check on every use. We do this
* because when a normal route referenced by an XFRM dst is
* obsoleted we do not go looking around for all parent
* referencing XFRM dsts so that we can invalidate them. It
* is just too much work. Instead we make the checks here on
* every use. For example:
*
* XFRM dst A --> IPv4 dst X
*
* X is the "xdst->route" of A (X is also the "dst->path" of A
* in this example). If X is marked obsolete, "A" will not
* notice. That's what we are validating here via the
* stale_bundle() check.
*
* When a policy's bundle is pruned, we dst_free() the XFRM
* dst which causes it's ->obsolete field to be set to
* DST_OBSOLETE_DEAD. If an XFRM dst has been pruned like
* this, we want to force a new route lookup.
*/
if (dst->obsolete < 0 && !stale_bundle(dst))
return dst;
return NULL;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Timo Teräs | 34 | 91.89% | 1 | 25.00% |
David S. Miller | 2 | 5.41% | 2 | 50.00% |
Alexey Dobriyan | 1 | 2.70% | 1 | 25.00% |
Total | 37 | 100.00% | 4 | 100.00% |
static int stale_bundle(struct dst_entry *dst)
{
return !xfrm_bundle_ok((struct xfrm_dst *)dst);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Timo Teräs | 19 | 82.61% | 1 | 33.33% |
David S. Miller | 3 | 13.04% | 1 | 33.33% |
Hideaki Yoshifuji / 吉藤英明 | 1 | 4.35% | 1 | 33.33% |
Total | 23 | 100.00% | 3 | 100.00% |
void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev)
{
while ((dst = dst->child) && dst->xfrm && dst->dev == dev) {
dst->dev = dev_net(dev)->loopback_dev;
dev_hold(dst->dev);
dev_put(dev);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Timo Teräs | 47 | 78.33% | 1 | 33.33% |
Hideaki Yoshifuji / 吉藤英明 | 10 | 16.67% | 1 | 33.33% |
David S. Miller | 3 | 5.00% | 1 | 33.33% |
Total | 60 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL(xfrm_dst_ifdown);
static void xfrm_link_failure(struct sk_buff *skb)
{
/* Impossible. Such dst must be popped before reaches point of failure. */
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Timo Teräs | 11 | 91.67% | 1 | 50.00% |
Hideaki Yoshifuji / 吉藤英明 | 1 | 8.33% | 1 | 50.00% |
Total | 12 | 100.00% | 2 | 100.00% |
static struct dst_entry *xfrm_negative_advice(struct dst_entry *dst)
{
if (dst) {
if (dst->obsolete) {
dst_release(dst);
dst = NULL;
}
}
return dst;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Timo Teräs | 26 | 66.67% | 1 | 50.00% |
Herbert Xu | 13 | 33.33% | 1 | 50.00% |
Total | 39 | 100.00% | 2 | 100.00% |
void xfrm_garbage_collect(struct net *net)
{
flow_cache_flush(net);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Steffen Klassert | 12 | 80.00% | 1 | 50.00% |
Fan Du | 3 | 20.00% | 1 | 50.00% |
Total | 15 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL(xfrm_garbage_collect);
void xfrm_garbage_collect_deferred(struct net *net)
{
flow_cache_flush_deferred(net);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Steffen Klassert | 12 | 80.00% | 1 | 50.00% |
Fan Du | 3 | 20.00% | 1 | 50.00% |
Total | 15 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL(xfrm_garbage_collect_deferred);
static void xfrm_init_pmtu(struct dst_entry *dst)
{
do {
struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
u32 pmtu, route_mtu_cached;
pmtu = dst_mtu(dst->child);
xdst->child_mtu_cached = pmtu;
pmtu = xfrm_state_mtu(dst->xfrm, pmtu);
route_mtu_cached = dst_mtu(xdst->route);
xdst->route_mtu_cached = route_mtu_cached;
if (pmtu > route_mtu_cached)
pmtu = route_mtu_cached;
dst_metric_set(dst, RTAX_MTU, pmtu);
} while ((dst = dst->next));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Herbert Xu | 97 | 95.10% | 3 | 75.00% |
David S. Miller | 5 | 4.90% | 1 | 25.00% |
Total | 102 | 100.00% | 4 | 100.00% |
/* Check that the bundle accepts the flow and its components are
* still valid.
*/
static int xfrm_bundle_ok(struct xfrm_dst *first)
{
struct dst_entry *dst = &first->u.dst;
struct xfrm_dst *last;
u32 mtu;
if (!dst_check(dst->path, ((struct xfrm_dst *)dst)->path_cookie) ||
(dst->dev && !netif_running(dst->dev)))
return 0;
if (dst->flags & DST_XFRM_QUEUE)
return 1;
last = NULL;
do {
struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
if (dst->xfrm->km.state != XFRM_STATE_VALID)
return 0;
if (xdst->xfrm_genid != dst->xfrm->genid)
return 0;
if (xdst->num_pols > 0 &&
xdst->policy_genid != atomic_read(&xdst->pols[0]->genid))
return 0;
mtu = dst_mtu(dst->child);
if (xdst->child_mtu_cached != mtu) {
last = xdst;
xdst->child_mtu_cached = mtu;
}
if (!dst_check(xdst->route, xdst->route_cookie))
return 0;
mtu = dst_mtu(xdst->route);
if (xdst->route_mtu_cached != mtu) {
last = xdst;
xdst->route_mtu_cached = mtu;
}
dst = dst->child;
} while (dst->xfrm);
if (likely(!last))
return 1;
mtu = last->child_mtu_cached;
for (;;) {
dst = &last->u.dst;
mtu = xfrm_state_mtu(dst->xfrm, mtu);
if (mtu > last->route_mtu_cached)
mtu = last->route_mtu_cached;
dst_metric_set(dst, RTAX_MTU, mtu);
if (last == first)
break;
last = (struct xfrm_dst *)last->u.dst.next;
last->child_mtu_cached = mtu;
}
return 1;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Herbert Xu | 263 | 76.68% | 4 | 30.77% |
Timo Teräs | 27 | 7.87% | 2 | 15.38% |
David S. Miller | 19 | 5.54% | 2 | 15.38% |
Hideaki Yoshifuji / 吉藤英明 | 13 | 3.79% | 1 | 7.69% |
Steffen Klassert | 11 | 3.21% | 1 | 7.69% |
Patrick McHardy | 7 | 2.04% | 1 | 7.69% |
Masahide Nakamura | 2 | 0.58% | 1 | 7.69% |
Stephen Hemminger | 1 | 0.29% | 1 | 7.69% |
Total | 343 | 100.00% | 13 | 100.00% |
static unsigned int xfrm_default_advmss(const struct dst_entry *dst)
{
return dst_metric_advmss(dst->path);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 21 | 100.00% | 1 | 100.00% |
Total | 21 | 100.00% | 1 | 100.00% |
static unsigned int xfrm_mtu(const struct dst_entry *dst)
{
unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
return mtu ? : dst_mtu(dst->path);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 20 | 57.14% | 1 | 33.33% |
Steffen Klassert | 15 | 42.86% | 2 | 66.67% |
Total | 35 | 100.00% | 3 | 100.00% |
static const void *xfrm_get_dst_nexthop(const struct dst_entry *dst,
const void *daddr)
{
const struct dst_entry *path = dst->path;
for (; dst != path; dst = dst->child) {
const struct xfrm_state *xfrm = dst->xfrm;
if (xfrm->props.mode == XFRM_MODE_TRANSPORT)
continue;
if (xfrm->type->flags & XFRM_TYPE_REMOTE_COADDR)
daddr = xfrm->coaddr;
else if (!(xfrm->type->flags & XFRM_TYPE_LOCAL_COADDR))
daddr = &xfrm->id.daddr;
}
return daddr;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Julian Anastasov | 103 | 96.26% | 2 | 66.67% |
David S. Miller | 4 | 3.74% | 1 | 33.33% |
Total | 107 | 100.00% | 3 | 100.00% |
static struct neighbour *xfrm_neigh_lookup(const struct dst_entry *dst,
struct sk_buff *skb,
const void *daddr)
{
const struct dst_entry *path = dst->path;
if (!skb)
daddr = xfrm_get_dst_nexthop(dst, daddr);
return path->ops->neigh_lookup(path, skb, daddr);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Julian Anastasov | 62 | 100.00% | 1 | 100.00% |
Total | 62 | 100.00% | 1 | 100.00% |
static void xfrm_confirm_neigh(const struct dst_entry *dst, const void *daddr)
{
const struct dst_entry *path = dst->path;
daddr = xfrm_get_dst_nexthop(dst, daddr);
path->ops->confirm_neigh(path, daddr);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Julian Anastasov | 47 | 100.00% | 2 | 100.00% |
Total | 47 | 100.00% | 2 | 100.00% |
int xfrm_policy_register_afinfo(const struct xfrm_policy_afinfo *afinfo, int family)
{
int err = 0;
if (WARN_ON(family >= ARRAY_SIZE(xfrm_policy_afinfo)))
return -EAFNOSUPPORT;
spin_lock(&xfrm_policy_afinfo_lock);
if (unlikely(xfrm_policy_afinfo[family] != NULL))
err = -EEXIST;
else {
struct dst_ops *dst_ops = afinfo->dst_ops;
if (likely(dst_ops->kmem_cachep == NULL))
dst_ops->kmem_cachep = xfrm_dst_cache;
if (likely(dst_ops->check == NULL))
dst_ops->check = xfrm_dst_check;
if (likely(dst_ops->default_advmss == NULL))
dst_ops->default_advmss = xfrm_default_advmss;
if (likely(dst_ops->mtu == NULL))
dst_ops->mtu = xfrm_mtu;
if (likely(dst_ops->negative_advice == NULL))
dst_ops->negative_advice = xfrm_negative_advice;
if (likely(dst_ops->link_failure == NULL))
dst_ops->link_failure = xfrm_link_failure;
if (likely(dst_ops->neigh_lookup == NULL))
dst_ops->neigh_lookup = xfrm_neigh_lookup;
if (likely(!dst_ops->confirm_neigh))
dst_ops->confirm_neigh = xfrm_confirm_neigh;
rcu_assign_pointer(xfrm_policy_afinfo[family], afinfo);
}
spin_unlock(&xfrm_policy_afinfo_lock);
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Joy Latten | 106 | 47.32% | 2 | 14.29% |
David S. Miller | 53 | 23.66% | 4 | 28.57% |
Hideaki Yoshifuji / 吉藤英明 | 27 | 12.05% | 1 | 7.14% |
Julian Anastasov | 12 | 5.36% | 1 | 7.14% |
Florian Westphal | 9 | 4.02% | 1 | 7.14% |
Kazunori Miyazawa | 7 | 3.12% | 1 | 7.14% |
Priyanka Jain | 4 | 1.79% | 1 | 7.14% |
Steffen Klassert | 3 | 1.34% | 1 | 7.14% |
Eric Dumazet | 2 | 0.89% | 1 | 7.14% |
Li RongQing | 1 | 0.45% | 1 | 7.14% |
Total | 224 | 100.00% | 14 | 100.00% |
EXPORT_SYMBOL(xfrm_policy_register_afinfo);
void xfrm_policy_unregister_afinfo(const struct xfrm_policy_afinfo *afinfo)
{
struct dst_ops *dst_ops = afinfo->dst_ops;
int i;
for (i = 0; i < ARRAY_SIZE(xfrm_policy_afinfo); i++) {
if (xfrm_policy_afinfo[i] != afinfo)
continue;
RCU_INIT_POINTER(xfrm_policy_afinfo[i], NULL);
break;
}
synchronize_rcu();
dst_ops->kmem_cachep = NULL;
dst_ops->check = NULL;
dst_ops->negative_advice = NULL;
dst_ops->link_failure = NULL;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hideaki Yoshifuji / 吉藤英明 | 38 | 42.70% | 1 | 16.67% |
Florian Westphal | 28 | 31.46% | 2 | 33.33% |
Alexey Kuznetsov | 16 | 17.98% | 1 | 16.67% |
Eric Dumazet | 4 | 4.49% | 1 | 16.67% |
Priyanka Jain | 3 | 3.37% | 1 | 16.67% |
Total | 89 | 100.00% | 6 | 100.00% |
EXPORT_SYMBOL(xfrm_policy_unregister_afinfo);
static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
switch (event) {
case NETDEV_DOWN:
xfrm_garbage_collect(dev_net(dev));
}
return NOTIFY_DONE;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Joy Latten | 32 | 65.31% | 1 | 20.00% |
Eric W. Biedermann | 7 | 14.29% | 1 | 20.00% |
Alexey Dobriyan | 6 | 12.24% | 1 | 20.00% |
Jiri Pirko | 3 | 6.12% | 1 | 20.00% |
Steffen Klassert | 1 | 2.04% | 1 | 20.00% |
Total | 49 | 100.00% | 5 | 100.00% |
static struct notifier_block xfrm_dev_notifier = {
.notifier_call = xfrm_dev_event,
};
#ifdef CONFIG_XFRM_STATISTICS
static int __net_init xfrm_statistics_init(struct net *net)
{
int rv;
net->mib.xfrm_statistics = alloc_percpu(struct linux_xfrm_mib);
if (!net->mib.xfrm_statistics)
return -ENOMEM;
rv = xfrm_proc_init(net);
if (rv < 0)
free_percpu(net->mib.xfrm_statistics);
return rv;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Alexey Dobriyan | 34 | 52.31% | 2 | 40.00% |
Masahide Nakamura | 15 | 23.08% | 1 | 20.00% |
Américo Wang | 12 | 18.46% | 1 | 20.00% |
Eric Dumazet | 4 | 6.15% | 1 | 20.00% |
Total | 65 | 100.00% | 5 | 100.00% |
static void xfrm_statistics_fini(struct net *net)
{
xfrm_proc_fini(net);
free_percpu(net->mib.xfrm_statistics);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Alexey Dobriyan | 24 | 96.00% | 2 | 66.67% |
Américo Wang | 1 | 4.00% | 1 | 33.33% |
Total | 25 | 100.00% | 3 | 100.00% |
#else
static int __net_init xfrm_statistics_init(struct net *net)
{
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Alexey Dobriyan | 15 | 100.00% | 1 | 100.00% |
Total | 15 | 100.00% | 1 | 100.00% |
static void xfrm_statistics_fini(struct net *net)
{
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Alexey Dobriyan | 10 | 100.00% | 1 | 100.00% |
Total | 10 | 100.00% | 1 | 100.00% |
#endif
static int __net_init xfrm_policy_init(struct net *net)
{
unsigned int hmask, sz;
int dir;
if (net_eq(net, &init_net))
xfrm_dst_cache = kmem_cache_create("xfrm_dst_cache",
sizeof(struct xfrm_dst),
0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
NULL);
hmask = 8 - 1;
sz = (hmask+1) * sizeof(struct hlist_head);
net->xfrm.policy_byidx = xfrm_hash_alloc(sz);
if (!net->xfrm.policy_byidx)
goto out_byidx;
net->xfrm.policy_idx_hmask = hmask;
for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
struct xfrm_policy_hash *htab;
net->xfrm.policy_count[dir] = 0;
net->xfrm.policy_count[XFRM_POLICY_MAX + dir] = 0;
INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]);
htab = &net->xfrm.policy_bydst[dir];
htab->table = xfrm_hash_alloc(sz);
if (!htab->table)
goto out_bydst;
htab->hmask = hmask;
htab->dbits4 = 32;
htab->sbits4 = 32;
htab->dbits6 = 128;
htab->sbits6 = 128;
}
net->xfrm.policy_hthresh.lbits4 = 32;
net->xfrm.policy_hthresh.rbits4 = 32;
net->xfrm.policy_hthresh.lbits6 = 128;
net->xfrm.policy_hthresh.rbits6 = 128;
seqlock_init(&net->xfrm.policy_hthresh.lock);
INIT_LIST_HEAD(&net->xfrm.policy_all);
INIT_WORK(&net->xfrm.policy_hash_work, xfrm_hash_resize);
INIT_WORK(&net->xfrm.policy_hthresh.work, xfrm_hash_rebuild);
if (net_eq(net, &init_net))
register_netdevice_notifier(&xfrm_dev_notifier);
return 0;
out_bydst:
for (dir--; dir >= 0; dir--) {
struct xfrm_policy_hash *htab;
htab = &net->xfrm.policy_bydst[dir];
xfrm_hash_free(htab->table, sz);
}
xfrm_hash_free(net->xfrm.policy_byidx, sz);
out_byidx:
return -ENOMEM;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Alexey Dobriyan | 154 | 39.79% | 8 | 53.33% |
Joy Latten | 112 | 28.94% | 1 | 6.67% |
Christophe Gouault | 90 | 23.26% | 2 | 13.33% |
Herbert Xu | 25 | 6.46% | 2 | 13.33% |
Timo Teräs | 5 | 1.29% | 1 | 6.67% |
Hideaki Yoshifuji / 吉藤英明 | 1 | 0.26% | 1 | 6.67% |
Total | 387 | 100.00% | 15 | 100.00% |
static void xfrm_policy_fini(struct net *net)
{
unsigned int sz;
int dir;
flush_work(&net->xfrm.policy_hash_work);
#ifdef CONFIG_XFRM_SUB_POLICY
xfrm_policy_flush(net, XFRM_POLICY_TYPE_SUB, false);
#endif
xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, false);
WARN_ON(!list_empty(&net->xfrm.policy_all));
for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
struct xfrm_policy_hash *htab;
WARN_ON(!hlist_empty(&net->xfrm.policy_inexact[dir]));
htab = &net->xfrm.policy_bydst[dir];
sz = (htab->hmask + 1) * sizeof(struct hlist_head);
WARN_ON(!hlist_empty(htab->table));
xfrm_hash_free(htab->table, sz);
}
sz = (net->xfrm.policy_idx_hmask + 1) * sizeof(struct hlist_head);
WARN_ON(!hlist_empty(net->xfrm.policy_byidx));
xfrm_hash_free(net->xfrm.policy_byidx, sz);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Alexey Dobriyan | 184 | 95.83% | 7 | 77.78% |
Michal Kubeček | 6 | 3.12% | 1 | 11.11% |
Tetsuo Handa | 2 | 1.04% | 1 | 11.11% |
Total | 192 | 100.00% | 9 | 100.00% |
static int __net_init xfrm_net_init(struct net *net)
{
int rv;
/* Initialize the per-net locks here */
spin_lock_init(&net->xfrm.xfrm_state_lock);
spin_lock_init(&net->xfrm.xfrm_policy_lock);
mutex_init(&net->xfrm.xfrm_cfg_mutex);
rv = xfrm_statistics_init(net);
if (rv < 0)
goto out_statistics;
rv = xfrm_state_init(net);
if (rv < 0)
goto out_state;
rv = xfrm_policy_init(net);
if (rv < 0)
goto out_policy;
rv = xfrm_sysctl_init(net);
if (rv < 0)
goto out_sysctl;
rv = flow_cache_init(net);
if (rv < 0)
goto out;
return 0;
out:
xfrm_sysctl_fini(net);
out_sysctl:
xfrm_policy_fini(net);
out_policy:
xfrm_state_fini(net);
out_state:
xfrm_statistics_fini(net);
out_statistics:
return rv;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Alexey Dobriyan | 105 | 64.81% | 3 | 50.00% |
Florian Westphal | 31 | 19.14% | 1 | 16.67% |
Steffen Klassert | 22 | 13.58% | 1 | 16.67% |
Fan Du | 4 | 2.47% | 1 | 16.67% |
Total | 162 | 100.00% | 6 | 100.00% |
static void __net_exit xfrm_net_exit(struct net *net)
{
flow_cache_fini(net);
xfrm_sysctl_fini(net);
xfrm_policy_fini(net);
xfrm_state_fini(net);
xfrm_statistics_fini(net);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Alexey Dobriyan | 32 | 86.49% | 3 | 75.00% |
Steffen Klassert | 5 | 13.51% | 1 | 25.00% |
Total | 37 | 100.00% | 4 | 100.00% |
static struct pernet_operations __net_initdata xfrm_net_ops = {
.init = xfrm_net_init,
.exit = xfrm_net_exit,
};
void __init xfrm_init(void)
{
flow_cache_hp_init();
register_pernet_subsys(&xfrm_net_ops);
seqcount_init(&xfrm_policy_hash_generation);
xfrm_input_init();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Florian Westphal | 6 | 23.08% | 1 | 16.67% |
Alexey Dobriyan | 6 | 23.08% | 1 | 16.67% |
Joy Latten | 5 | 19.23% | 1 | 16.67% |
Herbert Xu | 4 | 15.38% | 1 | 16.67% |
Sebastian Andrzej Siewior | 3 | 11.54% | 1 | 16.67% |
Hideaki Yoshifuji / 吉藤英明 | 2 | 7.69% | 1 | 16.67% |
Total | 26 | 100.00% | 6 | 100.00% |
#ifdef CONFIG_AUDITSYSCALL
static void xfrm_audit_common_policyinfo(struct xfrm_policy *xp,
struct audit_buffer *audit_buf)
{
struct xfrm_sec_ctx *ctx = xp->security;
struct xfrm_selector *sel = &xp->selector;
if (ctx)
audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s",
ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str);
switch (sel->family) {
case AF_INET:
audit_log_format(audit_buf, " src=%pI4", &sel->saddr.a4);
if (sel->prefixlen_s != 32)
audit_log_format(audit_buf, " src_prefixlen=%d",
sel->prefixlen_s);
audit_log_format(audit_buf, " dst=%pI4", &sel->daddr.a4);
if (sel->prefixlen_d != 32)
audit_log_format(audit_buf, " dst_prefixlen=%d",
sel->prefixlen_d);
break;
case AF_INET6:
audit_log_format(audit_buf, " src=%pI6", sel->saddr.a6);
if (sel->prefixlen_s != 128)
audit_log_format(audit_buf, " src_prefixlen=%d",
sel->prefixlen_s);
audit_log_format(audit_buf, " dst=%pI6", sel->daddr.a6);
if (sel->prefixlen_d != 128)
audit_log_format(audit_buf, " dst_prefixlen=%d",
sel->prefixlen_d);
break;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Paul Moore | 112 | 54.90% | 1 | 20.00% |
Joy Latten | 69 | 33.82% | 1 | 20.00% |
Herbert Xu | 17 | 8.33% | 1 | 20.00% |
Harvey Harrison | 6 | 2.94% | 2 | 40.00% |
Total | 204 | 100.00% | 5 | 100.00% |
void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, bool task_valid)
{
struct audit_buffer *audit_buf;
audit_buf = xfrm_audit_start("SPD-add");
if (audit_buf == NULL)
return;
xfrm_audit_helper_usrinfo(task_valid, audit_buf);
audit_log_format(audit_buf, " res=%u", result);
xfrm_audit_common_policyinfo(xp, audit_buf);
audit_log_end(audit_buf);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Joy Latten | 34 | 53.97% | 1 | 16.67% |
Alexey Kuznetsov | 10 | 15.87% | 1 | 16.67% |
Paul Moore | 9 | 14.29% | 2 | 33.33% |
David S. Miller | 7 | 11.11% | 1 | 16.67% |
Tetsuo Handa | 3 | 4.76% | 1 | 16.67% |
Total | 63 | 100.00% | 6 | 100.00% |
EXPORT_SYMBOL_GPL(xfrm_audit_policy_add);
void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result,
bool task_valid)
{
struct audit_buffer *audit_buf;
audit_buf = xfrm_audit_start("SPD-delete");
if (audit_buf == NULL)
return;
xfrm_audit_helper_usrinfo(task_valid, audit_buf);
audit_log_format(audit_buf, " res=%u", result);
xfrm_audit_common_policyinfo(xp, audit_buf);
audit_log_end(audit_buf);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Joy Latten | 29 | 46.03% | 1 | 12.50% |
David S. Miller | 14 | 22.22% | 1 | 12.50% |
Paul Moore | 9 | 14.29% | 2 | 25.00% |
Herbert Xu | 7 | 11.11% | 2 | 25.00% |
Tetsuo Handa | 3 | 4.76% | 1 | 12.50% |
Hideaki Yoshifuji / 吉藤英明 | 1 | 1.59% | 1 | 12.50% |
Total | 63 | 100.00% | 8 | 100.00% |
EXPORT_SYMBOL_GPL(xfrm_audit_policy_delete);
#endif
#ifdef CONFIG_XFRM_MIGRATE
static bool xfrm_migrate_selector_match(const struct xfrm_selector *sel_cmp,
const struct xfrm_selector *sel_tgt)
{
if (sel_cmp->proto == IPSEC_ULPROTO_ANY) {
if (sel_tgt->family == sel_cmp->family &&
xfrm_addr_equal(&sel_tgt->daddr, &sel_cmp->daddr,
sel_cmp->family) &&
xfrm_addr_equal(&sel_tgt->saddr, &sel_cmp->saddr,
sel_cmp->family) &&
sel_tgt->prefixlen_d == sel_cmp->prefixlen_d &&
sel_tgt->prefixlen_s == sel_cmp->prefixlen_s) {
return true;
}
} else {
if (memcmp(sel_tgt, sel_cmp, sizeof(*sel_tgt)) == 0) {
return true;
}
}
return false;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Shinta Sugimoto | 113 | 93.39% | 1 | 25.00% |
David S. Miller | 6 | 4.96% | 2 | 50.00% |
Hideaki Yoshifuji / 吉藤英明 | 2 | 1.65% | 1 | 25.00% |
Total | 121 | 100.00% | 4 | 100.00% |
static struct xfrm_policy *xfrm_migrate_policy_find(const struct xfrm_selector *sel,
u8 dir, u8 type, struct net *net)
{
struct xfrm_policy *pol, *ret = NULL;
struct hlist_head *chain;
u32 priority = ~0U;
spin_lock_bh(&net->xfrm.xfrm_policy_lock);
chain = policy_hash_direct(net, &sel->daddr, &sel->saddr, sel->family, dir);
hlist_for_each_entry(pol, chain, bydst) {
if (xfrm_migrate_selector_match(sel, &pol->selector) &&
pol->type == type) {
ret = pol;
priority = ret->priority;
break;
}
}
chain = &net->xfrm.policy_inexact[dir];
hlist_for_each_entry(pol, chain, bydst) {
if ((pol->priority >= priority) && ret)
break;
if (xfrm_migrate_selector_match(sel, &pol->selector) &&
pol->type == type) {
ret = pol;
break;
}
}
xfrm_pol_hold(ret);
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
return ret;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Shinta Sugimoto | 161 | 81.31% | 1 | 12.50% |
Fan Du | 16 | 8.08% | 2 | 25.00% |
Li RongQing | 13 | 6.57% | 1 | 12.50% |
Alexey Dobriyan | 5 | 2.53% | 2 | 25.00% |
Florian Westphal | 2 | 1.01% | 1 | 12.50% |
David S. Miller | 1 | 0.51% | 1 | 12.50% |
Total | 198 | 100.00% | 8 | 100.00% |
static int migrate_tmpl_match(const struct xfrm_migrate *m, const struct xfrm_tmpl *t)
{
int match = 0;
if (t->mode == m->mode && t->id.proto == m->proto &&
(m->reqid == 0 || t->reqid == m->reqid)) {
switch (t->mode) {
case XFRM_MODE_TUNNEL:
case XFRM_MODE_BEET:
if (xfrm_addr_equal(&t->id.daddr, &m->old_daddr,
m->old_family) &&
xfrm_addr_equal(&t->saddr, &m->old_saddr,
m->old_family)) {
match = 1;
}
break;
case XFRM_MODE_TRANSPORT:
/* in case of transport mode, template does not store
any IP addresses, hence we just compare mode and
protocol */
match = 1;
break;
default:
break;
}
}
return match;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Shinta Sugimoto | 130 | 97.01% | 1 | 33.33% |
David S. Miller | 2 | 1.49% | 1 | 33.33% |
Hideaki Yoshifuji / 吉藤英明 | 2 | 1.49% | 1 | 33.33% |
Total | 134 | 100.00% | 3 | 100.00% |
/* update endpoint address(es) of template(s) */
static int xfrm_policy_migrate(struct xfrm_policy *pol,
struct xfrm_migrate *m, int num_migrate)
{
struct xfrm_migrate *mp;
int i, j, n = 0;
write_lock_bh(&pol->lock);
if (unlikely(pol->walk.dead)) {
/* target policy has been deleted */
write_unlock_bh(&pol->lock);
return -ENOENT;
}
for (i = 0; i < pol->xfrm_nr; i++) {
for (j = 0, mp = m; j < num_migrate; j++, mp++) {
if (!migrate_tmpl_match(mp, &pol->xfrm_vec[i]))
continue;
n++;
if (pol->xfrm_vec[i].mode != XFRM_MODE_TUNNEL &&
pol->xfrm_vec[i].mode != XFRM_MODE_BEET)
continue;
/* update endpoints */
memcpy(&pol->xfrm_vec[i].id.daddr, &mp->new_daddr,
sizeof(pol->xfrm_vec[i].id.daddr));
memcpy(&pol->xfrm_vec[i].saddr, &mp->new_saddr,
sizeof(pol->xfrm_vec[i].saddr));
pol->xfrm_vec[i].encap_family = mp->new_family;
/* flush bundles */
atomic_inc(&pol->genid);
}
}
write_unlock_bh(&pol->lock);
if (!n)
return -ENODATA;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Shinta Sugimoto | 241 | 93.41% | 1 | 25.00% |
Herbert Xu | 13 | 5.04% | 2 | 50.00% |
Timo Teräs | 4 | 1.55% | 1 | 25.00% |
Total | 258 | 100.00% | 4 | 100.00% |
static int xfrm_migrate_check(const struct xfrm_migrate *m, int num_migrate)
{
int i, j;
if (num_migrate < 1 || num_migrate > XFRM_MAX_DEPTH)
return -EINVAL;
for (i = 0; i < num_migrate; i++) {
if (xfrm_addr_equal(&m[i].old_daddr, &m[i].new_daddr,
m[i].old_family) &&
xfrm_addr_equal(&m[i].old_saddr, &m[i].new_saddr,
m[i].old_family))
return -EINVAL;
if (xfrm_addr_any(&m[i].new_daddr, m[i].new_family) ||
xfrm_addr_any(&m[i].new_saddr, m[i].new_family))
return -EINVAL;
/* check if there is any duplicated entry */
for (j = i + 1; j < num_migrate; j++) {
if (!memcmp(&m[i].old_daddr, &m[j].old_daddr,
sizeof(m[i].old_daddr)) &&
!memcmp(&m[i].old_saddr, &m[j].old_saddr,
sizeof(m[i].old_saddr)) &&
m[i].proto == m[j].proto &&
m[i].mode == m[j].mode &&
m[i].reqid == m[j].reqid &&
m[i].old_family == m[j].old_family)
return -EINVAL;
}
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Shinta Sugimoto | 289 | 98.97% | 1 | 33.33% |
Hideaki Yoshifuji / 吉藤英明 | 2 | 0.68% | 1 | 33.33% |
David S. Miller | 1 | 0.34% | 1 | 33.33% |
Total | 292 | 100.00% | 3 | 100.00% |
int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
struct xfrm_migrate *m, int num_migrate,
struct xfrm_kmaddress *k, struct net *net)
{
int i, err, nx_cur = 0, nx_new = 0;
struct xfrm_policy *pol = NULL;
struct xfrm_state *x, *xc;
struct xfrm_state *x_cur[XFRM_MAX_DEPTH];
struct xfrm_state *x_new[XFRM_MAX_DEPTH];
struct xfrm_migrate *mp;
if ((err = xfrm_migrate_check(m, num_migrate)) < 0)
goto out;
/* Stage 1 - find policy */
if ((pol = xfrm_migrate_policy_find(sel, dir, type, net)) == NULL) {
err = -ENOENT;
goto out;
}
/* Stage 2 - find and update state(s) */
for (i = 0, mp = m; i < num_migrate; i++, mp++) {
if ((x = xfrm_migrate_state_find(mp, net))) {
x_cur[nx_cur] = x;
nx_cur++;
if ((xc = xfrm_state_migrate(x, mp))) {
x_new[nx_new] = xc;
nx_new++;
} else {
err = -ENODATA;
goto restore_state;
}
}
}
/* Stage 3 - update policy */
if ((err = xfrm_policy_migrate(pol, m, num_migrate)) < 0)
goto restore_state;
/* Stage 4 - delete old state(s) */
if (nx_cur) {
xfrm_states_put(x_cur, nx_cur);
xfrm_states_delete(x_cur, nx_cur);
}
/* Stage 5 - announce */
km_migrate(sel, dir, type, m, num_migrate, k);
xfrm_pol_put(pol);
return 0;
out:
return err;
restore_state:
if (pol)
xfrm_pol_put(pol);
if (nx_cur)
xfrm_states_put(x_cur, nx_cur);
if (nx_new)
xfrm_states_delete(x_new, nx_new);
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Shinta Sugimoto | 306 | 94.74% | 1 | 20.00% |
Fan Du | 9 | 2.79% | 2 | 40.00% |
Arnaud Ebalard | 7 | 2.17% | 1 | 20.00% |
David S. Miller | 1 | 0.31% | 1 | 20.00% |
Total | 323 | 100.00% | 5 | 100.00% |
EXPORT_SYMBOL(xfrm_migrate);
#endif
Overall Contributors
Person | Tokens | Prop | Commits | CommitProp |
Timo Teräs | 3070 | 17.20% | 7 | 2.34% |
Herbert Xu | 2133 | 11.95% | 41 | 13.71% |
David S. Miller | 2018 | 11.30% | 51 | 17.06% |
Steffen Klassert | 1449 | 8.12% | 16 | 5.35% |
Alexey Kuznetsov | 1253 | 7.02% | 8 | 2.68% |
Shinta Sugimoto | 1246 | 6.98% | 1 | 0.33% |
Alexey Dobriyan | 1120 | 6.27% | 28 | 9.36% |
Masahide Nakamura | 800 | 4.48% | 11 | 3.68% |
Christophe Gouault | 755 | 4.23% | 2 | 0.67% |
Joy Latten | 618 | 3.46% | 3 | 1.00% |
Hideaki Yoshifuji / 吉藤英明 | 607 | 3.40% | 7 | 2.34% |
Florian Westphal | 375 | 2.10% | 15 | 5.02% |
Eric Dumazet | 267 | 1.50% | 14 | 4.68% |
Jamal Hadi Salim | 243 | 1.36% | 8 | 2.68% |
Fan Du | 240 | 1.34% | 6 | 2.01% |
Andrew Morton | 226 | 1.27% | 2 | 0.67% |
Julian Anastasov | 224 | 1.25% | 2 | 0.67% |
Paul Moore | 156 | 0.87% | 5 | 1.67% |
Trent Jaeger | 136 | 0.76% | 1 | 0.33% |
James Morris | 117 | 0.66% | 3 | 1.00% |
Patrick McHardy | 110 | 0.62% | 4 | 1.34% |
Kazunori Miyazawa | 93 | 0.52% | 1 | 0.33% |
Eric Paris | 67 | 0.38% | 2 | 0.67% |
Baker Zhang | 57 | 0.32% | 1 | 0.33% |
Adrian Bunk | 51 | 0.29% | 2 | 0.67% |
Li RongQing | 44 | 0.25% | 6 | 2.01% |
Wei Yongjun | 34 | 0.19% | 2 | 0.67% |
Venkat Yekkirala | 34 | 0.19% | 3 | 1.00% |
Eric W. Biedermann | 30 | 0.17% | 5 | 1.67% |
Gao Feng | 24 | 0.13% | 1 | 0.33% |
David Ahern | 23 | 0.13% | 1 | 0.33% |
Tetsuo Handa | 19 | 0.11% | 1 | 0.33% |
Huaibin Wang | 17 | 0.10% | 1 | 0.33% |
Tobias Brunner | 15 | 0.08% | 1 | 0.33% |
Américo Wang | 15 | 0.08% | 2 | 0.67% |
Fernando Luis Vázquez Cao | 13 | 0.07% | 1 | 0.33% |
Sasha Levin | 12 | 0.07% | 1 | 0.33% |
Stephen Hemminger | 11 | 0.06% | 1 | 0.33% |
Priyanka Jain | 10 | 0.06% | 1 | 0.33% |
Madalin Bucur | 10 | 0.06% | 1 | 0.33% |
Xin Long | 9 | 0.05% | 1 | 0.33% |
Hiroaki SHIMODA | 9 | 0.05% | 1 | 0.33% |
Arnaldo Carvalho de Melo | 9 | 0.05% | 1 | 0.33% |
Arnaud Ebalard | 7 | 0.04% | 1 | 0.33% |
Harvey Harrison | 6 | 0.03% | 2 | 0.67% |
Joakim Koskela | 6 | 0.03% | 1 | 0.33% |
Michal Kubeček | 6 | 0.03% | 1 | 0.33% |
Thomas Egerer | 6 | 0.03% | 1 | 0.33% |
Ken Helias | 5 | 0.03% | 1 | 0.33% |
Pavel Emelyanov | 5 | 0.03% | 1 | 0.33% |
Ying Xue | 5 | 0.03% | 1 | 0.33% |
Nicolas Dichtel | 4 | 0.02% | 1 | 0.33% |
Krishna Kumar | 3 | 0.02% | 2 | 0.67% |
David Howells | 3 | 0.02% | 1 | 0.33% |
Thomas Gleixner | 3 | 0.02% | 1 | 0.33% |
Jiri Pirko | 3 | 0.02% | 1 | 0.33% |
Sebastian Andrzej Siewior | 3 | 0.02% | 1 | 0.33% |
Kris Katterjohn | 3 | 0.02% | 1 | 0.33% |
Christoph Lameter | 2 | 0.01% | 1 | 0.33% |
Christoph Hellwig | 2 | 0.01% | 1 | 0.33% |
Linus Torvalds | 2 | 0.01% | 1 | 0.33% |
Weilong Chen | 2 | 0.01% | 1 | 0.33% |
Changli Gao | 2 | 0.01% | 1 | 0.33% |
Eugene Surovegin | 2 | 0.01% | 1 | 0.33% |
Jesper Juhl | 2 | 0.01% | 1 | 0.33% |
Al Viro | 1 | 0.01% | 1 | 0.33% |
Panagiotis Issaris | 1 | 0.01% | 1 | 0.33% |
Alexander Alemayhu | 1 | 0.01% | 1 | 0.33% |
Daniel Borkmann | | 0.00% | 0 | 0.00% |
Total | 17854 | 100.00% | 299 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.