Subject: Skipping TCP / UDP / IP checksums on loopback traffic
To: NetBSD-network <tech-net@netbsd.org>
From: Jason Thorpe <thorpej@shagadelic.org>
List: tech-net
Date: 10/23/2004 10:40:59
--Apple-Mail-23--13025068
Content-Type: multipart/mixed; boundary=Apple-Mail-22--13025075
--Apple-Mail-22--13025075
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
charset=US-ASCII;
format=flowed
Folks...
There's no need to compute or check checksums for traffic over the
loopback interface. The following patch makes it optional, and
defaults to "off". Linux also skips checksums in this case, which
results in poor results for NetBSD compared to Linux in some
benchmarks.
Comments?
-- Jason R. Thorpe <thorpej@shagadelic.org>
--Apple-Mail-22--13025075
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
x-unix-mode=0644;
name="loopback-cksum-diffs.txt"
Content-Disposition: attachment;
filename=loopback-cksum-diffs.txt
Index: netinet/in.h
===================================================================
RCS file: /cvsroot/src/sys/netinet/in.h,v
retrieving revision 1.68
diff -u -p -r1.68 in.h
--- netinet/in.h 4 Sep 2004 23:30:07 -0000 1.68
+++ netinet/in.h 23 Oct 2004 17:29:36 -0000
@@ -437,7 +437,8 @@ struct ip_mreq {
#define IPCTL_CHECKINTERFACE 20 /* drop pkts in from 'wrong' iface */
#define IPCTL_IFQ 21 /* ipintrq node */
#define IPCTL_RANDOMID 22 /* use random IP ids (if configured) */
-#define IPCTL_MAXID 23
+#define IPCTL_LOOPBACKCKSUM 23 /* do IP checksum on loopback */
+#define IPCTL_MAXID 24
#define IPCTL_NAMES { \
{ 0, 0 }, \
@@ -463,6 +464,7 @@ struct ip_mreq {
{ "checkinterface", CTLTYPE_INT }, \
{ "ifq", CTLTYPE_NODE }, \
{ "random_id", CTLTYPE_INT }, \
+ { "do_loopback_cksum", CTLTYPE_INT }, \
}
#endif /* _NETBSD_SOURCE */
Index: netinet/ip_input.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/ip_input.c,v
retrieving revision 1.205
diff -u -p -r1.205 ip_input.c
--- netinet/ip_input.c 6 Oct 2004 01:34:11 -0000 1.205
+++ netinet/ip_input.c 23 Oct 2004 17:29:38 -0000
@@ -200,6 +200,7 @@ int ipprintfs = 0;
#endif
int ip_do_randomid = 0;
+int ip_do_loopback_cksum = 0;
/*
* XXX - Setting ip_checkinterface mostly implements the receive side of
@@ -572,10 +573,16 @@ ip_input(struct mbuf *m)
break;
default:
- /* Must compute it ourselves. */
- INET_CSUM_COUNTER_INCR(&ip_swcsum);
- if (in_cksum(m, hlen) != 0)
- goto badcsum;
+ /*
+ * Must compute it ourselves. Maybe skip checksum on
+ * loopback interfaces.
+ */
+ if (__predict_true(!(m->m_pkthdr.rcvif->if_flags &
+ IFF_LOOPBACK) || ip_do_loopback_cksum)) {
+ INET_CSUM_COUNTER_INCR(&ip_swcsum);
+ if (in_cksum(m, hlen) != 0)
+ goto badcsum;
+ }
break;
}
@@ -2342,4 +2349,11 @@ SYSCTL_SETUP(sysctl_net_inet_ip_setup, "
NULL, 0, &ip_do_randomid, 0,
CTL_NET, PF_INET, IPPROTO_IP,
IPCTL_RANDOMID, CTL_EOL);
+ sysctl_createv(clog, 0, NULL, NULL,
+ CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+ CTLTYPE_INT, "do_loopback_cksum",
+ SYSCTL_DESCR("Perform IP checksum on loopback"),
+ NULL, 0, &ip_do_loopback_cksum, 0,
+ CTL_NET, PF_INET, IPPROTO_IP,
+ IPCTL_LOOPBACKCKSUM, CTL_EOL);
}
Index: netinet/ip_output.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/ip_output.c,v
retrieving revision 1.136
diff -u -p -r1.136 ip_output.c
--- netinet/ip_output.c 6 Oct 2004 05:42:24 -0000 1.136
+++ netinet/ip_output.c 23 Oct 2004 17:29:39 -0000
@@ -745,7 +745,10 @@ spd_done:
INADDR_TO_IA(ip->ip_src, ia);
#endif
- m->m_pkthdr.csum_flags |= M_CSUM_IPv4;
+ /* Maybe skip checksums on loopback interfaces. */
+ if (__predict_true(!(ifp->if_flags & IFF_LOOPBACK) ||
+ ip_do_loopback_cksum))
+ m->m_pkthdr.csum_flags |= M_CSUM_IPv4;
sw_csum = m->m_pkthdr.csum_flags & ~ifp->if_csum_flags_tx;
/*
* If small enough for mtu of path, can just send directly.
Index: netinet/ip_var.h
===================================================================
RCS file: /cvsroot/src/sys/netinet/ip_var.h,v
retrieving revision 1.68
diff -u -p -r1.68 ip_var.h
--- netinet/ip_var.h 22 Apr 2004 01:01:41 -0000 1.68
+++ netinet/ip_var.h 23 Oct 2004 17:29:39 -0000
@@ -205,6 +205,7 @@ extern int anonportmin; /* minimum ep
extern int anonportmax; /* maximum ephemeral port */
extern int lowportmin; /* minimum reserved port */
extern int lowportmax; /* maximum reserved port */
+extern int ip_do_loopback_cksum; /* do IP checksum on loopback? */
extern struct rttimer_queue *ip_mtudisc_timeout_q;
#ifdef MBUFTRACE
extern struct mowner ip_rx_mowner;
Index: netinet/tcp_input.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/tcp_input.c,v
retrieving revision 1.209
diff -u -p -r1.209 tcp_input.c
--- netinet/tcp_input.c 15 Sep 2004 09:21:22 -0000 1.209
+++ netinet/tcp_input.c 23 Oct 2004 17:29:42 -0000
@@ -1135,10 +1135,18 @@ findpcb:
break;
default:
- /* Must compute it ourselves. */
- TCP_CSUM_COUNTER_INCR(&tcp_swcsum);
- if (in4_cksum(m, IPPROTO_TCP, toff, tlen + off) != 0)
- goto badcsum;
+ /*
+ * Must compute it ourselves. Maybe skip checksum
+ * on loopback interfaces.
+ */
+ if (__predict_true(!(m->m_pkthdr.rcvif->if_flags &
+ IFF_LOOPBACK) ||
+ tcp_do_loopback_cksum)) {
+ TCP_CSUM_COUNTER_INCR(&tcp_swcsum);
+ if (in4_cksum(m, IPPROTO_TCP, toff,
+ tlen + off) != 0)
+ goto badcsum;
+ }
break;
}
break;
Index: netinet/tcp_output.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/tcp_output.c,v
retrieving revision 1.114
diff -u -p -r1.114 tcp_output.c
--- netinet/tcp_output.c 20 May 2004 22:59:02 -0000 1.114
+++ netinet/tcp_output.c 23 Oct 2004 17:29:43 -0000
@@ -1099,12 +1099,18 @@ send:
/*
* Set ourselves up to be checksummed just before the packet
- * hits the wire.
+ * hits the wire. Maybe skip checksums on loopback interfaces.
*/
switch (af) {
#ifdef INET
case AF_INET:
- m->m_pkthdr.csum_flags = M_CSUM_TCPv4;
+ if (__predict_true(ro->ro_rt == NULL ||
+ !(ro->ro_rt->rt_ifp->if_flags &
+ IFF_LOOPBACK) ||
+ tcp_do_loopback_cksum))
+ m->m_pkthdr.csum_flags = M_CSUM_TCPv4;
+ else
+ m->m_pkthdr.csum_flags = 0;
m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum);
if (len + optlen) {
/* Fixup the pseudo-header checksum. */
@@ -1126,7 +1132,13 @@ send:
m->m_pkthdr.len = sizeof(struct ip6_hdr)
+ sizeof(struct tcphdr) + optlen + len;
#ifdef notyet
- m->m_pkthdr.csum_flags = M_CSUM_TCPv6;
+ if (__predict_true(ro->ro_rt == NULL ||
+ !(ro->ro_rt->rt_ifp->if_flags &
+ IFF_LOOPBACK) ||
+ tcp_do_loopback_cksum))
+ m->m_pkthdr.csum_flags = M_CSUM_TCPv6;
+ else
+ m->m_pkthdr.csum_flags = 0;
m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum);
#endif
if (len + optlen) {
@@ -1136,8 +1148,12 @@ send:
htons((u_int16_t) (len + optlen)));
}
#ifndef notyet
- th->th_sum = in6_cksum(m, 0, sizeof(struct ip6_hdr),
- sizeof(struct tcphdr) + optlen + len);
+ if (__predict_true(ro->ro_rt == NULL ||
+ !(ro->ro_rt->rt_ifp->if_flags &
+ IFF_LOOPBACK) ||
+ tcp_do_loopback_cksum))
+ th->th_sum = in6_cksum(m, 0, sizeof(struct ip6_hdr),
+ sizeof(struct tcphdr) + optlen + len);
#endif
break;
#endif
Index: netinet/tcp_subr.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/tcp_subr.c,v
retrieving revision 1.173
diff -u -p -r1.173 tcp_subr.c
--- netinet/tcp_subr.c 15 Sep 2004 09:21:22 -0000 1.173
+++ netinet/tcp_subr.c 23 Oct 2004 17:29:45 -0000
@@ -200,6 +200,7 @@ int tcp_compat_42 = 0;
#endif
int tcp_rst_ppslim = 100; /* 100pps */
int tcp_ackdrop_ppslim = 100; /* 100pps */
+int tcp_do_loopback_cksum = 0;
/* tcb hash */
#ifndef TCBHASHSIZE
Index: netinet/tcp_usrreq.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/tcp_usrreq.c,v
retrieving revision 1.92
diff -u -p -r1.92 tcp_usrreq.c
--- netinet/tcp_usrreq.c 25 May 2004 04:34:00 -0000 1.92
+++ netinet/tcp_usrreq.c 23 Oct 2004 17:29:46 -0000
@@ -1391,6 +1391,13 @@ sysctl_net_inet_tcp_setup2(struct sysctl
SYSCTL_DESCR("RFC1413 Identification Protocol lookups"),
sysctl_net_inet_tcp_ident, 0, NULL, sizeof(uid_t),
CTL_NET, pf, IPPROTO_TCP, TCPCTL_IDENT, CTL_EOL);
+ sysctl_createv(clog, 0, NULL, NULL,
+ CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+ CTLTYPE_INT, "do_loopback_cksum",
+ SYSCTL_DESCR("Perform TCP checksum on loopback"),
+ NULL, 0, &tcp_do_loopback_cksum, 0,
+ CTL_NET, pf, IPPROTO_TCP, TCPCTL_LOOPBACKCKSUM,
+ CTL_EOL);
}
/*
Index: netinet/tcp_var.h
===================================================================
RCS file: /cvsroot/src/sys/netinet/tcp_var.h,v
retrieving revision 1.113
diff -u -p -r1.113 tcp_var.h
--- netinet/tcp_var.h 15 Sep 2004 09:21:22 -0000 1.113
+++ netinet/tcp_var.h 23 Oct 2004 17:29:47 -0000
@@ -622,7 +622,8 @@ struct tcpstat {
#define TCPCTL_INIT_WIN_LOCAL 26 /* initial window for local nets */
#define TCPCTL_IDENT 27 /* rfc 931 identd */
#define TCPCTL_ACKDROPRATELIMIT 28 /* SYN/RST -> ACK rate limit */
-#define TCPCTL_MAXID 29
+#define TCPCTL_LOOPBACKCKSUM 29 /* do TCP checksum on loopback */
+#define TCPCTL_MAXID 30
#define TCPCTL_NAMES { \
{ 0, 0 }, \
@@ -654,6 +655,7 @@ struct tcpstat {
{ "init_win_local", CTLTYPE_INT }, \
{ "ident", CTLTYPE_STRUCT }, \
{ "ackdropppslimit", CTLTYPE_INT }, \
+ { "do_loopback_cksum", CTLTYPE_INT }, \
}
#ifdef _KERNEL
@@ -676,6 +678,7 @@ extern int tcp_ack_on_push; /* ACK immed
extern int tcp_syn_cache_limit; /* max entries for compressed state engine */
extern int tcp_syn_bucket_limit;/* max entries per hash bucket */
extern int tcp_log_refused; /* log refused connections */
+extern int tcp_do_loopback_cksum;/* do TCP checksum on loopback? */
extern int tcp_rst_ppslim;
extern int tcp_ackdrop_ppslim;
Index: netinet/udp_usrreq.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/udp_usrreq.c,v
retrieving revision 1.124
diff -u -p -r1.124 udp_usrreq.c
--- netinet/udp_usrreq.c 3 Sep 2004 18:14:09 -0000 1.124
+++ netinet/udp_usrreq.c 23 Oct 2004 17:29:47 -0000
@@ -141,6 +141,7 @@ int udpcksum = 1;
#else
int udpcksum = 0; /* XXX */
#endif
+int udp_do_loopback_cksum = 0;
struct inpcbtable udbtable;
struct udpstat udpstat;
@@ -287,10 +288,17 @@ udp_input(struct mbuf *m, ...)
break;
default:
- /* Need to compute it ourselves. */
- UDP_CSUM_COUNTER_INCR(&udp_swcsum);
- if (in4_cksum(m, IPPROTO_UDP, iphlen, len) != 0)
- goto badcsum;
+ /*
+ * Need to compute it ourselves. Maybe skip checksum
+ * on loopback interfaces.
+ */
+ if (__predict_true(!(m->m_pkthdr.rcvif->if_flags &
+ IFF_LOOPBACK) ||
+ udp_do_loopback_cksum)) {
+ UDP_CSUM_COUNTER_INCR(&udp_swcsum);
+ if (in4_cksum(m, IPPROTO_UDP, iphlen, len) != 0)
+ goto badcsum;
+ }
break;
}
}
@@ -419,15 +427,20 @@ udp6_input(struct mbuf **mp, int *offp,
}
/*
- * Checksum extended UDP header and data.
+ * Checksum extended UDP header and data. Maybe skip checksum
+ * on loopback interfaces.
*/
- if (uh->uh_sum == 0) {
- udp6stat.udp6s_nosum++;
- goto bad;
- }
- if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) {
- udp6stat.udp6s_badsum++;
- goto bad;
+ if (__predict_true(!(m->m_pkthdr.rcvif->if_flags &
+ IFF_LOOPBACK) ||
+ udp_do_loopback_cksum)) {
+ if (uh->uh_sum == 0) {
+ udp6stat.udp6s_nosum++;
+ goto bad;
+ }
+ if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) {
+ udp6stat.udp6s_badsum++;
+ goto bad;
+ }
}
/*
@@ -830,6 +843,7 @@ udp_output(struct mbuf *m, ...)
{
struct inpcb *inp;
struct udpiphdr *ui;
+ struct route *ro;
int len = m->m_pkthdr.len;
int error = 0;
va_list ap;
@@ -870,6 +884,8 @@ udp_output(struct mbuf *m, ...)
ui->ui_dport = inp->inp_fport;
ui->ui_ulen = htons((u_int16_t)len + sizeof(struct udphdr));
+ ro = &inp->inp_route;
+
/*
* Set up checksum and output datagram.
*/
@@ -877,11 +893,18 @@ udp_output(struct mbuf *m, ...)
/*
* XXX Cache pseudo-header checksum part for
* XXX "connected" UDP sockets.
+ * Maybe skip checksums on loopback interfaces.
*/
ui->ui_sum = in_cksum_phdr(ui->ui_src.s_addr,
ui->ui_dst.s_addr, htons((u_int16_t)len +
sizeof(struct udphdr) + IPPROTO_UDP));
- m->m_pkthdr.csum_flags = M_CSUM_UDPv4;
+ if (__predict_true(ro->ro_rt == NULL ||
+ !(ro->ro_rt->rt_ifp->if_flags &
+ IFF_LOOPBACK) ||
+ udp_do_loopback_cksum))
+ m->m_pkthdr.csum_flags = M_CSUM_UDPv4;
+ else
+ m->m_pkthdr.csum_flags = 0;
m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum);
} else
ui->ui_sum = 0;
@@ -890,7 +913,7 @@ udp_output(struct mbuf *m, ...)
((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */
udpstat.udps_opackets++;
- return (ip_output(m, inp->inp_options, &inp->inp_route,
+ return (ip_output(m, inp->inp_options, ro,
inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST),
inp->inp_moptions, inp->inp_socket));
@@ -1117,5 +1140,12 @@ SYSCTL_SETUP(sysctl_net_inet_udp_setup,
NULL, 0, &udp_recvspace, 0,
CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_RECVSPACE,
CTL_EOL);
+ sysctl_createv(clog, 0, NULL, NULL,
+ CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+ CTLTYPE_INT, "do_loopback_cksum",
+ SYSCTL_DESCR("Perform UDP checksum on loopback"),
+ NULL, 0, &udp_do_loopback_cksum, 0,
+ CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_LOOPBACKCKSUM,
+ CTL_EOL);
}
#endif
Index: netinet/udp_var.h
===================================================================
RCS file: /cvsroot/src/sys/netinet/udp_var.h,v
retrieving revision 1.24
diff -u -p -r1.24 udp_var.h
--- netinet/udp_var.h 21 Apr 2004 17:49:46 -0000 1.24
+++ netinet/udp_var.h 23 Oct 2004 17:29:47 -0000
@@ -71,18 +71,21 @@ struct udpstat {
#define UDPCTL_CHECKSUM 1 /* checksum UDP packets */
#define UDPCTL_SENDSPACE 2 /* default send buffer */
#define UDPCTL_RECVSPACE 3 /* default recv buffer */
-#define UDPCTL_MAXID 4
+#define UDPCTL_LOOPBACKCKSUM 4 /* do UDP checksum on loopback */
+#define UDPCTL_MAXID 5
#define UDPCTL_NAMES { \
{ 0, 0 }, \
{ "checksum", CTLTYPE_INT }, \
{ "sendspace", CTLTYPE_INT }, \
{ "recvspace", CTLTYPE_INT }, \
+ { "do_loopback_cksum", CTLTYPE_INT }, \
}
#ifdef _KERNEL
extern struct inpcbtable udbtable;
extern struct udpstat udpstat;
+extern int udp_do_loopback_cksum;
#ifdef __NO_STRICT_ALIGNMENT
#define UDP_HDR_ALIGNED_P(uh) 1
Index: netinet6/udp6_output.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/udp6_output.c,v
retrieving revision 1.18
diff -u -p -r1.18 udp6_output.c
--- netinet6/udp6_output.c 11 Jun 2004 04:10:10 -0000 1.18
+++ netinet6/udp6_output.c 23 Oct 2004 17:29:48 -0000
@@ -330,9 +330,15 @@ udp6_output(in6p, m, addr6, control, p)
ip6->ip6_src = *laddr;
ip6->ip6_dst = *faddr;
- if ((udp6->uh_sum = in6_cksum(m, IPPROTO_UDP,
- sizeof(struct ip6_hdr), plen)) == 0) {
- udp6->uh_sum = 0xffff;
+ /* Maybe skip checksum on loopback interfaces. */
+ if (__predict_true(in6p->in6p_route.ro_rt == NULL ||
+ !(in6p->in6p_route.ro_rt->rt_ifp->if_flags &
+ IFF_LOOPBACK) ||
+ udp_do_loopback_cksum)) {
+ if ((udp6->uh_sum = in6_cksum(m, IPPROTO_UDP,
+ sizeof(struct ip6_hdr), plen)) == 0) {
+ udp6->uh_sum = 0xffff;
+ }
}
if (in6p->in6p_flags & IN6P_MINMTU)
@@ -361,9 +367,16 @@ udp6_output(in6p, m, addr6, control, p)
flags = (in6p->in6p_socket->so_options &
(SO_DONTROUTE | SO_BROADCAST));
bcopy(&faddr->s6_addr[12], &ui->ui_dst, sizeof(ui->ui_dst));
- udp6->uh_sum = in_cksum(m, hlen + plen);
- if (udp6->uh_sum == 0)
- udp6->uh_sum = 0xffff;
+
+ /* Maybe skip checksum on loopback interfaces. */
+ if (__predict_true(in6p->in6p_route.ro_rt == NULL ||
+ !(in6p->in6p_route.ro_rt->rt_ifp->if_flags &
+ IFF_LOOPBACK) ||
+ udp_do_loopback_cksum)) {
+ udp6->uh_sum = in_cksum(m, hlen + plen);
+ if (udp6->uh_sum == 0)
+ udp6->uh_sum = 0xffff;
+ }
ip->ip_len = htons(hlen + plen);
ip->ip_ttl = in6_selecthlim(in6p, NULL); /* XXX */
Index: netinet6/udp6_usrreq.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/udp6_usrreq.c,v
retrieving revision 1.63
diff -u -p -r1.63 udp6_usrreq.c
--- netinet6/udp6_usrreq.c 25 May 2004 04:34:01 -0000 1.63
+++ netinet6/udp6_usrreq.c 23 Oct 2004 17:29:48 -0000
@@ -445,4 +445,11 @@ SYSCTL_SETUP(sysctl_net_inet6_udp6_setup
NULL, 0, &udp6_recvspace, 0,
CTL_NET, PF_INET6, IPPROTO_UDP, UDP6CTL_RECVSPACE,
CTL_EOL);
+ sysctl_createv(clog, 0, NULL, NULL,
+ CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+ CTLTYPE_INT, "do_loopback_cksum",
+ SYSCTL_DESCR("Perform UDP checksum on loopback"),
+ NULL, 0, &udp_do_loopback_cksum, 0,
+ CTL_NET, PF_INET6, IPPROTO_UDP, UDP6CTL_LOOPBACKCKSUM,
+ CTL_EOL);
}
Index: netinet6/udp6_var.h
===================================================================
RCS file: /cvsroot/src/sys/netinet6/udp6_var.h,v
retrieving revision 1.15
diff -u -p -r1.15 udp6_var.h
--- netinet6/udp6_var.h 4 Sep 2003 09:17:10 -0000 1.15
+++ netinet6/udp6_var.h 23 Oct 2004 17:29:48 -0000
@@ -87,12 +87,14 @@ struct udp6stat {
*/
#define UDP6CTL_SENDSPACE 1 /* default send buffer */
#define UDP6CTL_RECVSPACE 2 /* default recv buffer */
-#define UDP6CTL_MAXID 3
+#define UDP6CTL_LOOPBACKCKSUM 3 /* do UDP checksum on loopback? */
+#define UDP6CTL_MAXID 4
#define UDP6CTL_NAMES { \
{ 0, 0 }, \
{ "sendspace", CTLTYPE_INT }, \
{ "recvspace", CTLTYPE_INT }, \
+ { "do_loopback_cksum", CTLTYPE_INT }, \
}
#ifdef _KERNEL
--Apple-Mail-22--13025075--
--Apple-Mail-23--13025068
content-type: application/pgp-signature; x-mac-type=70674453;
name=PGP.sig
content-description: This is a digitally signed message part
content-disposition: inline; filename=PGP.sig
content-transfer-encoding: 7bit
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (Darwin)
iD8DBQFBeperOpVKkaBm8XkRAoXHAKCVrIS+Dqq/IDY+rT5LoDnQsm4OeQCghn+f
IceXbFDezswsfyC1KWitEng=
=InT3
-----END PGP SIGNATURE-----
--Apple-Mail-23--13025068--