diff options
author | Patrick McHardy <kaber@trash.net> | 2011-06-16 11:01:10 -0400 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2011-06-16 11:01:10 -0400 |
commit | 1f2d9c9dd8276b1c19ef80e6d8059fe47506d4c3 (patch) | |
tree | c5a3439c1c140eb87f7e3ece2e1148dece037b4f /net/netfilter | |
parent | a7fed7620b6eeaba98a558df46bb50a31828b462 (diff) | |
parent | 520b2756d9414cb6b0f6fc70714e95ee9248ebf4 (diff) |
Merge branch 'master' of /repos/git/net-next-2.6
Diffstat (limited to 'net/netfilter')
-rw-r--r-- | net/netfilter/ipset/ip_set_bitmap_ip.c | 2 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_bitmap_ipmac.c | 4 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_core.c | 22 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_app.c | 17 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_conn.c | 16 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_core.c | 127 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_ctl.c | 126 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_est.c | 14 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_ftp.c | 27 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_proto.c | 11 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_sync.c | 65 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_xmit.c | 97 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_extend.c | 8 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 8 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_sip.c | 16 | ||||
-rw-r--r-- | net/netfilter/x_tables.c | 4 | ||||
-rw-r--r-- | net/netfilter/xt_DSCP.c | 2 | ||||
-rw-r--r-- | net/netfilter/xt_conntrack.c | 5 | ||||
-rw-r--r-- | net/netfilter/xt_osf.c | 11 | ||||
-rw-r--r-- | net/netfilter/xt_set.c | 18 |
20 files changed, 389 insertions, 211 deletions
diff --git a/net/netfilter/ipset/ip_set_bitmap_ip.c b/net/netfilter/ipset/ip_set_bitmap_ip.c index a113ff066928..ba2d16607f48 100644 --- a/net/netfilter/ipset/ip_set_bitmap_ip.c +++ b/net/netfilter/ipset/ip_set_bitmap_ip.c | |||
@@ -293,7 +293,7 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[], | |||
293 | 293 | ||
294 | for (; !before(ip_to, ip); ip += map->hosts) { | 294 | for (; !before(ip_to, ip); ip += map->hosts) { |
295 | id = ip_to_id(map, ip); | 295 | id = ip_to_id(map, ip); |
296 | ret = adtfn(set, &id, timeout);; | 296 | ret = adtfn(set, &id, timeout); |
297 | 297 | ||
298 | if (ret && !ip_set_eexist(ret, flags)) | 298 | if (ret && !ip_set_eexist(ret, flags)) |
299 | return ret; | 299 | return ret; |
diff --git a/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/net/netfilter/ipset/ip_set_bitmap_ipmac.c index 00a33242e90c..a274300b6a56 100644 --- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c +++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c | |||
@@ -343,6 +343,10 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
343 | ipset_adtfn adtfn = set->variant->adt[adt]; | 343 | ipset_adtfn adtfn = set->variant->adt[adt]; |
344 | struct ipmac data; | 344 | struct ipmac data; |
345 | 345 | ||
346 | /* MAC can be src only */ | ||
347 | if (!(flags & IPSET_DIM_TWO_SRC)) | ||
348 | return 0; | ||
349 | |||
346 | data.id = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC)); | 350 | data.id = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC)); |
347 | if (data.id < map->first_ip || data.id > map->last_ip) | 351 | if (data.id < map->first_ip || data.id > map->last_ip) |
348 | return -IPSET_ERR_BITMAP_RANGE; | 352 | return -IPSET_ERR_BITMAP_RANGE; |
diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index 9152e69a162d..333b0bedf298 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c | |||
@@ -815,7 +815,7 @@ ip_set_flush(struct sock *ctnl, struct sk_buff *skb, | |||
815 | ip_set_id_t i; | 815 | ip_set_id_t i; |
816 | 816 | ||
817 | if (unlikely(protocol_failed(attr))) | 817 | if (unlikely(protocol_failed(attr))) |
818 | return -EPROTO; | 818 | return -IPSET_ERR_PROTOCOL; |
819 | 819 | ||
820 | if (!attr[IPSET_ATTR_SETNAME]) { | 820 | if (!attr[IPSET_ATTR_SETNAME]) { |
821 | for (i = 0; i < ip_set_max; i++) | 821 | for (i = 0; i < ip_set_max; i++) |
@@ -1022,8 +1022,9 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) | |||
1022 | if (cb->args[1] >= ip_set_max) | 1022 | if (cb->args[1] >= ip_set_max) |
1023 | goto out; | 1023 | goto out; |
1024 | 1024 | ||
1025 | pr_debug("args[0]: %ld args[1]: %ld\n", cb->args[0], cb->args[1]); | ||
1026 | max = cb->args[0] == DUMP_ONE ? cb->args[1] + 1 : ip_set_max; | 1025 | max = cb->args[0] == DUMP_ONE ? cb->args[1] + 1 : ip_set_max; |
1026 | dump_last: | ||
1027 | pr_debug("args[0]: %ld args[1]: %ld\n", cb->args[0], cb->args[1]); | ||
1027 | for (; cb->args[1] < max; cb->args[1]++) { | 1028 | for (; cb->args[1] < max; cb->args[1]++) { |
1028 | index = (ip_set_id_t) cb->args[1]; | 1029 | index = (ip_set_id_t) cb->args[1]; |
1029 | set = ip_set_list[index]; | 1030 | set = ip_set_list[index]; |
@@ -1038,8 +1039,8 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) | |||
1038 | * so that lists (unions of sets) are dumped last. | 1039 | * so that lists (unions of sets) are dumped last. |
1039 | */ | 1040 | */ |
1040 | if (cb->args[0] != DUMP_ONE && | 1041 | if (cb->args[0] != DUMP_ONE && |
1041 | !((cb->args[0] == DUMP_ALL) ^ | 1042 | ((cb->args[0] == DUMP_ALL) == |
1042 | (set->type->features & IPSET_DUMP_LAST))) | 1043 | !!(set->type->features & IPSET_DUMP_LAST))) |
1043 | continue; | 1044 | continue; |
1044 | pr_debug("List set: %s\n", set->name); | 1045 | pr_debug("List set: %s\n", set->name); |
1045 | if (!cb->args[2]) { | 1046 | if (!cb->args[2]) { |
@@ -1083,6 +1084,12 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) | |||
1083 | goto release_refcount; | 1084 | goto release_refcount; |
1084 | } | 1085 | } |
1085 | } | 1086 | } |
1087 | /* If we dump all sets, continue with dumping last ones */ | ||
1088 | if (cb->args[0] == DUMP_ALL) { | ||
1089 | cb->args[0] = DUMP_LAST; | ||
1090 | cb->args[1] = 0; | ||
1091 | goto dump_last; | ||
1092 | } | ||
1086 | goto out; | 1093 | goto out; |
1087 | 1094 | ||
1088 | nla_put_failure: | 1095 | nla_put_failure: |
@@ -1093,11 +1100,6 @@ release_refcount: | |||
1093 | pr_debug("release set %s\n", ip_set_list[index]->name); | 1100 | pr_debug("release set %s\n", ip_set_list[index]->name); |
1094 | ip_set_put_byindex(index); | 1101 | ip_set_put_byindex(index); |
1095 | } | 1102 | } |
1096 | |||
1097 | /* If we dump all sets, continue with dumping last ones */ | ||
1098 | if (cb->args[0] == DUMP_ALL && cb->args[1] >= max && !cb->args[2]) | ||
1099 | cb->args[0] = DUMP_LAST; | ||
1100 | |||
1101 | out: | 1103 | out: |
1102 | if (nlh) { | 1104 | if (nlh) { |
1103 | nlmsg_end(skb, nlh); | 1105 | nlmsg_end(skb, nlh); |
@@ -1118,7 +1120,7 @@ ip_set_dump(struct sock *ctnl, struct sk_buff *skb, | |||
1118 | 1120 | ||
1119 | return netlink_dump_start(ctnl, skb, nlh, | 1121 | return netlink_dump_start(ctnl, skb, nlh, |
1120 | ip_set_dump_start, | 1122 | ip_set_dump_start, |
1121 | ip_set_dump_done); | 1123 | ip_set_dump_done, 0); |
1122 | } | 1124 | } |
1123 | 1125 | ||
1124 | /* Add, del and test */ | 1126 | /* Add, del and test */ |
diff --git a/net/netfilter/ipvs/ip_vs_app.c b/net/netfilter/ipvs/ip_vs_app.c index 2dc6de13ac18..059af3120be7 100644 --- a/net/netfilter/ipvs/ip_vs_app.c +++ b/net/netfilter/ipvs/ip_vs_app.c | |||
@@ -572,11 +572,11 @@ static const struct file_operations ip_vs_app_fops = { | |||
572 | .open = ip_vs_app_open, | 572 | .open = ip_vs_app_open, |
573 | .read = seq_read, | 573 | .read = seq_read, |
574 | .llseek = seq_lseek, | 574 | .llseek = seq_lseek, |
575 | .release = seq_release, | 575 | .release = seq_release_net, |
576 | }; | 576 | }; |
577 | #endif | 577 | #endif |
578 | 578 | ||
579 | static int __net_init __ip_vs_app_init(struct net *net) | 579 | int __net_init __ip_vs_app_init(struct net *net) |
580 | { | 580 | { |
581 | struct netns_ipvs *ipvs = net_ipvs(net); | 581 | struct netns_ipvs *ipvs = net_ipvs(net); |
582 | 582 | ||
@@ -585,26 +585,17 @@ static int __net_init __ip_vs_app_init(struct net *net) | |||
585 | return 0; | 585 | return 0; |
586 | } | 586 | } |
587 | 587 | ||
588 | static void __net_exit __ip_vs_app_cleanup(struct net *net) | 588 | void __net_exit __ip_vs_app_cleanup(struct net *net) |
589 | { | 589 | { |
590 | proc_net_remove(net, "ip_vs_app"); | 590 | proc_net_remove(net, "ip_vs_app"); |
591 | } | 591 | } |
592 | 592 | ||
593 | static struct pernet_operations ip_vs_app_ops = { | ||
594 | .init = __ip_vs_app_init, | ||
595 | .exit = __ip_vs_app_cleanup, | ||
596 | }; | ||
597 | |||
598 | int __init ip_vs_app_init(void) | 593 | int __init ip_vs_app_init(void) |
599 | { | 594 | { |
600 | int rv; | 595 | return 0; |
601 | |||
602 | rv = register_pernet_subsys(&ip_vs_app_ops); | ||
603 | return rv; | ||
604 | } | 596 | } |
605 | 597 | ||
606 | 598 | ||
607 | void ip_vs_app_cleanup(void) | 599 | void ip_vs_app_cleanup(void) |
608 | { | 600 | { |
609 | unregister_pernet_subsys(&ip_vs_app_ops); | ||
610 | } | 601 | } |
diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c index c97bd45975be..bf28ac2fc99b 100644 --- a/net/netfilter/ipvs/ip_vs_conn.c +++ b/net/netfilter/ipvs/ip_vs_conn.c | |||
@@ -1046,7 +1046,7 @@ static const struct file_operations ip_vs_conn_fops = { | |||
1046 | .open = ip_vs_conn_open, | 1046 | .open = ip_vs_conn_open, |
1047 | .read = seq_read, | 1047 | .read = seq_read, |
1048 | .llseek = seq_lseek, | 1048 | .llseek = seq_lseek, |
1049 | .release = seq_release, | 1049 | .release = seq_release_net, |
1050 | }; | 1050 | }; |
1051 | 1051 | ||
1052 | static const char *ip_vs_origin_name(unsigned flags) | 1052 | static const char *ip_vs_origin_name(unsigned flags) |
@@ -1114,7 +1114,7 @@ static const struct file_operations ip_vs_conn_sync_fops = { | |||
1114 | .open = ip_vs_conn_sync_open, | 1114 | .open = ip_vs_conn_sync_open, |
1115 | .read = seq_read, | 1115 | .read = seq_read, |
1116 | .llseek = seq_lseek, | 1116 | .llseek = seq_lseek, |
1117 | .release = seq_release, | 1117 | .release = seq_release_net, |
1118 | }; | 1118 | }; |
1119 | 1119 | ||
1120 | #endif | 1120 | #endif |
@@ -1258,22 +1258,17 @@ int __net_init __ip_vs_conn_init(struct net *net) | |||
1258 | return 0; | 1258 | return 0; |
1259 | } | 1259 | } |
1260 | 1260 | ||
1261 | static void __net_exit __ip_vs_conn_cleanup(struct net *net) | 1261 | void __net_exit __ip_vs_conn_cleanup(struct net *net) |
1262 | { | 1262 | { |
1263 | /* flush all the connection entries first */ | 1263 | /* flush all the connection entries first */ |
1264 | ip_vs_conn_flush(net); | 1264 | ip_vs_conn_flush(net); |
1265 | proc_net_remove(net, "ip_vs_conn"); | 1265 | proc_net_remove(net, "ip_vs_conn"); |
1266 | proc_net_remove(net, "ip_vs_conn_sync"); | 1266 | proc_net_remove(net, "ip_vs_conn_sync"); |
1267 | } | 1267 | } |
1268 | static struct pernet_operations ipvs_conn_ops = { | ||
1269 | .init = __ip_vs_conn_init, | ||
1270 | .exit = __ip_vs_conn_cleanup, | ||
1271 | }; | ||
1272 | 1268 | ||
1273 | int __init ip_vs_conn_init(void) | 1269 | int __init ip_vs_conn_init(void) |
1274 | { | 1270 | { |
1275 | int idx; | 1271 | int idx; |
1276 | int retc; | ||
1277 | 1272 | ||
1278 | /* Compute size and mask */ | 1273 | /* Compute size and mask */ |
1279 | ip_vs_conn_tab_size = 1 << ip_vs_conn_tab_bits; | 1274 | ip_vs_conn_tab_size = 1 << ip_vs_conn_tab_bits; |
@@ -1309,17 +1304,14 @@ int __init ip_vs_conn_init(void) | |||
1309 | rwlock_init(&__ip_vs_conntbl_lock_array[idx].l); | 1304 | rwlock_init(&__ip_vs_conntbl_lock_array[idx].l); |
1310 | } | 1305 | } |
1311 | 1306 | ||
1312 | retc = register_pernet_subsys(&ipvs_conn_ops); | ||
1313 | |||
1314 | /* calculate the random value for connection hash */ | 1307 | /* calculate the random value for connection hash */ |
1315 | get_random_bytes(&ip_vs_conn_rnd, sizeof(ip_vs_conn_rnd)); | 1308 | get_random_bytes(&ip_vs_conn_rnd, sizeof(ip_vs_conn_rnd)); |
1316 | 1309 | ||
1317 | return retc; | 1310 | return 0; |
1318 | } | 1311 | } |
1319 | 1312 | ||
1320 | void ip_vs_conn_cleanup(void) | 1313 | void ip_vs_conn_cleanup(void) |
1321 | { | 1314 | { |
1322 | unregister_pernet_subsys(&ipvs_conn_ops); | ||
1323 | /* Release the empty cache */ | 1315 | /* Release the empty cache */ |
1324 | kmem_cache_destroy(ip_vs_conn_cachep); | 1316 | kmem_cache_destroy(ip_vs_conn_cachep); |
1325 | vfree(ip_vs_conn_tab); | 1317 | vfree(ip_vs_conn_tab); |
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index 07accf6b2401..bfa808f4da13 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c | |||
@@ -1113,6 +1113,9 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af) | |||
1113 | return NF_ACCEPT; | 1113 | return NF_ACCEPT; |
1114 | 1114 | ||
1115 | net = skb_net(skb); | 1115 | net = skb_net(skb); |
1116 | if (!net_ipvs(net)->enable) | ||
1117 | return NF_ACCEPT; | ||
1118 | |||
1116 | ip_vs_fill_iphdr(af, skb_network_header(skb), &iph); | 1119 | ip_vs_fill_iphdr(af, skb_network_header(skb), &iph); |
1117 | #ifdef CONFIG_IP_VS_IPV6 | 1120 | #ifdef CONFIG_IP_VS_IPV6 |
1118 | if (af == AF_INET6) { | 1121 | if (af == AF_INET6) { |
@@ -1343,6 +1346,7 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum) | |||
1343 | return NF_ACCEPT; /* The packet looks wrong, ignore */ | 1346 | return NF_ACCEPT; /* The packet looks wrong, ignore */ |
1344 | 1347 | ||
1345 | net = skb_net(skb); | 1348 | net = skb_net(skb); |
1349 | |||
1346 | pd = ip_vs_proto_data_get(net, cih->protocol); | 1350 | pd = ip_vs_proto_data_get(net, cih->protocol); |
1347 | if (!pd) | 1351 | if (!pd) |
1348 | return NF_ACCEPT; | 1352 | return NF_ACCEPT; |
@@ -1378,15 +1382,7 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum) | |||
1378 | ip_vs_in_stats(cp, skb); | 1382 | ip_vs_in_stats(cp, skb); |
1379 | if (IPPROTO_TCP == cih->protocol || IPPROTO_UDP == cih->protocol) | 1383 | if (IPPROTO_TCP == cih->protocol || IPPROTO_UDP == cih->protocol) |
1380 | offset += 2 * sizeof(__u16); | 1384 | offset += 2 * sizeof(__u16); |
1381 | verdict = ip_vs_icmp_xmit(skb, cp, pp, offset); | 1385 | verdict = ip_vs_icmp_xmit(skb, cp, pp, offset, hooknum); |
1382 | /* LOCALNODE from FORWARD hook is not supported */ | ||
1383 | if (verdict == NF_ACCEPT && hooknum == NF_INET_FORWARD && | ||
1384 | skb_rtable(skb)->rt_flags & RTCF_LOCAL) { | ||
1385 | IP_VS_DBG(1, "%s(): " | ||
1386 | "local delivery to %pI4 but in FORWARD\n", | ||
1387 | __func__, &skb_rtable(skb)->rt_dst); | ||
1388 | verdict = NF_DROP; | ||
1389 | } | ||
1390 | 1386 | ||
1391 | out: | 1387 | out: |
1392 | __ip_vs_conn_put(cp); | 1388 | __ip_vs_conn_put(cp); |
@@ -1408,7 +1404,6 @@ ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, unsigned int hooknum) | |||
1408 | struct ip_vs_protocol *pp; | 1404 | struct ip_vs_protocol *pp; |
1409 | struct ip_vs_proto_data *pd; | 1405 | struct ip_vs_proto_data *pd; |
1410 | unsigned int offset, verdict; | 1406 | unsigned int offset, verdict; |
1411 | struct rt6_info *rt; | ||
1412 | 1407 | ||
1413 | *related = 1; | 1408 | *related = 1; |
1414 | 1409 | ||
@@ -1470,23 +1465,12 @@ ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, unsigned int hooknum) | |||
1470 | if (!cp) | 1465 | if (!cp) |
1471 | return NF_ACCEPT; | 1466 | return NF_ACCEPT; |
1472 | 1467 | ||
1473 | verdict = NF_DROP; | ||
1474 | |||
1475 | /* do the statistics and put it back */ | 1468 | /* do the statistics and put it back */ |
1476 | ip_vs_in_stats(cp, skb); | 1469 | ip_vs_in_stats(cp, skb); |
1477 | if (IPPROTO_TCP == cih->nexthdr || IPPROTO_UDP == cih->nexthdr || | 1470 | if (IPPROTO_TCP == cih->nexthdr || IPPROTO_UDP == cih->nexthdr || |
1478 | IPPROTO_SCTP == cih->nexthdr) | 1471 | IPPROTO_SCTP == cih->nexthdr) |
1479 | offset += 2 * sizeof(__u16); | 1472 | offset += 2 * sizeof(__u16); |
1480 | verdict = ip_vs_icmp_xmit_v6(skb, cp, pp, offset); | 1473 | verdict = ip_vs_icmp_xmit_v6(skb, cp, pp, offset, hooknum); |
1481 | /* LOCALNODE from FORWARD hook is not supported */ | ||
1482 | if (verdict == NF_ACCEPT && hooknum == NF_INET_FORWARD && | ||
1483 | (rt = (struct rt6_info *) skb_dst(skb)) && | ||
1484 | rt->rt6i_dev && rt->rt6i_dev->flags & IFF_LOOPBACK) { | ||
1485 | IP_VS_DBG(1, "%s(): " | ||
1486 | "local delivery to %pI6 but in FORWARD\n", | ||
1487 | __func__, &rt->rt6i_dst); | ||
1488 | verdict = NF_DROP; | ||
1489 | } | ||
1490 | 1474 | ||
1491 | __ip_vs_conn_put(cp); | 1475 | __ip_vs_conn_put(cp); |
1492 | 1476 | ||
@@ -1529,6 +1513,11 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) | |||
1529 | IP_VS_DBG_ADDR(af, &iph.daddr), hooknum); | 1513 | IP_VS_DBG_ADDR(af, &iph.daddr), hooknum); |
1530 | return NF_ACCEPT; | 1514 | return NF_ACCEPT; |
1531 | } | 1515 | } |
1516 | /* ipvs enabled in this netns ? */ | ||
1517 | net = skb_net(skb); | ||
1518 | if (!net_ipvs(net)->enable) | ||
1519 | return NF_ACCEPT; | ||
1520 | |||
1532 | ip_vs_fill_iphdr(af, skb_network_header(skb), &iph); | 1521 | ip_vs_fill_iphdr(af, skb_network_header(skb), &iph); |
1533 | 1522 | ||
1534 | /* Bad... Do not break raw sockets */ | 1523 | /* Bad... Do not break raw sockets */ |
@@ -1562,7 +1551,6 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) | |||
1562 | ip_vs_fill_iphdr(af, skb_network_header(skb), &iph); | 1551 | ip_vs_fill_iphdr(af, skb_network_header(skb), &iph); |
1563 | } | 1552 | } |
1564 | 1553 | ||
1565 | net = skb_net(skb); | ||
1566 | /* Protocol supported? */ | 1554 | /* Protocol supported? */ |
1567 | pd = ip_vs_proto_data_get(net, iph.protocol); | 1555 | pd = ip_vs_proto_data_get(net, iph.protocol); |
1568 | if (unlikely(!pd)) | 1556 | if (unlikely(!pd)) |
@@ -1588,7 +1576,6 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) | |||
1588 | } | 1576 | } |
1589 | 1577 | ||
1590 | IP_VS_DBG_PKT(11, af, pp, skb, 0, "Incoming packet"); | 1578 | IP_VS_DBG_PKT(11, af, pp, skb, 0, "Incoming packet"); |
1591 | net = skb_net(skb); | ||
1592 | ipvs = net_ipvs(net); | 1579 | ipvs = net_ipvs(net); |
1593 | /* Check the server status */ | 1580 | /* Check the server status */ |
1594 | if (cp->dest && !(cp->dest->flags & IP_VS_DEST_F_AVAILABLE)) { | 1581 | if (cp->dest && !(cp->dest->flags & IP_VS_DEST_F_AVAILABLE)) { |
@@ -1743,10 +1730,16 @@ ip_vs_forward_icmp(unsigned int hooknum, struct sk_buff *skb, | |||
1743 | int (*okfn)(struct sk_buff *)) | 1730 | int (*okfn)(struct sk_buff *)) |
1744 | { | 1731 | { |
1745 | int r; | 1732 | int r; |
1733 | struct net *net; | ||
1746 | 1734 | ||
1747 | if (ip_hdr(skb)->protocol != IPPROTO_ICMP) | 1735 | if (ip_hdr(skb)->protocol != IPPROTO_ICMP) |
1748 | return NF_ACCEPT; | 1736 | return NF_ACCEPT; |
1749 | 1737 | ||
1738 | /* ipvs enabled in this netns ? */ | ||
1739 | net = skb_net(skb); | ||
1740 | if (!net_ipvs(net)->enable) | ||
1741 | return NF_ACCEPT; | ||
1742 | |||
1750 | return ip_vs_in_icmp(skb, &r, hooknum); | 1743 | return ip_vs_in_icmp(skb, &r, hooknum); |
1751 | } | 1744 | } |
1752 | 1745 | ||
@@ -1757,10 +1750,16 @@ ip_vs_forward_icmp_v6(unsigned int hooknum, struct sk_buff *skb, | |||
1757 | int (*okfn)(struct sk_buff *)) | 1750 | int (*okfn)(struct sk_buff *)) |
1758 | { | 1751 | { |
1759 | int r; | 1752 | int r; |
1753 | struct net *net; | ||
1760 | 1754 | ||
1761 | if (ipv6_hdr(skb)->nexthdr != IPPROTO_ICMPV6) | 1755 | if (ipv6_hdr(skb)->nexthdr != IPPROTO_ICMPV6) |
1762 | return NF_ACCEPT; | 1756 | return NF_ACCEPT; |
1763 | 1757 | ||
1758 | /* ipvs enabled in this netns ? */ | ||
1759 | net = skb_net(skb); | ||
1760 | if (!net_ipvs(net)->enable) | ||
1761 | return NF_ACCEPT; | ||
1762 | |||
1764 | return ip_vs_in_icmp_v6(skb, &r, hooknum); | 1763 | return ip_vs_in_icmp_v6(skb, &r, hooknum); |
1765 | } | 1764 | } |
1766 | #endif | 1765 | #endif |
@@ -1884,19 +1883,70 @@ static int __net_init __ip_vs_init(struct net *net) | |||
1884 | pr_err("%s(): no memory.\n", __func__); | 1883 | pr_err("%s(): no memory.\n", __func__); |
1885 | return -ENOMEM; | 1884 | return -ENOMEM; |
1886 | } | 1885 | } |
1886 | /* Hold the beast until a service is registerd */ | ||
1887 | ipvs->enable = 0; | ||
1887 | ipvs->net = net; | 1888 | ipvs->net = net; |
1888 | /* Counters used for creating unique names */ | 1889 | /* Counters used for creating unique names */ |
1889 | ipvs->gen = atomic_read(&ipvs_netns_cnt); | 1890 | ipvs->gen = atomic_read(&ipvs_netns_cnt); |
1890 | atomic_inc(&ipvs_netns_cnt); | 1891 | atomic_inc(&ipvs_netns_cnt); |
1891 | net->ipvs = ipvs; | 1892 | net->ipvs = ipvs; |
1893 | |||
1894 | if (__ip_vs_estimator_init(net) < 0) | ||
1895 | goto estimator_fail; | ||
1896 | |||
1897 | if (__ip_vs_control_init(net) < 0) | ||
1898 | goto control_fail; | ||
1899 | |||
1900 | if (__ip_vs_protocol_init(net) < 0) | ||
1901 | goto protocol_fail; | ||
1902 | |||
1903 | if (__ip_vs_app_init(net) < 0) | ||
1904 | goto app_fail; | ||
1905 | |||
1906 | if (__ip_vs_conn_init(net) < 0) | ||
1907 | goto conn_fail; | ||
1908 | |||
1909 | if (__ip_vs_sync_init(net) < 0) | ||
1910 | goto sync_fail; | ||
1911 | |||
1892 | printk(KERN_INFO "IPVS: Creating netns size=%zu id=%d\n", | 1912 | printk(KERN_INFO "IPVS: Creating netns size=%zu id=%d\n", |
1893 | sizeof(struct netns_ipvs), ipvs->gen); | 1913 | sizeof(struct netns_ipvs), ipvs->gen); |
1894 | return 0; | 1914 | return 0; |
1915 | /* | ||
1916 | * Error handling | ||
1917 | */ | ||
1918 | |||
1919 | sync_fail: | ||
1920 | __ip_vs_conn_cleanup(net); | ||
1921 | conn_fail: | ||
1922 | __ip_vs_app_cleanup(net); | ||
1923 | app_fail: | ||
1924 | __ip_vs_protocol_cleanup(net); | ||
1925 | protocol_fail: | ||
1926 | __ip_vs_control_cleanup(net); | ||
1927 | control_fail: | ||
1928 | __ip_vs_estimator_cleanup(net); | ||
1929 | estimator_fail: | ||
1930 | return -ENOMEM; | ||
1895 | } | 1931 | } |
1896 | 1932 | ||
1897 | static void __net_exit __ip_vs_cleanup(struct net *net) | 1933 | static void __net_exit __ip_vs_cleanup(struct net *net) |
1898 | { | 1934 | { |
1899 | IP_VS_DBG(10, "ipvs netns %d released\n", net_ipvs(net)->gen); | 1935 | __ip_vs_service_cleanup(net); /* ip_vs_flush() with locks */ |
1936 | __ip_vs_conn_cleanup(net); | ||
1937 | __ip_vs_app_cleanup(net); | ||
1938 | __ip_vs_protocol_cleanup(net); | ||
1939 | __ip_vs_control_cleanup(net); | ||
1940 | __ip_vs_estimator_cleanup(net); | ||
1941 | IP_VS_DBG(2, "ipvs netns %d released\n", net_ipvs(net)->gen); | ||
1942 | } | ||
1943 | |||
1944 | static void __net_exit __ip_vs_dev_cleanup(struct net *net) | ||
1945 | { | ||
1946 | EnterFunction(2); | ||
1947 | net_ipvs(net)->enable = 0; /* Disable packet reception */ | ||
1948 | __ip_vs_sync_cleanup(net); | ||
1949 | LeaveFunction(2); | ||
1900 | } | 1950 | } |
1901 | 1951 | ||
1902 | static struct pernet_operations ipvs_core_ops = { | 1952 | static struct pernet_operations ipvs_core_ops = { |
@@ -1906,6 +1956,10 @@ static struct pernet_operations ipvs_core_ops = { | |||
1906 | .size = sizeof(struct netns_ipvs), | 1956 | .size = sizeof(struct netns_ipvs), |
1907 | }; | 1957 | }; |
1908 | 1958 | ||
1959 | static struct pernet_operations ipvs_core_dev_ops = { | ||
1960 | .exit = __ip_vs_dev_cleanup, | ||
1961 | }; | ||
1962 | |||
1909 | /* | 1963 | /* |
1910 | * Initialize IP Virtual Server | 1964 | * Initialize IP Virtual Server |
1911 | */ | 1965 | */ |
@@ -1913,10 +1967,6 @@ static int __init ip_vs_init(void) | |||
1913 | { | 1967 | { |
1914 | int ret; | 1968 | int ret; |
1915 | 1969 | ||
1916 | ret = register_pernet_subsys(&ipvs_core_ops); /* Alloc ip_vs struct */ | ||
1917 | if (ret < 0) | ||
1918 | return ret; | ||
1919 | |||
1920 | ip_vs_estimator_init(); | 1970 | ip_vs_estimator_init(); |
1921 | ret = ip_vs_control_init(); | 1971 | ret = ip_vs_control_init(); |
1922 | if (ret < 0) { | 1972 | if (ret < 0) { |
@@ -1944,15 +1994,28 @@ static int __init ip_vs_init(void) | |||
1944 | goto cleanup_conn; | 1994 | goto cleanup_conn; |
1945 | } | 1995 | } |
1946 | 1996 | ||
1997 | ret = register_pernet_subsys(&ipvs_core_ops); /* Alloc ip_vs struct */ | ||
1998 | if (ret < 0) | ||
1999 | goto cleanup_sync; | ||
2000 | |||
2001 | ret = register_pernet_device(&ipvs_core_dev_ops); | ||
2002 | if (ret < 0) | ||
2003 | goto cleanup_sub; | ||
2004 | |||
1947 | ret = nf_register_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops)); | 2005 | ret = nf_register_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops)); |
1948 | if (ret < 0) { | 2006 | if (ret < 0) { |
1949 | pr_err("can't register hooks.\n"); | 2007 | pr_err("can't register hooks.\n"); |
1950 | goto cleanup_sync; | 2008 | goto cleanup_dev; |
1951 | } | 2009 | } |
1952 | 2010 | ||
1953 | pr_info("ipvs loaded.\n"); | 2011 | pr_info("ipvs loaded.\n"); |
2012 | |||
1954 | return ret; | 2013 | return ret; |
1955 | 2014 | ||
2015 | cleanup_dev: | ||
2016 | unregister_pernet_device(&ipvs_core_dev_ops); | ||
2017 | cleanup_sub: | ||
2018 | unregister_pernet_subsys(&ipvs_core_ops); | ||
1956 | cleanup_sync: | 2019 | cleanup_sync: |
1957 | ip_vs_sync_cleanup(); | 2020 | ip_vs_sync_cleanup(); |
1958 | cleanup_conn: | 2021 | cleanup_conn: |
@@ -1964,20 +2027,20 @@ cleanup_sync: | |||
1964 | ip_vs_control_cleanup(); | 2027 | ip_vs_control_cleanup(); |
1965 | cleanup_estimator: | 2028 | cleanup_estimator: |
1966 | ip_vs_estimator_cleanup(); | 2029 | ip_vs_estimator_cleanup(); |
1967 | unregister_pernet_subsys(&ipvs_core_ops); /* free ip_vs struct */ | ||
1968 | return ret; | 2030 | return ret; |
1969 | } | 2031 | } |
1970 | 2032 | ||
1971 | static void __exit ip_vs_cleanup(void) | 2033 | static void __exit ip_vs_cleanup(void) |
1972 | { | 2034 | { |
1973 | nf_unregister_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops)); | 2035 | nf_unregister_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops)); |
2036 | unregister_pernet_device(&ipvs_core_dev_ops); | ||
2037 | unregister_pernet_subsys(&ipvs_core_ops); /* free ip_vs struct */ | ||
1974 | ip_vs_sync_cleanup(); | 2038 | ip_vs_sync_cleanup(); |
1975 | ip_vs_conn_cleanup(); | 2039 | ip_vs_conn_cleanup(); |
1976 | ip_vs_app_cleanup(); | 2040 | ip_vs_app_cleanup(); |
1977 | ip_vs_protocol_cleanup(); | 2041 | ip_vs_protocol_cleanup(); |
1978 | ip_vs_control_cleanup(); | 2042 | ip_vs_control_cleanup(); |
1979 | ip_vs_estimator_cleanup(); | 2043 | ip_vs_estimator_cleanup(); |
1980 | unregister_pernet_subsys(&ipvs_core_ops); /* free ip_vs struct */ | ||
1981 | pr_info("ipvs unloaded.\n"); | 2044 | pr_info("ipvs unloaded.\n"); |
1982 | } | 2045 | } |
1983 | 2046 | ||
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 9930f340908a..699c79a55657 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c | |||
@@ -69,6 +69,11 @@ int ip_vs_get_debug_level(void) | |||
69 | } | 69 | } |
70 | #endif | 70 | #endif |
71 | 71 | ||
72 | |||
73 | /* Protos */ | ||
74 | static void __ip_vs_del_service(struct ip_vs_service *svc); | ||
75 | |||
76 | |||
72 | #ifdef CONFIG_IP_VS_IPV6 | 77 | #ifdef CONFIG_IP_VS_IPV6 |
73 | /* Taken from rt6_fill_node() in net/ipv6/route.c, is there a better way? */ | 78 | /* Taken from rt6_fill_node() in net/ipv6/route.c, is there a better way? */ |
74 | static int __ip_vs_addr_is_local_v6(struct net *net, | 79 | static int __ip_vs_addr_is_local_v6(struct net *net, |
@@ -1214,6 +1219,8 @@ ip_vs_add_service(struct net *net, struct ip_vs_service_user_kern *u, | |||
1214 | write_unlock_bh(&__ip_vs_svc_lock); | 1219 | write_unlock_bh(&__ip_vs_svc_lock); |
1215 | 1220 | ||
1216 | *svc_p = svc; | 1221 | *svc_p = svc; |
1222 | /* Now there is a service - full throttle */ | ||
1223 | ipvs->enable = 1; | ||
1217 | return 0; | 1224 | return 0; |
1218 | 1225 | ||
1219 | 1226 | ||
@@ -1472,6 +1479,84 @@ static int ip_vs_flush(struct net *net) | |||
1472 | return 0; | 1479 | return 0; |
1473 | } | 1480 | } |
1474 | 1481 | ||
1482 | /* | ||
1483 | * Delete service by {netns} in the service table. | ||
1484 | * Called by __ip_vs_cleanup() | ||
1485 | */ | ||
1486 | void __ip_vs_service_cleanup(struct net *net) | ||
1487 | { | ||
1488 | EnterFunction(2); | ||
1489 | /* Check for "full" addressed entries */ | ||
1490 | mutex_lock(&__ip_vs_mutex); | ||
1491 | ip_vs_flush(net); | ||
1492 | mutex_unlock(&__ip_vs_mutex); | ||
1493 | LeaveFunction(2); | ||
1494 | } | ||
1495 | /* | ||
1496 | * Release dst hold by dst_cache | ||
1497 | */ | ||
1498 | static inline void | ||
1499 | __ip_vs_dev_reset(struct ip_vs_dest *dest, struct net_device *dev) | ||
1500 | { | ||
1501 | spin_lock_bh(&dest->dst_lock); | ||
1502 | if (dest->dst_cache && dest->dst_cache->dev == dev) { | ||
1503 | IP_VS_DBG_BUF(3, "Reset dev:%s dest %s:%u ,dest->refcnt=%d\n", | ||
1504 | dev->name, | ||
1505 | IP_VS_DBG_ADDR(dest->af, &dest->addr), | ||
1506 | ntohs(dest->port), | ||
1507 | atomic_read(&dest->refcnt)); | ||
1508 | ip_vs_dst_reset(dest); | ||
1509 | } | ||
1510 | spin_unlock_bh(&dest->dst_lock); | ||
1511 | |||
1512 | } | ||
1513 | /* | ||
1514 | * Netdev event receiver | ||
1515 | * Currently only NETDEV_UNREGISTER is handled, i.e. if we hold a reference to | ||
1516 | * a device that is "unregister" it must be released. | ||
1517 | */ | ||
1518 | static int ip_vs_dst_event(struct notifier_block *this, unsigned long event, | ||
1519 | void *ptr) | ||
1520 | { | ||
1521 | struct net_device *dev = ptr; | ||
1522 | struct net *net = dev_net(dev); | ||
1523 | struct ip_vs_service *svc; | ||
1524 | struct ip_vs_dest *dest; | ||
1525 | unsigned int idx; | ||
1526 | |||
1527 | if (event != NETDEV_UNREGISTER) | ||
1528 | return NOTIFY_DONE; | ||
1529 | IP_VS_DBG(3, "%s() dev=%s\n", __func__, dev->name); | ||
1530 | EnterFunction(2); | ||
1531 | mutex_lock(&__ip_vs_mutex); | ||
1532 | for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) { | ||
1533 | list_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) { | ||
1534 | if (net_eq(svc->net, net)) { | ||
1535 | list_for_each_entry(dest, &svc->destinations, | ||
1536 | n_list) { | ||
1537 | __ip_vs_dev_reset(dest, dev); | ||
1538 | } | ||
1539 | } | ||
1540 | } | ||
1541 | |||
1542 | list_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) { | ||
1543 | if (net_eq(svc->net, net)) { | ||
1544 | list_for_each_entry(dest, &svc->destinations, | ||
1545 | n_list) { | ||
1546 | __ip_vs_dev_reset(dest, dev); | ||
1547 | } | ||
1548 | } | ||
1549 | |||
1550 | } | ||
1551 | } | ||
1552 | |||
1553 | list_for_each_entry(dest, &net_ipvs(net)->dest_trash, n_list) { | ||
1554 | __ip_vs_dev_reset(dest, dev); | ||
1555 | } | ||
1556 | mutex_unlock(&__ip_vs_mutex); | ||
1557 | LeaveFunction(2); | ||
1558 | return NOTIFY_DONE; | ||
1559 | } | ||
1475 | 1560 | ||
1476 | /* | 1561 | /* |
1477 | * Zero counters in a service or all services | 1562 | * Zero counters in a service or all services |
@@ -1981,7 +2066,7 @@ static const struct file_operations ip_vs_info_fops = { | |||
1981 | .open = ip_vs_info_open, | 2066 | .open = ip_vs_info_open, |
1982 | .read = seq_read, | 2067 | .read = seq_read, |
1983 | .llseek = seq_lseek, | 2068 | .llseek = seq_lseek, |
1984 | .release = seq_release_private, | 2069 | .release = seq_release_net, |
1985 | }; | 2070 | }; |
1986 | 2071 | ||
1987 | static int ip_vs_stats_show(struct seq_file *seq, void *v) | 2072 | static int ip_vs_stats_show(struct seq_file *seq, void *v) |
@@ -2021,7 +2106,7 @@ static const struct file_operations ip_vs_stats_fops = { | |||
2021 | .open = ip_vs_stats_seq_open, | 2106 | .open = ip_vs_stats_seq_open, |
2022 | .read = seq_read, | 2107 | .read = seq_read, |
2023 | .llseek = seq_lseek, | 2108 | .llseek = seq_lseek, |
2024 | .release = single_release, | 2109 | .release = single_release_net, |
2025 | }; | 2110 | }; |
2026 | 2111 | ||
2027 | static int ip_vs_stats_percpu_show(struct seq_file *seq, void *v) | 2112 | static int ip_vs_stats_percpu_show(struct seq_file *seq, void *v) |
@@ -2090,7 +2175,7 @@ static const struct file_operations ip_vs_stats_percpu_fops = { | |||
2090 | .open = ip_vs_stats_percpu_seq_open, | 2175 | .open = ip_vs_stats_percpu_seq_open, |
2091 | .read = seq_read, | 2176 | .read = seq_read, |
2092 | .llseek = seq_lseek, | 2177 | .llseek = seq_lseek, |
2093 | .release = single_release, | 2178 | .release = single_release_net, |
2094 | }; | 2179 | }; |
2095 | #endif | 2180 | #endif |
2096 | 2181 | ||
@@ -3585,6 +3670,10 @@ void __net_init __ip_vs_control_cleanup_sysctl(struct net *net) { } | |||
3585 | 3670 | ||
3586 | #endif | 3671 | #endif |
3587 | 3672 | ||
3673 | static struct notifier_block ip_vs_dst_notifier = { | ||
3674 | .notifier_call = ip_vs_dst_event, | ||
3675 | }; | ||
3676 | |||
3588 | int __net_init __ip_vs_control_init(struct net *net) | 3677 | int __net_init __ip_vs_control_init(struct net *net) |
3589 | { | 3678 | { |
3590 | int idx; | 3679 | int idx; |
@@ -3623,7 +3712,7 @@ err: | |||
3623 | return -ENOMEM; | 3712 | return -ENOMEM; |
3624 | } | 3713 | } |
3625 | 3714 | ||
3626 | static void __net_exit __ip_vs_control_cleanup(struct net *net) | 3715 | void __net_exit __ip_vs_control_cleanup(struct net *net) |
3627 | { | 3716 | { |
3628 | struct netns_ipvs *ipvs = net_ipvs(net); | 3717 | struct netns_ipvs *ipvs = net_ipvs(net); |
3629 | 3718 | ||
@@ -3636,11 +3725,6 @@ static void __net_exit __ip_vs_control_cleanup(struct net *net) | |||
3636 | free_percpu(ipvs->tot_stats.cpustats); | 3725 | free_percpu(ipvs->tot_stats.cpustats); |
3637 | } | 3726 | } |
3638 | 3727 | ||
3639 | static struct pernet_operations ipvs_control_ops = { | ||
3640 | .init = __ip_vs_control_init, | ||
3641 | .exit = __ip_vs_control_cleanup, | ||
3642 | }; | ||
3643 | |||
3644 | int __init ip_vs_control_init(void) | 3728 | int __init ip_vs_control_init(void) |
3645 | { | 3729 | { |
3646 | int idx; | 3730 | int idx; |
@@ -3654,33 +3738,32 @@ int __init ip_vs_control_init(void) | |||
3654 | INIT_LIST_HEAD(&ip_vs_svc_fwm_table[idx]); | 3738 | INIT_LIST_HEAD(&ip_vs_svc_fwm_table[idx]); |
3655 | } | 3739 | } |
3656 | 3740 | ||
3657 | ret = register_pernet_subsys(&ipvs_control_ops); | ||
3658 | if (ret) { | ||
3659 | pr_err("cannot register namespace.\n"); | ||
3660 | goto err; | ||
3661 | } | ||
3662 | |||
3663 | smp_wmb(); /* Do we really need it now ? */ | 3741 | smp_wmb(); /* Do we really need it now ? */ |
3664 | 3742 | ||
3665 | ret = nf_register_sockopt(&ip_vs_sockopts); | 3743 | ret = nf_register_sockopt(&ip_vs_sockopts); |
3666 | if (ret) { | 3744 | if (ret) { |
3667 | pr_err("cannot register sockopt.\n"); | 3745 | pr_err("cannot register sockopt.\n"); |
3668 | goto err_net; | 3746 | goto err_sock; |
3669 | } | 3747 | } |
3670 | 3748 | ||
3671 | ret = ip_vs_genl_register(); | 3749 | ret = ip_vs_genl_register(); |
3672 | if (ret) { | 3750 | if (ret) { |
3673 | pr_err("cannot register Generic Netlink interface.\n"); | 3751 | pr_err("cannot register Generic Netlink interface.\n"); |
3674 | nf_unregister_sockopt(&ip_vs_sockopts); | 3752 | goto err_genl; |
3675 | goto err_net; | ||
3676 | } | 3753 | } |
3677 | 3754 | ||
3755 | ret = register_netdevice_notifier(&ip_vs_dst_notifier); | ||
3756 | if (ret < 0) | ||
3757 | goto err_notf; | ||
3758 | |||
3678 | LeaveFunction(2); | 3759 | LeaveFunction(2); |
3679 | return 0; | 3760 | return 0; |
3680 | 3761 | ||
3681 | err_net: | 3762 | err_notf: |
3682 | unregister_pernet_subsys(&ipvs_control_ops); | 3763 | ip_vs_genl_unregister(); |
3683 | err: | 3764 | err_genl: |
3765 | nf_unregister_sockopt(&ip_vs_sockopts); | ||
3766 | err_sock: | ||
3684 | return ret; | 3767 | return ret; |
3685 | } | 3768 | } |
3686 | 3769 | ||
@@ -3688,7 +3771,6 @@ err: | |||
3688 | void ip_vs_control_cleanup(void) | 3771 | void ip_vs_control_cleanup(void) |
3689 | { | 3772 | { |
3690 | EnterFunction(2); | 3773 | EnterFunction(2); |
3691 | unregister_pernet_subsys(&ipvs_control_ops); | ||
3692 | ip_vs_genl_unregister(); | 3774 | ip_vs_genl_unregister(); |
3693 | nf_unregister_sockopt(&ip_vs_sockopts); | 3775 | nf_unregister_sockopt(&ip_vs_sockopts); |
3694 | LeaveFunction(2); | 3776 | LeaveFunction(2); |
diff --git a/net/netfilter/ipvs/ip_vs_est.c b/net/netfilter/ipvs/ip_vs_est.c index 8c8766ca56ad..508cce98777c 100644 --- a/net/netfilter/ipvs/ip_vs_est.c +++ b/net/netfilter/ipvs/ip_vs_est.c | |||
@@ -192,7 +192,7 @@ void ip_vs_read_estimator(struct ip_vs_stats_user *dst, | |||
192 | dst->outbps = (e->outbps + 0xF) >> 5; | 192 | dst->outbps = (e->outbps + 0xF) >> 5; |
193 | } | 193 | } |
194 | 194 | ||
195 | static int __net_init __ip_vs_estimator_init(struct net *net) | 195 | int __net_init __ip_vs_estimator_init(struct net *net) |
196 | { | 196 | { |
197 | struct netns_ipvs *ipvs = net_ipvs(net); | 197 | struct netns_ipvs *ipvs = net_ipvs(net); |
198 | 198 | ||
@@ -203,24 +203,16 @@ static int __net_init __ip_vs_estimator_init(struct net *net) | |||
203 | return 0; | 203 | return 0; |
204 | } | 204 | } |
205 | 205 | ||
206 | static void __net_exit __ip_vs_estimator_exit(struct net *net) | 206 | void __net_exit __ip_vs_estimator_cleanup(struct net *net) |
207 | { | 207 | { |
208 | del_timer_sync(&net_ipvs(net)->est_timer); | 208 | del_timer_sync(&net_ipvs(net)->est_timer); |
209 | } | 209 | } |
210 | static struct pernet_operations ip_vs_app_ops = { | ||
211 | .init = __ip_vs_estimator_init, | ||
212 | .exit = __ip_vs_estimator_exit, | ||
213 | }; | ||
214 | 210 | ||
215 | int __init ip_vs_estimator_init(void) | 211 | int __init ip_vs_estimator_init(void) |
216 | { | 212 | { |
217 | int rv; | 213 | return 0; |
218 | |||
219 | rv = register_pernet_subsys(&ip_vs_app_ops); | ||
220 | return rv; | ||
221 | } | 214 | } |
222 | 215 | ||
223 | void ip_vs_estimator_cleanup(void) | 216 | void ip_vs_estimator_cleanup(void) |
224 | { | 217 | { |
225 | unregister_pernet_subsys(&ip_vs_app_ops); | ||
226 | } | 218 | } |
diff --git a/net/netfilter/ipvs/ip_vs_ftp.c b/net/netfilter/ipvs/ip_vs_ftp.c index 6b5dd6ddaae9..af63553fa332 100644 --- a/net/netfilter/ipvs/ip_vs_ftp.c +++ b/net/netfilter/ipvs/ip_vs_ftp.c | |||
@@ -411,25 +411,35 @@ static struct ip_vs_app ip_vs_ftp = { | |||
411 | static int __net_init __ip_vs_ftp_init(struct net *net) | 411 | static int __net_init __ip_vs_ftp_init(struct net *net) |
412 | { | 412 | { |
413 | int i, ret; | 413 | int i, ret; |
414 | struct ip_vs_app *app = &ip_vs_ftp; | 414 | struct ip_vs_app *app; |
415 | struct netns_ipvs *ipvs = net_ipvs(net); | ||
416 | |||
417 | app = kmemdup(&ip_vs_ftp, sizeof(struct ip_vs_app), GFP_KERNEL); | ||
418 | if (!app) | ||
419 | return -ENOMEM; | ||
420 | INIT_LIST_HEAD(&app->a_list); | ||
421 | INIT_LIST_HEAD(&app->incs_list); | ||
422 | ipvs->ftp_app = app; | ||
415 | 423 | ||
416 | ret = register_ip_vs_app(net, app); | 424 | ret = register_ip_vs_app(net, app); |
417 | if (ret) | 425 | if (ret) |
418 | return ret; | 426 | goto err_exit; |
419 | 427 | ||
420 | for (i=0; i<IP_VS_APP_MAX_PORTS; i++) { | 428 | for (i=0; i<IP_VS_APP_MAX_PORTS; i++) { |
421 | if (!ports[i]) | 429 | if (!ports[i]) |
422 | continue; | 430 | continue; |
423 | ret = register_ip_vs_app_inc(net, app, app->protocol, ports[i]); | 431 | ret = register_ip_vs_app_inc(net, app, app->protocol, ports[i]); |
424 | if (ret) | 432 | if (ret) |
425 | break; | 433 | goto err_unreg; |
426 | pr_info("%s: loaded support on port[%d] = %d\n", | 434 | pr_info("%s: loaded support on port[%d] = %d\n", |
427 | app->name, i, ports[i]); | 435 | app->name, i, ports[i]); |
428 | } | 436 | } |
437 | return 0; | ||
429 | 438 | ||
430 | if (ret) | 439 | err_unreg: |
431 | unregister_ip_vs_app(net, app); | 440 | unregister_ip_vs_app(net, app); |
432 | 441 | err_exit: | |
442 | kfree(ipvs->ftp_app); | ||
433 | return ret; | 443 | return ret; |
434 | } | 444 | } |
435 | /* | 445 | /* |
@@ -437,9 +447,10 @@ static int __net_init __ip_vs_ftp_init(struct net *net) | |||
437 | */ | 447 | */ |
438 | static void __ip_vs_ftp_exit(struct net *net) | 448 | static void __ip_vs_ftp_exit(struct net *net) |
439 | { | 449 | { |
440 | struct ip_vs_app *app = &ip_vs_ftp; | 450 | struct netns_ipvs *ipvs = net_ipvs(net); |
441 | 451 | ||
442 | unregister_ip_vs_app(net, app); | 452 | unregister_ip_vs_app(net, ipvs->ftp_app); |
453 | kfree(ipvs->ftp_app); | ||
443 | } | 454 | } |
444 | 455 | ||
445 | static struct pernet_operations ip_vs_ftp_ops = { | 456 | static struct pernet_operations ip_vs_ftp_ops = { |
diff --git a/net/netfilter/ipvs/ip_vs_proto.c b/net/netfilter/ipvs/ip_vs_proto.c index 17484a4416ef..eb86028536fc 100644 --- a/net/netfilter/ipvs/ip_vs_proto.c +++ b/net/netfilter/ipvs/ip_vs_proto.c | |||
@@ -316,7 +316,7 @@ ip_vs_tcpudp_debug_packet(int af, struct ip_vs_protocol *pp, | |||
316 | /* | 316 | /* |
317 | * per network name-space init | 317 | * per network name-space init |
318 | */ | 318 | */ |
319 | static int __net_init __ip_vs_protocol_init(struct net *net) | 319 | int __net_init __ip_vs_protocol_init(struct net *net) |
320 | { | 320 | { |
321 | #ifdef CONFIG_IP_VS_PROTO_TCP | 321 | #ifdef CONFIG_IP_VS_PROTO_TCP |
322 | register_ip_vs_proto_netns(net, &ip_vs_protocol_tcp); | 322 | register_ip_vs_proto_netns(net, &ip_vs_protocol_tcp); |
@@ -336,7 +336,7 @@ static int __net_init __ip_vs_protocol_init(struct net *net) | |||
336 | return 0; | 336 | return 0; |
337 | } | 337 | } |
338 | 338 | ||
339 | static void __net_exit __ip_vs_protocol_cleanup(struct net *net) | 339 | void __net_exit __ip_vs_protocol_cleanup(struct net *net) |
340 | { | 340 | { |
341 | struct netns_ipvs *ipvs = net_ipvs(net); | 341 | struct netns_ipvs *ipvs = net_ipvs(net); |
342 | struct ip_vs_proto_data *pd; | 342 | struct ip_vs_proto_data *pd; |
@@ -349,11 +349,6 @@ static void __net_exit __ip_vs_protocol_cleanup(struct net *net) | |||
349 | } | 349 | } |
350 | } | 350 | } |
351 | 351 | ||
352 | static struct pernet_operations ipvs_proto_ops = { | ||
353 | .init = __ip_vs_protocol_init, | ||
354 | .exit = __ip_vs_protocol_cleanup, | ||
355 | }; | ||
356 | |||
357 | int __init ip_vs_protocol_init(void) | 352 | int __init ip_vs_protocol_init(void) |
358 | { | 353 | { |
359 | char protocols[64]; | 354 | char protocols[64]; |
@@ -382,7 +377,6 @@ int __init ip_vs_protocol_init(void) | |||
382 | REGISTER_PROTOCOL(&ip_vs_protocol_esp); | 377 | REGISTER_PROTOCOL(&ip_vs_protocol_esp); |
383 | #endif | 378 | #endif |
384 | pr_info("Registered protocols (%s)\n", &protocols[2]); | 379 | pr_info("Registered protocols (%s)\n", &protocols[2]); |
385 | return register_pernet_subsys(&ipvs_proto_ops); | ||
386 | 380 | ||
387 | return 0; | 381 | return 0; |
388 | } | 382 | } |
@@ -393,7 +387,6 @@ void ip_vs_protocol_cleanup(void) | |||
393 | struct ip_vs_protocol *pp; | 387 | struct ip_vs_protocol *pp; |
394 | int i; | 388 | int i; |
395 | 389 | ||
396 | unregister_pernet_subsys(&ipvs_proto_ops); | ||
397 | /* unregister all the ipvs protocols */ | 390 | /* unregister all the ipvs protocols */ |
398 | for (i = 0; i < IP_VS_PROTO_TAB_SIZE; i++) { | 391 | for (i = 0; i < IP_VS_PROTO_TAB_SIZE; i++) { |
399 | while ((pp = ip_vs_proto_table[i]) != NULL) | 392 | while ((pp = ip_vs_proto_table[i]) != NULL) |
diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c index 3e7961e85e9c..e292e5bddc70 100644 --- a/net/netfilter/ipvs/ip_vs_sync.c +++ b/net/netfilter/ipvs/ip_vs_sync.c | |||
@@ -1303,13 +1303,18 @@ static struct socket *make_send_sock(struct net *net) | |||
1303 | struct socket *sock; | 1303 | struct socket *sock; |
1304 | int result; | 1304 | int result; |
1305 | 1305 | ||
1306 | /* First create a socket */ | 1306 | /* First create a socket move it to right name space later */ |
1307 | result = __sock_create(net, PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock, 1); | 1307 | result = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock); |
1308 | if (result < 0) { | 1308 | if (result < 0) { |
1309 | pr_err("Error during creation of socket; terminating\n"); | 1309 | pr_err("Error during creation of socket; terminating\n"); |
1310 | return ERR_PTR(result); | 1310 | return ERR_PTR(result); |
1311 | } | 1311 | } |
1312 | 1312 | /* | |
1313 | * Kernel sockets that are a part of a namespace, should not | ||
1314 | * hold a reference to a namespace in order to allow to stop it. | ||
1315 | * After sk_change_net should be released using sk_release_kernel. | ||
1316 | */ | ||
1317 | sk_change_net(sock->sk, net); | ||
1313 | result = set_mcast_if(sock->sk, ipvs->master_mcast_ifn); | 1318 | result = set_mcast_if(sock->sk, ipvs->master_mcast_ifn); |
1314 | if (result < 0) { | 1319 | if (result < 0) { |
1315 | pr_err("Error setting outbound mcast interface\n"); | 1320 | pr_err("Error setting outbound mcast interface\n"); |
@@ -1334,8 +1339,8 @@ static struct socket *make_send_sock(struct net *net) | |||
1334 | 1339 | ||
1335 | return sock; | 1340 | return sock; |
1336 | 1341 | ||
1337 | error: | 1342 | error: |
1338 | sock_release(sock); | 1343 | sk_release_kernel(sock->sk); |
1339 | return ERR_PTR(result); | 1344 | return ERR_PTR(result); |
1340 | } | 1345 | } |
1341 | 1346 | ||
@@ -1350,12 +1355,17 @@ static struct socket *make_receive_sock(struct net *net) | |||
1350 | int result; | 1355 | int result; |
1351 | 1356 | ||
1352 | /* First create a socket */ | 1357 | /* First create a socket */ |
1353 | result = __sock_create(net, PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock, 1); | 1358 | result = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock); |
1354 | if (result < 0) { | 1359 | if (result < 0) { |
1355 | pr_err("Error during creation of socket; terminating\n"); | 1360 | pr_err("Error during creation of socket; terminating\n"); |
1356 | return ERR_PTR(result); | 1361 | return ERR_PTR(result); |
1357 | } | 1362 | } |
1358 | 1363 | /* | |
1364 | * Kernel sockets that are a part of a namespace, should not | ||
1365 | * hold a reference to a namespace in order to allow to stop it. | ||
1366 | * After sk_change_net should be released using sk_release_kernel. | ||
1367 | */ | ||
1368 | sk_change_net(sock->sk, net); | ||
1359 | /* it is equivalent to the REUSEADDR option in user-space */ | 1369 | /* it is equivalent to the REUSEADDR option in user-space */ |
1360 | sock->sk->sk_reuse = 1; | 1370 | sock->sk->sk_reuse = 1; |
1361 | 1371 | ||
@@ -1377,8 +1387,8 @@ static struct socket *make_receive_sock(struct net *net) | |||
1377 | 1387 | ||
1378 | return sock; | 1388 | return sock; |
1379 | 1389 | ||
1380 | error: | 1390 | error: |
1381 | sock_release(sock); | 1391 | sk_release_kernel(sock->sk); |
1382 | return ERR_PTR(result); | 1392 | return ERR_PTR(result); |
1383 | } | 1393 | } |
1384 | 1394 | ||
@@ -1473,7 +1483,7 @@ static int sync_thread_master(void *data) | |||
1473 | ip_vs_sync_buff_release(sb); | 1483 | ip_vs_sync_buff_release(sb); |
1474 | 1484 | ||
1475 | /* release the sending multicast socket */ | 1485 | /* release the sending multicast socket */ |
1476 | sock_release(tinfo->sock); | 1486 | sk_release_kernel(tinfo->sock->sk); |
1477 | kfree(tinfo); | 1487 | kfree(tinfo); |
1478 | 1488 | ||
1479 | return 0; | 1489 | return 0; |
@@ -1513,7 +1523,7 @@ static int sync_thread_backup(void *data) | |||
1513 | } | 1523 | } |
1514 | 1524 | ||
1515 | /* release the sending multicast socket */ | 1525 | /* release the sending multicast socket */ |
1516 | sock_release(tinfo->sock); | 1526 | sk_release_kernel(tinfo->sock->sk); |
1517 | kfree(tinfo->buf); | 1527 | kfree(tinfo->buf); |
1518 | kfree(tinfo); | 1528 | kfree(tinfo); |
1519 | 1529 | ||
@@ -1601,7 +1611,7 @@ outtinfo: | |||
1601 | outbuf: | 1611 | outbuf: |
1602 | kfree(buf); | 1612 | kfree(buf); |
1603 | outsocket: | 1613 | outsocket: |
1604 | sock_release(sock); | 1614 | sk_release_kernel(sock->sk); |
1605 | out: | 1615 | out: |
1606 | return result; | 1616 | return result; |
1607 | } | 1617 | } |
@@ -1610,6 +1620,7 @@ out: | |||
1610 | int stop_sync_thread(struct net *net, int state) | 1620 | int stop_sync_thread(struct net *net, int state) |
1611 | { | 1621 | { |
1612 | struct netns_ipvs *ipvs = net_ipvs(net); | 1622 | struct netns_ipvs *ipvs = net_ipvs(net); |
1623 | int retc = -EINVAL; | ||
1613 | 1624 | ||
1614 | IP_VS_DBG(7, "%s(): pid %d\n", __func__, task_pid_nr(current)); | 1625 | IP_VS_DBG(7, "%s(): pid %d\n", __func__, task_pid_nr(current)); |
1615 | 1626 | ||
@@ -1629,7 +1640,7 @@ int stop_sync_thread(struct net *net, int state) | |||
1629 | spin_lock_bh(&ipvs->sync_lock); | 1640 | spin_lock_bh(&ipvs->sync_lock); |
1630 | ipvs->sync_state &= ~IP_VS_STATE_MASTER; | 1641 | ipvs->sync_state &= ~IP_VS_STATE_MASTER; |
1631 | spin_unlock_bh(&ipvs->sync_lock); | 1642 | spin_unlock_bh(&ipvs->sync_lock); |
1632 | kthread_stop(ipvs->master_thread); | 1643 | retc = kthread_stop(ipvs->master_thread); |
1633 | ipvs->master_thread = NULL; | 1644 | ipvs->master_thread = NULL; |
1634 | } else if (state == IP_VS_STATE_BACKUP) { | 1645 | } else if (state == IP_VS_STATE_BACKUP) { |
1635 | if (!ipvs->backup_thread) | 1646 | if (!ipvs->backup_thread) |
@@ -1639,22 +1650,20 @@ int stop_sync_thread(struct net *net, int state) | |||
1639 | task_pid_nr(ipvs->backup_thread)); | 1650 | task_pid_nr(ipvs->backup_thread)); |
1640 | 1651 | ||
1641 | ipvs->sync_state &= ~IP_VS_STATE_BACKUP; | 1652 | ipvs->sync_state &= ~IP_VS_STATE_BACKUP; |
1642 | kthread_stop(ipvs->backup_thread); | 1653 | retc = kthread_stop(ipvs->backup_thread); |
1643 | ipvs->backup_thread = NULL; | 1654 | ipvs->backup_thread = NULL; |
1644 | } else { | ||
1645 | return -EINVAL; | ||
1646 | } | 1655 | } |
1647 | 1656 | ||
1648 | /* decrease the module use count */ | 1657 | /* decrease the module use count */ |
1649 | ip_vs_use_count_dec(); | 1658 | ip_vs_use_count_dec(); |
1650 | 1659 | ||
1651 | return 0; | 1660 | return retc; |
1652 | } | 1661 | } |
1653 | 1662 | ||
1654 | /* | 1663 | /* |
1655 | * Initialize data struct for each netns | 1664 | * Initialize data struct for each netns |
1656 | */ | 1665 | */ |
1657 | static int __net_init __ip_vs_sync_init(struct net *net) | 1666 | int __net_init __ip_vs_sync_init(struct net *net) |
1658 | { | 1667 | { |
1659 | struct netns_ipvs *ipvs = net_ipvs(net); | 1668 | struct netns_ipvs *ipvs = net_ipvs(net); |
1660 | 1669 | ||
@@ -1668,24 +1677,24 @@ static int __net_init __ip_vs_sync_init(struct net *net) | |||
1668 | return 0; | 1677 | return 0; |
1669 | } | 1678 | } |
1670 | 1679 | ||
1671 | static void __ip_vs_sync_cleanup(struct net *net) | 1680 | void __ip_vs_sync_cleanup(struct net *net) |
1672 | { | 1681 | { |
1673 | stop_sync_thread(net, IP_VS_STATE_MASTER); | 1682 | int retc; |
1674 | stop_sync_thread(net, IP_VS_STATE_BACKUP); | ||
1675 | } | ||
1676 | 1683 | ||
1677 | static struct pernet_operations ipvs_sync_ops = { | 1684 | retc = stop_sync_thread(net, IP_VS_STATE_MASTER); |
1678 | .init = __ip_vs_sync_init, | 1685 | if (retc && retc != -ESRCH) |
1679 | .exit = __ip_vs_sync_cleanup, | 1686 | pr_err("Failed to stop Master Daemon\n"); |
1680 | }; | ||
1681 | 1687 | ||
1688 | retc = stop_sync_thread(net, IP_VS_STATE_BACKUP); | ||
1689 | if (retc && retc != -ESRCH) | ||
1690 | pr_err("Failed to stop Backup Daemon\n"); | ||
1691 | } | ||
1682 | 1692 | ||
1683 | int __init ip_vs_sync_init(void) | 1693 | int __init ip_vs_sync_init(void) |
1684 | { | 1694 | { |
1685 | return register_pernet_subsys(&ipvs_sync_ops); | 1695 | return 0; |
1686 | } | 1696 | } |
1687 | 1697 | ||
1688 | void ip_vs_sync_cleanup(void) | 1698 | void ip_vs_sync_cleanup(void) |
1689 | { | 1699 | { |
1690 | unregister_pernet_subsys(&ipvs_sync_ops); | ||
1691 | } | 1700 | } |
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index 6132b213eddc..ee319a4338b0 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c | |||
@@ -87,7 +87,7 @@ __ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos) | |||
87 | /* Get route to destination or remote server */ | 87 | /* Get route to destination or remote server */ |
88 | static struct rtable * | 88 | static struct rtable * |
89 | __ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest, | 89 | __ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest, |
90 | __be32 daddr, u32 rtos, int rt_mode) | 90 | __be32 daddr, u32 rtos, int rt_mode, __be32 *ret_saddr) |
91 | { | 91 | { |
92 | struct net *net = dev_net(skb_dst(skb)->dev); | 92 | struct net *net = dev_net(skb_dst(skb)->dev); |
93 | struct rtable *rt; /* Route to the other host */ | 93 | struct rtable *rt; /* Route to the other host */ |
@@ -98,7 +98,12 @@ __ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest, | |||
98 | spin_lock(&dest->dst_lock); | 98 | spin_lock(&dest->dst_lock); |
99 | if (!(rt = (struct rtable *) | 99 | if (!(rt = (struct rtable *) |
100 | __ip_vs_dst_check(dest, rtos))) { | 100 | __ip_vs_dst_check(dest, rtos))) { |
101 | rt = ip_route_output(net, dest->addr.ip, 0, rtos, 0); | 101 | struct flowi4 fl4; |
102 | |||
103 | memset(&fl4, 0, sizeof(fl4)); | ||
104 | fl4.daddr = dest->addr.ip; | ||
105 | fl4.flowi4_tos = rtos; | ||
106 | rt = ip_route_output_key(net, &fl4); | ||
102 | if (IS_ERR(rt)) { | 107 | if (IS_ERR(rt)) { |
103 | spin_unlock(&dest->dst_lock); | 108 | spin_unlock(&dest->dst_lock); |
104 | IP_VS_DBG_RL("ip_route_output error, dest: %pI4\n", | 109 | IP_VS_DBG_RL("ip_route_output error, dest: %pI4\n", |
@@ -106,18 +111,30 @@ __ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest, | |||
106 | return NULL; | 111 | return NULL; |
107 | } | 112 | } |
108 | __ip_vs_dst_set(dest, rtos, dst_clone(&rt->dst), 0); | 113 | __ip_vs_dst_set(dest, rtos, dst_clone(&rt->dst), 0); |
109 | IP_VS_DBG(10, "new dst %pI4, refcnt=%d, rtos=%X\n", | 114 | dest->dst_saddr.ip = fl4.saddr; |
110 | &dest->addr.ip, | 115 | IP_VS_DBG(10, "new dst %pI4, src %pI4, refcnt=%d, " |
116 | "rtos=%X\n", | ||
117 | &dest->addr.ip, &dest->dst_saddr.ip, | ||
111 | atomic_read(&rt->dst.__refcnt), rtos); | 118 | atomic_read(&rt->dst.__refcnt), rtos); |
112 | } | 119 | } |
120 | daddr = dest->addr.ip; | ||
121 | if (ret_saddr) | ||
122 | *ret_saddr = dest->dst_saddr.ip; | ||
113 | spin_unlock(&dest->dst_lock); | 123 | spin_unlock(&dest->dst_lock); |
114 | } else { | 124 | } else { |
115 | rt = ip_route_output(net, daddr, 0, rtos, 0); | 125 | struct flowi4 fl4; |
126 | |||
127 | memset(&fl4, 0, sizeof(fl4)); | ||
128 | fl4.daddr = daddr; | ||
129 | fl4.flowi4_tos = rtos; | ||
130 | rt = ip_route_output_key(net, &fl4); | ||
116 | if (IS_ERR(rt)) { | 131 | if (IS_ERR(rt)) { |
117 | IP_VS_DBG_RL("ip_route_output error, dest: %pI4\n", | 132 | IP_VS_DBG_RL("ip_route_output error, dest: %pI4\n", |
118 | &daddr); | 133 | &daddr); |
119 | return NULL; | 134 | return NULL; |
120 | } | 135 | } |
136 | if (ret_saddr) | ||
137 | *ret_saddr = fl4.saddr; | ||
121 | } | 138 | } |
122 | 139 | ||
123 | local = rt->rt_flags & RTCF_LOCAL; | 140 | local = rt->rt_flags & RTCF_LOCAL; |
@@ -125,7 +142,7 @@ __ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest, | |||
125 | rt_mode)) { | 142 | rt_mode)) { |
126 | IP_VS_DBG_RL("Stopping traffic to %s address, dest: %pI4\n", | 143 | IP_VS_DBG_RL("Stopping traffic to %s address, dest: %pI4\n", |
127 | (rt->rt_flags & RTCF_LOCAL) ? | 144 | (rt->rt_flags & RTCF_LOCAL) ? |
128 | "local":"non-local", &rt->rt_dst); | 145 | "local":"non-local", &daddr); |
129 | ip_rt_put(rt); | 146 | ip_rt_put(rt); |
130 | return NULL; | 147 | return NULL; |
131 | } | 148 | } |
@@ -133,14 +150,14 @@ __ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest, | |||
133 | !((ort = skb_rtable(skb)) && ort->rt_flags & RTCF_LOCAL)) { | 150 | !((ort = skb_rtable(skb)) && ort->rt_flags & RTCF_LOCAL)) { |
134 | IP_VS_DBG_RL("Redirect from non-local address %pI4 to local " | 151 | IP_VS_DBG_RL("Redirect from non-local address %pI4 to local " |
135 | "requires NAT method, dest: %pI4\n", | 152 | "requires NAT method, dest: %pI4\n", |
136 | &ip_hdr(skb)->daddr, &rt->rt_dst); | 153 | &ip_hdr(skb)->daddr, &daddr); |
137 | ip_rt_put(rt); | 154 | ip_rt_put(rt); |
138 | return NULL; | 155 | return NULL; |
139 | } | 156 | } |
140 | if (unlikely(!local && ipv4_is_loopback(ip_hdr(skb)->saddr))) { | 157 | if (unlikely(!local && ipv4_is_loopback(ip_hdr(skb)->saddr))) { |
141 | IP_VS_DBG_RL("Stopping traffic from loopback address %pI4 " | 158 | IP_VS_DBG_RL("Stopping traffic from loopback address %pI4 " |
142 | "to non-local address, dest: %pI4\n", | 159 | "to non-local address, dest: %pI4\n", |
143 | &ip_hdr(skb)->saddr, &rt->rt_dst); | 160 | &ip_hdr(skb)->saddr, &daddr); |
144 | ip_rt_put(rt); | 161 | ip_rt_put(rt); |
145 | return NULL; | 162 | return NULL; |
146 | } | 163 | } |
@@ -229,8 +246,6 @@ out_err: | |||
229 | 246 | ||
230 | /* | 247 | /* |
231 | * Get route to destination or remote server | 248 | * Get route to destination or remote server |
232 | * rt_mode: flags, &1=Allow local dest, &2=Allow non-local dest, | ||
233 | * &4=Allow redirect from remote daddr to local | ||
234 | */ | 249 | */ |
235 | static struct rt6_info * | 250 | static struct rt6_info * |
236 | __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest, | 251 | __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest, |
@@ -250,7 +265,7 @@ __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest, | |||
250 | u32 cookie; | 265 | u32 cookie; |
251 | 266 | ||
252 | dst = __ip_vs_route_output_v6(net, &dest->addr.in6, | 267 | dst = __ip_vs_route_output_v6(net, &dest->addr.in6, |
253 | &dest->dst_saddr, | 268 | &dest->dst_saddr.in6, |
254 | do_xfrm); | 269 | do_xfrm); |
255 | if (!dst) { | 270 | if (!dst) { |
256 | spin_unlock(&dest->dst_lock); | 271 | spin_unlock(&dest->dst_lock); |
@@ -260,11 +275,11 @@ __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest, | |||
260 | cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; | 275 | cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; |
261 | __ip_vs_dst_set(dest, 0, dst_clone(&rt->dst), cookie); | 276 | __ip_vs_dst_set(dest, 0, dst_clone(&rt->dst), cookie); |
262 | IP_VS_DBG(10, "new dst %pI6, src %pI6, refcnt=%d\n", | 277 | IP_VS_DBG(10, "new dst %pI6, src %pI6, refcnt=%d\n", |
263 | &dest->addr.in6, &dest->dst_saddr, | 278 | &dest->addr.in6, &dest->dst_saddr.in6, |
264 | atomic_read(&rt->dst.__refcnt)); | 279 | atomic_read(&rt->dst.__refcnt)); |
265 | } | 280 | } |
266 | if (ret_saddr) | 281 | if (ret_saddr) |
267 | ipv6_addr_copy(ret_saddr, &dest->dst_saddr); | 282 | ipv6_addr_copy(ret_saddr, &dest->dst_saddr.in6); |
268 | spin_unlock(&dest->dst_lock); | 283 | spin_unlock(&dest->dst_lock); |
269 | } else { | 284 | } else { |
270 | dst = __ip_vs_route_output_v6(net, daddr, ret_saddr, do_xfrm); | 285 | dst = __ip_vs_route_output_v6(net, daddr, ret_saddr, do_xfrm); |
@@ -274,13 +289,14 @@ __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest, | |||
274 | } | 289 | } |
275 | 290 | ||
276 | local = __ip_vs_is_local_route6(rt); | 291 | local = __ip_vs_is_local_route6(rt); |
277 | if (!((local ? 1 : 2) & rt_mode)) { | 292 | if (!((local ? IP_VS_RT_MODE_LOCAL : IP_VS_RT_MODE_NON_LOCAL) & |
293 | rt_mode)) { | ||
278 | IP_VS_DBG_RL("Stopping traffic to %s address, dest: %pI6\n", | 294 | IP_VS_DBG_RL("Stopping traffic to %s address, dest: %pI6\n", |
279 | local ? "local":"non-local", daddr); | 295 | local ? "local":"non-local", daddr); |
280 | dst_release(&rt->dst); | 296 | dst_release(&rt->dst); |
281 | return NULL; | 297 | return NULL; |
282 | } | 298 | } |
283 | if (local && !(rt_mode & 4) && | 299 | if (local && !(rt_mode & IP_VS_RT_MODE_RDR) && |
284 | !((ort = (struct rt6_info *) skb_dst(skb)) && | 300 | !((ort = (struct rt6_info *) skb_dst(skb)) && |
285 | __ip_vs_is_local_route6(ort))) { | 301 | __ip_vs_is_local_route6(ort))) { |
286 | IP_VS_DBG_RL("Redirect from non-local address %pI6 to local " | 302 | IP_VS_DBG_RL("Redirect from non-local address %pI6 to local " |
@@ -386,7 +402,7 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
386 | EnterFunction(10); | 402 | EnterFunction(10); |
387 | 403 | ||
388 | if (!(rt = __ip_vs_get_out_rt(skb, NULL, iph->daddr, RT_TOS(iph->tos), | 404 | if (!(rt = __ip_vs_get_out_rt(skb, NULL, iph->daddr, RT_TOS(iph->tos), |
389 | IP_VS_RT_MODE_NON_LOCAL))) | 405 | IP_VS_RT_MODE_NON_LOCAL, NULL))) |
390 | goto tx_error_icmp; | 406 | goto tx_error_icmp; |
391 | 407 | ||
392 | /* MTU checking */ | 408 | /* MTU checking */ |
@@ -440,7 +456,8 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
440 | 456 | ||
441 | EnterFunction(10); | 457 | EnterFunction(10); |
442 | 458 | ||
443 | if (!(rt = __ip_vs_get_out_rt_v6(skb, NULL, &iph->daddr, NULL, 0, 2))) | 459 | if (!(rt = __ip_vs_get_out_rt_v6(skb, NULL, &iph->daddr, NULL, 0, |
460 | IP_VS_RT_MODE_NON_LOCAL))) | ||
444 | goto tx_error_icmp; | 461 | goto tx_error_icmp; |
445 | 462 | ||
446 | /* MTU checking */ | 463 | /* MTU checking */ |
@@ -517,7 +534,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
517 | RT_TOS(iph->tos), | 534 | RT_TOS(iph->tos), |
518 | IP_VS_RT_MODE_LOCAL | | 535 | IP_VS_RT_MODE_LOCAL | |
519 | IP_VS_RT_MODE_NON_LOCAL | | 536 | IP_VS_RT_MODE_NON_LOCAL | |
520 | IP_VS_RT_MODE_RDR))) | 537 | IP_VS_RT_MODE_RDR, NULL))) |
521 | goto tx_error_icmp; | 538 | goto tx_error_icmp; |
522 | local = rt->rt_flags & RTCF_LOCAL; | 539 | local = rt->rt_flags & RTCF_LOCAL; |
523 | /* | 540 | /* |
@@ -539,7 +556,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
539 | #endif | 556 | #endif |
540 | 557 | ||
541 | /* From world but DNAT to loopback address? */ | 558 | /* From world but DNAT to loopback address? */ |
542 | if (local && ipv4_is_loopback(rt->rt_dst) && | 559 | if (local && ipv4_is_loopback(cp->daddr.ip) && |
543 | rt_is_input_route(skb_rtable(skb))) { | 560 | rt_is_input_route(skb_rtable(skb))) { |
544 | IP_VS_DBG_RL_PKT(1, AF_INET, pp, skb, 0, "ip_vs_nat_xmit(): " | 561 | IP_VS_DBG_RL_PKT(1, AF_INET, pp, skb, 0, "ip_vs_nat_xmit(): " |
545 | "stopping DNAT to loopback address"); | 562 | "stopping DNAT to loopback address"); |
@@ -632,7 +649,9 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
632 | } | 649 | } |
633 | 650 | ||
634 | if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL, | 651 | if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL, |
635 | 0, 1|2|4))) | 652 | 0, (IP_VS_RT_MODE_LOCAL | |
653 | IP_VS_RT_MODE_NON_LOCAL | | ||
654 | IP_VS_RT_MODE_RDR)))) | ||
636 | goto tx_error_icmp; | 655 | goto tx_error_icmp; |
637 | local = __ip_vs_is_local_route6(rt); | 656 | local = __ip_vs_is_local_route6(rt); |
638 | /* | 657 | /* |
@@ -748,6 +767,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
748 | struct ip_vs_protocol *pp) | 767 | struct ip_vs_protocol *pp) |
749 | { | 768 | { |
750 | struct rtable *rt; /* Route to the other host */ | 769 | struct rtable *rt; /* Route to the other host */ |
770 | __be32 saddr; /* Source for tunnel */ | ||
751 | struct net_device *tdev; /* Device to other host */ | 771 | struct net_device *tdev; /* Device to other host */ |
752 | struct iphdr *old_iph = ip_hdr(skb); | 772 | struct iphdr *old_iph = ip_hdr(skb); |
753 | u8 tos = old_iph->tos; | 773 | u8 tos = old_iph->tos; |
@@ -761,7 +781,8 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
761 | 781 | ||
762 | if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip, | 782 | if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip, |
763 | RT_TOS(tos), IP_VS_RT_MODE_LOCAL | | 783 | RT_TOS(tos), IP_VS_RT_MODE_LOCAL | |
764 | IP_VS_RT_MODE_NON_LOCAL))) | 784 | IP_VS_RT_MODE_NON_LOCAL, |
785 | &saddr))) | ||
765 | goto tx_error_icmp; | 786 | goto tx_error_icmp; |
766 | if (rt->rt_flags & RTCF_LOCAL) { | 787 | if (rt->rt_flags & RTCF_LOCAL) { |
767 | ip_rt_put(rt); | 788 | ip_rt_put(rt); |
@@ -829,8 +850,8 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
829 | iph->frag_off = df; | 850 | iph->frag_off = df; |
830 | iph->protocol = IPPROTO_IPIP; | 851 | iph->protocol = IPPROTO_IPIP; |
831 | iph->tos = tos; | 852 | iph->tos = tos; |
832 | iph->daddr = rt->rt_dst; | 853 | iph->daddr = cp->daddr.ip; |
833 | iph->saddr = rt->rt_src; | 854 | iph->saddr = saddr; |
834 | iph->ttl = old_iph->ttl; | 855 | iph->ttl = old_iph->ttl; |
835 | ip_select_ident(iph, &rt->dst, NULL); | 856 | ip_select_ident(iph, &rt->dst, NULL); |
836 | 857 | ||
@@ -875,7 +896,8 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
875 | EnterFunction(10); | 896 | EnterFunction(10); |
876 | 897 | ||
877 | if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, | 898 | if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, |
878 | &saddr, 1, 1|2))) | 899 | &saddr, 1, (IP_VS_RT_MODE_LOCAL | |
900 | IP_VS_RT_MODE_NON_LOCAL)))) | ||
879 | goto tx_error_icmp; | 901 | goto tx_error_icmp; |
880 | if (__ip_vs_is_local_route6(rt)) { | 902 | if (__ip_vs_is_local_route6(rt)) { |
881 | dst_release(&rt->dst); | 903 | dst_release(&rt->dst); |
@@ -992,7 +1014,7 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
992 | if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip, | 1014 | if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip, |
993 | RT_TOS(iph->tos), | 1015 | RT_TOS(iph->tos), |
994 | IP_VS_RT_MODE_LOCAL | | 1016 | IP_VS_RT_MODE_LOCAL | |
995 | IP_VS_RT_MODE_NON_LOCAL))) | 1017 | IP_VS_RT_MODE_NON_LOCAL, NULL))) |
996 | goto tx_error_icmp; | 1018 | goto tx_error_icmp; |
997 | if (rt->rt_flags & RTCF_LOCAL) { | 1019 | if (rt->rt_flags & RTCF_LOCAL) { |
998 | ip_rt_put(rt); | 1020 | ip_rt_put(rt); |
@@ -1050,7 +1072,8 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
1050 | EnterFunction(10); | 1072 | EnterFunction(10); |
1051 | 1073 | ||
1052 | if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL, | 1074 | if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL, |
1053 | 0, 1|2))) | 1075 | 0, (IP_VS_RT_MODE_LOCAL | |
1076 | IP_VS_RT_MODE_NON_LOCAL)))) | ||
1054 | goto tx_error_icmp; | 1077 | goto tx_error_icmp; |
1055 | if (__ip_vs_is_local_route6(rt)) { | 1078 | if (__ip_vs_is_local_route6(rt)) { |
1056 | dst_release(&rt->dst); | 1079 | dst_release(&rt->dst); |
@@ -1109,12 +1132,13 @@ tx_error: | |||
1109 | */ | 1132 | */ |
1110 | int | 1133 | int |
1111 | ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | 1134 | ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, |
1112 | struct ip_vs_protocol *pp, int offset) | 1135 | struct ip_vs_protocol *pp, int offset, unsigned int hooknum) |
1113 | { | 1136 | { |
1114 | struct rtable *rt; /* Route to the other host */ | 1137 | struct rtable *rt; /* Route to the other host */ |
1115 | int mtu; | 1138 | int mtu; |
1116 | int rc; | 1139 | int rc; |
1117 | int local; | 1140 | int local; |
1141 | int rt_mode; | ||
1118 | 1142 | ||
1119 | EnterFunction(10); | 1143 | EnterFunction(10); |
1120 | 1144 | ||
@@ -1135,11 +1159,13 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
1135 | * mangle and send the packet here (only for VS/NAT) | 1159 | * mangle and send the packet here (only for VS/NAT) |
1136 | */ | 1160 | */ |
1137 | 1161 | ||
1162 | /* LOCALNODE from FORWARD hook is not supported */ | ||
1163 | rt_mode = (hooknum != NF_INET_FORWARD) ? | ||
1164 | IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL | | ||
1165 | IP_VS_RT_MODE_RDR : IP_VS_RT_MODE_NON_LOCAL; | ||
1138 | if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip, | 1166 | if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip, |
1139 | RT_TOS(ip_hdr(skb)->tos), | 1167 | RT_TOS(ip_hdr(skb)->tos), |
1140 | IP_VS_RT_MODE_LOCAL | | 1168 | rt_mode, NULL))) |
1141 | IP_VS_RT_MODE_NON_LOCAL | | ||
1142 | IP_VS_RT_MODE_RDR))) | ||
1143 | goto tx_error_icmp; | 1169 | goto tx_error_icmp; |
1144 | local = rt->rt_flags & RTCF_LOCAL; | 1170 | local = rt->rt_flags & RTCF_LOCAL; |
1145 | 1171 | ||
@@ -1162,7 +1188,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
1162 | #endif | 1188 | #endif |
1163 | 1189 | ||
1164 | /* From world but DNAT to loopback address? */ | 1190 | /* From world but DNAT to loopback address? */ |
1165 | if (local && ipv4_is_loopback(rt->rt_dst) && | 1191 | if (local && ipv4_is_loopback(cp->daddr.ip) && |
1166 | rt_is_input_route(skb_rtable(skb))) { | 1192 | rt_is_input_route(skb_rtable(skb))) { |
1167 | IP_VS_DBG(1, "%s(): " | 1193 | IP_VS_DBG(1, "%s(): " |
1168 | "stopping DNAT to loopback %pI4\n", | 1194 | "stopping DNAT to loopback %pI4\n", |
@@ -1227,12 +1253,13 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
1227 | #ifdef CONFIG_IP_VS_IPV6 | 1253 | #ifdef CONFIG_IP_VS_IPV6 |
1228 | int | 1254 | int |
1229 | ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | 1255 | ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, |
1230 | struct ip_vs_protocol *pp, int offset) | 1256 | struct ip_vs_protocol *pp, int offset, unsigned int hooknum) |
1231 | { | 1257 | { |
1232 | struct rt6_info *rt; /* Route to the other host */ | 1258 | struct rt6_info *rt; /* Route to the other host */ |
1233 | int mtu; | 1259 | int mtu; |
1234 | int rc; | 1260 | int rc; |
1235 | int local; | 1261 | int local; |
1262 | int rt_mode; | ||
1236 | 1263 | ||
1237 | EnterFunction(10); | 1264 | EnterFunction(10); |
1238 | 1265 | ||
@@ -1253,8 +1280,12 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
1253 | * mangle and send the packet here (only for VS/NAT) | 1280 | * mangle and send the packet here (only for VS/NAT) |
1254 | */ | 1281 | */ |
1255 | 1282 | ||
1283 | /* LOCALNODE from FORWARD hook is not supported */ | ||
1284 | rt_mode = (hooknum != NF_INET_FORWARD) ? | ||
1285 | IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL | | ||
1286 | IP_VS_RT_MODE_RDR : IP_VS_RT_MODE_NON_LOCAL; | ||
1256 | if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL, | 1287 | if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL, |
1257 | 0, 1|2|4))) | 1288 | 0, rt_mode))) |
1258 | goto tx_error_icmp; | 1289 | goto tx_error_icmp; |
1259 | 1290 | ||
1260 | local = __ip_vs_is_local_route6(rt); | 1291 | local = __ip_vs_is_local_route6(rt); |
diff --git a/net/netfilter/nf_conntrack_extend.c b/net/netfilter/nf_conntrack_extend.c index 80a23ed62bb0..05ecdc281a53 100644 --- a/net/netfilter/nf_conntrack_extend.c +++ b/net/netfilter/nf_conntrack_extend.c | |||
@@ -68,12 +68,6 @@ nf_ct_ext_create(struct nf_ct_ext **ext, enum nf_ct_ext_id id, gfp_t gfp) | |||
68 | return (void *)(*ext) + off; | 68 | return (void *)(*ext) + off; |
69 | } | 69 | } |
70 | 70 | ||
71 | static void __nf_ct_ext_free_rcu(struct rcu_head *head) | ||
72 | { | ||
73 | struct nf_ct_ext *ext = container_of(head, struct nf_ct_ext, rcu); | ||
74 | kfree(ext); | ||
75 | } | ||
76 | |||
77 | void *__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp) | 71 | void *__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp) |
78 | { | 72 | { |
79 | struct nf_ct_ext *old, *new; | 73 | struct nf_ct_ext *old, *new; |
@@ -114,7 +108,7 @@ void *__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp) | |||
114 | (void *)old + old->offset[i]); | 108 | (void *)old + old->offset[i]); |
115 | rcu_read_unlock(); | 109 | rcu_read_unlock(); |
116 | } | 110 | } |
117 | call_rcu(&old->rcu, __nf_ct_ext_free_rcu); | 111 | kfree_rcu(old, rcu); |
118 | ct->ext = new; | 112 | ct->ext = new; |
119 | } | 113 | } |
120 | 114 | ||
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 30bf8a167fc8..7dec88a1755b 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
@@ -970,7 +970,7 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, | |||
970 | 970 | ||
971 | if (nlh->nlmsg_flags & NLM_F_DUMP) | 971 | if (nlh->nlmsg_flags & NLM_F_DUMP) |
972 | return netlink_dump_start(ctnl, skb, nlh, ctnetlink_dump_table, | 972 | return netlink_dump_start(ctnl, skb, nlh, ctnetlink_dump_table, |
973 | ctnetlink_done); | 973 | ctnetlink_done, 0); |
974 | 974 | ||
975 | err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone); | 975 | err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone); |
976 | if (err < 0) | 976 | if (err < 0) |
@@ -1334,6 +1334,7 @@ ctnetlink_create_conntrack(struct net *net, u16 zone, | |||
1334 | struct nf_conn *ct; | 1334 | struct nf_conn *ct; |
1335 | int err = -EINVAL; | 1335 | int err = -EINVAL; |
1336 | struct nf_conntrack_helper *helper; | 1336 | struct nf_conntrack_helper *helper; |
1337 | struct nf_conn_tstamp *tstamp; | ||
1337 | 1338 | ||
1338 | ct = nf_conntrack_alloc(net, zone, otuple, rtuple, GFP_ATOMIC); | 1339 | ct = nf_conntrack_alloc(net, zone, otuple, rtuple, GFP_ATOMIC); |
1339 | if (IS_ERR(ct)) | 1340 | if (IS_ERR(ct)) |
@@ -1451,6 +1452,9 @@ ctnetlink_create_conntrack(struct net *net, u16 zone, | |||
1451 | __set_bit(IPS_EXPECTED_BIT, &ct->status); | 1452 | __set_bit(IPS_EXPECTED_BIT, &ct->status); |
1452 | ct->master = master_ct; | 1453 | ct->master = master_ct; |
1453 | } | 1454 | } |
1455 | tstamp = nf_conn_tstamp_find(ct); | ||
1456 | if (tstamp) | ||
1457 | tstamp->start = ktime_to_ns(ktime_get_real()); | ||
1454 | 1458 | ||
1455 | add_timer(&ct->timeout); | 1459 | add_timer(&ct->timeout); |
1456 | nf_conntrack_hash_insert(ct); | 1460 | nf_conntrack_hash_insert(ct); |
@@ -1836,7 +1840,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, | |||
1836 | if (nlh->nlmsg_flags & NLM_F_DUMP) { | 1840 | if (nlh->nlmsg_flags & NLM_F_DUMP) { |
1837 | return netlink_dump_start(ctnl, skb, nlh, | 1841 | return netlink_dump_start(ctnl, skb, nlh, |
1838 | ctnetlink_exp_dump_table, | 1842 | ctnetlink_exp_dump_table, |
1839 | ctnetlink_exp_done); | 1843 | ctnetlink_exp_done, 0); |
1840 | } | 1844 | } |
1841 | 1845 | ||
1842 | err = ctnetlink_parse_zone(cda[CTA_EXPECT_ZONE], &zone); | 1846 | err = ctnetlink_parse_zone(cda[CTA_EXPECT_ZONE], &zone); |
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 237cc1981b89..cb5a28581782 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c | |||
@@ -1419,6 +1419,7 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, | |||
1419 | const char *dptr, *end; | 1419 | const char *dptr, *end; |
1420 | s16 diff, tdiff = 0; | 1420 | s16 diff, tdiff = 0; |
1421 | int ret = NF_ACCEPT; | 1421 | int ret = NF_ACCEPT; |
1422 | bool term; | ||
1422 | typeof(nf_nat_sip_seq_adjust_hook) nf_nat_sip_seq_adjust; | 1423 | typeof(nf_nat_sip_seq_adjust_hook) nf_nat_sip_seq_adjust; |
1423 | 1424 | ||
1424 | if (ctinfo != IP_CT_ESTABLISHED && | 1425 | if (ctinfo != IP_CT_ESTABLISHED && |
@@ -1453,14 +1454,21 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, | |||
1453 | if (dptr + matchoff == end) | 1454 | if (dptr + matchoff == end) |
1454 | break; | 1455 | break; |
1455 | 1456 | ||
1456 | if (end + strlen("\r\n\r\n") > dptr + datalen) | 1457 | term = false; |
1457 | break; | 1458 | for (; end + strlen("\r\n\r\n") <= dptr + datalen; end++) { |
1458 | if (end[0] != '\r' || end[1] != '\n' || | 1459 | if (end[0] == '\r' && end[1] == '\n' && |
1459 | end[2] != '\r' || end[3] != '\n') | 1460 | end[2] == '\r' && end[3] == '\n') { |
1461 | term = true; | ||
1462 | break; | ||
1463 | } | ||
1464 | } | ||
1465 | if (!term) | ||
1460 | break; | 1466 | break; |
1461 | end += strlen("\r\n\r\n") + clen; | 1467 | end += strlen("\r\n\r\n") + clen; |
1462 | 1468 | ||
1463 | msglen = origlen = end - dptr; | 1469 | msglen = origlen = end - dptr; |
1470 | if (msglen > datalen) | ||
1471 | return NF_DROP; | ||
1464 | 1472 | ||
1465 | ret = process_sip_msg(skb, ct, dataoff, &dptr, &msglen); | 1473 | ret = process_sip_msg(skb, ct, dataoff, &dptr, &msglen); |
1466 | if (ret != NF_ACCEPT) | 1474 | if (ret != NF_ACCEPT) |
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 52959efca858..b0869fe3633b 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c | |||
@@ -455,6 +455,7 @@ void xt_compat_flush_offsets(u_int8_t af) | |||
455 | vfree(xt[af].compat_tab); | 455 | vfree(xt[af].compat_tab); |
456 | xt[af].compat_tab = NULL; | 456 | xt[af].compat_tab = NULL; |
457 | xt[af].number = 0; | 457 | xt[af].number = 0; |
458 | xt[af].cur = 0; | ||
458 | } | 459 | } |
459 | } | 460 | } |
460 | EXPORT_SYMBOL_GPL(xt_compat_flush_offsets); | 461 | EXPORT_SYMBOL_GPL(xt_compat_flush_offsets); |
@@ -473,8 +474,7 @@ int xt_compat_calc_jump(u_int8_t af, unsigned int offset) | |||
473 | else | 474 | else |
474 | return mid ? tmp[mid - 1].delta : 0; | 475 | return mid ? tmp[mid - 1].delta : 0; |
475 | } | 476 | } |
476 | WARN_ON_ONCE(1); | 477 | return left ? tmp[left - 1].delta : 0; |
477 | return 0; | ||
478 | } | 478 | } |
479 | EXPORT_SYMBOL_GPL(xt_compat_calc_jump); | 479 | EXPORT_SYMBOL_GPL(xt_compat_calc_jump); |
480 | 480 | ||
diff --git a/net/netfilter/xt_DSCP.c b/net/netfilter/xt_DSCP.c index 0a229191e55b..ae8271652efa 100644 --- a/net/netfilter/xt_DSCP.c +++ b/net/netfilter/xt_DSCP.c | |||
@@ -99,7 +99,7 @@ tos_tg6(struct sk_buff *skb, const struct xt_action_param *par) | |||
99 | u_int8_t orig, nv; | 99 | u_int8_t orig, nv; |
100 | 100 | ||
101 | orig = ipv6_get_dsfield(iph); | 101 | orig = ipv6_get_dsfield(iph); |
102 | nv = (orig & info->tos_mask) ^ info->tos_value; | 102 | nv = (orig & ~info->tos_mask) ^ info->tos_value; |
103 | 103 | ||
104 | if (orig != nv) { | 104 | if (orig != nv) { |
105 | if (!skb_make_writable(skb, sizeof(struct iphdr))) | 105 | if (!skb_make_writable(skb, sizeof(struct iphdr))) |
diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c index 481a86fdc409..61805d7b38aa 100644 --- a/net/netfilter/xt_conntrack.c +++ b/net/netfilter/xt_conntrack.c | |||
@@ -272,11 +272,6 @@ static int conntrack_mt_check(const struct xt_mtchk_param *par) | |||
272 | { | 272 | { |
273 | int ret; | 273 | int ret; |
274 | 274 | ||
275 | if (strcmp(par->table, "raw") == 0) { | ||
276 | pr_info("state is undetermined at the time of raw table\n"); | ||
277 | return -EINVAL; | ||
278 | } | ||
279 | |||
280 | ret = nf_ct_l3proto_try_module_get(par->family); | 275 | ret = nf_ct_l3proto_try_module_get(par->family); |
281 | if (ret < 0) | 276 | if (ret < 0) |
282 | pr_info("cannot load conntrack support for proto=%u\n", | 277 | pr_info("cannot load conntrack support for proto=%u\n", |
diff --git a/net/netfilter/xt_osf.c b/net/netfilter/xt_osf.c index 4327e101c047..846f895cb656 100644 --- a/net/netfilter/xt_osf.c +++ b/net/netfilter/xt_osf.c | |||
@@ -62,13 +62,6 @@ static const struct nla_policy xt_osf_policy[OSF_ATTR_MAX + 1] = { | |||
62 | [OSF_ATTR_FINGER] = { .len = sizeof(struct xt_osf_user_finger) }, | 62 | [OSF_ATTR_FINGER] = { .len = sizeof(struct xt_osf_user_finger) }, |
63 | }; | 63 | }; |
64 | 64 | ||
65 | static void xt_osf_finger_free_rcu(struct rcu_head *rcu_head) | ||
66 | { | ||
67 | struct xt_osf_finger *f = container_of(rcu_head, struct xt_osf_finger, rcu_head); | ||
68 | |||
69 | kfree(f); | ||
70 | } | ||
71 | |||
72 | static int xt_osf_add_callback(struct sock *ctnl, struct sk_buff *skb, | 65 | static int xt_osf_add_callback(struct sock *ctnl, struct sk_buff *skb, |
73 | const struct nlmsghdr *nlh, | 66 | const struct nlmsghdr *nlh, |
74 | const struct nlattr * const osf_attrs[]) | 67 | const struct nlattr * const osf_attrs[]) |
@@ -133,7 +126,7 @@ static int xt_osf_remove_callback(struct sock *ctnl, struct sk_buff *skb, | |||
133 | * We are protected by nfnl mutex. | 126 | * We are protected by nfnl mutex. |
134 | */ | 127 | */ |
135 | list_del_rcu(&sf->finger_entry); | 128 | list_del_rcu(&sf->finger_entry); |
136 | call_rcu(&sf->rcu_head, xt_osf_finger_free_rcu); | 129 | kfree_rcu(sf, rcu_head); |
137 | 130 | ||
138 | err = 0; | 131 | err = 0; |
139 | break; | 132 | break; |
@@ -414,7 +407,7 @@ static void __exit xt_osf_fini(void) | |||
414 | 407 | ||
415 | list_for_each_entry_rcu(f, &xt_osf_fingers[i], finger_entry) { | 408 | list_for_each_entry_rcu(f, &xt_osf_fingers[i], finger_entry) { |
416 | list_del_rcu(&f->finger_entry); | 409 | list_del_rcu(&f->finger_entry); |
417 | call_rcu(&f->rcu_head, xt_osf_finger_free_rcu); | 410 | kfree_rcu(f, rcu_head); |
418 | } | 411 | } |
419 | } | 412 | } |
420 | rcu_read_unlock(); | 413 | rcu_read_unlock(); |
diff --git a/net/netfilter/xt_set.c b/net/netfilter/xt_set.c index 061d48cec137..b3babaed7719 100644 --- a/net/netfilter/xt_set.c +++ b/net/netfilter/xt_set.c | |||
@@ -81,6 +81,7 @@ set_match_v0_checkentry(const struct xt_mtchk_param *par) | |||
81 | if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) { | 81 | if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) { |
82 | pr_warning("Protocol error: set match dimension " | 82 | pr_warning("Protocol error: set match dimension " |
83 | "is over the limit!\n"); | 83 | "is over the limit!\n"); |
84 | ip_set_nfnl_put(info->match_set.index); | ||
84 | return -ERANGE; | 85 | return -ERANGE; |
85 | } | 86 | } |
86 | 87 | ||
@@ -135,6 +136,8 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par) | |||
135 | if (index == IPSET_INVALID_ID) { | 136 | if (index == IPSET_INVALID_ID) { |
136 | pr_warning("Cannot find del_set index %u as target\n", | 137 | pr_warning("Cannot find del_set index %u as target\n", |
137 | info->del_set.index); | 138 | info->del_set.index); |
139 | if (info->add_set.index != IPSET_INVALID_ID) | ||
140 | ip_set_nfnl_put(info->add_set.index); | ||
138 | return -ENOENT; | 141 | return -ENOENT; |
139 | } | 142 | } |
140 | } | 143 | } |
@@ -142,6 +145,10 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par) | |||
142 | info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) { | 145 | info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) { |
143 | pr_warning("Protocol error: SET target dimension " | 146 | pr_warning("Protocol error: SET target dimension " |
144 | "is over the limit!\n"); | 147 | "is over the limit!\n"); |
148 | if (info->add_set.index != IPSET_INVALID_ID) | ||
149 | ip_set_nfnl_put(info->add_set.index); | ||
150 | if (info->del_set.index != IPSET_INVALID_ID) | ||
151 | ip_set_nfnl_put(info->del_set.index); | ||
145 | return -ERANGE; | 152 | return -ERANGE; |
146 | } | 153 | } |
147 | 154 | ||
@@ -192,6 +199,7 @@ set_match_checkentry(const struct xt_mtchk_param *par) | |||
192 | if (info->match_set.dim > IPSET_DIM_MAX) { | 199 | if (info->match_set.dim > IPSET_DIM_MAX) { |
193 | pr_warning("Protocol error: set match dimension " | 200 | pr_warning("Protocol error: set match dimension " |
194 | "is over the limit!\n"); | 201 | "is over the limit!\n"); |
202 | ip_set_nfnl_put(info->match_set.index); | ||
195 | return -ERANGE; | 203 | return -ERANGE; |
196 | } | 204 | } |
197 | 205 | ||
@@ -219,7 +227,7 @@ set_target(struct sk_buff *skb, const struct xt_action_param *par) | |||
219 | if (info->del_set.index != IPSET_INVALID_ID) | 227 | if (info->del_set.index != IPSET_INVALID_ID) |
220 | ip_set_del(info->del_set.index, | 228 | ip_set_del(info->del_set.index, |
221 | skb, par->family, | 229 | skb, par->family, |
222 | info->add_set.dim, | 230 | info->del_set.dim, |
223 | info->del_set.flags); | 231 | info->del_set.flags); |
224 | 232 | ||
225 | return XT_CONTINUE; | 233 | return XT_CONTINUE; |
@@ -245,13 +253,19 @@ set_target_checkentry(const struct xt_tgchk_param *par) | |||
245 | if (index == IPSET_INVALID_ID) { | 253 | if (index == IPSET_INVALID_ID) { |
246 | pr_warning("Cannot find del_set index %u as target\n", | 254 | pr_warning("Cannot find del_set index %u as target\n", |
247 | info->del_set.index); | 255 | info->del_set.index); |
256 | if (info->add_set.index != IPSET_INVALID_ID) | ||
257 | ip_set_nfnl_put(info->add_set.index); | ||
248 | return -ENOENT; | 258 | return -ENOENT; |
249 | } | 259 | } |
250 | } | 260 | } |
251 | if (info->add_set.dim > IPSET_DIM_MAX || | 261 | if (info->add_set.dim > IPSET_DIM_MAX || |
252 | info->del_set.flags > IPSET_DIM_MAX) { | 262 | info->del_set.dim > IPSET_DIM_MAX) { |
253 | pr_warning("Protocol error: SET target dimension " | 263 | pr_warning("Protocol error: SET target dimension " |
254 | "is over the limit!\n"); | 264 | "is over the limit!\n"); |
265 | if (info->add_set.index != IPSET_INVALID_ID) | ||
266 | ip_set_nfnl_put(info->add_set.index); | ||
267 | if (info->del_set.index != IPSET_INVALID_ID) | ||
268 | ip_set_nfnl_put(info->del_set.index); | ||
255 | return -ERANGE; | 269 | return -ERANGE; |
256 | } | 270 | } |
257 | 271 | ||