aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2008-11-18 05:54:05 -0500
committerPatrick McHardy <kaber@trash.net>2008-11-18 05:54:05 -0500
commit226c0c0ef2abdf91b8d9cce1aaf7d4635a5e5926 (patch)
treec1f5504d7942f0514ad38430668c8a7add4b7576 /net
parent4dc06f9633444f426ef9960c53426f2d2ded64ac (diff)
netfilter: ctnetlink: helper modules load-on-demand support
This patch adds module loading for helpers via ctnetlink. * Creation path: We support explicit and implicit helper assignation. For the explicit case, we try to load the module. If the module is correctly loaded and the helper is present, we return EAGAIN to re-start the creation. Otherwise, we return EOPNOTSUPP. * Update path: release the spin lock, load the module and check. If it is present, then return EAGAIN to re-start the update. This patch provides a refactorized function to lookup-and-set the connection tracking helper. The function removes the exported symbol __nf_ct_helper_find as it has not clients anymore. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/nf_conntrack_core.c28
-rw-r--r--net/netfilter/nf_conntrack_helper.c32
-rw-r--r--net/netfilter/nf_conntrack_netlink.c70
3 files changed, 93 insertions, 37 deletions
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 622d7c671cb7..1e649fb9e0df 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -588,14 +588,7 @@ init_conntrack(struct net *net,
588 nf_conntrack_get(&ct->master->ct_general); 588 nf_conntrack_get(&ct->master->ct_general);
589 NF_CT_STAT_INC(net, expect_new); 589 NF_CT_STAT_INC(net, expect_new);
590 } else { 590 } else {
591 struct nf_conntrack_helper *helper; 591 __nf_ct_try_assign_helper(ct, GFP_ATOMIC);
592
593 helper = __nf_ct_helper_find(&repl_tuple);
594 if (helper) {
595 help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
596 if (help)
597 rcu_assign_pointer(help->helper, helper);
598 }
599 NF_CT_STAT_INC(net, new); 592 NF_CT_STAT_INC(net, new);
600 } 593 }
601 594
@@ -772,7 +765,6 @@ void nf_conntrack_alter_reply(struct nf_conn *ct,
772 const struct nf_conntrack_tuple *newreply) 765 const struct nf_conntrack_tuple *newreply)
773{ 766{
774 struct nf_conn_help *help = nfct_help(ct); 767 struct nf_conn_help *help = nfct_help(ct);
775 struct nf_conntrack_helper *helper;
776 768
777 /* Should be unconfirmed, so not in hash table yet */ 769 /* Should be unconfirmed, so not in hash table yet */
778 NF_CT_ASSERT(!nf_ct_is_confirmed(ct)); 770 NF_CT_ASSERT(!nf_ct_is_confirmed(ct));
@@ -785,23 +777,7 @@ void nf_conntrack_alter_reply(struct nf_conn *ct,
785 return; 777 return;
786 778
787 rcu_read_lock(); 779 rcu_read_lock();
788 helper = __nf_ct_helper_find(newreply); 780 __nf_ct_try_assign_helper(ct, GFP_ATOMIC);
789 if (helper == NULL) {
790 if (help)
791 rcu_assign_pointer(help->helper, NULL);
792 goto out;
793 }
794
795 if (help == NULL) {
796 help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
797 if (help == NULL)
798 goto out;
799 } else {
800 memset(&help->help, 0, sizeof(help->help));
801 }
802
803 rcu_assign_pointer(help->helper, helper);
804out:
805 rcu_read_unlock(); 781 rcu_read_unlock();
806} 782}
807EXPORT_SYMBOL_GPL(nf_conntrack_alter_reply); 783EXPORT_SYMBOL_GPL(nf_conntrack_alter_reply);
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
index 9c06b9f86ad4..9e4b74b95ce8 100644
--- a/net/netfilter/nf_conntrack_helper.c
+++ b/net/netfilter/nf_conntrack_helper.c
@@ -44,7 +44,7 @@ static unsigned int helper_hash(const struct nf_conntrack_tuple *tuple)
44 (__force __u16)tuple->src.u.all) % nf_ct_helper_hsize; 44 (__force __u16)tuple->src.u.all) % nf_ct_helper_hsize;
45} 45}
46 46
47struct nf_conntrack_helper * 47static struct nf_conntrack_helper *
48__nf_ct_helper_find(const struct nf_conntrack_tuple *tuple) 48__nf_ct_helper_find(const struct nf_conntrack_tuple *tuple)
49{ 49{
50 struct nf_conntrack_helper *helper; 50 struct nf_conntrack_helper *helper;
@@ -62,7 +62,6 @@ __nf_ct_helper_find(const struct nf_conntrack_tuple *tuple)
62 } 62 }
63 return NULL; 63 return NULL;
64} 64}
65EXPORT_SYMBOL_GPL(__nf_ct_helper_find);
66 65
67struct nf_conntrack_helper * 66struct nf_conntrack_helper *
68__nf_conntrack_helper_find_byname(const char *name) 67__nf_conntrack_helper_find_byname(const char *name)
@@ -94,6 +93,35 @@ struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp)
94} 93}
95EXPORT_SYMBOL_GPL(nf_ct_helper_ext_add); 94EXPORT_SYMBOL_GPL(nf_ct_helper_ext_add);
96 95
96int __nf_ct_try_assign_helper(struct nf_conn *ct, gfp_t flags)
97{
98 int ret = 0;
99 struct nf_conntrack_helper *helper;
100 struct nf_conn_help *help = nfct_help(ct);
101
102 helper = __nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
103 if (helper == NULL) {
104 if (help)
105 rcu_assign_pointer(help->helper, NULL);
106 goto out;
107 }
108
109 if (help == NULL) {
110 help = nf_ct_helper_ext_add(ct, flags);
111 if (help == NULL) {
112 ret = -ENOMEM;
113 goto out;
114 }
115 } else {
116 memset(&help->help, 0, sizeof(help->help));
117 }
118
119 rcu_assign_pointer(help->helper, helper);
120out:
121 return ret;
122}
123EXPORT_SYMBOL_GPL(__nf_ct_try_assign_helper);
124
97static inline int unhelp(struct nf_conntrack_tuple_hash *i, 125static inline int unhelp(struct nf_conntrack_tuple_hash *i,
98 const struct nf_conntrack_helper *me) 126 const struct nf_conntrack_helper *me)
99{ 127{
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 49a04fa0becc..4f6486cfd337 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -917,8 +917,22 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nlattr *cda[])
917 } 917 }
918 918
919 helper = __nf_conntrack_helper_find_byname(helpname); 919 helper = __nf_conntrack_helper_find_byname(helpname);
920 if (helper == NULL) 920 if (helper == NULL) {
921#ifdef CONFIG_MODULES
922 spin_unlock_bh(&nf_conntrack_lock);
923
924 if (request_module("nfct-helper-%s", helpname) < 0) {
925 spin_lock_bh(&nf_conntrack_lock);
926 return -EOPNOTSUPP;
927 }
928
929 spin_lock_bh(&nf_conntrack_lock);
930 helper = __nf_conntrack_helper_find_byname(helpname);
931 if (helper)
932 return -EAGAIN;
933#endif
921 return -EOPNOTSUPP; 934 return -EOPNOTSUPP;
935 }
922 936
923 if (help) { 937 if (help) {
924 if (help->helper == helper) 938 if (help->helper == helper)
@@ -1082,7 +1096,6 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
1082{ 1096{
1083 struct nf_conn *ct; 1097 struct nf_conn *ct;
1084 int err = -EINVAL; 1098 int err = -EINVAL;
1085 struct nf_conn_help *help;
1086 struct nf_conntrack_helper *helper; 1099 struct nf_conntrack_helper *helper;
1087 1100
1088 ct = nf_conntrack_alloc(&init_net, otuple, rtuple, GFP_KERNEL); 1101 ct = nf_conntrack_alloc(&init_net, otuple, rtuple, GFP_KERNEL);
@@ -1097,16 +1110,55 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
1097 ct->status |= IPS_CONFIRMED; 1110 ct->status |= IPS_CONFIRMED;
1098 1111
1099 rcu_read_lock(); 1112 rcu_read_lock();
1100 helper = __nf_ct_helper_find(rtuple); 1113 if (cda[CTA_HELP]) {
1101 if (helper) { 1114 char *helpname;
1102 help = nf_ct_helper_ext_add(ct, GFP_ATOMIC); 1115
1103 if (help == NULL) { 1116 err = ctnetlink_parse_help(cda[CTA_HELP], &helpname);
1117 if (err < 0) {
1118 rcu_read_unlock();
1119 goto err;
1120 }
1121
1122 helper = __nf_conntrack_helper_find_byname(helpname);
1123 if (helper == NULL) {
1124 rcu_read_unlock();
1125#ifdef CONFIG_MODULES
1126 if (request_module("nfct-helper-%s", helpname) < 0) {
1127 err = -EOPNOTSUPP;
1128 goto err;
1129 }
1130
1131 rcu_read_lock();
1132 helper = __nf_conntrack_helper_find_byname(helpname);
1133 if (helper) {
1134 rcu_read_unlock();
1135 err = -EAGAIN;
1136 goto err;
1137 }
1138 rcu_read_unlock();
1139#endif
1140 err = -EOPNOTSUPP;
1141 goto err;
1142 } else {
1143 struct nf_conn_help *help;
1144
1145 help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
1146 if (help == NULL) {
1147 rcu_read_unlock();
1148 err = -ENOMEM;
1149 goto err;
1150 }
1151
1152 /* not in hash table yet so not strictly necessary */
1153 rcu_assign_pointer(help->helper, helper);
1154 }
1155 } else {
1156 /* try an implicit helper assignation */
1157 err = __nf_ct_try_assign_helper(ct, GFP_ATOMIC);
1158 if (err < 0) {
1104 rcu_read_unlock(); 1159 rcu_read_unlock();
1105 err = -ENOMEM;
1106 goto err; 1160 goto err;
1107 } 1161 }
1108 /* not in hash table yet so not strictly necessary */
1109 rcu_assign_pointer(help->helper, helper);
1110 } 1162 }
1111 1163
1112 if (cda[CTA_STATUS]) { 1164 if (cda[CTA_STATUS]) {