Messages in this thread Patch in this message | | | Date | Mon, 23 Feb 1998 15:41:28 -0300 (ART) | From | JuanJo Ciarlante <> | Subject | [PATCH (masq)] 2.0.33 crashes |
| |
Hi! I've attached a patch that *could* solve masquerading related 2.0.33 freezes. It changes: - use soft (instead of hard, cli() ) irq locking for . control connection handling (eg. ftp) . /proc/net/ip_masquerade - [bonus:] cleanup ip_autofw timers when deleting/flushing.
It will be great if ppl reporting freezes could test this (greater if it solves them :))
Regards...
-- Juanjo http://juanjox.home.ml.org
--- linux/include/net/ip_masq.h.dist Tue Dec 2 19:20:39 1997 +++ linux/include/net/ip_masq.h Mon Feb 23 09:57:43 1998 @@ -1,5 +1,7 @@ /* * IP masquerading functionality definitions + * + * $Id: ip_masq.h,v 0.12 1998/02/23 11:41:19 jjo Exp jjo $ */ #ifndef _IP_MASQ_H @@ -32,6 +34,7 @@ #define MASQUERADE_EXPIRE_TCP 15*60*HZ #define MASQUERADE_EXPIRE_TCP_FIN 2*60*HZ #define MASQUERADE_EXPIRE_UDP 5*60*HZ +#define MASQUERADE_EXPIRE_RETRY 1*60*HZ /* * ICMP can no longer be modified on the fly using an ioctl - this * define is the only way to change the timeouts @@ -51,7 +54,9 @@ #define IP_MASQ_F_SAW_FIN (IP_MASQ_F_SAW_FIN_IN | \ IP_MASQ_F_SAW_FIN_OUT) /* tcp fin pkts seen */ +#if 0 #define IP_MASQ_F_CONTROL 0x100 /* this is a control channel */ +#endif #define IP_MASQ_F_NO_SPORT 0x200 /* no sport set yet */ #define IP_MASQ_F_FTP_PASV 0x400 /* ftp PASV command just issued */ #define IP_MASQ_F_NO_REPLY 0x800 /* no reply yet from outside */ @@ -83,7 +88,8 @@ struct ip_masq_app *app; /* bound ip_masq_app object */ void *app_data; /* Application private data */ unsigned flags; /* status flags */ - struct ip_masq *control; /* Corresponding control connection */ + struct ip_masq *control; /* Master control connection */ + atomic_t n_control; /* Number of "controlled" masqs */ }; /* @@ -124,6 +130,10 @@ extern struct ip_masq *ip_masq_new(struct device *dev, int proto, __u32 saddr, __u16 sport, __u32 daddr, __u16 dport, unsigned flags); extern void ip_masq_set_expire(struct ip_masq *ms, unsigned long tout); +extern void ip_masq_control_add(struct ip_masq *ms, struct ip_masq* ctl_ms); +extern void ip_masq_control_del(struct ip_masq *ms); +extern struct ip_masq * ip_masq_control_get(struct ip_masq *ms); + #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW extern void ip_autofw_expire(unsigned long data); #endif @@ -199,6 +209,81 @@ #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW extern struct ip_autofw * ip_autofw_hosts; #endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */ + +/* + * atomic_t stuff + */ +#define ATOMIC_INIT(x) (x) +#define atomic_read(px) (*(px)) + + +/* + * Locking stuff + */ + + +static __inline__ void ip_masq_lock(atomic_t *lock, int rw) +{ +#if 0 + if (rw) +#endif + start_bh_atomic(); + atomic_inc(lock); +} + +static __inline__ void ip_masq_unlock(atomic_t *lock, int rw) +{ + atomic_dec(lock); +#if 0 + if (rw) +#endif + end_bh_atomic(); +} + +/* + * Sleep-able lockzzz... + */ +static __inline__ void ip_masq_lockz(atomic_t *lock, struct wait_queue ** waitq, int rw) +{ + if (rw) + while(atomic_read(lock)) sleep_on(waitq); + ip_masq_lock(lock, rw); +} + +static __inline__ void ip_masq_unlockz(atomic_t *lock, struct wait_queue ** waitq, int rw) +{ + ip_masq_unlock(lock, rw); + if (rw) + wake_up(waitq); +} + +/* + * Perfect for winning races ... ;) + */ +static __inline__ int ip_masq_nlocks(atomic_t *lock) +{ + return atomic_read(lock); +} + +extern atomic_t __ip_masq_lock; + +/* + * Debugging stuff + */ + + +#define IP_MASQ_INFO(msg...) \ + printk(KERN_INFO "IP_MASQ:" ## msg) + +#define IP_MASQ_DEBUG(msg...) \ + printk(KERN_DEBUG "IP_MASQ:" ## msg) + +#define IP_MASQ_ERR(msg...) \ + printk(KERN_ERR "IP_MASQ:" ## msg) + +#define IP_MASQ_WARNING(msg...) \ + printk(KERN_WARNING "IP_MASQ:" ## msg) + #endif /* __KERNEL__ */ --- linux/net/ipv4/ip_masq.c.dist Tue Aug 5 14:44:26 1997 +++ linux/net/ipv4/ip_masq.c Mon Feb 23 09:06:36 1998 @@ -4,6 +4,8 @@ * * Copyright (c) 1994 Pauline Middelink * + * $Id: ip_masq.c,v 0.12 1998/02/23 11:40:49 jjo Exp jjo $ + * * See ip_fw.c for original log * * Fixes: @@ -20,6 +22,8 @@ * Delian Delchev : Added support for ICMP requests and replys * Nigel Metheringham : ICMP in ICMP handling, tidy ups, bug fixes, made ICMP optional * Juan Jose Ciarlante : re-assign maddr if no packet received from outside + * Juan Jose Ciarlante : softlocking. + * Juan Jose Ciarlante : littl autofw oops fix * */ @@ -45,6 +49,14 @@ #define IP_MASQ_TAB_SIZE 256 /* must be power of 2 */ + +/* + * deletion-procinfo mutex lock + */ +static struct wait_queue *masq_wait; +atomic_t __ip_masq_lock = ATOMIC_INIT(0); + + /* * Implement IP packet masquerading */ @@ -130,6 +142,10 @@ X(ip_masq_free_ports), X(ip_masq_expire), X(ip_masq_out_get_2), + X(__ip_masq_lock), + X(ip_masq_control_add), + X(ip_masq_control_del), + X(ip_masq_control_get), #include <linux/symtab_end.h> }; @@ -519,54 +535,41 @@ return NULL; } +/* + * Lock-protect against /proc access (currently the only + * simultaneous possibility). + * Forget about cli() and friends. + */ static void masq_expire(unsigned long data) { - struct ip_masq *ms = (struct ip_masq *)data, *ms_data; - unsigned long flags; - - if (ms->flags & IP_MASQ_F_CONTROL) { - /* a control channel is about to expire */ - int idx = 0, reprieve = 0; -#ifdef DEBUG_CONFIG_IP_MASQUERADE - printk("Masquerade control %s %lX:%X about to expire\n", - masq_proto_name(ms->protocol), - ntohl(ms->saddr),ntohs(ms->sport)); -#endif - save_flags(flags); - cli(); + struct ip_masq *ms = (struct ip_masq *)data; + + ip_masq_lock(&__ip_masq_lock, 1); - /* - * If any other masquerade entry claims that the expiring entry - * is its control channel then keep the control entry alive. - * Useful for long running data channels with inactive control - * links which we don't want to lose, e.g. ftp. - * Assumption: loops such as a->b->a or a->a will never occur. - */ - for (idx = 0; idx < IP_MASQ_TAB_SIZE && !reprieve; idx++) { - for (ms_data = ip_masq_m_tab[idx]; ms_data ; ms_data = ms_data->m_link) { - if (ms_data->control == ms) { - reprieve = 1; /* this control connection can live a bit longer */ - ip_masq_set_expire(ms, ip_masq_expire->tcp_timeout); -#ifdef DEBUG_CONFIG_IP_MASQUERADE - printk("Masquerade control %s %lX:%X expiry reprieved\n", - masq_proto_name(ms->protocol), - ntohl(ms->saddr),ntohs(ms->sport)); -#endif - break; - } - } - } - restore_flags(flags); - if (reprieve) - return; + /* + * Already locked, do bounce ... + */ + if (ip_masq_nlocks(&__ip_masq_lock) != 1) { + goto masq_expire_later; } + /* + * do I control anybody? + */ + if (atomic_read(&ms->n_control)) + goto masq_expire_later; + + /* + * does anybody controls me? + */ + + if (ms->control) + ip_masq_control_del(ms); + #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("Masqueraded %s %lX:%X expired\n",masq_proto_name(ms->protocol),ntohl(ms->saddr),ntohs(ms->sport)); #endif - save_flags(flags); - cli(); if (ip_masq_unhash(ms)) { ip_masq_free_ports[masq_proto_num(ms->protocol)]++; @@ -575,7 +578,16 @@ kfree_s(ms,sizeof(*ms)); } - restore_flags(flags); +masq_expire_later: + IP_MASQ_DEBUG("masq_expire delayed: %s %08lX:%04X->%08lX:%04X nlocks-1=%d masq.n_control=%d\n", + masq_proto_name(ms->protocol), + ntohl(ms->saddr), ntohs(ms->sport), + ntohl(ms->daddr), ntohs(ms->dport), + ip_masq_nlocks(&__ip_masq_lock)-1, + atomic_read(&ms->n_control)); + + ip_masq_unlock(&__ip_masq_lock, 1); + ip_masq_set_expire(ms, MASQUERADE_EXPIRE_RETRY); } #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW @@ -1547,6 +1559,49 @@ return 0; } +void ip_masq_control_add(struct ip_masq *ms, struct ip_masq* ctl_ms) +{ + if (ms->control) { + IP_MASQ_ERR( "request control ADD for already controlled: %d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n", + NIPQUAD(ms->saddr),ntohs(ms->sport), + NIPQUAD(ms->daddr),ntohs(ms->dport)); + ip_masq_control_del(ms); + } + IP_MASQ_DEBUG("ADDing control for: ms.dst=%d.%d.%d.%d:%d ctl_ms.dst=%d.%d.%d.%d:%d\n", + NIPQUAD(ms->daddr),ntohs(ms->dport), + NIPQUAD(ctl_ms->daddr),ntohs(ctl_ms->dport)); + ms->control = ctl_ms; + atomic_inc(&ctl_ms->n_control); +} + +void ip_masq_control_del(struct ip_masq *ms) +{ + struct ip_masq *ctl_ms = ms->control; + if (!ctl_ms) { + IP_MASQ_ERR( "request control DEL for uncontrolled: %d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n", + NIPQUAD(ms->saddr),ntohs(ms->sport), + NIPQUAD(ms->daddr),ntohs(ms->dport)); + return; + } + IP_MASQ_DEBUG("DELeting control for: ms.dst=%d.%d.%d.%d:%d ctl_ms.dst=%d.%d.%d.%d:%d\n", + NIPQUAD(ms->daddr),ntohs(ms->dport), + NIPQUAD(ctl_ms->daddr),ntohs(ctl_ms->dport)); + ms->control = NULL; + if (atomic_read(&ctl_ms->n_control) == 0) { + IP_MASQ_ERR( "BUG control DEL with n=0 : %d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n", + NIPQUAD(ms->saddr),ntohs(ms->sport), + NIPQUAD(ms->daddr),ntohs(ms->dport)); + return; + + } + atomic_dec(&ctl_ms->n_control); +} + +struct ip_masq * ip_masq_control_get(struct ip_masq *ms) +{ + return ms->control; +} + /* * /proc/net entries */ @@ -1601,10 +1656,11 @@ { off_t pos=0, begin; struct ip_masq *ms; - unsigned long flags; char temp[129]; int idx = 0; int len=0; + + ip_masq_lockz(&__ip_masq_lock, &masq_wait, 0); if (offset < 128) { @@ -1620,8 +1676,6 @@ len = sprintf(buffer, "%-127s\n", temp); } pos = 128; - save_flags(flags); - cli(); for(idx = 0; idx < IP_MASQ_TAB_SIZE; idx++) for(ms = ip_masq_m_tab[idx]; ms ; ms = ms->m_link) @@ -1651,7 +1705,8 @@ goto done; } done: - restore_flags(flags); + ip_masq_unlockz(&__ip_masq_lock, &masq_wait, 0); + begin = len - (pos - offset); *start = buffer + begin; len -= begin; --- linux/net/ipv4/ip_masq_ftp.c.dist Tue Apr 8 12:47:47 1997 +++ linux/net/ipv4/ip_masq_ftp.c Mon Feb 23 09:06:36 1998 @@ -1,17 +1,16 @@ /* * IP_MASQ_FTP ftp masquerading module * - * - * Version: @(#)ip_masq_ftp.c 0.01 02/05/96 - * * Author: Wouter Gadeyne * + * $Id: ip_masq_ftp.c,v 0.3 1998/02/23 11:46:36 jjo Exp jjo $ * * Fixes: * Wouter Gadeyne : Fixed masquerading support of ftp PORT commands * Juan Jose Ciarlante : Code moved and adapted from ip_fw.c * Keith Owens : Add keep alive for ftp control channel * Nigel Metheringham : Added multiple port support + * Juan Jose Ciarlante : use ip_masq_control_xxx functions * * * @@ -146,8 +145,7 @@ if (n_ms==NULL) return 0; - n_ms->control = ms; /* keepalive from data to the control channel */ - ms->flags |= IP_MASQ_F_CONTROL; /* this is a control channel */ + ip_masq_control_add(n_ms, ms); } /* @@ -285,8 +283,8 @@ if (n_ms==NULL) return 0; - n_ms->control = ms; /* keepalive from data to the control channel */ - ms->flags |= IP_MASQ_F_CONTROL; /* this is a control channel */ + + ip_masq_control_add(n_ms, ms); } /* --- linux/net/ipv4/ip_fw.c.dist Tue Aug 12 15:30:28 1997 +++ linux/net/ipv4/ip_fw.c Mon Feb 23 09:08:14 1998 @@ -933,11 +933,15 @@ if (prev) { prev->next=curr->next; + if (curr->flags&IP_AUTOFW_ACTIVE) + del_timer(&curr->timer); kfree_s(curr,sizeof(struct ip_autofw)); return(0); } else { + if (ip_autofw_hosts->flags&IP_AUTOFW_ACTIVE) + del_timer(&ip_autofw_hosts->timer); kfree_s(ip_autofw_hosts,sizeof(struct ip_autofw)); ip_autofw_hosts=curr->next; return(0); @@ -956,6 +960,8 @@ { af=ip_autofw_hosts; ip_autofw_hosts=ip_autofw_hosts->next; + if (af->flags&IP_AUTOFW_ACTIVE) + del_timer(&af->timer); kfree_s(af,sizeof(struct ip_autofw)); } return(0); | |