Hi all,
Current tcpsp doesn't seem to have a way to stop forwarding for already
spliced TCP connections. I wrote this small patch to archive this with the help
of a cookie(a __u32 number). It is much useful in practice when we want to stop
particular spliced TCP connections, rather then to rmmod the whole tcpsp module.
diff -urN tcpsp/example/forwarder.c tcpspnew/example/forwarder.c
--- tcpsp/example/forwarder.c 2002-04-24 19:42:07.000000000 +0800
+++ tcpspnew/example/forwarder.c 2003-10-28 17:47:21.000000000 +0800
@@ -40,10 +40,10 @@
}
-int tcpsplicing(int fd1, int fd2, int n)
+int tcpsplicing(int fd1, int fd2, int n, __u32 cookie)
{
int sockfd;
- splice_conn_t sp = {fd1, fd2, n};
+ splice_conn_t sp = {fd1, fd2, n, cookie};
if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1)
return -1;
@@ -109,7 +109,7 @@
exit(1);
}
- if (tcpsplicing(fd1, fd2, n))
+ if (tcpsplicing(fd1, fd2, n, 1/*cookie*/))
printf("tcpsplicing failed\n");
else
printf("tcpsplicing succeeded\n");
diff -urN tcpsp/tcpsp_conn.c tcpspnew/tcpsp_conn.c
--- tcpsp/tcpsp_conn.c 2003-10-27 00:26:19.000000000 +0800
+++ tcpspnew/tcpsp_conn.c 2003-10-29 14:14:20.000000000 +0800
@@ -46,9 +46,10 @@
static kmem_cache_t *tcpsp_conn_cachep;
/* tcpsp onnection hash tables */
-#define TCPSP_NTABLES 2
+#define TCPSP_NTABLES 3
static struct list_head *tcpsp_conn_tab1;
static struct list_head *tcpsp_conn_tab2;
+static struct list_head *tcpsp_conn_tab3;
static rwlock_t tcpsp_conn_lock = RW_LOCK_UNLOCKED;
@@ -68,6 +69,16 @@
& TCPSP_CONN_TAB_MASK;
}
+/*
+ * Returns hash value for tcpsp connection cookie
+ */
+static inline unsigned
+tcpsp_conn_hash_cookie(__u32 cookie)
+{
+ return (cookie^(cookie>>TCPSP_CONN_TAB_BITS))
+ & TCPSP_CONN_TAB_MASK;
+}
+
/*
* Hashes tcpsp_conn in tcpsp_conn_tabs by <addr,port>.
@@ -89,6 +100,9 @@
hash = tcpsp_conn_hash_key(cp->conn[1].laddr, cp->conn[1].lport);
list_add(&cp->s_list, &tcpsp_conn_tab2[hash]);
+
+ hash = tcpsp_conn_hash_cookie(cp->cookie);
+ list_add(&cp->t_list, &tcpsp_conn_tab3[hash]);
cp->flags |= TCPSP_CONN_F_HASHED;
atomic_add(TCPSP_NTABLES, &cp->refcnt);
@@ -111,6 +125,7 @@
write_lock(&tcpsp_conn_lock);
list_del(&cp->f_list);
list_del(&cp->s_list);
+ list_del(&cp->t_list);
cp->flags &= ~TCPSP_CONN_F_HASHED;
atomic_sub(TCPSP_NTABLES, &cp->refcnt);
write_unlock(&tcpsp_conn_lock);
@@ -474,7 +489,7 @@
* Create and hash a new tcpsp into the tcpsp_conn_tabs.
*/
struct tcpsp_conn *
-tcpsp_conn_new(struct socket *sock1, struct socket *sock2, int n)
+tcpsp_conn_new(struct socket *sock1, struct socket *sock2, int n, __u32 cookie)
{
struct tcp_opt *tp1, *tp2;
struct tcpsp_conn *cp;
@@ -500,6 +515,8 @@
fill_conn_tuple(&cp->conn[1], sock2->sk);
cp->conn[1].splice_iss += n;
+
+ cp->cookie = cookie;
atomic_inc(&tcpsp_conn_count);
@@ -546,7 +563,7 @@
pos = 128;
if (pos > offset) {
len += sprintf(buffer+len, "%-127s\n",
- "FromIP FPrt ToIP TPrt LocalIP LPrt
DestIP DPrt State Expires");
+ "FromIP FPrt ToIP TPrt LocalIP LPrt
DestIP DPrt State Expires Cookie ");
}
for(idx = 0; idx < TCPSP_CONN_TAB_SIZE; idx++) {
@@ -563,7 +580,7 @@
if (pos <= offset)
continue;
sprintf(temp,
- "%08X %04X %08X %04X %08X %04X %08X %04X %-11s
%7lu",
+ "%08X %04X %08X %04X %08X %04X %08X %04X %-11s
%7lu %08X",
ntohl(cp->conn[0].raddr),
ntohs(cp->conn[0].rport),
ntohl(cp->conn[0].laddr),
@@ -573,7 +590,8 @@
ntohl(cp->conn[1].raddr),
ntohs(cp->conn[1].rport),
tcpsp_state_name(cp->state),
- cp->timer.expires-jiffies);
+ cp->timer.expires-jiffies,
+ cp->cookie);
len += sprintf(buffer+len, "%-127s\n", temp);
if (pos >= offset+length) {
read_unlock_bh(&tcpsp_conn_lock);
@@ -630,6 +648,41 @@
}
}
+/*
+ * Delete the connection entry matches the cookie in the tcpsp_conn_tab
+ */
+int tcpsp_conn_del(__u32 cookie)
+{
+ int idx;
+ struct tcpsp_conn *cp;
+ struct list_head *e, *nxt;
+
+ idx = tcpsp_conn_hash_cookie(cookie);
+ /*
+ * Lock is actually needed in this loop.
+ */
+ write_lock(&tcpsp_conn_lock);
+
+ list_for_each_safe (e, nxt, &tcpsp_conn_tab3[idx]) {
+ cp = list_entry(e, struct tcpsp_conn, t_list);
+ write_unlock(&tcpsp_conn_lock);
+ TCPSP_DBG(4, "del splicing connection\n");
+ if (cp->cookie == cookie){
+ if (del_timer(&cp->timer))
+ tcpsp_conn_expire_now(cp);
+ goto out_found;
+ }
+
+ write_lock(&tcpsp_conn_lock);
+ }
+ write_unlock(&tcpsp_conn_lock);
+
+ return -EINVAL;
+
+ out_found:
+ return 0;
+}
+
int tcpsp_conn_init(void)
{
@@ -647,6 +700,13 @@
vfree(tcpsp_conn_tab1);
return -ENOMEM;
}
+
+ if (!(tcpsp_conn_tab3 =
+ vmalloc(TCPSP_CONN_TAB_SIZE * sizeof(struct list_head)))) {
+ vfree(tcpsp_conn_tab2);
+ vfree(tcpsp_conn_tab1);
+ return -ENOMEM;
+ }
/* Allocate tcpsp_conn slab cache */
tcpsp_conn_cachep = kmem_cache_create("tcpsp_conn",
@@ -655,6 +715,7 @@
if (!tcpsp_conn_cachep) {
vfree(tcpsp_conn_tab1);
vfree(tcpsp_conn_tab2);
+ vfree(tcpsp_conn_tab3);
return -ENOMEM;
}
@@ -668,6 +729,7 @@
for (idx = 0; idx < TCPSP_CONN_TAB_SIZE; idx++) {
INIT_LIST_HEAD(&tcpsp_conn_tab1[idx]);
INIT_LIST_HEAD(&tcpsp_conn_tab2[idx]);
+ INIT_LIST_HEAD(&tcpsp_conn_tab3[idx]);
}
proc_net_create("tcpsp_conn", 0, tcpsp_conn_getinfo);
@@ -685,4 +747,5 @@
proc_net_remove("tcpsp_conn");
vfree(tcpsp_conn_tab1);
vfree(tcpsp_conn_tab2);
+ vfree(tcpsp_conn_tab3);
}
diff -urN tcpsp/tcpsp_ctl.c tcpspnew/tcpsp_ctl.c
--- tcpsp/tcpsp_ctl.c 2003-10-27 00:26:19.000000000 +0800
+++ tcpspnew/tcpsp_ctl.c 2003-10-29 11:22:22.000000000 +0800
@@ -169,7 +169,7 @@
}
-int sys_tcpsplicing(int fd1, int fd2, int n)
+int sys_tcpsplicing(int fd1, int fd2, int n, __u32 cookie)
{
struct socket *sock1, *sock2;
struct tcpsp_conn *cp;
@@ -180,7 +180,7 @@
if (!(sock2 = sockfd_lookup(fd2, &err)))
goto out_put_sock1;
- if (!(cp = tcpsp_conn_new(sock1, sock2, n)))
+ if (!(cp = tcpsp_conn_new(sock1, sock2, n, cookie)))
err = -ENOMEM;
else
tcpsp_conn_put(cp);
@@ -192,6 +192,11 @@
return err;
}
+int sys_tcpunsplicing(__u32 cookie)
+{
+ return tcpsp_conn_del(cookie);
+}
+
/* this interface is ugly, will be changed to system call */
static int
@@ -217,7 +222,10 @@
switch (cmd) {
case TCPSP_SO_SET_ADD:
- ret = sys_tcpsplicing(sp.s1, sp.s2, sp.n);
+ ret = sys_tcpsplicing(sp.s1, sp.s2, sp.n, sp.cookie);
+ break;
+ case TCPSP_SO_SET_DEL:
+ ret = sys_tcpunsplicing(sp.cookie);
break;
default:
ret = -EINVAL;
diff -urN tcpsp/tcpsp.h tcpspnew/tcpsp.h
--- tcpsp/tcpsp.h 2002-05-20 11:22:42.000000000 +0800
+++ tcpspnew/tcpsp.h 2003-10-29 11:21:40.000000000 +0800
@@ -24,7 +24,8 @@
#define TCPSP_SO_SET_NONE TCPSP_BASE_CTL /* just peek */
#define TCPSP_SO_SET_ADD (TCPSP_BASE_CTL+1)
-#define TCPSP_SO_SET_MAX TCPSP_SO_SET_ADD
+#define TCPSP_SO_SET_DEL (TCPSP_BASE_CTL+2)
+#define TCPSP_SO_SET_MAX TCPSP_SO_SET_DEL
#define TCPSP_SO_GET_VERSION TCPSP_BASE_CTL
#define TCPSP_SO_GET_INFO (TCPSP_BASE_CTL+1)
@@ -39,6 +40,8 @@
/* the number of bytes written to s2 */
int n;
+
+ __u32 cookie;
} splice_conn_t;
@@ -177,6 +180,7 @@
struct tcpsp_conn {
struct list_head f_list; /* first hash table */
struct list_head s_list; /* second hash table */
+ struct list_head t_list; /* third hash table */
atomic_t refcnt; /* reference count */
@@ -197,6 +201,9 @@
/* packet transmitter */
int (*packet_xmit)(struct sk_buff *skb);
+
+ /* cookie */
+ __u32 cookie; /* cookie */
};
@@ -232,7 +239,8 @@
extern void tcpsp_conn_put(struct tcpsp_conn *cp);
extern struct tcpsp_conn *
-tcpsp_conn_new(struct socket *sock1, struct socket *sock2, int n);
+tcpsp_conn_new(struct socket *sock1, struct socket *sock2, int n, __u32
cookie);
+extern int tcpsp_conn_del(__u32 cookie);
#define tcpsp_conn_expire_now(cp) cp->timer.function((unsigned long)cp)
extern const char * tcpsp_state_name(int state);
|