diff options
Diffstat (limited to 'net/ipv4')
| -rw-r--r-- | net/ipv4/devinet.c | 34 | ||||
| -rw-r--r-- | net/ipv4/esp4.c | 2 | ||||
| -rw-r--r-- | net/ipv4/ip_output.c | 8 | ||||
| -rw-r--r-- | net/ipv4/ipvs/Makefile | 2 | ||||
| -rw-r--r-- | net/ipv4/ipvs/ip_vs_proto.c | 3 | ||||
| -rw-r--r-- | net/ipv4/ipvs/ip_vs_proto_icmp.c | 182 | ||||
| -rw-r--r-- | net/ipv4/ipvs/ip_vs_xmit.c | 1 | ||||
| -rw-r--r-- | net/ipv4/multipath_drr.c | 18 | ||||
| -rw-r--r-- | net/ipv4/multipath_rr.c | 20 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ip_conntrack_core.c | 28 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ip_queue.c | 10 | ||||
| -rw-r--r-- | net/ipv4/tcp_input.c | 11 | ||||
| -rw-r--r-- | net/ipv4/udp.c | 12 |
13 files changed, 65 insertions, 266 deletions
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 3cc96730c4ed..478a30179a52 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c | |||
| @@ -233,11 +233,14 @@ int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b) | |||
| 233 | static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | 233 | static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, |
| 234 | int destroy) | 234 | int destroy) |
| 235 | { | 235 | { |
| 236 | struct in_ifaddr *promote = NULL; | ||
| 236 | struct in_ifaddr *ifa1 = *ifap; | 237 | struct in_ifaddr *ifa1 = *ifap; |
| 237 | 238 | ||
| 238 | ASSERT_RTNL(); | 239 | ASSERT_RTNL(); |
| 239 | 240 | ||
| 240 | /* 1. Deleting primary ifaddr forces deletion all secondaries */ | 241 | /* 1. Deleting primary ifaddr forces deletion all secondaries |
| 242 | * unless alias promotion is set | ||
| 243 | **/ | ||
| 241 | 244 | ||
| 242 | if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) { | 245 | if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) { |
| 243 | struct in_ifaddr *ifa; | 246 | struct in_ifaddr *ifa; |
| @@ -251,11 +254,16 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | |||
| 251 | continue; | 254 | continue; |
| 252 | } | 255 | } |
| 253 | 256 | ||
| 254 | *ifap1 = ifa->ifa_next; | 257 | if (!IN_DEV_PROMOTE_SECONDARIES(in_dev)) { |
| 258 | *ifap1 = ifa->ifa_next; | ||
| 255 | 259 | ||
| 256 | rtmsg_ifa(RTM_DELADDR, ifa); | 260 | rtmsg_ifa(RTM_DELADDR, ifa); |
| 257 | notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa); | 261 | notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa); |
| 258 | inet_free_ifa(ifa); | 262 | inet_free_ifa(ifa); |
| 263 | } else { | ||
| 264 | promote = ifa; | ||
| 265 | break; | ||
| 266 | } | ||
| 259 | } | 267 | } |
| 260 | } | 268 | } |
| 261 | 269 | ||
| @@ -281,6 +289,13 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | |||
| 281 | if (!in_dev->ifa_list) | 289 | if (!in_dev->ifa_list) |
| 282 | inetdev_destroy(in_dev); | 290 | inetdev_destroy(in_dev); |
| 283 | } | 291 | } |
| 292 | |||
| 293 | if (promote && IN_DEV_PROMOTE_SECONDARIES(in_dev)) { | ||
| 294 | /* not sure if we should send a delete notify first? */ | ||
| 295 | promote->ifa_flags &= ~IFA_F_SECONDARY; | ||
| 296 | rtmsg_ifa(RTM_NEWADDR, promote); | ||
| 297 | notifier_call_chain(&inetaddr_chain, NETDEV_UP, promote); | ||
| 298 | } | ||
| 284 | } | 299 | } |
| 285 | 300 | ||
| 286 | static int inet_insert_ifa(struct in_ifaddr *ifa) | 301 | static int inet_insert_ifa(struct in_ifaddr *ifa) |
| @@ -1384,6 +1399,15 @@ static struct devinet_sysctl_table { | |||
| 1384 | .proc_handler = &ipv4_doint_and_flush, | 1399 | .proc_handler = &ipv4_doint_and_flush, |
| 1385 | .strategy = &ipv4_doint_and_flush_strategy, | 1400 | .strategy = &ipv4_doint_and_flush_strategy, |
| 1386 | }, | 1401 | }, |
| 1402 | { | ||
| 1403 | .ctl_name = NET_IPV4_CONF_PROMOTE_SECONDARIES, | ||
| 1404 | .procname = "promote_secondaries", | ||
| 1405 | .data = &ipv4_devconf.promote_secondaries, | ||
| 1406 | .maxlen = sizeof(int), | ||
| 1407 | .mode = 0644, | ||
| 1408 | .proc_handler = &ipv4_doint_and_flush, | ||
| 1409 | .strategy = &ipv4_doint_and_flush_strategy, | ||
| 1410 | }, | ||
| 1387 | }, | 1411 | }, |
| 1388 | .devinet_dev = { | 1412 | .devinet_dev = { |
| 1389 | { | 1413 | { |
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 053a883247ba..eae84cc39d3f 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c | |||
| @@ -478,7 +478,7 @@ static int __init esp4_init(void) | |||
| 478 | { | 478 | { |
| 479 | struct xfrm_decap_state decap; | 479 | struct xfrm_decap_state decap; |
| 480 | 480 | ||
| 481 | if (sizeof(struct esp_decap_data) < | 481 | if (sizeof(struct esp_decap_data) > |
| 482 | sizeof(decap.decap_data)) { | 482 | sizeof(decap.decap_data)) { |
| 483 | extern void decap_data_too_small(void); | 483 | extern void decap_data_too_small(void); |
| 484 | 484 | ||
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index daebd93fd8a0..760dc8238d65 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c | |||
| @@ -490,6 +490,14 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) | |||
| 490 | /* Partially cloned skb? */ | 490 | /* Partially cloned skb? */ |
| 491 | if (skb_shared(frag)) | 491 | if (skb_shared(frag)) |
| 492 | goto slow_path; | 492 | goto slow_path; |
| 493 | |||
| 494 | BUG_ON(frag->sk); | ||
| 495 | if (skb->sk) { | ||
| 496 | sock_hold(skb->sk); | ||
| 497 | frag->sk = skb->sk; | ||
| 498 | frag->destructor = sock_wfree; | ||
| 499 | skb->truesize -= frag->truesize; | ||
| 500 | } | ||
| 493 | } | 501 | } |
| 494 | 502 | ||
| 495 | /* Everything is OK. Generate! */ | 503 | /* Everything is OK. Generate! */ |
diff --git a/net/ipv4/ipvs/Makefile b/net/ipv4/ipvs/Makefile index a788461a40c9..30e85de9ffff 100644 --- a/net/ipv4/ipvs/Makefile +++ b/net/ipv4/ipvs/Makefile | |||
| @@ -11,7 +11,7 @@ ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_AH) += ip_vs_proto_ah.o | |||
| 11 | 11 | ||
| 12 | ip_vs-objs := ip_vs_conn.o ip_vs_core.o ip_vs_ctl.o ip_vs_sched.o \ | 12 | ip_vs-objs := ip_vs_conn.o ip_vs_core.o ip_vs_ctl.o ip_vs_sched.o \ |
| 13 | ip_vs_xmit.o ip_vs_app.o ip_vs_sync.o \ | 13 | ip_vs_xmit.o ip_vs_app.o ip_vs_sync.o \ |
| 14 | ip_vs_est.o ip_vs_proto.o ip_vs_proto_icmp.o \ | 14 | ip_vs_est.o ip_vs_proto.o \ |
| 15 | $(ip_vs_proto-objs-y) | 15 | $(ip_vs_proto-objs-y) |
| 16 | 16 | ||
| 17 | 17 | ||
diff --git a/net/ipv4/ipvs/ip_vs_proto.c b/net/ipv4/ipvs/ip_vs_proto.c index 253c46252bd5..867d4e9c6594 100644 --- a/net/ipv4/ipvs/ip_vs_proto.c +++ b/net/ipv4/ipvs/ip_vs_proto.c | |||
| @@ -216,9 +216,6 @@ int ip_vs_protocol_init(void) | |||
| 216 | #ifdef CONFIG_IP_VS_PROTO_UDP | 216 | #ifdef CONFIG_IP_VS_PROTO_UDP |
| 217 | REGISTER_PROTOCOL(&ip_vs_protocol_udp); | 217 | REGISTER_PROTOCOL(&ip_vs_protocol_udp); |
| 218 | #endif | 218 | #endif |
| 219 | #ifdef CONFIG_IP_VS_PROTO_ICMP | ||
| 220 | REGISTER_PROTOCOL(&ip_vs_protocol_icmp); | ||
| 221 | #endif | ||
| 222 | #ifdef CONFIG_IP_VS_PROTO_AH | 219 | #ifdef CONFIG_IP_VS_PROTO_AH |
| 223 | REGISTER_PROTOCOL(&ip_vs_protocol_ah); | 220 | REGISTER_PROTOCOL(&ip_vs_protocol_ah); |
| 224 | #endif | 221 | #endif |
diff --git a/net/ipv4/ipvs/ip_vs_proto_icmp.c b/net/ipv4/ipvs/ip_vs_proto_icmp.c deleted file mode 100644 index 191e94aa1c1f..000000000000 --- a/net/ipv4/ipvs/ip_vs_proto_icmp.c +++ /dev/null | |||
| @@ -1,182 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * ip_vs_proto_icmp.c: ICMP load balancing support for IP Virtual Server | ||
| 3 | * | ||
| 4 | * Authors: Julian Anastasov <ja@ssi.bg>, March 2002 | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License | ||
| 8 | * version 2 as published by the Free Software Foundation; | ||
| 9 | * | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/kernel.h> | ||
| 14 | #include <linux/icmp.h> | ||
| 15 | #include <linux/netfilter.h> | ||
| 16 | #include <linux/netfilter_ipv4.h> | ||
| 17 | |||
| 18 | #include <net/ip_vs.h> | ||
| 19 | |||
| 20 | |||
| 21 | static int icmp_timeouts[1] = { 1*60*HZ }; | ||
| 22 | |||
| 23 | static char * icmp_state_name_table[1] = { "ICMP" }; | ||
| 24 | |||
| 25 | static struct ip_vs_conn * | ||
| 26 | icmp_conn_in_get(const struct sk_buff *skb, | ||
| 27 | struct ip_vs_protocol *pp, | ||
| 28 | const struct iphdr *iph, | ||
| 29 | unsigned int proto_off, | ||
| 30 | int inverse) | ||
| 31 | { | ||
| 32 | #if 0 | ||
| 33 | struct ip_vs_conn *cp; | ||
| 34 | |||
| 35 | if (likely(!inverse)) { | ||
| 36 | cp = ip_vs_conn_in_get(iph->protocol, | ||
| 37 | iph->saddr, 0, | ||
| 38 | iph->daddr, 0); | ||
| 39 | } else { | ||
| 40 | cp = ip_vs_conn_in_get(iph->protocol, | ||
| 41 | iph->daddr, 0, | ||
| 42 | iph->saddr, 0); | ||
| 43 | } | ||
| 44 | |||
| 45 | return cp; | ||
| 46 | |||
| 47 | #else | ||
| 48 | return NULL; | ||
| 49 | #endif | ||
| 50 | } | ||
| 51 | |||
| 52 | static struct ip_vs_conn * | ||
| 53 | icmp_conn_out_get(const struct sk_buff *skb, | ||
| 54 | struct ip_vs_protocol *pp, | ||
| 55 | const struct iphdr *iph, | ||
| 56 | unsigned int proto_off, | ||
| 57 | int inverse) | ||
| 58 | { | ||
| 59 | #if 0 | ||
| 60 | struct ip_vs_conn *cp; | ||
| 61 | |||
| 62 | if (likely(!inverse)) { | ||
| 63 | cp = ip_vs_conn_out_get(iph->protocol, | ||
| 64 | iph->saddr, 0, | ||
| 65 | iph->daddr, 0); | ||
| 66 | } else { | ||
| 67 | cp = ip_vs_conn_out_get(IPPROTO_UDP, | ||
| 68 | iph->daddr, 0, | ||
| 69 | iph->saddr, 0); | ||
| 70 | } | ||
| 71 | |||
| 72 | return cp; | ||
| 73 | #else | ||
| 74 | return NULL; | ||
| 75 | #endif | ||
| 76 | } | ||
| 77 | |||
| 78 | static int | ||
| 79 | icmp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp, | ||
| 80 | int *verdict, struct ip_vs_conn **cpp) | ||
| 81 | { | ||
| 82 | *verdict = NF_ACCEPT; | ||
| 83 | return 0; | ||
| 84 | } | ||
| 85 | |||
| 86 | static int | ||
| 87 | icmp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp) | ||
| 88 | { | ||
| 89 | if (!(skb->nh.iph->frag_off & __constant_htons(IP_OFFSET))) { | ||
| 90 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) { | ||
| 91 | if (ip_vs_checksum_complete(skb, skb->nh.iph->ihl * 4)) { | ||
| 92 | IP_VS_DBG_RL_PKT(0, pp, skb, 0, "Failed checksum for"); | ||
| 93 | return 0; | ||
| 94 | } | ||
| 95 | } | ||
| 96 | } | ||
| 97 | return 1; | ||
| 98 | } | ||
| 99 | |||
| 100 | static void | ||
| 101 | icmp_debug_packet(struct ip_vs_protocol *pp, | ||
| 102 | const struct sk_buff *skb, | ||
| 103 | int offset, | ||
| 104 | const char *msg) | ||
| 105 | { | ||
| 106 | char buf[256]; | ||
| 107 | struct iphdr _iph, *ih; | ||
| 108 | |||
| 109 | ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph); | ||
| 110 | if (ih == NULL) | ||
| 111 | sprintf(buf, "%s TRUNCATED", pp->name); | ||
| 112 | else if (ih->frag_off & __constant_htons(IP_OFFSET)) | ||
| 113 | sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u frag", | ||
| 114 | pp->name, NIPQUAD(ih->saddr), | ||
| 115 | NIPQUAD(ih->daddr)); | ||
| 116 | else { | ||
| 117 | struct icmphdr _icmph, *ic; | ||
| 118 | |||
| 119 | ic = skb_header_pointer(skb, offset + ih->ihl*4, | ||
| 120 | sizeof(_icmph), &_icmph); | ||
| 121 | if (ic == NULL) | ||
| 122 | sprintf(buf, "%s TRUNCATED to %u bytes\n", | ||
| 123 | pp->name, skb->len - offset); | ||
| 124 | else | ||
| 125 | sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u T:%d C:%d", | ||
| 126 | pp->name, NIPQUAD(ih->saddr), | ||
| 127 | NIPQUAD(ih->daddr), | ||
| 128 | ic->type, ic->code); | ||
| 129 | } | ||
| 130 | printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf); | ||
| 131 | } | ||
| 132 | |||
| 133 | static int | ||
| 134 | icmp_state_transition(struct ip_vs_conn *cp, int direction, | ||
| 135 | const struct sk_buff *skb, | ||
| 136 | struct ip_vs_protocol *pp) | ||
| 137 | { | ||
| 138 | cp->timeout = pp->timeout_table[IP_VS_ICMP_S_NORMAL]; | ||
| 139 | return 1; | ||
| 140 | } | ||
| 141 | |||
| 142 | static int | ||
| 143 | icmp_set_state_timeout(struct ip_vs_protocol *pp, char *sname, int to) | ||
| 144 | { | ||
| 145 | int num; | ||
| 146 | char **names; | ||
| 147 | |||
| 148 | num = IP_VS_ICMP_S_LAST; | ||
| 149 | names = icmp_state_name_table; | ||
| 150 | return ip_vs_set_state_timeout(pp->timeout_table, num, names, sname, to); | ||
| 151 | } | ||
| 152 | |||
| 153 | |||
| 154 | static void icmp_init(struct ip_vs_protocol *pp) | ||
| 155 | { | ||
| 156 | pp->timeout_table = icmp_timeouts; | ||
| 157 | } | ||
| 158 | |||
| 159 | static void icmp_exit(struct ip_vs_protocol *pp) | ||
| 160 | { | ||
| 161 | } | ||
| 162 | |||
| 163 | struct ip_vs_protocol ip_vs_protocol_icmp = { | ||
| 164 | .name = "ICMP", | ||
| 165 | .protocol = IPPROTO_ICMP, | ||
| 166 | .dont_defrag = 0, | ||
| 167 | .init = icmp_init, | ||
| 168 | .exit = icmp_exit, | ||
| 169 | .conn_schedule = icmp_conn_schedule, | ||
| 170 | .conn_in_get = icmp_conn_in_get, | ||
| 171 | .conn_out_get = icmp_conn_out_get, | ||
| 172 | .snat_handler = NULL, | ||
| 173 | .dnat_handler = NULL, | ||
| 174 | .csum_check = icmp_csum_check, | ||
| 175 | .state_transition = icmp_state_transition, | ||
| 176 | .register_app = NULL, | ||
| 177 | .unregister_app = NULL, | ||
| 178 | .app_conn_bind = NULL, | ||
| 179 | .debug_packet = icmp_debug_packet, | ||
| 180 | .timeout_change = NULL, | ||
| 181 | .set_state_timeout = icmp_set_state_timeout, | ||
| 182 | }; | ||
diff --git a/net/ipv4/ipvs/ip_vs_xmit.c b/net/ipv4/ipvs/ip_vs_xmit.c index faa6176bbeb1..de21da00057f 100644 --- a/net/ipv4/ipvs/ip_vs_xmit.c +++ b/net/ipv4/ipvs/ip_vs_xmit.c | |||
| @@ -508,7 +508,6 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
| 508 | rc = NF_ACCEPT; | 508 | rc = NF_ACCEPT; |
| 509 | /* do not touch skb anymore */ | 509 | /* do not touch skb anymore */ |
| 510 | atomic_inc(&cp->in_pkts); | 510 | atomic_inc(&cp->in_pkts); |
| 511 | __ip_vs_conn_put(cp); | ||
| 512 | goto out; | 511 | goto out; |
| 513 | } | 512 | } |
| 514 | 513 | ||
diff --git a/net/ipv4/multipath_drr.c b/net/ipv4/multipath_drr.c index 9349686131fc..cf2e6bcf7973 100644 --- a/net/ipv4/multipath_drr.c +++ b/net/ipv4/multipath_drr.c | |||
| @@ -57,7 +57,6 @@ struct multipath_device { | |||
| 57 | 57 | ||
| 58 | static struct multipath_device state[MULTIPATH_MAX_DEVICECANDIDATES]; | 58 | static struct multipath_device state[MULTIPATH_MAX_DEVICECANDIDATES]; |
| 59 | static DEFINE_SPINLOCK(state_lock); | 59 | static DEFINE_SPINLOCK(state_lock); |
| 60 | static struct rtable *last_selection = NULL; | ||
| 61 | 60 | ||
| 62 | static int inline __multipath_findslot(void) | 61 | static int inline __multipath_findslot(void) |
| 63 | { | 62 | { |
| @@ -111,11 +110,6 @@ struct notifier_block drr_dev_notifier = { | |||
| 111 | .notifier_call = drr_dev_event, | 110 | .notifier_call = drr_dev_event, |
| 112 | }; | 111 | }; |
| 113 | 112 | ||
| 114 | static void drr_remove(struct rtable *rt) | ||
| 115 | { | ||
| 116 | if (last_selection == rt) | ||
| 117 | last_selection = NULL; | ||
| 118 | } | ||
| 119 | 113 | ||
| 120 | static void drr_safe_inc(atomic_t *usecount) | 114 | static void drr_safe_inc(atomic_t *usecount) |
| 121 | { | 115 | { |
| @@ -144,14 +138,6 @@ static void drr_select_route(const struct flowi *flp, | |||
| 144 | int devidx = -1; | 138 | int devidx = -1; |
| 145 | int cur_min_devidx = -1; | 139 | int cur_min_devidx = -1; |
| 146 | 140 | ||
| 147 | /* if necessary and possible utilize the old alternative */ | ||
| 148 | if ((flp->flags & FLOWI_FLAG_MULTIPATHOLDROUTE) != 0 && | ||
| 149 | last_selection != NULL) { | ||
| 150 | result = last_selection; | ||
| 151 | *rp = result; | ||
| 152 | return; | ||
| 153 | } | ||
| 154 | |||
| 155 | /* 1. make sure all alt. nexthops have the same GC related data */ | 141 | /* 1. make sure all alt. nexthops have the same GC related data */ |
| 156 | /* 2. determine the new candidate to be returned */ | 142 | /* 2. determine the new candidate to be returned */ |
| 157 | result = NULL; | 143 | result = NULL; |
| @@ -229,12 +215,10 @@ static void drr_select_route(const struct flowi *flp, | |||
| 229 | } | 215 | } |
| 230 | 216 | ||
| 231 | *rp = result; | 217 | *rp = result; |
| 232 | last_selection = result; | ||
| 233 | } | 218 | } |
| 234 | 219 | ||
| 235 | static struct ip_mp_alg_ops drr_ops = { | 220 | static struct ip_mp_alg_ops drr_ops = { |
| 236 | .mp_alg_select_route = drr_select_route, | 221 | .mp_alg_select_route = drr_select_route, |
| 237 | .mp_alg_remove = drr_remove, | ||
| 238 | }; | 222 | }; |
| 239 | 223 | ||
| 240 | static int __init drr_init(void) | 224 | static int __init drr_init(void) |
| @@ -244,7 +228,7 @@ static int __init drr_init(void) | |||
| 244 | if (err) | 228 | if (err) |
| 245 | return err; | 229 | return err; |
| 246 | 230 | ||
| 247 | err = multipath_alg_register(&drr_ops, IP_MP_ALG_RR); | 231 | err = multipath_alg_register(&drr_ops, IP_MP_ALG_DRR); |
| 248 | if (err) | 232 | if (err) |
| 249 | goto fail; | 233 | goto fail; |
| 250 | 234 | ||
diff --git a/net/ipv4/multipath_rr.c b/net/ipv4/multipath_rr.c index 554a82568160..061b6b253982 100644 --- a/net/ipv4/multipath_rr.c +++ b/net/ipv4/multipath_rr.c | |||
| @@ -47,29 +47,12 @@ | |||
| 47 | #include <net/checksum.h> | 47 | #include <net/checksum.h> |
| 48 | #include <net/ip_mp_alg.h> | 48 | #include <net/ip_mp_alg.h> |
| 49 | 49 | ||
| 50 | #define MULTIPATH_MAX_CANDIDATES 40 | ||
| 51 | |||
| 52 | static struct rtable* last_used = NULL; | ||
| 53 | |||
| 54 | static void rr_remove(struct rtable *rt) | ||
| 55 | { | ||
| 56 | if (last_used == rt) | ||
| 57 | last_used = NULL; | ||
| 58 | } | ||
| 59 | |||
| 60 | static void rr_select_route(const struct flowi *flp, | 50 | static void rr_select_route(const struct flowi *flp, |
| 61 | struct rtable *first, struct rtable **rp) | 51 | struct rtable *first, struct rtable **rp) |
| 62 | { | 52 | { |
| 63 | struct rtable *nh, *result, *min_use_cand = NULL; | 53 | struct rtable *nh, *result, *min_use_cand = NULL; |
| 64 | int min_use = -1; | 54 | int min_use = -1; |
| 65 | 55 | ||
| 66 | /* if necessary and possible utilize the old alternative */ | ||
| 67 | if ((flp->flags & FLOWI_FLAG_MULTIPATHOLDROUTE) != 0 && | ||
| 68 | last_used != NULL) { | ||
| 69 | result = last_used; | ||
| 70 | goto out; | ||
| 71 | } | ||
| 72 | |||
| 73 | /* 1. make sure all alt. nexthops have the same GC related data | 56 | /* 1. make sure all alt. nexthops have the same GC related data |
| 74 | * 2. determine the new candidate to be returned | 57 | * 2. determine the new candidate to be returned |
| 75 | */ | 58 | */ |
| @@ -90,15 +73,12 @@ static void rr_select_route(const struct flowi *flp, | |||
| 90 | if (!result) | 73 | if (!result) |
| 91 | result = first; | 74 | result = first; |
| 92 | 75 | ||
| 93 | out: | ||
| 94 | last_used = result; | ||
| 95 | result->u.dst.__use++; | 76 | result->u.dst.__use++; |
| 96 | *rp = result; | 77 | *rp = result; |
| 97 | } | 78 | } |
| 98 | 79 | ||
| 99 | static struct ip_mp_alg_ops rr_ops = { | 80 | static struct ip_mp_alg_ops rr_ops = { |
| 100 | .mp_alg_select_route = rr_select_route, | 81 | .mp_alg_select_route = rr_select_route, |
| 101 | .mp_alg_remove = rr_remove, | ||
| 102 | }; | 82 | }; |
| 103 | 83 | ||
| 104 | static int __init rr_init(void) | 84 | static int __init rr_init(void) |
diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index 28d9425d5c39..09e824622977 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c | |||
| @@ -940,37 +940,25 @@ void ip_ct_refresh_acct(struct ip_conntrack *ct, | |||
| 940 | struct sk_buff * | 940 | struct sk_buff * |
| 941 | ip_ct_gather_frags(struct sk_buff *skb, u_int32_t user) | 941 | ip_ct_gather_frags(struct sk_buff *skb, u_int32_t user) |
| 942 | { | 942 | { |
| 943 | struct sock *sk = skb->sk; | ||
| 944 | #ifdef CONFIG_NETFILTER_DEBUG | 943 | #ifdef CONFIG_NETFILTER_DEBUG |
| 945 | unsigned int olddebug = skb->nf_debug; | 944 | unsigned int olddebug = skb->nf_debug; |
| 946 | #endif | 945 | #endif |
| 947 | 946 | ||
| 948 | if (sk) { | 947 | skb_orphan(skb); |
| 949 | sock_hold(sk); | ||
| 950 | skb_orphan(skb); | ||
| 951 | } | ||
| 952 | 948 | ||
| 953 | local_bh_disable(); | 949 | local_bh_disable(); |
| 954 | skb = ip_defrag(skb, user); | 950 | skb = ip_defrag(skb, user); |
| 955 | local_bh_enable(); | 951 | local_bh_enable(); |
| 956 | 952 | ||
| 957 | if (!skb) { | 953 | if (skb) { |
| 958 | if (sk) | 954 | ip_send_check(skb->nh.iph); |
| 959 | sock_put(sk); | 955 | skb->nfcache |= NFC_ALTERED; |
| 960 | return skb; | ||
| 961 | } | ||
| 962 | |||
| 963 | if (sk) { | ||
| 964 | skb_set_owner_w(skb, sk); | ||
| 965 | sock_put(sk); | ||
| 966 | } | ||
| 967 | |||
| 968 | ip_send_check(skb->nh.iph); | ||
| 969 | skb->nfcache |= NFC_ALTERED; | ||
| 970 | #ifdef CONFIG_NETFILTER_DEBUG | 956 | #ifdef CONFIG_NETFILTER_DEBUG |
| 971 | /* Packet path as if nothing had happened. */ | 957 | /* Packet path as if nothing had happened. */ |
| 972 | skb->nf_debug = olddebug; | 958 | skb->nf_debug = olddebug; |
| 973 | #endif | 959 | #endif |
| 960 | } | ||
| 961 | |||
| 974 | return skb; | 962 | return skb; |
| 975 | } | 963 | } |
| 976 | 964 | ||
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index e5746b674413..eda1fba431a4 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | * communicating with userspace via netlink. | 3 | * communicating with userspace via netlink. |
| 4 | * | 4 | * |
| 5 | * (C) 2000-2002 James Morris <jmorris@intercode.com.au> | 5 | * (C) 2000-2002 James Morris <jmorris@intercode.com.au> |
| 6 | * (C) 2003-2005 Netfilter Core Team <coreteam@netfilter.org> | ||
| 6 | * | 7 | * |
| 7 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
| 8 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
| @@ -17,6 +18,7 @@ | |||
| 17 | * 2005-01-10: Added /proc counter for dropped packets; fixed so | 18 | * 2005-01-10: Added /proc counter for dropped packets; fixed so |
| 18 | * packets aren't delivered to user space if they're going | 19 | * packets aren't delivered to user space if they're going |
| 19 | * to be dropped. | 20 | * to be dropped. |
| 21 | * 2005-05-26: local_bh_{disable,enable} around nf_reinject (Harald Welte) | ||
| 20 | * | 22 | * |
| 21 | */ | 23 | */ |
| 22 | #include <linux/module.h> | 24 | #include <linux/module.h> |
| @@ -71,7 +73,15 @@ static DECLARE_MUTEX(ipqnl_sem); | |||
| 71 | static void | 73 | static void |
| 72 | ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict) | 74 | ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict) |
| 73 | { | 75 | { |
| 76 | /* TCP input path (and probably other bits) assume to be called | ||
| 77 | * from softirq context, not from syscall, like ipq_issue_verdict is | ||
| 78 | * called. TCP input path deadlocks with locks taken from timer | ||
| 79 | * softirq, e.g. We therefore emulate this by local_bh_disable() */ | ||
| 80 | |||
| 81 | local_bh_disable(); | ||
| 74 | nf_reinject(entry->skb, entry->info, verdict); | 82 | nf_reinject(entry->skb, entry->info, verdict); |
| 83 | local_bh_enable(); | ||
| 84 | |||
| 75 | kfree(entry); | 85 | kfree(entry); |
| 76 | } | 86 | } |
| 77 | 87 | ||
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 79835a67a274..5bad504630a3 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
| @@ -4355,16 +4355,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, | |||
| 4355 | goto no_ack; | 4355 | goto no_ack; |
| 4356 | } | 4356 | } |
| 4357 | 4357 | ||
| 4358 | if (eaten) { | 4358 | __tcp_ack_snd_check(sk, 0); |
| 4359 | if (tcp_in_quickack_mode(tp)) { | ||
| 4360 | tcp_send_ack(sk); | ||
| 4361 | } else { | ||
| 4362 | tcp_send_delayed_ack(sk); | ||
| 4363 | } | ||
| 4364 | } else { | ||
| 4365 | __tcp_ack_snd_check(sk, 0); | ||
| 4366 | } | ||
| 4367 | |||
| 4368 | no_ack: | 4359 | no_ack: |
| 4369 | if (eaten) | 4360 | if (eaten) |
| 4370 | __kfree_skb(skb); | 4361 | __kfree_skb(skb); |
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 4a6952e3fee9..7c24e64b443f 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
| @@ -738,7 +738,7 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) | |||
| 738 | unsigned long amount; | 738 | unsigned long amount; |
| 739 | 739 | ||
| 740 | amount = 0; | 740 | amount = 0; |
| 741 | spin_lock_irq(&sk->sk_receive_queue.lock); | 741 | spin_lock_bh(&sk->sk_receive_queue.lock); |
| 742 | skb = skb_peek(&sk->sk_receive_queue); | 742 | skb = skb_peek(&sk->sk_receive_queue); |
| 743 | if (skb != NULL) { | 743 | if (skb != NULL) { |
| 744 | /* | 744 | /* |
| @@ -748,7 +748,7 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) | |||
| 748 | */ | 748 | */ |
| 749 | amount = skb->len - sizeof(struct udphdr); | 749 | amount = skb->len - sizeof(struct udphdr); |
| 750 | } | 750 | } |
| 751 | spin_unlock_irq(&sk->sk_receive_queue.lock); | 751 | spin_unlock_bh(&sk->sk_receive_queue.lock); |
| 752 | return put_user(amount, (int __user *)arg); | 752 | return put_user(amount, (int __user *)arg); |
| 753 | } | 753 | } |
| 754 | 754 | ||
| @@ -848,12 +848,12 @@ csum_copy_err: | |||
| 848 | /* Clear queue. */ | 848 | /* Clear queue. */ |
| 849 | if (flags&MSG_PEEK) { | 849 | if (flags&MSG_PEEK) { |
| 850 | int clear = 0; | 850 | int clear = 0; |
| 851 | spin_lock_irq(&sk->sk_receive_queue.lock); | 851 | spin_lock_bh(&sk->sk_receive_queue.lock); |
| 852 | if (skb == skb_peek(&sk->sk_receive_queue)) { | 852 | if (skb == skb_peek(&sk->sk_receive_queue)) { |
| 853 | __skb_unlink(skb, &sk->sk_receive_queue); | 853 | __skb_unlink(skb, &sk->sk_receive_queue); |
| 854 | clear = 1; | 854 | clear = 1; |
| 855 | } | 855 | } |
| 856 | spin_unlock_irq(&sk->sk_receive_queue.lock); | 856 | spin_unlock_bh(&sk->sk_receive_queue.lock); |
| 857 | if (clear) | 857 | if (clear) |
| 858 | kfree_skb(skb); | 858 | kfree_skb(skb); |
| 859 | } | 859 | } |
| @@ -1334,7 +1334,7 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) | |||
| 1334 | struct sk_buff_head *rcvq = &sk->sk_receive_queue; | 1334 | struct sk_buff_head *rcvq = &sk->sk_receive_queue; |
| 1335 | struct sk_buff *skb; | 1335 | struct sk_buff *skb; |
| 1336 | 1336 | ||
| 1337 | spin_lock_irq(&rcvq->lock); | 1337 | spin_lock_bh(&rcvq->lock); |
| 1338 | while ((skb = skb_peek(rcvq)) != NULL) { | 1338 | while ((skb = skb_peek(rcvq)) != NULL) { |
| 1339 | if (udp_checksum_complete(skb)) { | 1339 | if (udp_checksum_complete(skb)) { |
| 1340 | UDP_INC_STATS_BH(UDP_MIB_INERRORS); | 1340 | UDP_INC_STATS_BH(UDP_MIB_INERRORS); |
| @@ -1345,7 +1345,7 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) | |||
| 1345 | break; | 1345 | break; |
| 1346 | } | 1346 | } |
| 1347 | } | 1347 | } |
| 1348 | spin_unlock_irq(&rcvq->lock); | 1348 | spin_unlock_bh(&rcvq->lock); |
| 1349 | 1349 | ||
| 1350 | /* nothing to see, move along */ | 1350 | /* nothing to see, move along */ |
| 1351 | if (skb == NULL) | 1351 | if (skb == NULL) |
