blob: 9c558c40bfbb18dd8a4d82e3d9248ca63776c539 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * ip_vs_proto_udp.c: UDP load balancing support for IPVS
3 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
5 * Julian Anastasov <ja@ssi.bg>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 * Changes:
13 *
14 */
15
Hannes Eder9aada7a2009-07-30 14:29:44 -070016#define KMSG_COMPONENT "IPVS"
17#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
18
Arnaldo Carvalho de Melo14c85022005-12-27 02:43:12 -020019#include <linux/in.h>
20#include <linux/ip.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/kernel.h>
Herbert Xuaf1e1cf2007-10-14 00:39:33 -070022#include <linux/netfilter.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/netfilter_ipv4.h>
Arnaldo Carvalho de Melo14c85022005-12-27 02:43:12 -020024#include <linux/udp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
26#include <net/ip_vs.h>
Arnaldo Carvalho de Meloc9bdd4b2007-03-12 20:09:15 -030027#include <net/ip.h>
Stephen Rothwell63f2c042008-09-12 23:23:50 -070028#include <net/ip6_checksum.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
Linus Torvalds1da177e2005-04-16 15:20:36 -070030static int
Julius Volz51ef3482008-09-02 15:55:40 +020031udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
Linus Torvalds1da177e2005-04-16 15:20:36 -070032 int *verdict, struct ip_vs_conn **cpp)
33{
34 struct ip_vs_service *svc;
35 struct udphdr _udph, *uh;
Julius Volz3c2e0502008-09-02 15:55:38 +020036 struct ip_vs_iphdr iph;
Linus Torvalds1da177e2005-04-16 15:20:36 -070037
Julius Volz51ef3482008-09-02 15:55:40 +020038 ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
Julius Volz3c2e0502008-09-02 15:55:38 +020039
40 uh = skb_header_pointer(skb, iph.len, sizeof(_udph), &_udph);
Linus Torvalds1da177e2005-04-16 15:20:36 -070041 if (uh == NULL) {
42 *verdict = NF_DROP;
43 return 0;
44 }
45
Julius Volz51ef3482008-09-02 15:55:40 +020046 svc = ip_vs_service_get(af, skb->mark, iph.protocol,
Julius Volz3c2e0502008-09-02 15:55:38 +020047 &iph.daddr, uh->dest);
48 if (svc) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070049 if (ip_vs_todrop()) {
50 /*
51 * It seems that we are very loaded.
52 * We have to drop this packet :(
53 */
54 ip_vs_service_put(svc);
55 *verdict = NF_DROP;
56 return 0;
57 }
58
59 /*
60 * Let the virtual server select a real server for the
61 * incoming connection, and create a connection entry.
62 */
63 *cpp = ip_vs_schedule(svc, skb);
64 if (!*cpp) {
65 *verdict = ip_vs_leave(svc, skb, pp);
66 return 0;
67 }
68 ip_vs_service_put(svc);
69 }
70 return 1;
71}
72
73
74static inline void
Julius Volz0bbdd422008-09-02 15:55:42 +020075udp_fast_csum_update(int af, struct udphdr *uhdr,
76 const union nf_inet_addr *oldip,
77 const union nf_inet_addr *newip,
Al Viro014d7302006-09-28 14:29:52 -070078 __be16 oldport, __be16 newport)
Linus Torvalds1da177e2005-04-16 15:20:36 -070079{
Julius Volz0bbdd422008-09-02 15:55:42 +020080#ifdef CONFIG_IP_VS_IPV6
81 if (af == AF_INET6)
82 uhdr->check =
83 csum_fold(ip_vs_check_diff16(oldip->ip6, newip->ip6,
84 ip_vs_check_diff2(oldport, newport,
85 ~csum_unfold(uhdr->check))));
86 else
87#endif
88 uhdr->check =
89 csum_fold(ip_vs_check_diff4(oldip->ip, newip->ip,
90 ip_vs_check_diff2(oldport, newport,
91 ~csum_unfold(uhdr->check))));
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 if (!uhdr->check)
Al Virof6ab0282006-11-16 02:36:50 -080093 uhdr->check = CSUM_MANGLED_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070094}
95
Simon Horman503e81f2008-09-08 12:04:21 +100096static inline void
97udp_partial_csum_update(int af, struct udphdr *uhdr,
98 const union nf_inet_addr *oldip,
99 const union nf_inet_addr *newip,
100 __be16 oldlen, __be16 newlen)
101{
102#ifdef CONFIG_IP_VS_IPV6
103 if (af == AF_INET6)
104 uhdr->check =
Julian Anastasov5bc90682010-10-17 16:14:31 +0300105 ~csum_fold(ip_vs_check_diff16(oldip->ip6, newip->ip6,
Simon Horman503e81f2008-09-08 12:04:21 +1000106 ip_vs_check_diff2(oldlen, newlen,
Julian Anastasov5bc90682010-10-17 16:14:31 +0300107 csum_unfold(uhdr->check))));
Simon Horman503e81f2008-09-08 12:04:21 +1000108 else
109#endif
110 uhdr->check =
Julian Anastasov5bc90682010-10-17 16:14:31 +0300111 ~csum_fold(ip_vs_check_diff4(oldip->ip, newip->ip,
Simon Horman503e81f2008-09-08 12:04:21 +1000112 ip_vs_check_diff2(oldlen, newlen,
Julian Anastasov5bc90682010-10-17 16:14:31 +0300113 csum_unfold(uhdr->check))));
Simon Horman503e81f2008-09-08 12:04:21 +1000114}
115
116
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117static int
Herbert Xu3db05fe2007-10-15 00:53:15 -0700118udp_snat_handler(struct sk_buff *skb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
120{
121 struct udphdr *udph;
Julius Volz0bbdd422008-09-02 15:55:42 +0200122 unsigned int udphoff;
Simon Horman503e81f2008-09-08 12:04:21 +1000123 int oldlen;
Julian Anastasov8b27b102010-10-17 16:17:20 +0300124 int payload_csum = 0;
Julius Volz0bbdd422008-09-02 15:55:42 +0200125
126#ifdef CONFIG_IP_VS_IPV6
127 if (cp->af == AF_INET6)
128 udphoff = sizeof(struct ipv6hdr);
129 else
130#endif
131 udphoff = ip_hdrlen(skb);
Simon Horman503e81f2008-09-08 12:04:21 +1000132 oldlen = skb->len - udphoff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133
134 /* csum_check requires unshared skb */
Herbert Xu3db05fe2007-10-15 00:53:15 -0700135 if (!skb_make_writable(skb, udphoff+sizeof(*udph)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 return 0;
137
138 if (unlikely(cp->app != NULL)) {
Julian Anastasov8b27b102010-10-17 16:17:20 +0300139 int ret;
140
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 /* Some checks before mangling */
Julius Volz0bbdd422008-09-02 15:55:42 +0200142 if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 return 0;
144
145 /*
146 * Call application helper if needed
147 */
Julian Anastasov8b27b102010-10-17 16:17:20 +0300148 if (!(ret = ip_vs_app_pkt_out(cp, skb)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 return 0;
Julian Anastasov8b27b102010-10-17 16:17:20 +0300150 /* ret=2: csum update is needed after payload mangling */
151 if (ret == 1)
152 oldlen = skb->len - udphoff;
153 else
154 payload_csum = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 }
156
Julius Volz0bbdd422008-09-02 15:55:42 +0200157 udph = (void *)skb_network_header(skb) + udphoff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 udph->source = cp->vport;
159
160 /*
161 * Adjust UDP checksums
162 */
Simon Horman503e81f2008-09-08 12:04:21 +1000163 if (skb->ip_summed == CHECKSUM_PARTIAL) {
164 udp_partial_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr,
Harvey Harrisonca620592008-11-06 23:09:56 -0800165 htons(oldlen),
166 htons(skb->len - udphoff));
Julian Anastasov8b27b102010-10-17 16:17:20 +0300167 } else if (!payload_csum && (udph->check != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 /* Only port and addr are changed, do fast csum update */
Julius Volz0bbdd422008-09-02 15:55:42 +0200169 udp_fast_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 cp->dport, cp->vport);
Herbert Xu3db05fe2007-10-15 00:53:15 -0700171 if (skb->ip_summed == CHECKSUM_COMPLETE)
Julian Anastasov8b27b102010-10-17 16:17:20 +0300172 skb->ip_summed = (cp->app && pp->csum_check) ?
173 CHECKSUM_UNNECESSARY : CHECKSUM_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 } else {
175 /* full checksum calculation */
176 udph->check = 0;
Herbert Xu3db05fe2007-10-15 00:53:15 -0700177 skb->csum = skb_checksum(skb, udphoff, skb->len - udphoff, 0);
Julius Volz0bbdd422008-09-02 15:55:42 +0200178#ifdef CONFIG_IP_VS_IPV6
179 if (cp->af == AF_INET6)
180 udph->check = csum_ipv6_magic(&cp->vaddr.in6,
181 &cp->caddr.in6,
182 skb->len - udphoff,
183 cp->protocol, skb->csum);
184 else
185#endif
186 udph->check = csum_tcpudp_magic(cp->vaddr.ip,
187 cp->caddr.ip,
188 skb->len - udphoff,
189 cp->protocol,
190 skb->csum);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 if (udph->check == 0)
Al Virof6ab0282006-11-16 02:36:50 -0800192 udph->check = CSUM_MANGLED_0;
Julian Anastasov8b27b102010-10-17 16:17:20 +0300193 skb->ip_summed = CHECKSUM_UNNECESSARY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n",
195 pp->name, udph->check,
196 (char*)&(udph->check) - (char*)udph);
197 }
198 return 1;
199}
200
201
202static int
Herbert Xu3db05fe2007-10-15 00:53:15 -0700203udp_dnat_handler(struct sk_buff *skb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
205{
206 struct udphdr *udph;
Julius Volz0bbdd422008-09-02 15:55:42 +0200207 unsigned int udphoff;
Simon Horman503e81f2008-09-08 12:04:21 +1000208 int oldlen;
Julian Anastasov8b27b102010-10-17 16:17:20 +0300209 int payload_csum = 0;
Julius Volz0bbdd422008-09-02 15:55:42 +0200210
211#ifdef CONFIG_IP_VS_IPV6
212 if (cp->af == AF_INET6)
213 udphoff = sizeof(struct ipv6hdr);
214 else
215#endif
216 udphoff = ip_hdrlen(skb);
Simon Horman503e81f2008-09-08 12:04:21 +1000217 oldlen = skb->len - udphoff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
219 /* csum_check requires unshared skb */
Herbert Xu3db05fe2007-10-15 00:53:15 -0700220 if (!skb_make_writable(skb, udphoff+sizeof(*udph)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 return 0;
222
223 if (unlikely(cp->app != NULL)) {
Julian Anastasov8b27b102010-10-17 16:17:20 +0300224 int ret;
225
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 /* Some checks before mangling */
Julius Volz0bbdd422008-09-02 15:55:42 +0200227 if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 return 0;
229
230 /*
231 * Attempt ip_vs_app call.
232 * It will fix ip_vs_conn
233 */
Julian Anastasov8b27b102010-10-17 16:17:20 +0300234 if (!(ret = ip_vs_app_pkt_in(cp, skb)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 return 0;
Julian Anastasov8b27b102010-10-17 16:17:20 +0300236 /* ret=2: csum update is needed after payload mangling */
237 if (ret == 1)
238 oldlen = skb->len - udphoff;
239 else
240 payload_csum = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 }
242
Julius Volz0bbdd422008-09-02 15:55:42 +0200243 udph = (void *)skb_network_header(skb) + udphoff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 udph->dest = cp->dport;
245
246 /*
247 * Adjust UDP checksums
248 */
Simon Horman503e81f2008-09-08 12:04:21 +1000249 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Julian Anastasov5bc90682010-10-17 16:14:31 +0300250 udp_partial_csum_update(cp->af, udph, &cp->vaddr, &cp->daddr,
Harvey Harrisonca620592008-11-06 23:09:56 -0800251 htons(oldlen),
252 htons(skb->len - udphoff));
Julian Anastasov8b27b102010-10-17 16:17:20 +0300253 } else if (!payload_csum && (udph->check != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 /* Only port and addr are changed, do fast csum update */
Julius Volz0bbdd422008-09-02 15:55:42 +0200255 udp_fast_csum_update(cp->af, udph, &cp->vaddr, &cp->daddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 cp->vport, cp->dport);
Herbert Xu3db05fe2007-10-15 00:53:15 -0700257 if (skb->ip_summed == CHECKSUM_COMPLETE)
Julian Anastasov8b27b102010-10-17 16:17:20 +0300258 skb->ip_summed = (cp->app && pp->csum_check) ?
259 CHECKSUM_UNNECESSARY : CHECKSUM_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 } else {
261 /* full checksum calculation */
262 udph->check = 0;
Herbert Xu3db05fe2007-10-15 00:53:15 -0700263 skb->csum = skb_checksum(skb, udphoff, skb->len - udphoff, 0);
Julius Volz0bbdd422008-09-02 15:55:42 +0200264#ifdef CONFIG_IP_VS_IPV6
265 if (cp->af == AF_INET6)
266 udph->check = csum_ipv6_magic(&cp->caddr.in6,
267 &cp->daddr.in6,
268 skb->len - udphoff,
269 cp->protocol, skb->csum);
270 else
271#endif
272 udph->check = csum_tcpudp_magic(cp->caddr.ip,
273 cp->daddr.ip,
274 skb->len - udphoff,
275 cp->protocol,
276 skb->csum);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 if (udph->check == 0)
Al Virof6ab0282006-11-16 02:36:50 -0800278 udph->check = CSUM_MANGLED_0;
Herbert Xu3db05fe2007-10-15 00:53:15 -0700279 skb->ip_summed = CHECKSUM_UNNECESSARY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 }
281 return 1;
282}
283
284
285static int
Julius Volz51ef3482008-09-02 15:55:40 +0200286udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287{
288 struct udphdr _udph, *uh;
Julius Volz51ef3482008-09-02 15:55:40 +0200289 unsigned int udphoff;
290
291#ifdef CONFIG_IP_VS_IPV6
292 if (af == AF_INET6)
293 udphoff = sizeof(struct ipv6hdr);
294 else
295#endif
296 udphoff = ip_hdrlen(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
298 uh = skb_header_pointer(skb, udphoff, sizeof(_udph), &_udph);
299 if (uh == NULL)
300 return 0;
301
302 if (uh->check != 0) {
303 switch (skb->ip_summed) {
304 case CHECKSUM_NONE:
305 skb->csum = skb_checksum(skb, udphoff,
306 skb->len - udphoff, 0);
Patrick McHardy84fa7932006-08-29 16:44:56 -0700307 case CHECKSUM_COMPLETE:
Julius Volz51ef3482008-09-02 15:55:40 +0200308#ifdef CONFIG_IP_VS_IPV6
309 if (af == AF_INET6) {
310 if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
311 &ipv6_hdr(skb)->daddr,
312 skb->len - udphoff,
313 ipv6_hdr(skb)->nexthdr,
314 skb->csum)) {
315 IP_VS_DBG_RL_PKT(0, pp, skb, 0,
316 "Failed checksum for");
317 return 0;
318 }
319 } else
320#endif
321 if (csum_tcpudp_magic(ip_hdr(skb)->saddr,
322 ip_hdr(skb)->daddr,
323 skb->len - udphoff,
324 ip_hdr(skb)->protocol,
325 skb->csum)) {
326 IP_VS_DBG_RL_PKT(0, pp, skb, 0,
327 "Failed checksum for");
328 return 0;
329 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 break;
331 default:
Patrick McHardy84fa7932006-08-29 16:44:56 -0700332 /* No need to checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 break;
334 }
335 }
336 return 1;
337}
338
339
340/*
341 * Note: the caller guarantees that only one of register_app,
342 * unregister_app or app_conn_bind is called each time.
343 */
344
345#define UDP_APP_TAB_BITS 4
346#define UDP_APP_TAB_SIZE (1 << UDP_APP_TAB_BITS)
347#define UDP_APP_TAB_MASK (UDP_APP_TAB_SIZE - 1)
348
349static struct list_head udp_apps[UDP_APP_TAB_SIZE];
350static DEFINE_SPINLOCK(udp_app_lock);
351
Al Viro75e7ce62006-11-14 21:13:28 -0800352static inline __u16 udp_app_hashkey(__be16 port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353{
Al Viro75e7ce62006-11-14 21:13:28 -0800354 return (((__force u16)port >> UDP_APP_TAB_BITS) ^ (__force u16)port)
355 & UDP_APP_TAB_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356}
357
358
359static int udp_register_app(struct ip_vs_app *inc)
360{
361 struct ip_vs_app *i;
Al Viro75e7ce62006-11-14 21:13:28 -0800362 __u16 hash;
363 __be16 port = inc->port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 int ret = 0;
365
366 hash = udp_app_hashkey(port);
367
368
369 spin_lock_bh(&udp_app_lock);
370 list_for_each_entry(i, &udp_apps[hash], p_list) {
371 if (i->port == port) {
372 ret = -EEXIST;
373 goto out;
374 }
375 }
376 list_add(&inc->p_list, &udp_apps[hash]);
377 atomic_inc(&ip_vs_protocol_udp.appcnt);
378
379 out:
380 spin_unlock_bh(&udp_app_lock);
381 return ret;
382}
383
384
385static void
386udp_unregister_app(struct ip_vs_app *inc)
387{
388 spin_lock_bh(&udp_app_lock);
389 atomic_dec(&ip_vs_protocol_udp.appcnt);
390 list_del(&inc->p_list);
391 spin_unlock_bh(&udp_app_lock);
392}
393
394
395static int udp_app_conn_bind(struct ip_vs_conn *cp)
396{
397 int hash;
398 struct ip_vs_app *inc;
399 int result = 0;
400
401 /* Default binding: bind app only for NAT */
402 if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ)
403 return 0;
404
405 /* Lookup application incarnations and bind the right one */
406 hash = udp_app_hashkey(cp->vport);
407
408 spin_lock(&udp_app_lock);
409 list_for_each_entry(inc, &udp_apps[hash], p_list) {
410 if (inc->port == cp->vport) {
411 if (unlikely(!ip_vs_app_inc_get(inc)))
412 break;
413 spin_unlock(&udp_app_lock);
414
Hannes Eder1e3e2382009-08-02 11:05:41 +0000415 IP_VS_DBG_BUF(9, "%s(): Binding conn %s:%u->"
Julius Volzcfc78c52008-09-02 15:55:53 +0200416 "%s:%u to app %s on port %u\n",
417 __func__,
418 IP_VS_DBG_ADDR(cp->af, &cp->caddr),
419 ntohs(cp->cport),
420 IP_VS_DBG_ADDR(cp->af, &cp->vaddr),
421 ntohs(cp->vport),
422 inc->name, ntohs(inc->port));
423
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 cp->app = inc;
425 if (inc->init_conn)
426 result = inc->init_conn(inc, cp);
427 goto out;
428 }
429 }
430 spin_unlock(&udp_app_lock);
431
432 out:
433 return result;
434}
435
436
437static int udp_timeouts[IP_VS_UDP_S_LAST+1] = {
438 [IP_VS_UDP_S_NORMAL] = 5*60*HZ,
439 [IP_VS_UDP_S_LAST] = 2*HZ,
440};
441
Jan Engelhardt36cbd3d2009-08-05 10:42:58 -0700442static const char *const udp_state_name_table[IP_VS_UDP_S_LAST+1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 [IP_VS_UDP_S_NORMAL] = "UDP",
444 [IP_VS_UDP_S_LAST] = "BUG!",
445};
446
447
448static int
449udp_set_state_timeout(struct ip_vs_protocol *pp, char *sname, int to)
450{
451 return ip_vs_set_state_timeout(pp->timeout_table, IP_VS_UDP_S_LAST,
452 udp_state_name_table, sname, to);
453}
454
455static const char * udp_state_name(int state)
456{
457 if (state >= IP_VS_UDP_S_LAST)
458 return "ERR!";
459 return udp_state_name_table[state] ? udp_state_name_table[state] : "?";
460}
461
462static int
463udp_state_transition(struct ip_vs_conn *cp, int direction,
464 const struct sk_buff *skb,
465 struct ip_vs_protocol *pp)
466{
467 cp->timeout = pp->timeout_table[IP_VS_UDP_S_NORMAL];
468 return 1;
469}
470
471static void udp_init(struct ip_vs_protocol *pp)
472{
473 IP_VS_INIT_HASH_TABLE(udp_apps);
474 pp->timeout_table = udp_timeouts;
475}
476
477static void udp_exit(struct ip_vs_protocol *pp)
478{
479}
480
481
482struct ip_vs_protocol ip_vs_protocol_udp = {
483 .name = "UDP",
484 .protocol = IPPROTO_UDP,
Julian Anastasov2ad17de2008-04-29 03:21:23 -0700485 .num_states = IP_VS_UDP_S_LAST,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 .dont_defrag = 0,
487 .init = udp_init,
488 .exit = udp_exit,
489 .conn_schedule = udp_conn_schedule,
Simon Horman5c0d2372010-08-02 17:12:44 +0200490 .conn_in_get = ip_vs_conn_in_get_proto,
491 .conn_out_get = ip_vs_conn_out_get_proto,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 .snat_handler = udp_snat_handler,
493 .dnat_handler = udp_dnat_handler,
494 .csum_check = udp_csum_check,
495 .state_transition = udp_state_transition,
496 .state_name = udp_state_name,
497 .register_app = udp_register_app,
498 .unregister_app = udp_unregister_app,
499 .app_conn_bind = udp_app_conn_bind,
500 .debug_packet = ip_vs_tcpudp_debug_packet,
501 .timeout_change = NULL,
502 .set_state_timeout = udp_set_state_timeout,
503};