From: "Jim C. Brown" <jma5@umd.edu>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] vde-inject 0.0.0
Date: Wed, 8 Feb 2006 18:13:25 -0500 [thread overview]
Message-ID: <20060208231325.GA28610@jbrown.mylinuxbox.org> (raw)
[-- Attachment #1: Type: text/plain, Size: 1034 bytes --]
I've implemented a prototype kernel module as described in this email:
http://lists.gnu.org/archive/html/qemu-devel/2005-08/msg00123.html
Full source code and makefile attached as a bz2ball.
Not really strictly related to VDE, this module basically enables the creation
of a user space bridge.
Basically it creates /proc/vdeinject and uses that file to expose the netif_rx()
function. When you write a packet to it, the module handles all the skb stuff
and attempts to inject the packet into eth0. Currently my VDE setup seems to
be broken (my vde_pcap and vde_packet in particular don't want to work with my
vde_switch). It appears to work tho (as when using vde_pcap_inject to connect
to tap0, a dhcpd server that I was running on tap0 was able to pick up dhcp
requests from a guest).
Also, for those who want to see live updates as soon as I make changes, here
is a link:
http://jma-box.student.umd.edu:8080/vde-inject/vdeinject.c
--
Infinite complexity begets infinite beauty.
Infinite precision begets infinite perfection.
[-- Attachment #2: vde-inject.tbz --]
[-- Type: application/octet-stream, Size: 6767 bytes --]
[-- Attachment #3: vde_pcap_inject.c --]
[-- Type: text/plain, Size: 5846 bytes --]
/* Copyright (C) 2005 Jim Brown
* Copyright (C) 2005 Henrik Nordstrom
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
*
* The VDE connection setup (open_vde) is loosely based on a similar
* functions in vdeq.c by Renzo Davoli
*/
#include <sys/socket.h>
#include <netpacket/packet.h>
#include <net/ethernet.h> /* the L2 protocols */
#include <sys/ioctl.h>
#include <fcntl.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <sys/un.h>
#include <errno.h>
#include <signal.h>
#include <linux/if_tun.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <pcap.h>
#define SWITCH_MAGIC 0xfeedface
#define BUFSIZE 2048
#define ETH_ALEN 6
#define PCAP_READ_TIMEOUT 1
enum request_type {
REQ_NEW_CONTROL
};
struct request_v3 {
uint32_t magic;
uint32_t version;
enum request_type type;
struct sockaddr_un sock;
};
static int
open_vde(char *name, int intno, int group)
{
int pid = getpid();
struct request_v3 req;
int fdctl;
int fddata;
struct sockaddr_un sock;
if ((fdctl = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
perror("socket");
exit(1);
}
sock.sun_family = AF_UNIX;
snprintf(sock.sun_path, sizeof(sock.sun_path), "%s", name);
if (connect(fdctl, (struct sockaddr *) &sock, sizeof(sock))) {
perror("connect");
exit(1);
}
memset(&req, 0, sizeof(req));
req.magic = SWITCH_MAGIC;
req.version = 3;
req.type = REQ_NEW_CONTROL + ((group > 0) ? ((geteuid() << 8) + group) << 8 : 0);
req.sock.sun_family = AF_UNIX;
sprintf(&req.sock.sun_path[1], "%5d-%2d", pid, intno);
if ((fddata = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
perror("socket");
exit(1);
}
if (bind(fddata, (struct sockaddr *) &req.sock, sizeof(req.sock)) < 0) {
perror("bind");
exit(1);
}
if (send(fdctl, &req, sizeof(req), 0) < 0) {
perror("send");
exit(1);
}
if (recv(fdctl, &sock, sizeof(struct sockaddr_un), 0) < 0) {
perror("recv");
exit(1);
}
if (connect(fddata, (struct sockaddr *) &sock, sizeof(struct sockaddr_un)) < 0) {
perror("connect");
exit(1);
}
/* note: fdctl is intentionally leaked. Closed on exit by the OS. */
return fddata;
}
void
set_nonblocking(int fd)
{
int fl = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, (fl | O_NONBLOCK));
}
void
pcap_relay(u_char *args, const struct pcap_pkthdr *header, const u_char * packet)
{
int * vde_socket = (int *)args;
send(*vde_socket, packet, header->len, 0);
}
static void
wrap_dispatch(fd_set * rfd, pcap_t * handle, int vde_socket)
{
int n;
if (FD_ISSET(pcap_get_selectable_fd(handle), rfd)) {
n = pcap_dispatch(handle, -1, pcap_relay, (u_char *)&vde_socket);
}
}
int pcap_sendpacket(pcap_t * handle, const u_char * packet, int len, const char * dev)
{
struct sockaddr_ll sa1;
struct ifreq ifr;
strncpy (ifr.ifr_name, dev, sizeof(ifr.ifr_name) - 1);
ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0';
if (ioctl(pcap_fileno(handle), SIOCGIFINDEX, &ifr) == -1)
return -1;
memset(&sa1, 0, sizeof (sa1));
sa1.sll_family = AF_PACKET;
sa1.sll_ifindex = ifr.ifr_ifindex;
sa1.sll_protocol = htons(ETH_P_ALL);
if (sendto(pcap_fileno(handle), packet, len, 0, (struct sockaddr *)&sa1, sizeof(sa1)) == len)
{
return 0;
}
else
{
return -1;
}
}
int vde_inject_fd = -1;
static void
relay(fd_set * rfd, int vde_socket, pcap_t * handle, const char * dev)
{
int n;
char packet[65536];
union {
struct sockaddr_ll ll;
struct sockaddr_un un;
} sa;
socklen_t sa_len = sizeof(sa);
if (FD_ISSET(vde_socket, rfd)) {
n = recvfrom(vde_socket, packet, sizeof(packet), 0, (struct sockaddr *)&sa, &sa_len);
if (n > 0)
{
pcap_sendpacket(handle, packet, n, dev);
vde_inject_fd = open("/proc/vdeinject", O_WRONLY);
if (vde_inject_fd != -1)
{
write(vde_inject_fd, packet, n);
close(vde_inject_fd);
}
}
else if (n == 0)
exit(1);
else if (errno != EINTR) {
perror("recv:");
exit(1);
}
}
}
pcap_t * a;
void handle_cl(int signal)
{
printf("Caught signal %d, cleaning up ...\n", signal);
pcap_close(a);
exit(0);
}
int
main(int argc, char **argv)
{
int vde_socket;
pcap_t * handle;
char errbuf[PCAP_ERRBUF_SIZE];
const u_char * packet;
fd_set rfd;
int fds;
if (argc != 3) {
printf("Usage: %s interface vde_socket\n", argv[0]);
exit(1);
}
handle = pcap_open_live(argv[1], BUFSIZ, 1, PCAP_READ_TIMEOUT, errbuf);
if (handle == NULL)
{
printf("%s\n", errbuf);
exit(1);
}
vde_socket = open_vde(argv[2], 0, 0);
set_nonblocking(vde_socket);
a = handle;
signal(SIGINT, handle_cl);
fds = pcap_get_selectable_fd(handle);
if (vde_socket > fds)
fds = vde_socket;
fds += 1;
FD_ZERO(&rfd);
int i;
for (;;) {
int n;
FD_SET(pcap_get_selectable_fd(handle), &rfd);
FD_SET(vde_socket, &rfd);
n = select(fds, &rfd, NULL, NULL, NULL);
if (n > 0) {
wrap_dispatch(&rfd, handle, vde_socket);
relay(&rfd, vde_socket, handle, argv[1]);
} else if (n < 0 && errno != EINTR) {
perror("select:");
}
}
}
next reply other threads:[~2006-02-08 23:13 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-02-08 23:13 Jim C. Brown [this message]
2006-02-09 5:39 ` [Qemu-devel] vde-inject 0.0.1 Jim C. Brown
2006-02-09 18:23 ` Mulyadi Santosa
2006-02-10 5:34 ` Mulyadi Santosa
2006-02-10 17:09 ` Jim C. Brown
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20060208231325.GA28610@jbrown.mylinuxbox.org \
--to=jma5@umd.edu \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.