Teach ss to show sockets' shutdown state
Subsystems (2)
cover Teach ss to show sockets' shutdown state
In the net-next sits a patch which extends the sock-diag subsys to show the sockets' shutdown state. I propose to teach the ss tool to print this info when requested with -e|--extended key.
The output will look like arrows at the end of each line, like this:
ESTAB 0 0 127.0.0.1:41705 127.0.0.1:12345 ino:143321 sk:ffff88003a8cea00 --> ESTAB 0 0 127.0.0.1:46925 127.0.0.1:12346 ino:143322 sk:ffff88003a8ce4c0 <-- ESTAB 0 0 127.0.0.1:51678 127.0.0.1:12347 ino:143323 sk:ffff88003a8cdf80 --- ESTAB 0 0 127.0.0.1:46911 127.0.0.1:12348 ino:143324 sk:ffff88003b7f05c0 <->
for SHUT_RD, SHUT_WR, SHUT_RDWR and non-shutdown sockets respectively.
In order to do so, it's also required to implement support for the newer sock-diag in tcp and udp netlink code. I did it before, but broke compatibility with older kernels (those without sock-diag). Now this is fixed (checked on 2.6.40 kernel).
PATCH 1/5 ss: Rename some tcp- names into inet-
The sock-diag is capable to diag udp sockets as well. Prepare the ss code for this by first renaming soon-to-be-generic tcp-s names into inet-s.
--- misc/ss.c | 21 ++++++++++++--------- 1 files changed, 12 insertions(+), 9 deletions(-)
misc/ss.c +12 -9
@@ -1431,7 +1431,7 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r) } } -static int tcp_show_sock (struct nlmsghdr *nlh,struct filter *f) +static int inet_show_sock (struct nlmsghdr *nlh,struct filter *f) {struct inet_diag_msg *r =NLMSG_DATA (nlh);struct tcpstat s;
@@ -1495,7 +1495,7 @@ static int tcp_show_sock(struct nlmsghdr *nlh, struct filter *f)return 0 ; } -static int tcp_show_netlink (struct filter *f,FILE *dump_fp,int socktype) +static int inet_show_netlink (struct filter *f,FILE *dump_fp,int protocol) {int fd;struct sockaddr_nl nladdr;
@@ -1517,7 +1517,10 @@ static int tcp_show_netlink(struct filter *f, FILE *dump_fp, int socktype) nladdr.nl_family =AF_NETLINK ; req.nlh.nlmsg_len =sizeof (req); - req.nlh.nlmsg_type = socktype; +if (protocol ==IPPROTO_TCP ) + req.nlh.nlmsg_type =TCPDIAG_GETSOCK ; +else + req.nlh.nlmsg_type =DCCPDIAG_GETSOCK ; req.nlh.nlmsg_flags =NLM_F_ROOT |NLM_F_MATCH |NLM_F_REQUEST ; req.nlh.nlmsg_pid =0 ; req.nlh.nlmsg_seq =123456 ;
@@ -1626,7 +1629,7 @@ static int tcp_show_netlink(struct filter *f, FILE *dump_fp, int socktype) h =NLMSG_NEXT (h, status);continue ; } - err =tcp_show_sock (h,NULL ); + err =inet_show_sock (h,NULL );if (err <0 ) {close (fd);return err;
@@ -1699,7 +1702,7 @@ static int tcp_show_netlink_file(struct filter *f)return -1 ; } - err =tcp_show_sock (h, f); + err =inet_show_sock (h, f);if (err <0 )return err; }
@@ -1717,7 +1720,7 @@ static int tcp_show(struct filter *f, int socktype)return tcp_show_netlink_file (f);if (!getenv ("PROC_NET_TCP" ) && !getenv ("PROC_ROOT" ) - &&tcp_show_netlink (f,NULL , socktype) ==0 ) + &&inet_show_netlink (f,NULL , socktype) ==0 )return 0 ;/* Sigh... We have to parse /proc/net/tcp... */
@@ -2980,7 +2983,7 @@ int main(int argc, char *argv[])exit (-1 ); } } -tcp_show_netlink (¤t_filter, dump_fp,TCPDIAG_GETSOCK ); +inet_show_netlink (¤t_filter, dump_fp,IPPROTO_TCP );fflush (dump_fp);exit (0 ); }
@@ -3048,8 +3051,8 @@ int main(int argc, char *argv[])if (current_filter.dbs & (1 <<UDP_DB ))udp_show (¤t_filter);if (current_filter.dbs & (1 <<TCP_DB )) -tcp_show (¤t_filter,TCPDIAG_GETSOCK ); +tcp_show (¤t_filter,IPPROTO_TCP );if (current_filter.dbs & (1 <<DCCP_DB )) -tcp_show (¤t_filter,DCCPDIAG_GETSOCK ); +tcp_show (¤t_filter,IPPROTO_DCCP );return 0 ; }
Signature · 1 line
1.7.1
PATCH 2/5 ss: Split inet_show_netlink into parts
In reply to Pavel EmelyanovThe existing function inet_show_netlink sends tcp-diag request and then receives back the response and prints it on the screen.
The sock-diag and legacy tcp-diag have different request types, but report sockets in the same format. In order to support both it's convenient to split the code into sending and receiving parts.
--- misc/ss.c | 27 +++++++++++++++++++++------ 1 files changed, 21 insertions(+), 6 deletions(-)
misc/ss.c +21 -6
@@ -1495,9 +1495,8 @@ static int inet_show_sock(struct nlmsghdr *nlh, struct filter *f)return 0 ; } -static int inet_show_netlink (struct filter *f,FILE *dump_fp,int protocol) +static int tcpdiag_send (int fd,int protocol,struct filter *f) { -int fd;struct sockaddr_nl nladdr;struct {struct nlmsghdr nlh;
@@ -1507,12 +1506,8 @@ static int inet_show_netlink(struct filter *f, FILE *dump_fp, int protocol)int bclen;struct msghdr msg;struct rtattr rta; -char buf[8192 ];struct iovec iov[3 ]; -if ((fd =socket (AF_NETLINK ,SOCK_RAW ,NETLINK_INET_DIAG )) <0 ) -return -1 ; -memset (&nladdr,0 ,sizeof (nladdr)); nladdr.nl_family =AF_NETLINK ;
@@ -1563,6 +1558,26 @@ static int inet_show_netlink(struct filter *f, FILE *dump_fp, int protocol)return -1 ; } +return 0 ; +} + +static int inet_show_netlink (struct filter *f,FILE *dump_fp,int protocol) +{ +int fd; +struct sockaddr_nl nladdr; +struct msghdr msg; +char buf[8192 ]; +struct iovec iov[3 ]; + +if ((fd =socket (AF_NETLINK ,SOCK_RAW ,NETLINK_INET_DIAG )) <0 ) +return -1 ; + +if (tcpdiag_send (fd, protocol, f)) +return -1 ; + +memset (&nladdr,0 ,sizeof (nladdr)); + nladdr.nl_family =AF_NETLINK ; + iov[0 ] = (struct iovec ){ .iov_base = buf, .iov_len =sizeof (buf)
Signature · 1 line
1.7.1
PATCH 3/5 ss: Support sock-diag
In reply to Pavel EmelyanovThat is -- write the code, that sends diag request in new format. It's mostly copied from tcp-diag code. Plus, sock-diag differentiates sockets by families, thus we have to send two requests sequentially.
If we fail to submit new sock-diag request, try to fall-back and submit the legacy tcp-diag one.
--- misc/ss.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 files changed, 87 insertions(+), 8 deletions(-)
misc/ss.c +87 -8
@@ -1561,9 +1561,76 @@ static int tcpdiag_send(int fd, int protocol, struct filter *f)return 0 ; } +static int sockdiag_send (int family,int fd,int protocol,struct filter *f) +{ +struct sockaddr_nl nladdr; +struct { +struct nlmsghdr nlh; +struct inet_diag_req_v2 r; + } req; +char *bc =NULL ; +int bclen; +struct msghdr msg; +struct rtattr rta; +struct iovec iov[3 ]; + +if (family ==PF_UNSPEC ) +return tcpdiag_send (fd, protocol, f); + +memset (&nladdr,0 ,sizeof (nladdr)); + nladdr.nl_family =AF_NETLINK ; + + req.nlh.nlmsg_len =sizeof (req); + req.nlh.nlmsg_type =SOCK_DIAG_BY_FAMILY ; + req.nlh.nlmsg_flags =NLM_F_ROOT |NLM_F_MATCH |NLM_F_REQUEST ; + req.nlh.nlmsg_pid =0 ; + req.nlh.nlmsg_seq =123456 ; +memset (&req.r,0 ,sizeof (req.r)); + req.r.sdiag_family = family; + req.r.sdiag_protocol = protocol; + req.r.idiag_states = f->states; +if (show_mem) { + req.r.idiag_ext |= (1 <<(INET_DIAG_MEMINFO -1 )); + req.r.idiag_ext |= (1 <<(INET_DIAG_SKMEMINFO -1 )); + } + +if (show_tcpinfo) { + req.r.idiag_ext |= (1 <<(INET_DIAG_INFO -1 )); + req.r.idiag_ext |= (1 <<(INET_DIAG_VEGASINFO -1 )); + req.r.idiag_ext |= (1 <<(INET_DIAG_CONG -1 )); + } + + iov[0 ] = (struct iovec ){ + .iov_base = &req, + .iov_len =sizeof (req) + }; +if (f->f) { + bclen =ssfilter_bytecompile (f->f, &bc); + rta.rta_type =INET_DIAG_REQ_BYTECODE ; + rta.rta_len =RTA_LENGTH (bclen); + iov[1 ] = (struct iovec ){ &rta,sizeof (rta) }; + iov[2 ] = (struct iovec ){ bc, bclen }; + req.nlh.nlmsg_len +=RTA_LENGTH (bclen); + } + + msg = (struct msghdr ) { + .msg_name = (void *)&nladdr, + .msg_namelen =sizeof (nladdr), + .msg_iov = iov, + .msg_iovlen = f->f ?3 :1 , + }; + +if (sendmsg (fd, &msg,0 ) <0 ) { +close (fd); +return -1 ; + } + +return 0 ; +} +static int inet_show_netlink (struct filter *f,FILE *dump_fp,int protocol) { -int fd; +int fd, family;struct sockaddr_nl nladdr;struct msghdr msg;char buf[8192 ];
@@ -1572,7 +1639,9 @@ static int inet_show_netlink(struct filter *f, FILE *dump_fp, int protocol)if ((fd =socket (AF_NETLINK ,SOCK_RAW ,NETLINK_INET_DIAG )) <0 )return -1 ; -if (tcpdiag_send (fd, protocol, f)) + family =PF_INET ; +again: +if (sockdiag_send (family, fd, protocol, f))return -1 ;memset (&nladdr,0 ,sizeof (nladdr));
@@ -1620,15 +1689,19 @@ static int inet_show_netlink(struct filter *f, FILE *dump_fp, int protocol) h->nlmsg_seq != 123456) goto skip_it; -if (h->nlmsg_type ==NLMSG_DONE ) { -close (fd); -return 0 ; - } +if (h->nlmsg_type ==NLMSG_DONE ) + goto done; +if (h->nlmsg_type ==NLMSG_ERROR ) {struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA (h);if (h->nlmsg_len <NLMSG_LENGTH (sizeof (struct nlmsgerr ))) {fprintf (stderr,"ERROR truncated\n" ); }else { +if (family !=PF_UNSPEC ) { + family =PF_UNSPEC ; + goto again; + } + errno = -err->error;if (errno ==EOPNOTSUPP ) {close (fd);
@@ -1636,8 +1709,8 @@ static int inet_show_netlink(struct filter *f, FILE *dump_fp, int protocol) }perror ("TCPDIAG answers" ); } -close (fd); -return 0 ; + + goto done; }if (!dump_fp) {if (!(f->families & (1 <<r->idiag_family))) {
@@ -1663,6 +1736,12 @@ skip_it:exit (1 ); } } +done: +if (family ==PF_INET ) { + family =PF_INET6 ; + goto again; + } +close (fd);return 0 ; }
Signature · 1 line
1.7.1
PATCH 4/5 ss: Get udp sockets info via sock-diag
In reply to Pavel EmelyanovNow everything is prepared for it, so the patch is straightforward.
--- misc/ss.c | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-)
misc/ss.c +7 -0
@@ -1508,6 +1508,9 @@ static int tcpdiag_send(int fd, int protocol, struct filter *f)struct rtattr rta;struct iovec iov[3 ]; +if (protocol ==IPPROTO_UDP ) +return -1 ; +memset (&nladdr,0 ,sizeof (nladdr)); nladdr.nl_family =AF_NETLINK ;
@@ -1976,6 +1979,10 @@ int udp_show(struct filter *f) {FILE *fp =NULL ; +if (!getenv ("PROC_NET_UDP" ) && !getenv ("PROC_ROOT" ) + &&inet_show_netlink (f,NULL ,IPPROTO_UDP ) ==0 ) +return 0 ; + dg_proto =UDP_PROTO ;if (f->families&(1 <<AF_INET )) {
Signature · 1 line
1.7.1
Re: [PATCH 4/5] ss: Get udp sockets info via sock-diag
Quoted 4 lines · On Thu, 25 Oct 2012 17:24:58 +0400 Pavel Emelyanov <[email protected]> wrote:
Now everything is prepared for it, so the patch is straightforward.
Signed-off-by Pavel Emelyanov <[email protected]>
1-4 standalone and do not require latest kernel; therefore applied
Please resubmit #5 during next merge window.
PATCH 5/5 ss: Show inet and unix sockets' shutdown state
In reply to Pavel EmelyanovTo see this we need kernel >=3.7 with _SHUTDOWN nlarrts in diag messages. The output will look like arrows at the end of each line, like this:
ESTAB 0 0 127.0.0.1:41705 127.0.0.1:12345 ino:143321 sk:ffff88003a8cea00 --> ESTAB 0 0 127.0.0.1:46925 127.0.0.1:12346 ino:143322 sk:ffff88003a8ce4c0 <-- ESTAB 0 0 127.0.0.1:51678 127.0.0.1:12347 ino:143323 sk:ffff88003a8cdf80 --- ESTAB 0 0 127.0.0.1:46911 127.0.0.1:12348 ino:143324 sk:ffff88003b7f05c0 <->
for SHUT_RD, SHUT_WR, SHUT_RDWR and non-shutdown sockets respectively.
--- include/linux/inet_diag.h | 3 ++- include/linux/unix_diag.h | 1 + misc/ss.c | 26 ++++++++++++++++++++------ 3 files changed, 23 insertions(+), 7 deletions(-)
include/linux/inet_diag.h +2 -1
@@ -109,9 +109,10 @@ enum {INET_DIAG_TOS ,INET_DIAG_TCLASS ,INET_DIAG_SKMEMINFO , + INET_DIAG_SHUTDOWN, }; -#define INET_DIAG_MAX INET_DIAG_SKMEMINFO +#define INET_DIAG_MAX INET_DIAG_SHUTDOWN/* INET_DIAG_MEM */
include/linux/unix_diag.h +1 -0
@@ -37,6 +37,7 @@ enum {UNIX_DIAG_ICONS ,UNIX_DIAG_RQLEN ,UNIX_DIAG_MEMINFO , +UNIX_DIAG_SHUTDOWN , UNIX_DIAG_MAX, };
misc/ss.c +20 -6
@@ -1327,15 +1327,12 @@ static char *sprint_bw(char *buf, double bw)return buf; } -static void tcp_show_info (const struct nlmsghdr *nlh,struct inet_diag_msg *r) +static void tcp_show_info (const struct nlmsghdr *nlh,struct inet_diag_msg *r, +struct rtattr *tb[]) { -struct rtattr * tb[INET_DIAG_MAX +1 ];char b1[64 ];double rtt =0 ; -parse_rtattr (tb,INET_DIAG_MAX , (struct rtattr *)(r+1 ), - nlh->nlmsg_len -NLMSG_LENGTH (sizeof (*r))); -if (tb[INET_DIAG_SKMEMINFO ]) {const __u32 *skmeminfo =RTA_DATA (tb[INET_DIAG_SKMEMINFO ]);
@@ -1435,6 +1432,10 @@ static int inet_show_sock(struct nlmsghdr *nlh, struct filter *f) {struct inet_diag_msg *r =NLMSG_DATA (nlh);struct tcpstat s; +struct rtattr * tb[INET_DIAG_MAX +1 ]; + +parse_rtattr (tb,INET_DIAG_MAX , (struct rtattr *)(r+1 ), + nlh->nlmsg_len -NLMSG_LENGTH (sizeof (*r))); s.state = r->idiag_state; s.local.family = s.remote.family = r->idiag_family;
@@ -1484,10 +1485,15 @@ static int inet_show_sock(struct nlmsghdr *nlh, struct filter *f)if (r->id.idiag_cookie[1 ] !=0 )printf ("%08x" , r->id.idiag_cookie[1 ]);printf ("%08x" , r->id.idiag_cookie[0 ]); +if (tb[INET_DIAG_SHUTDOWN ]) { +unsigned char mask; + mask = *(__u8 *)RTA_DATA (tb[INET_DIAG_SHUTDOWN ]); +printf (" %c-%c" , mask &1 ?'-' :'<' , mask &2 ?'-' :'>' ); + } }if (show_mem || show_tcpinfo) {printf ("\n\t" ); -tcp_show_info (nlh, r); +tcp_show_info (nlh, r, tb); }printf ("\n" );
@@ -2184,6 +2190,14 @@ static int unix_show_sock(struct nlmsghdr *nlh, struct filter *f)printf (" users:(%s)" , ubuf); } +if (show_details) { +if (tb[UNIX_DIAG_SHUTDOWN ]) { +unsigned char mask; + mask = *(__u8 *)RTA_DATA (tb[UNIX_DIAG_SHUTDOWN ]); +printf (" %c-%c" , mask &1 ?'-' :'<' , mask &2 ?'-' :'>' ); + } + } +printf ("\n" );return 0 ;
Signature · 1 line
1.7.1
Re: [PATCH 5/5] ss: Show inet and unix sockets' shutdown state
Quoted 23 lines · On Thu, 25 Oct 2012 17:26:44 +0400 Pavel Emelyanov <[email protected]> wrote:
To see this we need kernel >=3.7 with
_SHUTDOWNnlarrts in diag messages. The output will look like arrows at the end of each line, like this:ESTAB 0 0 127.0.0.1:41705 127.0.0.1:12345 ino:143321 sk:ffff88003a8cea00 --> ESTAB 0 0 127.0.0.1:46925 127.0.0.1:12346 ino:143322 sk:ffff88003a8ce4c0 <-- ESTAB 0 0 127.0.0.1:51678 127.0.0.1:12347 ino:143323 sk:ffff88003a8cdf80 --- ESTAB 0 0 127.0.0.1:46911 127.0.0.1:12348 ino:143324 sk:ffff88003b7f05c0 <->for
SHUT_RD,SHUT_WR,SHUT_RDWRand non-shutdown sockets respectively.Signed-off-by Pavel Emelyanov <[email protected]>--- include/linux/inet_diag.h | 3 ++- include/linux/unix_diag.h | 1 + misc/ss.c | 26 ++++++++++++++++++++------ 3 files changed, 23 insertions(+), 7 deletions(-)include/linux/inet_diag.h +0
-0
include/linux/inet_diag.h enum { · line 113
Quoted 5 lines
include/linux/inet_diag.h +1
-0@@ -109,9 +109,10 @@ enum {INET_DIAG_TOS ,INET_DIAG_TCLASS ,INET_DIAG_SKMEMINFO , + INET_DIAG_SHUTDOWN, };
Since this requires 3.8 or later kernel, please resubmit this patch during that merge window.
Re: [PATCH 5/5] ss: Show inet and unix sockets' shutdown state
Quoted 21 lines · Stephen Hemminger
Quoted 18 lines · On Thu, 25 Oct 2012 17:26:44 +0400 Pavel Emelyanov <[email protected]> wrote:
To see this we need kernel >=3.7 with
_SHUTDOWNnlarrts in diag messages. The output will look like arrows at the end of each line, like this:ESTAB 0 0 127.0.0.1:41705 127.0.0.1:12345 ino:143321 sk:ffff88003a8cea00 --> ESTAB 0 0 127.0.0.1:46925 127.0.0.1:12346 ino:143322 sk:ffff88003a8ce4c0 <-- ESTAB 0 0 127.0.0.1:51678 127.0.0.1:12347 ino:143323 sk:ffff88003a8cdf80 --- ESTAB 0 0 127.0.0.1:46911 127.0.0.1:12348 ino:143324 sk:ffff88003b7f05c0 <->for
SHUT_RD,SHUT_WR,SHUT_RDWRand non-shutdown sockets respectively.Signed-off-by Pavel Emelyanov <[email protected]>--- include/linux/inet_diag.h | 3 ++- include/linux/unix_diag.h | 1 + misc/ss.c | 26 ++++++++++++++++++++------ 3 files changed, 23 insertions(+), 7 deletions(-)
Quoted 14 lines
include/linux/inet_diag.h enum { · line 113
Quoted 10 lines
include/linux/inet_diag.h +1
-0@@ -109,9 +109,10 @@ enum {INET_DIAG_TOS ,INET_DIAG_TCLASS ,INET_DIAG_SKMEMINFO , + INET_DIAG_SHUTDOWN, };Since this requires 3.8 or later kernel, please resubmit this patch during that merge window.
--
I am wondering what possibly could happen if applying this before ?
iproute2 should be non dependent on kernel version, we make sure to not add regressions.
Re: [PATCH 5/5] ss: Show inet and unix sockets' shutdown state
Quoted 37 lines · On Thu, 25 Oct 2012 18:53:30 +0200 Eric Dumazet <[email protected]> wrote:
Quoted 21 lines · Stephen Hemminger
Quoted 18 lines · On Thu, 25 Oct 2012 17:26:44 +0400 Pavel Emelyanov <[email protected]> wrote:
To see this we need kernel >=3.7 with
_SHUTDOWNnlarrts in diag messages. The output will look like arrows at the end of each line, like this:ESTAB 0 0 127.0.0.1:41705 127.0.0.1:12345 ino:143321 sk:ffff88003a8cea00 --> ESTAB 0 0 127.0.0.1:46925 127.0.0.1:12346 ino:143322 sk:ffff88003a8ce4c0 <-- ESTAB 0 0 127.0.0.1:51678 127.0.0.1:12347 ino:143323 sk:ffff88003a8cdf80 --- ESTAB 0 0 127.0.0.1:46911 127.0.0.1:12348 ino:143324 sk:ffff88003b7f05c0 <->for
SHUT_RD,SHUT_WR,SHUT_RDWRand non-shutdown sockets respectively.Signed-off-by Pavel Emelyanov <[email protected]>--- include/linux/inet_diag.h | 3 ++- include/linux/unix_diag.h | 1 + misc/ss.c | 26 ++++++++++++++++++++------ 3 files changed, 23 insertions(+), 7 deletions(-)Quoted 14 lines
include/linux/inet_diag.h enum { · line 113
Quoted 10 lines
include/linux/inet_diag.h +1
-0@@ -109,9 +109,10 @@ enum {INET_DIAG_TOS ,INET_DIAG_TCLASS ,INET_DIAG_SKMEMINFO , + INET_DIAG_SHUTDOWN, };Since this requires 3.8 or later kernel, please resubmit this patch during that merge window.
--
Quoted 7 lines
I am wondering what possibly could happen if applying this before ?
iproute2 should be non dependent on kernel version, we make sure to not add regressions.
I don't want the stashed kernel headers to get out of date with kernel exported ones.
People who want to test early features are free to build their own pre-release versions.
Re: [PATCH 5/5] ss: Show inet and unix sockets' shutdown state
Quoted 4 lines · Stephen Hemminger
I don't want the stashed kernel headers to get out of date with kernel exported ones.
People who want to test early features are free to build their own pre-release versions. --
Have you considered an iproute2-next tree, it would really help us a lot.
Just to be clear, were the patches 1-4 accepted ?
(UDP diag was added kernel in December 2011)
Thanks
Re: [PATCH 5/5] ss: Show inet and unix sockets' shutdown state
Quoted 7 lines · On Thu, 25 Oct 2012 20:00:54 +0200 Eric Dumazet <[email protected]> wrote:
Quoted 4 lines · Stephen Hemminger
I don't want the stashed kernel headers to get out of date with kernel exported ones.
People who want to test early features are free to build their own pre-release versions. --
Quoted 10 lines
Have you considered an iproute2-next tree, it would really help us a lot.
Just to be clear, were the patches 1-4 accepted ?
(UDP diag was added kernel in December 2011)
Thanks
The first 4 patches are fine, and I will probably take those.