X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=include%2Fnet%2Frequest_sock.h;h=c7190846e128e21221106379e619589b3d7f0603;hb=8d2f9e81169b8120cf2b4872930ae491b17c27b8;hp=9502f5587931d1a6427c8e7cee3ec4d392b29054;hpb=2e6599cb899ba4b133f42cbf9d2b1883d2dc583a;p=safe%2Fjmp%2Flinux-2.6 diff --git a/include/net/request_sock.h b/include/net/request_sock.h index 9502f55..c719084 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h @@ -16,62 +16,234 @@ #define _REQUEST_SOCK_H #include +#include #include +#include + #include -struct open_request; +struct request_sock; struct sk_buff; struct dst_entry; struct proto; -struct or_calltable { +struct request_sock_ops { int family; - kmem_cache_t *slab; int obj_size; + struct kmem_cache *slab; + char *slab_name; int (*rtx_syn_ack)(struct sock *sk, - struct open_request *req, - struct dst_entry *dst); - void (*send_ack)(struct sk_buff *skb, - struct open_request *req); - void (*send_reset)(struct sk_buff *skb); - void (*destructor)(struct open_request *req); + struct request_sock *req); + void (*send_ack)(struct sock *sk, struct sk_buff *skb, + struct request_sock *req); + void (*send_reset)(struct sock *sk, + struct sk_buff *skb); + void (*destructor)(struct request_sock *req); }; -/* struct open_request - mini sock to represent a connection request +/* struct request_sock - mini sock to represent a connection request */ -struct open_request { - struct open_request *dl_next; /* Must be first member! */ +struct request_sock { + struct request_sock *dl_next; /* Must be first member! */ u16 mss; u8 retrans; - u8 __pad; + u8 cookie_ts; /* syncookie: encode tcpopts in timestamp */ /* The following two fields can be easily recomputed I think -AK */ u32 window_clamp; /* window clamp at creation time */ u32 rcv_wnd; /* rcv_wnd offered first time */ u32 ts_recent; unsigned long expires; - struct or_calltable *class; + const struct request_sock_ops *rsk_ops; struct sock *sk; + u32 secid; + u32 peer_secid; }; -static inline struct open_request *tcp_openreq_alloc(struct or_calltable *class) +static inline struct request_sock *reqsk_alloc(const struct request_sock_ops *ops) { - struct open_request *req = kmem_cache_alloc(class->slab, SLAB_ATOMIC); + struct request_sock *req = kmem_cache_alloc(ops->slab, GFP_ATOMIC); if (req != NULL) - req->class = class; + req->rsk_ops = ops; return req; } -static inline void tcp_openreq_fastfree(struct open_request *req) +static inline void __reqsk_free(struct request_sock *req) { - kmem_cache_free(req->class->slab, req); + kmem_cache_free(req->rsk_ops->slab, req); +} + +static inline void reqsk_free(struct request_sock *req) +{ + req->rsk_ops->destructor(req); + __reqsk_free(req); +} + +extern int sysctl_max_syn_backlog; + +/** struct listen_sock - listen state + * + * @max_qlen_log - log_2 of maximal queued SYNs/REQUESTs + */ +struct listen_sock { + u8 max_qlen_log; + /* 3 bytes hole, try to use */ + int qlen; + int qlen_young; + int clock_hand; + u32 hash_rnd; + u32 nr_table_entries; + struct request_sock *syn_table[0]; +}; + +/** struct request_sock_queue - queue of request_socks + * + * @rskq_accept_head - FIFO head of established children + * @rskq_accept_tail - FIFO tail of established children + * @rskq_defer_accept - User waits for some data after accept() + * @syn_wait_lock - serializer + * + * %syn_wait_lock is necessary only to avoid proc interface having to grab the main + * lock sock while browsing the listening hash (otherwise it's deadlock prone). + * + * This lock is acquired in read mode only from listening_get_next() seq_file + * op and it's acquired in write mode _only_ from code that is actively + * changing rskq_accept_head. All readers that are holding the master sock lock + * don't need to grab this lock in read mode too as rskq_accept_head. writes + * are always protected from the main sock lock. + */ +struct request_sock_queue { + struct request_sock *rskq_accept_head; + struct request_sock *rskq_accept_tail; + rwlock_t syn_wait_lock; + u8 rskq_defer_accept; + /* 3 bytes hole, try to pack */ + struct listen_sock *listen_opt; +}; + +extern int reqsk_queue_alloc(struct request_sock_queue *queue, + unsigned int nr_table_entries); + +extern void __reqsk_queue_destroy(struct request_sock_queue *queue); +extern void reqsk_queue_destroy(struct request_sock_queue *queue); + +static inline struct request_sock * + reqsk_queue_yank_acceptq(struct request_sock_queue *queue) +{ + struct request_sock *req = queue->rskq_accept_head; + + queue->rskq_accept_head = NULL; + return req; +} + +static inline int reqsk_queue_empty(struct request_sock_queue *queue) +{ + return queue->rskq_accept_head == NULL; +} + +static inline void reqsk_queue_unlink(struct request_sock_queue *queue, + struct request_sock *req, + struct request_sock **prev_req) +{ + write_lock(&queue->syn_wait_lock); + *prev_req = req->dl_next; + write_unlock(&queue->syn_wait_lock); +} + +static inline void reqsk_queue_add(struct request_sock_queue *queue, + struct request_sock *req, + struct sock *parent, + struct sock *child) +{ + req->sk = child; + sk_acceptq_added(parent); + + if (queue->rskq_accept_head == NULL) + queue->rskq_accept_head = req; + else + queue->rskq_accept_tail->dl_next = req; + + queue->rskq_accept_tail = req; + req->dl_next = NULL; } -static inline void tcp_openreq_free(struct open_request *req) +static inline struct request_sock *reqsk_queue_remove(struct request_sock_queue *queue) { - req->class->destructor(req); - tcp_openreq_fastfree(req); + struct request_sock *req = queue->rskq_accept_head; + + WARN_ON(req == NULL); + + queue->rskq_accept_head = req->dl_next; + if (queue->rskq_accept_head == NULL) + queue->rskq_accept_tail = NULL; + + return req; +} + +static inline struct sock *reqsk_queue_get_child(struct request_sock_queue *queue, + struct sock *parent) +{ + struct request_sock *req = reqsk_queue_remove(queue); + struct sock *child = req->sk; + + WARN_ON(child == NULL); + + sk_acceptq_removed(parent); + __reqsk_free(req); + return child; +} + +static inline int reqsk_queue_removed(struct request_sock_queue *queue, + struct request_sock *req) +{ + struct listen_sock *lopt = queue->listen_opt; + + if (req->retrans == 0) + --lopt->qlen_young; + + return --lopt->qlen; +} + +static inline int reqsk_queue_added(struct request_sock_queue *queue) +{ + struct listen_sock *lopt = queue->listen_opt; + const int prev_qlen = lopt->qlen; + + lopt->qlen_young++; + lopt->qlen++; + return prev_qlen; +} + +static inline int reqsk_queue_len(const struct request_sock_queue *queue) +{ + return queue->listen_opt != NULL ? queue->listen_opt->qlen : 0; +} + +static inline int reqsk_queue_len_young(const struct request_sock_queue *queue) +{ + return queue->listen_opt->qlen_young; +} + +static inline int reqsk_queue_is_full(const struct request_sock_queue *queue) +{ + return queue->listen_opt->qlen >> queue->listen_opt->max_qlen_log; +} + +static inline void reqsk_queue_hash_req(struct request_sock_queue *queue, + u32 hash, struct request_sock *req, + unsigned long timeout) +{ + struct listen_sock *lopt = queue->listen_opt; + + req->expires = jiffies + timeout; + req->retrans = 0; + req->sk = NULL; + req->dl_next = lopt->syn_table[hash]; + + write_lock(&queue->syn_wait_lock); + lopt->syn_table[hash] = req; + write_unlock(&queue->syn_wait_lock); } #endif /* _REQUEST_SOCK_H */