aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Herbert <therbert@google.com>2014-11-12 14:54:09 -0500
committerDavid S. Miller <davem@davemloft.net>2014-11-12 15:01:35 -0500
commita8c5f90fb59a2d3bff0bd29adbb3e39fe0dd52f8 (patch)
tree49171c0ba2df50c16595901743dad7c0d32a7c33
parent4243cdc2c1e5a1375cc8397e8f9b06530f099c60 (diff)
ip_tunnel: Ops registration for secondary encap (fou, gue)
Instead of calling fou and gue functions directly from ip_tunnel use ops for these that were previously registered. This patch adds the logic to add and remove encapsulation operations for ip_tunnel, and modified fou (and gue) to register with ip_tunnels. This patch also addresses a circular dependency between ip_tunnel and fou that was causing link errors when CONFIG_NET_IP_TUNNEL=y and CONFIG_NET_FOU=m. References to fou an gue have been removed from ip_tunnel.c Reported-by: Randy Dunlap <rdunlap@infradead.org> Signed-off-by: Tom Herbert <therbert@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/fou.h25
-rw-r--r--include/net/ip_tunnels.h16
-rw-r--r--net/ipv4/fou.c85
-rw-r--r--net/ipv4/ip_tunnel.c78
4 files changed, 157 insertions, 47 deletions
diff --git a/include/net/fou.h b/include/net/fou.h
index 25b26ffcf1df..19b8a0c62a98 100644
--- a/include/net/fou.h
+++ b/include/net/fou.h
@@ -8,31 +8,12 @@
8#include <net/ip_tunnels.h> 8#include <net/ip_tunnels.h>
9#include <net/udp.h> 9#include <net/udp.h>
10 10
11size_t fou_encap_hlen(struct ip_tunnel_encap *e);
12static size_t gue_encap_hlen(struct ip_tunnel_encap *e);
13
11int fou_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e, 14int fou_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e,
12 u8 *protocol, struct flowi4 *fl4); 15 u8 *protocol, struct flowi4 *fl4);
13int gue_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e, 16int gue_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e,
14 u8 *protocol, struct flowi4 *fl4); 17 u8 *protocol, struct flowi4 *fl4);
15 18
16static size_t fou_encap_hlen(struct ip_tunnel_encap *e)
17{
18 return sizeof(struct udphdr);
19}
20
21static size_t gue_encap_hlen(struct ip_tunnel_encap *e)
22{
23 size_t len;
24 bool need_priv = false;
25
26 len = sizeof(struct udphdr) + sizeof(struct guehdr);
27
28 if (e->flags & TUNNEL_ENCAP_FLAG_REMCSUM) {
29 len += GUE_PLEN_REMCSUM;
30 need_priv = true;
31 }
32
33 len += need_priv ? GUE_LEN_PRIV : 0;
34
35 return len;
36}
37
38#endif 19#endif
diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h
index 5bc6edeb7143..25a59eb388a6 100644
--- a/include/net/ip_tunnels.h
+++ b/include/net/ip_tunnels.h
@@ -117,6 +117,22 @@ struct ip_tunnel_net {
117 struct hlist_head tunnels[IP_TNL_HASH_SIZE]; 117 struct hlist_head tunnels[IP_TNL_HASH_SIZE];
118}; 118};
119 119
120struct ip_tunnel_encap_ops {
121 size_t (*encap_hlen)(struct ip_tunnel_encap *e);
122 int (*build_header)(struct sk_buff *skb, struct ip_tunnel_encap *e,
123 u8 *protocol, struct flowi4 *fl4);
124};
125
126#define MAX_IPTUN_ENCAP_OPS 8
127
128extern const struct ip_tunnel_encap_ops __rcu *
129 iptun_encaps[MAX_IPTUN_ENCAP_OPS];
130
131int ip_tunnel_encap_add_ops(const struct ip_tunnel_encap_ops *op,
132 unsigned int num);
133int ip_tunnel_encap_del_ops(const struct ip_tunnel_encap_ops *op,
134 unsigned int num);
135
120#ifdef CONFIG_INET 136#ifdef CONFIG_INET
121 137
122int ip_tunnel_init(struct net_device *dev); 138int ip_tunnel_init(struct net_device *dev);
diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c
index 740ae099a0d9..fe0907774ce8 100644
--- a/net/ipv4/fou.c
+++ b/net/ipv4/fou.c
@@ -668,6 +668,30 @@ static const struct genl_ops fou_nl_ops[] = {
668 }, 668 },
669}; 669};
670 670
671size_t fou_encap_hlen(struct ip_tunnel_encap *e)
672{
673 return sizeof(struct udphdr);
674}
675EXPORT_SYMBOL(fou_encap_hlen);
676
677size_t gue_encap_hlen(struct ip_tunnel_encap *e)
678{
679 size_t len;
680 bool need_priv = false;
681
682 len = sizeof(struct udphdr) + sizeof(struct guehdr);
683
684 if (e->flags & TUNNEL_ENCAP_FLAG_REMCSUM) {
685 len += GUE_PLEN_REMCSUM;
686 need_priv = true;
687 }
688
689 len += need_priv ? GUE_LEN_PRIV : 0;
690
691 return len;
692}
693EXPORT_SYMBOL(gue_encap_hlen);
694
671static void fou_build_udp(struct sk_buff *skb, struct ip_tunnel_encap *e, 695static void fou_build_udp(struct sk_buff *skb, struct ip_tunnel_encap *e,
672 struct flowi4 *fl4, u8 *protocol, __be16 sport) 696 struct flowi4 *fl4, u8 *protocol, __be16 sport)
673{ 697{
@@ -787,6 +811,57 @@ int gue_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e,
787} 811}
788EXPORT_SYMBOL(gue_build_header); 812EXPORT_SYMBOL(gue_build_header);
789 813
814#ifdef CONFIG_NET_FOU_IP_TUNNELS
815
816static const struct ip_tunnel_encap_ops __read_mostly fou_iptun_ops = {
817 .encap_hlen = fou_encap_hlen,
818 .build_header = fou_build_header,
819};
820
821static const struct ip_tunnel_encap_ops __read_mostly gue_iptun_ops = {
822 .encap_hlen = gue_encap_hlen,
823 .build_header = gue_build_header,
824};
825
826static int ip_tunnel_encap_add_fou_ops(void)
827{
828 int ret;
829
830 ret = ip_tunnel_encap_add_ops(&fou_iptun_ops, TUNNEL_ENCAP_FOU);
831 if (ret < 0) {
832 pr_err("can't add fou ops\n");
833 return ret;
834 }
835
836 ret = ip_tunnel_encap_add_ops(&gue_iptun_ops, TUNNEL_ENCAP_GUE);
837 if (ret < 0) {
838 pr_err("can't add gue ops\n");
839 ip_tunnel_encap_del_ops(&fou_iptun_ops, TUNNEL_ENCAP_FOU);
840 return ret;
841 }
842
843 return 0;
844}
845
846static void ip_tunnel_encap_del_fou_ops(void)
847{
848 ip_tunnel_encap_del_ops(&fou_iptun_ops, TUNNEL_ENCAP_FOU);
849 ip_tunnel_encap_del_ops(&gue_iptun_ops, TUNNEL_ENCAP_GUE);
850}
851
852#else
853
854static int ip_tunnel_encap_add_fou_ops(void)
855{
856 return 0;
857}
858
859static int ip_tunnel_encap_del_fou_ops(void)
860{
861}
862
863#endif
864
790static int __init fou_init(void) 865static int __init fou_init(void)
791{ 866{
792 int ret; 867 int ret;
@@ -794,6 +869,14 @@ static int __init fou_init(void)
794 ret = genl_register_family_with_ops(&fou_nl_family, 869 ret = genl_register_family_with_ops(&fou_nl_family,
795 fou_nl_ops); 870 fou_nl_ops);
796 871
872 if (ret < 0)
873 goto exit;
874
875 ret = ip_tunnel_encap_add_fou_ops();
876 if (ret < 0)
877 genl_unregister_family(&fou_nl_family);
878
879exit:
797 return ret; 880 return ret;
798} 881}
799 882
@@ -801,6 +884,8 @@ static void __exit fou_fini(void)
801{ 884{
802 struct fou *fou, *next; 885 struct fou *fou, *next;
803 886
887 ip_tunnel_encap_del_fou_ops();
888
804 genl_unregister_family(&fou_nl_family); 889 genl_unregister_family(&fou_nl_family);
805 890
806 /* Close all the FOU sockets */ 891 /* Close all the FOU sockets */
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c
index c3587e1c8b82..63e745aadab6 100644
--- a/net/ipv4/ip_tunnel.c
+++ b/net/ipv4/ip_tunnel.c
@@ -57,10 +57,6 @@
57#include <net/rtnetlink.h> 57#include <net/rtnetlink.h>
58#include <net/udp.h> 58#include <net/udp.h>
59 59
60#if IS_ENABLED(CONFIG_NET_FOU)
61#include <net/fou.h>
62#endif
63
64#if IS_ENABLED(CONFIG_IPV6) 60#if IS_ENABLED(CONFIG_IPV6)
65#include <net/ipv6.h> 61#include <net/ipv6.h>
66#include <net/ip6_fib.h> 62#include <net/ip6_fib.h>
@@ -494,19 +490,50 @@ EXPORT_SYMBOL_GPL(ip_tunnel_rcv);
494 490
495static int ip_encap_hlen(struct ip_tunnel_encap *e) 491static int ip_encap_hlen(struct ip_tunnel_encap *e)
496{ 492{
497 switch (e->type) { 493 const struct ip_tunnel_encap_ops *ops;
498 case TUNNEL_ENCAP_NONE: 494 int hlen = -EINVAL;
495
496 if (e->type == TUNNEL_ENCAP_NONE)
499 return 0; 497 return 0;
500#if IS_ENABLED(CONFIG_NET_FOU) 498
501 case TUNNEL_ENCAP_FOU: 499 if (e->type >= MAX_IPTUN_ENCAP_OPS)
502 return fou_encap_hlen(e);
503 case TUNNEL_ENCAP_GUE:
504 return gue_encap_hlen(e);
505#endif
506 default:
507 return -EINVAL; 500 return -EINVAL;
508 } 501
502 rcu_read_lock();
503 ops = rcu_dereference(iptun_encaps[e->type]);
504 if (likely(ops && ops->encap_hlen))
505 hlen = ops->encap_hlen(e);
506 rcu_read_unlock();
507
508 return hlen;
509}
510
511const struct ip_tunnel_encap_ops __rcu *
512 iptun_encaps[MAX_IPTUN_ENCAP_OPS] __read_mostly;
513
514int ip_tunnel_encap_add_ops(const struct ip_tunnel_encap_ops *ops,
515 unsigned int num)
516{
517 return !cmpxchg((const struct ip_tunnel_encap_ops **)
518 &iptun_encaps[num],
519 NULL, ops) ? 0 : -1;
509} 520}
521EXPORT_SYMBOL(ip_tunnel_encap_add_ops);
522
523int ip_tunnel_encap_del_ops(const struct ip_tunnel_encap_ops *ops,
524 unsigned int num)
525{
526 int ret;
527
528 ret = (cmpxchg((const struct ip_tunnel_encap_ops **)
529 &iptun_encaps[num],
530 ops, NULL) == ops) ? 0 : -1;
531
532 synchronize_net();
533
534 return ret;
535}
536EXPORT_SYMBOL(ip_tunnel_encap_del_ops);
510 537
511int ip_tunnel_encap_setup(struct ip_tunnel *t, 538int ip_tunnel_encap_setup(struct ip_tunnel *t,
512 struct ip_tunnel_encap *ipencap) 539 struct ip_tunnel_encap *ipencap)
@@ -534,18 +561,19 @@ EXPORT_SYMBOL_GPL(ip_tunnel_encap_setup);
534int ip_tunnel_encap(struct sk_buff *skb, struct ip_tunnel *t, 561int ip_tunnel_encap(struct sk_buff *skb, struct ip_tunnel *t,
535 u8 *protocol, struct flowi4 *fl4) 562 u8 *protocol, struct flowi4 *fl4)
536{ 563{
537 switch (t->encap.type) { 564 const struct ip_tunnel_encap_ops *ops;
538 case TUNNEL_ENCAP_NONE: 565 int ret = -EINVAL;
566
567 if (t->encap.type == TUNNEL_ENCAP_NONE)
539 return 0; 568 return 0;
540#if IS_ENABLED(CONFIG_NET_FOU) 569
541 case TUNNEL_ENCAP_FOU: 570 rcu_read_lock();
542 return fou_build_header(skb, &t->encap, protocol, fl4); 571 ops = rcu_dereference(iptun_encaps[t->encap.type]);
543 case TUNNEL_ENCAP_GUE: 572 if (likely(ops && ops->build_header))
544 return gue_build_header(skb, &t->encap, protocol, fl4); 573 ret = ops->build_header(skb, &t->encap, protocol, fl4);
545#endif 574 rcu_read_unlock();
546 default: 575
547 return -EINVAL; 576 return ret;
548 }
549} 577}
550EXPORT_SYMBOL(ip_tunnel_encap); 578EXPORT_SYMBOL(ip_tunnel_encap);
551 579