diff options
Diffstat (limited to 'tags/2.6.20-2/20962_linux-2.6-xen-add-packet_auxdata-cmsg-1.patch')
-rw-r--r-- | tags/2.6.20-2/20962_linux-2.6-xen-add-packet_auxdata-cmsg-1.patch | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/tags/2.6.20-2/20962_linux-2.6-xen-add-packet_auxdata-cmsg-1.patch b/tags/2.6.20-2/20962_linux-2.6-xen-add-packet_auxdata-cmsg-1.patch new file mode 100644 index 0000000..16f11fa --- /dev/null +++ b/tags/2.6.20-2/20962_linux-2.6-xen-add-packet_auxdata-cmsg-1.patch @@ -0,0 +1,233 @@ +From: Herbert Xu <herbert.xu@redhat.com> +Subject: [RHEL5 PATCH] [PACKET]: Add PACKET_AUXDATA cmsg +Date: Wed, 10 Jan 2007 20:17:36 +1100 +Message-Id: <20070110091736.GA28579@gondor.apana.org.au> +Changelog: xen: Add PACKET_AUXDATA cmsg + + +Hi: + +RHEL5 BZ 219681 + +This patch forms part of the solution to #219681 where the DHCP server +can't serve any requests from clients running (in different domains) +on the same Xen host. + +I've sent a similar patch (without the Xen-specific code) upstream. + +This obsoletes the previous patch that computed the checksums in +kernel-space. + +[PACKET]: Add PACKET_AUXDATA cmsg + +HCP servers/clients using AF_PACKET) to be able to serve another +client on the same Xen host. + +The problem is that packets between different domains on the same +Xen host only have partial checksums. Unfortunately this piece of +information is not passed along in AF_PACKET unless you're using +the mmap interface. Since dhcpd doesn't support packet-mmap, UDP +packets from the same host come out with apparently bogus checksums. + +This patch adds a mechanism for AF_PACKET recvmsg(2) to return the +status along with the packet. It does so by adding a new cmsg that +contains this information along with some other relevant data such +as the original packet length. + +I didn't include the time stamp information since there is already +a cmsg for that. + +This patch also changes the mmap code to set the CSUMNOTREADY flag +on all packets instead of just outoing packets on cooked sockets. + +Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> + +Index: linux-2.6.20.i386/include/linux/if_packet.h +=================================================================== +--- linux-2.6.20.i386.orig/include/linux/if_packet.h ++++ linux-2.6.20.i386/include/linux/if_packet.h +@@ -41,6 +41,7 @@ struct sockaddr_ll + #define PACKET_RX_RING 5 + #define PACKET_STATISTICS 6 + #define PACKET_COPY_THRESH 7 ++#define PACKET_AUXDATA 8 + + struct tpacket_stats + { +@@ -48,6 +49,15 @@ struct tpacket_stats + unsigned int tp_drops; + }; + ++struct tpacket_auxdata ++{ ++ __u32 tp_status; ++ __u32 tp_len; ++ __u32 tp_snaplen; ++ __u16 tp_mac; ++ __u16 tp_net; ++}; ++ + struct tpacket_hdr + { + unsigned long tp_status; +Index: linux-2.6.20.i386/net/packet/af_packet.c +=================================================================== +--- linux-2.6.20.i386.orig/net/packet/af_packet.c ++++ linux-2.6.20.i386/net/packet/af_packet.c +@@ -200,7 +200,8 @@ struct packet_sock { + #endif + struct packet_type prot_hook; + spinlock_t bind_lock; +- char running; /* prot_hook is attached*/ ++ unsigned int running:1, /* prot_hook is attached*/ ++ auxdata:1; + int ifindex; /* bound device */ + __be16 num; + #ifdef CONFIG_PACKET_MULTICAST +@@ -214,6 +215,10 @@ struct packet_sock { + #endif + }; + ++#define PACKET_SKB_CB(__skb) ((struct tpacket_auxdata *)((__skb)->cb)) ++ ++extern int skb_checksum_setup(struct sk_buff *skb); ++ + #ifdef CONFIG_PACKET_MMAP + + static inline char *packet_lookup_frame(struct packet_sock *po, unsigned int position) +@@ -462,6 +467,7 @@ static int packet_rcv(struct sk_buff *sk + u8 * skb_head = skb->data; + int skb_len = skb->len; + unsigned int snaplen, res; ++ struct tpacket_auxdata *aux; + + if (skb->pkt_type == PACKET_LOOPBACK) + goto drop; +@@ -523,6 +529,18 @@ static int packet_rcv(struct sk_buff *sk + if (dev->hard_header_parse) + sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr); + ++ if (skb_checksum_setup(skb)) ++ goto drop_n_acct; ++ ++ aux = PACKET_SKB_CB(skb); ++ aux->tp_status = TP_STATUS_USER; ++ if (skb->ip_summed == CHECKSUM_PARTIAL) ++ aux->tp_status |= TP_STATUS_CSUMNOTREADY; ++ aux->tp_len = skb->len; ++ aux->tp_snaplen = snaplen; ++ aux->tp_mac = 0; ++ aux->tp_net = skb->nh.raw - skb->data; ++ + if (pskb_trim(skb, snaplen)) + goto drop_n_acct; + +@@ -582,8 +600,6 @@ static int tpacket_rcv(struct sk_buff *s + else if (skb->pkt_type == PACKET_OUTGOING) { + /* Special case: outgoing packets have ll header at head */ + skb_pull(skb, skb->nh.raw - skb->data); +- if (skb->ip_summed == CHECKSUM_PARTIAL) +- status |= TP_STATUS_CSUMNOTREADY; + } + } + +@@ -595,6 +611,11 @@ static int tpacket_rcv(struct sk_buff *s + if (snaplen > res) + snaplen = res; + ++ if (skb_checksum_setup(skb)) ++ goto drop; ++ if (skb->ip_summed == CHECKSUM_PARTIAL) ++ status |= TP_STATUS_CSUMNOTREADY; ++ + if (sk->sk_type == SOCK_DGRAM) { + macoff = netoff = TPACKET_ALIGN(TPACKET_HDRLEN) + 16; + } else { +@@ -1119,6 +1140,11 @@ static int packet_recvmsg(struct kiocb * + if (msg->msg_name) + memcpy(msg->msg_name, skb->cb, msg->msg_namelen); + ++ if (pkt_sk(sk)->auxdata) { ++ struct tpacket_auxdata *aux = PACKET_SKB_CB(skb); ++ put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(*aux), aux); ++ } ++ + /* + * Free or return the buffer as appropriate. Again this + * hides all the races and re-entrancy issues from us. +@@ -1317,6 +1343,7 @@ static int + packet_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) + { + struct sock *sk = sock->sk; ++ struct packet_sock *po = pkt_sk(sk); + int ret; + + if (level != SOL_PACKET) +@@ -1369,6 +1396,18 @@ packet_setsockopt(struct socket *sock, i + return 0; + } + #endif ++ case PACKET_AUXDATA: ++ { ++ int val; ++ ++ if (optlen < sizeof(val)) ++ return -EINVAL; ++ if (copy_from_user(&val, optval, sizeof(val))) ++ return -EFAULT; ++ ++ po->auxdata = !!val; ++ return 0; ++ } + default: + return -ENOPROTOOPT; + } +@@ -1378,8 +1417,11 @@ static int packet_getsockopt(struct sock + char __user *optval, int __user *optlen) + { + int len; ++ int val; + struct sock *sk = sock->sk; + struct packet_sock *po = pkt_sk(sk); ++ void *data; ++ struct tpacket_stats st; + + if (level != SOL_PACKET) + return -ENOPROTOOPT; +@@ -1392,9 +1434,6 @@ static int packet_getsockopt(struct sock + + switch(optname) { + case PACKET_STATISTICS: +- { +- struct tpacket_stats st; +- + if (len > sizeof(struct tpacket_stats)) + len = sizeof(struct tpacket_stats); + spin_lock_bh(&sk->sk_receive_queue.lock); +@@ -1403,16 +1442,23 @@ static int packet_getsockopt(struct sock + spin_unlock_bh(&sk->sk_receive_queue.lock); + st.tp_packets += st.tp_drops; + +- if (copy_to_user(optval, &st, len)) +- return -EFAULT; ++ data = &st; ++ break; ++ case PACKET_AUXDATA: ++ if (len > sizeof(int)) ++ len = sizeof(int); ++ val = po->auxdata; ++ ++ data = &val; + break; +- } + default: + return -ENOPROTOOPT; + } + + if (put_user(len, optlen)) + return -EFAULT; ++ if (copy_to_user(optval, data, len)) ++ return -EFAULT; + return 0; + } + |