diff -ruN linux-2.4.26-pre1.orig/include/net/ip_vs.h linux-2.4.26-pre1.udp_unconn/include/net/ip_vs.h --- linux-2.4.26-pre1.orig/include/net/ip_vs.h 2004-03-04 12:00:42.000000000 +0900 +++ linux-2.4.26-pre1.udp_unconn/include/net/ip_vs.h 2004-03-04 18:51:47.000000000 +0900 @@ -19,6 +19,7 @@ */ #define IP_VS_SVC_F_PERSISTENT 0x0001 /* persistent port */ #define IP_VS_SVC_F_HASHED 0x0002 /* hashed entry */ +#define IP_VS_SVC_F_UNCONN_UDP 0x0004 /* connectionless udp */ /* * Destination Server Flags @@ -82,6 +83,7 @@ #define IP_VS_CONN_F_IN_SEQ 0x0400 /* must do input seq adjust */ #define IP_VS_CONN_F_SEQ_MASK 0x0600 /* in/out sequence mask */ #define IP_VS_CONN_F_NO_CPORT 0x0800 /* no client port set yet */ +#define IP_VS_CONN_F_UNCONN_UDP 0x1000 /* connectionless udp */ /* Move it to better place one day, for now keep it unique */ #define NFC_IPVS_PROPERTY 0x10000 @@ -317,6 +319,7 @@ NET_IPV4_VS_EXPIRE_NODEST_CONN=23, NET_IPV4_VS_SYNC_THRESHOLD=24, NET_IPV4_VS_NAT_ICMP_SEND=25, + NET_IPV4_VS_TO_UDP_UNCONN=26, NET_IPV4_VS_LAST }; @@ -338,6 +341,7 @@ IP_VS_S_SYNACK, IP_VS_S_UDP, IP_VS_S_ICMP, + IP_VS_S_UDP_UNCONN, IP_VS_S_LAST }; @@ -603,6 +607,10 @@ ip_vs_conn_new(int proto, __u32 caddr, __u16 cport, __u32 vaddr, __u16 vport, __u32 daddr, __u16 dport, unsigned flags, struct ip_vs_dest *dest); +extern struct ip_vs_conn * +ip_vs_conn_new_no_hash(int proto, __u32 caddr, __u16 cport, __u32 vaddr, + __u16 vport, __u32 daddr, __u16 dport, + unsigned flags, struct ip_vs_dest *dest); extern void ip_vs_conn_expire_now(struct ip_vs_conn *cp); extern const char * ip_vs_state_name(int state); diff -ruN linux-2.4.26-pre1.orig/net/ipv4/ipvs/ip_vs_conn.c linux-2.4.26-pre1.udp_unconn/net/ipv4/ipvs/ip_vs_conn.c --- linux-2.4.26-pre1.orig/net/ipv4/ipvs/ip_vs_conn.c 2004-03-04 12:00:42.000000000 +0900 +++ linux-2.4.26-pre1.udp_unconn/net/ipv4/ipvs/ip_vs_conn.c 2004-03-04 18:51:47.000000000 +0900 @@ -318,6 +318,7 @@ [IP_VS_S_SYNACK] = 120*HZ, [IP_VS_S_UDP] = 5*60*HZ, [IP_VS_S_ICMP] = 1*60*HZ, + [IP_VS_S_UDP_UNCONN] = 2*HZ, [IP_VS_S_LAST] = 2*HZ, }, /* timeout */ }; @@ -340,6 +341,7 @@ [IP_VS_S_SYNACK] = 100*HZ, [IP_VS_S_UDP] = 3*60*HZ, [IP_VS_S_ICMP] = 1*60*HZ, + [IP_VS_S_UDP_UNCONN] = 2*HZ, [IP_VS_S_LAST] = 2*HZ, }, /* timeout */ }; @@ -367,6 +369,7 @@ [IP_VS_S_SYNACK] = "SYNACK", [IP_VS_S_UDP] = "UDP", [IP_VS_S_ICMP] = "ICMP", + [IP_VS_S_UDP_UNCONN] = "UDP_UNCONN", [IP_VS_S_LAST] = "BUG!", }; @@ -570,7 +573,10 @@ ret = vs_tcp_state(cp, state_off, tp); break; case IPPROTO_UDP: - ret = vs_set_state_timeout(cp, IP_VS_S_UDP); + if (unlikely(cp->flags & IP_VS_CONN_F_UNCONN_UDP)) + ret = vs_set_state_timeout(cp, IP_VS_S_UDP_UNCONN); + else + ret = vs_set_state_timeout(cp, IP_VS_S_UDP); break; case IPPROTO_ICMP: ret = vs_set_state_timeout(cp, IP_VS_S_ICMP); @@ -1176,6 +1182,7 @@ static void ip_vs_conn_expire(unsigned long data) { struct ip_vs_conn *cp = (struct ip_vs_conn *)data; + __u16 flags; if (cp->timeout_table) cp->timeout = cp->timeout_table->timeout[IP_VS_S_TIME_WAIT]; @@ -1196,7 +1203,9 @@ /* * unhash it if it is hashed in the conn table */ - ip_vs_conn_unhash(cp); + flags = cp->flags; + if (likely(flags & IP_VS_CONN_F_HASHED)) + ip_vs_conn_unhash(cp); /* * refcnt==1 implies I'm the only one referrer @@ -1222,7 +1231,8 @@ } /* hash it back to the table */ - ip_vs_conn_hash(cp); + if (likely(flags & IP_VS_CONN_F_HASHED)) + ip_vs_conn_hash(cp); expire_later: IP_VS_DBG(7, "delayed: refcnt-1=%d conn.n_control=%d\n", @@ -1244,9 +1254,9 @@ * Create a new connection entry and hash it into the ip_vs_conn_tab. */ struct ip_vs_conn * -ip_vs_conn_new(int proto, __u32 caddr, __u16 cport, __u32 vaddr, __u16 vport, - __u32 daddr, __u16 dport, unsigned flags, - struct ip_vs_dest *dest) +ip_vs_conn_new_no_hash(int proto, __u32 caddr, __u16 cport, __u32 vaddr, + __u16 vport, __u32 daddr, __u16 dport, unsigned flags, + struct ip_vs_dest *dest) { struct ip_vs_conn *cp; @@ -1300,7 +1310,26 @@ */ atomic_set(&cp->refcnt, 1); - /* Hash it in the ip_vs_conn_tab finally */ + return cp; +} + +/* + * Create a new connection entry and hash it into the ip_vs_conn_tab. + */ +struct ip_vs_conn * +ip_vs_conn_new(int proto, __u32 caddr, __u16 cport, __u32 vaddr, __u16 vport, + __u32 daddr, __u16 dport, unsigned flags, + struct ip_vs_dest *dest) +{ + struct ip_vs_conn *cp; + + /* Create the entry */ + cp = ip_vs_conn_new_no_hash(proto, caddr, cport, vaddr, vport, daddr, + dport, flags, dest); + if (cp == NULL) + return NULL; + + /* Hash it in the ip_vs_conn_tab */ ip_vs_conn_hash(cp); return cp; diff -ruN linux-2.4.26-pre1.orig/net/ipv4/ipvs/ip_vs_core.c linux-2.4.26-pre1.udp_unconn/net/ipv4/ipvs/ip_vs_core.c --- linux-2.4.26-pre1.orig/net/ipv4/ipvs/ip_vs_core.c 2003-11-29 03:26:21.000000000 +0900 +++ linux-2.4.26-pre1.udp_unconn/net/ipv4/ipvs/ip_vs_core.c 2004-03-04 18:51:47.000000000 +0900 @@ -293,12 +293,21 @@ /* * Create a new connection according to the template */ - cp = ip_vs_conn_new(iph->protocol, - iph->saddr, portp[0], - iph->daddr, portp[1], - dest->addr, dport, - 0, - dest); + + if (unlikely(svc->flags & IP_VS_SVC_F_UNCONN_UDP)) + cp = ip_vs_conn_new_no_hash(iph->protocol, + iph->saddr, portp[0], + iph->daddr, portp[1], + dest->addr, dport, + IP_VS_CONN_F_UNCONN_UDP, + dest); + else + cp = ip_vs_conn_new(iph->protocol, + iph->saddr, portp[0], + iph->daddr, portp[1], + dest->addr, dport, + 0, + dest); if (cp == NULL) { ip_vs_conn_put(ct); return NULL; @@ -360,12 +369,20 @@ /* * Create a connection entry. */ - cp = ip_vs_conn_new(iph->protocol, - iph->saddr, portp[0], - iph->daddr, portp[1], - dest->addr, dest->port?dest->port:portp[1], - 0, - dest); + if (unlikely(svc->flags & IP_VS_SVC_F_UNCONN_UDP)) + cp = ip_vs_conn_new_no_hash(iph->protocol, + iph->saddr, portp[0], + iph->daddr, portp[1], + dest->addr, dest->port?dest->port:portp[1], + IP_VS_CONN_F_UNCONN_UDP, + dest); + else + cp = ip_vs_conn_new(iph->protocol, + iph->saddr, portp[0], + iph->daddr, portp[1], + dest->addr, dest->port?dest->port:portp[1], + 0, + dest); if (cp == NULL) return NULL; @@ -1031,6 +1048,7 @@ struct ip_vs_service *svc; int ihl; int ret; + __u16 svc_flags; /* * Big tappo: only PACKET_HOST (nor loopback neither mcasts) @@ -1086,6 +1104,7 @@ if (!cp) return ip_vs_leave(svc, skb); ip_vs_conn_stats(cp, svc); + svc_flags = svc->flags; ip_vs_service_put(svc); } diff -ruN linux-2.4.26-pre1.orig/net/ipv4/ipvs/ip_vs_ctl.c linux-2.4.26-pre1.udp_unconn/net/ipv4/ipvs/ip_vs_ctl.c --- linux-2.4.26-pre1.orig/net/ipv4/ipvs/ip_vs_ctl.c 2004-03-04 12:00:42.000000000 +0900 +++ linux-2.4.26-pre1.udp_unconn/net/ipv4/ipvs/ip_vs_ctl.c 2004-03-04 18:53:19.000000000 +0900 @@ -1421,6 +1421,9 @@ {NET_IPV4_VS_TO_ICMP, "timeout_icmp", &vs_timeout_table_dos.timeout[IP_VS_S_ICMP], sizeof(int), 0644, NULL, &proc_dointvec_jiffies}, + {NET_IPV4_VS_TO_UDP_UNCONN, "timeout_udp_unconn", + &vs_timeout_table_dos.timeout[IP_VS_S_UDP_UNCONN], + sizeof(int), 0644, NULL, &proc_dointvec_jiffies}, {NET_IPV4_VS_CACHE_BYPASS, "cache_bypass", &sysctl_ip_vs_cache_bypass, sizeof(int), 0644, NULL, &proc_dointvec}, @@ -1510,11 +1513,13 @@ else temp2[0] = '\0'; - sprintf(temp, "%s %08X:%04X %s %s", + sprintf(temp, "%s %08X:%04X %s %s %s", ip_vs_proto_name(svc->protocol), ntohl(svc->addr), ntohs(svc->port), - svc->scheduler->name, temp2); + svc->scheduler->name, temp2, + svc->flags & IP_VS_SVC_F_UNCONN_UDP ? + "unconn_udp" : ""); len += sprintf(buf+len, "%-63s\n", temp); if (len >= length) goto done; @@ -1555,9 +1560,11 @@ else temp2[0] = '\0'; - sprintf(temp, "FWM %08X %s %s", + sprintf(temp, "FWM %08X %s %s %s", svc->fwmark, - svc->scheduler->name, temp2); + svc->scheduler->name, temp2, + svc->flags & IP_VS_SVC_F_UNCONN_UDP ? + "unconn_udp" : ""); len += sprintf(buf+len, "%-63s\n", temp); if (len >= length) goto done; @@ -1745,6 +1752,19 @@ } /* + * IP_VS_SVC_F_UNCONN_UDP is not valid for a IPPROTO_TCP service + */ + if (urule->protocol==IPPROTO_TCP && + urule->vs_flags&IP_VS_SVC_F_UNCONN_UDP) { + IP_VS_INFO("vs_ctl: IP_VS_SVC_F_UNCONN_UDP used with " + "IPPROTO_TCP: %d %d.%d.%d.%d:%d %s\n", + urule->protocol, NIPQUAD(urule->vaddr), + ntohs(urule->vport), urule->sched_name); + ret = -EFAULT; + goto out_unlock; + } + + /* * Lookup the exact service by or fwmark */ if (urule->vfwmark == 0)