diff options
Diffstat (limited to 'net/xfrm/xfrm_policy.c')
-rw-r--r-- | net/xfrm/xfrm_policy.c | 247 |
1 files changed, 241 insertions, 6 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 6c9aa642a2ba..5b47180986f8 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -35,6 +35,10 @@ | |||
35 | 35 | ||
36 | #include "xfrm_hash.h" | 36 | #include "xfrm_hash.h" |
37 | 37 | ||
38 | #define XFRM_QUEUE_TMO_MIN ((unsigned)(HZ/10)) | ||
39 | #define XFRM_QUEUE_TMO_MAX ((unsigned)(60*HZ)) | ||
40 | #define XFRM_MAX_QUEUE_LEN 100 | ||
41 | |||
38 | DEFINE_MUTEX(xfrm_cfg_mutex); | 42 | DEFINE_MUTEX(xfrm_cfg_mutex); |
39 | EXPORT_SYMBOL(xfrm_cfg_mutex); | 43 | EXPORT_SYMBOL(xfrm_cfg_mutex); |
40 | 44 | ||
@@ -51,7 +55,7 @@ static struct kmem_cache *xfrm_dst_cache __read_mostly; | |||
51 | static void xfrm_init_pmtu(struct dst_entry *dst); | 55 | static void xfrm_init_pmtu(struct dst_entry *dst); |
52 | static int stale_bundle(struct dst_entry *dst); | 56 | static int stale_bundle(struct dst_entry *dst); |
53 | static int xfrm_bundle_ok(struct xfrm_dst *xdst); | 57 | static int xfrm_bundle_ok(struct xfrm_dst *xdst); |
54 | 58 | static void xfrm_policy_queue_process(unsigned long arg); | |
55 | 59 | ||
56 | static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, | 60 | static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, |
57 | int dir); | 61 | int dir); |
@@ -287,8 +291,11 @@ struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp) | |||
287 | INIT_HLIST_NODE(&policy->byidx); | 291 | INIT_HLIST_NODE(&policy->byidx); |
288 | rwlock_init(&policy->lock); | 292 | rwlock_init(&policy->lock); |
289 | atomic_set(&policy->refcnt, 1); | 293 | atomic_set(&policy->refcnt, 1); |
294 | skb_queue_head_init(&policy->polq.hold_queue); | ||
290 | setup_timer(&policy->timer, xfrm_policy_timer, | 295 | setup_timer(&policy->timer, xfrm_policy_timer, |
291 | (unsigned long)policy); | 296 | (unsigned long)policy); |
297 | setup_timer(&policy->polq.hold_timer, xfrm_policy_queue_process, | ||
298 | (unsigned long)policy); | ||
292 | policy->flo.ops = &xfrm_policy_fc_ops; | 299 | policy->flo.ops = &xfrm_policy_fc_ops; |
293 | } | 300 | } |
294 | return policy; | 301 | return policy; |
@@ -309,6 +316,16 @@ void xfrm_policy_destroy(struct xfrm_policy *policy) | |||
309 | } | 316 | } |
310 | EXPORT_SYMBOL(xfrm_policy_destroy); | 317 | EXPORT_SYMBOL(xfrm_policy_destroy); |
311 | 318 | ||
319 | static void xfrm_queue_purge(struct sk_buff_head *list) | ||
320 | { | ||
321 | struct sk_buff *skb; | ||
322 | |||
323 | while ((skb = skb_dequeue(list)) != NULL) { | ||
324 | dev_put(skb->dev); | ||
325 | kfree_skb(skb); | ||
326 | } | ||
327 | } | ||
328 | |||
312 | /* Rule must be locked. Release descentant resources, announce | 329 | /* Rule must be locked. Release descentant resources, announce |
313 | * entry dead. The rule must be unlinked from lists to the moment. | 330 | * entry dead. The rule must be unlinked from lists to the moment. |
314 | */ | 331 | */ |
@@ -319,6 +336,9 @@ static void xfrm_policy_kill(struct xfrm_policy *policy) | |||
319 | 336 | ||
320 | atomic_inc(&policy->genid); | 337 | atomic_inc(&policy->genid); |
321 | 338 | ||
339 | del_timer(&policy->polq.hold_timer); | ||
340 | xfrm_queue_purge(&policy->polq.hold_queue); | ||
341 | |||
322 | if (del_timer(&policy->timer)) | 342 | if (del_timer(&policy->timer)) |
323 | xfrm_pol_put(policy); | 343 | xfrm_pol_put(policy); |
324 | 344 | ||
@@ -562,6 +582,46 @@ static inline int selector_cmp(struct xfrm_selector *s1, struct xfrm_selector *s | |||
562 | return 0; | 582 | return 0; |
563 | } | 583 | } |
564 | 584 | ||
585 | static void xfrm_policy_requeue(struct xfrm_policy *old, | ||
586 | struct xfrm_policy *new) | ||
587 | { | ||
588 | struct xfrm_policy_queue *pq = &old->polq; | ||
589 | struct sk_buff_head list; | ||
590 | |||
591 | __skb_queue_head_init(&list); | ||
592 | |||
593 | spin_lock_bh(&pq->hold_queue.lock); | ||
594 | skb_queue_splice_init(&pq->hold_queue, &list); | ||
595 | del_timer(&pq->hold_timer); | ||
596 | spin_unlock_bh(&pq->hold_queue.lock); | ||
597 | |||
598 | if (skb_queue_empty(&list)) | ||
599 | return; | ||
600 | |||
601 | pq = &new->polq; | ||
602 | |||
603 | spin_lock_bh(&pq->hold_queue.lock); | ||
604 | skb_queue_splice(&list, &pq->hold_queue); | ||
605 | pq->timeout = XFRM_QUEUE_TMO_MIN; | ||
606 | mod_timer(&pq->hold_timer, jiffies); | ||
607 | spin_unlock_bh(&pq->hold_queue.lock); | ||
608 | } | ||
609 | |||
610 | static bool xfrm_policy_mark_match(struct xfrm_policy *policy, | ||
611 | struct xfrm_policy *pol) | ||
612 | { | ||
613 | u32 mark = policy->mark.v & policy->mark.m; | ||
614 | |||
615 | if (policy->mark.v == pol->mark.v && policy->mark.m == pol->mark.m) | ||
616 | return true; | ||
617 | |||
618 | if ((mark & pol->mark.m) == pol->mark.v && | ||
619 | policy->priority == pol->priority) | ||
620 | return true; | ||
621 | |||
622 | return false; | ||
623 | } | ||
624 | |||
565 | int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | 625 | int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) |
566 | { | 626 | { |
567 | struct net *net = xp_net(policy); | 627 | struct net *net = xp_net(policy); |
@@ -569,7 +629,6 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
569 | struct xfrm_policy *delpol; | 629 | struct xfrm_policy *delpol; |
570 | struct hlist_head *chain; | 630 | struct hlist_head *chain; |
571 | struct hlist_node *entry, *newpos; | 631 | struct hlist_node *entry, *newpos; |
572 | u32 mark = policy->mark.v & policy->mark.m; | ||
573 | 632 | ||
574 | write_lock_bh(&xfrm_policy_lock); | 633 | write_lock_bh(&xfrm_policy_lock); |
575 | chain = policy_hash_bysel(net, &policy->selector, policy->family, dir); | 634 | chain = policy_hash_bysel(net, &policy->selector, policy->family, dir); |
@@ -578,7 +637,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
578 | hlist_for_each_entry(pol, entry, chain, bydst) { | 637 | hlist_for_each_entry(pol, entry, chain, bydst) { |
579 | if (pol->type == policy->type && | 638 | if (pol->type == policy->type && |
580 | !selector_cmp(&pol->selector, &policy->selector) && | 639 | !selector_cmp(&pol->selector, &policy->selector) && |
581 | (mark & pol->mark.m) == pol->mark.v && | 640 | xfrm_policy_mark_match(policy, pol) && |
582 | xfrm_sec_ctx_match(pol->security, policy->security) && | 641 | xfrm_sec_ctx_match(pol->security, policy->security) && |
583 | !WARN_ON(delpol)) { | 642 | !WARN_ON(delpol)) { |
584 | if (excl) { | 643 | if (excl) { |
@@ -603,8 +662,10 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
603 | net->xfrm.policy_count[dir]++; | 662 | net->xfrm.policy_count[dir]++; |
604 | atomic_inc(&flow_cache_genid); | 663 | atomic_inc(&flow_cache_genid); |
605 | rt_genid_bump(net); | 664 | rt_genid_bump(net); |
606 | if (delpol) | 665 | if (delpol) { |
666 | xfrm_policy_requeue(delpol, policy); | ||
607 | __xfrm_policy_unlink(delpol, dir); | 667 | __xfrm_policy_unlink(delpol, dir); |
668 | } | ||
608 | policy->index = delpol ? delpol->index : xfrm_gen_index(net, dir); | 669 | policy->index = delpol ? delpol->index : xfrm_gen_index(net, dir); |
609 | hlist_add_head(&policy->byidx, net->xfrm.policy_byidx+idx_hash(net, policy->index)); | 670 | hlist_add_head(&policy->byidx, net->xfrm.policy_byidx+idx_hash(net, policy->index)); |
610 | policy->curlft.add_time = get_seconds(); | 671 | policy->curlft.add_time = get_seconds(); |
@@ -1115,11 +1176,15 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) | |||
1115 | pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir); | 1176 | pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir); |
1116 | __xfrm_policy_link(pol, XFRM_POLICY_MAX+dir); | 1177 | __xfrm_policy_link(pol, XFRM_POLICY_MAX+dir); |
1117 | } | 1178 | } |
1118 | if (old_pol) | 1179 | if (old_pol) { |
1180 | if (pol) | ||
1181 | xfrm_policy_requeue(old_pol, pol); | ||
1182 | |||
1119 | /* Unlinking succeeds always. This is the only function | 1183 | /* Unlinking succeeds always. This is the only function |
1120 | * allowed to delete or replace socket policy. | 1184 | * allowed to delete or replace socket policy. |
1121 | */ | 1185 | */ |
1122 | __xfrm_policy_unlink(old_pol, XFRM_POLICY_MAX+dir); | 1186 | __xfrm_policy_unlink(old_pol, XFRM_POLICY_MAX+dir); |
1187 | } | ||
1123 | write_unlock_bh(&xfrm_policy_lock); | 1188 | write_unlock_bh(&xfrm_policy_lock); |
1124 | 1189 | ||
1125 | if (old_pol) { | 1190 | if (old_pol) { |
@@ -1310,6 +1375,8 @@ static struct flow_cache_object *xfrm_bundle_flo_get(struct flow_cache_object *f | |||
1310 | * It means we need to try again resolving. */ | 1375 | * It means we need to try again resolving. */ |
1311 | if (xdst->num_xfrms > 0) | 1376 | if (xdst->num_xfrms > 0) |
1312 | return NULL; | 1377 | return NULL; |
1378 | } else if (dst->flags & DST_XFRM_QUEUE) { | ||
1379 | return NULL; | ||
1313 | } else { | 1380 | } else { |
1314 | /* Real bundle */ | 1381 | /* Real bundle */ |
1315 | if (stale_bundle(dst)) | 1382 | if (stale_bundle(dst)) |
@@ -1673,6 +1740,171 @@ xfrm_resolve_and_create_bundle(struct xfrm_policy **pols, int num_pols, | |||
1673 | return xdst; | 1740 | return xdst; |
1674 | } | 1741 | } |
1675 | 1742 | ||
1743 | static void xfrm_policy_queue_process(unsigned long arg) | ||
1744 | { | ||
1745 | int err = 0; | ||
1746 | struct sk_buff *skb; | ||
1747 | struct sock *sk; | ||
1748 | struct dst_entry *dst; | ||
1749 | struct net_device *dev; | ||
1750 | struct xfrm_policy *pol = (struct xfrm_policy *)arg; | ||
1751 | struct xfrm_policy_queue *pq = &pol->polq; | ||
1752 | struct flowi fl; | ||
1753 | struct sk_buff_head list; | ||
1754 | |||
1755 | spin_lock(&pq->hold_queue.lock); | ||
1756 | skb = skb_peek(&pq->hold_queue); | ||
1757 | dst = skb_dst(skb); | ||
1758 | sk = skb->sk; | ||
1759 | xfrm_decode_session(skb, &fl, dst->ops->family); | ||
1760 | spin_unlock(&pq->hold_queue.lock); | ||
1761 | |||
1762 | dst_hold(dst->path); | ||
1763 | dst = xfrm_lookup(xp_net(pol), dst->path, &fl, | ||
1764 | sk, 0); | ||
1765 | if (IS_ERR(dst)) | ||
1766 | goto purge_queue; | ||
1767 | |||
1768 | if (dst->flags & DST_XFRM_QUEUE) { | ||
1769 | dst_release(dst); | ||
1770 | |||
1771 | if (pq->timeout >= XFRM_QUEUE_TMO_MAX) | ||
1772 | goto purge_queue; | ||
1773 | |||
1774 | pq->timeout = pq->timeout << 1; | ||
1775 | mod_timer(&pq->hold_timer, jiffies + pq->timeout); | ||
1776 | return; | ||
1777 | } | ||
1778 | |||
1779 | dst_release(dst); | ||
1780 | |||
1781 | __skb_queue_head_init(&list); | ||
1782 | |||
1783 | spin_lock(&pq->hold_queue.lock); | ||
1784 | pq->timeout = 0; | ||
1785 | skb_queue_splice_init(&pq->hold_queue, &list); | ||
1786 | spin_unlock(&pq->hold_queue.lock); | ||
1787 | |||
1788 | while (!skb_queue_empty(&list)) { | ||
1789 | skb = __skb_dequeue(&list); | ||
1790 | |||
1791 | xfrm_decode_session(skb, &fl, skb_dst(skb)->ops->family); | ||
1792 | dst_hold(skb_dst(skb)->path); | ||
1793 | dst = xfrm_lookup(xp_net(pol), skb_dst(skb)->path, | ||
1794 | &fl, skb->sk, 0); | ||
1795 | if (IS_ERR(dst)) { | ||
1796 | dev_put(skb->dev); | ||
1797 | kfree_skb(skb); | ||
1798 | continue; | ||
1799 | } | ||
1800 | |||
1801 | nf_reset(skb); | ||
1802 | skb_dst_drop(skb); | ||
1803 | skb_dst_set(skb, dst); | ||
1804 | |||
1805 | dev = skb->dev; | ||
1806 | err = dst_output(skb); | ||
1807 | dev_put(dev); | ||
1808 | } | ||
1809 | |||
1810 | return; | ||
1811 | |||
1812 | purge_queue: | ||
1813 | pq->timeout = 0; | ||
1814 | xfrm_queue_purge(&pq->hold_queue); | ||
1815 | } | ||
1816 | |||
1817 | static int xdst_queue_output(struct sk_buff *skb) | ||
1818 | { | ||
1819 | unsigned long sched_next; | ||
1820 | struct dst_entry *dst = skb_dst(skb); | ||
1821 | struct xfrm_dst *xdst = (struct xfrm_dst *) dst; | ||
1822 | struct xfrm_policy_queue *pq = &xdst->pols[0]->polq; | ||
1823 | |||
1824 | if (pq->hold_queue.qlen > XFRM_MAX_QUEUE_LEN) { | ||
1825 | kfree_skb(skb); | ||
1826 | return -EAGAIN; | ||
1827 | } | ||
1828 | |||
1829 | skb_dst_force(skb); | ||
1830 | dev_hold(skb->dev); | ||
1831 | |||
1832 | spin_lock_bh(&pq->hold_queue.lock); | ||
1833 | |||
1834 | if (!pq->timeout) | ||
1835 | pq->timeout = XFRM_QUEUE_TMO_MIN; | ||
1836 | |||
1837 | sched_next = jiffies + pq->timeout; | ||
1838 | |||
1839 | if (del_timer(&pq->hold_timer)) { | ||
1840 | if (time_before(pq->hold_timer.expires, sched_next)) | ||
1841 | sched_next = pq->hold_timer.expires; | ||
1842 | } | ||
1843 | |||
1844 | __skb_queue_tail(&pq->hold_queue, skb); | ||
1845 | mod_timer(&pq->hold_timer, sched_next); | ||
1846 | |||
1847 | spin_unlock_bh(&pq->hold_queue.lock); | ||
1848 | |||
1849 | return 0; | ||
1850 | } | ||
1851 | |||
1852 | static struct xfrm_dst *xfrm_create_dummy_bundle(struct net *net, | ||
1853 | struct dst_entry *dst, | ||
1854 | const struct flowi *fl, | ||
1855 | int num_xfrms, | ||
1856 | u16 family) | ||
1857 | { | ||
1858 | int err; | ||
1859 | struct net_device *dev; | ||
1860 | struct dst_entry *dst1; | ||
1861 | struct xfrm_dst *xdst; | ||
1862 | |||
1863 | xdst = xfrm_alloc_dst(net, family); | ||
1864 | if (IS_ERR(xdst)) | ||
1865 | return xdst; | ||
1866 | |||
1867 | if (net->xfrm.sysctl_larval_drop || num_xfrms <= 0 || | ||
1868 | (fl->flowi_flags & FLOWI_FLAG_CAN_SLEEP)) | ||
1869 | return xdst; | ||
1870 | |||
1871 | dst1 = &xdst->u.dst; | ||
1872 | dst_hold(dst); | ||
1873 | xdst->route = dst; | ||
1874 | |||
1875 | dst_copy_metrics(dst1, dst); | ||
1876 | |||
1877 | dst1->obsolete = DST_OBSOLETE_FORCE_CHK; | ||
1878 | dst1->flags |= DST_HOST | DST_XFRM_QUEUE; | ||
1879 | dst1->lastuse = jiffies; | ||
1880 | |||
1881 | dst1->input = dst_discard; | ||
1882 | dst1->output = xdst_queue_output; | ||
1883 | |||
1884 | dst_hold(dst); | ||
1885 | dst1->child = dst; | ||
1886 | dst1->path = dst; | ||
1887 | |||
1888 | xfrm_init_path((struct xfrm_dst *)dst1, dst, 0); | ||
1889 | |||
1890 | err = -ENODEV; | ||
1891 | dev = dst->dev; | ||
1892 | if (!dev) | ||
1893 | goto free_dst; | ||
1894 | |||
1895 | err = xfrm_fill_dst(xdst, dev, fl); | ||
1896 | if (err) | ||
1897 | goto free_dst; | ||
1898 | |||
1899 | out: | ||
1900 | return xdst; | ||
1901 | |||
1902 | free_dst: | ||
1903 | dst_release(dst1); | ||
1904 | xdst = ERR_PTR(err); | ||
1905 | goto out; | ||
1906 | } | ||
1907 | |||
1676 | static struct flow_cache_object * | 1908 | static struct flow_cache_object * |
1677 | xfrm_bundle_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir, | 1909 | xfrm_bundle_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir, |
1678 | struct flow_cache_object *oldflo, void *ctx) | 1910 | struct flow_cache_object *oldflo, void *ctx) |
@@ -1751,7 +1983,7 @@ make_dummy_bundle: | |||
1751 | /* We found policies, but there's no bundles to instantiate: | 1983 | /* We found policies, but there's no bundles to instantiate: |
1752 | * either because the policy blocks, has no transformations or | 1984 | * either because the policy blocks, has no transformations or |
1753 | * we could not build template (no xfrm_states).*/ | 1985 | * we could not build template (no xfrm_states).*/ |
1754 | xdst = xfrm_alloc_dst(net, family); | 1986 | xdst = xfrm_create_dummy_bundle(net, dst_orig, fl, num_xfrms, family); |
1755 | if (IS_ERR(xdst)) { | 1987 | if (IS_ERR(xdst)) { |
1756 | xfrm_pols_put(pols, num_pols); | 1988 | xfrm_pols_put(pols, num_pols); |
1757 | return ERR_CAST(xdst); | 1989 | return ERR_CAST(xdst); |
@@ -2359,6 +2591,9 @@ static int xfrm_bundle_ok(struct xfrm_dst *first) | |||
2359 | (dst->dev && !netif_running(dst->dev))) | 2591 | (dst->dev && !netif_running(dst->dev))) |
2360 | return 0; | 2592 | return 0; |
2361 | 2593 | ||
2594 | if (dst->flags & DST_XFRM_QUEUE) | ||
2595 | return 1; | ||
2596 | |||
2362 | last = NULL; | 2597 | last = NULL; |
2363 | 2598 | ||
2364 | do { | 2599 | do { |