From owner-freebsd-net@FreeBSD.ORG Thu Nov 18 16:50:01 2004 Return-Path: Delivered-To: freebsd-net@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 6534616A4CE for ; Thu, 18 Nov 2004 16:50:01 +0000 (GMT) Received: from fledge.watson.org (fledge.watson.org [204.156.12.50]) by mx1.FreeBSD.org (Postfix) with ESMTP id C759E43D5A for ; Thu, 18 Nov 2004 16:50:00 +0000 (GMT) (envelope-from robert@fledge.watson.org) Received: from fledge.watson.org (localhost [127.0.0.1]) by fledge.watson.org (8.13.1/8.13.1) with ESMTP id iAIGmSTf073999; Thu, 18 Nov 2004 11:48:28 -0500 (EST) (envelope-from robert@fledge.watson.org) Received: from localhost (robert@localhost)iAIGmSWh073996; Thu, 18 Nov 2004 16:48:28 GMT (envelope-from robert@fledge.watson.org) Date: Thu, 18 Nov 2004 16:48:28 +0000 (GMT) From: Robert Watson X-Sender: robert@fledge.watson.org To: Elton Machado In-Reply-To: <419CACF2.5020402@norteglobal.com> Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII cc: net@freebsd.org Subject: Re: How can I create and use a Tap device X-BeenThere: freebsd-net@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Networking and TCP/IP with FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 18 Nov 2004 16:50:01 -0000 On Thu, 18 Nov 2004, Elton Machado wrote: > I need a virtual ethernet device, can I use tap for that? > > How can I create it? Really quite easy, and fairly well documented in the man page. Basically, you need to: - Load the module or compile it in. - Open /dev/tapX where X is the interface number. When the device is opened, the network interface will be instantiated. - Read ethernet frames -- you'll get one per read, make sure to provide enough buffer room for a full frame at the MTU of choice. - Write ethernet frames -- one per write. Typically input from a tap device will look something like this: char packet[MAXPACKET]; struct ether_header *h; ssize_t len, recvlen; len = MAXPACKET; recvlen = read(tap_fd, packet, len); if (recvlen == -1) { perror("read"); return (-1); } if (len < sizeof(struct ether_header)) { fprintf(stderr, "short frame read"); return (-1); } eh = (struct ether_header *)(packet); ... And a write will look something like this: sendlen = write(tap_fd, packet, recvlen); if (sendlen == -1) { perror("write"); return (-1); } if (sendlen != recvlen) { fprintd(stderr, "short frame write"); return (-1); } Make sure to properly initialize the ethernet frame header with the protocol type, source/destination ethernet addresses, and so on. A couple of performance caveats: - Every packet delivery requires going to user space, so possibly a context switch and certainly a system call. - Every packet is copied to user space, and/or from user space, so you get a lot of memory copying. For prototyping or light-weight stuff, tap is a great tool, but to improve performance you want to run network code in the kernel, especially if there are other applications running (and/or processing packets), which will increase the number of context switches. The cost as it stands isn't bad -- I regularly use tap-derived tunnel software for remote network access without a hitch. There were recently some posts made with patches to optimize the allocation of kernel memory for packets sent using a tap device, which are in the mailing list archives (not sure if they were merged yet). Robert N M Watson FreeBSD Core Team, TrustedBSD Projects robert@fledge.watson.org Principal Research Scientist, McAfee Research