=back
-=head1 VNET COMMANDS
-
-The Virtual Network interfaces for Xen.
-
-FIXME: This needs a lot more explanation, or it needs to be ripped
-out entirely.
-
-=over 4
-
-=item B<vnet-list> [B<-l>|B<--long>]
-
-List vnets.
-
-=item B<vnet-create> I<config>
-
-Create a vnet from a config file.
-
-=item B<vnet-delete> I<vnetid>
-
-Delete a vnet.
-
-=back
-
=head1 SEE ALSO
B<xmdomain.cfg>(5), B<xentop>(1)
The bus, dev or func may be given in hex,
e.g. 0xff. With no leading 0x they are interpreted as decimal.
-<h2>(vnet) element</h2>
-Defines the virtual networks associated with vifs (may go away soon).
-Contains a list of vif elements:
-<ul>
- <li>id: id of the vif being configured.
- <li>vnet: id of vnet the vif is assigned to.
-</ul>
-
<h1>Examples</h1>
<p> A vm with 64 MB memory, root on /dev/xda1 (mapped from /dev/hda1),
one vif with default MAC.
)
</pre></code>
-<p>A vm with 64 MB memory, NFS root, and 2 vifs on separate vnets.
-<code><pre>
-(vm
- (name xendom2)
- (memory 64)
- # Define a linux image.
- (image
- (linux
- (kernel "/boot/vmlinuz-2.4.26-xen")
- (ip "::::xendom2:eth0:dhcp")
- (root "/dev/nfs")
- (args "rw fastboot nfsroot=15.144.25.79:/opt/xen/xendom2 4")
- )
- )
- # Define some vifs, with ids for use later.
- (device (vif (@ (id vif1)) (mac aa:00:00:00:00:12)))
- (device (vif (@ (id vif2)) (mac aa:00:00:00:10:12)))
-
- # Configure vnets. Refer to vifs by id.
- (vnet (vif (id vif1) (vnet 1))
- (vif (id vif2) (vnet 2)))
-
-)
-</pre></code>
-
</body>
</html>
{\tt xend\_console\_disconnect(self, id)}:\\
Disconnect any console TCP connection.
-\item {\tt GET /vnet}\\
- {\tt xend\_vnets()}:\\
- Get list of vnets (virtual networks).
-
-\item {\tt GET /vnet/[id]}\\
- {\tt xend\_vnet(id)}:\\
- Get information about a virtual network.
-
-\item {\tt POST /vnet create(config)}\\
- {\tt xend\_vnet\_create(conf)}:\\
- Create a vnet.
-
-\item {\tt POST /vnet/[id] delete()}\\
- {\tt xend\_vnet\_delete(id)}:\\
- Delete a vnet.
-
\item {\tt POST /event inject(event)}\\
{\tt xend\_event\_inject(sxpr)}:\\
Inject an event.
{\bfseries Ctrl+Alt+1} switches back to HVM guest's VGA.\\
{\bfseries Ctrl+Alt+3} switches to serial port output. It captures serial output from the HVM guest. It works only if the HVM guest was configured to use the serial port. \\
-\chapter{Vnets - Domain Virtual Networking}
-
-Xen optionally supports virtual networking for domains using {\em vnets}.
-These emulate private LANs that domains can use. Domains on the same
-vnet can be hosted on the same machine or on separate machines, and the
-vnets remain connected if domains are migrated. Ethernet traffic
-on a vnet is tunneled inside IP packets on the physical network. A vnet is a virtual
-network and addressing within it need have no relation to addressing on
-the underlying physical network. Separate vnets, or vnets and the physical network,
-can be connected using domains with more than one network interface and
-enabling IP forwarding or bridging in the usual way.
-
-Vnet support is included in \texttt{xm} and \xend:
-\begin{verbatim}
-# xm vnet-create <config>
-\end{verbatim}
-creates a vnet using the configuration in the file \verb|<config>|.
-When a vnet is created its configuration is stored by \xend and the vnet persists until it is
-deleted using
-\begin{verbatim}
-# xm vnet-delete <vnetid>
-\end{verbatim}
-The vnets \xend knows about are listed by
-\begin{verbatim}
-# xm vnet-list
-\end{verbatim}
-More vnet management commands are available using the
-\texttt{vn} tool included in the vnet distribution.
-
-The format of a vnet configuration file is
-\begin{verbatim}
-(vnet (id <vnetid>)
- (bridge <bridge>)
- (vnetif <vnet interface>)
- (security <level>))
-\end{verbatim}
-White space is not significant. The parameters are:
-\begin{itemize}
- \item \verb|<vnetid>|: vnet id, the 128-bit vnet identifier. This can be given
- as 8 4-digit hex numbers separated by colons, or in short form as a single 4-digit hex number.
- The short form is the same as the long form with the first 7 fields zero.
- Vnet ids must be non-zero and id 1 is reserved.
-
- \item \verb|<bridge>|: the name of a bridge interface to create for the vnet. Domains
- are connected to the vnet by connecting their virtual interfaces to the bridge.
- Bridge names are limited to 14 characters by the kernel.
-
- \item \verb|<vnetif>|: the name of the virtual interface onto the vnet (optional). The
- interface encapsulates and decapsulates vnet traffic for the network and is attached
- to the vnet bridge. Interface names are limited to 14 characters by the kernel.
-
- \item \verb|<level>|: security level for the vnet (optional). The level may be one of
- \begin{itemize}
- \item \verb|none|: no security (default). Vnet traffic is in clear on the network.
- \item \verb|auth|: authentication. Vnet traffic is authenticated using IPSEC
- ESP with hmac96.
- \item \verb|conf|: confidentiality. Vnet traffic is authenticated and encrypted
- using IPSEC ESP with hmac96 and AES-128.
- \end{itemize}
- Authentication and confidentiality are experimental and use hard-wired keys at present.
-\end{itemize}
-When a vnet is created its configuration is stored by \xend and the vnet persists until it is
-deleted using \texttt{xm vnet-delete <vnetid>}. The interfaces and bridges used by vnets
-are visible in the output of \texttt{ifconfig} and \texttt{brctl show}.
-
-\section{Example}
-If the file \path{vnet97.sxp} contains
-\begin{verbatim}
-(vnet (id 97) (bridge vnet97) (vnetif vnif97)
- (security none))
-\end{verbatim}
-Then \texttt{xm vnet-create vnet97.sxp} will define a vnet with id 97 and no security.
-The bridge for the vnet is called vnet97 and the virtual interface for it is vnif97.
-To add an interface on a domain to this vnet set its bridge to vnet97
-in its configuration. In Python:
-\begin{verbatim}
-vif="bridge=vnet97"
-\end{verbatim}
-In sxp:
-\begin{verbatim}
-(dev (vif (mac aa:00:00:01:02:03) (bridge vnet97)))
-\end{verbatim}
-Once the domain is started you should see its interface in the output of \texttt{brctl show}
-under the ports for \texttt{vnet97}.
-
-To get best performance it is a good idea to reduce the MTU of a domain's interface
-onto a vnet to 1400. For example using \texttt{ifconfig eth0 mtu 1400} or putting
-\texttt{MTU=1400} in \texttt{ifcfg-eth0}.
-You may also have to change or remove cached config files for eth0 under
-\texttt{/etc/sysconfig/networking}. Vnets work anyway, but performance can be reduced
-by IP fragmentation caused by the vnet encapsulation exceeding the hardware MTU.
-
-\section{Installing vnet support}
-Vnets are implemented using a kernel module, which needs to be loaded before
-they can be used. You can either do this manually before starting \xend, using the
-command \texttt{vn insmod}, or configure \xend to use the \path{network-vnet}
-script in the xend configuration file \texttt{/etc/xend/xend-config.sxp}:
-\begin{verbatim}
-(network-script network-vnet)
-\end{verbatim}
-This script insmods the module and calls the \path{network-bridge} script.
-
-The vnet code is not compiled and installed by default.
-To compile the code and install on the current system
-use \texttt{make install} in the root of the vnet source tree,
-\path{tools/vnet}. It is also possible to install to an installation
-directory using \texttt{make dist}. See the \path{Makefile} in
-the source for details.
-
-The vnet module creates vnet interfaces \texttt{vnif0002},
-\texttt{vnif0003} and \texttt{vnif0004} by default. You can test that
-vnets are working by configuring IP addresses on these interfaces
-and trying to ping them across the network. For example, using machines
-hostA and hostB:
-\begin{verbatim}
-hostA# ifconfig vnif0004 192.0.2.100 up
-hostB# ifconfig vnif0004 192.0.2.101 up
-hostB# ping 192.0.2.100
-\end{verbatim}
-
-The vnet implementation uses IP multicast to discover vnet interfaces, so
-all machines hosting vnets must be reachable by multicast. Network switches
-are often configured not to forward multicast packets, so this often
-means that all machines using a vnet must be on the same LAN segment,
-unless you configure vnet forwarding.
-
-You can test multicast coverage by pinging the vnet multicast address:
-\begin{verbatim}
-# ping -b 224.10.0.1
-\end{verbatim}
-You should see replies from all machines with the vnet module running.
-You can see if vnet packets are being sent or received by dumping traffic
-on the vnet UDP port:
-\begin{verbatim}
-# tcpdump udp port 1798
-\end{verbatim}
-
-If multicast is not being forwarded between machines you can configure
-multicast forwarding using vn. Suppose we have machines hostA on 192.0.2.200
-and hostB on 192.0.2.211 and that multicast is not forwarded between them.
-We use vn to configure each machine to forward to the other:
-\begin{verbatim}
-hostA# vn peer-add hostB
-hostB# vn peer-add hostA
-\end{verbatim}
-Multicast forwarding needs to be used carefully - you must avoid creating forwarding
-loops. Typically only one machine on a subnet needs to be configured to forward,
-as it will forward multicasts received from other machines on the subnet.
%% Chapter Glossary of Terms moved to glossary.tex
\chapter{Glossary of Terms}
+++ /dev/null
-This directory contains the implementation of vnets:
-virtual private networks for virtual machines.
-
-make
- - compile in local dirs. The module is in vnet-module/vnet_module.ko.
-
-make dist
- - compile and install into $(XEN_ROOT)/dist/install,
- - where XEN_ROOT is the root of the xen tree.
-
-make install
- - compile and install into system.
-
-By default the makefiles expect this code to have been installed
-in tools/vnet in a xen source tree. If compiling outside the xen
-source tree, set XEN_ROOT to the location of the xen source.
-You can do this in the environment or in a Make.local file
-in the current directory (see Make.env for details).
-
-The xen0 kernel must have been compiled before building the vnet module.
-The vnet module installs to
- /lib/modules/<kernel version>-xen0/kernel/xen/vnet_module.ko
-
-The vnet module should be loaded before starting xend, or
-xend will fail to create any persistent vnets it has in its configuration.
-The script network-vnet is a modified version of the xen network script
-that loads the module if it's not already loaded.
-
-The module uses kernel crypto functions, and these need to be
-enabled in the xen0 kernel config. They should be on by default -
-if they're not you will get compile or insmod errors (see below).
-
-Kernel config options:
-
-1) You will need to have your xen0 kernel compiled with HMAC_SUPPORT
- 2.6.x = (MAIN MENU: Cryptographic Options -> HMAC Support)
- BEFORE running "make install".
-
-2) You will want at least some of the other algorithms listed under
- "Cryptographic Options" for the kernel compiled as modules.
-
-3) You will want the networking IPsec/VLAN options compiled in as modules
- 2.6.x = (MAIN MENU: Device Drivers -> Networking Support ->
- Networking Options ->
- IP: AH transformation
- IP: ESP transformation
- IP: IPComp transformation
- IP: tunnel transformation
-
- IPsec user configuration interface
-
- 802.1Q VLAN Support
-
-Please refer to the additional documentation found in tools/vnet/doc for
-proper syntax and config file parameters.
+++ /dev/null
-This directory contains the implementation of vnets:
-virtual private networks for virtual machines.
-
-See 00INSTALL for build instructions, doc/ for more information
-and examples/ for example configurations.
-
-The vnet implementation can be run using a kernel module
-or a user-space daemon. The kernel module is in vnet-module/ and the
-user-space daemon (varpd) is in vnetd/. The user-space daemon
-needs the tun/tap kernel module. Vnets use multicast to find
-virtual interfaces and support broadcast. Either implementation can
-tunnel multicast packets to other implementations if wide-area
-multicast routing is not available.
-
-Mike Wray <mike.wray@hp.com>
\ No newline at end of file
+++ /dev/null
-# -*- mode: Makefile; -*-
-
-# Include any local overrides.
--include $(VNET_ROOT)/Make.local
-
-# If building vnets outside the xen source tree, set XEN_ROOT to the
-# absolute path of the root of the xen source tree. Edit this file
-# or set XEN_ROOT in Make.local, the make command line or
-# the environment. For example put this in Make.local:
-# export XEN_ROOT = $(shell cd ~/xen-unstable.hg && pwd)
-
-export XEN_ROOT ?= $(shell cd $(VNET_ROOT)/../.. && pwd)
-
-export LINUX_SERIES ?= 2.6
-
-DISTDIR ?= $(XEN_ROOT)/dist
-export DESTDIR ?= $(DISTDIR)/install
-
-export VNET_MODULE_DIR = $(VNET_ROOT)/vnet-module
-export VNETD_DIR = $(VNET_ROOT)/vnetd
-export LIBXUTIL_DIR = $(VNET_ROOT)/libxutil
-
-
-export GC_DIR = $(VNET_ROOT)/build/gc
-export GC_INCLUDE = $(GC_DIR)/include
-export GC_LIB_DIR = $(GC_DIR)/lib
-export GC_LIB_A = $(GC_LIB_DIR)/libgc.a
-export GC_LIB_SO = $(GC_LIB_DIR)/libgc.so
+++ /dev/null
-# -*- mode: Makefile; -*-
-
-ifndef VNET_ROOT
-export VNET_ROOT = $(shell pwd)
-include $(VNET_ROOT)/Make.env
-endif
-
-SUBDIRS:=
-SUBDIRS+= examples
-SUBDIRS+= scripts
-SUBDIRS+= gc
-SUBDIRS+= libxutil
-SUBDIRS+= vnetd
-SUBDIRS+= vnet-module
-
-.PHONY: all
-all: compile
-
-gc.tar.gz:
- #wget http://www.hpl.hp.com/personal/Hans_Boehm/gc/gc_source/$@
- wget $(XEN_EXTFILES_URL)/$@
-
-.PHONY: gc
-gc: gc.tar.gz
- tar xfz gc.tar.gz
- ln -sf gc?.? gc
-
-$(GC_LIB_A): gc
- (cd gc && ./configure --prefix=$(GC_DIR) )
- make -C gc
- DESTDIR="" make -C gc install
-
-.PHONY: gc-all
-gc-all: $(GC_LIB_A)
-
-.PHONY: gc-install
-gc-install:
-
-.PHONY: gc-clean
-gc-clean:
- -@$(RM) -r gc?.? gc
-
-submak = $(MAKE) -C $(patsubst %-$(1),%,$(@)) $(1)
-subtgt = $(patsubst %,%-$(1),$(SUBDIRS))
-
-%-all:
- $(call submak,all)
-
-%-clean:
- -$(call submak,clean)
-
-%-install:
- $(call submak,install)
-
-.PHONY: compile
-compile: $(call subtgt,all)
-
-.PHONY: install
-install: DESTDIR=
-install: dist
-
-.PHONY: dist
-dist: compile $(call subtgt,install)
-
-.PHONY: clean
-clean: $(call subtgt,clean)
- -@$(RM) -r build
-
-.PHONY: pristine
-pristine: clean
- -@$(RM) gc.tar.gz
-
-.PHONY: help
-help:
- @echo 'Cleaning targets:'
- @echo ' clean - clean subdirs and remove the build dir'
- @echo ' pristine - clean, then remove the gc tarball'
- @echo ''
- @echo 'Installation targets:'
- @echo ' install - build and install relative to /'
- @echo ' dist - build and install relative to DESTDIR (default XEN_ROOT/dist/install)'
- @echo ''
- @echo 'Compilation targets:'
- @echo ' all - same as compile'
- @echo ' compile - build everything'
- @echo ''
- @echo 'To build everything locally use "make" or "make all"'.
- @echo 'To build and install into XEN_ROOT/dist/install use "make dist".'
- @echo 'To build and install into the system use "make dist".'
- @echo 'See ./00README and ./00INSTALL for more information.'
+++ /dev/null
-#!/usr/bin/make -f
-# -*- mode: Makefile; -*-
-XEN_ROOT = $(CURDIR)/../../..
-include $(XEN_ROOT)/tools/Rules.mk
-
-VERSION = 1.0
-HEADER = Vnet
-
-PS2PDF := ps2pdf
-DVIPS := dvips
-LATEX := latex
-LATEX2HTML := latex2html
-DOXYGEN := doxygen
-POD2MAN := pod2man
-
-DOC_MAN5SRC := $(wildcard man/*.pod.5)
-DOC_MAN1SRC := $(wildcard man/*.pod.1)
-DOC_MAN1 := $(patsubst man/%.pod.1,man1/%.1,$(DOC_MAN1SRC))
-DOC_MAN5 := $(patsubst man/%.pod.5,man5/%.5,$(DOC_MAN5SRC))
-
-.PHONY: all man clean install
-
-.PHONY: all
-all: man
-
-.PHONY: man
-man:
- @if which $(POD2MAN) 1>/dev/null 2>/dev/null; then \
- $(MAKE) $(DOC_MAN1) $(DOC_MAN5); fi
-
-man1/%.1: man/%.pod.1 Makefile
- $(INSTALL_DIR) $(@D)
- $(POD2MAN) --release=$(VERSION) --name=`echo $@ | sed 's/^man1.//'| \
- sed 's/.1//'` -s 1 -c $(HEADER) $< $@
-
-man5/%.5: man/%.pod.5 Makefile
- $(INSTALL_DIR) $(@D)
- $(POD2MAN) --release=$(VERSION) --name=`echo $@ | sed 's/^man5.//'| \
- sed 's/.5//'` -s 5 -c $(HEADER) $< $@
-
-.PHONY: clean
-clean:
- @$(RM) -rf man5
- @$(RM) -rf man1
-
-.PHONY: install
- install: all
- $(INSTALL_DIR) $(DESTDIR)$(MANDIR)
- $(CP) -dR man1 $(DESTDIR)$(MANDIR)
- $(CP) -dR man5 $(DESTDIR)$(MANDIR)
-
+++ /dev/null
-=head1 NAME
-
-vn - Vnet (virtual networking) management utility.
-
-=head1 SYNOPSIS
-
-vn <command> [args]
-
-=head1 DESCRIPTION
-
-The B<vn> utility manages vnets, virtual networks for virtual machines.
-Before using vnets, the vnet kernel module must be installed or
-the user-space daemon vnetd must be running. Using the kernel module is recommended,
-see the B<insmod> command below.
-
-A vnet is a virtual network that behaves like a private LAN, transporting
-Ethernet frames. Each vnet is identified by a 128-bit vnet id and
-has a network device that interfaces to it. Ethernet packets written
-to the device are encapsulated and sent to the network.
-Received vnet packets are decapsulated and delivered from the device
-corresponding to their vnet id. The default encapsulation uses UDP on port 1798.
-
-Usually each vnet device is enslaved to a corresponding bridge, and virtual
-machine interfaces are attached to vnets by enslaving them to the bridge.
-Each vnet behaves like a private LAN: traffic on one vnet is not visible
-on other vnets, and interfaces on a vnet cannot see traffic on the
-physical network.
-
-Vnets can be connected together into larger networks
-by direct bridging or packet forwarding, or by using multihomed vms
-with interfaces on several vnets, or vnets and the physical network.
-As vnet interfaces are discovered dynamically, vnet connectivity is maintained
-if a vm using a vnet is migrated from one physical machine to another.
-
-In the commands vnet ids can be given in two forms. Long form, as 8 4-digit hex fields
-separated by colons, for example 0000:0000:0000:0000:0000:0000:0000:0004, and
-short form as a hex field, for example 0004 or 4. The short form is the same as the
-long form with the first 7 fields zero. Vnet id 0000:0000:0000:0000:0000:0000:0000:0001
-is reserved for the physical network and has no vnet device.
-
-Vnets use multicast to discover the location of virtual interfaces, by default
-using multicast group 224.10.0.1. If all the machines hosting vnets are on
-the same subnet, or reachable by multicast, vnets will span all the machines
-automatically. If some machines are not reachable by multicast you can configure
-vnets to perform multicast forwarding using UDP.
-
-The vnet devices are fully-functional network devices, so you can add IP addresses
-to them and test connectivity without any vms running.
-For example, using vnif0004 on machines A and B:
-
- A> ifconfig vnif0004 192.0.2.11
- B> ifconfig vnif0004 192.0.2.12
- B> ping 192.0.2.11
-
-If the vnet device is enslaved to a bridge you will have to add the IP address
-to the bridge instead. Use C<brctl show> or C<vn vnets> to see if a vnet
-device is on a bridge.
-
-=over 4
-
-=item B<insmod> I<[varp_mcaddr=ADDR]>
-
-Insert the vnet kernel module, optionally supplying the multicast
-address to use, default 224.10.0.1.
-
-=item B<varp>
-
-Print varp infrormation and varp cache.
-
-=item B<vnets> [options]
-
-Print the list of vnets (virtual networks). If a vnet device is on a bridge,
-also shows the bridge and its bridged interfaces.
-
-=over 4
-
-=item B<-a | --all>
-
-Also print the vifs on each vnet and varp information.
-
-=item B<-l | --long>
-
-Also print the ifconfig for the vnet devices.
-
-=back
-
-=item B<vnet-create> I<[options]> I<vnetid>
-
-Create a vnet with the given id. The options are:
-
-=over 4
-
-=item B<-s | --security> I<level>
-
-Security level, which can be one of I<none> for no security,
-I<auth> for message authentication, and I<conf> for message
-authentication and confidentiality. The default is no security.
-Security is provided using IPSEC, but uses hard-wired keys.
-
-=item B<-b | --bridge> I<bridgename>
-
-Create a bridge for the vnet called I<bridgename> and enslave
-the vnet device to it.
-
-=item B<-v | --vnetif> I<vnetifname>
-
-Use I<vnetifname> as the name for the vnet device. If this option
-is not specified the default is to name the device vnifN where N
-is the last field of the vnet id as 4 hex characters.
-For example vnif0004. Network device names can be at
-most 14 characters.
-
-=back
-
-=item B<vnet-delete> I<[options]> I<vnetid>
-
-Delete the vnet with the given id. The vnet device goes away too.
-
-=over 4
-
-=item B<-b | --bridge>
-
-If this option is specified, delete the bridge associated with the vnet.
-
-=back
-
-=item B<vifs>
-
-Print the list of vifs (virtual interfaces).
-
-=item B<vif-add> I<[-i|-interface]> I<vnet> I<vmac>
-
-Add a vif to a vnet. Here I<vnet> is the vnet id and I<vmac>
-is the vif's MAC address. Alternatively, I<vmac> can be the name of
-a network device if the I<-i> or -I<--interface> flag is given.
-
-It is not usually necessary to use B<vif-add> as vnets automatically
-add vifs for the MAC addresses they see.
-
-=item B<vif-delete> I<[-i|-interface]> I<vnet> I<vmac>
-
-Delete a vif from a vnet. Here I<vnet> is the vnet id and I<vmac>
-is the vif's MAC address. Alternatively, I<vmac> can be the name of
-a network device if the I<-i> of -I<--interface> flag is given.
-
-It is not usually necessary to use B<vif-delete> as vnets periodically
-delete unused vifs.
-
-=item B<peers>
-
-Print the list of peer vnet machines to forward multicasts to, and accept
-forwarded multicasts from.
-
-=item B<peer-add> I<addr>
-
-Add the peer with the given IP address or hostname.
-
-=item B<peer-delete> I<addr>
-
-Delete the peer with the given IP address or hostname.
-
-=back
-
-=head1 AUTHOR
-
-The author of vn and vnets is Mike Wray of HP Labs. Please send problems, bugs,
-enhancements requests etc. to mike.wray@hp.com.
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright (C) 2006 Mike Wray <mike.wray@hp.com>.
-
-This library is free software; you can redistribute it and/or modify
-it under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2.1 of the License, or
-(at your option) any later version.
+++ /dev/null
-Vnet Low-level Command Interface
-Mike Wray <mike.wray@hp.com>
-2006/10/12
-
-The vnet kernel module and user-space daemon vnetd support a low-level
-command interface to control vnets. The kernel module creates /proc/vnet/policy,
-which is used by writing commands into it. Vnetd listens on the unix-domain
-socket /tmp/vnetd.
-
-The vn utility in ../scripts provides a higher-level interface to
-the vnet commands (using the kernel module or vnetd).
-
-The commands are:
-
-(vnet.add (id <id>) [(vnetif <ifname>)] [(security { none | auth | conf } )] )
-
-Create the vnet with id <id> and the given security level (default none).
-Vnet ids are 128-bit and can be specified as 8 fields of 1 to 4 hex digits
-separated by colons. A vnet id with no colons is treated as one with the first
-7 fields zero. Examples:
-
-1500 - equivalent to 0:0:0:0:0:0:0:1500
-aaff:0:0:0:0:0:77:88
-
-Security levels:
-- none: no security
-- auth: message authentication (IPSEC hmac)
-- conf: message confidentiality (IPSEC hmac and encryption)
-
-The <ifname> is the name of the network device created for the vnet.
-If not given it defaults to vnif<N>, where <N> is the hex for the
-8-th field in the id. Note that network device names can have a
-maximum of 14 characters.
-
-(vnet.del (id <id>))
-
-Delete the vnet with id <id>.
-
-(vif.add (vnet <vnetid>) (vmac <macaddr>))
-
-Add the vif with MAC address <macaddr> to the vnet with id <vnetid>.
-This makes the vnet module respond to VARP requests for <macaddr>
-on vnet <vnetid>. The vnet implementation learns MAC addresses
-so doing this should not be necessary.
-
-(vif.del (vnet <vnetid>) (vmac <macaddr>))
-
-Remove the vif with MAC address <macaddr> from the vnet with id <vnetid>.
-The vnet module will stop responding to VARP for the vif.
-
-(peer.add (addr <addr>))
-
-Add a peer at IP address <addr> to forward multicasts to,
-and accept forwarded multicasts from.
-
-(peer.del (addr <addr>))
-
-Delete a peer.
-
-(vif.list) - get list of vifs.
-(vnet.list) - get list of vnets.
-(varp.list) - get vnet/varp info.
-(peer.list) - get list of peers.
-
-The kernel module produces output on the console, and vnetd
-returns output on the unix socket. The kernel module also provides
-the following files which can be read to get information:
-
-/proc/vnet/vifs - get list of vifs.
-/proc/vnet/vnets - get list of vnets.
-/proc/vnet/varp - get vnet/varp info.
-/proc/vnet/peers - get list of peers.
+++ /dev/null
-
-Vnets: Virtual Networks for Virtual Machines
-
-Mike Wray <mike.wray@hp.com>
-
-2005/12/13
-
-0) Introduction
----------------
-
-Vnets provide virtual private LANs for virtual machines.
-This is done using bridging and multipoint tunneling. A virtual interface
-on a vnet can only see other interfaces on the same vnet - it cannot
-see the real network, and the real network cannot see it either.
-
-Virtual interfaces on the same vnet can be on the same machine
-or on different machines, they can still talk. The hosting machines
-can even be on different subnets if you configure vnet forwarding,
-or have multicast routing enabled.
-
-
-1) Installing vnet support
---------------------------
-
-Assuming the code has been installed (make install in the parent directory),
-configure xend to use 'network-vnet' instead of the default 'network' to
-start up networking. This just loads the vnet module when networking starts.
-
-In /etc/xend/xend-config.sxp:
-
-Configure the network script:
-
-(network-script network-vnet)
-
-Restart xend.
-
-Alternatively insert the vnet module using 'vn insmod',
-preferably before xend starts.
-
-2) Creating vnets
------------------
-
-Xend already implements commands to add/remove vnets and
-bridge to them. To add a vnet use
-
-xm vnet-create <vnet config file>
-
-For example, if vnet97.sxp contains:
-
-(vnet (id 97) (bridge vnet97) (vnetif vnif97) (security none))
-
-do
-
-xm vnet-create vnet97.sxp
-
-This will define a vnet with id 97 and no security. The bridge for the
-vnet is called vnet97 and the virtual interface for it is vnif97.
-To add an interface on a vm to this vnet simply set its bridge to vnet97
-in its configuration.
-
-In Python:
-
-vif="bridge=vnet97"
-
-In sxp:
-
-(dev (vif (mac aa:00:00:01:02:03) (bridge vnet97)))
-
-By default vnets use udp encapsulation, but if you use etherip encapsulation
-you will also have to reduce the MTU of the corresponding
-device in the domain (because of the tunneling). Reducing the MTU may improve
-performance for udp encapsulation, but is not necessary.
-
-For example, for eth0 (in the domain, not dom0) use
-
-ifconfig eth0 mtu 1400
-
-or, better, put
-
-MTU=1400
-
-in /etc/sysconfig/network-scripts/ifcfg-eth0. You may also have to change or remove
-cached config files for eth0 under /etc/sysconfig/networking.
-
-Once configured, vnets are persistent in the xend database.
-To remove a vnet use
-
-xm vnet-delete <vnet id>
-
-To list vnets use
-
-xm vnet-list
-
-To get information on one or more vnet ids use
-
-xm vnet-list <vnet id>...
-
-You can also manage vnets using the vn utility which talks
-directly to the vnet implementation. The source is in ../scripts/vn
-and is installed in /usr/sbin/vn.
-
-3) Troubleshooting
-------------------
-
-The vnet module should appear in 'lsmod'.
-If a vnet has been configured it should appear in the output of 'xm vnet-list'.
-Its bridge and interface should appear in 'ifconfig'.
-It should also show in 'brctl show', with its attached interfaces.
-
-You can 'see into' a vnet from dom0 if you put an IP address on the bridge.
-For example, if you have vnet97 and a vm with ip addr 192.0.2.12 connected to it,
-then
-
-ifconfig vnet97 192.0.2.20 up
-
-should let you ping 192.0.2.12 via the vnet97 bridge.
-
-4) Examples
------------
-
-These assume a vnet with a bridge 'vnet97' has been created.
-
-Here's the full config for a vm on vnet 97, using ip addr 192.0.2.12:
-
-(vm
- (name dom12)
- (memory '64')
- (cpu '1')
- (console '8502')
- (image
- (linux
- (kernel /boot/vmlinuz-2.6-xenU)
- (ip 192.0.2.12:192.0.2.4::::eth0:off)
- (root /dev/sda1)
- (args 'rw fastboot 4')
- )
- )
- (device (vbd (uname phy:hda2) (dev sda1) (mode w)))
- (device (vif (mac aa:00:00:11:00:12) (bridge vnet97)))
-)
-
-If you run another vm on the same vnet:
-
-(vm
- (name dom11)
- (memory '64')
- (cpu '1')
- (console '8501')
- (image
- (linux
- (kernel /boot/vmlinuz-2.6-xenU)
- (ip 192.0.2.11:192.0.2.4::::eth0:off)
- (root /dev/sda1)
- (args 'rw fastboot 4')
- )
- )
- (device (vbd (uname phy:hda3) (dev sda1) (mode w)))
- (device (vif (mac aa:00:00:11:00:11) (bridge vnet97)))
-)
-
-the vms should be able to talk over the vnet. Check with ping.
-If they are both on the same machine the connection will simply
-be the vnet97 bridge, if they are on separate machines their
-packets will be tunneled in udp (or etherip). They should be able to
-see each other, but not the real network.
-
-
+++ /dev/null
-# -*- mode: Makefile; -*-
-#============================================================================
-XEN_ROOT = $(CURDIR)/../../..
-include $(XEN_ROOT)/tools/Rules.mk
-
-.PHONY: all
-all:
-
-.PHONY: install
-install:
- $(INSTALL_DIR) $(XEN_SCRIPT_DIR)
- $(INSTALL_PROG) network-vnet $(XEN_SCRIPT_DIR)
- $(INSTALL_PROG) vnet-insert $(XEN_SCRIPT_DIR)
-
-.PHONY: clean
-clean:
+++ /dev/null
-#!/bin/sh
-scriptdir=/etc/xen/scripts/
-
-case ${1} in
- start)
- ${scriptdir}/vnet-insert
- ;;
-esac
-
-${scriptdir}/network-bridge "$@"
+++ /dev/null
-#!/bin/bash
-
-# Insert the vnet module if it can be found and
-# it's not already there.
-vnet_insert () {
- local module="vnet_module"
- local mod_dir=/lib/modules/$(uname -r)
- local mod_obj=""
-
- if lsmod | grep -q ${module} ; then
- echo "VNET: ${module} loaded"
- return
- fi
- local mods=$(find ${mod_dir} -name "${module}.*o")
- if [[ ${mods} ]] ; then
- for mod_obj in ${mods} ; do
- break
- done
- fi
- if [ -z "${mod_obj}" ] ; then
- echo "VNET: ${module} not found"
- exit 1
- fi
- echo "VNET: Loading ${module} from ${mod_obj}"
- insmod ${mod_obj} "$@"
-}
-
-vnet_insert "$@"
+++ /dev/null
-# Vnet configuration for a vnet with id 97 and no security.
-(vnet (id 97) (bridge vnet97) (vnetif vnif97) (security none))
+++ /dev/null
-# Vnet configuration for a vnet with id 98 and message authentication.
-(vnet (id 98) (bridge vnet98) (vnetif vnif98) (security auth))
+++ /dev/null
-# Vnet configuration for a vnet with id 99 and message confidentiality.
-(vnet (id 99) (bridge vnet99) (vnif vnetif99) (security conf))
+++ /dev/null
-ifndef VNET_ROOT
-export VNET_ROOT = $(shell cd .. && pwd)
-include $(VNET_ROOT)/Make.env
-endif
-
-include $(XEN_ROOT)/tools/Rules.mk
-
-LIB_SRCS :=
-LIB_SRCS += allocate.c
-LIB_SRCS += enum.c
-LIB_SRCS += file_stream.c
-#LIB_SRCS += gzip_stream.c
-LIB_SRCS += hash_table.c
-LIB_SRCS += iostream.c
-LIB_SRCS += lexis.c
-LIB_SRCS += mem_stream.c
-LIB_SRCS += string_stream.c
-LIB_SRCS += sxpr.c
-LIB_SRCS += sxpr_parser.c
-LIB_SRCS += sys_net.c
-LIB_SRCS += sys_string.c
-LIB_SRCS += util.c
-
-LIB_OBJS := $(LIB_SRCS:.c=.o)
-PIC_OBJS := $(LIB_SRCS:.c=.opic)
-
-$(call cc-option-add,CFLAGS,CC,-fgnu89-inline)
-CFLAGS += -Werror -fno-strict-aliasing
-CFLAGS += -O3
-#CFLAGS += -g
-
-MAJOR := 3.0
-MINOR := 0
-LIB := libxutil.so
-LIB += libxutil.so.$(MAJOR)
-LIB += libxutil.so.$(MAJOR).$(MINOR)
-LIB += libxutil.a
-
-.PHONY: all
-all: build
-
-.PHONY: build
-build: #check-for-zlib
- $(MAKE) $(LIB)
-
-gzip_stream.o: check-for-zlib
-
-libxutil.so: libxutil.so.$(MAJOR)
- ln -sf $^ $@
-
-libxutil.so.$(MAJOR): libxutil.so.$(MAJOR).$(MINOR)
- ln -sf $^ $@
-
-libxutil.so.$(MAJOR).$(MINOR): $(PIC_OBJS)
- $(CC) $(CFLAGS) -Wl,$(SONAME_LDFLAG) -Wl,libxutil.so.$(MAJOR) $(SHLIB_LDFLAGS) -o $@ $^
-
-libxutil.a: $(LIB_OBJS)
- $(AR) rc $@ $^
-
-.PHONY: check-for-zlib
-check-for-zlib:
- @if [ ! -e /usr/include/zlib.h ]; then \
- echo "***********************************************************"; \
- echo "ERROR: install zlib header files (http://www.gzip.org/zlib)"; \
- echo "***********************************************************"; \
- false; \
- fi
-
-.PHONY: install
-install: build
- $(INSTALL_DIR) $(DESTDIR)$(LIBDIR)
- $(INSTALL_PROG) libxutil.so.$(MAJOR).$(MINOR) $(DESTDIR)$(LIBDIR)
- $(INSTALL_DATA) libxutil.a $(DESTDIR)$(LIBDIR)
- ln -sf libxutil.so.$(MAJOR).$(MINOR) $(DESTDIR)$(LIBDIR)/libxutil.so.$(MAJOR)
- ln -sf libxutil.so.$(MAJOR) $(DESTDIR)$(LIBDIR)/libxutil.so
-
-.PHONY: clean
-clean:
- -@$(RM) *.a *.so* *.o *.opic *.rpm
- -@$(RM) *~
- -@$(RM) $(DEPS)
-
--include $(DEPS)
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include "allocate.h"
-
-/** @file
- * Support for allocating memory.
- * Usable from user code or kernel code (with __KERNEL__ defined).
- * In user code will use GC if USE_GC is defined.
- */
-
-#ifdef __KERNEL__
-/*----------------------------------------------------------------------------*/
-# include <linux/config.h>
-# include <linux/slab.h>
-# include <linux/string.h>
-# include <linux/types.h>
-
-# define DEFAULT_TYPE 0
-# define MALLOC(n, type) kmalloc(n, type)
-# define FREE(ptr) kfree(ptr)
-
-/*----------------------------------------------------------------------------*/
-#else /* ! __KERNEL__ */
-
-# include <stdlib.h>
-# include <string.h>
-
-# define DEFAULT_TYPE 0
-
-#ifdef USE_GC
-# include "gc.h"
-# define MALLOC(n, typ) GC_malloc(n)
-# define FREE(ptr) (ptr=NULL)
-//typedef void *GC_PTR;
-//GC_PTR (*GC_oom_fn)(size_t n);
-#else
-# define MALLOC(n, type) malloc(n)
-# define FREE(ptr) free(ptr)
-#endif
-
-/*----------------------------------------------------------------------------*/
-#endif
-
-/** Function to call when memory cannot be allocated. */
-AllocateFailedFn *allocate_failed_fn = NULL;
-
-/** Allocate memory and zero it.
- * The type is only relevant when calling from kernel code,
- * from user code it is ignored.
- * In kernel code the values accepted by kmalloc can be used:
- * GFP_USER, GFP_ATOMIC, GFP_KERNEL.
- *
- * @param size number of bytes to allocate
- * @param type memory type to allocate (kernel only)
- * @return pointer to the allocated memory or zero
- * if malloc failed
- */
-void *allocate_type(int size, int type){
- void *p = MALLOC(size, type);
- if(p){
- memzero(p, size);
- } else if(allocate_failed_fn){
- allocate_failed_fn(size, type);
- }
- return p;
-}
-
-/** Allocate memory and zero it.
- *
- * @param size number of bytes to allocate
- * @return pointer to the allocated memory or zero
- * if malloc failed
- */
-void *allocate(int size){
- return allocate_type(size, DEFAULT_TYPE);
-}
-
-/** Free memory allocated by allocate().
- * No-op if 'p' is null.
- *
- * @param p memory to free
- */
-void deallocate(void *p){
- if(p){
- FREE(p);
- }
-}
-
-/** Set bytes to zero.
- * No-op if 'p' is null.
- *
- * @param p memory to zero
- * @param size number of bytes to zero
- */
-void memzero(void *p, int size){
- if(p){
- memset(p, 0, (size_t)size);
- }
-}
-
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _XUTIL_ALLOCATE_H_
-#define _XUTIL_ALLOCATE_H_
-
-/** Allocate memory for a given type, and cast. */
-#define ALLOCATE(ctype) (ctype *)allocate(sizeof(ctype))
-
-/** Allocate memory for a given type, and cast. */
-#define ALLOCATE_TYPE(ctype, type) (ctype *)allocate(sizeof(ctype))
-
-extern void *allocate_type(int size, int type);
-extern void *allocate(int size);
-extern void deallocate(void *);
-extern void memzero(void *p, int size);
-
-typedef void AllocateFailedFn(int size, int type);
-extern AllocateFailedFn *allocate_failed_fn;
-
-#endif /* _XUTIL_ALLOCATE_H_ */
-
-
-
-
-
-
-
-
-
+++ /dev/null
-/*
- * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef _XUTIL_DEBUG_H_
-#define _XUTIL_DEBUG_H_
-
-#ifndef MODULE_NAME
-#define MODULE_NAME ""
-#endif
-
-#ifdef __KERNEL__
-#include <linux/config.h>
-#include <linux/kernel.h>
-
-#ifdef DEBUG
-
-#define dprintf(fmt, args...) printk(KERN_DEBUG "[DBG] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
-#define wprintf(fmt, args...) printk(KERN_WARNING "[WRN] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
-#define iprintf(fmt, args...) printk(KERN_INFO "[INF] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
-#define eprintf(fmt, args...) printk(KERN_ERR "[ERR] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
-
-#else
-
-#define dprintf(fmt, args...) do {} while(0)
-#define wprintf(fmt, args...) printk(KERN_WARNING "[WRN] " MODULE_NAME fmt, ##args)
-#define iprintf(fmt, args...) printk(KERN_INFO "[INF] " MODULE_NAME fmt, ##args)
-#define eprintf(fmt, args...) printk(KERN_ERR "[ERR] " MODULE_NAME fmt, ##args)
-
-#endif
-
-#else
-
-#include <stdio.h>
-
-#ifdef DEBUG
-
-#define dprintf(fmt, args...) fprintf(stdout, "%d [DBG] " MODULE_NAME ">%s" fmt, getpid(), __FUNCTION__, ##args)
-#define wprintf(fmt, args...) fprintf(stderr, "%d [WRN] " MODULE_NAME ">%s" fmt, getpid(), __FUNCTION__, ##args)
-#define iprintf(fmt, args...) fprintf(stderr, "%d [INF] " MODULE_NAME ">%s" fmt, getpid(), __FUNCTION__, ##args)
-#define eprintf(fmt, args...) fprintf(stderr, "%d [ERR] " MODULE_NAME ">%s" fmt, getpid(), __FUNCTION__, ##args)
-
-#else
-
-#define dprintf(fmt, args...) do {} while(0)
-#define wprintf(fmt, args...) fprintf(stderr, "%d [WRN] " MODULE_NAME fmt, getpid(), ##args)
-#define iprintf(fmt, args...) fprintf(stderr, "%d [INF] " MODULE_NAME fmt, getpid(), ##args)
-#define eprintf(fmt, args...) fprintf(stderr, "%d [ERR] " MODULE_NAME fmt, getpid(), ##args)
-
-#endif
-
-#endif
-
-/** Print format for an IP address.
- * See NIPQUAD(), HIPQUAD()
- */
-#define IPFMT "%u.%u.%u.%u"
-
-#endif /* ! _XUTIL_DEBUG_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2002, 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef __KERNEL__
-#include <linux/errno.h>
-#else
-#include <errno.h>
-#endif
-
-#include "sys_string.h"
-#include "enum.h"
-
-/** Map an enum name to its value using a table.
- *
- * @param name enum name
- * @param defs enum definitions
- * @return enum value or -1 if not known
- */
-int enum_name_to_val(char *name, EnumDef *defs){
- int val = -1;
- for(; defs->name; defs++){
- if(!strcmp(defs->name, name)){
- val = defs->val;
- break;
- }
- }
- return val;
-}
-
-/** Map an enum value to its name using a table.
- *
- * @param val enum value
- * @param defs enum definitions
- * @param defs_n number of definitions
- * @return enum name or NULL if not known
- */
-char *enum_val_to_name(int val, EnumDef *defs){
- char *name = NULL;
- for(; defs->name; defs++){
- if(val == defs->val){
- name = defs->name;
- break;
- }
- }
- return name;
-}
-
+++ /dev/null
-/*
- * Copyright (C) 2002, 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _XUTIL_ENUM_H_
-#define _XUTIL_ENUM_H_
-
-/** Mapping of an enum value to a name. */
-typedef struct EnumDef {
- int val;
- char *name;
-} EnumDef;
-
-extern int enum_name_to_val(char *name, EnumDef *defs);
-extern char *enum_val_to_name(int val, EnumDef *defs);
-
-#endif /* _XUTIL_ENUM_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/** @file
- * An IOStream implementation using fds.
- */
-#ifndef __KERNEL__
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include "allocate.h"
-#include "fd_stream.h"
-
-#define MODULE_NAME "fd_stream"
-#define DEBUG 1
-//#undef DEBUG
-#include "debug.h"
-
-static int fd_read(IOStream *s, void *buf, size_t n);
-static int fd_write(IOStream *s, const void *buf, size_t n);
-static int fd_error(IOStream *s);
-static int fd_close(IOStream *s);
-static void fd_free(IOStream *s);
-static int fd_flush(IOStream *s);
-
-/** Methods used by a fd IOStream. */
-static const IOMethods fd_methods = {
- read: fd_read,
- write: fd_write,
- error: fd_error,
- close: fd_close,
- free: fd_free,
- flush: fd_flush,
-};
-
-/** Get the fd data.
- *
- * @param io fd stream
- * @return data
- */
-static inline FDData * fd_data(IOStream *io){
- return (FDData *)io->data;
-}
-
-/** Test if a stream is a fd stream.
- *
- * @param io stream
- * @return 0 if a fd stream, -EINVAL if not
- */
-int fd_stream_check(IOStream *io){
- return (io && io->methods == &fd_methods ? 0 : -EINVAL);
-}
-
-/** Get the data for a fd stream.
- *
- * @param io stream
- * @param data return value for the data
- * @return 0 if a fd stream, -EINVAL if not
- */
-int fd_stream_data(IOStream *io, FDData **data){
- int err = fd_stream_check(io);
- if(err){
- *data = NULL;
- } else {
- *data = fd_data(io);
- }
- return err;
-}
-
-
-/** Write to the underlying fd.
- *
- * @param stream input
- * @param buf where to put input
- * @param n number of bytes to write
- * @return number of bytes written
- */
-static int fd_write(IOStream *s, const void *buf, size_t n){
- FDData *data = fd_data(s);
- int k;
- k = write(data->fd, buf, n);
- return k;
-}
-
-/** Read from the underlying stream;
- *
- * @param stream input
- * @param buf where to put input
- * @param n number of bytes to read
- * @return number of bytes read
- */
-static int fd_read(IOStream *s, void *buf, size_t n){
- FDData *data = fd_data(s);
- int k;
- k = read(data->fd, buf, n);
- //printf("> fd_read> buf=%p n=%d --> k=%d\n", buf, n, k);
- return k;
-}
-
-/** Flush the fd (no-op).
- *
- * @param s fd stream
- * @return 0 on success, error code otherwise
- */
-static int fd_flush(IOStream *s){
- return 0;
-}
-
-/** Check if a fd stream has an error (no-op).
- *
- * @param s fd stream
- * @return 1 if has an error, 0 otherwise
- */
-static int fd_error(IOStream *s){
- return 0;
-}
-
-/** Close a fd stream.
- *
- * @param s fd stream to close
- * @return result of the close
- */
-static int fd_close(IOStream *s){
- FDData *data = fd_data(s);
- return close(data->fd);
-}
-
-/** Free a fd stream.
- *
- * @param s fd stream
- */
-static void fd_free(IOStream *s){
- FDData *data = fd_data(s);
- deallocate(data);
-}
-
-/** Create an IOStream for a fd.
- *
- * @param fd fd to wtap
- * @return new IOStream using fd for i/o
- */
-IOStream *fd_stream_new(int fd){
- int err = -ENOMEM;
- IOStream *io = NULL;
- FDData *data = NULL;
-
- io = ALLOCATE(IOStream);
- if(!io) goto exit;
- io->methods = &fd_methods;
- data = ALLOCATE(FDData);
- if(!data) goto exit;
- io->data = data;
- data->fd = fd;
- err = 0;
- exit:
- if(err){
- if(io){
- if(data) deallocate(data);
- deallocate(io);
- io = NULL;
- }
- }
- return io;
-}
-
-#endif
+++ /dev/null
-/*
- * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _XMC_FD_STREAM_H_
-#define _XMC_FD_STREAM_H_
-
-#ifndef __KERNEL__
-#include "iostream.h"
-
-/** Data associated with a fd stream. */
-typedef struct FDData {
- /** The socket file descriptor. */
- int fd;
-} FDData;
-
-extern IOStream *fd_stream_new(int fd);
-extern int fd_stream_data(IOStream *io, FDData **data);
-extern int fd_stream_check(IOStream *io);
-
-#endif
-#endif /* !_XMC_FD_STREAM_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/** @file
- * An IOStream implementation using FILE*.
- */
-#ifndef __KERNEL__
-#include <stdio.h>
-#include <stdlib.h>
-#include "allocate.h"
-#include "file_stream.h"
-
-static int file_read(IOStream *s, void *buf, size_t n);
-static int file_write(IOStream *s, const void *buf, size_t n);
-static int file_error(IOStream *s);
-static int file_close(IOStream *s);
-static void file_free(IOStream *s);
-static int file_flush(IOStream *s);
-
-/** Methods used by a FILE* IOStream. */
-static const IOMethods file_methods = {
- read: file_read,
- write: file_write,
- error: file_error,
- close: file_close,
- free: file_free,
- flush: file_flush,
-};
-
-/** IOStream for stdin. */
-static IOStream _iostdin = {
- methods: &file_methods,
- data: (void*)1,
- nofree: 1,
-};
-
-/** IOStream for stdout. */
-static IOStream _iostdout = {
- methods: &file_methods,
- data: (void*)2,
- nofree: 1,
-};
-
-/** IOStream for stderr. */
-static IOStream _iostderr = {
- methods: &file_methods,
- data: (void*)3,
- nofree: 1,
-};
-
-/** IOStream for stdin. */
-IOStream *iostdin = &_iostdin;
-
-/** IOStream for stdout. */
-IOStream *iostdout = &_iostdout;
-
-/** IOStream for stderr. */
-IOStream *iostderr = &_iostderr;
-
-/* Get the underlying FILE*.
- *
- * @param s file stream
- * @return the stream s wraps
- */
-static inline FILE *get_file(IOStream *s){
- FILE *data = NULL;
- switch((long)s->data){
- case 1:
- data = stdin;
- break;
- case 2:
- data = stdout;
- break;
- case 3:
- data = stderr;
- break;
- default:
- data = (FILE*)s->data;
- break;
- }
- return data;
-}
-
-/** Control buffering on the underlying stream, like setvbuf().
- *
- * @param io file stream
- * @param buf buffer
- * @param mode buffering mode (see man setvbuf())
- * @param size buffer size
- * @return 0 on success, non-zero otherwise
- */
-int file_stream_setvbuf(IOStream *io, char *buf, int mode, size_t size){
- return setvbuf(get_file(io), buf, mode, size);
-}
-
-/** Write to the underlying stream using fwrite();
- *
- * @param stream input
- * @param buf where to put input
- * @param n number of bytes to write
- * @return number of bytes written
- */
-static int file_write(IOStream *s, const void *buf, size_t n){
- return fwrite(buf, 1, n, get_file(s));
-}
-
-/** Read from the underlying stream using fread();
- *
- * @param stream input
- * @param buf where to put input
- * @param n number of bytes to read
- * @return number of bytes read
- */
-static int file_read(IOStream *s, void *buf, size_t n){
- return fread(buf, 1, n, get_file(s));
-}
-
-/** Fush the underlying stream using fflush().
- *
- * @param s file stream
- * @return 0 on success, error code otherwise
- */
-static int file_flush(IOStream *s){
- return fflush(get_file(s));
-}
-
-/** Check if a stream has an error.
- *
- * @param s file stream
- * @return 1 if has an error, 0 otherwise
- */
-static int file_error(IOStream *s){
- return ferror(get_file(s));
-}
-
-/** Close a file stream.
- *
- * @param s file stream to close
- * @return result of the close
- */
-static int file_close(IOStream *s){
- int result = 0;
- result = fclose(get_file(s));
- return result;
-}
-
-/** Free a file stream.
- *
- * @param s file stream
- */
-static void file_free(IOStream *s){
- // Nothing extra to do - close did it all.
-}
-
-/** Create an IOStream for a stream.
- *
- * @param f stream to wrap
- * @return new IOStream using f for i/o
- */
-IOStream *file_stream_new(FILE *f){
- IOStream *io = ALLOCATE(IOStream);
- if(io){
- io->methods = &file_methods;
- io->data = (void*)f;
- }
- return io;
-}
-
-/** IOStream version of fopen().
- *
- * @param file name of the file to open
- * @param flags giving the mode to open in (as for fopen())
- * @return new stream for the open file, or 0 if failed
- */
-IOStream *file_stream_fopen(const char *file, const char *flags){
- IOStream *io = 0;
- FILE *fin = fopen(file, flags);
- if(fin){
- io = file_stream_new(fin);
- if(!io){
- fclose(fin);
- }
- }
- return io;
-}
-
-/** IOStream version of fdopen().
- *
- * @param fd file descriptor
- * @param flags giving the mode to open in (as for fdopen())
- * @return new stream for the open file, or 0 if failed. Always takes
- * ownership of fd.
- */
-IOStream *file_stream_fdopen(int fd, const char *flags){
- IOStream *io = 0;
- FILE *fin = fdopen(fd, flags);
- if(fin){
- io = file_stream_new(fin);
- if(!io){
- fclose(fin);
- }
- }
- return io;
-}
-#endif
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _XUTIL_FILE_STREAM_H_
-#define _XUTIL_FILE_STREAM_H_
-
-#ifndef __KERNEL__
-#include "iostream.h"
-#include <stdio.h>
-
-extern IOStream *file_stream_new(FILE *f);
-extern IOStream *file_stream_fopen(const char *file, const char *flags);
-extern IOStream *file_stream_fdopen(int fd, const char *flags);
-extern IOStream get_stream_stdout(void);
-extern IOStream get_stream_stderr(void);
-extern IOStream get_stream_stdin(void);
-
-extern int file_stream_setvbuf(IOStream *io, char *buf, int mode, size_t size);
-#endif
-#endif /* !_XUTIL_FILE_STREAM_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2003 Hewlett-Packard Company.
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/** @file
- * An IOStream implementation using zlib gzFile to provide
- * compression and decompression.
- */
-#ifndef __KERNEL__
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "zlib.h"
-
-#include "allocate.h"
-#include "gzip_stream.h"
-
-static int gzip_read(IOStream *s, void *buf, size_t n);
-static int gzip_write(IOStream *s, const void *buf, size_t n);
-static int gzip_error(IOStream *s);
-static int gzip_close(IOStream *s);
-static void gzip_free(IOStream *s);
-static int gzip_flush(IOStream *s);
-
-/** Methods used by a gzFile* IOStream. */
-static const IOMethods gzip_methods = {
- read: gzip_read,
- write: gzip_write,
- error: gzip_error,
- close: gzip_close,
- free: gzip_free,
- flush: gzip_flush,
-};
-
-/** Get the underlying gzFile*.
- *
- * @param s gzip stream
- * @return the stream s wraps
- */
-static inline gzFile get_gzfile(IOStream *s){
- return (gzFile)s->data;
-}
-
-/** Write to the underlying stream.
- *
- * @param stream destination
- * @param buf data
- * @param n number of bytes to write
- * @return number of bytes written
- */
-static int gzip_write(IOStream *s, const void *buf, size_t n){
- return gzwrite(get_gzfile(s), (void*)buf, n);
-}
-
-/** Read from the underlying stream.
- *
- * @param stream input
- * @param buf where to put input
- * @param n number of bytes to read
- * @return number of bytes read
- */
-static int gzip_read(IOStream *s, void *buf, size_t n){
- return gzread(get_gzfile(s), buf, n);
-}
-
-/** Flush the underlying stream.
- *
- * @param s gzip stream
- * @return 0 on success, error code otherwise
- */
-static int gzip_flush(IOStream *s){
- //return gzflush(get_gzfile(s), Z_NO_FLUSH);
- return gzflush(get_gzfile(s), Z_SYNC_FLUSH);
- //return gzflush(get_gzfile(s), Z_FULL_FLUSH);
-}
-
-/** Check if a stream has an error.
- *
- * @param s gzip stream
- * @return 1 if has an error, 0 otherwise
- */
-static int gzip_error(IOStream *s){
- int err;
- gzFile *gz = get_gzfile(s);
- gzerror(gz, &err);
- return (err == Z_ERRNO ? 1 /* ferror(gzfile(gz)) */ : err);
-}
-
-/** Close a gzip stream.
- *
- * @param s gzip stream to close
- * @return result of the close
- */
-static int gzip_close(IOStream *s){
- int result = 0;
- result = gzclose(get_gzfile(s));
- return result;
-}
-
-/** Free a gzip stream.
- *
- * @param s gzip stream
- */
-static void gzip_free(IOStream *s){
- // Nothing to do - close did it all.
-}
-
-/** Create an IOStream for a gzip stream.
- *
- * @param f stream to wrap
- * @return new IOStream using f for i/o
- */
-IOStream *gzip_stream_new(gzFile *f){
- IOStream *io = ALLOCATE(IOStream);
- if(io){
- io->methods = &gzip_methods;
- io->data = (void*)f;
- }
- return io;
-}
-
-/** IOStream version of fopen().
- *
- * @param file name of the file to open
- * @param flags giving the mode to open in (as for fopen())
- * @return new stream for the open file, or NULL if failed
- */
-IOStream *gzip_stream_fopen(const char *file, const char *flags){
- IOStream *io = NULL;
- gzFile *fgz;
- fgz = gzopen(file, flags);
- if(fgz){
- io = gzip_stream_new(fgz);
- if(!io){
- gzclose(fgz);
- }
- }
- return io;
-}
-
-/** IOStream version of fdopen().
- *
- * @param fd file descriptor
- * @param flags giving the mode to open in (as for fdopen())
- * @return new stream for the open file, or NULL if failed. Always takes
- * ownership of fd.
- */
-IOStream *gzip_stream_fdopen(int fd, const char *flags){
- IOStream *io = NULL;
- gzFile *fgz;
- fgz = gzdopen(fd, flags);
- if(fgz){
- io = gzip_stream_new(fgz);
- if(!io)
- gzclose(fgz);
- }
- return io;
-}
-#endif
+++ /dev/null
-/*
- * Copyright (C) 2003 Hewlett-Packard Company.
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _XUTIL_GZIP_STREAM_H_
-#define _XUTIL_GZIP_STREAM_H_
-
-#ifndef __KERNEL__
-#include "iostream.h"
-#include "zlib.h"
-
-extern IOStream *gzip_stream_new(gzFile *f);
-extern IOStream *gzip_stream_fopen(const char *file, const char *flags);
-extern IOStream *gzip_stream_fdopen(int fd, const char *flags);
-#endif
-#endif /* !_XUTIL_GZIP_STREAM_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2005 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef __KERNEL__
-# include <linux/config.h>
-# include <linux/module.h>
-# include <linux/kernel.h>
-# include <linux/errno.h>
-#else
-# include <errno.h>
-# include <stddef.h>
-#endif
-
-#include "allocate.h"
-#include "hash_table.h"
-
-/** @file
- * Base support for hashtables.
- *
- * Hash codes are reduced modulo the number of buckets to index tables,
- * so there is no need for hash functions to limit the range of hashcodes.
- * In fact it is assumed that hashcodes do not change when the number of
- * buckets in the table changes.
- */
-
-/*============================================================================*/
-/*
---------------------------------------------------------------------
-lookup2.c, by Bob Jenkins, December 1996, Public Domain.
-You can use this free for any purpose. It has no warranty.
---------------------------------------------------------------------
-*/
-
-#define hashsize(n) ((ub4)1<<(n))
-#define hashmask(n) (hashsize(n)-1)
-
-/*
---------------------------------------------------------------------
-mix -- mix 3 32-bit values reversibly.
-For every delta with one or two bit set, and the deltas of all three
- high bits or all three low bits, whether the original value of a,b,c
- is almost all zero or is uniformly distributed,
-* If mix() is run forward or backward, at least 32 bits in a,b,c
- have at least 1/4 probability of changing.
-* If mix() is run forward, every bit of c will change between 1/3 and
- 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.)
-mix() was built out of 36 single-cycle latency instructions in a
- structure that could supported 2x parallelism, like so:
- a -= b;
- a -= c; x = (c>>13);
- b -= c; a ^= x;
- b -= a; x = (a<<8);
- c -= a; b ^= x;
- c -= b; x = (b>>13);
- ...
- Unfortunately, superscalar Pentiums and Sparcs can't take advantage
- of that parallelism. They've also turned some of those single-cycle
- latency instructions into multi-cycle latency instructions. Still,
- this is the fastest good hash I could find. There were about 2^^68
- to choose from. I only looked at a billion or so.
---------------------------------------------------------------------
-*/
-#define mix(a,b,c) \
-{ \
- a -= b; a -= c; a ^= (c>>13); \
- b -= c; b -= a; b ^= (a<<8); \
- c -= a; c -= b; c ^= (b>>13); \
- a -= b; a -= c; a ^= (c>>12); \
- b -= c; b -= a; b ^= (a<<16); \
- c -= a; c -= b; c ^= (b>>5); \
- a -= b; a -= c; a ^= (c>>3); \
- b -= c; b -= a; b ^= (a<<10); \
- c -= a; c -= b; c ^= (b>>15); \
-}
-
-/*
---------------------------------------------------------------------
-hash() -- hash a variable-length key into a 32-bit value
- k : the key (the unaligned variable-length array of bytes)
- len : the length of the key, counting by bytes
- level : can be any 4-byte value
-Returns a 32-bit value. Every bit of the key affects every bit of
-the return value. Every 1-bit and 2-bit delta achieves avalanche.
-About 36+6len instructions.
-
-The best hash table sizes are powers of 2. There is no need to do
-mod a prime (mod is sooo slow!). If you need less than 32 bits,
-use a bitmask. For example, if you need only 10 bits, do
- h = (h & hashmask(10));
-In which case, the hash table should have hashsize(10) elements.
-
-If you are hashing n strings (ub1 **)k, do it like this:
- for (i=0, h=0; i<n; ++i) h = hash( k[i], len[i], h);
-
-By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this
-code any way you wish, private, educational, or commercial. It's free.
-
-See http://burlteburtle.net/bob/hash/evahash.html
-Use for hash table lookup, or anything where one collision in 2^32 is
-acceptable. Do NOT use for cryptographic purposes.
---------------------------------------------------------------------
-*/
-
-static inline ub4 _hash(const ub1 *k, ub4 length, ub4 initval)
-//register ub1 *k; /* the key */
-//register ub4 length; /* the length of the key */
-//register ub4 initval; /* the previous hash, or an arbitrary value */
-{
- /*register*/ ub4 a,b,c,len;
-
- /* Set up the internal state */
- len = length;
- a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
- c = initval; /* the previous hash value */
-
- /*---------------------------------------- handle most of the key */
- while (len >= 12)
- {
- a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24));
- b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24));
- c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24));
- mix(a,b,c);
- k += 12; len -= 12;
- }
-
- /*------------------------------------- handle the last 11 bytes */
- c += length;
- switch(len) /* all the case statements fall through */
- {
- case 11: c+=((ub4)k[10]<<24);
- case 10: c+=((ub4)k[9]<<16);
- case 9 : c+=((ub4)k[8]<<8);
- /* the first byte of c is reserved for the length */
- case 8 : b+=((ub4)k[7]<<24);
- case 7 : b+=((ub4)k[6]<<16);
- case 6 : b+=((ub4)k[5]<<8);
- case 5 : b+=k[4];
- case 4 : a+=((ub4)k[3]<<24);
- case 3 : a+=((ub4)k[2]<<16);
- case 2 : a+=((ub4)k[1]<<8);
- case 1 : a+=k[0];
- /* case 0: nothing left to add */
- }
- mix(a,b,c);
- /*-------------------------------------------- report the result */
- return c;
-}
-
-ub4 hash(const ub1 *k, ub4 length, ub4 initval){
- return _hash(k, length, initval);
-}
-
-/*============================================================================*/
-
-/** Get the bucket for a hashcode in a hash table.
- *
- * @param table to get bucket from
- * @param hashcode to get bucket for
- * @return bucket
- */
-inline HTBucket * get_bucket(HashTable *table, Hashcode hashcode){
- return table->buckets + (hashcode % table->buckets_n);
-}
-
-/** Initialize a hash table.
- *
- * @param table to initialize
- */
-static void HashTable_init(HashTable *table){
- int i;
-
- for(i = 0; i < table->buckets_n; i++){
- HTBucket *bucket = get_bucket(table, i);
- bucket->head = NULL;
- bucket->count = 0;
- }
- table->entry_count = 0;
-}
-
-/** Allocate a new hashtable.
- * If the number of buckets is not positive the default is used.
- *
- * @param buckets_n number of buckets
- * @return new hashtable or null
- */
-HashTable *HashTable_new(int buckets_n){
- HashTable *z = ALLOCATE(HashTable);
- if(!z) goto exit;
- if(buckets_n <= 0){
- buckets_n = HT_BUCKETS_N;
- }
- z->buckets = (HTBucket*)allocate(buckets_n * sizeof(HTBucket));
- if(!z->buckets){
- deallocate(z);
- z = NULL;
- goto exit;
- }
- z->buckets_n = buckets_n;
- HashTable_init(z);
- exit:
- return z;
-}
-
-/** Free a hashtable.
- * Any entries are removed and freed.
- *
- * @param h hashtable (ignored if null)
- */
-void HashTable_free(HashTable *h){
- if(h){
- HashTable_clear(h);
- deallocate(h->buckets);
- deallocate(h);
- }
-}
-
-/** Push an entry on the list in the bucket for a given hashcode.
- *
- * @param table to add entry to
- * @param hashcode for the entry
- * @param entry to add
- */
-static inline void push_on_bucket(HashTable *table, Hashcode hashcode,
- HTEntry *entry){
- HTBucket *bucket;
- HTEntry *old_head;
-
- bucket = get_bucket(table, hashcode);
- old_head = bucket->head;
- bucket->count++;
- bucket->head = entry;
- entry->next = old_head;
-}
-
-/** Change the number of buckets in a hashtable.
- * No-op if the number of buckets is not positive.
- * Existing entries are reallocated to buckets based on their hashcodes.
- * The table is unmodified if the number of buckets cannot be changed.
- *
- * @param table hashtable
- * @param buckets_n new number of buckets
- * @return 0 on success, error code otherwise
- */
-int HashTable_set_buckets_n(HashTable *table, int buckets_n){
- int err = 0;
- HTBucket *old_buckets = table->buckets;
- int old_buckets_n = table->buckets_n;
- int i;
-
- if(buckets_n <= 0){
- err = -EINVAL;
- goto exit;
- }
- table->buckets = (HTBucket*)allocate(buckets_n * sizeof(HTBucket));
- if(!table->buckets){
- err = -ENOMEM;
- table->buckets = old_buckets;
- goto exit;
- }
- table->buckets_n = buckets_n;
- for(i=0; i < old_buckets_n; i++){
- HTBucket *bucket = old_buckets + i;
- HTEntry *entry, *next;
- for(entry = bucket->head; entry; entry = next){
- next = entry->next;
- push_on_bucket(table, entry->hashcode, entry);
- }
- }
- deallocate(old_buckets);
- exit:
- return err;
-}
-
-/** Adjust the number of buckets so the table is neither too full nor too empty.
- * The table is unmodified if adjusting fails.
- *
- * @param table hash table
- * @param buckets_min minimum number of buckets (use default if 0 or negative)
- * @return 0 on success, error code otherwise
- */
-int HashTable_adjust(HashTable *table, int buckets_min){
- int buckets_n = 0;
- int err = 0;
- if(buckets_min <= 0) buckets_min = HT_BUCKETS_N;
- if(table->entry_count >= table->buckets_n){
- // The table is dense - expand it.
- buckets_n = 2 * table->buckets_n;
- } else if((table->buckets_n > buckets_min) &&
- (4 * table->entry_count < table->buckets_n)){
- // The table is more than minimum size and sparse - shrink it.
- buckets_n = 2 * table->entry_count;
- if(buckets_n < buckets_min) buckets_n = buckets_min;
- }
- if(buckets_n){
- err = HashTable_set_buckets_n(table, buckets_n);
- }
- return err;
-}
-
-/** Allocate a new entry for a given value.
- *
- * @param value to put in the entry
- * @return entry, or 0 on failure
- */
-HTEntry * HTEntry_new(Hashcode hashcode, void *key, void *value){
- HTEntry *z = ALLOCATE(HTEntry);
- if(z){
- z->hashcode = hashcode;
- z->key = key;
- z->value = value;
- }
- return z;
-}
-
-/** Free an entry.
- *
- * @param z entry to free
- */
-inline void HTEntry_free(HTEntry *z){
- if(z){
- deallocate(z);
- }
-}
-
-/** Free an entry in a hashtable.
- * The table's entry_free_fn is used is defined, otherwise
- * the HTEntry itself is freed.
- *
- * @param table hashtable
- * @param entry to free
- */
-inline void HashTable_free_entry(HashTable *table, HTEntry *entry){
- if(!entry) return;
- if(table && table->entry_free_fn){
- table->entry_free_fn(table, entry);
- } else {
- HTEntry_free(entry);
- }
-}
-
-/** Get the first entry satisfying a test from the bucket for the
- * given hashcode.
- *
- * @param table to look in
- * @param hashcode indicates the bucket
- * @param test_fn test to apply to elements
- * @param arg first argument to calls to test_fn
- * @return entry found, or 0
- */
-inline HTEntry * HashTable_find_entry(HashTable *table, Hashcode hashcode,
- TableTestFn *test_fn, TableArg arg){
- HTBucket *bucket;
- HTEntry *entry = NULL;
- HTEntry *next;
-
- bucket = get_bucket(table, hashcode);
- for(entry = bucket->head; entry; entry = next){
- next = entry->next;
- if(test_fn(arg, table, entry)){
- break;
- }
- }
- return entry;
-}
-
-/** Test hashtable keys for equality.
- * Uses the table's key_equal_fn if defined, otherwise pointer equality.
- *
- * @param key1 key to compare
- * @param key2 key to compare
- * @return 1 if equal, 0 otherwise
- */
-inline int HashTable_key_equal(HashTable *table, void *key1, void *key2){
- if(table->key_size){
- return memcmp(key1, key2, table->key_size) == 0;
- }
- return (table->key_equal_fn ? table->key_equal_fn(key1, key2) : key1 == key2);
-}
-
-/** Compute the hashcode of a hashtable key.
- * The table's key_hash_fn is used if defined, otherwise the address of
- * the key is hashed.
- *
- * @param table hashtable
- * @param key to hash
- * @return hashcode
- */
-inline Hashcode HashTable_key_hash(HashTable *table, void *key){
- if(table->key_size){
- return _hash(key, table->key_size, 0);
- }
- return (table->key_hash_fn
- ? table->key_hash_fn(key)
- : hash_hvoid(0, &key, sizeof(key)));
-}
-
-/** Test if an entry has a given key.
- *
- * @param arg containing key to test for
- * @param table the entry is in
- * @param entry to test
- * @return 1 if the entry has the key, 0 otherwise
- */
-static inline int has_key(TableArg arg, HashTable *table, HTEntry *entry){
- return HashTable_key_equal(table, arg.ptr, entry->key);
-}
-
-/** Get an entry with a given key.
- *
- * @param table to search
- * @param key to look for
- * @return entry if found, null otherwise
- */
-inline HTEntry * HashTable_get_entry(HashTable *table, void *key){
- Hashcode hashcode;
- HTBucket *bucket;
- HTEntry *entry = NULL;
- HTEntry *next;
-
- hashcode = HashTable_key_hash(table, key);
- bucket = get_bucket(table, hashcode);
- for(entry = bucket->head; entry; entry = next){
- next = entry->next;
- if(HashTable_key_equal(table, key, entry->key)){
- break;
- }
- }
- return entry;
-}
-
-/** Get the value of an entry with a given key.
- *
- * @param table to search
- * @param key to look for
- * @return value if an entry was found, null otherwise
- */
-inline void * HashTable_get(HashTable *table, void *key){
- HTEntry *entry = HashTable_get_entry(table, key);
- return (entry ? entry->value : 0);
-}
-
-/** Print the buckets in a table.
- *
- * @param table to print
- */
-void show_buckets(HashTable *table, IOStream *io){
- int i,j ;
- IOStream_print(io, "entry_count=%d buckets_n=%d\n", table->entry_count, table->buckets_n);
- for(i=0; i < table->buckets_n; i++){
- if(0 || table->buckets[i].count>0){
- IOStream_print(io, "bucket %3d %3d %10p ", i,
- table->buckets[i].count,
- table->buckets[i].head);
- for(j = table->buckets[i].count; j>0; j--){
- IOStream_print(io, "+");
- }
- IOStream_print(io, "\n");
- }
- }
- HashTable_print(table, io);
-}
-
-/** Print an entry in a table.
- *
- * @param entry to print
- * @param arg a pointer to an IOStream to print to
- * @return 0
- */
-static int print_entry(TableArg arg, HashTable *table, HTEntry *entry){
- IOStream *io = (IOStream*)arg.ptr;
- IOStream_print(io, " b=%4lx h=%08lx |-> e=%8p k=%8p v=%8p\n",
- entry->hashcode % table->buckets_n,
- entry->hashcode,
- entry, entry->key, entry->value);
- return 0;
-}
-
-/** Print a hash table.
- *
- * @param table to print
- */
-void HashTable_print(HashTable *table, IOStream *io){
- IOStream_print(io, "{\n");
- HashTable_map(table, print_entry, (TableArg){ ptr: io });
- IOStream_print(io, "}\n");
-}
-/*==========================================================================*/
-
-/** Add an entry to the bucket for the
- * given hashcode.
- *
- * @param table to insert in
- * @param hashcode indicates the bucket
- * @param key to add an entry for
- * @param value to add an entry for
- * @return entry on success, 0 on failure
- */
-inline HTEntry * HashTable_add_entry(HashTable *table, Hashcode hashcode, void *key, void *value){
- HTEntry *entry = HTEntry_new(hashcode, key, value);
- if(entry){
- push_on_bucket(table, hashcode, entry);
- table->entry_count++;
- }
- return entry;
-}
-
-/** Move the front entry for a bucket to the correct point in the bucket order as
- * defined by the order function. If this is called every time a new entry is added
- * the bucket will be maintained in sorted order.
- *
- * @param table to modify
- * @param hashcode indicates the bucket
- * @param order entry comparison function
- * @return 0 if an entry was moved, 1 if not
- */
-int HashTable_order_bucket(HashTable *table, Hashcode hashcode, TableOrderFn *order){
- HTEntry *new_entry = NULL, *prev = NULL, *entry = NULL;
- HTBucket *bucket;
- int err = 1;
-
- bucket = get_bucket(table, hashcode);
- new_entry = bucket->head;
- if(!new_entry || !new_entry->next) goto exit;
- for(entry = new_entry->next; entry; prev = entry, entry = entry->next){
- if(order(new_entry, entry) <= 0) break;
- }
- if(prev){
- err = 0;
- bucket->head = new_entry->next;
- new_entry->next = entry;
- prev->next = new_entry;
- }
- exit:
- return err;
-}
-
-/** Add an entry to a hashtable.
- * The entry is added to the bucket for its key's hashcode.
- *
- * @param table to insert in
- * @param key to add an entry for
- * @param value to add an entry for
- * @return entry on success, 0 on failure
- */
-inline HTEntry * HashTable_add(HashTable *table, void *key, void *value){
- return HashTable_add_entry(table, HashTable_key_hash(table, key), key, value);
-}
-
-/** Remove entries satisfying a test from the bucket for the
- * given hashcode.
- *
- * @param table to remove from
- * @param hashcode indicates the bucket
- * @param test_fn test to apply to elements
- * @param arg first argument to calls to test_fn
- * @return number of entries removed
- */
-inline int HashTable_remove_entry(HashTable *table, Hashcode hashcode,
- TableTestFn *test_fn, TableArg arg){
- HTBucket *bucket;
- HTEntry *entry, *prev = NULL, *next;
- int removed_count = 0;
-
- bucket = get_bucket(table, hashcode);
- for(entry = bucket->head; entry; entry = next){
- next = entry->next;
- if(test_fn(arg, table, entry)){
- if(prev){
- prev->next = next;
- } else {
- bucket->head = next;
- }
- bucket->count--;
- table->entry_count--;
- removed_count++;
- HashTable_free_entry(table, entry);
- entry = NULL;
- }
- prev = entry;
- }
- return removed_count;
-}
-
-/** Remove entries with a given key.
- *
- * @param table to remove from
- * @param key of entries to remove
- * @return number of entries removed
- */
-inline int HashTable_remove(HashTable *table, void *key){
- Hashcode hashcode;
- HTBucket *bucket;
- HTEntry *entry, *prev = NULL, *next;
- int removed_count = 0;
-
- hashcode = HashTable_key_hash(table, key);
- bucket = get_bucket(table, hashcode);
- for(entry = bucket->head; entry; entry = next){
- next = entry->next;
- if(HashTable_key_equal(table, key, entry->key)){
- if(prev){
- prev->next = next;
- } else {
- bucket->head = next;
- }
- bucket->count--;
- table->entry_count--;
- removed_count++;
- HashTable_free_entry(table, entry);
- entry = NULL;
- }
- prev = entry;
- }
- return removed_count;
-}
-
-/** Remove (and free) all the entries in a bucket.
- *
- * @param bucket to clear
- */
-static inline void bucket_clear(HashTable *table, HTBucket *bucket){
- HTEntry *entry, *next;
-
- for(entry = bucket->head; entry; entry = next){
- next = entry->next;
- HashTable_free_entry(table, entry);
- }
- bucket->head = NULL;
- table->entry_count -= bucket->count;
- bucket->count = 0;
-}
-
-/** Remove (and free) all the entries in a table.
- *
- * @param table to clear
- */
-void HashTable_clear(HashTable *table){
- int i, n = table->buckets_n;
-
- for(i = 0; i < n; i++){
- bucket_clear(table, table->buckets + i);
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2005 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _XUTIL_HASH_TABLE_H_
-#define _XUTIL_HASH_TABLE_H_
-
-#include "iostream.h"
-#include "sys_string.h"
-
-typedef unsigned long Hashcode;
-
-/** Type used to pass parameters to table functions. */
-typedef union TableArg {
- unsigned long ul;
- void *ptr;
-} TableArg;
-
-/** An entry in a bucket list. */
-typedef struct HTEntry {
- /** Hashcode of the entry's key. */
- Hashcode hashcode;
- /** The key for this entry. */
- void *key;
- /** The value in this entry. */
- void *value;
- /** The next entry in the list. */
- struct HTEntry *next;
-} HTEntry;
-
-/** A bucket in a rule table. */
-typedef struct HTBucket {
- /** Number of entries in the bucket. */
- int count;
- /** First entry in the bucket (may be null). */
- HTEntry *head;
-} HTBucket;
-
-/** Default number of buckets in a hash table.
- * You want enough buckets so the lists in the buckets will typically be short.
- * If the hash function is good it doesn't matter whether the number of
- * buckets is prime or not.
- */
-//#define HT_BUCKETS_N 1
-//#define HT_BUCKETS_N 3
-//#define HT_BUCKETS_N 7
-//#define HT_BUCKETS_N 17
-//#define HT_BUCKETS_N 97
-//#define HT_BUCKETS_N 211
-//#define HT_BUCKETS_N 401
-#define HT_BUCKETS_N 1021
-
-typedef struct HashTable HashTable;
-
-/** Type for a function used to select table entries. */
-typedef int TableTestFn(TableArg arg, HashTable *table, HTEntry *entry);
-
-/** Type for a function to map over table entries. */
-typedef int TableMapFn(TableArg arg, HashTable *table, HTEntry *entry);
-
-/** Type for a function to free table entries. */
-typedef void TableFreeFn(HashTable *table, HTEntry *entry);
-
-/** Type for a function to hash table keys. */
-typedef Hashcode TableHashFn(void *key);
-
-/** Type for a function to test table keys for equality. */
-typedef int TableEqualFn(void *key1, void *key2);
-
-/** Type for a function to order table entries. */
-typedef int TableOrderFn(HTEntry *e1, HTEntry *e2);
-
-/** General hash table.
- * A hash table with a list in each bucket.
- * Functions can be supplied for freeing entries, hashing keys, and comparing keys.
- * These all default to 0, when default behaviour treating keys as integers is used.
- */
-struct HashTable {
- /** Array of buckets, each with its own list. */
- HTBucket *buckets;
- /** Number of buckets in the bucket array. */
- int buckets_n;
- /** Number of entries in the table. */
- int entry_count;
- unsigned long key_size;
- /** Function to free keys and values in entries. */
- TableFreeFn *entry_free_fn;
- /** Function to hash keys. */
- TableHashFn *key_hash_fn;
- /** Function to compare keys for equality. */
- TableEqualFn *key_equal_fn;
- /** Place for the user of the table to hang extra data. */
- void *user_data;
-};
-
-extern HashTable *HashTable_new(int bucket_n);
-extern void HashTable_free(HashTable *table);
-extern HTEntry * HTEntry_new(Hashcode hashcode, void *key, void *value);
-extern void HTEntry_free(HTEntry *entry);
-extern int HashTable_set_bucket_n(HashTable *table, int bucket_n);
-extern void HashTable_clear(HashTable *table);
-extern HTEntry * HashTable_add_entry(HashTable *table, Hashcode hashcode, void *key, void *value);
-extern HTEntry * HashTable_get_entry(HashTable *table, void *key);
-extern HTEntry * HashTable_add(HashTable *table, void *key, void *value);
-extern void * HashTable_get(HashTable *table, void *key);
-extern int HashTable_remove(HashTable *table, void *key);
-extern HTEntry * HashTable_find_entry(HashTable *table, Hashcode hashcode,
- TableTestFn *test_fn, TableArg arg);
-extern int HashTable_remove_entry(HashTable *table, Hashcode hashcode,
- TableTestFn *test_fn, TableArg arg);
-extern void HashTable_print(HashTable *table, IOStream *out);
-extern int HashTable_set_buckets_n(HashTable *table, int buckets_n);
-extern int HashTable_adjust(HashTable *table, int buckets_min);
-
-extern int HashTable_order_bucket(HashTable *table, Hashcode hashcode, TableOrderFn *order);
-
-typedef unsigned long ub4;
-typedef unsigned char ub1;
-
-extern ub4 hash(const ub1 *k, ub4 length, ub4 initval);
-
-/** Hash some bytes starting with a given hashcode.
- *
- * @param h initial hashcode - use 0, a previous hash, or an arbitrary value
- * @param b bytes to hash
- * @param b_n number of bytes to hash
- * @return hashcode
- */
-static inline Hashcode hash_hvoid(Hashcode h, const void *b, unsigned b_n){
- return hash(b, b_n, h);
-}
-
-/** Hash a string (null-terminated).
- *
- * @param s input to hash
- * @return hashcode
- */
-static inline Hashcode hash_string(char *s){
- return (s ? hash_hvoid(0, s, strlen(s)) : 0);
-}
-
-/** Macro to declare variables for HashTable_for_each() to use.
- *
- * @param entry variable that is set to entries in the table
- */
-#define HashTable_for_decl(entry) \
- HashTable *_var_table; \
- HTBucket *_var_bucket; \
- HTBucket *_var_end; \
- HTEntry *_var_next; \
- HTEntry *entry
-
-/** Macro to iterate over the entries in a hashtable.
- * Must be in a scope where HashTable_for_decl() has been used to declare
- * variables for it to use.
- * The variable 'entry' is iterated over entries in the table.
- * The code produced is syntactically a loop, so it must be followed by
- * a loop body, typically some statements in braces:
- * HashTable_for_each(entry, table){ ...loop body... }
- *
- * HashTable_for_each() and HashTable_for_decl() cannot be used for nested
- * loops as variables will clash.
- *
- * @note The simplest way to code a direct loop over the entries in a hashtable
- * is to use a loop over the buckets, with a nested loop over the entries
- * in a bucket. Using this approach in a macro means the macro contains
- * an opening brace, and calls to it must be followed by 2 braces!
- * To avoid this the code has been restructured so that it is a for loop.
- * So that statements could be used in the test expression of the for loop,
- * we have used the gcc statement expression extension ({ ... }).
- *
- * @param entry variable to iterate over the entries
- * @param table to iterate over (non-null)
- */
-#define HashTable_for_each(entry, table) \
- _var_table = table; \
- _var_bucket = _var_table->buckets; \
- _var_end = _var_bucket + _var_table->buckets_n; \
- for(entry=0, _var_next=0; \
- ({ if(_var_next){ \
- entry = _var_next; \
- _var_next = entry->next; \
- } else { \
- while(_var_bucket < _var_end){ \
- entry = _var_bucket->head; \
- _var_bucket++; \
- if(entry){ \
- _var_next = entry->next; \
- break; \
- } \
- } \
- }; \
- entry; }); \
- entry = _var_next )
-
-/** Map a function over the entries in a table.
- * Mapping stops when the function returns a non-zero value.
- * Uses the gcc statement expression extension ({ ... }).
- *
- * @param table to map over
- * @param fn function to apply to entries
- * @param arg first argument to call the function with
- * @return 0 if fn always returned 0, first non-zero value otherwise
- */
-#define HashTable_map(table, fn, arg) \
- ({ HashTable_for_decl(_var_entry); \
- TableArg _var_arg = arg; \
- int _var_value = 0; \
- HashTable_for_each(_var_entry, table){ \
- if((_var_value = fn(_var_arg, _var_table, _var_entry))) break; \
- } \
- _var_value; })
-
-/** Cast x to the type for a key or value in a hash table.
- * This avoids compiler warnings when using short integers
- * as keys or values (especially on 64-bit platforms).
- */
-#define HKEY(x) ((void*)(unsigned long)(x))
-
-/** Cast x from the type for a key or value in a hash table.
- * to an unsigned long. This avoids compiler warnings when using
- * short integers as keys or values (especially on 64-bit platforms).
- */
-#define HVAL(x) ((unsigned long)(x))
-
-#endif /* !_XUTIL_HASH_TABLE_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include "iostream.h"
-#include "sys_string.h"
-
-/** Print on a stream, like vfprintf().
- *
- * @param stream to print to
- * @param format for the print (as fprintf())
- * @param args arguments to print
- * @return result code from the print
- */
-int IOStream_vprint(IOStream *stream, const char *format, va_list args){
- char buffer[1024];
- int k = sizeof(buffer), n;
-
- n = vsnprintf(buffer, k, (char*)format, args);
- if(n < 0 || n > k ){
- n = k;
- }
- n = IOStream_write(stream, buffer, n);
- return n;
-}
-
-/** Print on a stream, like fprintf().
- *
- * @param stream to print to
- * @param format for the print (as fprintf())
- * @return result code from the print
- */
-int IOStream_print(IOStream *stream, const char *format, ...){
- va_list args;
- int result = -1;
-
- va_start(args, format);
- result = IOStream_vprint(stream, format, args);
- va_end(args);
- return result;
-}
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _XUTIL_IOSTREAM_H_
-#define _XUTIL_IOSTREAM_H_
-
-#include <stdarg.h>
-
-#ifdef __KERNEL__
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#else
-#include <errno.h>
-#include <stdint.h>
-#include <stddef.h>
-#endif
-
-#include "allocate.h"
-
-/** End of input return value (for getc). */
-#define IOSTREAM_EOF -1
-
-/** An input/output abstraction.
- */
-typedef struct IOStream IOStream;
-
-/** Record of the functions to use for operations on an
- * IOStream implementation.
- */
-typedef struct IOMethods {
- /** Read function. Called with the user data, buffer to read into
- * and number of bytes to read. Must return number of bytes read
- * on success, less than zero on error.
- */
- int (*read)(IOStream *stream, void *buf, size_t n);
-
- /** Write function. Called with user data, buffer to write and
- * number of bytes to write. Must return number of bytes written on
- * success, less than zero otherwise.
- */
- int (*write)(IOStream *stream, const void *buf, size_t n);
-
- int (*flush)(IOStream *s);
-
- int (*error)(IOStream *s);
-
- int (*close)(IOStream *s);
-
- void (*free)(IOStream *s);
-
- void (*lock)(IOStream *s);
- void (*unlock)(IOStream *s);
-
-} IOMethods;
-
-/** Abstract i/o object.
- */
-struct IOStream {
- /** Methods to use to implement operations. */
- const IOMethods *methods;
- /** Private state for the implementation. */
- const void *data;
- /** Flag indicating whether the stream is closed. */
- int closed;
- /** Number of bytes written. */
- int written;
- /** Number of bytes read. */
- int read;
- /** Flag indicating whether not to free when closed. */
- int nofree;
-};
-
-
-/** IOStream version of stdin. */
-extern IOStream *iostdin;
-
-/** IOStream version of stdout, */
-extern IOStream *iostdout;
-
-/** IOStream version of stderr. */
-extern IOStream *iostderr;
-
-extern int IOStream_print(IOStream *io, const char *format, ...);
-extern int IOStream_vprint(IOStream *io, const char *format, va_list args);
-
-/** Read from a stream.
- *
- * @param stream input
- * @param buf where to put input
- * @param n number of bytes to read
- * @return if ok, number of bytes read, otherwise negative error code
- */
-static inline int IOStream_read(IOStream *stream, void *buf, size_t n){
- int result;
- if(stream->closed){
- result = -EIO;
- goto exit;
- }
- if(!stream->methods || !stream->methods->read){
- result = -EINVAL;
- goto exit;
- }
- result = (stream->methods->read)(stream, buf, n);
- if(result > 0){
- stream->read += result;
- }
- exit:
- return result;
-}
-
-/** Write to a stream.
- *
- * @param stream input
- * @param buf where to put input
- * @param n number of bytes to write
- * @return if ok, number of bytes written, otherwise negative error code
- */
-static inline int IOStream_write(IOStream *stream, const void *buf, size_t n){
- int result;
- if(stream->closed){
- result = -EIO;
- goto exit;
- }
- if(!stream->methods || !stream->methods->write){
- result = -EINVAL;
- goto exit;
- }
- result = (stream->methods->write)(stream, buf, n);
- if(result > 0){
- stream->written += result;
- }
- exit:
- return result;
-}
-
-/** Flush the stream.
- *
- * @param stream stream
- * @return 0 on success, negative error code otherwise
- */
-static inline int IOStream_flush(IOStream *stream){
- int result = 0;
- if(stream->closed){
- result = -EIO;
- } else if(stream->methods->flush){
- result = (stream->methods->flush)(stream);
- }
- return result;
-}
-
-/** Check whether the stream has an error.
- *
- * @param stream to check
- * @return 1 for error, 0 otherwise
- */
-static inline int IOStream_error(IOStream *stream){
- int err = 0;
- if(stream->methods && stream->methods->error){
- err = (stream->methods->error)(stream);
- }
- return err;
-}
-
-/** Close the stream.
- *
- * @param stream to close
- * @return 0 on success, negative error code otherwise
- */
-static inline int IOStream_close(IOStream *stream){
- int err = 0;
- if(!stream || stream->closed){
- err = -EIO;
- goto exit;
- }
- if(stream->methods && stream->methods->close){
- err = (stream->methods->close)(stream);
- stream->closed = 1;
- }
- if(stream->nofree) goto exit;
- if(stream->methods && stream->methods->free){
- (stream->methods->free)(stream);
- }
- *stream = (IOStream){};
- deallocate(stream);
- exit:
- return err;
-}
-
-/** Test if the stream has been closed.
- *
- * @param stream to check
- * @return 1 if closed, 0 otherwise
- */
-static inline int IOStream_is_closed(IOStream *stream){
- return stream->closed;
-}
-
-/** Print a character to a stream, like fputc().
- *
- * @param stream to print to
- * @param c character to print
- * @return result code from the print
- */
-static inline int IOStream_putc(IOStream *stream, int c){
- int err;
- unsigned char b = (unsigned char)c;
- err = IOStream_write(stream, &b, 1);
- if(err < 1){
- err = IOSTREAM_EOF;
- } else {
- err = b;
- }
- return err;
-}
-
-/** Read from a stream, like fgetc().
- *
- * @param stream to read from
- * @return IOSTREAM_EOF on error, character read otherwise
- */
-static inline int IOStream_getc(IOStream *stream){
- int err, rc;
- unsigned char b;
-
- err = IOStream_read(stream, &b, 1);
- if(err < 1){
- rc = IOSTREAM_EOF;
- } else {
- rc = b;
- }
- return rc;
-}
-
-/** Get number of bytes read.
- *
- * @param stream to get from
- * @return number of bytes read
- */
-static inline int IOStream_get_read(IOStream *stream){
- return stream->read;
-}
-
-/** Get number of bytes written.
- *
- * @param stream to get from
- * @return number of bytes written
- */
-static inline int IOStream_get_written(IOStream *stream){
- return stream->written;
-}
-
-
-#endif /* ! _XUTIL_IOSTREAM_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/** @file
- * An IOStream implementation using printk() for output.
- * Input is not implemented.
- */
-#ifdef __KERNEL__
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-
-#include "kernel_stream.h"
-#include "allocate.h"
-
-/** Number of characters in the output buffer.
- * The kernel uses 1024 for printk, so that should suffice.
- */
-#define BUF_N 1024
-
-/** State for a kernel stream. */
-typedef struct KernelData {
- /** Stream lock. We need a lock to serialize access to the stream. */
- spinlock_t lock;
- /** Saved flags for locking. */
- unsigned long flags;
- /** Size of the output buffer. */
- int buf_n;
- /** Output buffer. */
- char buf[BUF_N];
-} KernelData;
-
-static int kernel_write(IOStream *s, const void *msg, size_t n);
-static void kernel_free(IOStream *s);
-static void kernel_stream_lock(IOStream *s);
-static void kernel_stream_unlock(IOStream *s);
-
-/** Methods for a kernel stream. Output only. */
-static const IOMethods kernel_methods = {
- write: kernel_write,
- free: kernel_free,
- lock: kernel_stream_lock,
- unlock: kernel_stream_unlock,
-};
-
-/** Shared state for kernel streams.
- * All implementations write using printk, so we can use
- * shared state and avoid allocating it.
- */
-static const KernelData kernel_data = {
- lock: SPIN_LOCK_UNLOCKED,
- flags: 0,
- buf_n: BUF_N,
-};
-
-/** Stream for kernel printk. */
-static IOStream iokernel = {
- methods: &kernel_methods,
- data: &kernel_data,
- nofree: 1,
-};
-
-/** Stream for kernel printk. */
-IOStream *iostdout = &iokernel;
-
-/** Stream for kernel printk. */
-IOStream *iostdin = &iokernel;
-
-/** Stream for kernel printk. */
-IOStream *iostderr = &iokernel;
-
-/** Get an output-only stream implementation using
- * printk(). The stream uses static storage, and must not be freed.
- *
- * @return kernel stream
- */
-IOStream get_stream_kernel(void){
- return iokernel;
-}
-
-/** Obtain the lock on the stream state.
- *
- * @param kdata stream state
- */
-static inline void KernelData_lock(KernelData *kdata){
- spin_lock_irqsave(&kdata->lock, kdata->flags);
-}
-
-/** Release the lock on the stream state.
- *
- * @param kdata stream state
- */
-static inline void KernelData_unlock(KernelData *kdata){
- spin_unlock_irqrestore(&kdata->lock, kdata->flags);
-}
-
-/** Get the stream state.
- *
- * @param s kernel stream
- * @return stream state
- */
-static inline KernelData *get_kernel_data(IOStream *s){
- return (KernelData*)s->data;
-}
-
-/** Obtain the lock on the stream state.
- *
- * @param s stream
- */
-void kernel_stream_lock(IOStream *s){
- KernelData_lock(get_kernel_data(s));
-}
-
-/** Release the lock on the stream state.
- *
- * @param s stream
- */
-void kernel_stream_unlock(IOStream *s){
- KernelData_unlock(get_kernel_data(s));
-}
-
-/** Write to a kernel stream.
- *
- * @param stream kernel stream
- * @param format print format
- * @param args print arguments
- * @return result of the print
- */
-static int kernel_write(IOStream *stream, const void *buf, size_t n){
- KernelData *kdata = get_kernel_data(stream);
- int k;
- k = kdata->buf_n - 1;
- if(n < k) k = n;
- memcpy(kdata->buf, buf, k);
- kdata->buf[k] = '\0';
- printk(kdata->buf);
- return k;
-}
-
-/** Free a kernel stream.
- * Frees the internal state of the stream.
- * Do not call this unless the stream was dynamically allocated.
- * Do not call this on a stream returned from get_stream_kernel().
- *
- * @param io stream to free
- */
-static void kernel_free(IOStream *io){
- KernelData *kdata;
- if(io == &iokernel) return;
- kdata = get_kernel_data(io);
- memset(kdata, 0, sizeof(*kdata));
- deallocate(kdata);
-}
-#endif /* __KERNEL__ */
-
-
-
-
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _XUTIL_KERNEL_STREAM_H_
-#define _XUTIL_KERNEL_STREAM_H_
-
-#ifdef __KERNEL__
-#include "iostream.h"
-
-extern IOStream get_stream_kernel(void);
-#define get_stream_stdout get_stream_kernel
-
-#endif /* __KERNEL__ */
-#endif /* !_XUTIL_KERNEL_STREAM_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/** @file
- * Lexical analysis.
- */
-
-#include "sys_string.h"
-#include "lexis.h"
-#include <errno.h>
-
-/** Check if a value lies in a (closed) range.
- *
- * @param x value to test
- * @param lo low end of the range
- * @param hi high end of the range
- * @return 1 if x is in the interval [lo, hi], 0 otherwise
- */
-inline static int in_range(int x, int lo, int hi){
- return (lo <= x) && (x <= hi);
-}
-
-/** Determine if a string is an (unsigned) decimal number.
- *
- * @param s pointer to characters to test
- * @param n length of string
- * @return 1 if s is a decimal number, 0 otherwise.
- */
-int is_decimal_number(const char *s, int n){
- int i;
- if(n <= 0)return 0;
- for(i = 0; i < n; i++){
- if(!in_decimal_digit_class(s[i])) return 0;
- }
- return 1;
-}
-
-/** Determine if a string is a hex number.
- * Hex numbers are 0, or start with 0x or 0X followed
- * by a non-zero number of hex digits (0-9,a-f,A-F).
- *
- * @param s pointer to characters to test
- * @param n length of string
- * @return 1 if s is a hex number, 0 otherwise.
- */
-int is_hex_number(const char *s, int n){
- int i;
- if(n <= 0) return 0;
- if(n == 1){
- return s[0]=='0';
- }
- if(n <= 3) return 0;
- if(s[0] != '0' || (s[1] != 'x' && s[1] != 'X')) return 0;
- for(i = 2; i < n; i++){
- if(!in_hex_digit_class(s[i])) return 0;
- }
- return 1;
-}
-
-/** Test if a string matches a keyword.
- * The comparison is case-insensitive.
- * The comparison fails if either argument is null.
- *
- * @param s string
- * @param k keyword
- * @return 1 if they match, 0 otherwise
- */
-int is_keyword(const char *s, const char *k){
- return s && k && !strcasecmp(s, k);
-}
-
-/** Test if a string matches a character.
- *
- * @param s string
- * @param c character (non-null)
- * @return 1 if s contains exactly c, 0 otherwise
- */
-int is_keychar(const char *s, char c){
- return c && (s[0] == c) && !s[1];
-}
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _XUTIL_LEXIS_H_
-#define _XUTIL_LEXIS_H_
-
-#include "sys_string.h"
-
-#ifdef __KERNEL__
-# include <linux/ctype.h>
-#else
-# include <ctype.h>
-#endif
-
-/** @file
- * Lexical analysis.
- */
-
-/** Class of characters treated as space. */
-#define space_class ((char []){ '\n', '\r', '\t', ' ', '\f' , 0 })
-
-/** Class of separator characters. */
-#define sep_class "{}()<>[]!;\"'"
-
-#define comment_class "#"
-
-/** Determine if a character is in a given class.
- *
- * @param c character to test
- * @param s null-terminated string of characters in the class
- * @return 1 if c is in the class, 0 otherwise.
- */
-static inline int in_class(int c, const char *s){
- return s && (strchr(s, c) != 0);
-}
-
-/** Determine if a character is in the space class.
- *
- * @param c character to test
- * @return 1 if c is in the class, 0 otherwise.
- */
-static inline int in_space_class(int c){
- return in_class(c, space_class);
-}
-
-static inline int in_comment_class(int c){
- return in_class(c, comment_class);
-}
-
-/** Determine if a character is in the separator class.
- * Separator characters terminate tokens, and do not need space
- * to separate them.
- *
- * @param c character to test
- * @return 1 if c is in the class, 0 otherwise.
- */
-static inline int in_sep_class(int c){
- return in_class(c, sep_class);
-}
-
-/** Determine if a character is in the alpha class.
- *
- * @param c character to test
- * @return 1 if c is in the class, 0 otherwise.
- */
-static inline int in_alpha_class(int c){
- return isalpha(c);
-}
-
-/** Determine if a character is in the octal digit class.
- *
- * @param c character to test
- * @return 1 if c is in the class, 0 otherwise.
- */
-static inline int in_octal_digit_class(int c){
- return '0' <= c && c <= '7';
-}
-
-/** Determine if a character is in the decimal digit class.
- *
- * @param c character to test
- * @return 1 if c is in the class, 0 otherwise.
- */
-static inline int in_decimal_digit_class(int c){
- return isdigit(c);
-}
-
-/** Determine if a character is in the hex digit class.
- *
- * @param c character to test
- * @return 1 if c is in the class, 0 otherwise.
- */
-static inline int in_hex_digit_class(int c){
- return isdigit(c) || in_class(c, "abcdefABCDEF");
-}
-
-
-static inline int in_string_quote_class(int c){
- return in_class(c, "'\"");
-}
-
-static inline int in_printable_class(int c){
- return ('A' <= c && c <= 'Z')
- || ('a' <= c && c <= 'z')
- || ('0' <= c && c <= '9')
- || in_class(c, "!$%&*+,-./:;<=>?@^_`{|}~");
-}
-
-extern int is_decimal_number(const char *s, int n);
-extern int is_hex_number(const char *s, int n);
-extern int is_keyword(const char *s, const char *k);
-extern int is_keychar(const char *s, char c);
-
-#endif /* !_XUTIL_LEXIS_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2005 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/** @file
- * IOStream subtype for input and output to memory.
- * Usable from user or kernel code (with __KERNEL__ defined).
- */
-
-#include "sys_string.h"
-#include "mem_stream.h"
-#include "allocate.h"
-
-/** Internal state for a memory stream.
- *
- * The memory stream buffer is treated as a circular buffer.
- * The lo and hi markers indicate positions in the buffer, but
- * are not reduced modulo the buffer size. This avoids the ambiguity
- * between a full and empty buffer when using reduced values.
- *
- * If x is a marker, then buf + (x % buf_n) is the corresponding
- * pointer into the buffer. When the buffer is empty, lo == hi,
- * and the corresponding pointers are equal. When the buffer is
- * full, hi == lo + buf_n, and the corresponding pointers
- * are also equal.
- *
- * Data is written after the high pointer and read from the lo pointer.
- * The value hi - lo is the number of bytes in the buffer.
- */
-typedef struct MemData {
- /** Data buffer. */
- char *buf;
- /** Low marker - start of readable area. */
- unsigned long lo;
- /** High marker - end of readable area, start of writeable area. */
- unsigned long hi;
- /** Size of the buffer. */
- unsigned int buf_n;
- /** Maximum size the buffer can grow to. */
- unsigned int buf_max;
- /** Error code. */
- int err;
-} MemData;
-
-/** Get number of bytes available to read.
- *
- * @param data mem stream
- * @return bytes
- */
-static inline int mem_len(struct MemData *data){
- return data->hi - data->lo;
-}
-
-/** Get available space left in the buffer.
- *
- * @param data mem stream
- * @return bytes
- */
-static inline int mem_room(struct MemData *data){
- return data->buf_n - mem_len(data);
-}
-
-/** Get a pointer to the start of the data in the buffer.
- *
- * @param data mem stream
- * @return lo pointer
- */
-static inline char * mem_lo(struct MemData *data){
- return data->buf + (data->lo % data->buf_n);
-}
-
-/** Get a pointer to the end of the data in the buffer.
- *
- * @param data mem stream
- * @return hi pointer
- */
-static inline char * mem_hi(struct MemData *data){
- return data->buf + (data->hi % data->buf_n);
-}
-
-/** Get a pointer to the end of the buffer.
- *
- * @param data mem stream
- * @return end pointer
- */
-static inline char * mem_end(struct MemData *data){
- return data->buf + data->buf_n;
-}
-
-static int mem_error(IOStream *io);
-static int mem_close(IOStream *io);
-static void mem_free(IOStream *io);
-static int mem_write(IOStream *io, const void *msg, size_t n);
-static int mem_read(IOStream *io, void *buf, size_t n);
-
-/** Minimum delta used to increment the buffer. */
-static int delta_min = 256;
-
-/** Methods for a memory stream. */
-static IOMethods mem_methods = {
- read: mem_read,
- write: mem_write,
- error: mem_error,
- close: mem_close,
- free: mem_free,
-};
-
-/** Get the memory stream state.
- *
- * @param io memory stream
- * @return state
- */
-static inline MemData *get_mem_data(IOStream *io){
- return (MemData*)io->data;
-}
-
-/** Get the number of bytes available to read.
- *
- * @param io memory stream
- * @return number of bytes
- */
-int mem_stream_avail(IOStream *io){
- MemData *data = get_mem_data(io);
- return (data->err ? -data->err : mem_len(data));
-}
-
-/** Copy bytes from a memory stream into a buffer.
- *
- * @param data mem stream
- * @param buf buffer
- * @param n number of bytes to copy
- */
-static void mem_get(MemData *data, char *buf, size_t n){
- char *start = mem_lo(data);
- char *end = mem_end(data);
- if (start + n < end) {
- memcpy(buf, start, n);
- } else {
- int k = end - start;
- memcpy(buf, start, k);
- memcpy(buf + k, data->buf, n - k);
- }
-}
-
-/** Copy bytes from a buffer into a memory stream.
- *
- * @param data mem stream
- * @param buf buffer
- * @param n number of bytes to copy
- */
-static void mem_put(MemData *data, const char *buf, size_t n){
- char *start = mem_hi(data);
- char *end = mem_end(data);
- if(start + n < end){
- memcpy(start, buf, n);
- } else {
- int k = end - start;
- memcpy(start, buf, k);
- memcpy(data->buf, buf + k, n - k);
- }
-}
-
-/** Expand the buffer used by a memory stream.
- *
- * @param data mem stream
- * @param extra number of bytes to expand by
- * @return 0 on success, negative error otherwise
- */
-static int mem_expand(MemData *data, size_t extra){
- int err = -ENOMEM;
- int delta = (extra < delta_min ? delta_min : extra);
- int buf_n;
- char *buf;
- if(data->buf_max > 0){
- int delta_max = data->buf_max - data->buf_n;
- if(delta > delta_max){
- delta = extra;
- if(delta > delta_max) goto exit;
- }
- }
- buf_n = data->buf_n + delta;
- buf = allocate(buf_n);
- if(!buf) goto exit;
- mem_get(data, buf, mem_len(data));
- data->hi = mem_len(data);
- data->lo = 0;
- deallocate(data->buf);
- data->buf = buf;
- data->buf_n = buf_n;
- err = 0;
- exit:
- if(err){
- data->err = -err;
- }
- return err;
-}
-
-/** Write bytes from a buffer into a memory stream.
- * The internal buffer is expanded as needed to hold the data,
- * up to the stream maximum (if specified). If the buffer cannot
- * be expanded -ENOMEM is returned.
- *
- * @param io mem stream
- * @param buf buffer
- * @param n number of bytes to write
- * @return number of bytes written on success, negative error code otherwise
- */
-static int mem_write(IOStream *io, const void *msg, size_t n){
- int room;
- MemData *data = get_mem_data(io);
- if(data->err) return -data->err;
- room = mem_room(data);
- if(n > room){
- int err = mem_expand(data, n - room);
- if(err) return err;
- }
- mem_put(data, msg, n);
- data->hi += n;
- return n;
-}
-
-/** Read bytes from a memory stream into a buffer.
- *
- * @param io mem stream
- * @param buf buffer
- * @param n maximum number of bytes to read
- * @return number of bytes read on success, negative error code otherwise
- */
-static int mem_read(IOStream *io, void *buf, size_t n){
- int k;
- MemData *data = get_mem_data(io);
- if(data->err) return -data->err;
- k = mem_len(data);
- if(n > k){
- n = k;
- }
- mem_get(data, buf, n);
- data->lo += n;
- return n;
-}
-
-/** Test if a memory stream has an error.
- *
- * @param io mem stream
- * @return 0 if ok, error code otherwise
- */
-static int mem_error(IOStream *io){
- MemData *data = get_mem_data(io);
- return data->err;
-}
-
-/** Close a memory stream.
- *
- * @param io mem stream
- * @return 0
- */
-static int mem_close(IOStream *io){
- MemData *data = get_mem_data(io);
- if(!data->err){
- data->err = ENOTCONN;
- }
- return 0;
-}
-
-/** Free a memory stream.
- *
- * @param io mem stream
- */
-static void mem_free(IOStream *io){
- MemData *data = get_mem_data(io);
- deallocate(data->buf);
- memzero(data, sizeof(*data));
- deallocate(data);
-}
-
-/** Allocate and initialise a memory stream.
- *
- * @param buf_n initial buffer size (0 means default)
- * @param buf_max maximum buffer size (0 means no max)
- * @return new stream (free using IOStream_close)
- */
-IOStream *mem_stream_new_size(size_t buf_n, size_t buf_max){
- int err = -ENOMEM;
- MemData *data = ALLOCATE(MemData);
- IOStream *io = NULL;
- if(!data) goto exit;
- io = ALLOCATE(IOStream);
- if(!io) goto exit;
- if(buf_n <= delta_min){
- buf_n = delta_min;
- }
- if(buf_max > 0 && buf_max < buf_n){
- buf_max = buf_n;
- }
- data->buf = allocate(buf_n);
- if(!data->buf) goto exit;
- data->buf_n = buf_n;
- data->buf_max = buf_max;
- io->methods = &mem_methods;
- io->data = data;
- io->nofree = 0;
- err = 0;
- exit:
- if(err){
- deallocate(data);
- deallocate(io);
- io = NULL;
- }
- return io;
-}
+++ /dev/null
-/*
- * Copyright (C) 2005 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _XUTIL_MEM_STREAM_H_
-#define _XUTIL_MEM_STREAM_H_
-
-#include "iostream.h"
-
-extern IOStream *mem_stream_new_size(size_t buf_n, size_t buf_max);
-
-extern int mem_stream_avail(IOStream *io);
-
-static inline IOStream *mem_stream_new(void){
- return mem_stream_new_size(0, 0);
-}
-
-#endif /* !_XUTIL_MEM_STREAM_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/** @file
- * An IOStream implementation using sockets.
- */
-#ifndef __KERNEL__
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include "allocate.h"
-#include "socket_stream.h"
-
-#define MODULE_NAME "sock"
-#define DEBUG 0
-//#undef DEBUG
-#include "debug.h"
-
-static int socket_read(IOStream *s, void *buf, size_t n);
-static int socket_write(IOStream *s, const void *buf, size_t n);
-static int socket_error(IOStream *s);
-static int socket_close(IOStream *s);
-static void socket_free(IOStream *s);
-static int socket_flush(IOStream *s);
-
-/** Methods used by a socket IOStream. */
-static const IOMethods socket_methods = {
- read: socket_read,
- write: socket_write,
- error: socket_error,
- close: socket_close,
- free: socket_free,
- flush: socket_flush,
-};
-
-/** Get the socket data.
- *
- * @param io socket stream
- * @return data
- */
-static inline SocketData * socket_data(IOStream *io){
- return (SocketData *)io->data;
-}
-
-/** Test if a stream is a socket stream.
- *
- * @param io stream
- * @return 0 if a socket stream, -EINVAL if not
- */
-int socket_stream_check(IOStream *io){
- return (io && io->methods == &socket_methods ? 0 : -EINVAL);
-}
-
-/** Get the data for a socket stream.
- *
- * @param io stream
- * @param data return value for the data
- * @return 0 if a socket stream, -EINVAL if not
- */
-int socket_stream_data(IOStream *io, SocketData **data){
- int err = socket_stream_check(io);
- if(err){
- *data = NULL;
- } else {
- *data = socket_data(io);
- }
- return err;
-}
-
-/** Set the destination address for a socket stream.
- *
- * @param io stream
- * @param addr address
- * @return 0 if a socket stream, -EINVAL if not
- */
-int socket_stream_set_addr(IOStream *io, struct sockaddr_in *addr){
- int err = 0;
- SocketData *data = NULL;
- err = socket_stream_data(io, &data);
- if(!err){
- data->daddr = *addr;
- }
- return err;
-}
-
-/** Set the send flags for a socket stream.
- *
- * @param io stream
- * @param flags flags
- * @return 0 if a socket stream, -EINVAL if not
- */
-int socket_stream_set_flags(IOStream *io, int flags){
- int err = 0;
- SocketData *data = NULL;
- err = socket_stream_data(io, &data);
- if(!err){
- data->flags = flags;
- }
- return err;
-}
-
-/** Write to the underlying socket using sendto.
- *
- * @param stream input
- * @param buf where to put input
- * @param n number of bytes to write
- * @return number of bytes written
- */
-static int socket_write(IOStream *s, const void *buf, size_t n){
- SocketData *data = socket_data(s);
- struct sockaddr *daddr = (struct sockaddr *)&data->daddr;
- socklen_t daddr_n = sizeof(data->daddr);
- int k;
- dprintf("> sock=%d addr=%s:%d n=%d\n",
- data->fd, inet_ntoa(data->daddr.sin_addr), ntohs(data->daddr.sin_port), n);
- if(0){
- struct sockaddr_in self = {};
- socklen_t self_n;
- getsockname(data->fd, (struct sockaddr *)&self, &self_n);
- dprintf("> sockname sock=%d %s:%d\n",
- data->fd, inet_ntoa(self.sin_addr), ntohs(self.sin_port));
- }
- k = sendto(data->fd, buf, n, data->flags, daddr, daddr_n);
- dprintf("> sendto=%d\n", k);
- return k;
-}
-
-/** Read from the underlying stream using recv();
- *
- * @param stream input
- * @param buf where to put input
- * @param n number of bytes to read
- * @return number of bytes read
- */
-static int socket_read(IOStream *s, void *buf, size_t n){
- SocketData *data = socket_data(s);
- int k;
- struct sockaddr *saddr = (struct sockaddr *)&data->saddr;
- socklen_t saddr_n = sizeof(data->saddr);
- k = recvfrom(data->fd, buf, n, data->flags, saddr, &saddr_n);
- return k;
-}
-
-/** Flush the socket (no-op).
- *
- * @param s socket stream
- * @return 0 on success, error code otherwise
- */
-static int socket_flush(IOStream *s){
- return 0;
-}
-
-/** Check if a socket stream has an error (no-op).
- *
- * @param s socket stream
- * @return 1 if has an error, 0 otherwise
- */
-static int socket_error(IOStream *s){
- // Read SOL_SOCKET/SO_ERROR ?
- return 0;
-}
-
-/** Close a socket stream.
- *
- * @param s socket stream to close
- * @return result of the close
- */
-static int socket_close(IOStream *s){
- SocketData *data = socket_data(s);
- return close(data->fd);
-}
-
-/** Free a socket stream.
- *
- * @param s socket stream
- */
-static void socket_free(IOStream *s){
- SocketData *data = socket_data(s);
- deallocate(data);
-}
-
-/** Create an IOStream for a socket.
- *
- * @param fd socket to wtap
- * @return new IOStream using fd for i/o
- */
-IOStream *socket_stream_new(int fd){
- int err = -ENOMEM;
- IOStream *io = NULL;
- SocketData *data = NULL;
-
- io = ALLOCATE(IOStream);
- if(!io) goto exit;
- io->methods = &socket_methods;
- data = ALLOCATE(SocketData);
- if(!data) goto exit;
- io->data = data;
- data->fd = fd;
- data->buf_n = sizeof(data->buf);
- err = 0;
- exit:
- if(err){
- if(io){
- if(data) deallocate(data);
- deallocate(io);
- io = NULL;
- }
- }
- return io;
-}
-
-#endif
+++ /dev/null
-/*
- * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _XEN_LIB_SOCKET_STREAM_H_
-#define _XEN_LIB_SOCKET_STREAM_H_
-
-#ifndef __KERNEL__
-#include "iostream.h"
-#include <stdio.h>
-
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-/** Data associated with a socket stream. */
-typedef struct SocketData {
- /** The socket file descriptor. */
- int fd;
- /** Source address from last read (recvfrom). */
- struct sockaddr_in saddr;
- /** Destination address for writes (sendto). */
- struct sockaddr_in daddr;
- /** Write flags (sendto). */
- int flags;
- /** Buffer size. */
- int buf_n;
- /** Buffer for formatted printing. */
- char buf[1024];
-} SocketData;
-
-extern IOStream *socket_stream_new(int fd);
-extern int socket_stream_data(IOStream *io, SocketData **data);
-extern int socket_stream_check(IOStream *io);
-extern int socket_stream_set_addr(IOStream *io, struct sockaddr_in *addr);
-extern int socket_stream_set_flags(IOStream *io, int flags);
-
-#endif
-#endif /* !_XEN_LIB_SOCKET_STREAM_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/** @file
- * IOStream subtype for input and output to strings.
- * Usable from user or kernel code (with __KERNEL__ defined).
- */
-
-#include "sys_string.h"
-#include "string_stream.h"
-#include "allocate.h"
-
-static int string_error(IOStream *io);
-static int string_close(IOStream *io);
-static void string_free(IOStream *io);
-static int string_write(IOStream *io, const void *msg, size_t n);
-static int string_read(IOStream *io, void *buf, size_t n);
-
-/** Methods for a string stream. */
-static IOMethods string_methods = {
- read: string_read,
- write: string_write,
- error: string_error,
- close: string_close,
- free: string_free,
-};
-
-/** Get the string stream state.
- *
- * @param io string stream
- * @return state
- */
-static inline StringData *get_string_data(IOStream *io){
- return (StringData*)io->data;
-}
-
-static int string_write(IOStream *io, const void *msg, size_t n){
- StringData *data = get_string_data(io);
- int k;
-
- k = data->end - data->out;
- if(n > k) n = k;
- memcpy(data->out, msg, n);
- data->out += n;
- return n;
-}
-
-static int string_read(IOStream *io, void *buf, size_t n){
- StringData *data = get_string_data(io);
- int k;
-
- k = data->end - data->in;
- if(n > k) n = k;
- memcpy(buf, data->in, k);
- data->in += n;
- return n;
-}
-
-/** Test if a string stream has an error.
- *
- * @param io string stream
- * @return 0 if ok, error code otherwise
- */
-static int string_error(IOStream *io){
- StringData *data = get_string_data(io);
- return data->out == NULL;
-}
-
-/** Close a string stream.
- *
- * @param io string stream
- * @return 0
- */
-static int string_close(IOStream *io){
- StringData *data = get_string_data(io);
- data->in = NULL;
- data->out = NULL;
- return 0;
-}
-
-/** Free a string stream.
- * The stream state is freed, but the underlying string is not.
- *
- * @param io string stream
- */
-static void string_free(IOStream *io){
- StringData *data = get_string_data(io);
- memzero(data, sizeof(*data));
- deallocate(data);
-}
-
-/** Get the methods to use for a string stream.
- *
- * @return methods
- */
-IOMethods *string_stream_get_methods(void){
- return &string_methods;
-}
-
-/** Initialise a string stream, usually from static data.
- * If the stream and StringData should be freed when
- * the stream is closed, unset io->nofree.
- * The string is not freed on close.
- *
- * @param io address of IOStream to fill in
- * @param data address of StringData to fill in
- * @param s string to use
- * @param n length of the string
- */
-void string_stream_init(IOStream *io, StringData *data, char *s, int n){
- if(data && io){
- memzero(data, sizeof(*data));
- data->string = (char*)s;
- data->in = data->string;
- data->out = data->string;
- data->size = n;
- data->end = data->string + n;
- memzero(io, sizeof(*io));
- io->methods = &string_methods;
- io->data = data;
- io->nofree = 1;
- }
-}
-
-/** Allocate and initialise a string stream.
- * The stream is freed on close, but the string is not.
- *
- * @param s string to use
- * @param n length of the string
- * @return new stream (free using IOStream_free)
- */
-IOStream *string_stream_new(char *s, int n){
- int ok = 0;
- StringData *data = ALLOCATE(StringData);
- IOStream *io = ALLOCATE(IOStream);
- if(data && io){
- ok = 1;
- string_stream_init(io, data, s, n);
- io->nofree = 0;
- }
- if(!ok){
- deallocate(data);
- deallocate(io);
- io = NULL;
- }
- return io;
-}
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _XUTIL_STRING_STREAM_H_
-#define _XUTIL_STRING_STREAM_H_
-
-#include "iostream.h"
-
-/** Internal state for a string stream.
- * Exposed here so that string streams can be statically created, using
- * string_stream_init().
- */
-typedef struct {
- /** The string used for input and ouput. */
- char *string;
- /** Output pointer. */
- char *out;
- /** Input pointer. */
- char *in;
- /** Length of string. */
- int size;
- /** End marker. */
- char *end;
-} StringData;
-
-extern IOMethods *string_stream_get_methods(void);
-extern IOStream *string_stream_new(char *s, int n);
-extern void string_stream_init(IOStream *stream, StringData *data, char *s, int n);
-
-#endif /* !_XUTIL_STRING_STREAM_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <stdarg.h>
-#include "sys_string.h"
-#include "lexis.h"
-#include "sys_net.h"
-#include "hash_table.h"
-#include "sxpr.h"
-
-#ifdef __KERNEL__
-#include <linux/errno.h>
-#else
-#include <errno.h>
-#endif
-
-#ifdef __KERNEL__
-#include <linux/random.h>
-
-int rand(void){
- int v;
- get_random_bytes(&v, sizeof(v));
- return v;
-}
-
-#else
-#include <stdlib.h>
-#endif
-
-#undef free
-
-/** @file
- * General representation of sxprs.
- * Includes print, equal, and free functions for the sxpr types.
- *
- * Zero memory containing an Sxpr will have the value ONONE - this is intentional.
- * When a function returning an sxpr cannot allocate memory we return ONOMEM.
- *
- */
-
-static int atom_print(IOStream *io, Sxpr obj, unsigned flags);
-static int atom_equal(Sxpr x, Sxpr y);
-static void atom_free(Sxpr obj);
-static Sxpr atom_copy(Sxpr obj);
-
-static int string_print(IOStream *io, Sxpr obj, unsigned flags);
-static int string_equal(Sxpr x, Sxpr y);
-static void string_free(Sxpr obj);
-static Sxpr string_copy(Sxpr obj);
-
-static int cons_print(IOStream *io, Sxpr obj, unsigned flags);
-static int cons_equal(Sxpr x, Sxpr y);
-static void cons_free(Sxpr obj);
-static Sxpr cons_copy(Sxpr obj);
-
-static int null_print(IOStream *io, Sxpr obj, unsigned flags);
-static int none_print(IOStream *io, Sxpr obj, unsigned flags);
-static int int_print(IOStream *io, Sxpr obj, unsigned flags);
-static int bool_print(IOStream *io, Sxpr obj, unsigned flags);
-static int err_print(IOStream *io, Sxpr obj, unsigned flags);
-static int nomem_print(IOStream *io, Sxpr obj, unsigned flags);
-
-/** Type definitions. */
-static SxprType types[1024] = {
- [T_NONE] { .type= T_NONE, .name= "none", .print= none_print },
- [T_NULL] { .type= T_NULL, .name= "null", .print= null_print },
- [T_UINT] { .type= T_UINT, .name= "int", .print= int_print, },
- [T_BOOL] { .type= T_BOOL, .name= "bool", .print= bool_print, },
- [T_ERR] { .type= T_ERR, .name= "err", .print= err_print, },
- [T_NOMEM] { .type= T_ERR, .name= "nomem", .print= nomem_print, },
- [T_ATOM] { .type= T_ATOM, .name= "atom", .print= atom_print,
- .pointer= TRUE,
- .free= atom_free,
- .equal= atom_equal,
- .copy= atom_copy,
- },
- [T_STRING] { .type= T_STRING, .name= "string", .print= string_print,
- .pointer= TRUE,
- .free= string_free,
- .equal= string_equal,
- .copy= string_copy,
- },
- [T_CONS] { .type= T_CONS, .name= "cons", .print= cons_print,
- .pointer= TRUE,
- .free= cons_free,
- .equal= cons_equal,
- .copy= cons_copy,
- },
-};
-
-/** Number of entries in the types array. */
-static int type_sup = sizeof(types)/sizeof(types[0]);
-
-/** Define a type.
- * The tydef must have a non-zero type code.
- * It is an error if the type code is out of range or already defined.
- *
- * @param tydef type definition
- * @return 0 on success, error code otherwise
- */
-int def_sxpr_type(SxprType *tydef){
- int err = 0;
- int ty = tydef->type;
- if(ty < 0 || ty >= type_sup){
- err = -EINVAL;
- goto exit;
- }
- if(types[ty].type){
- err = -EEXIST;
- goto exit;
- }
- types[ty] = *tydef;
- exit:
- return err;
-
-}
-
-/** Get the type definition for a given type code.
- *
- * @param ty type code
- * @return type definition or null
- */
-SxprType *get_sxpr_type(int ty){
- if(0 <= ty && ty < type_sup){
- return types+ty;
- }
- return NULL;
-}
-
-/** The default print function.
- *
- * @param io stream to print to
- * @param x sxpr to print
- * @param flags print flags
- * @return number of bytes written on success
- */
-int default_print(IOStream *io, Sxpr x, unsigned flags){
- return IOStream_print(io, "#<%u %lu>\n", get_type(x), get_ul(x));
-}
-
-/** The default equal function.
- * Uses eq().
- *
- * @param x sxpr to compare
- * @param y sxpr to compare
- * @return 1 if equal, 0 otherwise
- */
-int default_equal(Sxpr x, Sxpr y){
- return eq(x, y);
-}
-
-/** General sxpr print function.
- * Prints an sxpr on a stream using the print function for the sxpr type.
- * Printing is controlled by flags from the PrintFlags enum.
- * If PRINT_TYPE is in the flags the sxpr type is printed before the sxpr
- * (for debugging).
- *
- * @param io stream to print to
- * @param x sxpr to print
- * @param flags print flags
- * @return number of bytes written
- */
-int objprint(IOStream *io, Sxpr x, unsigned flags){
- SxprType *def = get_sxpr_type(get_type(x));
- ObjPrintFn *print_fn = (def && def->print ? def->print : default_print);
- int k = 0;
- if(!io) return k;
- if(flags & PRINT_TYPE){
- k += IOStream_print(io, "%s:", def->name);
- }
- if(def->pointer && (flags & PRINT_ADDR)){
- k += IOStream_print(io, "<%p>", get_ptr(x));
- }
- k += print_fn(io, x, flags);
- return k;
-}
-
-Sxpr objcopy(Sxpr x){
- SxprType *def = get_sxpr_type(get_type(x));
- ObjCopyFn *copy_fn = (def ? def->copy : NULL);
- Sxpr v;
- if(copy_fn){
- v = copy_fn(x);
- } else if(def->pointer){
- v = ONOMEM;
- } else {
- v = x;
- }
- return v;
-}
-
-/** General sxpr free function.
- * Frees an sxpr using the free function for its type.
- * Free functions must recursively free any subsxprs.
- * If no function is defined then the default is to
- * free sxprs whose type has pointer true.
- * Sxprs must not be used after freeing.
- *
- * @param x sxpr to free
- */
-void objfree(Sxpr x){
- SxprType *def = get_sxpr_type(get_type(x));
-
- if(def){
- if(def->free){
- def->free(x);
- } else if (def->pointer){
- hfree(x);
- }
- }
-}
-
-/** General sxpr equality function.
- * Compares x and y using the equal function for x.
- * Uses default_equal() if x has no equal function.
- *
- * @param x sxpr to compare
- * @param y sxpr to compare
- * @return 1 if equal, 0 otherwise
- */
-int objequal(Sxpr x, Sxpr y){
- SxprType *def = get_sxpr_type(get_type(x));
- ObjEqualFn *equal_fn = (def && def->equal ? def->equal : default_equal);
- return equal_fn(x, y);
-}
-
-/** Search for a key in an alist.
- * An alist is a list of conses, where the cars
- * of the conses are the keys. Compares keys using equality.
- *
- * @param k key
- * @param l alist to search
- * @return first element of l with car k, or ONULL
- */
-Sxpr assoc(Sxpr k, Sxpr l){
- for( ; CONSP(l) ; l = CDR(l)){
- Sxpr x = CAR(l);
- if(CONSP(x) && objequal(k, CAR(x))){
- return x;
- }
- }
- return ONULL;
-}
-
-/** Search for a key in an alist.
- * An alist is a list of conses, where the cars
- * of the conses are the keys. Compares keys using eq.
- *
- * @param k key
- * @param l alist to search
- * @return first element of l with car k, or ONULL
- */
-Sxpr assocq(Sxpr k, Sxpr l){
- for( ; CONSP(l); l = CDR(l)){
- Sxpr x = CAR(l);
- if(CONSP(x) && eq(k, CAR(x))){
- return x;
- }
- }
- return ONULL;
-}
-
-/** Add a new key and value to an alist.
- *
- * @param k key
- * @param l value
- * @param l alist
- * @return l with the new cell added to the front
- */
-Sxpr acons(Sxpr k, Sxpr v, Sxpr l){
- Sxpr x, y;
- x = cons_new(k, v);
- if(NOMEMP(x)) return x;
- y = cons_new(x, l);
- if(NOMEMP(y)) cons_free_cells(x);
- return y;
-}
-
-/** Test if a list contains an element.
- * Uses sxpr equality.
- *
- * @param l list
- * @param x element to look for
- * @return a tail of l with x as car, or ONULL
- */
-Sxpr cons_member(Sxpr l, Sxpr x){
- for( ; CONSP(l) && !eq(x, CAR(l)); l = CDR(l)){}
- return l;
-}
-
-/** Test if a list contains an element satisfying a test.
- * The test function is called with v and an element of the list.
- *
- * @param l list
- * @param test_fn test function to use
- * @param v value for first argument to the test
- * @return a tail of l with car satisfying the test, or 0
- */
-Sxpr cons_member_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){
- for( ; CONSP(l) && !test_fn(v, CAR(l)); l = CDR(l)){ }
- return l;
-}
-
-/** Test if the elements of list 't' are a subset of the elements
- * of list 's'. Element order is not significant.
- *
- * @param s element list to check subset of
- * @param t element list to check if is a subset
- * @return 1 if is a subset, 0 otherwise
- */
-int cons_subset(Sxpr s, Sxpr t){
- for( ; CONSP(t); t = CDR(t)){
- if(!CONSP(cons_member(s, CAR(t)))){
- return 0;
- }
- }
- return 1;
-}
-
-/** Test if two lists have equal sets of elements.
- * Element order is not significant.
- *
- * @param s list to check
- * @param t list to check
- * @return 1 if equal, 0 otherwise
- */
-int cons_set_equal(Sxpr s, Sxpr t){
- return cons_subset(s, t) && cons_subset(t, s);
-}
-
-#ifdef USE_GC
-/*============================================================================*/
-/* The functions inside this ifdef are only safe if GC is used.
- * Otherwise they may leak memory.
- */
-
-/** Remove an element from a list (GC only).
- * Uses sxpr equality and removes all instances, even
- * if there are more than one.
- *
- * @param l list to remove elements from
- * @param x element to remove
- * @return modified input list
- */
-Sxpr cons_remove(Sxpr l, Sxpr x){
- return cons_remove_if(l, eq, x);
-}
-
-/** Remove elements satisfying a test (GC only).
- * The test function is called with v and an element of the set.
- *
- * @param l list to remove elements from
- * @param test_fn function to use to decide if an element should be removed
- * @return modified input list
- */
-Sxpr cons_remove_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){
- Sxpr prev = ONULL, elt, next;
-
- for(elt = l; CONSP(elt); elt = next){
- next = CDR(elt);
- if(test_fn(v, CAR(elt))){
- if(NULLP(prev)){
- l = next;
- } else {
- CDR(prev) = next;
- }
- }
- }
- return l;
-}
-
-/** Set the value for a key in an alist (GC only).
- * If the key is present, changes the value, otherwise
- * adds a new cell.
- *
- * @param k key
- * @param v value
- * @param l alist
- * @return modified or extended list
- */
-Sxpr setf(Sxpr k, Sxpr v, Sxpr l){
- Sxpr e = assoc(k, l);
- if(NULLP(e)){
- l = acons(k, v, l);
- } else {
- CAR(CDR(e)) = v;
- }
- return l;
-}
-/*============================================================================*/
-#endif /* USE_GC */
-
-/** Create a new atom with the given name.
- *
- * @param name the name
- * @return new atom
- */
-Sxpr atom_new(char *name){
- Sxpr n, obj = ONOMEM;
- long v;
-
- // Don't always want to do this.
- if(0 && convert_atol(name, &v) == 0){
- obj = OINT(v);
- } else {
- n = string_new(name);
- if(NOMEMP(n)) goto exit;
- obj = HALLOC(ObjAtom, T_ATOM);
- if(NOMEMP(obj)){
- string_free(n);
- goto exit;
- }
- OBJ_ATOM(obj)->name = n;
- }
- exit:
- return obj;
-}
-
-/** Free an atom.
- *
- * @param obj to free
- */
-void atom_free(Sxpr obj){
- // Interned atoms are shared, so do not free.
- if(OBJ_ATOM(obj)->interned) return;
- objfree(OBJ_ATOM(obj)->name);
- hfree(obj);
-}
-
-/** Copy an atom.
- *
- * @param obj to copy
- */
-Sxpr atom_copy(Sxpr obj){
- Sxpr v;
- if(OBJ_ATOM(obj)->interned){
- v = obj;
- } else {
- v = atom_new(atom_name(obj));
- }
- return v;
-}
-
-/** Print an atom. Prints the atom name.
- *
- * @param io stream to print to
- * @param obj to print
- * @param flags print flags
- * @return number of bytes printed
- */
-int atom_print(IOStream *io, Sxpr obj, unsigned flags){
- return objprint(io, OBJ_ATOM(obj)->name, flags);
-}
-
-/** Atom equality.
- *
- * @param x to compare
- * @param y to compare
- * @return 1 if equal, 0 otherwise
- */
-int atom_equal(Sxpr x, Sxpr y){
- int ok;
- ok = eq(x, y);
- if(ok) goto exit;
- ok = ATOMP(y) && string_equal(OBJ_ATOM(x)->name, OBJ_ATOM(y)->name);
- if(ok) goto exit;
- ok = STRINGP(y) && string_equal(OBJ_ATOM(x)->name, y);
- exit:
- return ok;
-}
-
-/** Get the name of an atom.
- *
- * @param obj atom
- * @return name
- */
-char * atom_name(Sxpr obj){
- return string_string(OBJ_ATOM(obj)->name);
-}
-
-int atom_length(Sxpr obj){
- return string_length(OBJ_ATOM(obj)->name);
-}
-
-/** Get the C string from a string sxpr.
- *
- * @param obj string sxpr
- * @return string
- */
-char * string_string(Sxpr obj){
- return OBJ_STRING(obj)->data;
-}
-
-/** Get the length of a string.
- *
- * @param obj string
- * @return length
- */
-int string_length(Sxpr obj){
- return OBJ_STRING(obj)->len;
-}
-
-/** Create a new string. The input string is copied,
- * and must be null-terminated.
- *
- * @param s characters to put in the string
- * @return new sxpr
- */
-Sxpr string_new(char *s){
- int n = (s ? strlen(s) : 0);
- return string_new_n(s, n);
-}
-
-/** Create a new string. The input string is copied,
- * and need not be null-terminated.
- *
- * @param s characters to put in the string (may be null)
- * @param n string length
- * @return new sxpr
- */
-Sxpr string_new_n(char *s, int n){
- Sxpr obj;
- obj = halloc(sizeof(ObjString) + n + 1, T_STRING);
- if(!NOMEMP(obj)){
- char *str = OBJ_STRING(obj)->data;
- OBJ_STRING(obj)->len = n;
- if(s){
- memcpy(str, s, n);
- str[n] = '\0';
- } else {
- memset(str, 0, n + 1);
- }
- }
- return obj;
-}
-
-/** Free a string.
- *
- * @param obj to free
- */
-void string_free(Sxpr obj){
- hfree(obj);
-}
-
-/** Copy a string.
- *
- * @param obj to copy
- */
-Sxpr string_copy(Sxpr obj){
- return string_new_n(string_string(obj), string_length(obj));
-}
-
-/** Determine if a string needs escapes when printed
- * using the given flags.
- *
- * @param str string to check
- * @param n string length
- * @param flags print flags
- * @return 1 if needs escapes, 0 otherwise
- */
-int needs_escapes(char *str, int n, unsigned flags){
- char *c;
- int i;
- int val = 0;
-
- if(str){
- for(i=0, c=str; i<n; i++, c++){
- if(in_alpha_class(*c)) continue;
- if(in_decimal_digit_class(*c)) continue;
- if(in_class(*c, "/._+:@~-")) continue;
- val = 1;
- break;
- }
- }
- return val;
-}
-
-char randchar(void){
- int r;
- char c;
- for( ; ; ){
- r = rand();
- c = (r >> 16) & 0xff;
- if('a' <= c && c <= 'z') break;
- }
- return c;
-}
-
-int string_contains(char *s, int s_n, char *k, int k_n){
- int i, n = s_n - k_n;
- for(i=0; i < n; i++){
- if(!memcmp(s+i, k, k_n)) return 1;
- }
- return 0;
-}
-
-int string_delim(char *s, int s_n, char *d, int d_n){
- int i;
- if(d_n < 4) return -1;
- memset(d, 0, d_n+1);
- for(i=0; i<3; i++){
- d[i] = randchar();
- }
- for( ; i < d_n; i++){
- if(!string_contains(s, s_n, d, i)){
- return i;
- }
- d[i] = randchar();
- }
- return -1;
-}
-
-/** Print the bytes in a string as-is.
- *
- * @param io stream
- * @param str string
- * @param n length
- * @return bytes written or error code
- */
-int _string_print_raw(IOStream *io, char *str, int n){
- int k = 0;
- k = IOStream_write(io, str, n);
- return k;
-}
-
-/** Print a string in counted data format.
- *
- * @param io stream
- * @param str string
- * @param n length
- * @return bytes written or error code
- */
-int _string_print_counted(IOStream *io, char *str, int n){
- int k = 0;
- k += IOStream_print(io, "%c%c%d%c",
- c_data_open, c_data_count, n, c_data_count);
- k += IOStream_write(io, str, n);
- return k;
-}
-
-/** Print a string in quoted data format.
- *
- * @param io stream
- * @param str string
- * @param n length
- * @return bytes written or error code
- */
-int _string_print_quoted(IOStream *io, char *str, int n){
- int k = 0;
- char d[10];
- int d_n;
- d_n = string_delim(str, n, d, sizeof(d) - 1);
- k += IOStream_print(io, "%c%c%s%c",
- c_data_open, c_data_quote, d, c_data_quote);
- k += IOStream_write(io, str, n);
- k += IOStream_print(io, "%c%s%c", c_data_quote, d, c_data_quote);
- return k;
-}
-
-/** Print a string as a quoted string.
- *
- * @param io stream
- * @param str string
- * @param n length
- * @return bytes written or error code
- */
-int _string_print_string(IOStream *io, char *str, int n){
- int k = 0;
-
- k += IOStream_print(io, "\"");
- if(str){
- char *s, *t;
- for(s = str, t = str + n; s < t; s++){
- if(*s < ' ' || *s >= 127 ){
- switch(*s){
- case '\a': k += IOStream_print(io, "\\a"); break;
- case '\b': k += IOStream_print(io, "\\b"); break;
- case '\f': k += IOStream_print(io, "\\f"); break;
- case '\n': k += IOStream_print(io, "\\n"); break;
- case '\r': k += IOStream_print(io, "\\r"); break;
- case '\t': k += IOStream_print(io, "\\t"); break;
- case '\v': k += IOStream_print(io, "\\v"); break;
- default:
- // Octal escape;
- k += IOStream_print(io, "\\%o", *s);
- break;
- }
- } else if(*s == c_double_quote ||
- *s == c_single_quote ||
- *s == c_escape){
- k += IOStream_print(io, "\\%c", *s);
- } else {
- k+= IOStream_print(io, "%c", *s);
- }
- }
- }
- k += IOStream_print(io, "\"");
- return k;
-}
-
-/** Print a string to a stream, with escapes if necessary.
- *
- * @param io stream to print to
- * @param str string
- * @param n string length
- * @param flags print flags
- * @return number of bytes written
- */
-int _string_print(IOStream *io, char *str, int n, unsigned flags){
- int k = 0;
- if((flags & PRINT_COUNTED)){
- k = _string_print_counted(io, str, n);
- } else if((flags & PRINT_RAW) || !needs_escapes(str, n, flags)){
- k = _string_print_raw(io, str, n);
- } else if(n > 50){
- k = _string_print_quoted(io, str, n);
- } else {
- k = _string_print_string(io, str, n);
- }
- return k;
-}
-
-/** Print a string to a stream, with escapes if necessary.
- *
- * @param io stream to print to
- * @param obj string
- * @param flags print flags
- * @return number of bytes written
- */
-int string_print(IOStream *io, Sxpr obj, unsigned flags){
- return _string_print(io,
- OBJ_STRING(obj)->data,
- OBJ_STRING(obj)->len,
- flags);
-}
-
-int string_eq(char *s, int s_n, char *t, int t_n){
- return (s_n == t_n) && (memcmp(s, t, s_n) == 0);
-}
-
-/** Compare an sxpr with a string for equality.
- *
- * @param x string to compare with
- * @param y sxpr to compare
- * @return 1 if equal, 0 otherwise
- */
-int string_equal(Sxpr x, Sxpr y){
- int ok = 0;
- ok = eq(x,y);
- if(ok) goto exit;
- ok = has_type(y, T_STRING) &&
- string_eq(OBJ_STRING(x)->data, OBJ_STRING(x)->len,
- OBJ_STRING(y)->data, OBJ_STRING(y)->len);
- if(ok) goto exit;
- ok = has_type(y, T_ATOM) &&
- string_eq(OBJ_STRING(x)->data, OBJ_STRING(x)->len,
- atom_name(y), atom_length(y));
- exit:
- return ok;
-}
-
-/** Create a new cons cell.
- * The cell is ONOMEM if either argument is.
- *
- * @param car sxpr for the car
- * @param cdr sxpr for the cdr
- * @return new cons
- */
-Sxpr cons_new(Sxpr car, Sxpr cdr){
- Sxpr obj;
- if(NOMEMP(car) || NOMEMP(cdr)){
- obj = ONOMEM;
- } else {
- obj = HALLOC(ObjCons, T_CONS);
- if(!NOMEMP(obj)){
- ObjCons *z = OBJ_CONS(obj);
- z->car = car;
- z->cdr = cdr;
- }
- }
- return obj;
-}
-
-/** Push a new element onto a list.
- *
- * @param list list to add to
- * @param elt element to add
- * @return 0 if successful, error code otherwise
- */
-int cons_push(Sxpr *list, Sxpr elt){
- Sxpr l;
- l = cons_new(elt, *list);
- if(NOMEMP(l)) return -ENOMEM;
- *list = l;
- return 0;
-}
-
-/** Free a cons. Recursively frees the car and cdr.
- *
- * @param obj to free
- */
-void cons_free(Sxpr obj){
- Sxpr next;
- for(; CONSP(obj); obj = next){
- next = CDR(obj);
- objfree(CAR(obj));
- hfree(obj);
- }
- if(!NULLP(obj)){
- objfree(obj);
- }
-}
-
-/** Copy a cons. Recursively copies the car and cdr.
- *
- * @param obj to copy
- */
-Sxpr cons_copy(Sxpr obj){
- Sxpr v = ONULL;
- Sxpr l = ONULL, x = ONONE;
- for(l = obj; CONSP(l); l = CDR(l)){
- x = objcopy(CAR(l));
- if(NOMEMP(x)) goto exit;
- x = cons_new(x, v);
- if(NOMEMP(x)) goto exit;
- v = x;
- }
- v = nrev(v);
- exit:
- if(NOMEMP(x)){
- objfree(v);
- v = ONOMEM;
- }
- return v;
-}
-
-/** Free a cons and its cdr cells, but not the car sxprs.
- * Does nothing if called on something that is not a cons.
- *
- * @param obj to free
- */
-void cons_free_cells(Sxpr obj){
- Sxpr next;
- for(; CONSP(obj); obj = next){
- next = CDR(obj);
- hfree(obj);
- }
-}
-
-/** Print a cons.
- * Prints the cons in list format if the cdrs are conses.
- * uses pair (dot) format if the last cdr is not a cons (or null).
- *
- * @param io stream to print to
- * @param obj to print
- * @param flags print flags
- * @return number of bytes written
- */
-int cons_print(IOStream *io, Sxpr obj, unsigned flags){
- int first = 1;
- int k = 0;
- k += IOStream_print(io, "(");
- for( ; CONSP(obj) ; obj = CDR(obj)){
- if(first){
- first = 0;
- } else {
- k += IOStream_print(io, " ");
- }
- k += objprint(io, CAR(obj), flags);
- }
- if(!NULLP(obj)){
- k += IOStream_print(io, " . ");
- k += objprint(io, obj, flags);
- }
- k += IOStream_print(io, ")");
- return (IOStream_error(io) ? -1 : k);
-}
-
-/** Compare a cons with another sxpr for equality.
- * If y is a cons, compares the cars and cdrs recursively.
- *
- * @param x cons to compare
- * @param y sxpr to compare
- * @return 1 if equal, 0 otherwise
- */
-int cons_equal(Sxpr x, Sxpr y){
- return CONSP(y) &&
- objequal(CAR(x), CAR(y)) &&
- objequal(CDR(x), CDR(y));
-}
-
-/** Return the length of a cons list.
- *
- * @param obj list
- * @return length
- */
-int cons_length(Sxpr obj){
- int count = 0;
- for( ; CONSP(obj); obj = CDR(obj)){
- count++;
- }
- return count;
-}
-
-/** Destructively reverse a cons list in-place.
- * If the argument is not a cons it is returned unchanged.
- *
- * @param l to reverse
- * @return reversed list
- */
-Sxpr nrev(Sxpr l){
- if(CONSP(l)){
- // Iterate down the cells in the list making the cdr of
- // each cell point to the previous cell. The last cell
- // is the head of the reversed list.
- Sxpr prev = ONULL;
- Sxpr cell = l;
- Sxpr next;
-
- while(1){
- next = CDR(cell);
- CDR(cell) = prev;
- if(!CONSP(next)) break;
- prev = cell;
- cell = next;
- }
- l = cell;
- }
- return l;
-}
-
-/** Print the null sxpr.
- *
- * @param io stream to print to
- * @param obj to print
- * @param flags print flags
- * @return number of bytes written
- */
-static int null_print(IOStream *io, Sxpr obj, unsigned flags){
- return IOStream_print(io, "()");
-}
-
-/** Print the `unspecified' sxpr none.
- *
- * @param io stream to print to
- * @param obj to print
- * @param flags print flags
- * @return number of bytes written
- */
-static int none_print(IOStream *io, Sxpr obj, unsigned flags){
- return IOStream_print(io, "<none>");
-}
-
-/** Print an integer.
- *
- * @param io stream to print to
- * @param obj to print
- * @param flags print flags
- * @return number of bytes written
- */
-static int int_print(IOStream *io, Sxpr obj, unsigned flags){
- return IOStream_print(io, "%d", OBJ_INT(obj));
-}
-
-/** Print a boolean.
- *
- * @param io stream to print to
- * @param obj to print
- * @param flags print flags
- * @return number of bytes written
- */
-static int bool_print(IOStream *io, Sxpr obj, unsigned flags){
- return IOStream_print(io, (OBJ_UINT(obj) ? k_true : k_false));
-}
-
-/** Print an error.
- *
- * @param io stream to print to
- * @param obj to print
- * @param flags print flags
- * @return number of bytes written
- */
-static int err_print(IOStream *io, Sxpr obj, unsigned flags){
- int err = OBJ_INT(obj);
- if(err < 0) err = -err;
- return IOStream_print(io, "[error:%d:%s]", err, strerror(err));
-}
-
-/** Print the 'nomem' sxpr.
- *
- * @param io stream to print to
- * @param obj to print
- * @param flags print flags
- * @return number of bytes written
- */
-static int nomem_print(IOStream *io, Sxpr obj, unsigned flags){
- return IOStream_print(io, "[ENOMEM]");
-}
-
-int sxprp(Sxpr obj, Sxpr name){
- return CONSP(obj) && objequal(CAR(obj), name);
-}
-
-/** Get the name of an element.
- *
- * @param obj element
- * @return name
- */
-Sxpr sxpr_name(Sxpr obj){
- Sxpr val = ONONE;
- if(CONSP(obj)){
- val = CAR(obj);
- } else if(STRINGP(obj) || ATOMP(obj)){
- val = obj;
- }
- return val;
-}
-
-int sxpr_is(Sxpr obj, char *s){
- if(ATOMP(obj)) return string_eq(atom_name(obj), atom_length(obj), s, strlen(s));
- if(STRINGP(obj)) return string_eq(string_string(obj), string_length(obj), s, strlen(s));
- return 0;
-}
-
-int sxpr_elementp(Sxpr obj, Sxpr name){
- int ok = 0;
- ok = CONSP(obj) && objequal(CAR(obj), name);
- return ok;
-}
-
-/** Get the attributes of an sxpr.
- *
- * @param obj sxpr
- * @return attributes
- */
-Sxpr sxpr_attributes(Sxpr obj){
- Sxpr val = ONULL;
- if(CONSP(obj)){
- obj = CDR(obj);
- if(CONSP(obj)){
- obj = CAR(obj);
- if(sxprp(obj, intern("@"))){
- val = CDR(obj);
- }
- }
- }
- return val;
-}
-
-Sxpr sxpr_attribute(Sxpr obj, Sxpr key, Sxpr def){
- Sxpr val = ONONE;
- val = assoc(sxpr_attributes(obj), key);
- if(CONSP(val) && CONSP(CDR(val))){
- val = CADR(def);
- } else {
- val = def;
- }
- return val;
-}
-
-/** Get the children of an sxpr.
- *
- * @param obj sxpr
- * @return children
- */
-Sxpr sxpr_children(Sxpr obj){
- Sxpr val = ONULL;
- if(CONSP(obj)){
- val = CDR(obj);
- if(CONSP(val) && sxprp(CAR(val), intern("@"))){
- val = CDR(val);
- }
- }
- return val;
-}
-
-Sxpr sxpr_child(Sxpr obj, Sxpr name, Sxpr def){
- Sxpr val = ONONE;
- Sxpr l;
- for(l = sxpr_children(obj); CONSP(l); l = CDR(l)){
- if(sxprp(CAR(l), name)){
- val = CAR(l);
- break;
- }
- }
- if(NONEP(val)) val = def;
- return val;
-}
-
-Sxpr sxpr_child0(Sxpr obj, Sxpr def){
- Sxpr val = ONONE;
- Sxpr l = sxpr_children(obj);
- if(CONSP(l)){
- val = CAR(l);
- } else {
- val = def;
- }
- return val;
-}
-
-Sxpr sxpr_childN(Sxpr obj, int n, Sxpr def){
- Sxpr val = def;
- Sxpr l;
- int i;
- for (i = 0, l = sxpr_children(obj); CONSP(l); i++, l = CDR(l)){
- if(i == n){
- val = CAR(l);
- break;
- }
- }
- return val;
-}
-
-Sxpr sxpr_child_value(Sxpr obj, Sxpr name, Sxpr def){
- Sxpr val = ONONE;
- val = sxpr_child(obj, name, ONONE);
- if(NONEP(val)){
- val = def;
- } else {
- val = sxpr_child0(val, def);
- }
- return val;
-}
-
-/** Table of interned symbols. Indexed by symbol name. */
-static HashTable *symbols = NULL;
-
-/** Hash function for entries in the symbol table.
- *
- * @param key to hash
- * @return hashcode
- */
-static Hashcode sym_hash_fn(void *key){
- return hash_string((char*)key);
-}
-
-/** Key equality function for the symbol table.
- *
- * @param x to compare
- * @param y to compare
- * @return 1 if equal, 0 otherwise
- */
-static int sym_equal_fn(void *x, void *y){
- return !strcmp((char*)x, (char*)y);
-}
-
-/** Entry free function for the symbol table.
- *
- * @param table the entry is in
- * @param entry being freed
- */
-static void sym_free_fn(HashTable *table, HTEntry *entry){
- if(entry){
- objfree(((ObjAtom*)entry->value)->name);
- HTEntry_free(entry);
- }
-}
-
-/** Initialize the symbol table.
- *
- * @return 0 on sucess, error code otherwise
- */
-static int init_symbols(void){
- symbols = HashTable_new(100);
- if(symbols){
- symbols->key_hash_fn = sym_hash_fn;
- symbols->key_equal_fn = sym_equal_fn;
- symbols->entry_free_fn = sym_free_fn;
- return 0;
- }
- return -1;
-}
-
-/** Cleanup the symbol table. Frees the table and all its symbols.
- */
-void cleanup_symbols(void){
- HashTable_free(symbols);
- symbols = NULL;
-}
-
-/** Get the interned symbol with the given name.
- * No new symbol is created.
- *
- * @return symbol or null
- */
-Sxpr get_symbol(char *sym){
- HTEntry *entry;
- if(!symbols){
- if(init_symbols()) return ONOMEM;
- return ONULL;
- }
- entry = HashTable_get_entry(symbols, sym);
- if(entry){
- return OBJP(T_ATOM, entry->value);
- } else {
- return ONULL;
- }
-}
-
-/** Get the interned symbol with the given name.
- * Creates a new symbol if necessary.
- *
- * @return symbol
- */
-Sxpr intern(char *sym){
- Sxpr symbol = get_symbol(sym);
- if(NULLP(symbol)){
- if(!symbols) return ONOMEM;
- symbol = atom_new(sym);
- if(!NOMEMP(symbol)){
- OBJ_ATOM(symbol)->interned = TRUE;
- HashTable_add(symbols, atom_name(symbol), get_ptr(symbol));
- }
- }
- return symbol;
-}
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef _XUTIL_SXPR_H_
-#define _XUTIL_SXPR_H_
-
-#ifdef __KERNEL__
-#include <linux/config.h>
-#include <linux/types.h>
-#else
-#include <stdint.h>
-#endif
-
-#include "hash_table.h"
-#include "iostream.h"
-#include "allocate.h"
-
-/** @file
- * Definitions for rules and sxprs.
- */
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-#ifndef TRUE
-#define TRUE 1
-#endif
-
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-/** Sxpr type. */
-typedef int16_t TypeCode;
-
-/** A typed sxpr handle.*/
-typedef struct Sxpr {
- /** Sxpr type. */
- TypeCode type;
- union {
- /** Sxpr value. */
- unsigned long ul;
- /** Pointer. */
- void *ptr;
- } v;
-} Sxpr;
-
-/** Get the integer value from an sxpr.
- *
- * @param obj sxpr
- * @return value
- */
-static inline unsigned long get_ul(Sxpr obj){
- return obj.v.ul;
-}
-
-/** Get the pointer value from an sxpr.
- *
- * @param obj sxpr
- * @return value
- */
-static inline void * get_ptr(Sxpr obj){
- return obj.v.ptr;
-}
-
-/** Create an sxpr containing a pointer.
- *
- * @param ty typecode
- * @param val pointer
- * @return sxpr
- */
-static inline Sxpr obj_ptr(TypeCode ty, void *val){
- return (Sxpr){ .type= ty, .v= { .ptr= val } };
-}
-
-/** Create an sxpr containing an integer.
- *
- * @param ty typecode
- * @param val integer
- * @return sxpr
- */
-static inline Sxpr obj_ul(TypeCode ty, unsigned long val){
- return (Sxpr){ .type= ty, .v= { .ul= val } };
-}
-
-/** Get the type of an sxpr.
- *
- * @param obj sxpr
- * @return type
- */
-static inline TypeCode get_type(Sxpr obj){
- return obj.type;
-}
-
-/** Check the type of an sxpr.
- *
- * @param obj sxpr
- * @param type to check
- * @return 1 if has the type, 0 otherwise
- */
-static inline int has_type(Sxpr obj, TypeCode type){
- return get_type(obj) == type;
-}
-
-/** Compare sxprs for literal equality of type and value.
- *
- * @param x sxpr to compare
- * @param y sxpr to compare
- * @return 1 if equal, 0 otherwise
- */
-static inline int eq(Sxpr x, Sxpr y){
- return ((get_type(x) == get_type(y)) && (get_ul(x) == get_ul(y)));
-}
-
-/** The 'unspecified' sxpr. */
-#define T_NONE ((TypeCode)0)
-/** The empty list. */
-#define T_NULL ((TypeCode)1)
-/** Unsigned integer. */
-#define T_UINT ((TypeCode)2)
-/** A string. */
-#define T_STRING ((TypeCode)3)
-/** An atom. */
-#define T_ATOM ((TypeCode)4)
-/** A boolean. */
-#define T_BOOL ((TypeCode)5)
-
-/** A cons (pair or list). */
-#define T_CONS ((TypeCode)10)
-
-/** An error. */
-#define T_ERR ((TypeCode)40)
-/** Sxpr type to indicate out of memory. */
-#define T_NOMEM ((TypeCode)41)
-
-typedef struct ObjString {
- int len;
- char data[0];
-} ObjString;
-
-/** An atom. */
-typedef struct ObjAtom {
- Sxpr name;
- Hashcode hashcode;
- int interned;
-} ObjAtom;
-
-/** A cons (pair). */
-typedef struct ObjCons {
- Sxpr car;
- Sxpr cdr;
-} ObjCons;
-
-/** Flags for sxpr printing. */
-enum PrintFlags {
- PRINT_RAW = 0x001,
- PRINT_TYPE = 0x002,
- PRINT_PRETTY = 0x004,
- PRINT_COUNTED = 0x008,
- PRINT_ADDR = 0x010,
-};
-
-extern int _string_print(IOStream *io, char *str, int n, unsigned flags);
-extern int _string_print_raw(IOStream *io, char *str, int n);
-extern int _string_print_counted(IOStream *io, char *str, int n);
-extern int _string_print_quoted(IOStream *io, char *str, int n);
-extern int _string_print_string(IOStream *io, char *str, int n);
-
-/** An integer sxpr.
- *
- * @param ty type
- * @param val integer value
- */
-#define OBJI(ty, val) obj_ul(ty, val)
-
-/** Make an integer sxpr.
- * @param x value
- */
-#define OINT(x) OBJI(T_UINT, x)
-
-/** Make an error sxpr.
- *
- * @param x value
- */
-#define OERR(x) OBJI(T_ERR, x)
-
-/** Out of memory constant. */
-#define ONOMEM OBJI(T_NOMEM, 0)
-
-/** The `unspecified' constant. */
-#define ONONE OBJI(T_NONE, 0)
-
-/** Empty list constant. */
-#define ONULL OBJI(T_NULL, 0)
-
-/** False constant. */
-#define OFALSE OBJI(T_BOOL, 0)
-
-/** True constant. */
-#define OTRUE OBJI(T_BOOL, 1)
-
-/** A pointer sxpr.
- * If the pointer is non-null, returns an sxpr containing it.
- * If the pointer is null, returns ONOMEM.
- *
- * @param ty type
- * @param val pointer
- */
-static inline Sxpr OBJP(int ty, void *val){
- return (val ? obj_ptr(ty, val) : ONOMEM);
-}
-
-/** Make an integer sxpr containing a pointer.
- *
- * @param val pointer
- */
-static inline Sxpr PTR(void *val){
- return OBJP(T_UINT, (void*)(val));
-}
-
-/** Allocate some memory and return an sxpr containing it.
- * Returns ONOMEM if allocation failed.
- *
- * @param n number of bytes to allocate
- * @param ty typecode
- * @return sxpr
- */
-static inline Sxpr halloc(int n, int ty){
- return OBJP(ty, allocate(n));
-}
-
-/** Allocate an sxpr containing a pointer to the given type.
- *
- * @param _ctype type (uses sizeof to determine how many bytes to allocate)
- * @param _tycode typecode
- * @return sxpr, ONOMEM if allocation failed
- */
-#define HALLOC(_ctype, _tycode) halloc(sizeof(_ctype), _tycode)
-
-/* Recognizers for the various sxpr types. */
-#define ATOMP(obj) has_type(obj, T_ATOM)
-#define BOOLP(obj) has_type(obj, T_BOOL)
-#define CONSP(obj) has_type(obj, T_CONS)
-#define ERRP(obj) has_type(obj, T_ERR)
-#define INTP(obj) has_type(obj, T_UINT)
-#define NOMEMP(obj) has_type(obj, T_NOMEM)
-#define NONEP(obj) has_type(obj, T_NONE)
-#define NULLP(obj) has_type(obj, T_NULL)
-#define STRINGP(obj) has_type(obj, T_STRING)
-
-#define TRUEP(obj) get_ul(obj)
-
-/** Convert an sxpr to an unsigned integer. */
-#define OBJ_UINT(x) get_ul(x)
-/** Convert an sxpr to an integer. */
-#define OBJ_INT(x) (int)get_ul(x)
-
-/* Conversions of sxprs to their values.
- * No checking is done.
- */
-#define OBJ_STRING(x) ((ObjString*)get_ptr(x))
-#define OBJ_CONS(x) ((ObjCons*)get_ptr(x))
-#define OBJ_ATOM(x) ((ObjAtom*)get_ptr(x))
-#define OBJ_SET(x) ((ObjSet*)get_ptr(x))
-#define CAR(x) (OBJ_CONS(x)->car)
-#define CDR(x) (OBJ_CONS(x)->cdr)
-
-#define CAAR(x) (CAR(CAR(x)))
-#define CADR(x) (CAR(CDR(x)))
-#define CDAR(x) (CDR(CAR(x)))
-#define CDDR(x) (CDR(CDR(x)))
-
-/** Checked version of CAR
- *
- * @param x sxpr
- * @return CAR if a cons, x otherwise
- */
-static inline Sxpr car(Sxpr x){
- return (CONSP(x) ? CAR(x) : x);
-}
-
-/** Checked version of CDR.
- *
- * @param x sxpr
- * @return CDR if a cons, null otherwise
- */
-static inline Sxpr cdr(Sxpr x){
- return (CONSP(x) ? CDR(x) : ONULL);
-}
-
-typedef int ObjPrintFn(IOStream *io, Sxpr obj, unsigned flags);
-typedef int ObjEqualFn(Sxpr obj, Sxpr other);
-typedef void ObjFreeFn(Sxpr obj);
-typedef Sxpr ObjCopyFn(Sxpr obj);
-
-/** An sxpr type definition. */
-typedef struct SxprType {
- TypeCode type;
- char *name;
- int pointer;
- ObjPrintFn *print;
- ObjEqualFn *equal;
- ObjFreeFn *free;
- ObjCopyFn *copy;
-} SxprType;
-
-extern int def_sxpr_type(SxprType *tydef);
-extern SxprType *get_sxpr_type(int ty);
-
-/** Free the pointer in an sxpr.
- *
- * @param x sxpr containing a pointer
- */
-static inline void hfree(Sxpr x){
- deallocate(get_ptr(x));
-}
-
-extern int objprint(IOStream *io, Sxpr x, unsigned flags);
-extern int objequal(Sxpr x, Sxpr y);
-extern void objfree(Sxpr x);
-extern Sxpr objcopy(Sxpr x);
-
-extern void cons_free_cells(Sxpr obj);
-extern Sxpr intern(char *s);
-
-extern Sxpr assoc(Sxpr k, Sxpr l);
-extern Sxpr assocq(Sxpr k, Sxpr l);
-extern Sxpr acons(Sxpr k, Sxpr v, Sxpr l);
-extern Sxpr nrev(Sxpr l);
-extern Sxpr cons_member(Sxpr l, Sxpr x);
-extern Sxpr cons_member_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v);
-extern int cons_subset(Sxpr s, Sxpr t);
-extern int cons_set_equal(Sxpr s, Sxpr t);
-
-#ifdef USE_GC
-extern Sxpr cons_remove(Sxpr l, Sxpr x);
-extern Sxpr cons_remove_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v);
-#endif
-
-extern Sxpr atom_new(char *name);
-extern char * atom_name(Sxpr obj);
-extern int atom_length(Sxpr obj);
-
-extern Sxpr string_new(char *s);
-extern Sxpr string_new_n(char *s, int n);
-extern char * string_string(Sxpr obj);
-extern int string_length(Sxpr obj);
-
-extern Sxpr cons_new(Sxpr car, Sxpr cdr);
-extern int cons_push(Sxpr *list, Sxpr elt);
-extern int cons_length(Sxpr obj);
-
-Sxpr sxpr_name(Sxpr obj);
-int sxpr_is(Sxpr obj, char *s);
-int sxpr_elementp(Sxpr obj, Sxpr name);
-Sxpr sxpr_attributes(Sxpr obj);
-Sxpr sxpr_attribute(Sxpr obj, Sxpr key, Sxpr def);
-Sxpr sxpr_children(Sxpr obj);
-Sxpr sxpr_child(Sxpr obj, Sxpr name, Sxpr def);
-Sxpr sxpr_childN(Sxpr obj, int n, Sxpr def);
-Sxpr sxpr_child0(Sxpr obj, Sxpr def);
-Sxpr sxpr_child_value(Sxpr obj, Sxpr name, Sxpr def);
-
-/** Create a new atom.
- *
- * @param s atom name
- * @return new atom
- */
-static inline Sxpr mkatom(char *s){
- return atom_new(s);
-}
-
-/** Create a new string sxpr.
- *
- * @param s string bytes (copied)
- * @return new string
- */
-static inline Sxpr mkstring(char *s){
- return string_new(s);
-}
-
-/** Create an integer sxpr.
- *
- * @param i value
- * @return sxpr
- */
-static inline Sxpr mkint(int i){
- return OBJI(T_UINT, i);
-}
-
-/** Create a boolean sxpr.
- *
- * @param b value
- * @return sxpr
- */
-static inline Sxpr mkbool(int b){
- return OBJI(T_BOOL, (b ? 1 : 0));
-}
-
-/* Constants used in parsing and printing. */
-#define k_list_open "("
-#define c_list_open '('
-#define k_list_close ")"
-#define c_list_close ')'
-#define k_true "true"
-#define k_false "false"
-
-#define c_escape '\\'
-#define c_single_quote '\''
-#define c_double_quote '"'
-#define c_string_open c_double_quote
-#define c_string_close c_double_quote
-
-#define c_data_open '<'
-#define c_data_quote '<'
-#define c_data_count '*'
-//#define c_data_open '['
-//#define c_data_close ']'
-//#define c_binary '*'
-
-#define c_var '$'
-#define c_eval '!'
-#define c_concat_open '{'
-#define c_concat_close '}'
-
-#endif /* ! _XUTIL_SXPR_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2005 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef __KERNEL__
-# include <linux/config.h>
-# include <linux/module.h>
-# include <linux/kernel.h>
-# include <linux/string.h>
-# include <linux/errno.h>
-#else
-# include <stdlib.h>
-# include <errno.h>
-#endif
-
-#include "sys_net.h"
-
-#include "iostream.h"
-#include "lexis.h"
-#include "sxpr_parser.h"
-#include "sys_string.h"
-#include "enum.h"
-
-/** @file
- * Sxpr parsing.
- *
- * So that the parser does not leak memory, all sxprs constructed by
- * the parser must be freed on error. On successful parse the sxpr
- * returned becomes the responsibility of the caller.
- *
- * @author Mike Wray <mike.wray@hpl.hp.com>
- */
-
-#ifdef DEBUG
-#define dprintf(fmt, args...) IOStream_print(iostdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args)
-#else
-#define dprintf(fmt, args...) do{ }while(0)
-#endif
-
-#undef printf
-#define printf(fmt, args...) IOStream_print(iostdout, fmt, ##args)
-
-static int state_start(Parser *p, char c);
-static int begin_start(Parser *p, char c);
-
-#if 0
-/** Print a parse error.
- *
- * @param in parser
- * @param msg format followed by printf arguments
- */
-static void eprintf(Parser *in, char *msg, ...){
- va_list args;
- if(in->error_out){
- va_start(args, msg);
- IOStream_vprint(in->error_out, msg, args);
- va_end(args);
- }
-}
-
-/** Print a parse warning.
- *
- * @param in parser
- * @param msg format followed by printf arguments
- */
-static void wprintf(Parser *in, char *msg, ...){
- va_list args;
- if(in->error_out){
- va_start(args, msg);
- IOStream_vprint(in->error_out, msg, args);
- va_end(args);
- }
-}
-#endif
-
-
-/*============================================================================*/
-
-/** Record defining the message for a parse error. */
-typedef struct {
- ParseErrorId id;
- char *message;
-} ParseError;
-
-/** Format for printing parse error messages. */
-#define PARSE_ERR_FMT "parse error> line %3d, column %2d: %s"
-
-/** Message catalog for the parse error codes. */
-static ParseError catalog[] = {
- { PARSE_ERR_UNSPECIFIED, "unspecified error" },
- { PARSE_ERR_NOMEM, "out of memory" },
- { PARSE_ERR_UNEXPECTED_EOF, "unexpected end of input" },
- { PARSE_ERR_TOKEN_TOO_LONG, "token too long" },
- { PARSE_ERR_INVALID_SYNTAX, "syntax error" },
- { PARSE_ERR_INVALID_ESCAPE, "invalid escape" },
- { 0, NULL }
-};
-
-/** Number of entries in the message catalog. */
-const static int catalog_n = sizeof(catalog)/sizeof(ParseError);
-
-/** Set the parser error stream.
- * Parse errors are reported on the the error stream if it is non-null.
- *
- * @param z parser
- * @param error_out error stream
- */
-void Parser_set_error_stream(Parser *z, IOStream *error_out){
- z->error_out = error_out;
-}
-
-/** Get the parser error message for an error code.
- *
- * @param id error code
- * @return error message (empty string if the code is unknown)
- */
-static char *get_message(ParseErrorId id){
- int i;
- for(i = 0; i < catalog_n; i++){
- if(id == catalog[i].id){
- return catalog[i].message;
- }
- }
- return "";
-}
-
-#if 0
-/** Get the line number.
- *
- * @param in parser
- */
-static int get_line(Parser *in){
- return in->line_no;
-}
-
-/** Get the column number.
- *
- * @param in parser
- */
-static int get_column(Parser *in){
- return in->char_no;
-}
-#endif
-
-/** Get the line number the current token started on.
- *
- * @param in parser
- */
-static int get_tok_line(Parser *in){
- return in->tok_begin_line;
-}
-
-/** Get the column number the current token started on.
- *
- * @param in parser
- */
-static int get_tok_column(Parser *in){
- return in->tok_begin_char;
-}
-
-/** Return the current token.
- * The return value points at the internal buffer, so
- * it must not be modified (or freed). Use copy_token() if you need a copy.
- *
- * @param p parser
- * @return token
- */
-char *peek_token(Parser *p){
- return p->tok;
-}
-
-int token_len(Parser *p){
- return p->tok_end - p->tok;
-}
-
-/** Return a copy of the current token.
- * The returned value should be freed when finished with.
- *
- * @param p parser
- * @return copy of token
- */
-char *copy_token(Parser *p){
- int n = token_len(p);
- char *buf = allocate(n + 1);
- if(buf){
- memcpy(buf, peek_token(p), n);
- buf[n] = '\0';
- }
- return buf;
-}
-
-void new_token(Parser *p){
- memset(p->buf, 0, p->buf_end - p->buf);
- p->tok = p->buf;
- p->tok_end = p->tok;
- p->tok_begin_line = p->line_no;
- p->tok_begin_char = p->char_no;
-}
-
-/** Report a parse error.
- * Does nothing if the error stream is null or there is no error.
- *
- * @param in parser
- */
-static void report_error(Parser *in){
- if(in->error_out && in->err){
- char *msg = get_message(in->err);
- char *tok = peek_token(in);
- IOStream_print(in->error_out, PARSE_ERR_FMT,
- get_tok_line(in), get_tok_column(in), msg);
- if(tok && tok[0]){
- IOStream_print(in->error_out, " '%s'", tok);
- }
- IOStream_print(in->error_out, "\n");
- }
-}
-
-/** Get the error message for the current parse error code.
- * Does nothing if there is no error.
- *
- * @param in parser
- * @param buf where to place the message
- * @param n maximum number of characters to place in buf
- * @return current error code (zero for no error)
- */
-int Parser_error_message(Parser *in, char *buf, int n){
- if(in->err){
- char *msg = get_message(in->err);
- snprintf(buf, n, PARSE_ERR_FMT, get_tok_line(in),
- get_tok_column(in), msg);
- }
- return in->err;
-}
-
-/** Flag a parse error. All subsequent reads will fail.
- * Does not change the parser error code if it is already set.
- *
- * @param in parser
- * @param id error code
- */
-int Parser_error_id(Parser *in, ParseErrorId id){
- if(!in->err){
- in->err = id;
- report_error(in);
- }
- return -EINVAL;
-}
-
-/** Flag an unspecified parse error.
- *
- * @param in parser
- */
-int Parser_error(Parser *in){
- return Parser_error_id(in, PARSE_ERR_INVALID_SYNTAX);
-}
-
-/** Test if the parser's error flag is set.
- *
- * @param in parser
- * @return 1 if set, 0 otherwise
- */
-int Parser_has_error(Parser *in){
- return (in->err > 0);
-}
-
-/** Test if the parser is at end of input.
- *
- * @param in parser
- * @return 1 if at EOF, 0 otherwise
- */
-int Parser_at_eof(Parser *p){
- return p->eof;
-}
-
-void ParserState_free(ParserState *z){
- if(!z) return;
- objfree(z->val);
- deallocate(z);
-}
-
-int ParserState_new(ParserStateFn *fn, char *name,
- ParserState *parent, ParserState **val){
- int err = -ENOMEM;
- ParserState *z;
- z = ALLOCATE(ParserState);
- if(!z) goto exit;
- z->name = name;
- z->fn = fn;
- z->parent = parent;
- z->val = ONULL;
- err = 0;
- exit:
- *val = (err ? NULL : z);
- return err;
-}
-
-void Parser_pop(Parser *p){
- ParserState *s = p->state;
- if(!s) return;
- dprintf("Parser_pop> %s\n", s->name);
- p->state = s->parent;
- if (p->start_state == s) {
- p->start_state = NULL;
- }
- ParserState_free(s);
-}
-
-/** Free a parser.
- * No-op if the parser is null.
- *
- * @param z parser
- */
-void Parser_free(Parser *z){
- if(!z) return;
- // Hmmm. Need to free states, but careful about double free of values.
- while(z->state){
- objfree(z->state->val);
- Parser_pop(z);
- }
- if(z->buf) deallocate(z->buf);
- objfree(z->val);
- z->val = ONONE;
- deallocate(z);
-}
-
-int Parser_push(Parser *p, ParserStateFn *fn, char *name){
- dprintf("Parser_push> %s\n", name);
- return ParserState_new(fn, name, p->state, &p->state);
-}
-
-int Parser_return(Parser *p){
- int err = 0;
- Sxpr val = ONONE;
- if(!p->state){
- err = -EINVAL;
- goto exit;
- }
- val = p->state->val;
- p->state->val = ONONE;
- Parser_pop(p);
- if(p->state){
- err = cons_push(&p->state->val, val);
- } else {
- val = nrev(val);
- p->val = val;
- }
- exit:
- if(err){
- objfree(val);
- }
- return err;
-}
-
-/** Reset the fields of a parser to initial values.
- *
- * @param z parser
- */
-static void reset(Parser *z){
- // leave flags
- // leave error_out
- while(z->state){
- Parser_pop(z);
- }
- z->val = ONONE;
- z->eof = 0;
- z->err = 0;
- z->line_no = 1;
- z->char_no = 0;
- memset(z->buf, 0, z->buf_end - z->buf);
- z->tok = z->buf;
- z->tok_end = z->tok;
- z->tok_begin_line = 0;
- z->tok_begin_char = 0;
- z->start_state = NULL;
-}
-
-/** Create a new parser. The error stream defaults to null.
- */
-Parser * Parser_new(void){
- Parser *z = ALLOCATE(Parser);
- int n = PARSER_BUF_SIZE;
- int err = -ENOMEM;
-
- if(!z) goto exit;
- z->buf = allocate(n);
- if(!z->buf) goto exit;
- err = 0;
- z->buf_end = z->buf + n;
- z->begin = begin_start;
- reset(z);
- exit:
- if(err){
- Parser_free(z);
- z = NULL;
- }
- return z;
-}
-
-/** Get the next character.
- * Records the character read in the parser,
- * and sets the line and character counts.
- *
- * @param p parser
- * @return error flag: 0 on success, non-zero on error
- */
-static int input_char(Parser *p, char c){
- int err = 0;
- if(c=='\n'){
- p->line_no++;
- p->char_no = 0;
- } else {
- p->char_no++;
- }
- return err;
-}
-
-int save_char(Parser *p, char c){
- int err = 0;
- if(p->tok_end >= p->buf_end){
- int buf_n = (p->buf_end - p->buf) + PARSER_BUF_INCREMENT;
- char *buf = allocate(buf_n);
- if(!buf){
- err = -ENOMEM;
- goto exit;
- }
- memcpy(buf, p->buf, p->tok_end - p->buf);
- p->buf_end = buf + buf_n;
- p->tok = buf + (p->tok - p->buf);
- p->tok_end = buf + (p->tok_end - p->buf);
- deallocate(p->buf);
- p->buf = buf;
- }
- *p->tok_end++ = c;
- exit:
- return err;
-}
-
-/** Determine if a character is a separator.
- *
- * @param p parser
- * @param c character to test
- * @return 1 if a separator, 0 otherwise
- */
-static int is_separator(Parser *p, char c){
- return in_sep_class(c);
-}
-
-int Parser_set_value(Parser *p, Sxpr obj){
- int err = 0;
- if(NOMEMP(obj)){
- err = -ENOMEM;
- } else {
- p->state->val = obj;
- }
- return err;
-}
-
-int Parser_intern(Parser *p){
- Sxpr obj = intern(peek_token(p));
- return Parser_set_value(p, obj);
-}
-
-int Parser_atom(Parser *p){
- Sxpr obj;
- long v;
- if(Parser_flags(p, PARSE_INT) &&
- convert_atol(peek_token(p), &v) == 0){
- obj = OINT(v);
- } else {
- obj = atom_new(peek_token(p));
- }
- return Parser_set_value(p, obj);
-}
-
-int Parser_string(Parser *p){
- Sxpr obj = string_new_n(peek_token(p), token_len(p));
- return Parser_set_value(p, obj);
-}
-
-int Parser_data(Parser *p){
- Sxpr obj = string_new_n(peek_token(p), token_len(p));
- return Parser_set_value(p, obj);
-}
-
-int Parser_uint(Parser *p){
- unsigned int x = htonl(*(unsigned int *)peek_token(p));
- return Parser_set_value(p, OINT(x));
-}
-
-static int get_escape(char c, char *d){
- int err = 0;
- switch(c){
- case 'a': *d = '\a'; break;
- case 'b': *d = '\b'; break;
- case 'f': *d = '\f'; break;
- case 'n': *d = '\n'; break;
- case 'r': *d = '\r'; break;
- case 't': *d = '\t'; break;
- case 'v': *d = '\v'; break;
- case c_escape: *d = c_escape; break;
- case c_single_quote: *d = c_single_quote; break;
- case c_double_quote: *d = c_double_quote; break;
- default:
- err = -EINVAL;
- }
- return err;
-}
-
-int Parser_ready(Parser *p){
- return CONSP(p->val) || (p->start_state && CONSP(p->start_state->val));
-}
-
-Sxpr Parser_get_val(Parser *p){
- Sxpr v = ONONE, w = ONONE;
- if(CONSP(p->val)){
- } else if (p->start_state && CONSP(p->start_state->val)){
- p->val = p->start_state->val;
- p->val = nrev(p->val);
- p->start_state->val = ONULL;
- } else {
- goto exit;
- }
- w = p->val;
- v = CAR(w);
- p->val = CDR(w);
- hfree(w);
- exit:
- return v;
-}
-
-Sxpr Parser_get_all(Parser *p){
- Sxpr v = ONULL;
- if(CONSP(p->val)){
- v = p->val;
- p->val = ONONE;
- } else if(p->start_state && CONSP(p->start_state->val)){
- v = p->start_state->val;
- p->start_state->val = ONULL;
- v = nrev(v);
- }
- return v;
-}
-
-static int state_comment(Parser *p, char c){
- int err = 0;
- if(c == '\n' || Parser_at_eof(p)){
- Parser_pop(p);
- } else {
- err = input_char(p, c);
- }
- return err;
-}
-
-static int begin_comment(Parser *p, char c){
- int err = 0;
- err = Parser_push(p, state_comment, "comment");
- if(err) goto exit;
- err = input_char(p, c);
- exit:
- return err;
-}
-
-static int end_string(Parser *p){
- int err = 0;
- err = Parser_string(p);
- if(err) goto exit;
- err = Parser_return(p);
- exit:
- return err;
-}
-
-static int octaldone(Parser *p){
- int err = 0;
- char d = (char)(p->state->ival & 0xff);
- Parser_pop(p);
- err = Parser_input_char(p, d);
- return err;
-}
-
-static int octaldigit(Parser *p, int d){
- int err = 0;
- p->state->ival *= 8;
- p->state->ival += d;
- p->state->count++;
- if(err) goto exit;
- if(p->state->ival < 0 || p->state->ival > 0xff){
- err = Parser_error(p);
- goto exit;
- }
- if(p->state->count == 3){
- err = octaldone(p);
- }
- exit:
- return err;
-}
-
-static int state_octal(Parser *p, char c){
- int err = 0;
- if(Parser_at_eof(p)){
- err = Parser_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
- goto exit;
- } else if('0' <= c && c <= '7'){
- err = octaldigit(p, c - '0');
- } else {
- err = octaldone(p);
- if(err) goto exit;
- Parser_input_char(p, c);
- }
- exit:
- return err;
-}
-
-static int hexdone(Parser *p){
- int err = 0;
- char d = (char)(p->state->ival & 0xff);
- Parser_pop(p);
- err = Parser_input_char(p, d);
- return err;
-}
-
-static int hexdigit(Parser *p, int d){
- int err = 0;
- p->state->ival *= 16;
- p->state->ival += d;
- p->state->count++;
- if(err) goto exit;
- if(p->state->ival < 0 || p->state->ival > 0xff){
- err = Parser_error(p);
- goto exit;
- }
- if(p->state->count == 2){
- err = hexdone(p);
- }
- exit:
- return err;
-}
-
-static int state_hex(Parser *p, char c){
- int err = 0;
- if(Parser_at_eof(p)){
- err = Parser_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
- goto exit;
- } else if('0' <= c && c <= '9'){
- err = hexdigit(p, c - '0');
- } else if('A' <= c && c <= 'F'){
- err = hexdigit(p, c - 'A' + 10);
- } else if('a' <= c && c <= 'f'){
- err = hexdigit(p, c - 'a' + 10);
- } else if(p->state->count){
- err = hexdone(p);
- if(err) goto exit;
- Parser_input_char(p, c);
- }
- exit:
- return err;
-}
-
-static int state_escape(Parser *p, char c){
- int err = 0;
- char d;
- if(Parser_at_eof(p)){
- err = Parser_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
- goto exit;
- }
- if(get_escape(c, &d) == 0){
- err = save_char(p, d);
- if(err) goto exit;
- Parser_pop(p);
- } else if(c == 'x'){
- p->state->fn = state_hex;
- p->state->ival = 0;
- p->state->count = 0;
- } else {
- p->state->fn = state_octal;
- p->state->ival = 0;
- p->state->count = 0;
- err = Parser_input_char(p, c);
- }
- exit:
- return err;
-}
-
-static int state_string(Parser *p, char c){
- int err = 0;
- if(Parser_at_eof(p)){
- err = Parser_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
- } else if(c == p->state->delim){
- err = end_string(p);
- } else if(c == '\\'){
- err = Parser_push(p, state_escape, "escape");
- } else {
- err = save_char(p, c);
- }
- return err;
-}
-
-static int begin_string(Parser *p, char c){
- int err = 0;
- err = Parser_push(p, state_string, "string");
- if(err) goto exit;
- new_token(p);
- p->state->delim = c;
- exit:
- return err;
-}
-
-static int end_atom(Parser *p){
- int err = 0;
- err = Parser_atom(p);
- if(err) goto exit;
- err = Parser_return(p);
- exit:
- return err;
-}
-
-static int state_atom(Parser *p, char c){
- int err = 0;
- if(Parser_at_eof(p)){
- err = end_atom(p);
- } else if(is_separator(p, c) ||
- in_space_class(c) ||
- in_comment_class(c)){
- err = end_atom(p);
- if(err) goto exit;
- err = Parser_input_char(p, c);
- } else {
- err = save_char(p, c);
- }
- exit:
- return err;
-}
-
-static int begin_atom(Parser *p, char c){
- int err = 0;
- err = Parser_push(p, state_atom, "atom");
- if(err) goto exit;
- new_token(p);
- err = save_char(p, c);
- exit:
- return err;
-}
-
-static int end_data(Parser *p){
- int err = 0;
- err = Parser_data(p);
- if(err) goto exit;
- err = Parser_return(p);
- exit:
- return err;
-}
-
-static int counted_data(Parser *p, char c){
- int err = 0;
- err = save_char(p, c);
- if(err) goto exit;
- if(token_len(p) == p->state->count){
- err = end_data(p);
- }
- exit:
- return err;
-}
-
-static int counted_data_count(Parser *p, char c){
- int err = 0;
- if(c == p->state->delim){
- new_token(p);
- p->state->count = p->state->ival;
- p->state->fn = counted_data;
- } else if('0' <= c && c <= '9'){
- p->state->ival *= 10;
- p->state->ival += c - '0';
- } else {
- err = -EINVAL;
- }
- return err;
-}
-
-static int quoted_data(Parser *p, char c){
- int err = 0;
- int count = p->state->count;
- err = save_char(p, c);
- if(err) goto exit;
- // Check that buf is longer than delim and
- // ends with delim. If so, trim delim off and return.
- if((token_len(p) >= count) &&
- !memcmp(p->tok_end - count, p->buf, count)){
- p->tok_end -= count;
- end_data(p);
- }
- exit:
- return err;
-}
-
-static int quoted_data_delim(Parser *p, char c){
- // Saves the delim in the token buffer.
- int err = 0;
- err = save_char(p, c);
- if(err) goto exit;
- if(c == p->state->delim){
- p->state->fn = quoted_data;
- p->state->count = token_len(p);
- // Advance the token pointer past the delim.
- p->tok = p->tok_end;
- }
- exit:
- return err;
-}
-
-static int state_data(Parser *p, char c){
- // Quoted data:
- // <<delim< anything not containing delimiter<delim<
- // Where 'delim' is anything not containing '<'.
- // Counted data:
- // <*nnn..* N bytes
- // Where nnn... is N in decimal (
- int err = 0;
- switch(c){
- case c_data_count:
- p->state->delim = c;
- p->state->fn = counted_data_count;
- p->state->ival = 0;
- new_token(p);
- break;
- case c_data_quote:
- p->state->delim = c;
- p->state->fn = quoted_data_delim;
- new_token(p);
- err = save_char(p, c);
- break;
- default:
- err = Parser_error(p);
- break;
- }
- return err;
-}
-
-static int begin_data(Parser *p, char c){
- int err = 0;
- err = Parser_push(p, state_data, "data");
- if(err) goto exit;
- new_token(p);
- exit:
- return err;
-}
-
-static int state_list(Parser *p, char c){
- int err = 0;
- dprintf(">\n");
- if(Parser_at_eof(p)){
- err = Parser_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
- } else if(c == c_list_close){
- p->state->val = nrev(p->state->val);
- err = Parser_return(p);
- } else {
- err = state_start(p, c);
- }
- dprintf("< err=%d\n", err);
- return err;
-
-}
-
-static int begin_list(Parser *p, char c){
- return Parser_push(p, state_list, "list");
-}
-
-static int state_start(Parser *p, char c){
- int err = 0;
- dprintf(">\n");
- if(Parser_at_eof(p)){
- err = Parser_return(p);
- } else if(in_space_class(c)){
- //skip
- } else if(in_comment_class(c)){
- begin_comment(p, c);
- } else if(c == c_list_open){
- begin_list(p, c);
- } else if(c == c_list_close){
- err = Parser_error(p);
- } else if(in_string_quote_class(c)){
- begin_string(p, c);
- } else if(c == c_data_open){
- begin_data(p, c);
- } else if(in_printable_class(c)){
- begin_atom(p, c);
- } else if(c == 0x04){
- //ctrl-D, EOT: end-of-text.
- Parser_input_eof(p);
- } else {
- err = Parser_error(p);
- }
- dprintf("< err=%d\n", err);
- return err;
-}
-
-int begin_start(Parser *p, char c){
- int err = 0;
- dprintf(">\n");
- err = Parser_push(p, state_start, "start");
- if(err) goto exit;
- p->start_state = p->state;
- exit:
- dprintf("< err=%d\n", err);
- return err;
-}
-
-int Parser_input_char(Parser *p, char c){
- int err = 0;
- if(Parser_at_eof(p)){
- //skip;
- } else {
- input_char(p, c);
- }
- if(!p->state){
- err = p->begin(p, c);
- if(err) goto exit;
- }
- err = p->state->fn(p, c);
- exit:
- return err;
-}
-
-int Parser_input_eof(Parser *p){
- int err = 0;
- p->eof = 1;
- err = Parser_input_char(p, IOSTREAM_EOF);
- return err;
-}
-
-int Parser_input(Parser *p, char *buf, int buf_n){
- int err = 0;
- int i = 0;
- dprintf("> buf_n=%d\n", buf_n);
- if(buf_n <= 0){
- buf_n = 0;
- err = Parser_input_eof(p);
- goto exit;
- }
- dprintf("> buf=|%*s|\n", buf_n, buf);
- for(i = 0; i < buf_n; i++){
- err = Parser_input_char(p, buf[i]);
- if(err) goto exit;
- }
- exit:
- err = (err < 0 ? err : buf_n);
- dprintf("< err=%d\n", err);
- return err;
-}
-
-#ifdef SXPR_PARSER_MAIN
-/* Stuff for standalone testing. */
-
-#include "file_stream.h"
-//#include "string_stream.h"
-
-/** Main program for testing.
- * Parses input and prints it.
- *
- * @param argc number of arguments
- * @param argv arguments
- * @return error code
- */
-int main(int argc, char *argv[]){
- Parser *pin;
- int err = 0;
- char buf[1024];
- int k;
- Sxpr obj;
- int i = 0;
-
- pin = Parser_new();
- Parser_set_error_stream(pin, iostdout);
- dprintf("> parse...\n");
- while(1){
- k = fread(buf, 1, 100, stdin);
- if(k>=0){
- buf[k+1] = '\0';
- }
- err = Parser_input(pin, buf, k);
- while(Parser_ready(pin)){
- obj = Parser_get_val(pin);
- printf("obj %d\n", i++);
- objprint(iostdout, obj, 0); printf("\n");
- }
- if(k <= 0) break;
- }
- dprintf("> err=%d\n", err);
- return 0;
-}
-#endif
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2005 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _XUTIL_SXPR_PARSER_H_
-#define _XUTIL_SXPR_PARSER_H_
-
-#include "sxpr.h"
-#include "iostream.h"
-
-/** @file
- * Sxpr parsing definitions.
- */
-
-/** Initial size of a parser input buffer.
- */
-#define PARSER_BUF_SIZE 512
-
-/** Input buffer size increment (when it's full).
- */
-#define PARSER_BUF_INCREMENT 512
-
-struct Parser;
-typedef int ParserStateFn(struct Parser *, char c);
-
-typedef struct ParserState {
- struct ParserState *parent;
- Sxpr val;
- int ival;
- int count;
- char delim;
- ParserStateFn *fn;
- char *name;
-} ParserState;
-
-typedef struct Parser {
- /** Initial state function. */
- ParserStateFn *begin;
- /** Parse value. */
- Sxpr val;
- /** Error reporting stream (null for no reports). */
- IOStream *error_out;
- /** End-of-file flag, */
- int eof;
- /** Error flag. Non-zero if there has been a read error. */
- int err;
- /** Line number on input (from 1). */
- int line_no;
- /** Column number of input (reset on new line). */
- int char_no;
- /** Buffer for reading tokens. */
- char *buf;
- char *buf_end;
- char *tok;
- char *tok_end;
- /** Line the last token started on. */
- int tok_begin_line;
- /** Character number the last token started on. */
- int tok_begin_char;
- /** Parsing flags. */
- int flags;
- ParserState *state;
- ParserState *start_state;
-} Parser;
-
-/** Parser error codes. */
-typedef enum {
- PARSE_ERR_NONE=0,
- PARSE_ERR_UNSPECIFIED,
- PARSE_ERR_NOMEM,
- PARSE_ERR_UNEXPECTED_EOF,
- PARSE_ERR_TOKEN_TOO_LONG,
- PARSE_ERR_INVALID_SYNTAX,
- PARSE_ERR_INVALID_ESCAPE,
-} ParseErrorId;
-
-
-/** Parser flags. */
-enum {
- /** Convert integer atoms to ints. */
- PARSE_INT=1,
-};
-
-/** Raise some parser flags.
- *
- * @param in parser
- * @param flags flags mask
- */
-static inline void Parser_flags_raise(Parser *in, int flags){
- in->flags |= flags;
-}
-
-/** Lower some parser flags.
- *
- * @param in parser
- * @param flags flags mask
- */
-static inline void Parser_flags_lower(Parser *in, int flags){
- in->flags &= ~flags;
-}
-
-/** Clear all parser flags.
- *
- * @param in parser
- */
-static inline void Parser_flags_clear(Parser *in){
- in->flags = 0;
-}
-
-static inline int Parser_flags(Parser *in, int flags){
- return in->flags & flags;
-}
-
-extern void Parser_free(Parser *z);
-extern Parser * Parser_new(void);
-extern int Parser_input(Parser *p, char *buf, int buf_n);
-extern int Parser_input_eof(Parser *p);
-extern int Parser_input_char(Parser *p, char c);
-extern void Parser_set_error_stream(Parser *z, IOStream *error_out);
-
-extern int Parser_error_message(Parser *in, char *buf, int n);
-extern int Parser_has_error(Parser *in);
-extern int Parser_at_eof(Parser *in);
-
-extern int Parser_ready(Parser *p);
-extern Sxpr Parser_get_val(Parser *p);
-extern Sxpr Parser_get_all(Parser *p);
-
-/* Internal parser api. */
-void Parser_pop(Parser *p);
-int Parser_push(Parser *p, ParserStateFn *fn, char *name);
-int Parser_return(Parser *p);
-int Parser_at_eof(Parser *p);
-int Parser_error(Parser *in);
-int Parser_set_value(Parser *p, Sxpr val);
-int Parser_intern(Parser *p);
-int Parser_string(Parser *p);
-int Parser_data(Parser *p);
-int Parser_uint(Parser *p);
-
-char *peek_token(Parser *p);
-char *copy_token(Parser *p);
-void new_token(Parser *p);
-int save_char(Parser *p, char c);
-int token_len(Parser *p);
-
-#endif /* ! _XUTIL_SXPR_PARSER_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include "sys_net.h"
-#include "sys_string.h"
-
-#ifdef __KERNEL__
-# include <linux/errno.h>
-#else
-# include <errno.h>
-#endif
-
-/** @file
- * All network data are kept in network order and only converted to
- * host order for display. Network data includes IP addresses, port numbers and
- * network masks.
- */
-
-/** Maximum value for a port. */
-#define PORT_MAX 0xffff
-
-/** Convert a number of bits to a network mask
- * for IP addresses. The number of bits must
- * be in the range 1-31.
- *
- * @param n number of bits to set in the mask
- * @return value with n high bits set (in network order)
- */
-unsigned long bits_to_mask(int n){
- unsigned long mask = (n ? (1 << 31) : 0);
- int i;
- for(i=1; i<n; i++){
- mask |= (mask >> 1);
- }
- return htonl(mask);
-}
-
-/** Convert a network mask to a number of bits.
- *
- * @param mask network mask in network order
- * @return number of bits in mask
- */
-int mask_to_bits(unsigned long mask){
- // Start with n set to the number of bits in the mask. Then reduce n by
- // the number of low zero bits in the mask.
- int n = 32;
- for(mask = ntohl(mask);
- (mask & 1)==0 && n>0;
- mask >>= 1){
- n--;
- }
- return n;
-}
-
-/** Get the index of the first occurrence of a character in a string.
- * Stops at end of string or after n characters.
- *
- * @param s input string
- * @param n maximum number of charactes to search
- * @param c character to look for
- * @return index of first occurrence, -1 if not found
- */
-inline static int indexof(const char *s, int n, char c){
- int i;
- for(i=0; i<n && *s; i++, s++){
- if(*s == c) return i;
- }
- return -1;
-}
-
-/** Convert an IPv4 address in dot notation into an unsigned long (in network order).
- *
- * @param s input string
- * @param address where to put the address
- * @return 0 on success, negative on error
- */
-int get_inet_addr(const char *s, unsigned long *address){
- // Number of bits in a byte.
- const int BYTE_BITS = 8;
- // Number of bytes in a word.
- const int WORD_BYTES = 4;
- // Max value for a component of an address.
- const int ADDR_MAX = 255;
- // Separator for components of an address.
- const char dot = '.';
-
- int n;
- unsigned long addr = 0;
- unsigned long v;
- int i;
- int err = -EINVAL;
- // Bit shift for the current byte.
- int shift = BYTE_BITS * (WORD_BYTES - 1);
- char buf[64];
-
- n = strlen(s);
- if(n >= sizeof(buf)){
- goto exit;
- }
- for(i=0; i < WORD_BYTES; i++){
- int idx = indexof(s, n, dot);
- idx = (idx < 0 ? strlen(s) : idx);
- strncpy(buf, s, idx); buf[idx]='\0';
- if(convert_atoul(buf, &v)){
- goto exit;
- }
- if(v < 0 || v > ADDR_MAX){
- goto exit;
- }
- addr |= (v << shift);
- if(idx == n) break;
- shift -= BYTE_BITS;
- s += idx+1;
- }
- err = 0;
- exit:
- addr = htonl(addr);
- *address = (err ? 0 : addr);
- return err;
-}
-
-#ifdef __KERNEL__
-/** Convert an address in network order to IPv4 dot notation.
- * The return value is a static buffer which is overwritten on each call.
- *
- * @param inaddr address (in network order)
- * @return address in dot notation
- */
-char *inet_ntoa(struct in_addr inaddr){
- static char address[16] = {};
- uint32_t addr = ntohl(inaddr.s_addr);
- snprintf(address, sizeof(address), "%d.%d.%d.%d",
- (unsigned)((addr >> 24) & 0xff),
- (unsigned)((addr >> 16) & 0xff),
- (unsigned)((addr >> 8) & 0xff),
- (unsigned)((addr ) & 0xff));
- return address;
-}
-
-
-/** Convert a string in IPv4 dot notation to an int in network order.
- *
- * @param address address in dot notation
- * @param inp result of conversion (in network order)
- * @return 0 on success, error code on error
- */
-int inet_aton(const char *address, struct in_addr *inp){
- int err = 0;
- unsigned long addr;
-
- err = get_inet_addr(address, &addr);
- if(err) goto exit;
- inp->s_addr = addr;
- exit:
- return err;
-}
-#endif
-
-/** Convert a hostname or IPv4 address string to an address in network order.
- *
- * @param name input hostname or address string
- * @param address where to put the address
- * @return 0 if address found OK, nonzero otherwise
- */
-int get_host_address(const char *name, unsigned long *address){
-#ifdef __KERNEL__
- return get_inet_addr(name, address);
-#else
- struct hostent *host = gethostbyname(name);
- if(!host){
- return -ENOENT;
- }
- *address = ((struct in_addr *)(host->h_addr))->s_addr;
- return 0;
-#endif
-}
-
-/** Convert a service name to a port (in network order).
- *
- * @param name service name
- * @param port where to put the port
- * @return 0 if service port found OK, negative otherwise
- */
-int get_service_port(const char *name, unsigned long *port){
-#ifdef __KERNEL__
- return -ENOSYS;
-#else
- struct servent *service;
- service = getservbyname(name, 0);
- if(!service){
- return -EINVAL;
- }
- *port = service->s_port;
- return 0;
-#endif
-}
-
-/** Convert a port number (in network order) to a service name.
- *
- * @param port the port number
- * @return service name if found OK, NULL otherwise
- */
-char *get_port_service(unsigned long port){
-#ifdef __KERNEL__
- return NULL;
-#else
- struct servent *service = getservbyport(port, 0);
- return (service ? service->s_name : NULL);
-#endif
-}
-
-/** Convert a decimal integer or service name to a port (in network order).
- *
- * @param s input to convert
- * @param port where to put the port
- * @return 0 if port found OK, -1 otherwise
- */
-int convert_service_to_port(const char *s, unsigned long *port){
- int err = 0;
- unsigned long value;
- if(convert_atoul(s, &value) == 0){
- int ok = (0 <= value) && (value <= PORT_MAX);
- if(ok){
- value = htons((unsigned short)value);
- } else {
- err = -EINVAL;
- }
- } else {
- err = get_service_port(s, &value);
- }
- *port = (err ? 0: value);
- return err;
-}
-
-#define MAC_ELEMENT_N 6 // Number of elements in a MAC address.
-#define MAC_DIGIT_N 2 // Number of digits in an element in a MAC address.
-#define MAC_LENGTH 17 //((MAC_ELEMENT_N * MAC_DIGIT_N) + MAC_ELEMENT_N - 1)
-
-/** Convert a mac address from a string of the form
- * XX:XX:XX:XX:XX:XX to numerical form (an array of 6 unsigned chars).
- * Each X denotes a hex digit: 0..9, a..f, A..F.
- * Also supports using '-' as the separator instead of ':'.
- *
- * @param mac_in string to convert
- * @param mac destination for the value
- * @return 0 on success, -1 on error
- */
-int mac_aton(const char *mac_in, unsigned char *mac){
- int err = 0;
- int i, j;
- const char *p;
- char sep = 0;
- unsigned char d;
- if(!mac_in || strlen(mac_in) != MAC_LENGTH){
- err = -1;
- goto exit;
- }
- for(i = 0, p = mac_in; i < MAC_ELEMENT_N; i++){
- d = 0;
- if(i){
- if(!sep){
- if(*p == ':' || *p == '-') sep = *p;
- }
- if(sep && *p == sep){
- p++;
- } else {
- err = -1;
- goto exit;
- }
- }
- for(j = 0; j < MAC_DIGIT_N; j++, p++){
- if(j) d <<= 4;
- if(*p >= '0' && *p <= '9'){
- d += (*p - '0');
- } else if(*p >= 'A' && *p <= 'F'){
- d += (*p - 'A') + 10;
- } else if(*p >= 'a' && *p <= 'f'){
- d += (*p - 'a') + 10;
- } else {
- err = -1;
- goto exit;
- }
- }
- mac[i] = d;
- }
- exit:
- return err;
-}
-
-/** Convert a MAC address from numerical form to a string.
- *
- * @param mac address to convert
- * @return static string value
- */
-char *mac_ntoa(const unsigned char *mac){
- static char buf[MAC_LENGTH + 1];
- int buf_n = sizeof(buf);
-
- memset(buf, 0, buf_n);
- snprintf(buf, buf_n, "%02x:%02x:%02x:%02x:%02x:%02x",
- mac[0], mac[1], mac[2],
- mac[3], mac[4], mac[5]);
- buf[buf_n - 1] = '\0';
- return buf;
-}
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _XUTIL_SYS_NET_H_
-#define _XUTIL_SYS_NET_H_
-/** @file
- *
- * Replacement for standard network includes.
- * Works in user or kernel code.
- */
-
-extern int get_inet_addr(const char *s, unsigned long *address);
-extern unsigned long bits_to_mask(int n);
-extern int mask_to_bits(unsigned long mask);
-extern int get_host_address(const char *name, unsigned long *address);
-extern int get_service_port(const char *name, unsigned long *port);
-extern char *get_port_service(unsigned long port);
-extern int convert_service_to_port(const char *s, unsigned long *port);
-
-#ifdef __KERNEL__
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <asm/byteorder.h>
-
-#ifndef htonl
-#define htonl(x) __constant_htonl(x)
-#endif
-
-#ifndef ntohl
-#define ntohl(x) __constant_ntohl(x)
-#endif
-
-#ifndef htons
-#define htons(x) __constant_htons(x)
-#endif
-
-#ifndef ntohs
-#define ntohs(x) __constant_ntohs(x)
-#endif
-
-#include <linux/in.h>
-extern char *inet_ntoa(struct in_addr inaddr);
-extern int inet_aton(const char *address, struct in_addr *inp);
-
-#else
-
-#include <limits.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <arpa/inet.h>
-
-#endif
-
-extern char *mac_ntoa(const unsigned char *macaddr);
-extern int mac_aton(const char *addr, unsigned char *macaddr);
-
-#endif /* !_XUTIL_SYS_NET_H_ */
-
-
-
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef __KERNEL__
-# include <linux/config.h>
-# include <linux/module.h>
-# include <linux/kernel.h>
-# include <linux/errno.h>
-#else
-# include <errno.h>
-#endif
-
-#include "allocate.h"
-#include "sys_string.h"
-
-#ifdef __KERNEL__
-
-#define deferr(_err) case _err: return #_err
-
-extern char *strerror(int err)
-{
- switch(err){
- deferr(EPERM);
- deferr(ENOENT);
- deferr(ESRCH);
- deferr(EINTR);
- deferr(EIO);
- deferr(EINVAL);
- deferr(ENOMEM);
- deferr(EACCES);
- deferr(EFAULT);
- deferr(EBUSY);
-
- default:
- return "ERROR";
- }
-}
-
-#endif
-
-/** Set the base to use for converting a string to a number. Base is
- * hex if starts with 0x, otherwise decimal.
- *
- * @param s input string
- * @param base where to put the base
- * @return rest of s to parse as a number
- */
-inline static const char * convert_set_base(const char *s, int *base){
- *base = 10;
- if(s){
- if(*s=='0'){
- s++;
- if(*s=='x' || *s=='X'){
- *base = 16;
- s++;
- }
- }
- }
- return s;
-}
-
-/** Set the sign to use for converting a string to a number.
- * Value is 1 for positive, -1 for negative.
- *
- * @param s input string
- * @param sign where to put the sign
- * @return rest of s to parse as a number
- */
-inline static const char * convert_set_sign(const char *s, int *sign){
- *sign = 1;
- if(s){
- if(*s == '+'){
- *sign = 1;
- s++;
- } else if (*s == '-'){
- *sign = -1;
- s++;
- }
- }
- return s;
-}
-
-/** Get the numerical value of a digit in the given base.
- *
- * @param c digit character
- * @param base to use
- * @return numerical value of digit in range 0..base-1 or
- * -1 if not in range for the base
- */
-inline static int convert_get_digit(char c, int base){
- int d;
-
- if('0'<=c && c<='9'){
- d = c - '0';
- } else if('a'<=c && c<='f'){
- d = c - 'a' + 10;
- } else if('A'<=c && c<='F'){
- d = c - 'A' + 10;
- } else {
- d = -1;
- }
- return (d < base ? d : -1);
-}
-
-/** Convert a string to an unsigned long by parsing it as a number.
- * Will accept hex or decimal in usual C syntax.
- *
- * @param str input string
- * @param val where to put the result
- * @return 0 if converted OK, negative otherwise
- */
-int convert_atoul(const char *str, unsigned long *val){
- int err = 0;
- unsigned long v = 0;
- int base;
- const char *s = str;
-
- if(!s) {
- err = -EINVAL;
- goto exit;
- }
- s = convert_set_base(s, &base);
- for( ; !err && *s; s++){
- int digit = convert_get_digit(*s, base);
- if(digit<0){
- err = -EINVAL;
- goto exit;
- }
- v *= base;
- v += digit;
- }
- exit:
- *val = (err ? 0 : v);
- return err;
-}
-
-/** Convert a string to a long by parsing it as a number.
- * Will accept hex or decimal in usual C syntax.
- *
- * @param str input string
- * @param val where to put the result
- * @return 0 if converted OK, negative otherwise
- */
-int convert_atol(const char *str, long *val){
- int err = 0;
- unsigned long v = 0;
- int base, sign = 1;
- const char *s = str;
-
- if(!s) {
- err = -EINVAL;
- goto exit;
- }
- s = convert_set_sign(s, &sign);
- s = convert_set_base(s, &base);
- for( ; !err && *s; s++){
- int digit = convert_get_digit(*s, base);
- if(digit<0){
- err = -EINVAL;
- goto exit;
- }
- v *= base;
- v += digit;
- }
- if(sign < 0) v = -v;
- exit:
- *val = (err ? 0 : v);
- return err;
-}
-
-/** Combine a directory path with a relative path to produce
- * a new path.
- *
- * @param s directory path
- * @param t relative path
- * @return new combined path s/t
- */
-int path_concat(char *s, char *t, char **val){
- int err = 0;
- int sn, tn, vn;
- char *v;
- sn = strlen(s);
- if(sn > 0 && s[sn-1] == '/'){
- sn--;
- }
- tn = strlen(t);
- if(tn > 0 && t[0] == '/'){
- tn--;
- }
- vn = sn+tn+1;
- v = (char*)allocate(vn+1);
- if(!v){
- err = -ENOMEM;
- goto exit;
- }
- strncpy(v, s, sn);
- v[sn] = '/';
- strncpy(v+sn+1, t, tn);
- v[vn] = '\0';
- exit:
- *val = (err ? NULL : v);
- return err;
-}
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _XUTIL_SYS_STRING_H_
-#define _XUTIL_SYS_STRING_H_
-/** @file
- * Replacement for standard string includes.
- * Works in user or kernel code.
- */
-/*============================================================================*/
-#ifdef __KERNEL__
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <stdarg.h>
-#include "allocate.h"
-
-extern char *strerror(int err);
-
-#if 0
-static inline int tolower(int c){
- return (c>='A' && c<='Z' ? (c-'A')+'a' : c);
-}
-#endif
-
-static inline int isalpha(int c){
- return (c>='A' && c<='Z') || (c>='a' && c<='z');
-}
-
-static inline int isdigit(int c){
- return (c>='0' && c<='9');
-}
-
-#if 0
-static inline int strcasecmp(const char *s1, const char *s2){
- int c1, c2;
-
- do {
- c1 = tolower(*s1++);
- c2 = tolower(*s2++);
- } while (c1 && c1 == c2);
- return c1 - c2;
-}
-#endif
-
-static inline char * strdup(const char *s){
- int n = (s ? 1+strlen(s) : 0);
- char *copy = (n ? allocate(n) : NULL);
- if(copy){
- strcpy(copy, s);
- }
- return copy;
-}
-
-/*============================================================================*/
-#else
-#include <string.h>
-#include <stdio.h>
-
-#ifndef _GNU_SOURCE
-static inline size_t strnlen(const char *s, size_t n){
- int k = 0;
- if(s){
- for(k=0; *s && k<n; s++, k++){}
- }
- return k;
-}
-#endif
-
-#endif
-/*============================================================================*/
-
-extern int convert_atoul(const char *s, unsigned long *v);
-extern int convert_atol(const char *s, long *v);
-extern int path_concat(char *s, char *t, char **val);
-
-#endif /* !_XUTIL_SYS_STRING_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2002 - 2004 Mike Wray <mike.wray@hp.com>.
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include "sys_net.h"
-#include "sys_string.h"
-
-#ifndef __KERNEL__
-# include <grp.h>
-# include <pwd.h>
-#endif
-
-#include "util.h"
-
-
-/** @file Various utility functions.
- */
-
-/** Print an address (in network order) as an IPv4 address string
- * in dot notation.
- *
- * @param io where to print address
- * @param address to print (in network order)
- * @return bytes printed
- */
-int print_address(IOStream *io, unsigned long address){
-#ifdef __KERNEL__
- address = ntohl(address);
- return IOStream_print(io, "%u.%u.%u.%u",
- (unsigned)((address >> 24) & 0xff),
- (unsigned)((address >> 16) & 0xff),
- (unsigned)((address >> 8) & 0xff),
- (unsigned)((address ) & 0xff));
-#else
- struct in_addr inaddr = { s_addr: address };
- return IOStream_print(io, inet_ntoa(inaddr));
-#endif
-}
-
-/** Get the protocol number for a protocol.
- *
- * @param name protocol name
- * @param protocol where to put the protocol number
- * @return 0 if OK, error otherwise
- */
-int get_protocol_number(char *name, unsigned long *protocol){
-#ifdef __KERNEL__
- return -1;
-#else
- struct protoent *proto = getprotobyname(name);
- if(!proto){
- return -1;
- }
- *protocol = proto->p_proto;
- return 0;
-#endif
-}
-
-/** Get the protocol name for a protocol number.
- *
- * @param protocol number
- * @return name or null
- */
-char *get_protocol_name(unsigned long protocol){
-#ifdef __KERNEL__
- return 0;
-#else
- struct protoent *proto = getprotobynumber(protocol);
- if(!proto){
- return 0;
- }
- return proto->p_name;
-#endif
-}
-
-/** Get the host name for an address.
- *
- * @param addr address
- * @return host name or null
- */
-char *get_host_name(unsigned long addr){
-#ifdef __KERNEL__
- return 0;
-#else
- struct in_addr inaddr;
- struct hostent *host = 0;
-
- inaddr.s_addr = addr;
- host = gethostbyaddr((char*)&inaddr, sizeof(inaddr), AF_INET);
- if(!host) return NULL;
- return host->h_name;
-#endif
-}
+++ /dev/null
-/*
- * Copyright (C) 2002 - 2004 Mike Wray <mike.wray@hp.com>.
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _XEN_LIB_UTIL_H_
-#define _XEN_LIB_UTIL_H_
-
-#include "iostream.h"
-
-extern int print_address(IOStream *io, unsigned long address);
-extern int get_protocol_number(char *name, unsigned long *protocol);
-extern char *get_protocol_name(unsigned long protocol);
-extern char *get_host_name(unsigned long addr);
-
-#endif /* ! _XEN_LIB_UTIL_H_ */
+++ /dev/null
-# -*- mode: Makefile; -*-
-#============================================================================
-XEN_ROOT = $(CURDIR)/../../..
-include $(XEN_ROOT)/tools/Rules.mk
-
-.PHONY: all
-all:
-
-.PHONY: install
-install:
- $(INSTALL_DIR) $(DESTDIR)$(SBINDIR)
- $(INSTALL_PROG) vn $(DESTDIR)$(SBINDIR)
-
-.PHONY: clean
-clean:
+++ /dev/null
-#!/usr/bin/env python2.4
-# -*- mode: python; -*-
-#============================================================================
-# Copyright (C) 2005, 2006 Mike Wray <mike.wray@hp.com>
-#
-# This library is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation; either version 2.1 of the License, or
-# (at your option) any later version.
-#
-# This library 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 Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#============================================================================
-
-# Vnet (network virtualization) control utility.
-
-import os
-import os.path
-import re
-import socket
-import sys
-from getopt import getopt, GetoptError
-
-from xen.xend import sxp
-from xen.xend.PrettyPrint import prettyprint
-
-# Path of unix-domain socket to vnetd.
-VNETD_PATH = "/tmp/vnetd"
-
-def vnetd_running():
- return os.path.exists(VNETD_PATH)
-
-def vnetd_open():
- sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
- sock.connect(VNETD_PATH)
- fi = sock.makefile('r', 0)
- fo = sock.makefile('w', 0)
- return (fi, fo)
-
-os.defpath += ':/sbin:/usr/sbin:/usr/local/sbin'
-CMD_IFCONFIG = 'ifconfig'
-CMD_BRCTL = 'brctl'
-
-opts = None
-
-class Opts:
-
- def __init__(self, **kwds):
- for (k, v) in kwds.items():
- setattr(self, k, v)
-
-opts = Opts(verbose=False, dryrun=False)
-
-def set_opts(val):
- global opts
- opts = val
- return opts
-
-def cmd(prog, *args):
- """Execute command 'prog' with 'args', optionally printing the command.
- """
- global opts
- command = " ".join([ prog ] + map(str, args))
- if opts.verbose:
- print command
- if not opts.dryrun:
- os.system(command)
-
-def vif_bridge_add(bridge, vif):
- """Add a network interface to a bridge.
- """
- cmd(CMD_BRCTL, 'addif', bridge, vif)
-
-def vif_bridge_rem(bridge, vif):
- """Remove a network interface from a bridge.
- """
- cmd(CMD_BRCTL, 'delif', bridge, vif)
-
-def bridge_create(bridge, **kwd):
- """Create a bridge.
- Defaults hello time to 0, forward delay to 0 and stp off.
- """
- cmd(CMD_BRCTL, 'addbr', bridge)
- if kwd.get('hello', None) is None:
- kwd['hello'] = 0
- if kwd.get('fd', None) is None:
- kwd['fd'] = 0
- if kwd.get('stp', None) is None:
- kwd['stp'] = 'off'
- bridge_set(bridge, **kwd)
- cmd(CMD_IFCONFIG, bridge, "up")
-
-def bridge_set(bridge, hello=None, fd=None, stp=None):
- """Set bridge parameters.
- """
- if hello is not None:
- cmd(CMD_BRCTL, 'sethello', bridge, hello)
- if fd is not None:
- cmd(CMD_BRCTL, 'setfd', bridge, fd)
- if stp is not None:
- cmd(CMD_BRCTL, 'stp', bridge, stp)
-
-def bridge_del(bridge):
- """Delete a bridge.
- """
- cmd(CMD_IFCONFIG, bridge, 'down')
- cmd(CMD_BRCTL, 'delbr', bridge)
-
-class Bridge:
- # Network interfaces are at /sys/class/net/*.
- # A bridge interface has ./bridge dir, ./brif is dir of bridged interfaces
- # (symlinks to the brport dirs).
- # If an interface is bridged ./brport is bridged port info,
- # brport/bridge is a symlink to the bridge.
-
- INTERFACE_DIR = "/sys/class/net"
-
- def isBridge(klass, dev):
- """Test if a network interface is a bridge.
- """
- devdir = os.path.join(klass.INTERFACE_DIR, dev)
- brdir = os.path.join(devdir, "bridge")
- try:
- os.stat(brdir)
- return True
- except:
- return False
-
- isBridge = classmethod(isBridge)
-
- def getInterfaces(klass):
- """Get a list of the network interfaces.
- """
- try:
- v = os.listdir(klass.INTERFACE_DIR)
- v.sort()
- return v
- except:
- return []
-
- getInterfaces = classmethod(getInterfaces)
-
- def getInterfaceAddr(klass, intf):
- intfdir = os.path.join(klass.INTERFACE_DIR, intf)
- addrfile = os.path.join(intfdir, "address")
- try:
- f = file(addrfile, "rb")
- except Exception, ex:
- #print ex
- return None
- try:
- return f.readline().strip()
- finally:
- f.close()
-
- getInterfaceAddr = classmethod(getInterfaceAddr)
-
- def getBridges(klass):
- """Get a list of the bridges.
- """
- return [ dev for dev in klass.getInterfaces() if klass.isBridge(dev) ]
-
- getBridges = classmethod(getBridges)
-
- def getBridgeInterfaces(klass, dev):
- """Get a list of the interfaces attached to a bridge.
- """
- devdir = os.path.join(klass.INTERFACE_DIR, dev)
- intfdir = os.path.join(devdir, "brif")
- try:
- v = os.listdir(intfdir)
- v.sort()
- return v
- except:
- return []
-
- getBridgeInterfaces = classmethod(getBridgeInterfaces)
-
- def getBridge(klass, dev):
- """Get the bridge an interface is attached to (if any).
- """
- devdir = os.path.join(klass.INTERFACE_DIR, dev)
- brfile = os.path.join(devdir, "brport/bridge")
- try:
- brpath = os.readlink(brfile)
- return os.path.basename(brpath)
- except:
- return None
-
- getBridge = classmethod(getBridge)
-
-def vnet_cmd(expr):
- """Send a command expression to the vnet implementation.
- """
- if vnetd_running():
- (fi, fo) = vnetd_open()
- else:
- fi = None
- fo = file("/proc/vnet/policy", "wb")
- try:
- sxp.show(expr, fo)
- fo.flush()
- finally:
- if fi: fi.close()
- if fo: fo.close()
-
-def varp_flush():
- """Flush the varp cache.
- """
- expr = ['varp.flush']
- return vnet_cmd(expr)
-
-def vif_add(vnetid, vmac):
- """Tell the vnet implementation to add a vif to a vnet.
- """
- expr = ['vif.add', ['vnet', vnetid], ['vmac', vmac]]
- return vnet_cmd(expr)
-
-def vif_del(vnetid, vmac):
- """Tell the vnet implementation to delete a vif from a vnet.
- """
- expr = ['vif.del', ['vnet', vnetid], ['vmac', vmac]]
- return vnet_cmd(expr)
-
-def vnet_add(vnetid, vnetif=None, security=None):
- """Tell the vnet implementation to add a vnet.
- """
- expr = ['vnet.add', ['id', vnetid]]
- if vnetif:
- expr.append(['vnetif', vnetif])
- if security:
- expr.append(['security', security])
- return vnet_cmd(expr)
-
-def peer_add(addr, port=None):
- expr = ['peer.add', ['addr', addr]]
- if port:
- expr.append(['port', port])
- return vnet_cmd(expr)
-
-def peer_del(addr, port=None):
- expr = ['peer.del', ['addr', addr]]
- return vnet_cmd(expr)
-
-def vnet_del(vnetid):
- """Tell the vnet implementation to delete a vnet.
- """
- expr = ['vnet.del', ['id', vnetid]]
- return vnet_cmd(expr)
-
-def vnet_create(vnetid, vnetif=None, bridge=None, security=None):
- """Tell the vnet implementation to add a vnet.
- If 'bridge' is non-null, create the bridge and add the vnet interface
- to it.
- """
- vnet_add(vnetid, vnetif=vnetif, security=security)
- val = vnet_lookup(vnetid)
- if not vnetif:
- vnetif = sxp.child_value(val, "vnetif")
- vmac = get_mac(vnetif)
- emac = get_mac("eth0") or get_mac("eth1") or get_mac("eth2")
- if emac and vmac != emac:
- set_mac(vnetif, emac)
- cmd(CMD_IFCONFIG, vnetif, 'up')
- if bridge:
- bridge_create(bridge)
- vif_bridge_add(bridge, vnetif)
- return val
-
-def vnet_delete(vnet, delbridge=False):
- """Tell the vnet implementation to delete a vnet.
- If the vnet interface is attached to a bridge,
- remove it from the bridge, and if delbridge is true
- delete the bridge.
- """
- v = vnet_lookup(vnet)
- if not v:
- raise GetoptError("vnet not found: %s" % vnet)
- vnetid = sxp.child_value(v, "id")
- vnetif = sxp.child_value(v, "vnetif")
- bridge = Bridge.getBridge(vnetif)
- if bridge:
- vif_bridge_rem(bridge, vnetif)
- if delbridge:
- bridge_del(bridge)
- return vnet_del(vnetid)
-
-def get_mac(intf):
- """Get the mac address of an interface.
- """
- try:
- return Bridge.getInterfaceAddr(intf)
- except:
- pass
-
- hwre = re.compile(".*\s+HWaddr\s+(?P<mac>\S*)\s+.*")
- fin = os.popen("%s %s" % (CMD_IFCONFIG, intf), 'r')
- try:
- for x in fin:
- m = hwre.match(x)
- if not m:
- continue
- info = m.groupdict()
- return info['mac']
- return None
- finally:
- fin.close()
-
-def set_mac(intf, mac):
- cmd(CMD_IFCONFIG, intf, 'down')
- cmd(CMD_IFCONFIG, intf, 'hw', 'ether', mac)
- cmd(CMD_IFCONFIG, intf, 'up')
-
-def get_addr(host):
- return socket.gethostbyname(host)
-
-def get_port(srv):
- return srv
-
-def vnetidof(v):
- """Normalise a vnet id. Adds leading 0 fields to make up 8 if
- there aren't enough. Pads all fields to 4 hex digits.
- """
- try:
- l = v.split(":")
- l = [ int(x or 0, 16) for x in l ]
- l = [ 0 ] * (8 - len(l)) + l
- return ":".join([ "%04x" % x for x in l ])
- except:
- return None
-
-def vnet_lookup(vnet, vnets=None):
- """Find the vnet with the given vnet id or vnet interface.
-
- @param vnet id or interface
- @param vnets list of vnet info to use (get from implementation if None)
- @return vnet info or None if not found
- """
- vnetid = vnetidof(vnet)
- if vnets is None:
- vnets = vnet_list()
- for v in vnets:
- vid = sxp.child_value(v, "id")
- if vid == vnet or vid == vnetid:
- return v
- if sxp.child_value(v, "vnetif") == vnet:
- return v
- return None
-
-def get_vnetid(vnet):
- """Get the normalised vnet id of the given vnet id or vnet interface.
- Raises an error if the vnet cannot be found.
- """
- v = vnet_lookup(vnet)
- if not v:
- raise GetoptError("vnet not found: %s" % vnet)
- vnetid = sxp.child_value(v, "id")
- return vnetid
-
-def vif_list():
- """Get the list of vif info from the vnet implementation.
- """
- if vnetd_running():
- (fi, fo) = vnetd_open()
- sxp.show(['vif.list'], fo)
- fo.flush()
- else:
- fi = file("/proc/vnet/vifs")
- fo = None
- try:
- return sxp.parse(fi) or []
- finally:
- if fi: fi.close()
- if fo: fo.close()
-
-def vnets_filter(vnetlist, vnets):
- """Filter a list of vnet info by a list of vnet ids or interfaces.
- """
- if vnets is None:
- val = vnetlist
- else:
- val = []
- for x in vnets:
- v = vnet_lookup(x, vnets=vnetlist)
- if not v:
- continue
- val.append(v)
- return val
-
-def vnet_list(vnets=None):
- """Get the list of vnet info from the vnet implementation,
- sorted by vnet id.
-
- @param vnets list of vnet ids or interfaces to filter the results by
- """
- if vnetd_running():
- (fi, fo) = vnetd_open()
- sxp.show(['vnet.list'], fo)
- fo.flush()
- else:
- fi = file("/proc/vnet/vnets")
- fo = None
- try:
- val = vnets_filter(sxp.parse(fi) or [], vnets)
- val.sort(lambda x, y:
- cmp(sxp.child_value(x, "id"),
- sxp.child_value(y, "id")))
- return val
- finally:
- if fi: fi.close()
- if fo: fo.close()
-
-def vnif_list(vnets=None):
- """Get the list of vnet interface names from the vnet implementation.
-
- @param vnets list of vnet ids or interfaces to filter the results by
- """
- vnifs = []
- for v in vnet_list(vnets=vnets):
- vnetif = sxp.child_value(v, "vnetif")
- if vnetif:
- vnifs.append(vnetif)
- return vnifs
-
-def varp_list():
- """Get the list of varp info from the vnet implementation.
- """
- if vnetd_running():
- (fi, fo) = vnetd_open()
- sxp.show(['varp.list'], fo)
- fo.flush()
- else:
- fi = file("/proc/vnet/varp")
- fo = None
- try:
- return sxp.parse(fi) or []
- finally:
- if fi: fi.close()
- if fo: fo.close()
-
-def peer_list():
- if vnetd_running():
- (fi, fo) = vnetd_open()
- sxp.show(['peer.list'], fo)
- fo.flush()
- else:
- fi = file("/proc/vnet/peers")
- fo = None
- try:
- return sxp.parse(fi) or []
- finally:
- if fi: fi.close()
- if fo: fo.close()
-
-class Opt:
- """Declares command-line options for a command.
- """
-
- def getopt(klass, argv, opts, args):
- """Get options and args from argv.
- The value opts in the return value has an attribute for
- eacho option or arg. The value args in the return value
- is the remaining arguments.
-
- @param argv arguments
- @param opts option specifiers (list of Opt objects)
- @param args arg specififiers (list of Arg objects)
- @return (opts, args)
- """
- shortopts = "".join([ x.optShort() for x in opts ])
- longopts = [ x.optLong() for x in opts ]
- (ovals, oargs) = getopt(argv[1:], shortopts, longopts)
- odir = Opts()
- for x in opts:
- x.setDefault(odir)
- for (k, v) in ovals:
- for x in opts:
- x.setOpt(k, v, odir)
- argc = len(oargs)
- if len(oargs) < len(args):
- raise GetoptError("insufficient arguments for %s" % argv[0])
- for (x, v) in zip(args, oargs):
- x.setArg(v, odir)
- return (odir, oargs[len(args): ])
-
- getopt = classmethod(getopt)
-
- def gethelp(klass, opts, args):
- l = []
- for x in opts:
- l.append(x.help())
- for x in args:
- l.append(x.help())
- return " ".join(l)
-
- gethelp = classmethod(gethelp)
-
- """A command=-line option.
-
- @param name option name (this attribute is set to value in opts)
- @param short short option flag (single-character string)
- @param long long option name (defaults to option name, pass "" to suppress)
- @param arg argument name (option has no arg if not specified)
- """
- def __init__(self, name, short=None, long=None, arg=False):
- self.name = name
- self.short = short
- if long is None:
- long = name
- elif not long:
- long = None
- self.long = long
- self.arg = arg
-
- def help(self):
- s = self.keyShort()
- l = self.keyLong()
- if s and l:
- return "[%s | %s]" % (s, l)
- else:
- return s or l
-
- def keyShort(self):
- if self.short:
- return "-%s" % self.short
- else:
- return None
-
- def keyLong(self):
- if self.long:
- return "--%s" % self.long
- else:
- return None
-
- def optLong(self):
- if not self.long:
- return None
- if self.arg:
- return "%s=" % self.long
- else:
- return self.long
-
- def optShort(self):
- if not self.short:
- return None
- if self.arg:
- return "%s:" % self.short
- else:
- return self.short
-
- def setDefault(self, vals):
- if self.arg:
- setattr(vals, self.name, None)
- else:
- setattr(vals, self.name, False)
-
- def setOpt(self, k, v, vals):
- if k in [ self.keyShort(), self.keyLong() ]:
- if self.arg:
- setattr(vals, self.name, v)
- else:
- if v not in [ None, '' ]:
- raise GetoptError("option %s does not take an argument" % k)
- setattr(vals, self.name, True)
-
-class Arg:
-
- """A command-line parameter. Args get their values from arguments
- left over after option processing and are assigned in order.
- The value is accessible as the attribute called 'name' in opts.
-
- @param name argument name
- """
- def __init__(self, name):
- self.name = name
-
- def setArg(self, v, vals):
- setattr(vals, self.name, v)
-
- def help(self):
- return "<%s>" % self.name
-
-class VnMain:
-
- """Methods beginning with this prefix are commands.
- They must all have arguments like this:
-
- op_foo(self, argv, args, opts)
-
- argv: original command-line arguments
- args: arguments left after option processing
- opts: option and arg values (accessible as attributes)
-
- Method options are specified by setting attribute
- .opts on the method to a list of Option objects.
- For args set .args to a list of Arg objects.
- Use .use for short usage string, .help for long help.
-
- Each option or arg defines an attribute in opts. For example
- an option with name 'foo' is accessible as 'opts.foo'.
- """
- opPrefix = "op_"
-
- def __init__(self, argv):
- if argv:
- self.name = argv[0]
- else:
- self.name = "vn"
- self.argv = argv
- self.argc = len(argv)
-
- def error(self, v):
- print >>sys.stderr, "%s: %s" % (self.name, v)
- sys.exit(1)
-
- def getFunction(self, opname):
- key = self.opPrefix + opname.replace("-", "_")
- fn = getattr(self, key, None)
- if not fn:
- raise ValueError("unknown command: %s" % opname)
- return fn
-
- def main(self):
- if self.argc < 2:
- args = ["help"]
- else:
- args = self.argv[1:]
- try:
- fn = self.getFunction(args[0])
- except ValueError, ex:
- self.error(ex)
- try:
- fnopts = self.getOpts(fn)
- fnargs = self.getArgs(fn)
- (opts, parms) = Opt.getopt(args, fnopts, fnargs)
- return fn(args, parms, opts)
- except GetoptError, ex:
- self.error(ex)
- except ValueError, ex:
- self.error(ex)
- except Exception, ex:
- import traceback; traceback.print_exc()
- self.error(ex)
-
- def getOpts(self, meth):
- return getattr(meth, "opts", [])
-
- def getArgs(self, meth):
- return getattr(meth, "args", [])
-
- def getUse(self, meth):
- return getattr(meth, "use", "")
-
- def getHelp(self, meth):
- return getattr(meth, "help", "") or self.getUse(meth)
-
- def fnHelp(self, meth):
- return Opt.gethelp(self.getOpts(meth), self.getArgs(meth))
-
- def printHelp(self, fn, opt_long):
- meth = getattr(self, fn)
- opname = fn[len(self.opPrefix):].replace("_", "-")
- if opt_long:
- help = self.getHelp(meth)
- print "\n %s" % opname
- if help:
- print "%s" % help
- else:
- use = self.getUse(meth)
- print " %s %s" % (opname, self.fnHelp(meth))
- if use:
- print "\t\t%s" % use
-
- def show_vnif(self, dev):
- cmd(CMD_IFCONFIG, dev)
- bridge = Bridge.getBridge(dev)
- if bridge:
- print " Bridge:", bridge
- interfaces = Bridge.getBridgeInterfaces(bridge)
- if dev in interfaces:
- interfaces.remove(dev)
- if interfaces:
- print " Interfaces:", ", ".join(interfaces)
- print
-
- def op_help(self, argv, args, opts):
- if opts.long:
- print '%s <command> <options>' % self.name
- print self.long_help
- else:
- print '%s:' % self.name
- l = dir(self)
- l.sort()
- for fn in l:
- if fn.startswith(self.opPrefix):
- self.printHelp(fn, opts.long)
- print
-
- op_help.opts = [ Opt('long', short='l') ]
-
- def op_vnets(self, argv, args, opts):
- vnets = vnet_list(vnets=args or None)
- for v in vnets:
- prettyprint(v, width=50)
- print
- if not opts.long:
- continue
- vnif = sxp.child_value(v, "vnetif")
- if not vnif:
- continue
- self.show_vnif(vnif)
- if opts.all:
- vnetids = {}
- for v in vnets:
- vnetids[sxp.child_value(v, "id")] = v
- for v in vif_list():
- vnet = sxp.child_value(v, "vnet")
- if vnet not in vnetids:
- continue
- prettyprint(v)
- print
- for v in varp_list():
- prettyprint(v)
- print
-
- op_vnets.opts = [ Opt('all', short='a'), Opt('long', short='l') ]
-
- def op_vnifs(self, argv, args, opts):
- vnifs = vnif_list(vnets=args or None)
- for vnif in vnifs:
- self.show_vnif(vnif)
-
- def op_vifs(self, argv, args, opts):
- for v in vif_list():
- prettyprint(v)
- print
-
- def op_varp(self, argv, args, opts):
- for v in varp_list():
- prettyprint(v)
- print
-
- def op_varp_flush(self, argv, args, opts):
- varp_flush()
-
- def op_vnet_create(self, argv, args, opts):
- return vnet_create(opts.vnet,
- vnetif=opts.vnetif,
- bridge=opts.bridge,
- security=opts.security)
-
- op_vnet_create.args = [ Arg('vnet') ]
- op_vnet_create.opts = [ Opt('security', short='s', arg="SECURITY"),
- Opt('bridge', short='b', arg="BRIDGE"),
- Opt('vnetif', short='v', arg="VNETIF") ]
-
- def op_vnet_delete(self, argv, args, opts):
- vnetid = get_vnetid(opts.vnet)
- return vnet_delete(vnetid, delbridge=opts.bridge)
-
- op_vnet_delete.args = [ Arg('vnet') ]
- op_vnet_delete.opts = [ Opt('bridge', short='b') ]
-
- def op_vif_add(self, argv, args, opts):
- vnetid = get_vnetid(opts.vnet)
- if opts.interface:
- vmac = get_mac(opts.vmac)
- if not vmac:
- raise ValueError("interface not found: %s" % opts.vmac)
- else:
- vmac = opts.vmac
- return vif_add(vnetid, vmac)
-
- op_vif_add.args = [ Arg('vnet'), Arg('vmac') ]
- op_vif_add.opts = [ Opt('interface', short='i') ]
-
- def op_vif_delete(self, argv, args, opts):
- vnetid = get_vnetid(opts.vnet)
- if opts.interface:
- vmac = get_mac(opts.vmac)
- else:
- vmac = opts.vmac
- return vif_del(vnetid, vmac)
-
- op_vif_delete.args = [ Arg('vnet'), Arg('vmac') ]
- op_vif_delete.opts = [ Opt('interface', short='i') ]
-
- def op_peer_add(self, argv, args, opts):
- addr = get_addr(opts.addr)
- if(opts.port):
- port = get_port(opts.port)
- else:
- port = None
- return peer_add(addr, port)
-
- op_peer_add.args = [ Arg('addr') ]
- op_peer_add.opts = [ Opt('port', short='p') ]
-
- def op_peer_delete(self, argv, args, opts):
- addr = get_addr(opts.addr)
- return peer_del(addr)
-
- op_peer_delete.args = [ Arg('addr') ]
-
- def op_peers(self, argv, args, opts):
- for v in peer_list():
- prettyprint(v)
- print
-
- def op_bridges(self, argv, args, opts):
- if opts.long:
- for bridge in Bridge.getBridges():
- cmd(CMD_IFCONFIG, bridge)
- interfaces = Bridge.getBridgeInterfaces(bridge)
- if interfaces:
- print " Interfaces:", ", ".join(interfaces)
- print
- else:
- for bridge in Bridge.getBridges():
- print bridge,
- interfaces = Bridge.getBridgeInterfaces(bridge)
- if interfaces:
- print ":", ", ".join(interfaces)
- else:
- print
-
- op_bridges.opts = [ Opt('long', short='l') ]
-
- def op_insmod(self, argv, args, opts):
- """Insert the vnet kernel module."""
- cmd("/etc/xen/scripts/vnet-insert", *args)
-
- long_help = """Control utility for vnets (virtual networking).
-Report bugs to Mike Wray <mike.wray@hp.com>.
-"""
-
- op_help.use = "Print help."
- op_help.help = "Print help, long help if the option -l or --long is given."
-
- op_vnets.use = """Print vnets."""
- op_vnets.help = """Print vnet information, where options are:
- -a, -all Print vnets, vifs and varp info.
- -l, --long Print ifconfigs for vnet interfaces."""
-
- op_vifs.use = "Print vifs."
-
- op_vnifs.use = "Print ifconfigs for vnet network interfaces."
-
- op_varp.use = "Print varp info and entries in the varp cache."
-
- op_varp_flush.use = "Flush the varp cache."
-
- op_vnet_create.use = "Create a vnet."
-
- op_vnet_delete.use = "Delete a vnet."
- op_vnet_delete.help = """Delete a vnet.
- -b, --bridge Delete the bridge the vnet interface is attached to.
- """
-
- op_vif_add.use = "Add a vif to a vnet."
- op_vif_add.help = """Add a vif to a vnet. Not usually needed as vifs
-are added automatically.
- -i, --interface The vmac is the name of an interface to get the mac from."""
-
- op_vif_delete.use = "Delete a vif from a vnet."
- op_vif_delete.help = """Delete a vif from a vnet. Not usually needed as vifs
-are removed periodically.
- -i, --interface The vmac is the name of an interface to get the mac from."""
-
- op_peer_add.use = "Add a peer."
- op_peer_add.help = """Add a peer: <addr> <port>
-Vnets use multicast to discover interfaces, but networks are often configured
-not to forward multicast. Vnets forward multicasts to peers using UDP.
-Only add peers if multicasts are not working, check with
-
-ping -b 224.10.0.1
-
-Only add peers at one machine in a subnet, otherwise you may cause forwarding
-loops.
-"""
-
- op_peer_delete.use = "Delete a peer."
- op_peer_delete.help= "Delete a peer: <addr>"
-
- op_peers.use = "List peers."
- op_peers.help = "List peers."
-
- op_bridges.use = "Print bridges."
-
- op_insmod.use = "Insert the vnet kernel module, optionally with parameters."
-
-if __name__ == "__main__":
- vn = VnMain(sys.argv)
- vn.main()
-
+++ /dev/null
-Vnet module for network virtualization.
-Mike Wray <mike.wray@hp.com>
-
-*) Compiling
-The vnet module can be compiled for 2.4 or 2.6 series kernels.
-The makefiles use the following variables, which
-can be set in your env or on the make command line:
-
-LINUX_SERIES: linux release to compile for: 2.4, or 2.6 (default).
-XEN_ROOT: root of the xen tree containing kernel source.
-KERNEL_VERSION: kernel version, default got from XEN_ROOT.
-KERNEL_SRC: path to kernel source, default build-linux-<VERSION>
- under XEN_ROOT.
-
-*) For 2.4 kernel
-
-To compile from scratch:
-
-make clean
-make LINUX_SERIES=2.4
-
-This will build vnet_module.o in the current directory.
-To install the module use
-
-make LINUX_SERIES=2.4 install
-
-*) For 2.6 kernel
-
-To compile from scratch:
-
-make clean
-make
-
-This will build vnet_module.ko in the current directory.
-To install the module use
-
-make install
-
-
+++ /dev/null
-# -*- mode: Makefile; -*-
-#============================================================================
-#
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-#
-# 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-1307 USA
-#============================================================================
-
-ifndef VNET_ROOT
-export VNET_ROOT = $(shell cd .. && pwd)
-include $(VNET_ROOT)/Make.env
-endif
-
-#============================================================================
-ifeq ($(src),)
-
-include Makefile-$(LINUX_SERIES)
-
-#============================================================================
-else
-#============================================================================
-# This section is for the 2.6 kbuild.
-
-#$(warning KBUILD_EXTMOD $(KBUILD_EXTMOD))
-#$(warning src $(src))
-#$(warning obj $(obj))
-
-include $(src)/Makefile.vnet
-
-obj-m = vnet_module.o
-vnet_module-objs = $(VNET_OBJ)
-vnet_module-objs += $(VNET_LIB_OBJ)
-
-#----------------------------------------------------------------------------
-# The fancy stuff in the kernel build defeats 'vpath %.c' so we can't
-# use that to get the lib files compiled.
-# Setup explicit rules for them using the kbuild C compile rule.
-
-# File names in the lib dir.
-remote_srcs = $(foreach file,$(VNET_LIB_SRC),$(LIBXUTIL_DIR)/$(file))
-
-# Equivalent file names here.
-local_srcs = $(foreach file,$(VNET_LIB_SRC),$(src)/$(file))
-
-# Objects for the local names.
-local_objs = $(local_srcs:.c=.o)
-
-# Make the local objects depend on compiling the remote sources.
-$(local_objs): $(src)/%.o: $(LIBXUTIL_DIR)/%.c
- $(call if_changed_rule,cc_o_c)
-#----------------------------------------------------------------------------
-
-vpath %.h $(LIBXUTIL_DIR)
-EXTRA_CFLAGS += -I $(LIBXUTIL_DIR)
-EXTRA_CFLAGS += -I $(src)
-
-endif
-#============================================================================
-
+++ /dev/null
-# -*- mode: Makefile; -*-
-#============================================================================
-#
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-#
-# 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-1307 USA
-#============================================================================
-
-#============================================================================
-# Vnet module makefile for 2.4 series kernels.
-
-LINUX_SERIES =2.4
-include Makefile.ver
-
-KERNEL_MODULE := vnet_module.o
-
-CONFIG_MODVERSIONS := $(shell grep 'CONFIG_MODVERSIONS=y' $(KERNEL_SRC)/.config && echo 1 || echo 0)
-
-include Makefile.vnet
-
-VNET_OBJ += $(VNET_LIB_OBJ)
-
-#----------------------------------------------------------------------------
-
-vpath %.h $(KERNEL_SRC)/include
-INCLUDES+= -I $(KERNEL_SRC)/include
-
-vpath %.h $(LIBXUTIL_DIR)
-vpath %.c $(LIBXUTIL_DIR)
-INCLUDES += -I $(LIBXUTIL_DIR)
-
-INCLUDES+= -I .
-
-#----------------------------------------------------------------------------
-
-CPPFLAGS += -D__KERNEL__
-CPPFLAGS += -DMODULE
-
-ifeq ($(CONFIG_MODVERSIONS), 1)
-CPPFLAGS += -DMODVERSIONS
-CPPFLAGS += -include $(KERNEL_SRC)/include/linux/modversions.h
-endif
-
-CPPFLAGS += $(INCLUDES)
-
-CFLAGS += -Wall
-CFLAGS += -Wstrict-prototypes
-CFLAGS += -Wno-trigraphs
-CFLAGS += -Wno-unused-function
-CFLAGS += -Wno-unused-parameter
-
-CFLAGS += -g
-CFLAGS += -O2
-CFLAGS += -fno-strict-aliasing
-CFLAGS += -fno-common
-#CFLAGS += -fomit-frame-pointer
-
-# Dependencies. Gcc generates them for us.
-CFLAGS += -Wp,-MD,.$(@F).d
-VNET_DEP = .*.d
-#----------------------------------------------------------------------------
-
-.PHONY: all
-all: module
-
-.PHONY: module modules
-module modules: $(KERNEL_MODULE)
-
-$(KERNEL_MODULE): $(VNET_OBJ)
- $(LD) -r -o $@ $^
-
-.PHONY: install install-module modules_install
-install install-module modules_install: module
- install -m 0755 -d $(DESTDIR)$(KERNEL_MODULE_DIR)
- install -m 0554 $(KERNEL_MODULE) $(DESTDIR)$(KERNEL_MODULE_DIR)
-
-TAGS:
- etags *.c *.h
-
-.PHONY: clean
-clean:
- -@$(RM) *.a *.o *.ko *~
- -@$(RM) $(VNET_DEP) .*.cmd *.mod.?
- -@$(RM) -r .tmp_versions
-
--include $(VNET_DEP)
+++ /dev/null
-# -*- mode: Makefile; -*-
-#============================================================================
-#
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-#
-# 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-1307 USA
-#============================================================================
-
-#============================================================================
-# Vnet module makefile for 2.6 series kernels.
-
-LINUX_SERIES =2.6
-include Makefile.ver
-
-KERNEL_MODULE = vnet_module.ko
-
-#----------------------------------------------------------------------------
-#export KBUILD_VERBOSE=1
-
-.PHONY: all
-all: module module_version
-
-.PHONY: module
-module modules:
- $(MAKE) -C $(KERNEL_SRC) M=`pwd` modules
-
-.PHONY: module_version
-module_version:
- $(warning Module version $(shell strings $(KERNEL_MODULE) | grep vermagic))
-
-.PHONY: install install-module modules_install
-install install-module modules_install: module
- install -m 0755 -d $(DESTDIR)$(KERNEL_MODULE_DIR)
- install -m 0554 $(KERNEL_MODULE) $(DESTDIR)$(KERNEL_MODULE_DIR)
-
-.PHONY: clean
-clean:
- -@$(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean
- -@$(RM) *.a *.o *.ko *~ .*.d .*.cmd *.mod.?
- -@$(RM) -r .tmp_versions
-
-.PHONY: TAGS
-TAGS:
- etags *.c *.h
-
+++ /dev/null
-# -*- mode: Makefile; -*-
-#============================================================================
-#
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-#
-# 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-1307 USA
-#============================================================================
-
-LINUX_SERIES?=2.6
-
-LINUX_VERSION?=$(shell (/bin/ls -d $(XEN_ROOT)/linux-$(LINUX_SERIES).* 2>/dev/null) | \
- sed -e 's!^.*linux-\(.\+\).hg!\1!' )
-
-ifeq ($(LINUX_VERSION),)
-$(error Kernel source for linux $(LINUX_SERIES) not found)
-endif
-
-KERNEL_VERSION?=$(shell (/bin/ls -d $(XEN_ROOT)/build-linux-$(LINUX_VERSION)* 2>/dev/null) | \
- grep -v -m 1 -e '-xenU' | \
- sed -e 's!^.*linux-\(.\+\)!\1!' )
-
-KERNEL_SRC ?= $(XEN_ROOT)/build-linux-$(KERNEL_VERSION)
-
-ifeq ($(KERNEL_SRC),)
-$(error Kernel source for kernel $(KERNEL_VERSION) not found)
-endif
-
-# Get the full kernel release version from its makefile, as the source path
-# may not have the extraversion, e.g. linux-2.6.12-xen0 may contain release
-# 2.6.12.6-xen0.
-KERNEL_RELEASE=$(shell make -s -C $(KERNEL_SRC) kernelrelease)
-
-KERNEL_MODULE_DIR=/lib/modules/$(KERNEL_RELEASE)/kernel
-
-$(warning KERNEL_SRC $(KERNEL_SRC))
-$(warning LINUX_VERSION $(LINUX_VERSION))
-$(warning KERNEL_VERSION $(KERNEL_VERSION))
-$(warning KERNEL_RELEASE $(KERNEL_RELEASE))
-$(warning KERNEL_MODULE_DIR $(KERNEL_MODULE_DIR))
+++ /dev/null
-# -*- mode: Makefile; -*-
-#============================================================================
-#
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-#
-# 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-1307 USA
-#============================================================================
-
-ifeq ($(src),)
-SRC_DIR=
-else
-SRC_DIR=$(src)/
-endif
-
-VNET_SRC :=
-VNET_SRC += esp.c
-VNET_SRC += etherip.c
-VNET_SRC += random.c
-VNET_SRC += sa_algorithm.c
-VNET_SRC += sa.c
-VNET_SRC += skb_context.c
-VNET_SRC += skb_util.c
-VNET_SRC += sxpr_util.c
-VNET_SRC += timer_util.c
-VNET_SRC += tunnel.c
-VNET_SRC += varp.c
-VNET_SRC += varp_socket.c
-VNET_SRC += vif.c
-VNET_SRC += vnet.c
-VNET_SRC += vnet_dev.c
-VNET_SRC += vnet_ioctl.c
-VNET_SRC += vnet_eval.c
-VNET_SRC += vnet_forward.c
-
-VNET_LIB_SRC += allocate.c
-VNET_LIB_SRC += enum.c
-VNET_LIB_SRC += hash_table.c
-VNET_LIB_SRC += iostream.c
-VNET_LIB_SRC += kernel_stream.c
-VNET_LIB_SRC += mem_stream.c
-VNET_LIB_SRC += sxpr.c
-VNET_LIB_SRC += sxpr_parser.c
-VNET_LIB_SRC += sys_net.c
-VNET_LIB_SRC += sys_string.c
-
-VNET_OBJ := $(VNET_SRC:.c=.o)
-VNET_LIB_OBJ := $(VNET_LIB_SRC:.c=.o)
-
+++ /dev/null
-/*
- * Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <asm/uaccess.h>
-
-#include <linux/init.h>
-
-#include <linux/version.h>
-
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/net.h>
-#include <linux/in.h>
-#include <linux/inet.h>
-
-#include <net/ip.h>
-#include <net/protocol.h>
-#include <net/route.h>
-
-#include <linux/if_ether.h>
-#include <linux/icmp.h>
-
-#include <asm/scatterlist.h>
-#include <linux/crypto.h>
-#include <linux/pfkeyv2.h>
-#include <linux/random.h>
-
-#include <esp.h>
-#include <sa.h>
-#include <sa_algorithm.h>
-#include <tunnel.h>
-#include <vnet.h>
-#include <skb_util.h>
-#include <skb_context.h>
-
-static const int DEBUG_ICV = 0;
-
-#define MODULE_NAME "IPSEC"
-#define DEBUG 1
-#undef DEBUG
-#include "debug.h"
-
-#ifndef CONFIG_CRYPTO_HMAC
-#warning No esp transform - CONFIG_CRYPTO_HMAC not defined
-
-int __init esp_module_init(void){
- return 0;
-}
-
-void __exit esp_module_exit(void){
-}
-
-#else
-
-/* Outgoing packet: [ eth | ip | data ]
- * After etherip: [ eth2 | ip2 | ethip | eth | ip | data ]
- * After esp : [ eth2 | ip2 | esp | {ethip | eth | ip | data} | pad | icv ]
- * ^ +
- * The curly braces { ... } denote encryption.
- * The esp header includes the fixed esp headers and the iv (variable size).
- * The point marked ^ does not move. To the left is in the header, to the right
- * is in the frag. Remember that all outgoing skbs (from domains) have 1 frag.
- * Data after + is added by esp, using an extra frag.
- *
- * Incoming as above.
- * After decrypt: [ eth2 | ip2 | esp | ethip | eth | ip | data | pad | icv ]
- * Trim tail: [ eth2 | ip2 | esp | ethip | eth | ip | data ]
- * Drop hdr: [ eth2 | ip2 | ethip | eth | ip | data ]
- * ^
- * The point marked ^ does not move. Incoming skbs are linear (no frags).
- * The tail is trimmed by adjusting skb->tail and len.
- * The esp hdr is dropped by using memmove to move the headers and
- * adjusting the skb pointers.
- *
- * todo: Now this code is in linux we can't assume 1 frag for outbound skbs,
- * or (maybe) that memmove is safe on inbound.
- */
-
-/** Round n up to a multiple of block.
- * If block is less than 2 does nothing.
- * Otherwise assume block is a power of 2.
- *
- * @param n to round up
- * @param block size to round to a multiple of
- * @return rounded value
- */
-static inline int roundupto(int n, int block){
- if(block <= 1) return n;
- block--;
- return (n + block) & ~block;
-}
-
-/** Check if n is a multiple of block.
- * If block is less than 2 returns 1.
- * Otherwise assumes block is a power of 2.
- *
- * @param n to check
- * @param block block size
- * @return 1 if a multiple, 0 otherwise
- */
-static inline int multipleof(int n, int block){
- if(block <= 1) return 1;
- block--;
- return !(n & block);
-}
-
-/** Convert from bits to bytes.
- *
- * @param n number of bits
- * @return number of bytes
- */
-static inline int bits_to_bytes(int n){
- return n / 8;
-}
-
-
-/** Insert esp padding at the end of an skb.
- * Inserts padding bytes, number of padding bytes, protocol number.
- *
- * @param skb skb
- * @param offset offset from skb end to where padding should end
- * @param extra_n total amount of padding
- * @param protocol protocol number (from original ip hdr)
- * @return 0 on success, error code otherwise
- */
-static int esp_sa_pad(struct sk_buff *skb, int offset, int extra_n,
- unsigned char protocol){
- int err;
- char *data;
- int pad_n = extra_n - ESP_PAD_N;
- int i;
- char buf[extra_n];
-
- data = buf;
- for(i = 1; i <= pad_n; i++){
- *data++ = i;
- }
- *data++ = pad_n;
- *data++ = protocol;
- err = skb_put_bits(skb, skb->len - offset - extra_n, buf, extra_n);
- return err;
-}
-
-/** Encrypt skb. Skips esp header and iv.
- * Assumes skb->data points at esp header.
- *
- * @param esp esp state
- * @parm esph esp header
- * @param skb packet
- * @param head_n size of esp header and iv
- * @param iv_n size of iv
- * @param text_n size of ciphertext
- * @return 0 on success, error code otherwise
- */
-static int esp_sa_encrypt(ESPState *esp, ESPHdr *esph, struct sk_buff *skb,
- int head_n, int iv_n, int text_n){
- int err = 0;
- int sg_n = skb_shinfo(skb)->nr_frags + 1;
- struct scatterlist sg[sg_n];
-
- err = skb_scatterlist(skb, sg, &sg_n, head_n, text_n);
- if(err) goto exit;
- if(iv_n){
- crypto_cipher_set_iv(esp->cipher.tfm, esp->cipher.iv, iv_n);
- }
- crypto_cipher_encrypt(esp->cipher.tfm, sg, sg, text_n);
- if(iv_n){
- memcpy(esph->data, esp->cipher.iv, iv_n);
- crypto_cipher_get_iv(esp->cipher.tfm, esp->cipher.iv, iv_n);
- }
- exit:
- return err;
-}
-
-/** Decrypt skb. Skips esp header and iv.
- * Assumes skb->data points at esp header.
- *
- * @param esp esp state
- * @parm esph esp header
- * @param skb packet
- * @param head_n size of esp header and iv
- * @param iv_n size of iv
- * @param text_n size of ciphertext
- * @return 0 on success, error code otherwise
- */
-static int esp_sa_decrypt(ESPState *esp, ESPHdr *esph, struct sk_buff *skb,
- int head_n, int iv_n, int text_n){
- int err = 0;
- int sg_n = skb_shinfo(skb)->nr_frags + 1;
- struct scatterlist sg[sg_n];
-
- err = skb_scatterlist(skb, sg, &sg_n, head_n, text_n);
- if(err) goto exit;
- if(iv_n){
- crypto_cipher_set_iv(esp->cipher.tfm, esph->data, iv_n);
- }
- crypto_cipher_decrypt(esp->cipher.tfm, sg, sg, text_n);
- exit:
- return err;
-}
-
-/** Compute icv. Includes esp header, iv and ciphertext.
- * Assumes skb->data points at esp header.
- *
- * @param esp esp state
- * @param skb packet
- * @param digest_n number of bytes to digest
- * @param icv_n size of icv
- * @return 0 on success, error code otherwise
- */
-static int esp_sa_digest(ESPState *esp, struct sk_buff *skb, int digest_n, int icv_n){
- int err = 0;
- u8 icv[icv_n];
-
- if(DEBUG_ICV){
- dprintf("> skb digest_n=%d icv_n=%d\n", digest_n, icv_n);
- skb_print_bits("esp", skb, 0, digest_n);
- }
- memset(icv, 0, icv_n);
- esp->digest.icv(esp, skb, 0, digest_n, icv);
- skb_put_bits(skb, digest_n, icv, icv_n);
- return err;
-}
-
-/** Check the icv and trim it from the skb tail.
- *
- * @param sa sa state
- * @param esp esp state
- * @param esph esp header
- * @param skb packet
- * @return 0 on success, error code otherwise
- */
-static int esp_check_icv(SAState *sa, ESPState *esp, ESPHdr *esph, struct sk_buff *skb){
- int err = 0;
- int icv_n = esp->digest.icv_n;
- int digest_n = skb->len - icv_n;
- u8 icv_skb[icv_n];
- u8 icv_new[icv_n];
-
- dprintf(">\n");
- if(DEBUG_ICV){
- dprintf("> skb len=%d digest_n=%d icv_n=%d\n",
- skb->len, digest_n, icv_n);
- skb_print_bits("esp", skb, 0, skb->len);
- }
- if(skb_copy_bits(skb, digest_n, icv_skb, icv_n)){
- wprintf("> Error getting icv from skb\n");
- goto exit;
- }
- esp->digest.icv(esp, skb, 0, digest_n, icv_new);
- if(DEBUG_ICV){
- dprintf("> len=%d icv_n=%d", digest_n, icv_n);
- printk("\nskb="); buf_print(icv_skb, icv_n);
- printk("new="); buf_print(icv_new, icv_n);
- }
- if(unlikely(memcmp(icv_new, icv_skb, icv_n))){
- wprintf("> ICV check failed!\n");
- err = -EINVAL;
- sa->counts.integrity_failures++;
- goto exit;
- }
- skb_trim_tail(skb, icv_n);
- exit:
- dprintf("< err=%d\n", err);
- return err;
-}
-
-/** Send a packet via an ESP SA.
- *
- * @param sa SA state
- * @param skb packet to send
- * @param tunnel underlying tunnel
- * @return 0 on success, negative error code otherwise
- */
-static int esp_sa_send(SAState *sa, struct sk_buff *skb, Tunnel *tunnel){
- int err = 0;
- int ip_n; // Size of ip header.
- int plaintext_n; // Size of plaintext.
- int ciphertext_n; // Size of ciphertext (including padding).
- int extra_n; // Extra bytes needed for ciphertext.
- int icv_n = 0; // Size of integrity check value (icv).
- int iv_n = 0; // Size of initialization vector (iv).
- int head_n; // Size of esp header and iv.
- int tail_n; // Size of esp trailer: padding and icv.
- ESPState *esp;
- ESPHdr *esph;
-
- dprintf(">\n");
- esp = sa->data;
- ip_n = (skb->nh.iph->ihl << 2);
- // Assuming skb->data points at ethernet header, exclude ethernet
- // header and IP header.
- plaintext_n = skb->len - ETH_HLEN - ip_n;
- // Add size of padding fields.
- ciphertext_n = roundupto(plaintext_n + ESP_PAD_N, esp->cipher.block_n);
- if(esp->cipher.pad_n > 0){
- ciphertext_n = roundupto(ciphertext_n, esp->cipher.pad_n);
- }
- extra_n = ciphertext_n - plaintext_n;
- iv_n = esp->cipher.iv_n;
- icv_n = esp->digest.icv_n;
- dprintf("> len=%d plaintext=%d ciphertext=%d extra=%d\n",
- skb->len, plaintext_n, ciphertext_n, extra_n);
- dprintf("> iv=%d icv=%d\n", iv_n, icv_n);
- skb_print_bits("iv", skb, 0, skb->len);
-
- // Add headroom for esp header and iv, tailroom for the ciphertext
- // and icv.
- head_n = ESP_HDR_N + iv_n;
- tail_n = extra_n + icv_n;
- err = skb_make_room(&skb, skb, head_n, tail_n);
- if(err) goto exit;
- dprintf("> skb=%p\n", skb);
- // Move the headers up to make space for the esp header. We can
- // use memmove() since all this data fits in the skb head.
- // todo: Can't assume this anymore?
- dprintf("> header push...\n");
- __skb_push(skb, head_n);
- if(0 && skb->mac.raw){
- dprintf("> skb->mac=%p\n", skb->mac.raw);
- dprintf("> ETH header pull...\n");
- memmove(skb->data, skb->mac.raw, ETH_HLEN);
- skb->mac.raw = skb->data;
- skb_pull_vn(skb, ETH_HLEN);
- }
- dprintf("> IP header pull...\n");
- memmove(skb->data, skb->nh.raw, ip_n);
- skb->nh.raw = skb->data;
- skb_pull_vn(skb, ip_n);
- esph = (void*)skb->data;
- // Add spi and sequence number.
- esph->spi = sa->ident.spi;
- esph->seq = htonl(++sa->replay.send_seq);
- // Insert the padding bytes: extra bytes less the pad fields
- // themselves.
- dprintf("> esp_sa_pad ...\n");
- esp_sa_pad(skb, icv_n, extra_n, skb->nh.iph->protocol);
- if(sa->security & SA_CONF){
- dprintf("> esp_sa_encrypt...\n");
- err = esp_sa_encrypt(esp, esph, skb, head_n, iv_n, ciphertext_n);
- if(err) goto exit;
- }
- if(icv_n){
- dprintf("> esp_sa_digest...\n");
- err = esp_sa_digest(esp, skb, head_n + ciphertext_n, icv_n);
- if(err) goto exit;
- }
- dprintf("> IP header push...\n");
- __skb_push(skb, ip_n);
- if(0 && skb->mac.raw){
- dprintf("> ETH header push...\n");
- __skb_push(skb, ETH_HLEN);
- }
- // Fix ip header. Adjust length field, set protocol, zero
- // checksum.
- {
- // Total packet length (bytes).
- int tot_len = ntohs(skb->nh.iph->tot_len);
- tot_len += head_n;
- tot_len += tail_n;
- skb->nh.iph->protocol = IPPROTO_ESP;
- skb->nh.iph->tot_len = htons(tot_len);
- skb->nh.iph->check = 0;
- }
- err = Tunnel_send(tunnel, skb);
- exit:
- dprintf("< err=%d\n", err);
- return err;
-}
-
-/** Release an skb context.
- * Drops the refcount on the SA.
- *
- * @param context to free
- */
-static void esp_context_free_fn(SkbContext *context){
- SAState *sa;
- if(!context) return;
- sa = context->data;
- if(!sa) return;
- context->data = NULL;
- SAState_decref(sa);
-}
-
-/** Receive a packet via an ESP SA.
- * Does ESP receive processing (check icv, decrypt), strips
- * ESP header and re-receives.
- *
- * If return 1 the packet has been freed.
- * If return <= 0 the caller must free.
- *
- * @param sa SA
- * @param skb packet
- * @return >= 0 on success, negative protocol otherwise
- */
-static int esp_sa_recv(SAState *sa, struct sk_buff *skb){
- int err = -EINVAL;
- int mine = 0;
- int vnet = 0; //todo: fixme - need to record skb vnet somewhere
- ESPState *esp;
- ESPHdr *esph;
- ESPPadding *pad;
- int block_n; // Cipher blocksize.
- int icv_n; // Size of integrity check value (icv).
- int iv_n; // Size of initialization vector (iv).
- int text_n; // Size of text (ciphertext or plaintext).
- int head_n; // Size of esp header and iv.
-
- dprintf("> skb=%p\n", skb);
- // Assumes skb->data points at esp hdr.
- esph = (void*)skb->data;
- esp = sa->data;
- block_n = crypto_tfm_alg_blocksize(esp->cipher.tfm);
- icv_n = esp->digest.icv_n;
- iv_n = esp->cipher.iv_n;
- head_n = ESP_HDR_N + iv_n;
- text_n = skb->len - head_n - icv_n;
- if(text_n < ESP_PAD_N || !multipleof(text_n, block_n)){
- wprintf("> Invalid size: text_n=%d tfm:block_n=%d esp:block_n=%d\n",
- text_n, block_n, esp->cipher.block_n);
- goto exit;
- }
- if(icv_n){
- err = esp_check_icv(sa, esp, esph, skb);
- if(err) goto exit;
- }
- mine = 1;
- if(sa->security & SA_CONF){
- err = esp_sa_decrypt(esp, esph, skb, head_n, iv_n, text_n);
- if(err) goto exit;
- }
- // Strip esp header by moving the other headers down.
- //todo Maybe not safe to do this anymore.
- memmove(skb->mac.raw + head_n, skb->mac.raw, (skb->data - skb->mac.raw));
- skb->mac.raw += head_n;
- skb->nh.raw += head_n;
- // Move skb->data back to ethernet header.
- // Do in 2 moves to ensure offsets are +ve,
- // since args to skb_pull/skb_push are unsigned.
- skb_pull_vn(skb, head_n);
- __skb_push(skb, skb->data - skb->mac.raw);
- // After this esph is invalid.
- esph = NULL;
- // Trim padding, restore protocol in IP header.
- pad = skb_trim_tail(skb, ESP_PAD_N);
- text_n -= ESP_PAD_N;
- if((pad->pad_n > 255) | (pad->pad_n > text_n)){
- wprintf("> Invalid padding: pad_n=%d text_n=%d\n", pad->pad_n, text_n);
- goto exit;
- }
- skb_trim_tail(skb, pad->pad_n);
- skb->nh.iph->protocol = pad->protocol;
- err = skb_push_context(skb, vnet, sa->ident.addr, IPPROTO_ESP,
- sa, esp_context_free_fn);
- if(err) goto exit;
- // Increase sa refcount now the skb context refers to it.
- // Refcount is decreased by esp_context_free_fn.
- SAState_incref(sa);
- // Deliver skb to be received by network code.
- // Not safe to refer to the skb after this.
- // todo: return -skb->nh.iph->protocol instead?
- netif_rx(skb);
- exit:
- if(mine){
- if(err < 0){
- kfree_skb(skb);
- }
- err = 1;
- }
- dprintf("< skb=%p err=%d\n", skb, err);
- return err;
-}
-
-/** Estimate the packet size for some data using ESP processing.
- *
- * @param sa ESP SA
- * @param data_n data size
- * @return size after ESP processing
- */
-static u32 esp_sa_size(SAState *sa, int data_n){
- // Even in transport mode have to round up to blocksize.
- // Have to add some padding for alignment even if pad_n is zero.
- ESPState *esp = sa->data;
-
- data_n = roundupto(data_n + ESP_PAD_N, esp->cipher.block_n);
- if(esp->cipher.pad_n > 0){
- data_n = roundupto(data_n, esp->cipher.pad_n);
- }
- data_n += esp->digest.icv_n;
- //data_n += esp->cipher.iv_n;
- data_n += ESP_HDR_N;
- return data_n;
-}
-
-/** Compute an icv using HMAC digest.
- *
- * @param esp ESP state
- * @param skb packet to digest
- * @param offset offset to start at
- * @param len number of bytes to digest
- * @param icv return parameter for ICV
- * @return 0 on success, negative error code otherwise
- */
-static inline void esp_hmac_digest(ESPState *esp, struct sk_buff *skb,
- int offset, int len, u8 *icv){
- int err = 0;
- struct crypto_tfm *digest = esp->digest.tfm;
- char *icv_tmp = esp->digest.icv_tmp;
- int sg_n = skb_shinfo(skb)->nr_frags + 1;
- struct scatterlist sg[sg_n];
-
- dprintf("> offset=%d len=%d\n", offset, len);
- memset(icv, 0, esp->digest.icv_n);
- if(DEBUG_ICV){
- dprintf("> key len=%d\n", esp->digest.key_n);
- printk("\nkey=");
- buf_print(esp->digest.key,esp->digest.key_n);
- }
- crypto_hmac_init(digest, esp->digest.key, &esp->digest.key_n);
- err = skb_scatterlist(skb, sg, &sg_n, offset, len);
- crypto_hmac_update(digest, sg, sg_n);
- crypto_hmac_final(digest, esp->digest.key, &esp->digest.key_n, icv_tmp);
- if(DEBUG_ICV){
- dprintf("> digest len=%d ", esp->digest.icv_n);
- printk("\nval=");
- buf_print(icv_tmp, esp->digest.icv_n);
- }
- memcpy(icv, icv_tmp, esp->digest.icv_n);
- dprintf("<\n");
-}
-
-/** Finish up an esp state.
- * Releases the digest, cipher, iv and frees the state.
- *
- * @parma esp state
- */
-static void esp_fini(ESPState *esp){
- if(!esp) return;
- if(esp->digest.tfm){
- crypto_free_tfm(esp->digest.tfm);
- esp->digest.tfm = NULL;
- }
- if(esp->digest.icv_tmp){
- kfree(esp->digest.icv_tmp);
- esp->digest.icv_tmp = NULL;
- }
- if(esp->cipher.tfm){
- crypto_free_tfm(esp->cipher.tfm);
- esp->cipher.tfm = NULL;
- }
- if(esp->cipher.iv){
- kfree(esp->cipher.iv);
- esp->cipher.iv = NULL;
- }
- kfree(esp);
-}
-
-/** Release an ESP SA.
- *
- * @param sa ESO SA
- */
-static void esp_sa_fini(SAState *sa){
- ESPState *esp;
- if(!sa) return;
- esp = sa->data;
- if(!esp) return;
- esp_fini(esp);
- sa->data = NULL;
-}
-
-/** Initialize the cipher for an ESP SA.
- *
- * @param sa ESP SA
- * @param esp ESP state
- * @return 0 on success, negative error code otherwise
- */
-static int esp_cipher_init(SAState *sa, ESPState *esp){
- int err = 0;
- SAAlgorithm *algo = NULL;
- int cipher_mode = CRYPTO_TFM_MODE_CBC;
-
- dprintf("> sa=%p esp=%p\n", sa, esp);
- dprintf("> cipher=%s\n", sa->cipher.name);
- algo = sa_cipher_by_name(sa->cipher.name);
- if(!algo){
- wprintf("> Cipher unavailable: %s\n", sa->cipher.name);
- err = -EINVAL;
- goto exit;
- }
- esp->cipher.key_n = roundupto(sa->cipher.bits, 8);
- // If cipher is null must use ECB because CBC algo does not support blocksize 1.
- if(strcmp(sa->cipher.name, "cipher_null")){
- cipher_mode = CRYPTO_TFM_MODE_ECB;
- }
- esp->cipher.tfm = crypto_alloc_tfm(sa->cipher.name, cipher_mode);
- if(!esp->cipher.tfm){
- err = -ENOMEM;
- goto exit;
- }
- esp->cipher.block_n = roundupto(crypto_tfm_alg_blocksize(esp->cipher.tfm), 4);
- esp->cipher.iv_n = crypto_tfm_alg_ivsize(esp->cipher.tfm);
- esp->cipher.pad_n = 0;
- if(esp->cipher.iv_n){
- esp->cipher.iv = kmalloc(esp->cipher.iv_n, GFP_KERNEL);
- get_random_bytes(esp->cipher.iv, esp->cipher.iv_n);
- }
- crypto_cipher_setkey(esp->cipher.tfm, esp->cipher.key, esp->cipher.key_n);
- err = 0;
- exit:
- dprintf("< err=%d\n", err);
- return err;
-}
-
-/** Initialize the digest for an ESP SA.
- *
- * @param sa ESP SA
- * @param esp ESP state
- * @return 0 on success, negative error code otherwise
- */
-static int esp_digest_init(SAState *sa, ESPState *esp){
- int err = 0;
- SAAlgorithm *algo = NULL;
-
- dprintf(">\n");
- esp->digest.key = sa->digest.key;
- esp->digest.key_n = bits_to_bytes(roundupto(sa->digest.bits, 8));
- esp->digest.tfm = crypto_alloc_tfm(sa->digest.name, 0);
- if(!esp->digest.tfm){
- err = -ENOMEM;
- goto exit;
- }
- algo = sa_digest_by_name(sa->digest.name);
- if(!algo){
- wprintf("> Digest unavailable: %s\n", sa->digest.name);
- err = -EINVAL;
- goto exit;
- }
- esp->digest.icv = esp_hmac_digest;
- esp->digest.icv_full_n = bits_to_bytes(algo->info.digest.icv_fullbits);
- esp->digest.icv_n = bits_to_bytes(algo->info.digest.icv_truncbits);
-
- if(esp->digest.icv_full_n != crypto_tfm_alg_digestsize(esp->digest.tfm)){
- err = -EINVAL;
- wprintf("> digest %s, size %u != %hu\n",
- sa->digest.name,
- crypto_tfm_alg_digestsize(esp->digest.tfm),
- esp->digest.icv_full_n);
- goto exit;
- }
-
- esp->digest.icv_tmp = kmalloc(esp->digest.icv_full_n, GFP_KERNEL);
- if(!esp->digest.icv_tmp){
- err = -ENOMEM;
- goto exit;
- }
- exit:
- dprintf("< err=%d\n", err);
- return err;
-}
-
-/** Initialize an ESP SA.
- *
- * @param sa ESP SA
- * @param args arguments
- * @return 0 on success, negative error code otherwise
- */
-static int esp_sa_init(SAState *sa, void *args){
- int err = 0;
- ESPState *esp = NULL;
-
- dprintf("> sa=%p\n", sa);
- esp = kmalloc(sizeof(*esp), GFP_KERNEL);
- if(!esp){
- err = -ENOMEM;
- goto exit;
- }
- *esp = (ESPState){};
- err = esp_cipher_init(sa, esp);
- if(err) goto exit;
- err = esp_digest_init(sa, esp);
- if(err) goto exit;
- sa->data = esp;
- exit:
- if(err){
- if(esp) esp_fini(esp);
- }
- dprintf("< err=%d\n", err);
- return err;
-}
-
-/** SA type for ESP.
- */
-static SAType esp_sa_type = {
- .name = "ESP",
- .protocol = IPPROTO_ESP,
- .init = esp_sa_init,
- .fini = esp_sa_fini,
- .size = esp_sa_size,
- .recv = esp_sa_recv,
- .send = esp_sa_send
-};
-
-/** Get the ESP header from a packet.
- *
- * @param skb packet
- * @param esph return parameter for header
- * @return 0 on success, negative error code otherwise
- */
-static int esp_skb_header(struct sk_buff *skb, ESPHdr **esph){
- int err = 0;
- if(skb->len < ESP_HDR_N){
- err = -EINVAL;
- goto exit;
- }
- *esph = (ESPHdr*)skb->data;
- exit:
- return err;
-}
-
-/** Handle an incoming skb with ESP protocol.
- *
- * Lookup spi, if state found hand to the state.
- * If no state, check spi, if ok, create state and pass to it.
- * If spi not ok, drop.
- *
- * Return value convention for protocols:
- * >= 0 Protocol took the packet
- * < 0 A -ve protocol id the packet should be re-received as.
- *
- * So always return >=0 if we took the packet, even if we dropped it.
- *
- * @param skb packet
- * @return 0 on sucess, negative protocol number otherwise
- */
-static int esp_protocol_recv(struct sk_buff *skb){
- int err = 0;
- const int eth_n = ETH_HLEN;
- int ip_n;
- ESPHdr *esph = NULL;
- SAState *sa = NULL;
- u32 addr;
-
- dprintf(">\n");
-#ifdef DEBUG
- dprintf("> recv skb=\n");
- skb_print_bits("", skb, 0, skb->len);
-#endif
- ip_n = (skb->nh.iph->ihl << 2);
- if(skb->data == skb->mac.raw){
- // skb->data points at ethernet header.
- if (!pskb_may_pull(skb, eth_n + ip_n)){
- wprintf("> Malformed skb\n");
- err = -EINVAL;
- goto exit;
- }
- skb_pull_vn(skb, eth_n + ip_n);
- }
- addr = skb->nh.iph->daddr;
- err = esp_skb_header(skb, &esph);
- if(err) goto exit;
- dprintf("> spi=%08x protocol=%d addr=" IPFMT "\n",
- esph->spi, IPPROTO_ESP, NIPQUAD(addr));
- sa = sa_table_lookup_spi(esph->spi, IPPROTO_ESP, addr);
- if(!sa){
- err = vnet_sa_create(esph->spi, IPPROTO_ESP, addr, &sa);
- if(err) goto exit;
- }
- //todo: Return a -ve protocol instead? See esp_sa_recv.
- err = SAState_recv(sa, skb);
- exit:
- if(sa) SAState_decref(sa);
- if(err <= 0){
- kfree_skb(skb);
- err = 0;
- }
- dprintf("< err=%d\n", err);
- return err;
-}
-
-/** Handle an ICMP error related to ESP.
- *
- * @param skb ICMP error packet
- * @param info
- */
-static void esp_protocol_icmp_err(struct sk_buff *skb, u32 info){
- struct iphdr *iph = (struct iphdr*)skb->data;
- ESPHdr *esph;
- SAState *sa;
-
- dprintf("> ICMP error type=%d code=%d\n",
- skb->h.icmph->type, skb->h.icmph->code);
- if(skb->h.icmph->type != ICMP_DEST_UNREACH ||
- skb->h.icmph->code != ICMP_FRAG_NEEDED){
- return;
- }
-
- //todo: need to check skb has enough len to do this.
- esph = (ESPHdr*)(skb->data + (iph->ihl << 2));
- sa = sa_table_lookup_spi(esph->spi, IPPROTO_ESP, iph->daddr);
- if(!sa) return;
- wprintf("> ICMP unreachable on SA ESP spi=%08x addr=" IPFMT "\n",
- ntohl(esph->spi), NIPQUAD(iph->daddr));
- SAState_decref(sa);
-}
-
-//============================================================================
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-// Code for 2.6 kernel.
-
-/** Protocol handler for ESP.
- */
-static struct net_protocol esp_protocol = {
- .handler = esp_protocol_recv,
- .err_handler = esp_protocol_icmp_err
-};
-
-static int esp_protocol_add(void){
- return inet_add_protocol(&esp_protocol, IPPROTO_ESP);
-}
-
-static int esp_protocol_del(void){
- return inet_del_protocol(&esp_protocol, IPPROTO_ESP);
-}
-
-//============================================================================
-#else
-//============================================================================
-// Code for 2.4 kernel.
-
-/** Protocol handler for ESP.
- */
-static struct inet_protocol esp_protocol = {
- .name = "ESP",
- .protocol = IPPROTO_ESP,
- .handler = esp_protocol_recv,
- .err_handler = esp_protocol_icmp_err
-};
-
-static int esp_protocol_add(void){
- inet_add_protocol(&esp_protocol);
- return 0;
-}
-
-static int esp_protocol_del(void){
- return inet_del_protocol(&esp_protocol);
-}
-
-#endif
-//============================================================================
-
-
-/** Initialize the ESP module.
- * Registers the ESP protocol and SA type.
- *
- * @return 0 on success, negative error code otherwise
- */
-int __init esp_module_init(void){
- int err = 0;
- dprintf(">\n");
- err = SAType_add(&esp_sa_type);
- if(err < 0){
- eprintf("> Error adding esp sa type\n");
- goto exit;
- }
- esp_protocol_add();
- exit:
- dprintf("< err=%d\n", err);
- return err;
-}
-
-/** Finalize the ESP module.
- * Deregisters the ESP protocol and SA type.
- */
-void __exit esp_module_exit(void){
- if(esp_protocol_del() < 0){
- eprintf("> Error removing esp protocol\n");
- }
- if(SAType_del(&esp_sa_type) < 0){
- eprintf("> Error removing esp sa type\n");
- }
-}
-
-#endif // CONFIG_CRYPTO_HMAC
+++ /dev/null
-/*
- * Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-#ifndef __VNET_ESP_H__
-#define __VNET_ESP_H__
-
-#ifdef __KERNEL__
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/crypto.h>
-
-#else
-
-#include "sys_kernel.h"
-
-struct crypto_tfm;
-
-#endif
-
-/** Header used by IPSEC ESP (Encapsulated Security Payload). */
-typedef struct ESPHdr {
- /** The spi (security parameters index). */
- u32 spi;
- /** Sequence number. */
- u32 seq;
- /* Variable length data (depends on crypto suite).
- Mind the 64 bit alignment! */
- u8 data[0];
-} ESPHdr;
-
-/** Padding trailer used by IPSEC ESP.
- * Follows the padding itself with the padding length and the
- * protocol being encapsulated.
- */
-typedef struct ESPPadding {
- u8 pad_n;
- u8 protocol;
-} ESPPadding;
-
-/** Size of the esp header (spi and seq). */
-static const int ESP_HDR_N = sizeof(ESPHdr);
-
-/** Size of the esp pad and next protocol field. */
-static const int ESP_PAD_N = sizeof(ESPPadding);
-
-enum {
- SASTATE_VOID,
- SASTATE_ACQUIRE,
- SASTATE_VALID,
- SASTATE_ERROR,
- SASTATE_EXPIRED,
- SASTATE_DEAD,
-};
-
-struct ESPState;
-
-/** A cipher instance. */
-typedef struct ESPCipher {
- /** Cipher key. */
- u8 *key;
- /** Key size (bytes). */
- int key_n;
- /** Initialization vector (IV). */
- u8 *iv;
- /** IV size (bytes). */
- int iv_n;
- /** Block size for padding (bytes). */
- int pad_n;
- /** Cipher block size (bytes). */
- int block_n;
- /** Cipher crypto transform. */
- struct crypto_tfm *tfm;
-} ESPCipher;
-
-/** A digest instance. */
-typedef struct ESPDigest {
- /** Digest key. */
- u8 *key;
- /** Key size (bytes) */
- int key_n;
- /** ICV size used (bytes). */
- u8 icv_n;
- /** Full ICV size when computed (bytes). */
- u8 icv_full_n;
- /** Working storage for computing ICV. */
- u8 *icv_tmp;
- /** Function used to compute ICV (e.g. HMAC). */
- void (*icv)(struct ESPState *esp,
- struct sk_buff *skb,
- int offset,
- int len,
- u8 *icv);
- /** Digest crypto transform (e.g. SHA). */
- struct crypto_tfm *tfm;
-} ESPDigest;
-
-typedef struct ESPState {
- struct ESPCipher cipher;
- struct ESPDigest digest;
-} ESPState;
-
-extern int esp_module_init(void);
-extern void esp_module_exit(void);
-
-#endif /* !__VNET_ESP_H__ */
+++ /dev/null
-/*
- * Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-#ifdef __KERNEL__
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <linux/version.h>
-
-#include <linux/skbuff.h>
-#include <linux/net.h>
-#include <linux/netdevice.h>
-#include <linux/in.h>
-#include <linux/inet.h>
-#include <linux/netfilter_bridge.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/icmp.h>
-#include <linux/udp.h>
-
-#include <net/ip.h>
-#include <net/protocol.h>
-#include <net/route.h>
-#include <net/checksum.h>
-
-#else
-
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include "sys_kernel.h"
-#include "spinlock.h"
-#include "skbuff.h"
-#include <linux/ip.h>
-#include <linux/udp.h>
-
-#define IP_DF 0x4000 /* Flag: "Don't Fragment" */
-
-#endif
-
-#include <etherip.h>
-#include <tunnel.h>
-#include <vnet.h>
-#include <varp.h>
-#include <if_varp.h>
-#include <varp.h>
-#include <skb_util.h>
-#include <skb_context.h>
-
-#define MODULE_NAME "VNET"
-#define DEBUG 1
-#undef DEBUG
-#include "debug.h"
-
-/** @file Etherip implementation.
- * The etherip protocol is used to transport Ethernet frames in IP packets.
- */
-
-/** Flag controlling whether to use etherip-in-udp encapsulation.
- * If false we send etherip protocol in IP packets.
- * If true we send etherip protocol in UDP packets with a vnet header.
- */
-int etherip_in_udp = 1;
-
-/** Get the vnet label from an etherip header.
- *
- * @param hdr header
- * @@param vnet (in net order)
- */
-void etheriphdr_get_vnet(struct etheriphdr *hdr, VnetId *vnet){
-#ifdef CONFIG_ETHERIP_EXT
- *vnet = *(VnetId*)hdr->vnet;
-#else
- *vnet = (VnetId){};
- vnet->u.vnet16[VNET_SIZE16 - 1] = (unsigned short)hdr->reserved;
-
-#endif
-}
-
-/** Set the vnet label in an etherip header.
- * Also sets the etherip version.
- *
- * @param hdr header
- * @param vnet vnet label (in net order)
- */
-void etheriphdr_set_vnet(struct etheriphdr *hdr, VnetId *vnet){
-#ifdef CONFIG_ETHERIP_EXT
- hdr->version = ETHERIP_VERSION;
- *(VnetId*)hdr->vnet = *vnet;
-#else
- hdr->version = ETHERIP_VERSION;
- hdr->reserved = (vnet->u.vnet16[VNET_SIZE16 - 1] & 0x0fff);
-#endif
-}
-
-/** Open an etherip tunnel.
- *
- * @param tunnel to open
- * @return 0 on success, error code otherwise
- */
-static int etherip_tunnel_open(Tunnel *tunnel){
- return 0;
-}
-
-/** Close an etherip tunnel.
- *
- * @param tunnel to close
- */
-static void etherip_tunnel_close(Tunnel *tunnel){
-}
-
-
-static inline int skb_make_headroom(struct sk_buff **pskb, struct sk_buff *skb, int head_n){
- int err = 0;
- dprintf("> skb=%p headroom=%d head_n=%d\n", skb, skb_headroom(skb), head_n);
- if(head_n > skb_headroom(skb) || skb_cloned(skb) || skb_shared(skb)){
- // Expand header the way GRE does.
- struct sk_buff *new_skb = skb_realloc_headroom(skb, head_n + 16);
- if(!new_skb){
- err = -ENOMEM;
- goto exit;
- }
- kfree_skb(skb);
- *pskb = new_skb;
- } else {
- *pskb = skb;
- }
- exit:
- return err;
-}
-
-/** Send a packet via an etherip tunnel.
- * Adds etherip header and new ip header around ethernet frame.
- *
- * @param tunnel tunnel
- * @param skb packet
- * @return 0 on success, error code otherwise
- */
-static int etherip_tunnel_send(Tunnel *tunnel, struct sk_buff *skb){
- int err = 0;
- const int ip_n = sizeof(struct iphdr);
- const int etherip_n = sizeof(struct etheriphdr);
- const int udp_n = sizeof(struct udphdr);
- const int vnet_n = sizeof(struct VnetMsgHdr);
- int head_n = etherip_n + ip_n /* + ETH_HLEN */;
- VnetId *vnet = &tunnel->key.vnet;
- struct etheriphdr *etheriph;
- u32 saddr = 0;
-
- if(etherip_in_udp){
- head_n += vnet_n + udp_n;
- }
- err = skb_make_headroom(&skb, skb, head_n);
- if(err) goto exit;
-
- // Null the pointer as we are pushing a new IP header.
- skb->mac.raw = NULL;
-
- // Setup the etherip header.
- etheriph = (void*)skb_push(skb, etherip_n);
- etheriphdr_set_vnet(etheriph, vnet);
-
- if(etherip_in_udp){
- // Vnet header.
- struct VnetMsgHdr *vhdr = (void*)skb_push(skb, vnet_n);
- vhdr->id = htons(VUDP_ID);
- vhdr->opcode = 0;
-
- // Setup the UDP header.
- skb->h.raw = skb_push(skb, udp_n);
- skb->h.uh->source = varp_port; // Source port.
- skb->h.uh->dest = varp_port; // Destination port.
- skb->h.uh->len = htons(skb->len); // Total packet length (bytes).
- skb->h.uh->check = 0;
- }
-
- // Setup the IP header.
- skb->nh.raw = skb_push(skb, ip_n);
- skb->nh.iph->version = 4; // Standard version.
- skb->nh.iph->ihl = ip_n / 4; // IP header length (32-bit words).
- skb->nh.iph->tos = 0; // No special type-of-service.
- skb->nh.iph->tot_len = htons(skb->len); // Total packet length (bytes).
- skb->nh.iph->id = 0; // No flow id (since no frags).
- if(etherip_in_udp){
- skb->nh.iph->protocol = IPPROTO_UDP; // IP protocol number.
- skb->nh.iph->frag_off = 0;
- } else {
- skb->nh.iph->protocol = IPPROTO_ETHERIP;// IP protocol number.
- skb->nh.iph->frag_off = htons(IP_DF); // Don't fragment - can't handle frags.
- }
- skb->nh.iph->ttl = 64; // Linux default time-to-live.
- skb->nh.iph->saddr = saddr; // Source address.
- skb->nh.iph->daddr = tunnel->key.addr.u.ip4.s_addr; // Destination address.
- skb->nh.iph->check = 0; // Zero the checksum.
-
- // Ethernet header will be filled-in by device.
- err = Tunnel_send(tunnel->base, skb);
- skb = NULL;
- exit:
- if(err && skb){
- wprintf("< err=%d\n", err);
- kfree_skb(skb);
- }
- return err;
-}
-
-/** Tunnel type for etherip.
- */
-static TunnelType _etherip_tunnel_type = {
- .name = "ETHERIP",
- .open = etherip_tunnel_open,
- .close = etherip_tunnel_close,
- .send = etherip_tunnel_send
-};
-
-TunnelType *etherip_tunnel_type = &_etherip_tunnel_type;
-
-int etherip_tunnel_create(VnetId *vnet, VarpAddr *addr, Tunnel *base, Tunnel **tunnel){
- return Tunnel_create(etherip_tunnel_type, vnet, addr, base, tunnel);
-}
-
-#if defined(__KERNEL__) && defined(CONFIG_BRIDGE_NETFILTER)
-/** We need our own copy of this as it is no longer exported from the bridge module.
- */
-static inline void _nf_bridge_save_header(struct sk_buff *skb){
- int header_size = 16;
-
- // Were using this modified to use h_proto instead of skb->protocol.
- if(skb->protocol == htons(ETH_P_8021Q)){
- header_size = 18;
- }
- memcpy(skb->nf_bridge->data, skb->data - header_size, header_size);
-}
-#endif
-
-/** Do etherip receive processing.
- * Strips the etherip header to extract the ethernet frame, sets
- * the vnet from the header and re-receives the frame.
- *
- * Return code 1 means we now own the packet - the caller must not free it.
- * Return code < 0 means an error - caller still owns the packet.
- *
- * @param skb packet
- * @return 1 on success, error code otherwise
- */
-int etherip_protocol_recv(struct sk_buff *skb){
- int err = 0;
- const int etherip_n = sizeof(struct etheriphdr);
- struct etheriphdr *etheriph;
- Vnet *vinfo = NULL;
- VnetId vnet = {};
- u32 saddr, daddr;
- char vnetbuf[VNET_ID_BUF];
- struct ethhdr *eth;
- struct sk_buff *newskb;
-
- dprintf(">\n");
- saddr = skb->nh.iph->saddr;
- daddr = skb->nh.iph->daddr;
- if(MULTICAST(daddr) && (daddr != varp_mcast_addr)){
- // Ignore multicast packets not addressed to us.
- wprintf("> Ignoring mcast skb: src=%u.%u.%u.%u dst=%u.%u.%u.%u"
- " varp_mcast_addr=%u.%u.%u.%u\n",
- NIPQUAD(saddr), NIPQUAD(daddr), NIPQUAD(varp_mcast_addr));
- goto exit;
- }
- if(skb->data == skb->mac.raw){
- // skb->data points at ethernet header.
- //FIXME: Does this ever happen?
- //dprintf("> len=%d\n", skb->len);
- int ip_n = (skb->nh.iph->ihl << 2);
- int pull_n = ETH_HLEN + ip_n;
- if (!pskb_may_pull(skb, pull_n)){
- wprintf("> Malformed skb (eth+ip) src=%u.%u.%u.%u\n",
- NIPQUAD(saddr));
- err = -EINVAL;
- goto exit;
- }
- skb_pull_vn(skb, pull_n);
- }
- // Assume skb->data points at etherip header.
- etheriph = (void*)skb->data;
- if(etheriph->version != ETHERIP_VERSION){
- wprintf("> Bad etherip version=%d src=%u.%u.%u.%u\n",
- etheriph->version, NIPQUAD(saddr));
- err = -EINVAL;
- goto exit;
- }
- if(!pskb_may_pull(skb, etherip_n)){
- wprintf("> Malformed skb (etherip) src=%u.%u.%u.%u\n",
- NIPQUAD(saddr));
- err = -EINVAL;
- goto exit;
- }
- etheriphdr_get_vnet(etheriph, &vnet);
- // If vnet is secure, context must include IPSEC ESP.
- err = vnet_check_context(&vnet, SKB_CONTEXT(skb), &vinfo);
- if(err){
- wprintf("> Failed security check vnet=%s src=%u.%u.%u.%u\n",
- VnetId_ntoa(&vnet, vnetbuf), NIPQUAD(saddr));
- goto exit;
- }
- // Point at the headers in the contained ethernet frame.
- skb->mac.raw = skb_pull_vn(skb, etherip_n);
-
- newskb = alloc_skb(skb->len, GFP_ATOMIC);
- if (!newskb) {
- wprintf("> alloc new sk_buff failed \n");
- goto exit;
- }
- newskb->mac.raw = skb_put(newskb, skb->len);
- skb_copy_bits(skb, 0, newskb->data, skb->len);
- kfree_skb(skb);
- skb = newskb;
-
- eth = eth_hdr(skb);
-
- // Simulate the logic from eth_type_trans()
- // to set skb->pkt_type and skb->protocol.
- if(mac_is_multicast(eth->h_dest)){
- if(mac_is_broadcast(eth->h_dest)){
- skb->pkt_type = PACKET_BROADCAST;
- } else {
- skb->pkt_type = PACKET_MULTICAST;
- }
- } else {
- skb->pkt_type = PACKET_HOST;
- }
- if(ntohs(eth->h_proto) >= 1536){
- skb->protocol = eth->h_proto;
- } else {
- skb->protocol = htons(ETH_P_802_2);
- }
-
- // Assuming a standard Ethernet frame.
- // Should check for protocol? Support ETH_P_8021Q too.
- skb->nh.raw = skb_pull_vn(skb, ETH_HLEN);
- skb->h.raw = newskb->nh.raw + sizeof(struct iphdr);
-
- dprintf("> Unpacked srcaddr=" IPFMT " dstaddr=" IPFMT " vnet=%s srcmac=" MACFMT " dstmac=" MACFMT "\n",
- NIPQUAD(skb->nh.iph->saddr),
- NIPQUAD(skb->nh.iph->daddr),
- VnetId_ntoa(&vnet, vnetbuf),
- MAC6TUPLE(eth->h_source),
- MAC6TUPLE(eth->h_dest));
- //print_skb(__FUNCTION__, 0, skb);
-
- {
- // Know source ip, vnet, vmac, so update the varp cache.
- // For this to work forwarded vnet packets must have the
- // original source address.
- VarpAddr addr = { .family = AF_INET };
- addr.u.ip4.s_addr = saddr;
- varp_update(&vnet, eth->h_source, &addr);
- }
-
- err = vnet_skb_recv(skb, vinfo);
- exit:
- if(vinfo) Vnet_decref(vinfo);
- dprintf("< skb=%p err=%d\n", skb, err);
- return err;
-}
-
-
-#ifdef __KERNEL__
-
-/** Handle an ICMP error related to etherip.
- *
- * @param skb ICMP error packet
- * @param info
- */
-static void etherip_protocol_icmp_err(struct sk_buff *skb, u32 info){
- struct iphdr *iph = (struct iphdr*)skb->data;
-
- wprintf("> ICMP error type=%d code=%d addr=" IPFMT "\n",
- skb->h.icmph->type, skb->h.icmph->code, NIPQUAD(iph->daddr));
-
- if (skb->h.icmph->type != ICMP_DEST_UNREACH ||
- skb->h.icmph->code != ICMP_FRAG_NEEDED){
- return;
- }
- wprintf("> MTU too big addr= " IPFMT "\n", NIPQUAD(iph->daddr));
-}
-
-//============================================================================
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-// Code for 2.6 kernel.
-
-/** Etherip protocol. */
-static struct net_protocol etherip_protocol = {
- .handler = etherip_protocol_recv,
- .err_handler = etherip_protocol_icmp_err,
-};
-
-static int etherip_protocol_add(void){
- return inet_add_protocol(ðerip_protocol, IPPROTO_ETHERIP);
-}
-
-static int etherip_protocol_del(void){
- return inet_del_protocol(ðerip_protocol, IPPROTO_ETHERIP);
-}
-
-//============================================================================
-#else
-//============================================================================
-// Code for 2.4 kernel.
-
-/** Etherip protocol. */
-static struct inet_protocol etherip_protocol = {
- .name = "ETHERIP",
- .protocol = IPPROTO_ETHERIP,
- .handler = etherip_protocol_recv,
- .err_handler = etherip_protocol_icmp_err,
-};
-
-static int etherip_protocol_add(void){
- inet_add_protocol(ðerip_protocol);
- return 0;
-}
-
-static int etherip_protocol_del(void){
- return inet_del_protocol(ðerip_protocol);
-}
-
-#endif
-//============================================================================
-
-
-/** Initialize the etherip module.
- * Registers the etherip protocol.
- *
- * @return 0 on success, error code otherwise
- */
-int __init etherip_module_init(void) {
- int err = 0;
- etherip_protocol_add();
- return err;
-}
-
-/** Finalize the etherip module.
- * Deregisters the etherip protocol.
- */
-void __exit etherip_module_exit(void) {
- if(etherip_protocol_del() < 0){
- printk(KERN_INFO "%s: can't remove etherip protocol\n", __FUNCTION__);
- }
-}
-
-#endif // __KERNEL__
+++ /dev/null
-/*
- * Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-#ifndef _VNET_ETHERIP_H_
-#define _VNET_ETHERIP_H_
-
-#include "if_etherip.h"
-
-#ifdef __KERNEL__
-extern int etherip_module_init(void);
-extern void etherip_module_exit(void);
-#endif
-
-extern int etherip_protocol_recv(struct sk_buff *skb);
-extern int etherip_in_udp;
-
-struct VnetId;
-struct VarpAddr;
-struct Tunnel;
-
-extern int etherip_tunnel_create(struct VnetId *vnet, struct VarpAddr *addr,
- struct Tunnel *base, struct Tunnel **tunnel);
-#endif
+++ /dev/null
-/*
- * Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-#ifndef _VNET_IF_ETHERIP_H_
-#define _VNET_IF_ETHERIP_H_
-
-#ifdef __KERNEL__
-#include <asm/byteorder.h>
-#else
-#define __KERNEL__
-/* This include may cause a compile warning, which can be ignored.
- * Can't use <endian.h> because it doesn't define
- *__LITTLE_ENDIAN_BITFIELD or __BIG_ENDIAN_BITFIELD.
- */
-#include <asm/byteorder.h>
-#undef __KERNEL__
-#endif
-
-#include <if_varp.h>
-
-#define CONFIG_ETHERIP_EXT
-
-#ifdef CONFIG_ETHERIP_EXT
-
-/* Extended header with room for a longer vnet id. */
-
-#define ETHERIP_VERSION 4
-
-struct etheriphdr {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
- __u16 reserved:12,
- version:4;
-#elif defined (__BIG_ENDIAN_BITFIELD)
- __u16 version:4,
- reserved:12;
-#else
-#error "Adjust your <asm/byteorder.h> defines"
-#endif
- __u8 vnet[VNETID_SIZE8];
-} __attribute__ ((packed));
-
-#else
-
-/* Original header as in Etherip RFC. */
-
-#define ETHERIP_VERSION 3
-
-struct etheriphdr
-{
-#if defined(__LITTLE_ENDIAN_BITFIELD)
- __u16 reserved:12,
- version:4;
-#elif defined (__BIG_ENDIAN_BITFIELD)
- __u16 version:4,
- reserved:12;
-#else
-#error "Adjust your <asm/byteorder.h> defines"
-#endif
-
-};
-#endif
-
-
-#ifndef IPPROTO_ETHERIP
-#define IPPROTO_ETHERIP 97
-#endif
-
-#endif /* ! _VNET_IF_ETHERIP_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-
-#ifndef _VNET_IF_VARP_H
-#define _VNET_IF_VARP_H
-
-/* Need struct in_addr, struct in6_addr. */
-#ifdef __KERNEL__
-
-#include <linux/in.h>
-#include <linux/in6.h>
-
-#else
-
-#include <sys/socket.h>
-#include <netinet/in.h>
-
-#endif
-
-#include <linux/if_ether.h>
-
-typedef struct Vmac {
- unsigned char mac[ETH_ALEN];
-} Vmac;
-
-enum {
- /* Varp protocol messages.
- * Format is defined by struct VarpHdr.
- */
- VARP_ID = 1,
-
- /* Vnet ethernet in udp messages.
- * Format is uint16_t id (VUDP_ID), then
- * struct etheriphdr.
- */
- VUDP_ID = 2,
-
- /* Forwarded messages.
- */
- VFWD_ID = 3,
-
- /* Varp request. */
- VARP_OP_REQUEST = 1,
- /* Varp announce. */
- VARP_OP_ANNOUNCE = 2,
-};
-
-#define VNETID_SIZE8 16
-#define VNETID_SIZE16 (VNETID_SIZE8 >> 1)
-#define VNETID_SIZE32 (VNETID_SIZE8 >> 2)
-
-typedef struct VnetId {
- union {
- uint8_t vnet8[VNETID_SIZE8];
- uint16_t vnet16[VNETID_SIZE16];
- uint32_t vnet32[VNETID_SIZE32];
- } u;
-} __attribute__((packed)) VnetId;
-
-typedef struct VarpAddr {
- uint8_t family; // AF_INET or AF_INET6.
- union {
- uint8_t raw[16];
- struct in_addr ip4;
- struct in6_addr ip6;
- } u;
- //uint16_t port;
-} __attribute__((packed)) VarpAddr;
-
-typedef struct VnetMsgHdr {
- uint16_t id;
- uint16_t opcode;
-} __attribute__((packed)) VnetMsgHdr;
-
-typedef struct VarpHdr {
- VnetMsgHdr hdr;
- VnetId vnet;
- Vmac vmac;
- VarpAddr addr;
-} __attribute__((packed)) VarpHdr;
-
-
-/** Default address for varp/vnet broadcasts: 224.10.0.1 */
-#define VARP_MCAST_ADDR 0xe00a0001
-
-/** UDP port to use for varp protocol. */
-#define VARP_PORT 1798
-
-#endif /* ! _VNET_IF_VARP_H */
+++ /dev/null
-/* PF_KEY user interface, this is defined by rfc2367 so
- * do not make arbitrary modifications or else this header
- * file will not be compliant.
- */
-
-#ifndef _LINUX_PFKEY2_H
-#define _LINUX_PFKEY2_H
-
-#include <linux/types.h>
-
-#define PF_KEY_V2 2
-#define PFKEYV2_REVISION 199806L
-
-struct sadb_msg {
- uint8_t sadb_msg_version;
- uint8_t sadb_msg_type;
- uint8_t sadb_msg_errno;
- uint8_t sadb_msg_satype;
- uint16_t sadb_msg_len;
- uint16_t sadb_msg_reserved;
- uint32_t sadb_msg_seq;
- uint32_t sadb_msg_pid;
-} __attribute__((packed));
-/* sizeof(struct sadb_msg) == 16 */
-
-struct sadb_ext {
- uint16_t sadb_ext_len;
- uint16_t sadb_ext_type;
-} __attribute__((packed));
-/* sizeof(struct sadb_ext) == 4 */
-
-struct sadb_sa {
- uint16_t sadb_sa_len;
- uint16_t sadb_sa_exttype;
- uint32_t sadb_sa_spi;
- uint8_t sadb_sa_replay;
- uint8_t sadb_sa_state;
- uint8_t sadb_sa_auth;
- uint8_t sadb_sa_encrypt;
- uint32_t sadb_sa_flags;
-} __attribute__((packed));
-/* sizeof(struct sadb_sa) == 16 */
-
-struct sadb_lifetime {
- uint16_t sadb_lifetime_len;
- uint16_t sadb_lifetime_exttype;
- uint32_t sadb_lifetime_allocations;
- uint64_t sadb_lifetime_bytes;
- uint64_t sadb_lifetime_addtime;
- uint64_t sadb_lifetime_usetime;
-} __attribute__((packed));
-/* sizeof(struct sadb_lifetime) == 32 */
-
-struct sadb_address {
- uint16_t sadb_address_len;
- uint16_t sadb_address_exttype;
- uint8_t sadb_address_proto;
- uint8_t sadb_address_prefixlen;
- uint16_t sadb_address_reserved;
-} __attribute__((packed));
-/* sizeof(struct sadb_address) == 8 */
-
-struct sadb_key {
- uint16_t sadb_key_len;
- uint16_t sadb_key_exttype;
- uint16_t sadb_key_bits;
- uint16_t sadb_key_reserved;
-} __attribute__((packed));
-/* sizeof(struct sadb_key) == 8 */
-
-struct sadb_ident {
- uint16_t sadb_ident_len;
- uint16_t sadb_ident_exttype;
- uint16_t sadb_ident_type;
- uint16_t sadb_ident_reserved;
- uint64_t sadb_ident_id;
-} __attribute__((packed));
-/* sizeof(struct sadb_ident) == 16 */
-
-struct sadb_sens {
- uint16_t sadb_sens_len;
- uint16_t sadb_sens_exttype;
- uint32_t sadb_sens_dpd;
- uint8_t sadb_sens_sens_level;
- uint8_t sadb_sens_sens_len;
- uint8_t sadb_sens_integ_level;
- uint8_t sadb_sens_integ_len;
- uint32_t sadb_sens_reserved;
-} __attribute__((packed));
-/* sizeof(struct sadb_sens) == 16 */
-
-/* followed by:
- uint64_t sadb_sens_bitmap[sens_len];
- uint64_t sadb_integ_bitmap[integ_len]; */
-
-struct sadb_prop {
- uint16_t sadb_prop_len;
- uint16_t sadb_prop_exttype;
- uint8_t sadb_prop_replay;
- uint8_t sadb_prop_reserved[3];
-} __attribute__((packed));
-/* sizeof(struct sadb_prop) == 8 */
-
-/* followed by:
- struct sadb_comb sadb_combs[(sadb_prop_len +
- sizeof(uint64_t) - sizeof(struct sadb_prop)) /
- sizeof(strut sadb_comb)]; */
-
-struct sadb_comb {
- uint8_t sadb_comb_auth;
- uint8_t sadb_comb_encrypt;
- uint16_t sadb_comb_flags;
- uint16_t sadb_comb_auth_minbits;
- uint16_t sadb_comb_auth_maxbits;
- uint16_t sadb_comb_encrypt_minbits;
- uint16_t sadb_comb_encrypt_maxbits;
- uint32_t sadb_comb_reserved;
- uint32_t sadb_comb_soft_allocations;
- uint32_t sadb_comb_hard_allocations;
- uint64_t sadb_comb_soft_bytes;
- uint64_t sadb_comb_hard_bytes;
- uint64_t sadb_comb_soft_addtime;
- uint64_t sadb_comb_hard_addtime;
- uint64_t sadb_comb_soft_usetime;
- uint64_t sadb_comb_hard_usetime;
-} __attribute__((packed));
-/* sizeof(struct sadb_comb) == 72 */
-
-struct sadb_supported {
- uint16_t sadb_supported_len;
- uint16_t sadb_supported_exttype;
- uint32_t sadb_supported_reserved;
-} __attribute__((packed));
-/* sizeof(struct sadb_supported) == 8 */
-
-/* followed by:
- struct sadb_alg sadb_algs[(sadb_supported_len +
- sizeof(uint64_t) - sizeof(struct sadb_supported)) /
- sizeof(struct sadb_alg)]; */
-
-struct sadb_alg {
- uint8_t sadb_alg_id;
- uint8_t sadb_alg_ivlen;
- uint16_t sadb_alg_minbits;
- uint16_t sadb_alg_maxbits;
- uint16_t sadb_alg_reserved;
-} __attribute__((packed));
-/* sizeof(struct sadb_alg) == 8 */
-
-struct sadb_spirange {
- uint16_t sadb_spirange_len;
- uint16_t sadb_spirange_exttype;
- uint32_t sadb_spirange_min;
- uint32_t sadb_spirange_max;
- uint32_t sadb_spirange_reserved;
-} __attribute__((packed));
-/* sizeof(struct sadb_spirange) == 16 */
-
-struct sadb_x_kmprivate {
- uint16_t sadb_x_kmprivate_len;
- uint16_t sadb_x_kmprivate_exttype;
- u_int32_t sadb_x_kmprivate_reserved;
-} __attribute__((packed));
-/* sizeof(struct sadb_x_kmprivate) == 8 */
-
-struct sadb_x_sa2 {
- uint16_t sadb_x_sa2_len;
- uint16_t sadb_x_sa2_exttype;
- uint8_t sadb_x_sa2_mode;
- uint8_t sadb_x_sa2_reserved1;
- uint16_t sadb_x_sa2_reserved2;
- uint32_t sadb_x_sa2_sequence;
- uint32_t sadb_x_sa2_reqid;
-} __attribute__((packed));
-/* sizeof(struct sadb_x_sa2) == 16 */
-
-struct sadb_x_policy {
- uint16_t sadb_x_policy_len;
- uint16_t sadb_x_policy_exttype;
- uint16_t sadb_x_policy_type;
- uint8_t sadb_x_policy_dir;
- uint8_t sadb_x_policy_reserved;
- uint32_t sadb_x_policy_id;
- uint32_t sadb_x_policy_reserved2;
-} __attribute__((packed));
-/* sizeof(struct sadb_x_policy) == 16 */
-
-struct sadb_x_ipsecrequest {
- uint16_t sadb_x_ipsecrequest_len;
- uint16_t sadb_x_ipsecrequest_proto;
- uint8_t sadb_x_ipsecrequest_mode;
- uint8_t sadb_x_ipsecrequest_level;
- uint16_t sadb_x_ipsecrequest_reqid;
-} __attribute__((packed));
-/* sizeof(struct sadb_x_ipsecrequest) == 16 */
-
-/* This defines the TYPE of Nat Traversal in use. Currently only one
- * type of NAT-T is supported, draft-ietf-ipsec-udp-encaps-06
- */
-struct sadb_x_nat_t_type {
- uint16_t sadb_x_nat_t_type_len;
- uint16_t sadb_x_nat_t_type_exttype;
- uint8_t sadb_x_nat_t_type_type;
- uint8_t sadb_x_nat_t_type_reserved[3];
-} __attribute__((packed));
-/* sizeof(struct sadb_x_nat_t_type) == 8 */
-
-/* Pass a NAT Traversal port (Source or Dest port) */
-struct sadb_x_nat_t_port {
- uint16_t sadb_x_nat_t_port_len;
- uint16_t sadb_x_nat_t_port_exttype;
- uint16_t sadb_x_nat_t_port_port;
- uint16_t sadb_x_nat_t_port_reserved;
-} __attribute__((packed));
-/* sizeof(struct sadb_x_nat_t_port) == 8 */
-
-/* Message types */
-#define SADB_RESERVED 0
-#define SADB_GETSPI 1
-#define SADB_UPDATE 2
-#define SADB_ADD 3
-#define SADB_DELETE 4
-#define SADB_GET 5
-#define SADB_ACQUIRE 6
-#define SADB_REGISTER 7
-#define SADB_EXPIRE 8
-#define SADB_FLUSH 9
-#define SADB_DUMP 10
-#define SADB_X_PROMISC 11
-#define SADB_X_PCHANGE 12
-#define SADB_X_SPDUPDATE 13
-#define SADB_X_SPDADD 14
-#define SADB_X_SPDDELETE 15
-#define SADB_X_SPDGET 16
-#define SADB_X_SPDACQUIRE 17
-#define SADB_X_SPDDUMP 18
-#define SADB_X_SPDFLUSH 19
-#define SADB_X_SPDSETIDX 20
-#define SADB_X_SPDEXPIRE 21
-#define SADB_X_SPDDELETE2 22
-#define SADB_X_NAT_T_NEW_MAPPING 23
-#define SADB_MAX 23
-
-/* Security Association flags */
-#define SADB_SAFLAGS_PFS 1
-
-/* Security Association states */
-#define SADB_SASTATE_LARVAL 0
-#define SADB_SASTATE_MATURE 1
-#define SADB_SASTATE_DYING 2
-#define SADB_SASTATE_DEAD 3
-#define SADB_SASTATE_MAX 3
-
-/* Security Association types */
-#define SADB_SATYPE_UNSPEC 0
-#define SADB_SATYPE_AH 2
-#define SADB_SATYPE_ESP 3
-#define SADB_SATYPE_RSVP 5
-#define SADB_SATYPE_OSPFV2 6
-#define SADB_SATYPE_RIPV2 7
-#define SADB_SATYPE_MIP 8
-#define SADB_X_SATYPE_IPCOMP 9
-#define SADB_SATYPE_MAX 9
-
-/* Authentication algorithms */
-#define SADB_AALG_NONE 0
-#define SADB_AALG_MD5HMAC 2
-#define SADB_AALG_SHA1HMAC 3
-#define SADB_X_AALG_SHA2_256HMAC 5
-#define SADB_X_AALG_SHA2_384HMAC 6
-#define SADB_X_AALG_SHA2_512HMAC 7
-#define SADB_X_AALG_RIPEMD160HMAC 8
-#define SADB_X_AALG_NULL 251 /* kame */
-#define SADB_AALG_MAX 251
-
-/* Encryption algorithms */
-#define SADB_EALG_NONE 0
-#define SADB_EALG_DESCBC 2
-#define SADB_EALG_3DESCBC 3
-#define SADB_X_EALG_CASTCBC 6
-#define SADB_X_EALG_BLOWFISHCBC 7
-#define SADB_EALG_NULL 11
-#define SADB_X_EALG_AESCBC 12
-#define SADB_EALG_MAX 12
-
-/* Compression algorithms */
-#define SADB_X_CALG_NONE 0
-#define SADB_X_CALG_OUI 1
-#define SADB_X_CALG_DEFLATE 2
-#define SADB_X_CALG_LZS 3
-#define SADB_X_CALG_LZJH 4
-#define SADB_X_CALG_MAX 4
-
-/* Extension Header values */
-#define SADB_EXT_RESERVED 0
-#define SADB_EXT_SA 1
-#define SADB_EXT_LIFETIME_CURRENT 2
-#define SADB_EXT_LIFETIME_HARD 3
-#define SADB_EXT_LIFETIME_SOFT 4
-#define SADB_EXT_ADDRESS_SRC 5
-#define SADB_EXT_ADDRESS_DST 6
-#define SADB_EXT_ADDRESS_PROXY 7
-#define SADB_EXT_KEY_AUTH 8
-#define SADB_EXT_KEY_ENCRYPT 9
-#define SADB_EXT_IDENTITY_SRC 10
-#define SADB_EXT_IDENTITY_DST 11
-#define SADB_EXT_SENSITIVITY 12
-#define SADB_EXT_PROPOSAL 13
-#define SADB_EXT_SUPPORTED_AUTH 14
-#define SADB_EXT_SUPPORTED_ENCRYPT 15
-#define SADB_EXT_SPIRANGE 16
-#define SADB_X_EXT_KMPRIVATE 17
-#define SADB_X_EXT_POLICY 18
-#define SADB_X_EXT_SA2 19
-/* The next four entries are for setting up NAT Traversal */
-#define SADB_X_EXT_NAT_T_TYPE 20
-#define SADB_X_EXT_NAT_T_SPORT 21
-#define SADB_X_EXT_NAT_T_DPORT 22
-#define SADB_X_EXT_NAT_T_OA 23
-#define SADB_EXT_MAX 23
-
-/* Identity Extension values */
-#define SADB_IDENTTYPE_RESERVED 0
-#define SADB_IDENTTYPE_PREFIX 1
-#define SADB_IDENTTYPE_FQDN 2
-#define SADB_IDENTTYPE_USERFQDN 3
-#define SADB_IDENTTYPE_MAX 3
-
-#endif /* !(_LINUX_PFKEY2_H) */
+++ /dev/null
-/*
- * Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/random.h>
-
-#include "hash_table.h"
-
-#define MODULE_NAME "RANDOM"
-#define DEBUG 1
-#undef DEBUG
-#include "debug.h"
-
-/** @file
- * Source of randomness.
- * Current implementation is not enough.
- * Needs to be cryptographically strong.
- */
-
-static unsigned long seed = 0;
-static unsigned long count = 0;
-
-/** Contribute some random bytes.
- *
- * @param src bytes to contribute
- * @param src_n number of bytes
- */
-void add_random_bytes(const void *src, int src_n){
- ++count;
- seed = hash_hvoid(seed, &count, sizeof(count));
- seed = hash_hvoid(seed, src, src_n);
-}
-
-/** Get one random byte.
- *
- * @return random byte
- */
-int get_random_byte(void){
- int tmp = jiffies;
- add_random_bytes(&tmp, sizeof(tmp));
- return seed;
-}
-
-#ifndef __KERNEL__
-/* Get some random bytes.
- *
- * @param dst destination for the bytes
- * @param dst_n number of bytes to get
- */
-void get_random_bytes(void *dst, int dst_n){
- int i;
- char *p = (char *)dst;
- for(i = 0; i < dst_n; i++){
- *p++ = get_random_byte();
- }
-}
-#endif
-
-int __init random_module_init(void){
- int dummy;
- int tmp = jiffies;
- seed = (unsigned long)&dummy;
- add_random_bytes(&tmp, sizeof(tmp));
- return 0;
-}
-
-void __exit random_module_exit(void){
-}
-
+++ /dev/null
-/*
- * Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-#ifndef __VNET_RANDOM_H__
-#define __VNET_RANDOM_H__
-
-extern void get_random_bytes(void *dst, int dst_n);
-extern void add_random_bytes(const void *src, int src_n);
-
-extern int random_module_init(void);
-extern void random_module_exit(void);
-
-#endif /* ! __VNET_RANDOM_H__ */
+++ /dev/null
-/*
- * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-#include <linux/kernel.h>
-
-#include <tunnel.h>
-#include <vnet.h>
-#include <sa.h>
-#include <sa_algorithm.h>
-
-#include "hash_table.h"
-#include "allocate.h"
-
-#define MODULE_NAME "IPSEC"
-#define DEBUG 1
-#undef DEBUG
-#include "debug.h"
-
-/** @file IPSEC Security Association (SA).
- */
-
-/** Maximum number of protocols.*/
-#define INET_PROTOCOL_MAX 256
-
-/** Table of SA types indexed by protocol. */
-static SAType *sa_type[INET_PROTOCOL_MAX] = {};
-
-/** Hash a protocol number.
- *
- * @param protocol protocol number
- * @return hashcode
- */
-static inline unsigned char InetProtocol_hash(int protocol){
- return (protocol) & (INET_PROTOCOL_MAX - 1);
-}
-
-/** Register an SA type.
- * It is an error if an SA type is already registered for the protocol.
- *
- * @param type SA type
- * @return 0 on success, error code otherwise
- */
-int SAType_add(SAType *type){
- int err = -EINVAL;
- int hash;
- if(!type) goto exit;
- hash = InetProtocol_hash(type->protocol);
- if(sa_type[hash]) goto exit;
- err = 0;
- sa_type[hash] = type;
- exit:
- return err;
-}
-
-/** Deregister an SA type.
- * It is an error if no SA type is registered for the protocol.
- *
- * @param type SA type
- * @return 0 on success, error code otherwise
- */
-int SAType_del(SAType *type){
- int err = -EINVAL;
- int hash;
- if(!type) goto exit;
- hash = InetProtocol_hash(type->protocol);
- if(!sa_type[hash]) goto exit;
- err = 0;
- sa_type[hash] = NULL;
- exit:
- return err;
-}
-
-int SAType_get(int protocol, SAType **type){
- int err = -ENOENT;
- int hash;
- hash = InetProtocol_hash(protocol);
- *type = sa_type[hash];
- if(!*type) goto exit;
- err = 0;
- exit:
- return err;
-}
-
-/* Defeat compiler warnings about unused functions. */
-static int sa_key_check(SAKey *key, enum sa_alg_type type) __attribute__((unused));
-static u32 random_spi(void) __attribute__((unused));
-static u32 generate_key(u32 key, u32 offset, u32 spi) __attribute__((unused));
-
-/** Check a key has an acceptable length for an algorithm.
- *
- * @param key key
- * @param type algorithm
- * @return 0 on success, error code otherwise
- */
-static int sa_key_check(SAKey *key, enum sa_alg_type type){
- return 0;
-}
-
-static unsigned long sa_spi_counter = 0;
-
-/** Mangle some input to generate output.
- * This is used to derive spis and keying material from secrets,
- * so it probably ought to be cryptographically strong.
- * Probably ought to use a good hash (sha1) or cipher (aes).
- *
- * @param input input bytes
- * @param n number of bytes
- * @return mangled value
- */
-static u32 mangle(void *input, int n){
- return hash_hvoid(0, input, n);
-}
-
-/** Generate a random spi.
- * Uses a hashed counter.
- *
- * @return spi
- */
-static u32 random_spi(void){
- u32 spi;
- do{
- spi = sa_spi_counter++;
- spi = mangle(&spi, sizeof(spi));
- } while(!spi);
- return spi;
-}
-
- /** Generate a spi for a given protocol and address, using a secret key.
- * The offset is used when it is necessary to generate more than one spi
- * for the same protocol and address.
- *
- * @param key key
- * @param offset offset
- * @param protocol protocol
- * @param addr IP address
- * @return spi
- */
-static u32 generate_spi(u32 key, u32 offset, u32 protocol, u32 addr){
- u32 input[] = { key, offset, protocol, addr };
- return mangle(input, sizeof(input));
-}
-
-/** Generate keying material for a given spi, based on a
- * secret.
- *
- * @param key secret
- * @param offset offset
- * @param spi spi
- * @return keying material
- */
-static u32 generate_key(u32 key, u32 offset, u32 spi){
- u32 input[] = { key, offset, spi };
- return mangle(input, sizeof(input));
-}
-
-/** Allocate a spi.
- * Want to use random ones.
- * So check for ones not in use.
- *
- * When using static keying, both ends need to agree on key.
- * How does that work? Also, will suddenly get traffic using a spi,
- * and will have to create SA then. Or need to create in advance.
- * But can't do that because don't know peers.
- * When get message on a spi that doesn't exist - do what?
- * Use a spi related to the destination addr and a secret.
- * Then receiver can check if spi is ok and create SA on demand.
- * Use hash of key, protocol, addr to generate. Then have to check
- * for in-use because of potential collisions. Receiver can do the
- * same hash and check spi is in usable range. Then derive keys from
- * the spi (using another secret).
- *
- * @param key spi generation key
- * @param protocol protocol
- * @param addr IP address
- * @param spip return parameter for spi
- * @return 0 on success, error code otherwise
- */
-int sa_spi_alloc(u32 key, u32 protocol, u32 addr, u32 *spip){
- int err = 0;
- int i = 0, n = 100;
- u32 spi;
- for(i = 0; i < n; i++, spi++){
- spi = generate_spi(key, i, protocol, addr);
- if(!spi) continue;
- if(!sa_table_lookup_spi(spi, protocol, addr)){
- *spip = spi;
- goto exit;
- }
- }
- err = -ENOMEM;
- exit:
- return err;
-}
-
-/** Table of SAs. Indexed by unique id and spi/protocol/addr triple.
- */
-static HashTable *sa_table = NULL;
-
-static u32 sa_id = 1;
-
-/** Hash an SA id.
- *
- * @param id SA id
- * @return hashcode
- */
-static inline Hashcode sa_table_hash_id(u32 id){
- return hash_hvoid(0, &id, sizeof(id));
-}
-
-/** Hash SA spi/protocol/addr.
- *
- * @param spi spi
- * @param protocol protocol
- * @param addr IP address
- * @return hashcode
- */
-static inline Hashcode sa_table_hash_spi(u32 spi, u32 protocol, u32 addr){
- u32 a[] = { spi, protocol, addr };
- return hash_hvoid(0, a, sizeof(a));
-}
-
-/** Test if an SA entry has a given value.
- *
- * @param arg contains SA pointer
- * @param table hashtable
- * @param entry entry containing SA
- * @return 1 if it does, 0 otherwise
- */
-static int sa_table_state_fn(TableArg arg, HashTable *table, HTEntry *entry){
- return entry->value == arg.ptr;
-}
-
-/** Test if an SA entry has a given id.
- *
- * @param arg contains SA id
- * @param table hashtable
- * @param entry entry containing SA
- * @return 1 if it does, 0 otherwise
- */
-static int sa_table_id_fn(TableArg arg, HashTable *table, HTEntry *entry){
- SAState *state = entry->value;
- u32 id = arg.ul;
- return state->ident.id == id;
-}
-
-/** Test if an SA entry has a given spi/protocol/addr.
- *
- * @param arg contains SAIdent pointer
- * @param table hashtable
- * @param entry entry containing SA
- * @return 1 if it does, 0 otherwise
- */
-static int sa_table_spi_fn(TableArg arg, HashTable *table, HTEntry *entry){
- SAState *state = entry->value;
- SAIdent *ident = arg.ptr;
- return state->ident.spi == ident->spi
- && state->ident.protocol == ident->protocol
- && state->ident.addr == ident->addr;
-}
-
-/** Free an SA entry. Decrements the SA refcount and frees the entry.
- *
- * @param table containing table
- * @param entry to free
- */
-static void sa_table_free_fn(HashTable *table, HTEntry *entry){
- if(!entry) return;
- if(entry->value){
- SAState *state = entry->value;
- SAState_decref(state);
- }
- deallocate(entry);
-}
-
-/** Initialize the SA table.
- *
- * @return 0 on success, error code otherwise
- */
-int sa_table_init(void){
- int err = 0;
- sa_table = HashTable_new(0);
- if(!sa_table){
- err = -ENOMEM;
- goto exit;
- }
- sa_table->entry_free_fn = sa_table_free_fn;
-
- exit:
- return err;
-}
-
-void sa_table_exit(void){
- HashTable_free(sa_table);
-}
-
-/** Remove an SA from the table.
- *
- * @param state SA
- */
-int sa_table_delete(SAState *state){
- int count = 0;
- Hashcode h1, h2;
- TableArg arg = { .ptr = state };
- // Remove by id.
- h1 = sa_table_hash_id(state->ident.id);
- count += HashTable_remove_entry(sa_table, h1, sa_table_state_fn, arg);
- // Remove by spi/protocol/addr if spi nonzero.
- if(!state->ident.spi) goto exit;
- h2 = sa_table_hash_spi(state->ident.spi, state->ident.protocol, state->ident.addr);
- if(h1 == h2) goto exit;
- count += HashTable_remove_entry(sa_table, h2, sa_table_state_fn, arg);
- exit:
- return count;
-}
-
-/** Add an SA to the table.
- * The SA is indexed by id and spi/protocol/addr (if the spi is non-zero).
- *
- * @param state SA
- * @return 0 on success, error code otherwise
- */
-int sa_table_add(SAState *state){
- int err = 0;
- Hashcode h1, h2;
- int entries = 0;
-
- dprintf(">\n");
- // Index by id.
- h1 = sa_table_hash_id(state->ident.id);
- if(!HashTable_add_entry(sa_table, h1, HKEY(state->ident.id), state)){
- err = -ENOMEM;
- goto exit;
- }
- entries++;
- SAState_incref(state);
- // Index by spi/protocol/addr if spi non-zero.
- if(state->ident.spi){
- h2 = sa_table_hash_spi(state->ident.spi, state->ident.protocol, state->ident.addr);
- if(h1 != h2){
- if(!HashTable_add_entry(sa_table, h2, HKEY(state->ident.id), state)){
- err = -ENOMEM;
- goto exit;
- }
- entries++;
- SAState_incref(state);
- }
- }
- exit:
- if(err && entries){
- sa_table_delete(state);
- }
- dprintf("< err=%d\n", err);
- return err;
-}
-
-
-/** Find an SA by spi/protocol/addr.
- * Increments the SA refcount on success.
- *
- * @param spi spi
- * @param protocol protocol
- * @param addr IP address
- * @return SA or NULL
- */
-SAState * sa_table_lookup_spi(u32 spi, u32 protocol, u32 addr){
- SAState *state = NULL;
- Hashcode h;
- SAIdent id = {
- .spi = spi,
- .protocol = protocol,
- .addr = addr };
- TableArg arg = { .ptr = &id };
- HTEntry *entry = NULL;
-
- h = sa_table_hash_spi(spi, protocol, addr);
- entry = HashTable_find_entry(sa_table, h, sa_table_spi_fn, arg);
- if(entry){
- state = entry->value;
- SAState_incref(state);
- }
- return state;
-}
-
-/** Find an SA by unique id.
- * Increments the SA refcount on success.
- *
- * @param id id
- * @return SA or NULL
- */
-SAState * sa_table_lookup_id(u32 id){
- Hashcode h;
- TableArg arg = { .ul = id };
- HTEntry *entry = NULL;
- SAState *state = NULL;
-
- dprintf("> id=%u\n", id);
- h = sa_table_hash_id(id);
- entry = HashTable_find_entry(sa_table, h, sa_table_id_fn, arg);
- if(entry){
- state = entry->value;
- SAState_incref(state);
- }
- dprintf("< state=%p\n", state);
- return state;
-}
-
-/** Replace an existing SA by another in the table.
- * The existing SA is not removed if the new one cannot be added.
- *
- * @param existing SA to replace
- * @param state new SA
- * @return 0 on success, error code otherwise
- */
-static int sa_table_replace(SAState *existing, SAState *state){
- int err = 0;
- // Need check for in-use?
-
- dprintf(">\n");
- if(existing->keying.state != SA_STATE_ACQUIRE){
- err = -EINVAL;
- goto exit;
- }
- // replace it.
- err = sa_table_add(state);
- if(err) goto exit;
- sa_table_delete(existing);
- exit:
- dprintf("< err=%d\n", err);
- return err;
-}
-
-/** Allocate an SA.
- *
- * @return SA or NULL
- */
-SAState *SAState_alloc(void){
- SAState *state;
-
- dprintf(">\n");
- state = kmalloc(sizeof(SAState), GFP_ATOMIC);
- if(!state) goto exit;
- *state = (SAState){};
- atomic_set(&state->refcount, 1);
- state->lock = SPIN_LOCK_UNLOCKED;
- exit:
- dprintf("< state=%p\n", state);
- return state;
-}
-
-/** Create an SA in initial state.
- * It has no spi and its keying state is acquire.
- * It must have a unique id, protocol and address.
- * At some point it should get updated with a complete SA.
- *
- * @param ident SA identifier
- * @param statep return parameter for new SA
- * @return 0 on success, error code otherwise
- */
-int SAState_init(SAIdent *ident, SAState **statep){
- int err = 0;
- SAState *state = NULL;
-
- if(ident->spi || !ident->id){
- err = -EINVAL;
- goto exit;
- }
- state = SAState_alloc();
- if (!state){
- err = -ENOMEM;
- goto exit;
- }
- state->ident = *ident;
- state->keying.state = SA_STATE_ACQUIRE;
- exit:
- return err;
-}
-
-/** Create a complete SA, with spi and cipher suite.
- *
- * @param info SA parameters
- * @param statep return parameter for new SA
- * @return 0 on success, error code otherwise
- */
-int SAState_create(SAInfo *info, SAState **statep){
- int err = 0;
- SAState *state = NULL;
-
- dprintf(">\n");
- state = SAState_alloc();
- if (!state){
- err = -ENOMEM;
- goto exit;
- }
- state->ident = info->ident;
- state->limits = info->limits;
- state->digest = info->digest;
- state->cipher = info->cipher;
- state->compress = info->compress;
- state->security = info->security;
- err = SAType_get(state->ident.protocol, &state->type);
- if (err) goto exit;
- err = state->type->init(state, NULL);
- if (err) goto exit;
- state->keying.state = SA_STATE_VALID;
- exit:
- if(err){
- SAState_decref(state);
- state = NULL;
- }
- *statep = state;
- dprintf("< err=%d\n", err);
- return err;
-}
-
-/** Create an SA for the given spi etc.
- * For now we fix the cipher suite and the keys.
- * Digest is SHA1 HMAC with a 128-bit key.
- * Cipher is AES (Rijndael) in CBC mode with a 128-bit key.
- *
- * The cipher suite and keys should really come from policy, with the
- * possibility of negotiating them with the peer (using IKE).
- * Negotiation creates difficulties though - because the SA cannot
- * be created immediately we have to be able to queue packets
- * while the SA is being negotiated.
- *
- * @param spi spi
- * @param protocol protocol
- * @param addr address
- * @param sa return parameter for SA
- * @return 0 on success, error code otherwise
- */
-int sa_create(int security, u32 spi, u32 protocol, u32 addr, SAState **sa){
- int err = 0;
- SAInfo info = {};
- char *digest_name = "sha1";
- char *digest_key = "0123456789abcdef";
- int digest_key_n = strlen(digest_key);
- char *cipher_name= "aes";
- char *cipher_key = "0123456789ABCDEF";
- int cipher_key_n = strlen(cipher_key);
-
- dprintf("> security=%d spi=%u protocol=%u addr=" IPFMT "\n",
- security, spi, protocol, NIPQUAD(addr));
- if(!spi){
- spi = generate_spi(0, 0, protocol, addr);
- }
- dprintf("> info...\n");
- info.ident.id = sa_id++;
- info.ident.spi = spi;
- info.ident.protocol = protocol;
- info.ident.addr = addr;
- info.security = security;
-
- //sa_algorithm_probe_all();
-
- dprintf("> digest name=%s key_n=%d\n", digest_name, digest_key_n);
- strcpy(info.digest.name, digest_name);
- info.digest.bits = digest_key_n * 8;
- memcpy(info.digest.key, digest_key, digest_key_n);
-
- if(security & SA_CONF){
- dprintf("> cipher name=%s key_n=%d\n", cipher_name, cipher_key_n);
- strcpy(info.cipher.name, cipher_name);
- info.cipher.bits = cipher_key_n * 8;
- memcpy(info.cipher.key, cipher_key, cipher_key_n);
- } else {
- dprintf("> cipher name=%s key_n=%d\n", "cipher_null", 0);
- strcpy(info.cipher.name, "cipher_null");
- info.cipher.bits = 0;
- memset(info.cipher.key, 0, sizeof(info.cipher.key));
- }
-
- err = sa_set(&info, 0, sa);
- dprintf("< err=%d\n", err);
- return err;
-}
-
-/** Create or update an SA.
- * The SA is added to the table.
- *
- * @param info SA parameters
- * @param update create if zero, update otherwise
- * @return 0 on success, error code otherwise
- */
-int sa_set(SAInfo *info, int update, SAState **val){
- int err = 0;
- SAState *state = NULL;
- SAState *existing = NULL;
-
- dprintf("> info=%p update=%d val=%p\n", info, update, val);
- existing = sa_table_lookup_id(info->ident.id);
- if(update && !existing){
- err = -ENOENT;
- } else if(!update && existing){
- err = -EINVAL;
- }
- if(err) goto exit;
- err = SAState_create(info, &state);
- if (err) goto exit;
- if(existing){
- err = sa_table_replace(existing, state);
- } else {
- err = sa_table_add(state);
- }
- exit:
- if(existing) SAState_decref(existing);
- if(val && !err){
- *val = state;
- } else {
- SAState_decref(state);
- }
- dprintf("< err=%d\n", err);
- return err;
-}
-
-/** Delete an SA. Removes it from the SA table.
- * It is an error if no SA with the given id exists.
- *
- * @param id SA id
- * @return 0 on success, error code otherwise
- */
-int sa_delete(int id){
- int err = 0;
- SAState *state;
- state = sa_table_lookup_id(id);
- if (!state){
- err = -ENOENT;
- goto exit;
- }
- sa_table_delete(state);
- SAState_decref(state);
- exit:
- return err;
-}
-/** Determine ESP security mode for a new SA.
- *
- * @param spi incoming spi
- * @param protocol incoming protocol
- * @param addr source address
- * @return security level or negative error code
- *
- * @todo Need to check spi, and do some lookup for security params.
- */
-int vnet_sa_security(u32 spi, int protocol, u32 addr){
- extern int vnet_security_default;
- int security = vnet_security_default;
- dprintf("< security=%x\n", security);
- return security;
-}
-
-/** Create a new SA for incoming traffic.
- *
- * @param spi incoming spi
- * @param protocol incoming protocol
- * @param addr source address
- * @param sa return parameter for SA
- * @return 0 on success, error code otherwise
- */
-int vnet_sa_create(u32 spi, int protocol, u32 addr, SAState **sa){
- int err = 0;
- int security = vnet_sa_security(spi, protocol, addr);
- if(security < 0){
- err = security;
- goto exit;
- }
- err = sa_create(security, spi, protocol, addr, sa);
- exit:
- return err;
-}
-/** Open function for SA tunnels.
- *
- * @param tunnel to open
- * @return 0 on success, error code otherwise
- */
-static int sa_tunnel_open(Tunnel *tunnel){
- int err = 0;
- //dprintf(">\n");
- //dprintf("< err=%d\n", err);
- return err;
-}
-
-/** Close function for SA tunnels.
- *
- * @param tunnel to close (OK if null)
- */
-static void sa_tunnel_close(Tunnel *tunnel){
- SAState *sa;
- if(!tunnel) return;
- sa = tunnel->data;
- if(!sa) return;
- SAState_decref(sa);
- tunnel->data = NULL;
-}
-
-/** Packet send function for SA tunnels.
- *
- * @param tunnel to send on
- * @param skb packet to send
- * @return 0 on success, negative error code on error
- */
-static int sa_tunnel_send(Tunnel *tunnel, struct sk_buff *skb){
- int err = -EINVAL;
- SAState *sa;
- if(!tunnel){
- wprintf("> Null tunnel!\n");
- goto exit;
- }
- sa = tunnel->data;
- if(!sa){
- wprintf("> Null SA!\n");
- goto exit;
- }
- err = SAState_send(sa, skb, tunnel->base);
- exit:
- return err;
-}
-
-/** Functions used by SA tunnels. */
-static TunnelType _sa_tunnel_type = {
- .name = "SA",
- .open = sa_tunnel_open,
- .close = sa_tunnel_close,
- .send = sa_tunnel_send
-};
-
-/** Functions used by SA tunnels. */
-TunnelType *sa_tunnel_type = &_sa_tunnel_type;
-
-int sa_tunnel_create(Vnet *info, VarpAddr *addr, Tunnel *base, Tunnel **tunnel){
- int err = 0;
- SAState *sa = NULL;
- //FIXME: Assuming IPv4 for now.
- u32 ipaddr = addr->u.ip4.s_addr;
- err = Tunnel_create(sa_tunnel_type, &info->vnet, addr, base, tunnel);
- if(err) goto exit;
- err = sa_create(info->security, 0, IPPROTO_ESP, ipaddr, &sa);
- if(err) goto exit;
- (*tunnel)->data = sa;
- exit:
- return err;
-}
+++ /dev/null
-/*
- * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-#ifndef __VNET_SA_H__
-#define __VNET_SA_H__
-
-#ifdef __KERNEL__
-#include <linux/types.h>
-#include <linux/crypto.h>
-
-#else
-
-#include "sys_kernel.h"
-
-#endif
-
-struct Vnet;
-struct VarpAddr;
-struct Tunnel;
-
-#ifndef CRYPTO_MAX_KEY_BYTES
-#define CRYPTO_MAX_KEY_BYTES 64
-#define CRYPTO_MAX_KEY_BITS (CRYPTO_MAX_KEY_BYTES * 8)
-#endif
-
-#ifndef CRYPTO_MAX_ALG_NAME
-#define CRYPTO_MAX_ALG_NAME 64
-#endif
-
-typedef struct SALimits {
- u64 bytes_soft;
- u64 bytes_hard;
- u64 packets_soft;
- u64 packets_hard;
-} SALimits;
-
-typedef struct SACounts {
- u64 bytes;
- u64 packets;
- u32 integrity_failures;
-} SACounts;
-
-typedef struct SAReplay {
- int replay;
- u32 send_seq;
- u32 recv_seq;
- u32 bitmap;
- u32 replay_window;
-} SAReplay;
-
-typedef struct SAKey {
- char name[CRYPTO_MAX_ALG_NAME];
- int bits;
- char key[CRYPTO_MAX_KEY_BYTES];
-} SAKey;
-
-typedef struct SAKeying {
- u8 state;
- u8 dying;
-} SAKeying;
-
-typedef struct SAIdent {
- u32 id;
- u32 spi;
- u32 addr;
- u32 protocol;
-} SAIdent;
-
-struct SAType;
-
-/** Security assocation (SA). */
-typedef struct SAState {
- atomic_t refcount;
- spinlock_t lock;
- /** Identifier. */
- struct SAIdent ident;
- /** Security flags. */
- int security;
- /** Keying state. */
- struct SAKeying keying;
- /** Byte counts etc. */
- struct SACounts counts;
- /** Byte limits etc. */
- struct SALimits limits;
- /** Replay protection. */
- struct SAReplay replay;
- /** Digest algorithm. */
- struct SAKey digest;
- /** Cipher algorithm. */
- struct SAKey cipher;
- /** Compress algorith. */
- struct SAKey compress;
- /** SA type (ESP, AH). */
- struct SAType *type;
- /** Data for the SA type to use. */
- void *data;
-} SAState;
-
-typedef struct SAType {
- char *name;
- int protocol;
- int (*init)(SAState *state, void *args);
- void (*fini)(SAState *state);
- int (*recv)(SAState *state, struct sk_buff *skb);
- int (*send)(SAState *state, struct sk_buff *skb, struct Tunnel *tunnel);
- u32 (*size)(SAState *state, int size);
-} SAType;
-
-/** Information needed to create an SA.
- * Unused algorithms have zero key size.
- */
-typedef struct SAInfo {
- /** Identifier. */
- SAIdent ident;
- /** Security flags. */
- int security;
- /** Digest algorithm and key. */
- SAKey digest;
- /** Cipher algorithm and key. */
- SAKey cipher;
- /** Compress algorithm and key. */
- SAKey compress;
- /** SA lifetime limits. */
- SALimits limits;
- /** Replay protection window. */
- int replay_window;
-} SAInfo;
-
-enum sa_alg_type {
- SA_ALG_DIGEST = 1,
- SA_ALG_CIPHER = 2,
- SA_ALG_COMPRESS = 3,
-};
-
-extern int SAType_add(SAType *type);
-extern int SAType_del(SAType *type);
-extern int SAType_get(int protocol, SAType **type);
-
-extern int sa_table_init(void);
-extern void sa_table_exit(void);
-extern int sa_table_delete(SAState *state);
-extern int sa_table_add(SAState *state);
-extern SAState * sa_table_lookup_spi(u32 spi, u32 protocol, u32 addr);
-extern SAState * sa_table_lookup_id(u32 id);
-
-/** Increment reference count.
- *
- * @param sa security association (may be null)
- */
-static inline void SAState_incref(SAState *sa){
- if(!sa) return;
- atomic_inc(&sa->refcount);
-}
-
-/** Decrement reference count, freeing if zero.
- *
- * @param sa security association (may be null)
- */
-static inline void SAState_decref(SAState *sa){
- if(!sa) return;
- if(atomic_dec_and_test(&sa->refcount)){
- sa->type->fini(sa);
- kfree(sa);
- }
-}
-
-extern SAState *SAState_alloc(void);
-extern int SAState_init(SAIdent *id, SAState **statep);
-extern int SAState_create(SAInfo *info, SAState **statep);
-
-static inline int SAState_send(SAState *sa, struct sk_buff *skb, struct Tunnel *tunnel){
- return sa->type->send(sa, skb, tunnel);
-}
-
-static inline int SAState_recv(SAState *sa, struct sk_buff *skb){
- return sa->type->recv(sa, skb);
-}
-
-static inline int SAState_size(SAState *sa, int n){
- return sa->type->size(sa, n);
-}
-
-extern int sa_create(int security, u32 spi, u32 protocol, u32 addr, SAState **sa);
-extern int sa_set(SAInfo *info, int update, SAState **val);
-extern int sa_delete(int id);
-
-enum {
- SA_AUTH = 1,
- SA_CONF = 2
-};
-
-enum {
- SA_STATE_ACQUIRE = 1,
- SA_STATE_VALID = 2,
-};
-
-extern int sa_tunnel_create(struct Vnet *info, struct VarpAddr *addr,
- struct Tunnel *base, struct Tunnel **tunnel);
-
-#endif /* !__VNET_SA_H__ */
+++ /dev/null
-/*
- * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
- * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/crypto.h>
-#include <linux/sched.h>
-//#include <asm/softirq.h>
-
-#include <sa_algorithm.h>
-
-#define MODULE_NAME "IPSEC"
-#define DEBUG 1
-#undef DEBUG
-#include "debug.h"
-
-/** @file Tables of supported IPSEC algorithms.
- * Has tables for digests, ciphers and compression algorithms.
- */
-
-/*
- * Algorithms supported by IPsec. These entries contain properties which
- * are used in key negotiation and sa processing, and are used to verify
- * that instantiated crypto transforms have correct parameters for IPsec
- * purposes.
- */
-
-/** Digests. */
-static SAAlgorithm digest_alg[] = {
- {
- .name = "digest_null",
- .info = {
- .digest = {
- .icv_truncbits = 0,
- .icv_fullbits = 0,
- }
- },
- .alg = {
- .sadb_alg_id = SADB_X_AALG_NULL,
- .sadb_alg_ivlen = 0,
- .sadb_alg_minbits = 0,
- .sadb_alg_maxbits = 0
- }
- },
- {
- .name = "md5",
- .info = { .digest = {
- .icv_truncbits = 96,
- .icv_fullbits = 128,
- } },
- .alg = {
- .sadb_alg_id = SADB_AALG_MD5HMAC,
- .sadb_alg_ivlen = 0,
- .sadb_alg_minbits = 128,
- .sadb_alg_maxbits = 128
- }
- },
- {
- .name = "sha1",
- .info = {
- .digest = {
- .icv_truncbits = 96,
- .icv_fullbits = 160,
- }
- },
- .alg = {
- .sadb_alg_id = SADB_AALG_SHA1HMAC,
- .sadb_alg_ivlen = 0,
- .sadb_alg_minbits = 160,
- .sadb_alg_maxbits = 160
- }
- },
- {
- .name = "sha256",
- .info = {
- .digest = {
- .icv_truncbits = 128,
- .icv_fullbits = 256,
- }
- },
- .alg = {
- .sadb_alg_id = SADB_X_AALG_SHA2_256HMAC,
- .sadb_alg_ivlen = 0,
- .sadb_alg_minbits = 256,
- .sadb_alg_maxbits = 256
- }
- },
-/* { */
-/* .name = "ripemd160", */
-/* .info = { */
-/* .digest = { */
-/* .icv_truncbits = 96, */
-/* .icv_fullbits = 160, */
-/* } */
-/* }, */
-/* .alg = { */
-/* .sadb_alg_id = SADB_X_AALG_RIPEMD160HMAC, */
-/* .sadb_alg_ivlen = 0, */
-/* .sadb_alg_minbits = 160, */
-/* .sadb_alg_maxbits = 160 */
-/* } */
-/* }, */
- { /* Terminator */ }
-};
-
-/** Ciphers. */
-static SAAlgorithm cipher_alg[] = {
- {
- .name = "cipher_null",
- .info = {
- .cipher = {
- .blockbits = 8,
- .defkeybits = 0,
- }
- },
- .alg = {
- .sadb_alg_id = SADB_EALG_NULL,
- .sadb_alg_ivlen = 0,
- .sadb_alg_minbits = 0,
- .sadb_alg_maxbits = 0
- }
- },
- {
- .name = "des",
- .info = {
- .cipher = {
- .blockbits = 64,
- .defkeybits = 64,
- }
- },
- .alg = {
- .sadb_alg_id = SADB_EALG_DESCBC,
- .sadb_alg_ivlen = 8,
- .sadb_alg_minbits = 64,
- .sadb_alg_maxbits = 64
- }
- },
- {
- .name = "des3_ede",
- .info = {
- .cipher = {
- .blockbits = 64,
- .defkeybits = 192,
- }
- },
- .alg = {
- .sadb_alg_id = SADB_EALG_3DESCBC,
- .sadb_alg_ivlen = 8,
- .sadb_alg_minbits = 192,
- .sadb_alg_maxbits = 192
- }
- },
-/* { */
-/* .name = "cast128", */ //cast5?
-/* .info = { */
-/* .cipher = { */
-/* .blockbits = 64, */
-/* .defkeybits = 128, */
-/* } */
-/* }, */
-/* .alg = { */
-/* .sadb_alg_id = SADB_X_EALG_CASTCBC, */
-/* .sadb_alg_ivlen = 8, */
-/* .sadb_alg_minbits = 40, */
-/* .sadb_alg_maxbits = 128 */
-/* } */
-/* }, */
- {
- .name = "blowfish",
- .info = {
- .cipher = {
- .blockbits = 64,
- .defkeybits = 128,
- }
- },
- .alg = {
- .sadb_alg_id = SADB_X_EALG_BLOWFISHCBC,
- .sadb_alg_ivlen = 8,
- .sadb_alg_minbits = 40,
- .sadb_alg_maxbits = 448
- }
- },
- {
- .name = "aes",
- .info = {
- .cipher = {
- .blockbits = 128,
- .defkeybits = 128,
- }
- },
- .alg = {
- .sadb_alg_id = SADB_X_EALG_AESCBC,
- .sadb_alg_ivlen = 8,
- .sadb_alg_minbits = 128,
- .sadb_alg_maxbits = 256
- }
- },
- { /* Terminator */ }
-};
-
-/** Compressors. */
-static SAAlgorithm compress_alg[] = {
- {
- .name = "deflate",
- .info = {
- .compress = {
- .threshold = 90,
- }
- },
- .alg = { .sadb_alg_id = SADB_X_CALG_DEFLATE }
- },
-/* { */
-/* .name = "lzs", */
-/* .info = { */
-/* .compress = { */
-/* .threshold = 90, */
-/* } */
-/* }, */
-/* .alg = { .sadb_alg_id = SADB_X_CALG_LZS } */
-/* }, */
-/* { */
-/* .name = "lzjh", */
-/* .info = { */
-/* .compress = { */
-/* .threshold = 50, */
-/* } */
-/* }, */
-/* .alg = { .sadb_alg_id = SADB_X_CALG_LZJH } */
-/* }, */
- { /* Terminator */ }
-};
-
-static SAAlgorithm *sa_algorithm_by_id(SAAlgorithm *algo, int alg_id) {
- for( ; algo && algo->name; algo++){
- if (algo->alg.sadb_alg_id == alg_id) {
- return (algo->available ? algo : NULL);
- }
- }
- return NULL;
-}
-
-
-static SAAlgorithm *sa_algorithm_by_name(SAAlgorithm *algo, char *name) {
- if (!name) return NULL;
- for( ; algo && algo->name; algo++){
- if (strcmp(name, algo->name) == 0) {
- return (algo->available ? algo : NULL);
- }
- }
- return NULL;
-}
-
-SAAlgorithm *sa_digest_by_id(int alg_id) {
- return sa_algorithm_by_id(digest_alg, alg_id);
-}
-
-SAAlgorithm *sa_cipher_by_id(int alg_id) {
- return sa_algorithm_by_id(cipher_alg, alg_id);
-}
-
-SAAlgorithm *sa_compress_by_id(int alg_id) {
- return sa_algorithm_by_id(compress_alg, alg_id);
-}
-
-SAAlgorithm *sa_digest_by_name(char *name) {
- return sa_algorithm_by_name(digest_alg, name);
-}
-
-SAAlgorithm *sa_cipher_by_name(char *name) {
- return sa_algorithm_by_name(cipher_alg, name);
-}
-
-SAAlgorithm *sa_compress_by_name(char *name) {
- return sa_algorithm_by_name(compress_alg, name);
-}
-
-SAAlgorithm *sa_digest_by_index(unsigned int idx) {
- return digest_alg + idx;
-}
-
-SAAlgorithm *sa_cipher_by_index(unsigned int idx) {
- return cipher_alg + idx;
-}
-
-SAAlgorithm *sa_compress_by_index(unsigned int idx) {
- return compress_alg + idx;
-}
-
-static void sa_algorithm_probe(SAAlgorithm *algo){
- int status;
- dprintf("> algo=%p\n", algo);
- for( ; algo && algo->name; algo++){
- dprintf("> algorithm %s...\n", algo->name);
- status = crypto_alg_available(algo->name, 0);
- dprintf("> algorithm %s status=%d\n",algo->name, status);
- if (algo->available != status){
- algo->available = status;
- }
- }
- dprintf("<\n");
-}
-
-/** Crypto api is broken. When an unregistered algorithm is requested it
- * tries to load a module of the same name. But not all algorithms are
- * defined by modules of the same name.
- */
-static char *crypto_modules[] = {
- "aes",
- //"arc4",
- "blowfish",
- //"cast5",
- //"cast6",
- "crypto_null",
- "des",
- //"md4",
- "md5",
- //"serpent",
- "sha1",
- "sha256",
- //"sha512",
- //"twofish",
- NULL
-};
-
-#include <linux/kmod.h>
-
-static void sa_module_probe(char **modules){
- char **p;
- dprintf(">\n");
- for(p = modules; *p; p++){
- dprintf("> %s\n", *p);
- request_module(*p);
- }
- dprintf("<\n");
-}
-
-/**
- * Probe for the availability of crypto algorithms, and set the available
- * flag for any algorithms found on the system. This is typically called by
- * pfkey during userspace SA add, update or register.
- */
-void sa_algorithm_probe_all(void){
- dprintf("> \n");
- //BUG_ON(in_softirq());
- sa_module_probe(crypto_modules);
- sa_algorithm_probe(digest_alg);
- sa_algorithm_probe(cipher_alg);
- sa_algorithm_probe(compress_alg);
- dprintf("<\n");
-}
+++ /dev/null
-/*
- * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-#ifndef __VNET_SA_ALGORITHM_H__
-#define __VNET_SA_ALGORITHM_H__
-
-#include <linux/types.h>
-#include <linux/pfkeyv2.h>
-
-typedef struct SADigestInfo {
- u16 icv_truncbits;
- u16 icv_fullbits;
-} SADigestInfo;
-
-typedef struct SACipherInfo {
- u16 blockbits;
- u16 defkeybits;
-} SACipherInfo;
-
-typedef struct SACompressInfo {
- u16 threshold;
-} SACompressInfo;
-
-typedef struct SAAlgorithm {
- char *name;
- u8 available;
- union {
- SADigestInfo digest;
- SACipherInfo cipher;
- SACompressInfo compress;
- } info;
- struct sadb_alg alg;
-} SAAlgorithm;
-
-extern SAAlgorithm *sa_digest_by_id(int alg_id);
-extern SAAlgorithm *sa_cipher_by_id(int alg_id);
-extern SAAlgorithm *sa_compress_by_id(int alg_id);
-extern SAAlgorithm *sa_digest_by_name(char *name);
-extern SAAlgorithm *sa_cipher_by_name(char *name);
-extern SAAlgorithm *sa_compress_by_name(char *name);
-extern SAAlgorithm *sa_digest_by_index(unsigned int idx);
-extern SAAlgorithm *sa_cipher_by_index(unsigned int idx);
-extern SAAlgorithm *sa_compress_by_index(unsigned int idx);
-extern void sa_algorithm_probe_all(void);
-
-#define MAX_KEY_BITS 512
-
-#endif /* ! __VNET_SA_ALGORITHM_H__ */
+++ /dev/null
-/*
- * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/skbuff.h>
-#include <linux/slab.h>
-
-#include <skb_context.h>
-
-#define MODULE_NAME "VNET"
-#define DEBUG 1
-#undef DEBUG
-#include "debug.h"
-
-SkbContext *SkbContext_create(u32 vnet, u32 addr, int protocol, void *data,
- void (*free_fn)(SkbContext *)){
- SkbContext *context = NULL;
-
- context = kmalloc(sizeof(SkbContext), GFP_ATOMIC);
- if(!context) goto exit;
- context->vnet = vnet;
- context->addr = addr;
- context->protocol = protocol;
- context->data = data;
- context->free_fn = free_fn;
- context->next = NULL;
- atomic_set(&context ->refcount, 1);
- exit:
- return context;
-}
-
-void SkbContext_free(SkbContext *context){
- if(!context) return;
- if(context->next) SkbContext_decref(context->next);
- if(context->free_fn) context->free_fn(context);
- context->vnet = 0;
- context->addr = 0;
- context->protocol = 0;
- context->free_fn = NULL;
- context->data = NULL;
- context->next = NULL;
- kfree(context);
-}
-
-int SkbContext_push(SkbContext **val, u32 vnet, u32 addr, int protocol,
- void *data, void (*free_fn)(SkbContext *)){
- int err = 0;
- SkbContext *context = NULL;
-
- dprintf("> vnet=%u addr=%u.%u.%u.%u protocol=%d\n",
- vnet, NIPQUAD(addr), protocol);
- context = SkbContext_create(vnet, addr, protocol, data, free_fn);
- if(!context){
- err = -ENOMEM;
- goto exit;
- }
- context->next = *val;
- *val = context;
- exit:
- dprintf("< err=%d\n", err);
- return err;
-}
-
-int skb_push_context(struct sk_buff *skb, u32 vnet, u32 addr, int protocol,
- void *data, void (*free_fn)(SkbContext *)){
- int err = 0;
- //SkbContext *ctxt = SKB_CONTEXT(skb);
- dprintf("> skb=%p\n", skb);
-
- //err = SkbContext_push(&ctxt, vnet, addr, protocol, data, free_fn); //todo fixme
- //SKB_CONTEXT(skb) = ctxt;//todo fixme
- dprintf("< err=%d\n", err);
- return err;
-}
-
-
+++ /dev/null
-/*
- * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-
-#ifndef __VNET_SKB_CONTEXT_H__
-#define __VNET_SKB_CONTEXT_H__
-
-#ifdef __KERNEL__
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <asm/atomic.h>
-#include <linux/types.h>
-
-//todo: fixme
-#define SKB_CONTEXT(_skb) ((SkbContext *)(&(_skb)->cb[0]))
-
-#else
-
-#include "sys_kernel.h"
-#include "spinlock.h"
-
-//todo: fixme
-#define SKB_CONTEXT(_skb) ((SkbContext *)NULL)
-
-#endif
-
-/** Structure used to record inbound processing path for skbs.
- * For example, the ETHERIP protocol handler can use this to
- * tell whether an inbound packet came through IPSEC ESP or not.
- */
-typedef struct SkbContext {
- u32 vnet;
- u32 addr;
- int protocol;
- void *data;
- void (*free_fn)(struct SkbContext *);
- atomic_t refcount;
- struct SkbContext *next;
-} SkbContext;
-
-/** Decrement the reference count, freeing if zero.
- *
- * @param context context (may be null)
- */
-static inline void SkbContext_decref(SkbContext *context){
- extern void SkbContext_free(SkbContext *context);
- if(!context) return;
- if(atomic_dec_and_test(&context->refcount)){
- SkbContext_free(context);
- }
-}
-
-/** Increment the reference count.
- *
- * @param context context (may be null)
- */
-static inline void SkbContext_incref(SkbContext *context){
- if(!context) return;
- atomic_inc(&context->refcount);
-}
-
-extern SkbContext *SkbContext_create(u32 vnet, u32 addr, int protocol, void *data,
- void (*free_fn)(SkbContext *));
-
-extern int SkbContext_push(SkbContext **val, u32 vnet, u32 addr, int protocol,
- void *data, void (*free_fn)(SkbContext *));
-
-struct sk_buff;
-extern int skb_push_context(struct sk_buff *skb, u32 vnet, u32 addr, int protocol,
- void *data, void (*free_fn)(SkbContext *));
-
-#endif /* !__VNET_SKB_CONTEXT_H__ */
+++ /dev/null
-/*
- * Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-#ifdef __KERNEL__
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/version.h>
-
-#include <asm/scatterlist.h>
-#include <linux/crypto.h>
-#include <linux/pfkeyv2.h>
-#include <linux/random.h>
-
-#include <linux/net.h>
-#include <linux/in.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/tcp.h>
-#include <linux/udp.h>
-
-#include <net/ip.h>
-#include <net/protocol.h>
-#include <net/route.h>
-#include <linux/skbuff.h>
-
-#else
-
-#include <stdlib.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <errno.h>
-
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include <linux/if_ether.h>
-#include <linux/if_arp.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <linux/udp.h>
-
-#include "sys_kernel.h"
-#include "skbuff.h"
-
-#if defined(__LITTLE_ENDIAN)
-#define HIPQUAD(addr) \
- ((unsigned char *)&addr)[3], \
- ((unsigned char *)&addr)[2], \
- ((unsigned char *)&addr)[1], \
- ((unsigned char *)&addr)[0]
-#elif defined(__BIG_ENDIAN)
-#define HIPQUAD NIPQUAD
-#else
-#error "Please fix asm/byteorder.h"
-#endif /* __LITTLE_ENDIAN */
-
-#endif
-
-#include <varp.h>
-#include <skb_util.h>
-
-#define MODULE_NAME "VNET"
-#define DEBUG 1
-#undef DEBUG
-#include "debug.h"
-
-//============================================================================
-/** Make enough room in an skb for extra header and trailer.
- *
- * @param pskb return parameter for expanded skb
- * @param skb skb
- * @param head_n required headroom
- * @param tail_n required tailroom
- * @return 0 on success, error code otherwise
- */
-int skb_make_room(struct sk_buff **pskb, struct sk_buff *skb, int head_n, int tail_n){
- int err = 0;
- int has_headroom = (head_n <= skb_headroom(skb));
- int has_tailroom = (tail_n <= skb_tailroom(skb));
- int writeable = !skb_cloned(skb) && !skb_shared(skb);
-
- dprintf("> skb=%p headroom=%d head_n=%d tailroom=%d tail_n=%d\n",
- skb,
- skb_headroom(skb), head_n,
- skb_tailroom(skb), tail_n);
- if(writeable && has_headroom && has_tailroom){
- // There's room! Reuse it.
- *pskb = skb;
- } else if(writeable && has_tailroom){
- // Tailroom, no headroom. Expand header the way GRE does.
- struct sk_buff *new_skb = skb_realloc_headroom(skb, head_n + 16);
- if(!new_skb){
- err = -ENOMEM;
- goto exit;
- }
- kfree_skb(skb);
- *pskb = new_skb;
- } else {
- // No room. Expand. There may be more efficient ways to do
- // this, but this is simple and correct.
- struct sk_buff *new_skb = skb_copy_expand(skb, head_n + 16, tail_n, GFP_ATOMIC);
- if(!new_skb){
- err = -ENOMEM;
- goto exit;
- }
- kfree_skb(skb);
- *pskb = new_skb;
- }
- dprintf("> skb=%p headroom=%d head_n=%d tailroom=%d tail_n=%d\n",
- *pskb,
- skb_headroom(*pskb), head_n,
- skb_tailroom(*pskb), tail_n);
- exit:
- dprintf("< err=%d\n", err);
- return err;
-}
-
-/** Copy some data bits from a kernel buffer to an skb.
- * Derived in the obvious way from skb_copy_bits().
- */
-int skb_put_bits(const struct sk_buff *skb, int offset, void *src, int len)
-{
- int i, copy;
- int start = skb->len - skb->data_len;
-
- if (offset > (int)skb->len-len)
- goto fault;
-
- /* Copy header. */
- if ((copy = start-offset) > 0) {
- if (copy > len)
- copy = len;
- memcpy(skb->data + offset, src, copy);
- if ((len -= copy) == 0)
- return 0;
- offset += copy;
- src += copy;
- }
-
-#ifdef __KERNEL__
- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- int end;
-
- BUG_TRAP(start <= offset+len);
-
- end = start + skb_shinfo(skb)->frags[i].size;
- if ((copy = end-offset) > 0) {
- u8 *vaddr;
-
- if (copy > len)
- copy = len;
-
- vaddr = kmap_skb_frag(&skb_shinfo(skb)->frags[i]);
- memcpy(vaddr + skb_shinfo(skb)->frags[i].page_offset + offset - start,
- src,
- copy);
- kunmap_skb_frag(vaddr);
-
- if ((len -= copy) == 0)
- return 0;
- offset += copy;
- src += copy;
- }
- start = end;
- }
-
- if (skb_shinfo(skb)->frag_list) {
- struct sk_buff *list;
-
- for (list = skb_shinfo(skb)->frag_list; list; list=list->next) {
- int end;
-
- BUG_TRAP(start <= offset+len);
-
- end = start + list->len;
- if ((copy = end-offset) > 0) {
- if (copy > len)
- copy = len;
- if (skb_put_bits(list, offset-start, src, copy))
- goto fault;
- if ((len -= copy) == 0)
- return 0;
- offset += copy;
- src += copy;
- }
- start = end;
- }
- }
-#else
- i=0;
-#endif
-
- if (len == 0)
- return 0;
-
- fault:
- return -EFAULT;
-}
-
-int skboffset(struct sk_buff *skb, unsigned char *ptr){
- if(!ptr || ptr < skb->head || ptr > skb->tail){
- return -1;
- }
- return (ptr - skb->head);
-}
-
-/** Print some bits of an skb.
- *
- * @param skb to print
- * @param offset byte offset to start printing at
- * @param n number of bytes to print
- */
-void skb_print_bits(const char *msg, struct sk_buff *skb, int offset, int n){
- int chunk = 16;
- int i, k;
- u8 buff[chunk];
- if(!skb) return;
- printk("%s> tot=%d len=%d data=%d mac=%d nh=%d h=%d\n",
- msg,
- skb->tail - skb->head,
- skb->len,
- skboffset(skb, skb->data),
- skboffset(skb, skb->mac.raw),
- skboffset(skb, skb->nh.raw),
- skboffset(skb, skb->h.raw));
- printk("%s> head=%p data=%p mac=%p nh=%p h=%p tail=%p\n",
- msg, skb->head, skb->data,
- skb->mac.raw, skb->nh.raw, skb->h.raw,
- skb->tail);
- while(n){
- k = (n > chunk ? chunk : n);
- skb_copy_bits(skb, offset, buff, k);
- printk("%03d ", offset);
- for(i=0; i<k; i++){
- if(i == 8)printk(" ");
- printk(":%02x", buff[i] & 0xff);
- }
- printk(" \n");
- n -= k;
- offset += k;
- }
-}
-
-/** Print a buffer.
- *
- * @param buf to print
- * @param n number of bytes to print
- */
-void buf_print(char *buf, int n){
- int i;
- for(i=0; i<n; i++){
- if( i % 16 == 0) printk("\n%04d ", i);
- else if(i % 8 == 0) printk(" ");
- printk(":%02x", buf[i] & 0xff);
- }
- printk(" %04d\n", n);
-}
-
-/** Remove some space from the tail of an skb.
- *
- * @todo fixme: Do we need to handle frags?
- */
-void *skb_trim_tail(struct sk_buff *skb, int n){
- skb->tail -= n;
- skb->len -= n;
- return skb->tail;
-}
-
-#ifdef __KERNEL__
-
-static const int DEBUG_SCATTERLIST = 0;
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-#define SET_SCATTER_ADDR(sg, addr) do{} while(0)
-#else
-#define SET_SCATTER_ADDR(sg, addr) (sg).address = (addr)
-#endif
-
-/** Convert a (possibly fragmented) skb into a scatter list.
- *
- * @param skb skb to convert
- * @param sg scatterlist to set up
- * @param sg_n size of sg on input, number of elements set on output
- * @param offset offset into data to start at
- * @param len number of bytes
- * @return 0 on success, error code otherwise
- */
-int skb_scatterlist(struct sk_buff *skb, struct scatterlist *sg, int *sg_n,
- int offset, int len){
- int err = 0;
- int start; // No. of bytes copied so far (where next copy starts).
- int size; // Size of the next chunk.
- int end; // Where the next chunk ends (start + size).
- int copy; // Number of bytes to copy in one operation.
- int sg_i = 0; // Index into sg.
- int i;
-
- if(DEBUG_SCATTERLIST){
- dprintf("> offset=%d len=%d (end=%d), skb len=%d,\n",
- offset, len, offset+len, skb->len);
- }
- start = 0;
- size = skb_headlen(skb);
- end = start + size;
- copy = end - offset;
- if(copy > 0){
- char *p;
- if(copy > len) copy = len;
- if(sg_i >= *sg_n){
- err = -EINVAL;
- goto exit;
- }
- p = skb->data + offset;
- SET_SCATTER_ADDR(sg[sg_i], NULL);
- sg[sg_i].page = virt_to_page(p);
- sg[sg_i].offset = ((unsigned long)p & ~PAGE_MASK);
- sg[sg_i].length = copy;
- if(DEBUG_SCATTERLIST){
- dprintf("> sg_i=%d .page=%p .offset=%u .length=%d\n",
- sg_i, sg[sg_i].page, sg[sg_i].offset, sg[sg_i].length);
- }
- sg_i++;
- if((len -= copy) == 0) goto exit;
- offset += copy;
- }
- start = end;
- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++){
- BUG_TRAP(start <= offset + len);
- size = skb_shinfo(skb)->frags[i].size;
- end = start + size;
- copy = end - offset;
- if(copy > 0){
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- if(copy > len) copy = len;
- if(sg_i >= *sg_n){
- err = -EINVAL;
- goto exit;
- }
- SET_SCATTER_ADDR(sg[sg_i], NULL);
- sg[sg_i].page = frag->page;
- sg[sg_i].offset = frag->page_offset + offset - start;
- sg[sg_i].length = copy;
- if(DEBUG_SCATTERLIST){
- dprintf("> sg_i=%d .page=%p .offset=%u .length=%d\n",
- sg_i, sg[sg_i].page, sg[sg_i].offset, sg[sg_i].length);
- }
- sg_i++;
- if((len -= copy) == 0) goto exit;
- offset += copy;
- }
- start = end;
- }
- exit:
- if(!err) *sg_n = sg_i;
- if(len) wprintf("> len=%d\n", len);
- if(len) BUG();
- if(err) dprintf("< err=%d sg_n=%d\n", err, *sg_n);
- return err;
-}
-
-#endif
-
-void print_skb_data(const char *msg, int count, struct sk_buff *skb, u8 *data, int len)
-{
- static int skb_count = 1000000;
- u8 *ptr, *end;
- u32 src_addr, dst_addr;
- // Transport layer header.
- union {
- struct tcphdr *th;
- struct udphdr *uh;
- struct icmphdr *icmph;
- struct igmphdr *igmph;
- struct iphdr *ipiph;
- unsigned char *raw;
- } h;
- // Network layer header.
- union {
- struct iphdr *iph;
- struct ipv6hdr *ipv6h;
- struct arpheader *arph;
- struct ipxhdr *ipxh;
- unsigned char *raw;
- } nh;
- // Link layer header.
- union {
- struct ethhdr *ethernet;
- unsigned char *raw;
- } mac;
- int protocol;
- if(!count) count = ++skb_count;
- if(!msg) msg = (char *)__FUNCTION__;
- if(!data){
- printk("%s.%d> null data\n", msg, count);
- return;
- }
- ptr = data;
- end = data + len;
- mac.raw = ptr;
- ptr += sizeof(struct ethhdr);
- if(ptr > end){ printk("***MAC:"); goto exit; }
- protocol = ntohs(mac.ethernet->h_proto);
- nh.raw = ptr;
-
- printk("%s.%d> type=%d protocol=0x%x\n",
- msg, count, skb->pkt_type, htons(skb->protocol));
- if(1){
- printk("%s.%d> %p mac src=" MACFMT " dst=" MACFMT "\n",
- msg, count, data,
- MAC6TUPLE(mac.ethernet->h_source),
- MAC6TUPLE(mac.ethernet->h_dest));
- }
-
- switch(protocol){
- case ETH_P_ARP:
- ptr += sizeof(struct arpheader);
- if(ptr > end){ printk("***ARP:"); goto exit; }
- if(0){
- printk("%s.%d> ARP hrd=%d, pro=%d, hln=%d, pln=%d, op=%d\n",
- msg, count,
- nh.arph->ar_hrd, nh.arph->ar_pro, nh.arph->ar_hln,
- nh.arph->ar_pln, nh.arph->ar_op);
- }
- memcpy(&src_addr, nh.arph->ar_sip, 4);
- src_addr = ntohl(src_addr);
- memcpy(&dst_addr, nh.arph->ar_tip, 4);
- dst_addr = ntohl(dst_addr);
- printk("%s.%d> ARP HW src=" MACFMT " dst=" MACFMT "\n",
- msg, count, MAC6TUPLE(nh.arph->ar_sha), MAC6TUPLE(nh.arph->ar_tha));
- printk("%s.%d> ARP IP src=" IPFMT " dst=" IPFMT "\n",
- msg, count, HIPQUAD(src_addr), HIPQUAD(dst_addr));
- break;
- case ETH_P_IP: {
- u16 src_port, dst_port;
- if(ptr + sizeof(struct iphdr) > end){ printk("***IP:"); goto exit; }
- src_addr = ntohl(nh.iph->saddr);
- dst_addr = ntohl(nh.iph->daddr);
- if(1){
- printk("%s.%d> IP proto=%d src=" IPFMT " dst=" IPFMT "\n",
- msg, count, nh.iph->protocol,
- HIPQUAD(src_addr), HIPQUAD(dst_addr));
- printk("%s.%d> IP tot_len=%u len=%d\n",
- msg, count, ntohs(nh.iph->tot_len), len - ETH_HLEN);
- }
- ptr += (nh.iph->ihl * 4);
- if(ptr > end){ printk ("***IP: len"); goto exit; }
- h.raw = ptr;
- switch(nh.iph->protocol){
- case IPPROTO_TCP:
- ptr += sizeof(struct tcphdr);
- if(ptr > end){ printk("***TCP:"); goto exit; }
- src_port = ntohs(h.th->source);
- dst_port = ntohs(h.th->dest);
- printk("%s.%d> TCP src=" IPFMT ":%u dst=" IPFMT ":%u\n",
- msg, count,
- HIPQUAD(src_addr), src_port,
- HIPQUAD(dst_addr), dst_port);
- break;
- case IPPROTO_UDP:
- ptr += sizeof(struct udphdr);
- if(ptr > end){ printk("***UDP:"); goto exit; }
- src_port = ntohs(h.uh->source);
- dst_port = ntohs(h.uh->dest);
- printk("%s.%d> UDP src=" IPFMT ":%u dst=" IPFMT ":%u\n",
- msg, count,
- HIPQUAD(src_addr), src_port,
- HIPQUAD(dst_addr), dst_port);
- break;
- default:
- printk("%s.%d> IP %d src=" IPFMT " dst=" IPFMT "\n",
- msg, count,
- nh.iph->protocol, HIPQUAD(src_addr), HIPQUAD(dst_addr));
- break;
- }
- break; }
- case ETH_P_IPV6:
- printk("%s.%d> IPv6\n", msg, count);
- break;
- case ETH_P_IPX:
- printk("%s.%d> IPX\n", msg, count);
- break;
- default:
- printk("%s.%d> protocol=%d\n", msg, count, protocol);
- break;
- }
- return;
- exit:
- printk("%s.%d> %s: skb problem\n", msg, count, __FUNCTION__);
- printk("%s.%d> %s: data=%p end=%p(%d) ptr=%p(%d) eth=%d ip=%d\n",
- msg, count, __FUNCTION__,
- data, end, end - data, ptr, ptr - data,
- sizeof(struct ethhdr),
- sizeof(struct iphdr));
- return;
-}
-
-void print_skb(const char *msg, int count, struct sk_buff *skb){
- print_skb_data(msg, count, skb, skb->mac.raw, skb->tail - skb->mac.raw);
-}
-
-void print_ethhdr(const char *msg, struct sk_buff *skb){
- struct ethhdr *eth;
-
- if(!skb || skboffset(skb, skb->mac.raw) < 0) return;
- eth = eth_hdr(skb);
- printk("%s> ETH proto=%d src=" MACFMT " dst=" MACFMT "\n",
- msg,
- ntohs(eth->h_proto),
- MAC6TUPLE(eth->h_source),
- MAC6TUPLE(eth->h_dest));
-}
-
-void print_iphdr(const char *msg, struct sk_buff *skb){
- u32 src_addr, dst_addr;
-
- if(!skb || skboffset(skb, skb->nh.raw) < 0) return;
- src_addr = ntohl(skb->nh.iph->saddr);
- dst_addr = ntohl(skb->nh.iph->daddr);
- printk("%s> IP proto=%d src=" IPFMT " dst=" IPFMT " tot_len=%u\n",
- msg,
- skb->nh.iph->protocol,
- HIPQUAD(src_addr),
- HIPQUAD(dst_addr),
- ntohs(skb->nh.iph->tot_len));
-}
-
-void print_udphdr(const char *msg, struct sk_buff *skb){
- if(!skb || skboffset(skb, skb->h.raw) < 0) return;
- printk("%s> UDP src=%u dst=%u len=%u\n",
- msg,
- ntohs(skb->h.uh->source),
- ntohs(skb->h.uh->dest),
- ntohs(skb->h.uh->len));
-}
+++ /dev/null
-/*
- * Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-#ifndef _VNET_SKB_UTIL_H_
-#define _VNET_SKB_UTIL_H_
-
-#ifdef __KERNEL__
-#include <net/route.h>
-#include <linux/skbuff.h>
-
-#else
-
-#include "skbuff.h"
-
-#endif
-
-struct sk_buff;
-
-extern int skb_make_room(struct sk_buff **pskb, struct sk_buff *skb, int head_n, int tail_n);
-
-extern int skb_put_bits(const struct sk_buff *skb, int offset, void *src, int len);
-
-extern void skb_print_bits(const char *msg, struct sk_buff *skb, int offset, int n);
-
-extern void buf_print(char *buf, int n);
-
-extern void *skb_trim_tail(struct sk_buff *skb, int n);
-
-extern void print_skb_data(const char *msg, int count, struct sk_buff *skb, u8 *data, int len);
-extern void print_skb(const char *msg, int count, struct sk_buff *skb);
-
-extern void print_ethhdr(const char *msg, struct sk_buff *skb);
-extern void print_iphdr(const char *msg, struct sk_buff *skb);
-extern void print_udphdr(const char *msg, struct sk_buff *skb);
-
-/* The mac.ethernet field went away in 2.6 in favour of eth_hdr().
- */
-#ifdef __KERNEL__
-# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
-# define NEED_ETH_HDR
-# endif
-#else
-# define NEED_ETH_HDR
-#endif
-
-#ifdef NEED_ETH_HDR
-
-static inline struct ethhdr *eth_hdr(const struct sk_buff *skb)
-{
- return (struct ethhdr *)skb->mac.raw;
-}
-
-#endif
-
-/*
- * It's a copy from {kernel}/include/linux/skbuff.h func '__skb_pull' and 'skb_pull'
- * to aviodthe BUG_ON when pulling into the data (getting forwarded ip-frames)
- */
-static inline unsigned char *__skb_pull_vn(struct sk_buff *skb, unsigned int len)
-{
- skb->len -= len;
- //BUG_ON(skb->len < skb->data_len);
- return skb->data += len;
-}
-static inline unsigned char *skb_pull_vn(struct sk_buff *skb, unsigned int len)
-{
- return unlikely(len > skb->len) ? NULL : __skb_pull_vn(skb, len);
-}
-
-
-#ifdef __KERNEL__
-
-struct scatterlist;
-
-extern int skb_scatterlist(struct sk_buff *skb, struct scatterlist *sg,
- int *sg_n, int offset, int len);
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-
-static inline int skb_route(struct sk_buff *skb, struct rtable **prt){
- int err = 0;
- struct flowi fl = {
- .nl_u = {
- .ip4_u = {
- .daddr = skb->nh.iph->daddr,
- .saddr = skb->nh.iph->saddr,
- .tos = skb->nh.iph->tos,
- }
- }
- };
-
- if(skb->dev){
- fl.oif = skb->dev->ifindex;
- }
- err = ip_route_output_key(prt, &fl);
- return err;
-}
-
-#else
-
-static inline int skb_route(struct sk_buff *skb, struct rtable **prt){
- int err = 0;
- struct rt_key key = { };
- key.dst = skb->nh.iph->daddr;
- key.src = skb->nh.iph->saddr;
- key.tos = skb->nh.iph->tos;
- if(skb->dev){
- key.oif = skb->dev->ifindex;
- }
- err = ip_route_output_key(prt, &key);
- return err;
-}
-
-#endif
-
-#endif /* __KERNEL__ */
-
-/** Arp header struct with all the fields so we can access them. */
-struct arpheader
-{
- unsigned short ar_hrd; /* format of hardware address */
- unsigned short ar_pro; /* format of protocol address */
- unsigned char ar_hln; /* length of hardware address */
- unsigned char ar_pln; /* length of protocol address */
- unsigned short ar_op; /* ARP opcode (command) */
-
-#if 1
- /*
- * Ethernet looks like this : This bit is variable sized however...
- */
- unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
- unsigned char ar_sip[4]; /* sender IP address */
- unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
- unsigned char ar_tip[4]; /* target IP address */
-#endif
-
-};
-
-#endif /* ! _VNET_SKB_UTIL_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2005 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-#include "sys_net.h"
-#include "if_varp.h"
-#include "varp_util.h"
-#include "sxpr_util.h"
-
-int stringof(Sxpr exp, char **s){
- int err = 0;
- if(ATOMP(exp)){
- *s = atom_name(exp);
- } else if(STRINGP(exp)){
- *s = string_string(exp);
- } else {
- err = -EINVAL;
- *s = NULL;
- }
- return err;
-}
-
-int child_string(Sxpr exp, Sxpr key, char **s){
- int err = 0;
- Sxpr val = sxpr_child_value(exp, key, ONONE);
- err = stringof(val, s);
- return err;
-}
-
-int intof(Sxpr exp, int *v){
- int err = 0;
- char *s;
- unsigned long l;
- if(INTP(exp)){
- *v = OBJ_INT(exp);
- } else {
- err = stringof(exp, &s);
- if(err) goto exit;
- err = convert_atoul(s, &l);
- *v = (int)l;
- }
- exit:
- return err;
-}
-
-int child_int(Sxpr exp, Sxpr key, int *v){
- int err = 0;
- Sxpr val = sxpr_child_value(exp, key, ONONE);
- err = intof(val, v);
- return err;
-}
-
-int vnetof(Sxpr exp, VnetId *v){
- int err = 0;
- char *s;
- err = stringof(exp, &s);
- if(err) goto exit;
- err = VnetId_aton(s, v);
- exit:
- return err;
-}
-
-int child_vnet(Sxpr exp, Sxpr key, VnetId *v){
- int err = 0;
- Sxpr val = sxpr_child_value(exp, key, ONONE);
- err = vnetof(val, v);
- return err;
-}
-
-int macof(Sxpr exp, unsigned char *v){
- int err = 0;
- char *s;
- err = stringof(exp, &s);
- if(err) goto exit;
- err = mac_aton(s, v);
- exit:
- return err;
-}
-
-int child_mac(Sxpr exp, Sxpr key, unsigned char *v){
- int err = 0;
- Sxpr val = sxpr_child_value(exp, key, ONONE);
- err = macof(val, v);
- return err;
-}
-
-int addrof(Sxpr exp, uint32_t *v){
- int err = 0;
- char *s;
- unsigned long w;
- err = stringof(exp, &s);
- if(err) goto exit;
- err = get_inet_addr(s, &w);
- if(err) goto exit;
- *v = (uint32_t)w;
- exit:
- return err;
-}
-
-int child_addr(Sxpr exp, Sxpr key, uint32_t *v){
- int err = 0;
- Sxpr val = sxpr_child_value(exp, key, ONONE);
- err = addrof(val, v);
- return err;
-}
+++ /dev/null
-/*
- * Copyright (C) 2005 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-#ifndef _SXPR_UTIL_H_
-#define _SXPR_UTIL__H_
-
-#include "sxpr.h"
-struct VnetId;
-
-int stringof(Sxpr exp, char **s);
-int child_string(Sxpr exp, Sxpr key, char **s);
-int intof(Sxpr exp, int *v);
-int child_int(Sxpr exp, Sxpr key, int *v);
-int vnetof(Sxpr exp, struct VnetId *v);
-int child_vnet(Sxpr exp, Sxpr key, struct VnetId *v);
-int macof(Sxpr exp, unsigned char *v);
-int child_mac(Sxpr exp, Sxpr key, unsigned char *v);
-int addrof(Sxpr exp, uint32_t *v);
-int child_addr(Sxpr exp, Sxpr key, uint32_t *v);
-
-#endif /* ! _SXPR_UTIL_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2005 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-
-#ifdef __KERNEL__
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/version.h>
-
-#include <linux/spinlock.h>
-#include <asm/semaphore.h>
-
-#else
-
-#include "sys_kernel.h"
-#include "spinlock.h"
-
-#endif
-
-#include "timer_util.h"
-
-#define MODULE_NAME "TIMER"
-#define DEBUG 1
-#undef DEBUG
-#include "debug.h"
-
-#ifdef __KERNEL__
-
-void timer_init(struct timer_list *timer, void (*fn)(unsigned long), void *data){
- init_timer(timer);
- timer->data = (unsigned long)data;
- timer->function = fn;
-}
-
-void timer_set(struct timer_list *timer, unsigned long ttl){
- unsigned long now = jiffies;
- timer->expires = now + ttl;
- add_timer(timer);
-}
-
-#else
-
-void timer_init(struct Timer *timer, void (*fn)(unsigned long), void *data){
- *timer = (struct Timer){};
- timer->data = (unsigned long)data;
- timer->fn = fn;
-}
-
-void timer_set(struct Timer *timer, unsigned long ttl){
- double now = time_now();
- timer->expiry = now + (double)ttl/(double)HZ;
- Timer_cancel(timer);
- Timer_add(timer);
-}
-
-#endif
+++ /dev/null
-/*
- * Copyright (C) 2005 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-
-#ifndef _VNET_TIMER_UTIL_H_
-#define _VNET_TIMER_UTIL_H_
-
-#ifdef __KERNEL__
-
-struct timer_list;
-#define timer_cancel del_timer
-
-#else /* __KERNEL__ */
-
-#include "timer.h"
-#define timer_list Timer
-#define HZ 1000
-#define jiffies (unsigned long)(time_now() * HZ)
-#define timer_cancel Timer_cancel
-
-#endif /* __KERNEL__ */
-
-void timer_init(struct timer_list *timer, void (*fn)(unsigned long), void *data);
-void timer_set(struct timer_list *timer, unsigned long ttl);
-
-#endif /*! _VNET_TIMER_UTIL_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-#ifdef __KERNEL__
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-
-#else
-
-#include "sys_kernel.h"
-#include "spinlock.h"
-#include "skbuff.h"
-
-#endif
-
-#include <tunnel.h>
-#include <vnet.h>
-#include <varp.h>
-#include "hash_table.h"
-
-#define MODULE_NAME "VNET"
-#define DEBUG 1
-#undef DEBUG
-#include "debug.h"
-
-/** Table of tunnels, indexed by vnet and addr. */
-HashTable *tunnel_table = NULL;
-rwlock_t tunnel_table_lock = RW_LOCK_UNLOCKED;
-
-#define tunnel_read_lock(flags) read_lock_irqsave(&tunnel_table_lock, (flags))
-#define tunnel_read_unlock(flags) read_unlock_irqrestore(&tunnel_table_lock, (flags))
-#define tunnel_write_lock(flags) write_lock_irqsave(&tunnel_table_lock, (flags))
-#define tunnel_write_unlock(flags) write_unlock_irqrestore(&tunnel_table_lock, (flags))
-
-void Tunnel_free(Tunnel *tunnel){
- tunnel->type->close(tunnel);
- Tunnel_decref(tunnel->base);
- kfree(tunnel);
-}
-
-void Tunnel_print(Tunnel *tunnel){
- if(tunnel){
- iprintf("Tunnel<%p base=%p ref=%02d type=%s>\n",
- tunnel,
- tunnel->base,
- atomic_read(&tunnel->refcount),
- tunnel->type->name);
- if(tunnel->base){
- Tunnel_print(tunnel->base);
- }
- } else {
- iprintf("Tunnel<%p base=%p ref=%02d type=%s>\n",
- NULL, NULL, 0, "ip");
- }
-}
-
-int Tunnel_create(TunnelType *type, VnetId *vnet, VarpAddr *addr,
- Tunnel *base, Tunnel **val){
- int err = 0;
- Tunnel *tunnel = NULL;
- if(!type || !type->open || !type->send || !type->close){
- err = -EINVAL;
- goto exit;
- }
- tunnel = kmalloc(sizeof(Tunnel), GFP_ATOMIC);
- if(!tunnel){
- err = -ENOMEM;
- goto exit;
- }
- atomic_set(&tunnel->refcount, 1);
- tunnel->key.vnet = *vnet;
- tunnel->key.addr = *addr;
- tunnel->type = type;
- tunnel->data = NULL;
- tunnel->send_stats = (TunnelStats){};
- Tunnel_incref(base);
- tunnel->base = base;
- err = type->open(tunnel);
- exit:
- if(err && tunnel){
- Tunnel_decref(tunnel);
- tunnel = NULL;
- }
- *val = tunnel;
- dprintf("< err=%d\n", err);
- return err;
-}
-
-void TunnelStats_update(TunnelStats *stats, int len, int err){
- dprintf(">len=%d err=%d\n", len, err);
- if(err){
- stats->dropped_bytes += len;
- stats->dropped_packets++;
- } else {
- stats->bytes += len;
- stats->packets++;
- }
- dprintf("<\n");
-}
-
-static inline Hashcode tunnel_table_key_hash_fn(void *k){
- return hash_hvoid(0, k, sizeof(TunnelKey));
-}
-
-static int tunnel_table_key_equal_fn(void *k1, void *k2){
- return memcmp(k1, k2, sizeof(TunnelKey)) == 0;
-}
-
-static void tunnel_table_entry_free_fn(HashTable *table, HTEntry *entry){
- Tunnel *tunnel;
- if(!entry) return;
- tunnel = entry->value;
- Tunnel_decref(tunnel);
- HTEntry_free(entry);
-}
-
-int Tunnel_init(void){
- int err = 0;
- dprintf(">\n");
- tunnel_table = HashTable_new(0);
- if(!tunnel_table){
- err = -ENOMEM;
- goto exit;
- }
- tunnel_table->entry_free_fn = tunnel_table_entry_free_fn;
- tunnel_table->key_size = sizeof(TunnelKey);
- tunnel_table->key_hash_fn = tunnel_table_key_hash_fn;
- tunnel_table->key_equal_fn = tunnel_table_key_equal_fn;
- exit:
- dprintf("< err=%d\n", err);
- return err;
-}
-
-/** Lookup tunnel state by vnet and destination.
- * The caller must drop the tunnel reference when done.
- *
- * @param vnet vnet
- * @param addr destination address
- * @return 0 on success
- */
-int Tunnel_lookup(VnetId *vnet, VarpAddr *addr, Tunnel **tunnel){
- unsigned long flags;
- TunnelKey key = { .vnet = *vnet, .addr = *addr };
- dprintf(">\n");
- tunnel_read_lock(flags);
- *tunnel = HashTable_get(tunnel_table, &key);
- tunnel_read_unlock(flags);
- Tunnel_incref(*tunnel);
- dprintf("< tunnel=%p\n", *tunnel);
- return (*tunnel ? 0 : -ENOENT);
-}
-
-/** Get a tunnel to a given vnet and destination, creating
- * a tunnel if necessary.
- * The caller must drop the tunnel reference when done.
- *
- * @param vnet vnet
- * @param addr destination address
- * @param ctor tunnel constructor
- * @parma ptunnel return parameter for the tunnel
- * @return 0 on success
- */
-int Tunnel_open(VnetId *vnet, VarpAddr *addr,
- int (*ctor)(VnetId *vnet, VarpAddr *addr, Tunnel **ptunnel),
- Tunnel **ptunnel){
- int err = 0;
- Tunnel *tunnel = NULL;
- unsigned long flags;
- TunnelKey key = { .vnet = *vnet, .addr = *addr };
-
- tunnel_write_lock(flags);
- tunnel = HashTable_get(tunnel_table, &key);
- if(!tunnel){
- err = ctor(vnet, addr, &tunnel);
- if(err) goto exit;
- if(!HashTable_add(tunnel_table, tunnel, tunnel)){
- err = -ENOMEM;
- goto exit;
- }
- }
- exit:
- tunnel_write_unlock(flags);
- if(err){
- Tunnel_decref(tunnel);
- *ptunnel = NULL;
- } else {
- Tunnel_incref(tunnel);
- *ptunnel = tunnel;
- }
- return err;
-}
-
-int Tunnel_add(Tunnel *tunnel){
- int err = 0;
- unsigned long flags;
- dprintf(">\n");
- tunnel_write_lock(flags);
- if(HashTable_add(tunnel_table, tunnel, tunnel)){
- Tunnel_incref(tunnel);
- } else {
- err = -ENOMEM;
- }
- tunnel_write_unlock(flags);
- dprintf("< err=%d\n", err);
- return err;
-}
-
-int Tunnel_del(Tunnel *tunnel){
- int err;
- unsigned long flags;
- tunnel_write_lock(flags);
- err = HashTable_remove(tunnel_table, tunnel);
- tunnel_write_unlock(flags);
- return err;
-}
-
-/** Do tunnel send processing on a packet.
- *
- * @param tunnel tunnel state
- * @param skb packet
- * @return 0 on success, error code otherwise
- */
-int Tunnel_send(Tunnel *tunnel, struct sk_buff *skb){
- int err = 0;
- dprintf("> tunnel=%p skb=%p\n", tunnel, skb);
- if(tunnel){
- int len = skb->len;
- dprintf("> type=%s type->send...\n", tunnel->type->name);
- // Must not refer to skb after sending - might have been freed.
- err = tunnel->type->send(tunnel, skb);
- TunnelStats_update(&tunnel->send_stats, len, err);
- } else {
- err = skb_xmit(skb);
- }
- dprintf("< err=%d\n", err);
- return err;
-}
-
-int __init tunnel_module_init(void){
- return Tunnel_init();
-}
-
-void __exit tunnel_module_exit(void){
- unsigned long flags;
- tunnel_write_lock(flags);
- if(tunnel_table){
- HashTable_free(tunnel_table);
- tunnel_table = NULL;
- }
- tunnel_write_unlock(flags);
-}
+++ /dev/null
-/*
- * Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-#ifndef __VNET_TUNNEL_H__
-#define __VNET_TUNNEL_H__
-
-#ifdef __KERNEL__
-#include <linux/types.h>
-#include <asm/atomic.h>
-
-#else
-
-//#include <linux/types.h>
-#include "sys_kernel.h"
-#include "spinlock.h"
-
-#endif
-
-#include <if_varp.h>
-
-struct sk_buff;
-struct Tunnel;
-
-typedef struct TunnelType {
- const char *name;
- int (*open)(struct Tunnel *tunnel);
- int (*send)(struct Tunnel *tunnel, struct sk_buff *skb);
- void (*close)(struct Tunnel *tunnel);
-} TunnelType;
-
-typedef struct TunnelStats {
- int bytes;
- int packets;
- int dropped_bytes;
- int dropped_packets;
-} TunnelStats;
-
-typedef struct TunnelKey {
- struct VnetId vnet;
- struct VarpAddr addr;
-} TunnelKey;
-
-typedef struct Tunnel {
- /** Key identifying the tunnel. Must be first. */
- struct TunnelKey key;
- /** Reference count. */
- atomic_t refcount;
- /** Tunnel type. */
- struct TunnelType *type;
- /** Statistics. */
- struct TunnelStats send_stats;
- /** Type-dependent state. */
- void *data;
- /** Underlying tunnel (may be null). */
- struct Tunnel *base;
-} Tunnel;
-
-extern void Tunnel_free(struct Tunnel *tunnel);
-
-/** Decrement the reference count, freeing if zero.
- *
- * @param tunnel tunnel (may be null)
- */
-static inline void Tunnel_decref(struct Tunnel *tunnel){
- if(!tunnel) return;
- if(atomic_dec_and_test(&tunnel->refcount)){
- Tunnel_free(tunnel);
- }
-}
-
-/** Increment the reference count.
- *
- * @param tunnel tunnel (may be null)
- */
-static inline void Tunnel_incref(struct Tunnel *tunnel){
- if(!tunnel) return;
- atomic_inc(&tunnel->refcount);
-}
-
-extern int Tunnel_init(void);
-extern int Tunnel_lookup(struct VnetId *vnet, struct VarpAddr *addr, struct Tunnel **tunnel);
-extern int Tunnel_open(struct VnetId *vnet, struct VarpAddr *addr,
- int (*ctor)(struct VnetId *vnet,
- struct VarpAddr *addr,
- struct Tunnel **ptunnel),
- struct Tunnel **ptunnel);
-extern int Tunnel_add(struct Tunnel *tunnel);
-extern int Tunnel_del(struct Tunnel *tunnel);
-extern void Tunnel_print(struct Tunnel *tunnel);
-extern int Tunnel_send(struct Tunnel *tunnel, struct sk_buff *skb);
-
-extern int Tunnel_create(struct TunnelType *type, struct VnetId *vnet, struct VarpAddr *addr,
- struct Tunnel *base, struct Tunnel **tunnelp);
-
-extern int tunnel_module_init(void);
-extern void tunnel_module_exit(void);
-
-#endif /* !__VNET_TUNNEL_H__ */
+++ /dev/null
-/*
- * Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-
-#ifdef __KERNEL__
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/version.h>
-
-#include <linux/net.h>
-#include <linux/in.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/udp.h>
-
-#include <net/ip.h>
-#include <net/protocol.h>
-#include <net/route.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-#include <asm/semaphore.h>
-
-#else
-
-#include "sys_kernel.h"
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <linux/ip.h>
-#include <linux/udp.h>
-#include "spinlock.h"
-#include "skbuff.h"
-
-#endif
-
-#include <tunnel.h>
-#include <vnet.h>
-#include <vif.h>
-#include <if_varp.h>
-#include <varp.h>
-#include <varp_util.h>
-#include <vnet.h>
-#include <etherip.h>
-#include <vnet_forward.h>
-
-#include "allocate.h"
-#include "iostream.h"
-#include "hash_table.h"
-#include "sys_net.h"
-#include "sys_string.h"
-#include "skb_util.h"
-#include "timer_util.h"
-
-#define MODULE_NAME "VARP"
-#define DEBUG 1
-#undef DEBUG
-#include "debug.h"
-
-/** @file VARP: Virtual ARP.
- *
- * Handles virtual ARP requests for vnet/vmac.
- */
-
-/*
-
-Varp uses UDP on port 1798.
-
-on domain up: ?
- send varp.announce { id, vmac, vnet, coa } for each vif
- that haven't announced before, or has changed.
- install vif entries in local table.
-
-on varp.announce{ id, vmac, vnet, coa }:
- update VARP entry for vmac x vnet if have one, reset ttl.
-
-on varp.request { id, vmac, vnet }:
- if have a vif for the requested vmac/vnet,
- reply with varp.announce{ id, vmac, vnet, coa }
-
-on timer:
- traverse VARP table, flush old entries.
-
-on probe timer:
- probe again if not out of tries.
- if out of tries invalidate entry.
-
-*/
-
-/** Time-to-live of varp entries (in jiffies).*/
-#define VARP_ENTRY_TTL (60*HZ)
-
-/** Maximum number of varp probes to make. */
-#define VARP_PROBE_MAX 5
-
-/** Interval between varp probes (in jiffies). */
-#define VARP_PROBE_INTERVAL (3*HZ)
-
-/** Maximum number of queued skbs for a varp entry. */
-#define VARP_QUEUE_MAX 16
-
-/** Number of buckets in the varp table (must be prime). */
-#define VARP_TABLE_BUCKETS 3001
-
-/** Varp entry states. */
-enum {
- VARP_STATE_INCOMPLETE = 1,
- VARP_STATE_REACHABLE = 2,
- VARP_STATE_FAILED = 3,
-};
-
-/** Varp entry flags. */
-enum {
- VARP_FLAG_PROBING = 1,
- VARP_FLAG_PERMANENT = 2,
-};
-
-/** Key for varp entries. */
-typedef struct VarpKey {
- /** Vnet id (network order). */
- VnetId vnet;
- /** Virtual MAC address. */
- Vmac vmac;
-} VarpKey;
-
-/** An entry in the varp cache. */
-typedef struct VarpEntry {
- /** Key for the entry. */
- VarpKey key;
- /** Care-of address for the key. */
- VarpAddr addr;
- /** Last-updated timestamp. */
- unsigned long timestamp;
- /** State. */
- short state;
- /** Flags. */
- short flags;
- /** Reference count. */
- atomic_t refcount;
- /** Lock. */
- rwlock_t lock;
- unsigned long lflags;
-
- /** How many probes have been made. */
- atomic_t probes;
- /** Probe timer. */
- struct timer_list timer;
- void (*error)(struct VarpEntry *ventry, struct sk_buff *skb);
- /** Outbound skb queue. */
- struct sk_buff_head queue;
- /** Maximum size of the queue. */
- int queue_max;
- atomic_t deleted;
-} VarpEntry;
-
-/** The varp cache. Varp entries indexed by VarpKey. */
-typedef struct VarpTable {
-
- HashTable *table;
-
- /** Sweep timer. */
- struct timer_list timer;
-
- rwlock_t lock;
- struct semaphore mutex;
-
- int entry_ttl;
- int probe_max;
- int probe_interval;
- int queue_max;
-
-} VarpTable;
-
-/** The varp cache. */
-static VarpTable *varp_table = NULL;
-
-/** Module parameter for the multicast address. */
-static char *varp_mcaddr = NULL;
-
-/** Multicast address (network order). */
-u32 varp_mcast_addr = 0;
-
-/** UDP port (network order). */
-u16 varp_port = 0;
-
-char *varp_device = "xen-br0";
-
-#define VarpTable_read_lock(vtable, flags) \
- do{ read_lock_irqsave(&(vtable)->lock, (flags)); } while(0)
-
-#define VarpTable_read_unlock(vtable, flags) \
- do{ read_unlock_irqrestore(&(vtable)->lock, (flags)); } while(0)
-
-#define VarpTable_write_lock(vtable, flags) \
- do{ write_lock_irqsave(&(vtable)->lock, (flags)); } while(0)
-
-#define VarpTable_write_unlock(vtable, flags) \
- do{ write_unlock_irqrestore(&(vtable)->lock, (flags)); } while(0)
-
-#define VarpEntry_lock(ventry, flags) \
- do{ write_lock_irqsave(&(ventry)->lock, (flags)); (ventry)->lflags = (flags); } while(0)
-
-#define VarpEntry_unlock(ventry, flags) \
- do{ (flags) = (ventry)->lflags; write_unlock_irqrestore(&(ventry)->lock, (flags)); } while(0)
-
-void VarpTable_sweep(VarpTable *vtable);
-void VarpTable_flush(VarpTable *vtable);
-void VarpTable_print(VarpTable *vtable, IOStream *io);
-int VarpEntry_output(VarpEntry *ventry, struct sk_buff *skb);
-
-#include "./varp_util.c"
-
-/** Print the varp cache (if debug on).
- */
-void varp_dprint(void){
-#ifdef DEBUG
- VarpTable_print(varp_table, iostdout);
-#endif
-}
-
-/** Flush the varp cache.
- */
-void varp_flush(void){
- VarpTable_flush(varp_table);
-}
-
-#ifdef __KERNEL__
-static int device_ucast_addr(const char *device, uint32_t *addr)
-{
- int err;
- struct net_device *dev = NULL;
-
- err = vnet_get_device(device, &dev);
- if(err) goto exit;
- err = vnet_get_device_address(dev, addr);
- exit:
- if(err){
- *addr = 0;
- }
- return err;
-}
-
-/** Get the unicast address of the varp device.
- */
-int varp_ucast_addr(uint32_t *addr)
-{
- int err = -ENODEV;
- const char *devices[] = { varp_device, "eth0", "eth1", "eth2", NULL };
- const char **p;
- for(p = devices; err && *p; p++){
- err = device_ucast_addr(*p, addr);
- }
- return err;
-}
-
-/** Lookup a network device by name.
- *
- * @param name device name
- * @param dev return parameter for the device
- * @return 0 on success, error code otherwise
- */
-int vnet_get_device(const char *name, struct net_device **dev){
- int err = 0;
- *dev = dev_get_by_name(name);
- if(!*dev){
- err = -ENETDOWN;
- }
- return err;
-}
-
-/** Get the source address from a device.
- *
- * @param dev device
- * @param addr return parameter for address
- * @return 0 on success, error code otherwise
- */
-int vnet_get_device_address(struct net_device *dev, u32 *addr){
- int err = 0;
- struct in_device *in_dev;
-
- in_dev = in_dev_get(dev);
- if(!in_dev){
- err = -ENODEV;
- goto exit;
- }
- *addr = in_dev->ifa_list->ifa_address;
- in_dev_put(in_dev);
- exit:
- return err;
-}
-
-#else
-
-int varp_ucast_addr(uint32_t *addr)
-{
- return 0;
-}
-
-#endif
-
-/** Print varp info and the varp cache.
- */
-void varp_print(IOStream *io){
- uint32_t addr = 0;
- varp_ucast_addr(&addr);
-
- IOStream_print(io, "(varp \n");
- IOStream_print(io, " (device %s)\n", varp_device);
- IOStream_print(io, " (mcast_addr " IPFMT ")\n", NIPQUAD(varp_mcast_addr));
- IOStream_print(io, " (ucast_addr " IPFMT ")\n", NIPQUAD(addr));
- IOStream_print(io, " (port %d)\n", ntohs(varp_port));
- IOStream_print(io, " (encapsulation %s)\n",
- (etherip_in_udp ? "etherip_in_udp" : "etherip"));
- IOStream_print(io, " (entry_ttl %lu)\n", varp_table->entry_ttl);
- IOStream_print(io, ")\n");
- VarpTable_print(varp_table, io);
-}
-
-#ifdef __KERNEL__
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-
-static inline int addr_route(u32 daddr, struct rtable **prt){
- int err = 0;
- struct flowi fl = {
- .nl_u = {
- .ip4_u = {
- .daddr = daddr,
- }
- }
- };
-
- err = ip_route_output_key(prt, &fl);
- return err;
-}
-
-#else
-
-static inline int addr_route(u32 daddr, struct rtable **prt){
- int err = 0;
- struct rt_key key = { .dst = daddr };
- err = ip_route_output_key(prt, &key);
- return err;
-}
-
-#endif // LINUX_VERSION_CODE
-
-#ifndef LL_RESERVED_SPACE
-#define HH_DATA_MOD 16
-#define LL_RESERVED_SPACE(dev) \
- ((dev->hard_header_len & ~(HH_DATA_MOD - 1)) + HH_DATA_MOD)
-
-#endif // LL_RESERVED_SPACE
-
-#else // __KERNEL__
-
-#define ip_eth_mc_map(daddr, dmac) do{ }while(0)
-
-#endif // __KERNEL__
-
-/** Send a varp protocol message.
- *
- * @param opcode varp opcode (host order)
- * @param dev device (may be null)
- * @param skb skb being replied to (may be null)
- * @param vnet vnet id (in network order)
- * @param vmac vmac (in network order)
- * @return 0 on success, error code otherwise
- */
-int varp_send(u16 opcode, struct net_device *dev, struct sk_buff *skbin,
- VnetId *vnet, Vmac *vmac){
- int err = 0;
- int link_n = 0;
- int ip_n = sizeof(struct iphdr);
- int udp_n = sizeof(struct udphdr);
- int varp_n = sizeof(VarpHdr);
- struct sk_buff *skbout = NULL;
- VarpHdr *varph = NULL;
- u8 smacbuf[6] = {}, dmacbuf[6] = {};
- u8 *smac = smacbuf, *dmac = dmacbuf;
- u32 saddr = 0, daddr = 0;
- u16 sport = 0, dport = 0;
-#if defined(DEBUG)
- char vnetbuf[VNET_ID_BUF];
-#endif
-
- dprintf("> opcode=%d vnet= %s vmac=" MACFMT "\n",
- opcode, VnetId_ntoa(vnet, vnetbuf), MAC6TUPLE(vmac->mac));
-
- dport = varp_port;
- if(skbin){
- daddr = skbin->nh.iph->saddr;
- dmac = eth_hdr(skbin)->h_source;
- sport = skbin->h.uh->dest;
- } else {
- if(MULTICAST(varp_mcast_addr)){
- daddr = varp_mcast_addr;
- ip_eth_mc_map(daddr, dmac);
- } else {
- daddr = INADDR_BROADCAST;
- }
- sport = varp_port;
- }
-
-#ifdef __KERNEL__
- {
- struct in_device *in_dev = NULL;
- if(!dev){
- struct rtable *rt = NULL;
- err = addr_route(daddr, &rt);
- if(err) goto exit;
- dev = rt->u.dst.dev;
- }
-
- in_dev = in_dev_get(dev);
- if(!in_dev){
- err = -ENODEV;
- goto exit;
- }
- link_n = LL_RESERVED_SPACE(dev);
- saddr = in_dev->ifa_list->ifa_address;
- smac = dev->dev_addr;
- if(daddr == INADDR_BROADCAST){
- daddr = in_dev->ifa_list->ifa_broadcast;
- dmac = dev->broadcast;
- }
- in_dev_put(in_dev);
- }
-#else
- {
- extern uint32_t vnetd_addr(void);
- saddr = vnetd_addr();
- }
-#endif // __KERNEL__
-
- dprintf("> dev=%s\n", (dev ? dev->name : "<none>"));
- dprintf("> smac=" MACFMT " dmac=" MACFMT "\n", MAC6TUPLE(smac), MAC6TUPLE(dmac));
- dprintf("> saddr=" IPFMT " daddr=" IPFMT "\n", NIPQUAD(saddr), NIPQUAD(daddr));
- dprintf("> sport=%u dport=%u\n", ntohs(sport), ntohs(dport));
-
- skbout = alloc_skb(link_n + ip_n + udp_n + varp_n, GFP_ATOMIC);
- if (!skbout){
- err = -ENOMEM;
- goto exit;
- }
- skbout->dev = dev;
- skb_reserve(skbout, link_n);
- skbout->protocol = htons(ETH_P_IP);
-
-#ifdef __KERNEL__
- // Device header. Pushes device header on front of skb.
- if (dev->hard_header){
- err = dev->hard_header(skbout, dev, ETH_P_IP, dmac, smac, skbout->len);
- if(err < 0) goto exit;
- skbout->mac.raw = skbout->data;
- }
-#else
- smac = smac; // Defeat unused variable warning.
-#endif // __KERNEL__
-
- // IP header.
- skbout->nh.raw = skb_put(skbout, ip_n);
- skbout->nh.iph->version = 4;
- skbout->nh.iph->ihl = ip_n / 4;
- skbout->nh.iph->tos = 0;
- skbout->nh.iph->tot_len = htons(ip_n + udp_n + varp_n);
- skbout->nh.iph->id = 0;
- skbout->nh.iph->frag_off = 0;
- skbout->nh.iph->ttl = 64;
- skbout->nh.iph->protocol = IPPROTO_UDP;
- skbout->nh.iph->saddr = saddr;
- skbout->nh.iph->daddr = daddr;
- skbout->nh.iph->check = 0;
-
- // UDP header.
- skbout->h.raw = skb_put(skbout, udp_n);
- skbout->h.uh->source = sport;
- skbout->h.uh->dest = dport;
- skbout->h.uh->len = htons(udp_n + varp_n);
- skbout->h.uh->check = 0;
-
- // Varp header.
- varph = (void*)skb_put(skbout, varp_n);
- *varph = (VarpHdr){};
- varph->hdr.id = htons(VARP_ID);
- varph->hdr.opcode = htons(opcode);
- varph->vnet = *vnet;
- varph->vmac = *vmac;
- varph->addr.family = AF_INET;
- varph->addr.u.ip4.s_addr = saddr;
-
- err = skb_xmit(skbout);
-
- exit:
- if(err && skbout) kfree_skb(skbout);
- dprintf("< err=%d\n", err);
- return err;
-}
-
-
-/** Send a varp request for the vnet and destination mac of a packet.
- * Assumes the ventry is locked.
- *
- * @param skb packet
- * @param vnet vnet (in network order)
- * @return 0 on success, error code otherwise
- */
-int varp_solicit(VnetId *vnet, Vmac *vmac){
- return varp_send(VARP_OP_REQUEST, NULL, NULL, vnet, vmac);
-}
-
-/* Test some flags.
- *
- * @param ventry varp entry
- * @param flags to test
- * @return nonzero if flags set
- */
-int VarpEntry_get_flags(VarpEntry *ventry, int flags){
- return ventry->flags & flags;
-}
-
-/** Set some flags.
- *
- * @param ventry varp entry
- * @param flags to set
- * @param set set flags on if nonzero, off if zero
- * @return new flags value
- */
-int VarpEntry_set_flags(VarpEntry *ventry, int flags, int set){
- if(set){
- ventry->flags |= flags;
- } else {
- ventry->flags &= ~flags;
- }
- return ventry->flags;
-}
-
-/** Print a varp entry.
- *
- * @param ventry varp entry
- */
-void VarpEntry_print(VarpEntry *ventry, IOStream *io){
- IOStream_print(io, "(ventry \n");
- if(ventry){
- unsigned long now = jiffies;
- char *state, *flags;
- char vnetbuf[VNET_ID_BUF];
- char addrbuf[VARP_ADDR_BUF];
-
- switch(ventry->state){
- case VARP_STATE_INCOMPLETE: state = "incomplete"; break;
- case VARP_STATE_REACHABLE: state = "reachable"; break;
- case VARP_STATE_FAILED: state = "failed"; break;
- default: state = "unknown"; break;
- }
- flags = (VarpEntry_get_flags(ventry, VARP_FLAG_PROBING) ? "P" : "-");
-
- IOStream_print(io, " (ref %d)\n", atomic_read(&ventry->refcount));
- IOStream_print(io, " (state %s)\n", state);
- IOStream_print(io, " (flags %s)\n", flags);
- IOStream_print(io, " (addr %s)\n", VarpAddr_ntoa(&ventry->addr, addrbuf));
- IOStream_print(io, " (queue %d)\n", skb_queue_len(&ventry->queue));
- IOStream_print(io, " (age %lu)\n", now - ventry->timestamp);
- IOStream_print(io, " (vmac " MACFMT ")\n", MAC6TUPLE(ventry->key.vmac.mac));
- IOStream_print(io, " (vnet %s)\n", VnetId_ntoa(&ventry->key.vnet, vnetbuf));
- }
- IOStream_print(io, ")\n");
-}
-
-/** Free a varp entry.
- *
- * @param ventry varp entry
- */
-static void VarpEntry_free(VarpEntry *ventry){
- if(!ventry) return;
- deallocate(ventry);
-}
-
-/** Increment reference count.
- *
- * @param ventry varp entry (may be null)
- */
-void VarpEntry_incref(VarpEntry *ventry){
- if(!ventry) return;
- atomic_inc(&ventry->refcount);
-}
-
-/** Decrement reference count, freeing if zero.
- *
- * @param ventry varp entry (may be null)
- */
-void VarpEntry_decref(VarpEntry *ventry){
- if(!ventry) return;
- if(atomic_dec_and_test(&ventry->refcount)){
- VarpEntry_free(ventry);
- }
-}
-
-/** Call the error handler.
- *
- * @param ventry varp entry
- */
-void VarpEntry_error(VarpEntry *ventry){
- struct sk_buff *skb;
- skb = skb_peek(&ventry->queue);
- if(!skb) return;
- if(ventry->error) ventry->error(ventry, skb);
- skb_queue_purge(&ventry->queue);
-}
-
-/** Schedule the varp entry timer.
- * Must increment the reference count before doing
- * this the first time, so the ventry won't be freed
- * before the timer goes off.
- *
- * @param ventry varp entry
- */
-void VarpEntry_schedule(VarpEntry *ventry){
- timer_set(&ventry->timer, VARP_PROBE_INTERVAL);
-}
-
-/** Function called when a varp entry timer goes off.
- * If the entry is still incomplete, carries on probing.
- * Otherwise stops probing.
- *
- * @param arg ventry
- */
-static void varp_timer_fn(unsigned long arg){
- unsigned long flags;
- VarpEntry *ventry = (VarpEntry *)arg;
- struct sk_buff *skb = NULL;
- int probing = 0;
-
- dprintf(">\n");
- VarpEntry_lock(ventry, flags);
- if(!atomic_read(&ventry->deleted)){
- switch(ventry->state){
- case VARP_STATE_REACHABLE:
- case VARP_STATE_FAILED:
- break;
- case VARP_STATE_INCOMPLETE:
- // Probe if haven't run out of tries, otherwise fail.
- if(atomic_read(&ventry->probes) < VARP_PROBE_MAX){
- unsigned long qflags;
- VnetId vnet;
- Vmac vmac;
-
- probing = 1;
- spin_lock_irqsave(&ventry->queue.lock, qflags);
- skb = skb_peek(&ventry->queue);
- if(skb){
- vmac = *(Vmac*)eth_hdr(skb)->h_dest;
- }
- spin_unlock_irqrestore(&ventry->queue.lock, qflags);
- if(skb){
- dprintf("> skbs in queue - solicit\n");
- vnet = ventry->key.vnet;
- atomic_inc(&ventry->probes);
- VarpEntry_unlock(ventry, flags);
- varp_solicit(&vnet, &vmac);
- VarpEntry_lock(ventry, flags);
- } else {
- dprintf("> empty queue.\n");
- }
- VarpEntry_schedule(ventry);
- } else {
- VarpEntry_error(ventry);
- ventry->state = VARP_STATE_FAILED;
- }
- break;
- }
- }
- VarpEntry_set_flags(ventry, VARP_FLAG_PROBING, probing);
- VarpEntry_unlock(ventry, flags);
- if(!probing) VarpEntry_decref(ventry);
- dprintf("<\n");
-}
-
-/** Default error function for varp entries.
- *
- * @param ventry varp entry
- * @param skb packet dropped because of error
- */
-static void varp_error_fn(VarpEntry *ventry, struct sk_buff *skb){
-}
-
-/** Create a varp entry. Initializes the internal state.
- *
- * @param vnet vnet id
- * @param vmac virtual MAC address (copied)
- * @return ventry or null
- */
-VarpEntry * VarpEntry_new(VnetId *vnet, Vmac *vmac){
- VarpEntry *ventry = ALLOCATE(VarpEntry);
- if(ventry){
- unsigned long now = jiffies;
-
- atomic_set(&ventry->refcount, 1);
- atomic_set(&ventry->probes, 0);
- atomic_set(&ventry->deleted, 0);
- ventry->lock = RW_LOCK_UNLOCKED;
- ventry->state = VARP_STATE_INCOMPLETE;
- ventry->queue_max = VARP_QUEUE_MAX;
- skb_queue_head_init(&ventry->queue);
- timer_init(&ventry->timer, varp_timer_fn, ventry);
- ventry->timestamp = now;
- ventry->error = varp_error_fn;
-
- ventry->key.vnet = *vnet;
- ventry->key.vmac = *vmac;
- }
- return ventry;
-}
-
-/** Hash function for keys in the varp cache.
- * Hashes the vnet id and mac.
- *
- * @param k key (VarpKey)
- * @return hashcode
- */
-static Hashcode varp_key_hash_fn(void *k){
- return hash_hvoid(0, k, sizeof(VarpKey));
-}
-
-/** Test equality for keys in the varp cache.
- * Compares vnet and mac.
- *
- * @param k1 key to compare (VarpKey)
- * @param k2 key to compare (VarpKey)
- * @return 1 if equal, 0 otherwise
- */
-static int varp_key_equal_fn(void *k1, void *k2){
- return memcmp(k1, k2, sizeof(VarpKey)) == 0;
-}
-
-/** Free an entry in the varp cache.
- *
- * @param table containing table
- * @param entry entry to free
- */
-static void varp_entry_free_fn(HashTable *table, HTEntry *entry){
- VarpEntry *ventry;
- if(!entry) return;
- ventry = entry->value;
- if(ventry) VarpEntry_decref(ventry);
- HTEntry_free(entry);
-}
-
-/** Free the whole varp cache.
- * Dangerous.
- *
- * @param vtable varp cache
- */
-void VarpTable_free(VarpTable *vtable){
- unsigned long vtflags;
- if(!vtable) return;
- VarpTable_write_lock(vtable, vtflags);
- timer_cancel(&vtable->timer);
- vtable->timer.data = 0;
- if(vtable->table){
- HashTable *table = vtable->table;
- HashTable_for_decl(entry);
-
- vtable->table = NULL;
- HashTable_for_each(entry, table){
- VarpEntry *ventry = entry->value;
- unsigned long flags;
- VarpEntry_lock(ventry, flags);
- atomic_set(&ventry->deleted, 1);
- if(VarpEntry_get_flags(ventry, VARP_FLAG_PROBING)){
- timer_cancel(&ventry->timer);
- ventry->timer.data = 0;
- VarpEntry_decref(ventry);
- }
- VarpEntry_unlock(ventry, flags);
- }
- HashTable_free(table);
- }
- VarpTable_write_unlock(vtable, vtflags);
- deallocate(vtable);
-}
-
-/** Schedule the varp table timer.
- *
- * @param vtable varp table
- */
-void VarpTable_schedule(VarpTable *vtable){
- timer_set(&vtable->timer, vtable->entry_ttl);
-}
-
-/** Function called when the varp table timer goes off.
- * Sweeps old varp cache entries and reschedules itself.
- *
- * @param arg varp table
- */
-static void varp_table_timer_fn(unsigned long arg){
- VarpTable *vtable = (VarpTable *)arg;
- if(vtable){
- VarpTable_sweep(vtable);
- VarpTable_schedule(vtable);
- }
-}
-
-/** Print a varp table.
- *
- * @param vtable table
- */
-void VarpTable_print(VarpTable *vtable, IOStream *io){
- HashTable_for_decl(entry);
- VarpEntry *ventry;
- unsigned long vtflags, flags;
-
- VarpTable_read_lock(vtable, vtflags);
- HashTable_for_each(entry, vtable->table){
- ventry = entry->value;
- VarpEntry_lock(ventry, flags);
- VarpEntry_print(ventry, io);
- VarpEntry_unlock(ventry, flags);
- }
- VarpTable_read_unlock(vtable, vtflags);
-}
-
-/** Create a varp table.
- *
- * @return new table or null
- */
-VarpTable * VarpTable_new(void){
- int err = -ENOMEM;
- VarpTable *vtable = NULL;
-
- vtable = ALLOCATE(VarpTable);
- if(!vtable) goto exit;
- vtable->table = HashTable_new(VARP_TABLE_BUCKETS);
- if(!vtable->table) goto exit;
- vtable->table->key_size = sizeof(VarpKey);
- vtable->table->key_equal_fn = varp_key_equal_fn;
- vtable->table->key_hash_fn = varp_key_hash_fn;
- vtable->table->entry_free_fn = varp_entry_free_fn;
-
- vtable->entry_ttl = VARP_ENTRY_TTL;
- vtable->probe_max = VARP_PROBE_MAX;
- vtable->probe_interval = VARP_PROBE_INTERVAL;
- vtable->queue_max = VARP_QUEUE_MAX;
-
- init_MUTEX(&vtable->mutex);
- vtable->lock = RW_LOCK_UNLOCKED;
- timer_init(&vtable->timer, varp_table_timer_fn, vtable);
- err = 0;
- exit:
- if(err){
- VarpTable_free(vtable);
- vtable = NULL;
- }
- return vtable;
-}
-
-/** Add a new entry to the varp table.
- *
- * @param vtable table
- * @param vnet vnet id
- * @param vmac virtual MAC address (copied)
- * @return new entry or null
- */
-VarpEntry * VarpTable_add(VarpTable *vtable, VnetId *vnet, Vmac *vmac){
- int err = 0;
- VarpKey key = { .vnet = *vnet, .vmac = *vmac};
- VarpEntry *ventry = NULL;
- HTEntry *entry = NULL;
- unsigned long vtflags;
-
- VarpTable_write_lock(vtable, vtflags);
- ventry = HashTable_get(vtable->table, &key);
- if(ventry){
- VarpEntry_incref(ventry);
- goto exit;
- }
- err = -ENOMEM;
- ventry = VarpEntry_new(vnet, vmac);
- if(!ventry) goto exit;
- entry = HashTable_add(vtable->table, ventry, ventry);
- if(!entry){
- VarpEntry_decref(ventry);
- ventry = NULL;
- goto exit;
- }
- err = 0;
- VarpEntry_incref(ventry);
- exit:
- VarpTable_write_unlock(vtable, vtflags);
- return ventry;
-}
-
-/** Remove an entry from the varp table.
- *
- * @param vtable table
- * @param ventry entry to remove
- * @return removed count
- */
-int VarpTable_remove(VarpTable *vtable, VarpEntry *ventry){
- //TODO: Could send a varp announce with null addr for the entry
- // vnet and vmac to notify others, so they will resolve the addr
- // instead of sending traffic to us.
- atomic_set(&ventry->deleted, 1);
- skb_queue_purge(&ventry->queue);
- return HashTable_remove(vtable->table, ventry);
-}
-
-/** Remove all entries using a vnet.
- * Caller must hold the table lock.
- *
- * @param vtable table
- * @param vnet vnet
- * @return removed count
- */
-int VarpTable_remove_vnet(VarpTable *vtable, VnetId *vnet){
- int count = 0;
- HashTable_for_decl(entry);
-
- HashTable_for_each(entry, vtable->table){
- VarpEntry *ventry = entry->value;
- if(VnetId_eq(&ventry->key.vnet, vnet)){
- count += VarpTable_remove(vtable, ventry);
- }
- }
- return count;
-}
-
-/** Remove all entries using a vnet from the varp table.
- *
- * @param vnet vnet
- * @return removed count
- */
-int varp_remove_vnet(VnetId *vnet){
- int count = 0;
- unsigned long vtflags;
-
- VarpTable_write_lock(varp_table, vtflags);
- count = VarpTable_remove_vnet(varp_table, vnet);
- VarpTable_write_unlock(varp_table, vtflags);
- return count;
-}
-
-/** Lookup an entry in the varp table.
- *
- * @param vtable table
- * @param vnet vnet id
- * @param vmac virtual MAC address
- * @param create create a new entry if needed if true
- * @return entry found or null
- */
-VarpEntry * VarpTable_lookup(VarpTable *vtable, VnetId *vnet, Vmac *vmac, int create){
- VarpKey key = { .vnet = *vnet, .vmac = *vmac };
- VarpEntry *ventry = NULL;
- unsigned long vtflags;
-
- VarpTable_read_lock(vtable, vtflags);
- ventry = HashTable_get(vtable->table, &key);
- if(ventry) VarpEntry_incref(ventry);
- VarpTable_read_unlock(vtable, vtflags);
-
- if(!ventry && create){
- ventry = VarpTable_add(vtable, vnet, vmac);
- }
- return ventry;
-}
-
-/** Handle output for a reachable ventry.
- * Send the skb using the tunnel to the care-of address.
- * Assumes the ventry lock is held.
- *
- * @param ventry varp entry
- * @param skb skb to send
- * @return 0 on success, error code otherwise
- */
-int VarpEntry_send(VarpEntry *ventry, struct sk_buff *skb){
- int err = 0;
- unsigned long flags = 0;
- VarpAddr addr;
- VnetId vnet;
-
- dprintf("> skb=%p\n", skb);
- vnet = ventry->key.vnet;
- addr = ventry->addr;
- VarpEntry_unlock(ventry, flags);
- err = vnet_tunnel_send(&vnet, &addr, skb);
- VarpEntry_lock(ventry, flags);
- dprintf("< err=%d\n", err);
- return err;
-}
-
-/** Handle output for a non-reachable ventry. Send messages to complete it.
- * If the entry is still incomplete, queue the skb, otherwise
- * send it. If the queue is full, dequeue and free an old skb to
- * make room for the new one.
- * Assumes the ventry lock is held.
- *
- * @param ventry varp entry
- * @param skb skb to send
- * @return 0 on success, error code otherwise
- */
-int VarpEntry_resolve(VarpEntry *ventry, struct sk_buff *skb){
- int err = 0;
- unsigned long flags = 0;
- VnetId vnet;
- Vmac vmac;
-
- dprintf("> skb=%p\n", skb);
- ventry->state = VARP_STATE_INCOMPLETE;
- atomic_set(&ventry->probes, 1);
- if(!VarpEntry_get_flags(ventry, VARP_FLAG_PROBING)){
- VarpEntry_set_flags(ventry, VARP_FLAG_PROBING, 1);
- VarpEntry_incref(ventry);
- VarpEntry_schedule(ventry);
- }
- vnet = ventry->key.vnet;
- vmac = *(Vmac*)eth_hdr(skb)->h_dest;
- VarpEntry_unlock(ventry, flags);
- varp_solicit(&vnet, &vmac);
- VarpEntry_lock(ventry, flags);
-
- if(ventry->state == VARP_STATE_INCOMPLETE){
- while(skb_queue_len(&ventry->queue) >= ventry->queue_max){
- struct sk_buff *oldskb;
- oldskb = skb_dequeue(&ventry->queue);
- //oldskb = ventry->queue.next;
- //__skb_unlink(oldskb, &ventry->queue);
- if(!oldskb) break;
- dprintf("> dropping skb=%p\n", oldskb);
- kfree_skb(oldskb);
- }
- skb_queue_tail(&ventry->queue, skb);
- } else {
- err = VarpEntry_send(ventry, skb);
- }
- dprintf("< err=%d\n", err);
- return err;
-}
-
-/** Process the output queue for a ventry. Sends the queued skbs if
- * the ventry is reachable, otherwise drops them.
- *
- * @param ventry varp entry
- */
-void VarpEntry_process_queue(VarpEntry *ventry){
- struct sk_buff *skb;
- for( ; ; ){
- if(ventry->state != VARP_STATE_REACHABLE) break;
- skb = skb_dequeue(&ventry->queue);
- if(!skb) break;
- VarpEntry_send(ventry, skb);
- }
- skb_queue_purge(&ventry->queue);
-}
-
-/** Multicast an skb on a vnet.
- *
- * @param vnet vnet id
- * @param skb skb to send
- * @return 0 on success, error code otherwise
- */
-static int varp_multicast(VnetId *vnet, struct sk_buff *skb){
- VarpAddr addr = { .family = AF_INET };
- addr.u.ip4.s_addr = varp_mcast_addr;
- return vnet_tunnel_send(vnet, &addr, skb);
-}
-
-/** Handle output for a ventry. Resolves the ventry
- * if necessary.
- *
- * @param ventry varp entry
- * @param skb skb to send
- * @return 0 on success, error code otherwise
- */
-int VarpEntry_output(VarpEntry *ventry, struct sk_buff *skb){
- int err = 0;
- unsigned long flags;
-
- VarpEntry_lock(ventry, flags);
- switch(ventry->state){
- case VARP_STATE_REACHABLE:
- if(skb_queue_len(&ventry->queue) > 0){
- VarpEntry_process_queue(ventry);
- }
- err = VarpEntry_send(ventry, skb);
- break;
- default:
- if(0){
- err = VarpEntry_resolve(ventry, skb);
- } else {
- // Multicast the skb if the entry is not reachable.
- VnetId vnet = ventry->key.vnet;
- VarpEntry_unlock(ventry, flags);
- err = varp_multicast(&vnet, skb);
- VarpEntry_lock(ventry, flags);
- }
- break;
- }
- VarpEntry_unlock(ventry, flags);
- return err;
-}
-
-/** Update a ventry. Sets the address and state to those given
- * and sets the timestamp to 'now'.
- *
- * @param ventry varp entry
- * @param addr care-of address
- * @param state state
- * @return 0 on success, error code otherwise
- */
-int VarpEntry_update(VarpEntry *ventry, VarpAddr *addr, int state, int vflags){
- int err = 0;
- unsigned long now = jiffies;
- unsigned long flags;
-
- VarpEntry_lock(ventry, flags);
- //if(atomic_read(&ventry->deleted)) goto exit;
- if(VarpEntry_get_flags(ventry, VARP_FLAG_PERMANENT)) goto exit;
- ventry->addr = *addr;
- ventry->timestamp = now;
- ventry->state = state;
- // Can't process the queue while atomic as it calls schedule(),
- // and that's bad.
- //if(0 && (vflags & VARP_UPDATE_QUEUE) && !in_atomic()){
- // VarpEntry_process_queue(ventry);
- //}
- exit:
- VarpEntry_unlock(ventry, flags);
- dprintf("< err=%d\n", err);
- return err;
-}
-
-/** Update the entry for a vnet.
- *
- * @param vtable varp table
- * @param vnet vnet id
- * @param vmac mac address
- * @param addr care-of-address
- * @param state state
- * @param flags update flags
- * @return 0 on success, error code otherwise
- */
-int VarpTable_update(VarpTable *vtable, VnetId *vnet, Vmac *vmac, VarpAddr *addr,
- int state, int flags){
- int err = 0;
- VarpEntry *ventry;
-#ifdef DEBUG
- char vnetbuf[VNET_ID_BUF];
- char addrbuf[VARP_ADDR_BUF];
-
- dprintf("> vnet=%s mac=" MACFMT " addr=%s state=%d flags=%x\n",
- VnetId_ntoa(vnet, vnetbuf),
- MAC6TUPLE(vmac->mac),
- VarpAddr_ntoa(addr, addrbuf),
- state,
- flags);
-#endif
- ventry = VarpTable_lookup(vtable, vnet, vmac, (flags & VARP_UPDATE_CREATE));
- if(!ventry){
- err = -ENOENT;
- goto exit;
- }
- err = VarpEntry_update(ventry, addr, state, flags);
- VarpEntry_decref(ventry);
- exit:
- dprintf("< err=%d\n", err);
- return err;
-}
-
-/** Update the entry for a vnet: make it reachable and create an entry
- * if needed.
- *
- * @param vnet vnet id
- * @param vmac mac address
- * @param addr care-of-address
- * @return 0 on success, error code otherwise
- */
-int varp_update(VnetId *vnet, unsigned char *vmac, VarpAddr *addr){
- int err = 0;
- if(!varp_table){
- err = -ENOSYS;
- } else {
- err = VarpTable_update(varp_table, vnet, (Vmac*)vmac, addr,
- VARP_STATE_REACHABLE, VARP_UPDATE_CREATE);
- }
- return err;
-}
-
-static inline int VarpEntry_sweepable(VarpEntry *ventry){
- return !VarpEntry_get_flags(ventry, (VARP_FLAG_PERMANENT | VARP_FLAG_PROBING));
-}
-
-static inline int VarpTable_old(VarpTable *vtable, VarpEntry *ventry, unsigned long now){
- return now - ventry->timestamp > vtable->entry_ttl;
-}
-
-/** Sweep old varp entries.
- * Doesn't affect entries that are probing or permanent.
- *
- * @param vtable table
- */
-void VarpTable_sweep(VarpTable *vtable){
- HashTable_for_decl(entry);
- VarpEntry *ventry;
- unsigned long now = jiffies;
- unsigned long vtflags, flags;
- int sweep, swept = 0;
-
- if(!vtable) return;
- VarpTable_write_lock(vtable, vtflags);
- HashTable_for_each(entry, vtable->table){
- ventry = entry->value;
- VarpEntry_lock(ventry, flags);
- sweep = VarpEntry_sweepable(ventry) && VarpTable_old(vtable, ventry, now);
- if(sweep){
- swept++;
- iprintf("> Sweeping:\n");
- VarpEntry_print(ventry, iostdout);
- //VarpEntry_process_queue(ventry);
- ventry->state = VARP_STATE_INCOMPLETE;
- }
- VarpEntry_unlock(ventry, flags);
- if(sweep){
- VarpTable_remove(vtable, ventry);
- }
- }
- VarpTable_write_unlock(vtable, vtflags);
- if(swept){
- iprintf(">\n");
- varp_print(iostdout);
- }
-}
-
-/** Flush the varp table.
- *
- * @param vtable table
- */
-void VarpTable_flush(VarpTable *vtable){
- HashTable_for_decl(entry);
- VarpEntry *ventry;
- unsigned long vtflags, flags;
- int flush;
-
- VarpTable_write_lock(vtable, vtflags);
- HashTable_for_each(entry, vtable->table){
- ventry = entry->value;
- VarpEntry_lock(ventry, flags);
- flush = (!VarpEntry_get_flags(ventry, VARP_FLAG_PERMANENT) &&
- !VarpEntry_get_flags(ventry, VARP_FLAG_PROBING));
- if(flush){
- iprintf("> Flushing:\n");
- VarpEntry_print(ventry, iostdout);
- }
- VarpEntry_unlock(ventry, flags);
- if(flush){
- VarpTable_remove(vtable, ventry);
- }
- }
- VarpTable_write_unlock(vtable, vtflags);
-}
-
-/** Handle a varp request. Look for a vif with the requested
- * vnet and vmac. If find one, reply with the vnet, vmac and our
- * address. Otherwise do nothing.
- *
- * @param skb incoming message
- * @param varph varp message
- * @return 0 if ok, -ENOENT if no matching vif, or error code
- */
-int varp_handle_request(struct sk_buff *skb, VarpHdr *varph){
- int err = -ENOENT;
- VnetId *vnet;
- Vmac *vmac;
- Vif *vif = NULL;
-
- dprintf(">\n");
- vnet = &varph->vnet;
- vmac = &varph->vmac;
- if(vif_lookup(vnet, vmac, &vif)) goto exit;
- varp_send(VARP_OP_ANNOUNCE, skb->dev, skb, vnet, vmac);
- vif_decref(vif);
- exit:
- dprintf("< err=%d\n", err);
- return err;
-}
-
-/** Announce the vnet and vmac of a vif (gratuitous varp).
- *
- * @param dev device to send on (may be null)
- * @param vif vif
- * @return 0 on success, error code otherwise
- */
-int varp_announce_vif(struct net_device *dev, Vif *vif){
- int err = 0;
- dprintf(">\n");
- if(!varp_table){
- err = -ENOSYS;
- goto exit;
- }
- err = varp_send(VARP_OP_ANNOUNCE, dev, NULL, &vif->vnet, &vif->vmac);
- exit:
- dprintf("< err=%d\n", err);
- return err;
-}
-
-/** Handle a varp announce message.
- * Update the matching ventry if we have one.
- *
- * @param skb incoming message
- * @param varp message
- * @return 0 if OK, -ENOENT if no matching entry
- */
-int varp_handle_announce(struct sk_buff *skb, VarpHdr *varph){
- int err = 0;
-
- dprintf(">\n");
- err = VarpTable_update(varp_table,
- &varph->vnet, &varph->vmac, &varph->addr,
- VARP_STATE_REACHABLE,
- (VARP_UPDATE_CREATE | VARP_UPDATE_QUEUE));
- dprintf("< err=%d\n", err);
- return err;
-}
-
-/** Handle an incoming varp message.
- *
- * @param skb incoming message
- * @return 0 if OK, error code otherwise
- */
-int varp_handle_message(struct sk_buff *skb){
- // Assume nh, h set, skb->data points at udp hdr (h).
- int err = -EINVAL;
- VarpHdr *varph; // = (void*)(skb->h.uh + 1);
-
- dprintf("> skb=%p saddr=" IPFMT " daddr=" IPFMT "\n",
- skb,
- NIPQUAD(skb->nh.iph->saddr),
- NIPQUAD(skb->nh.iph->daddr));
- if(!varp_table){
- err = -ENOSYS;
- return err;
- }
- if(MULTICAST(skb->nh.iph->daddr)){
- if(skb->nh.iph->daddr != varp_mcast_addr){
- // Ignore multicast packets not addressed to us.
- err = 0;
- dprintf("> Ignoring daddr=" IPFMT " mcaddr=" IPFMT "\n",
- NIPQUAD(skb->nh.iph->daddr), NIPQUAD(varp_mcast_addr));
- goto exit;
- }
- }
- varph = (void*)skb_pull_vn(skb, sizeof(struct udphdr));
- if(skb->len < sizeof(struct VnetMsgHdr)){
- wprintf("> Varp msg too short: %d < %d\n", skb->len, sizeof(struct VnetMsgHdr));
- goto exit;
- }
- switch(ntohs(varph->hdr.id)){
- case VARP_ID: // Varp message. Handled below.
- if(skb->len < sizeof(*varph)){
- wprintf("> Varp msg too short: %d < %d\n", skb->len, sizeof(*varph));
- goto exit;
- }
- break;
- case VUDP_ID: // Etherip-in-udp packet.
- skb_pull_vn(skb, sizeof(struct VnetMsgHdr));
- err = etherip_protocol_recv(skb);
- goto exit;
- case VFWD_ID: // Forwarded.
- skb_pull_vn(skb, sizeof(struct VnetMsgHdr));
- err = vnet_forward_recv(skb);
- goto exit;
- default:
- // It's not varp at all - ignore it.
- wprintf("> Invalid varp id: %d\n", ntohs(varph->hdr.id));
- print_skb("INVALID", 0, skb);
- goto exit;
- }
-#ifdef DEBUG
- {
- char vnetbuf[VNET_ID_BUF];
- char addrbuf[VARP_ADDR_BUF];
- dprintf("> saddr=" IPFMT " daddr=" IPFMT "\n",
- NIPQUAD(skb->nh.iph->saddr), NIPQUAD(skb->nh.iph->daddr));
- dprintf("> sport=%u dport=%u\n", ntohs(skb->h.uh->source), ntohs(skb->h.uh->dest));
- dprintf("> opcode=%d vnet=%s vmac=" MACFMT " addr=%s\n",
- ntohs(varph->hdr.opcode),
- VnetId_ntoa(&varph->vnet, vnetbuf),
- MAC6TUPLE(varph->vmac.mac),
- VarpAddr_ntoa(&varph->addr, addrbuf));
- varp_dprint();
- }
-#endif
- switch(ntohs(varph->hdr.opcode)){
- case VARP_OP_REQUEST:
- err = varp_handle_request(skb, varph);
- break;
- case VARP_OP_ANNOUNCE:
- err = varp_handle_announce(skb, varph);
- break;
- default:
- wprintf("> Unknown opcode: %d \n", ntohs(varph->hdr.opcode));
- break;
- }
- exit:
- dprintf("< err=%d\n", err);
- return err;
-}
-
-/** Send an outgoing packet on the appropriate vnet tunnel.
- *
- * @param skb outgoing message
- * @param vnet vnet (network order)
- * @return 0 on success, error code otherwise
- */
-int varp_output(struct sk_buff *skb, VnetId *vnet){
- int err = 0;
- unsigned char *mac = NULL;
- Vmac *vmac = NULL;
- VarpEntry *ventry = NULL;
-#if defined(DEBUG)
- char vnetbuf[VNET_ID_BUF];
-#endif
-
- dprintf("> vnet=%s\n", VnetId_ntoa(vnet, vnetbuf));
- if(!varp_table){
- err = -ENOSYS;
- goto exit;
- }
- if(!skb->mac.raw){
- wprintf("> No ethhdr in skb!\n");
- err = -EINVAL;
- goto exit;
- }
- mac = eth_hdr(skb)->h_dest;
- vmac = (Vmac*)mac;
- if(mac_is_multicast(mac)){
- err = varp_multicast(vnet, skb);
- } else {
- ventry = VarpTable_lookup(varp_table, vnet, vmac, 1);
- if(ventry){
- err = VarpEntry_output(ventry, skb);
- VarpEntry_decref(ventry);
- } else {
- err = -ENOMEM;
- }
- }
- exit:
- dprintf("< err=%d\n", err);
- return err;
-}
-
-/** Set the varp multicast address (after initialization).
- *
- * @param addr address (network order)
- * @return 0 on success, error code otherwise
- */
-int varp_set_mcast_addr(uint32_t addr){
- int err = 0;
- varp_close();
- varp_mcast_addr = addr;
- err = varp_open(varp_mcast_addr, varp_port);
- return err;
-}
-
-/** Initialize the varp multicast address from a module parameter.
- *
- * @param s address in IPv4 notation
- * @return 0 on success, error code otherwise
- */
-static void varp_init_mcast_addr(char *s){
- unsigned long v = 0;
-
- dprintf("> %s\n", s);
- if(s && (get_inet_addr(s, &v) >= 0)){
- varp_mcast_addr = (u32)v;
- } else {
- varp_mcast_addr = htonl(VARP_MCAST_ADDR);
- }
-}
-
-/** Initialize the varp cache.
- *
- * @return 0 on success, error code otherwise
- */
-int varp_init(void){
- int err = 0;
-
- dprintf(">\n");
- varp_table = VarpTable_new();
- if(!varp_table){
- err = -ENOMEM;
- goto exit;
- }
- VarpTable_schedule(varp_table);
- varp_init_mcast_addr(varp_mcaddr);
- varp_port = htons(VARP_PORT);
-
- err = varp_open(varp_mcast_addr, varp_port);
- exit:
- dprintf("< err=%d\n", err);
- return err;
-}
-
-/** Close the varp cache.
- */
-void varp_exit(void){
- dprintf(">\n");
- varp_close();
- if(varp_table){
- VarpTable *vtable = varp_table;
- varp_table = NULL;
- VarpTable_free(vtable);
- }
- dprintf("<\n");
-}
-
-module_param(varp_mcaddr, charp, 0644);
-module_param(varp_device, charp, 0644);
-MODULE_PARM_DESC(varp_mcaddr, "VARP multicast address");
-MODULE_PARM_DESC(varp_device, "VARP network device");
+++ /dev/null
-/*
- * Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-
-#ifndef _VNET_VARP_H
-#define _VNET_VARP_H
-
-#ifdef __KERNEL__
-
-#else
-
-#include "sys_kernel.h"
-
-#endif
-
-#include "hash_table.h"
-#include "if_varp.h"
-#include "varp_util.h"
-
-#define CONFIG_VARP_GRATUITOUS 1
-
-struct net_device;
-struct sk_buff;
-struct Vif;
-
-enum {
- VARP_UPDATE_CREATE = 1,
- VARP_UPDATE_QUEUE = 2,
-};
-
-extern int vnet_get_device(const char *name, struct net_device **dev);
-extern int vnet_get_device_address(struct net_device *dev, u32 *addr);
-
-extern int varp_remove_vnet(struct VnetId *vnet);
-extern int varp_handle_message(struct sk_buff *skb);
-extern int varp_output(struct sk_buff *skb, struct VnetId *vnet);
-extern int varp_update(struct VnetId *vnet, unsigned char *vmac,
- struct VarpAddr *addr);
-
-extern int varp_init(void);
-extern void varp_exit(void);
-
-extern int varp_open(u32 mcaddr, u16 port);
-extern void varp_close(void);
-extern int varp_set_mcast_addr(u32 addr);
-
-extern void varp_print(struct IOStream *io);
-extern void varp_flush(void);
-
-extern int varp_announce_vif(struct net_device *dev, struct Vif *vif);
-
-extern u32 varp_mcast_addr;
-extern u16 varp_port;
-
-/* MAC broadcast addr is ff-ff-ff-ff-ff-ff (all 1's).
- * MAC multicast addr has low bit 1, i.e. 01-00-00-00-00-00.
- */
-
-/** Test if a MAC address is a multicast or broadcast address.
- *
- * @param mac address
- * @return 1 if it is, 0 if not
- */
-static inline int mac_is_multicast(u8 mac[ETH_ALEN]){
- return mac[0] & 1;
-}
-
-/** Test if a MAC address is the broadcast address.
- *
- * @param mac address
- * @return 1 if it is, 0 if not
- */
-static inline int mac_is_broadcast(u8 mac[ETH_ALEN]){
- u8 mac_bcast_val[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- return memcmp(mac, mac_bcast_val, ETH_ALEN) == 0;
-}
-
-/** Test if a MAC address is the all-zero address.
- *
- * @param mac address
- * @return 1 if it is, 0 if not
- */
-static inline int mac_is_zero(u8 mac[ETH_ALEN]){
- u8 mac_zero_val[ETH_ALEN] = {};
- return memcmp(mac, mac_zero_val, ETH_ALEN) == 0;
-}
-
-/** Print format for a mac address. */
-#define MACFMT "%02x:%02x:%02x:%02x:%02x:%02x"
-
-#define MAC6TUPLE(_mac) (_mac)[0], (_mac)[1], (_mac)[2], (_mac)[3], (_mac)[4], (_mac)[5]
-
-/** Get the subnet defined by a netmask and addr.
- *
- * @param netmask subnet netmask
- * @param addr subnet address
- * @return subnet
- */
-static inline u32 subnet_net(u32 netmask, u32 addr){
- return netmask & addr;
-}
-
-/** Get the address within a subnet.
- *
- * @param netmask subnet netmask
- * @param addr address
- * @return address within the subnet
- */
-static inline u32 subnet_addr(u32 netmask, u32 addr){
- return ~netmask & addr;
-}
-
-/** Get the broadcast address for a subnet.
- *
- * @param netmask subnet netmask
- * @param netaddr subnet address
- * @return subnet broadcast address
- */
-static inline u32 subnet_broadcast_addr(u32 netmask, u32 netaddr){
- return subnet_net(netmask, netaddr) | ~netmask;
-}
-
-/** Test if an address corresponds to a subnet broadcast.
- * True if the address within the subnet is all 1's (in binary).
- * (even if the address is not in the subnet).
- *
- * @param netmask subnet mask
- * @param add address
- * @return 1 if it does, 0 otherwise
- */
-static inline int subnet_broadcast(u32 netmask, u32 addr){
- return subnet_addr(netmask, INADDR_ANY) == subnet_addr(netmask, addr);
-}
-
-/** Test if an address is in a subnet.
- *
- * @param netmask subnet mask
- * @param netaddr subnet address
- * @param addr address
- * @return 1 if it is, 0 otherwise
- */
-static inline int subnet_local(u32 netmask, u32 netaddr, u32 addr){
- return subnet_net(netmask, netaddr) == subnet_net(netmask, addr);
-}
-
-#endif /* ! _VNET_VARP_H */
+++ /dev/null
-/*
- * Copyright (C) 2004, 2005, 2006 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/version.h>
-
-#include <asm/uaccess.h>
-#include <linux/net.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/sched.h>
-#include <linux/file.h>
-#include <linux/version.h>
-#include <linux/smp_lock.h>
-#include <net/sock.h>
-
-#include <if_varp.h>
-#include <varp.h>
-#include <vnet_forward.h>
-
-/* Get macros needed to define system calls as functions in the kernel. */
-#define __KERNEL_SYSCALLS__
-int errno=0;
-#include <linux/unistd.h>
-
-#define MODULE_NAME "VARP"
-#define DEBUG 1
-#undef DEBUG
-#include "debug.h"
-
-/** @file
- * Support for the VARP udp sockets.
- */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
-
-/* Compensate for struct sock fields having 'sk_' added to them in 2.6. */
-#define sk_receive_queue receive_queue
-#define sk_sleep sleep
-
-/* Here because inline in 'socket.c' (2.4, in net.h for 2.6). */
-#define sockfd_put(sock) fput((sock)->file)
-
-#endif
-
-static inline mm_segment_t change_fs(mm_segment_t fs){
- mm_segment_t oldfs = get_fs();
- set_fs(fs);
- return oldfs;
-}
-
-/** Define the fcntl() syscall. */
-static inline _syscall3(int, fcntl,
- unsigned int, fd,
- unsigned int, cmd,
- unsigned long, arg)
-
-/* Replicate the user-space socket API.
- * The parts we need anyway.
- *
- * Some architectures use socketcall() to multiplex the socket-related calls,
- * but others define individual syscalls instead.
- * Architectures using socketcall() define __ARCH_WANT_SYS_SOCKETCALL.
- * NB. x86_64 architecture asserts __ARCH_WANT_SYS_SOCKETCALL in error.
- */
-
-#if defined(__ARCH_WANT_SYS_SOCKETCALL) && !defined(__x86_64__)
-
-/* Define the socketcall() syscall.
- * Multiplexes all the socket-related calls.
- *
- * @param call socket call id
- * @param args arguments (upto 6)
- * @return call-dependent value
- */
-static inline _syscall2(int, socketcall,
- int, call,
- unsigned long *, args)
-
-int socket(int family, int type, int protocol){
- unsigned long args[6];
-
- args[0] = (unsigned long)family;
- args[1] = (unsigned long)type;
- args[2] = (unsigned long)protocol;
- return socketcall(SYS_SOCKET, args);
-}
-
-int bind(int fd, struct sockaddr *umyaddr, int addrlen){
- unsigned long args[6];
-
- args[0] = (unsigned long)fd;
- args[1] = (unsigned long)umyaddr;
- args[2] = (unsigned long)addrlen;
- return socketcall(SYS_BIND, args);
-}
-
-int connect(int fd, struct sockaddr *uservaddr, int addrlen){
- unsigned long args[6];
-
- args[0] = (unsigned long)fd;
- args[1] = (unsigned long)uservaddr;
- args[2] = (unsigned long)addrlen;
- return socketcall(SYS_CONNECT, args);
-}
-
-int sendto(int fd, void * buff, size_t len,
- unsigned flags, struct sockaddr *addr,
- int addr_len){
- unsigned long args[6];
-
- args[0] = (unsigned long)fd;
- args[1] = (unsigned long)buff;
- args[2] = (unsigned long)len;
- args[3] = (unsigned long)flags;
- args[4] = (unsigned long)addr;
- args[5] = (unsigned long)addr_len;
- return socketcall(SYS_SENDTO, args);
-}
-
-int recvfrom(int fd, void * ubuf, size_t size,
- unsigned flags, struct sockaddr *addr,
- int *addr_len){
- unsigned long args[6];
-
- args[0] = (unsigned long)fd;
- args[1] = (unsigned long)ubuf;
- args[2] = (unsigned long)size;
- args[3] = (unsigned long)flags;
- args[4] = (unsigned long)addr;
- args[5] = (unsigned long)addr_len;
- return socketcall(SYS_RECVFROM, args);
-}
-
-int setsockopt(int fd, int level, int optname, void *optval, int optlen){
- unsigned long args[6];
-
- args[0] = (unsigned long)fd;
- args[1] = (unsigned long)level;
- args[2] = (unsigned long)optname;
- args[3] = (unsigned long)optval;
- args[4] = (unsigned long)optlen;
- return socketcall(SYS_SETSOCKOPT, args);
-}
-
-int getsockopt(int fd, int level, int optname, void *optval, int *optlen){
- unsigned long args[6];
-
- args[0] = (unsigned long)fd;
- args[1] = (unsigned long)level;
- args[2] = (unsigned long)optname;
- args[3] = (unsigned long)optval;
- args[4] = (unsigned long)optlen;
- return socketcall(SYS_GETSOCKOPT, args);
-}
-
-int shutdown(int fd, int how){
- unsigned long args[6];
-
- args[0] = (unsigned long)fd;
- args[1] = (unsigned long)how;
- return socketcall(SYS_SHUTDOWN, args);
-}
-
-int getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len){
- unsigned long args[6];
-
- args[0] = (unsigned long)fd;
- args[1] = (unsigned long)usockaddr;
- args[2] = (unsigned long)usockaddr_len;
- return socketcall(SYS_GETSOCKNAME, args);
-}
-
-#else /* !__ARCH_WANT_SYS_SOCKETCALL */
-
-/* No socketcall - define the individual syscalls. */
-
-static inline _syscall3(int, socket,
- int, family,
- int, type,
- int, protocol);
-
-static inline _syscall3(int, bind,
- int, fd,
- struct sockaddr *, umyaddr,
- int, addrlen);
-
-static inline _syscall3(int, connect,
- int, fd,
- struct sockaddr *, uservaddr,
- int, addrlen);
-
-static inline _syscall6(int, sendto,
- int, fd,
- void *, buff,
- size_t, len,
- unsigned, flags,
- struct sockaddr *, addr,
- int, addr_len);
-
-static inline _syscall6(int, recvfrom,
- int, fd,
- void *, ubuf,
- size_t, size,
- unsigned, flags,
- struct sockaddr *, addr,
- int *, addr_len);
-
-static inline _syscall5(int, setsockopt,
- int, fd,
- int, level,
- int, optname,
- void *, optval,
- int, optlen);
-
-static inline _syscall5(int, getsockopt,
- int, fd,
- int, level,
- int, optname,
- void *, optval,
- int *, optlen);
-
-static inline _syscall2(int, shutdown,
- int, fd,
- int, how);
-
-static inline _syscall3(int, getsockname,
- int, fd,
- struct sockaddr *, usockaddr,
- int *, usockaddr_len);
-
-#endif /* __ARCH_WANT_SYS_SOCKETCALL */
-
-/*============================================================================*/
-/** Socket flags. */
-enum VsockFlag {
- VSOCK_REUSE = 1,
- VSOCK_BIND = 2,
- VSOCK_CONNECT = 4,
- VSOCK_BROADCAST = 8,
- VSOCK_MULTICAST = 16,
- VSOCK_NONBLOCK = 32,
- };
-
-/** Convert socket flags to a string.
- *
- * @param flags flags
- * @return static string
- */
-char * socket_flags(int flags){
- static char s[7];
- int i = 0;
- s[i++] = (flags & VSOCK_CONNECT ? 'c' : '-');
- s[i++] = (flags & VSOCK_BIND ? 'b' : '-');
- s[i++] = (flags & VSOCK_REUSE ? 'r' : '-');
- s[i++] = (flags & VSOCK_BROADCAST ? 'B' : '-');
- s[i++] = (flags & VSOCK_MULTICAST ? 'M' : '-');
- s[i++] = (flags & VSOCK_NONBLOCK ? 'N' : '-');
- s[i++] = '\0';
- return s;
-}
-
-/** Control flag for whether varp should be running.
- * If this is set 0 then the varp thread will notice and
- * (eventually) exit.
- */
-atomic_t varp_run = ATOMIC_INIT(0);
-
-enum {
- VARP_STATE_EXITED = 2,
- VARP_STATE_RUNNING = 1,
- VARP_STATE_NONE = 0,
- VARP_STATE_ERROR = -1,
-};
-
-/** State indicating whether the varp thread is running. */
-atomic_t varp_state = ATOMIC_INIT(VARP_STATE_NONE);
-
-int varp_thread_err = 0;
-
-/** The varp multicast socket. */
-int varp_mcast_sock = -1;
-
-/** The varp unicast socket. */
-int varp_ucast_sock = -1;
-
-/** Set socket option to reuse address.
- *
- * @param sock socket
- * @param reuse flag
- * @return 0 on success, error code otherwise
- */
-int setsock_reuse(int sock, int reuse){
- int err = 0;
- err = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
- if(err < 0){
- eprintf("> setsockopt SO_REUSEADDR: %d %d\n", err, errno);
- }
- return err;
-}
-
-/** Set socket broadcast option.
- *
- * @param sock socket
- * @param bcast flag
- * @return 0 on success, error code otherwise
- */
-int setsock_broadcast(int sock, int bcast){
- int err = 0;
- err = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &bcast, sizeof(bcast));
- if(err < 0){
- eprintf("> setsockopt SO_BROADCAST: %d %d\n", err, errno);
- }
- return err;
-}
-
-/** Join a socket to a multicast group.
- *
- * @param sock socket
- * @param saddr multicast address
- * @return 0 on success, error code otherwise
- */
-int setsock_multicast(int sock, uint32_t saddr){
- int err = 0;
- struct ip_mreqn mreq = {};
- int mloop = 0;
-
- // See 'man 7 ip' for these options.
- mreq.imr_multiaddr.s_addr = saddr; // IP multicast address.
- mreq.imr_address.s_addr = INADDR_ANY; // Interface IP address.
- mreq.imr_ifindex = 0; // Interface index (0 means any).
- err = setsockopt(sock, SOL_IP, IP_MULTICAST_LOOP, &mloop, sizeof(mloop));
- if(err < 0){
- eprintf("> setsockopt IP_MULTICAST_LOOP: %d %d\n", err, errno);
- goto exit;
- }
- err = setsockopt(sock, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
- if(err < 0){
- eprintf("> setsockopt IP_ADD_MEMBERSHIP: %d %d\n", err, errno);
- goto exit;
- }
- exit:
- return err;
-}
-
-/** Set a socket's multicast ttl (default is 1).
- * @param sock socket
- * @param ttl ttl
- * @return 0 on success, error code otherwise
- */
-int setsock_multicast_ttl(int sock, uint8_t ttl){
- int err = 0;
- err = setsockopt(sock, SOL_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
- return err;
-}
-
-/** Create a socket.
- * The flags can include values from enum VsockFlag.
- *
- * @param socktype socket type
- * @param saddr address
- * @param port port
- * @param flags flags
- * @param val return value for the socket connection
- * @return 0 on success, error code otherwise
- */
-int create_socket(int socktype, uint32_t saddr, uint32_t port, int flags, int *val){
- int err = 0;
- int sock;
- struct sockaddr_in addr_in;
- struct sockaddr *addr = (struct sockaddr *)&addr_in;
- int addr_n = sizeof(addr_in);
- int sockproto = 0;
-
- //dprintf(">\n");
- addr_in.sin_family = AF_INET;
- addr_in.sin_addr.s_addr = saddr;
- addr_in.sin_port = port;
- dprintf("> flags=%s addr=%u.%u.%u.%u port=%d\n",
- socket_flags(flags),
- NIPQUAD(saddr), ntohs(port));
-
- switch(socktype){
- case SOCK_DGRAM: sockproto = IPPROTO_UDP; break;
- case SOCK_STREAM: sockproto = IPPROTO_TCP; break;
- }
- sock = socket(AF_INET, socktype, sockproto);
- if(sock < 0) goto exit;
- if(flags & VSOCK_REUSE){
- err = setsock_reuse(sock, 1);
- if(err < 0) goto exit;
- }
- if(flags & VSOCK_BROADCAST){
- err = setsock_broadcast(sock, 1);
- if(err < 0) goto exit;
- }
- if(flags & VSOCK_MULTICAST){
- err = setsock_multicast(sock, saddr);
- if(err < 0) goto exit;
- }
- if(flags & VSOCK_CONNECT){
- err = connect(sock, addr, addr_n);
- if(err < 0) goto exit;
- }
- if(flags & VSOCK_BIND){
- err = bind(sock, addr, addr_n);
- if(err < 0) goto exit;
- }
- if(flags & VSOCK_NONBLOCK){
- err = fcntl(sock, F_SETFL, O_NONBLOCK);
- if(err < 0) goto exit;
- }
- exit:
- *val = (err ? -1 : sock);
- if(err) eprintf("> err=%d errno=%d\n", err, errno);
- return err;
-}
-
-/** Open the varp multicast socket.
- *
- * @param mcaddr multicast address
- * @param port port
- * @param val return parameter for the socket
- * @return 0 on success, error code otherwise
- */
-int varp_mcast_open(uint32_t mcaddr, uint16_t port, int *val){
- int err = 0;
- int flags = VSOCK_REUSE;
- int sock = 0;
-
- dprintf(">\n");
- flags |= VSOCK_MULTICAST;
- flags |= VSOCK_BROADCAST;
-
- err = create_socket(SOCK_DGRAM, mcaddr, port, flags, &sock);
- if(err < 0) goto exit;
- if(MULTICAST(mcaddr)){
- err = setsock_multicast_ttl(sock, 1);
- if(err < 0) goto exit;
- }
- exit:
- if(err){
- shutdown(sock, 2);
- }
- *val = (err ? -1 : sock);
- dprintf("< err=%d val=%d\n", err, *val);
- return err;
-}
-
-/** Open the varp unicast socket.
- *
- * @param addr address
- * @param port port
- * @param val return parameter for the socket
- * @return 0 on success, error code otherwise
- */
-int varp_ucast_open(uint32_t addr, u16 port, int *val){
- int err = 0;
- int flags = (VSOCK_BIND | VSOCK_REUSE);
- dprintf(">\n");
- err = create_socket(SOCK_DGRAM, addr, port, flags, val);
- dprintf("< err=%d val=%d\n", err, *val);
- return err;
-}
-
-/**
- * Return code > 0 means the handler owns the packet.
- * Return code <= 0 means we still own it, with < 0 meaning
- * an error.
- */
-static int handle_varp_skb(struct sk_buff *skb){
- int err = 0;
- switch(skb->pkt_type){
- case PACKET_BROADCAST:
- case PACKET_MULTICAST:
- vnet_forward_send(skb);
- /* Fall through. */
- case PACKET_HOST:
- err = varp_handle_message(skb);
- break;
- case PACKET_OTHERHOST:
- dprintf("> PACKET_OTHERHOST\n");
- break;
- case PACKET_OUTGOING:
- dprintf("> PACKET_OUTGOING\n");
- break;
- case PACKET_FASTROUTE:
- dprintf("> PACKET_FASTROUTE\n");
- break;
- case PACKET_LOOPBACK:
- // Outbound mcast/bcast are echoed with this type. Drop.
- dprintf("> LOOP src=" IPFMT " dst=" IPFMT " dev=%s\n",
- NIPQUAD(skb->nh.iph->saddr),
- NIPQUAD(skb->nh.iph->daddr),
- (skb->dev ? skb->dev->name : "??"));
- default:
- // Drop.
- break;
- }
- if(err <= 0){
- kfree_skb(skb);
- }
- return (err < 0 ? err : 0);
-}
-
-/** Handle some skbs on a varp socket (if any).
- *
- * @param fd socket file descriptor
- * @param n maximum number of skbs to handle
- * @return number of skbs handled
- */
-static int handle_varp_sock(int fd, int n){
- int ret = 0;
- int err = 0;
- struct sk_buff *skb;
- struct socket *sock = NULL;
-
- sock = sockfd_lookup(fd, &err);
- if (!sock){
- wprintf("> no sock for fd=%d\n", fd);
- goto exit;
- }
- for( ; ret < n; ret++){
- if(!sock->sk) break;
- skb = skb_dequeue(&sock->sk->sk_receive_queue);
- if(!skb) break;
- // Call the skb destructor so it isn't charged to the socket anymore.
- // An skb from a socket receive queue is charged to the socket
- // by skb_set_owner_r() until its destructor is called.
- // If the destructor is not called the socket will run out of
- // receive queue space and be unable to accept incoming skbs.
- // The destructor used is sock_rfree(), see 'include/net/sock.h'.
- // Other destructors: sock_wfree, sk_stream_rfree.
- skb_orphan(skb);
- handle_varp_skb(skb);
- }
- sockfd_put(sock);
- exit:
- dprintf("< ret=%d\n", ret);
- return ret;
-}
-
-/** Add a wait queue to a socket.
- *
- * @param fd socket file descriptor
- * @param waitq queue
- * @return 0 on success, error code otherwise
- */
-int sock_add_wait_queue(int fd, wait_queue_t *waitq){
- int err = -EINVAL;
- struct socket *sock = NULL;
-
- if(fd < 0) goto exit;
- sock = sockfd_lookup(fd, &err);
- if (!sock) goto exit;
- add_wait_queue(sock->sk->sk_sleep, waitq);
- sockfd_put(sock);
- err = 0;
- exit:
- return err;
-}
-
-/** Remove a wait queue from a socket.
- *
- * @param fd socket file descriptor
- * @param waitq queue
- * @return 0 on success, error code otherwise
- */
-int sock_remove_wait_queue(int fd, wait_queue_t *waitq){
- int err = -EINVAL;
- struct socket *sock = NULL;
-
- if(fd < 0) goto exit;
- sock = sockfd_lookup(fd, &err);
- if (!sock) goto exit;
- remove_wait_queue(sock->sk->sk_sleep, waitq);
- sockfd_put(sock);
- err = 0;
- exit:
- return err;
-}
-
-#if 0
-// Default data ready function on a socket.
-static void sock_def_readable(struct sock *sk, int len)
-{
- read_lock(&sk->sk_callback_lock);
- if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
- wake_up_interruptible(sk->sk_sleep);
- sk_wake_async(sk,1,POLL_IN);
- read_unlock(&sk->sk_callback_lock);
-}
-#endif
-
-static void sock_data_ready(struct sock *sk, int len){
- struct sk_buff *skb;
- //read_lock(&sk->sk_callback_lock);
- skb = skb_dequeue(&sk->sk_receive_queue);
- if(skb){
- skb_orphan(skb);
- }
- //read_unlock(&sk->sk_callback_lock);
- if(skb){
- handle_varp_skb(skb);
- }
-}
-
-/** Set the data ready callback on a socket.
- */
-int sock_set_callback(int fd){
- int err = -EINVAL;
- struct socket *sock = NULL;
-
- if(fd < 0) goto exit;
- sock = sockfd_lookup(fd, &err);
- if (!sock) goto exit;
- sock->sk->sk_data_ready = sock_data_ready;
- sockfd_put(sock);
- err = 0;
- exit:
- return err;
-}
-
-/** Open the sockets. */
-int varp_sockets_open(u32 mcaddr, u16 port){
- int err = 0;
- mm_segment_t oldfs;
-
- dprintf("> mcaddr=%u.%u.%u.%u port=%u\n", NIPQUAD(mcaddr), ntohs(port));
- oldfs = change_fs(KERNEL_DS);
- err = varp_mcast_open(mcaddr, port, &varp_mcast_sock);
- if(err < 0 ) goto exit;
- err = varp_ucast_open(INADDR_ANY, port, &varp_ucast_sock);
- if(err < 0 ) goto exit;
- sock_set_callback(varp_ucast_sock);
- sock_set_callback(varp_mcast_sock);
- exit:
- set_fs(oldfs);
- dprintf("< err=%d\n", err);
- return err;
-}
-
-/** Close the sockets. */
-void varp_sockets_close(void){
- mm_segment_t oldfs;
- oldfs = change_fs(KERNEL_DS);
- if(varp_mcast_sock >= 0){
- shutdown(varp_mcast_sock, 2);
- varp_mcast_sock = -1;
- }
- if(varp_ucast_sock >= 0){
- shutdown(varp_ucast_sock, 2);
- varp_ucast_sock = -1;
- }
- set_fs(oldfs);
-}
-
-/** Loop handling the varp sockets.
- * We use kernel API for this (waitqueue, schedule_timeout) instead
- * of select because the select syscall was returning EFAULT. Oh well.
- *
- * @param arg arguments
- * @return exit code
- */
-int varp_main(void *arg){
- int err = 0;
- long timeout = 1 * HZ;
- int count = 0;
- DECLARE_WAITQUEUE(mcast_wait, current);
- DECLARE_WAITQUEUE(ucast_wait, current);
-
- dprintf("> start\n");
- snprintf(current->comm, sizeof(current->comm), "varp_main");
-
- err = sock_add_wait_queue(varp_mcast_sock, &mcast_wait);
- if(err) goto exit_mcast_sock;
- err = sock_add_wait_queue(varp_ucast_sock, &ucast_wait);
- if(err) goto exit_ucast_sock;
- atomic_set(&varp_state, VARP_STATE_RUNNING);
- for( ; atomic_read(&varp_run); ){
- count = 0;
- count += handle_varp_sock(varp_mcast_sock, 1);
- count += handle_varp_sock(varp_ucast_sock, 16);
- if(!count){
- if(!atomic_read(&varp_run)) break;
- // No skbs were handled, go to sleep.
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(timeout);
- __set_current_state(TASK_RUNNING);
- }
- }
- exit_ucast_sock:
- sock_remove_wait_queue(varp_ucast_sock, &ucast_wait);
- exit_mcast_sock:
- sock_remove_wait_queue(varp_mcast_sock, &mcast_wait);
- varp_sockets_close();
- if(err){
- eprintf("%s< err=%d\n", __FUNCTION__, err);
- }
- varp_thread_err = err;
- atomic_set(&varp_state, VARP_STATE_EXITED);
- //MOD_DEC_USE_COUNT;
- return err;
-}
-
-/** Close the varp sockets and stop the thread handling them.
- */
-void varp_close(void){
- int tries = 10;
- dprintf(">\n");
- // Tell the varp thread to stop and wait a while for it.
- atomic_set(&varp_run, 0);
- while(atomic_read(&varp_state) == VARP_STATE_RUNNING && tries-- > 0){
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ / 2);
- __set_current_state(TASK_RUNNING);
- }
- //MOD_DEC_USE_COUNT;
- dprintf("<\n");
-}
-
-/** Open the varp sockets and start the thread handling them.
- *
- * @param mcaddr multicast address
- * @param port port
- * @return 0 on success, error code otherwise
- */
-int varp_open(u32 mcaddr, u16 port){
- int err = 0;
-
- //MOD_INC_USE_COUNT;
- dprintf(">\n");
- err = varp_sockets_open(mcaddr, port);
- if(err) goto exit;
- atomic_set(&varp_run, 1);
- atomic_set(&varp_state, VARP_STATE_NONE);
- kernel_thread(varp_main, NULL, (CLONE_FS | CLONE_FILES | CLONE_SIGHAND));
-#if 0
- while(atomic_read(&varp_state) == VARP_STATE_NONE){
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(1 * HZ);
- __set_current_state(TASK_RUNNING);
- }
- err = varp_thread_err;
-#endif
- exit:
- if(err){
- wprintf("> err=%d\n", err);
- }
- return err;
-}
+++ /dev/null
-/*
- * Copyright (C) 2005 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-
-static int hex16(char *s, uint16_t *val)
-{
- int err = -EINVAL;
- uint16_t v = 0;
-
- for( ; *s; s++){
- v <<= 4;
- if('0' <= *s && *s <= '9'){
- v |= *s - '0';
- } else if('A' <= *s && *s <= 'F'){
- v |= *s - 'A' + 10;
- } else if('a' <= *s && *s <= 'f'){
- v |= *s - 'a' + 10;
- } else {
- goto exit;
- }
- }
- err = 0;
- exit:
- *val = (err ? 0 : v);
- return err;
-}
-
-int VnetId_aton(const char *s, VnetId *vnet){
- int err = -EINVAL;
- const char *p, *q;
- uint16_t v;
- char buf[5];
- int buf_n = sizeof(buf) - 1;
- int i, n;
- const int elts_n = VNETID_SIZE16;
-
- q = s;
- p = strchr(q, ':');
- i = (p ? 0 : elts_n - 1);
- do {
- if(!p){
- if(i < elts_n - 1) goto exit;
- p = s + strlen(s);
- }
- n = p - q;
- if(n > buf_n) goto exit;
- memcpy(buf, q, n);
- buf[n] = '\0';
- err = hex16(buf, &v);
- if(err) goto exit;
- vnet->u.vnet16[i] = htons(v);
- q = p+1;
- p = strchr(q, ':');
- i++;
- } while(i < elts_n);
- err = 0;
- exit:
- if(err){
- *vnet = (VnetId){};
- }
- return err;
-}
+++ /dev/null
-/*
- * Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-#ifndef _VNET_VARP_UTIL_H
-#define _VNET_VARP_UTIL_H
-
-#include "hash_table.h"
-
-/** Size of a string buffer to store a varp address. */
-#define VARP_ADDR_BUF 56
-
-/** Size of a string buffer to store a vnet id. */
-#define VNET_ID_BUF 56
-
-#ifndef NIPQUAD
-#define NIPQUAD(addr) \
- ((unsigned char *)&addr)[0], \
- ((unsigned char *)&addr)[1], \
- ((unsigned char *)&addr)[2], \
- ((unsigned char *)&addr)[3]
-#endif
-
-#ifndef NIP6
-#define NIP6(addr) \
- ntohs((addr).s6_addr16[0]), \
- ntohs((addr).s6_addr16[1]), \
- ntohs((addr).s6_addr16[2]), \
- ntohs((addr).s6_addr16[3]), \
- ntohs((addr).s6_addr16[4]), \
- ntohs((addr).s6_addr16[5]), \
- ntohs((addr).s6_addr16[6]), \
- ntohs((addr).s6_addr16[7])
-#endif
-
-
-static inline const char *VarpAddr_ntoa(VarpAddr *addr, char buf[VARP_ADDR_BUF])
-{
- switch(addr->family){
- default:
- case AF_INET:
- snprintf(buf, sizeof(buf), "%u.%u.%u.%u",
- NIPQUAD(addr->u.ip4));
- break;
- case AF_INET6:
- snprintf(buf, sizeof(buf), "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
- NIP6(addr->u.ip6));
- break;
- }
- return buf;
-}
-
-static inline const char *VnetId_ntoa(VnetId *vnet, char buf[VNET_ID_BUF])
-{
- snprintf(buf, sizeof(buf), "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
- ntohs(vnet->u.vnet16[0]), \
- ntohs(vnet->u.vnet16[1]), \
- ntohs(vnet->u.vnet16[2]), \
- ntohs(vnet->u.vnet16[3]), \
- ntohs(vnet->u.vnet16[4]), \
- ntohs(vnet->u.vnet16[5]), \
- ntohs(vnet->u.vnet16[6]), \
- ntohs(vnet->u.vnet16[7]));
- return buf;
-}
-
-extern int VnetId_aton(const char *s, VnetId *vnet);
-
-/** Convert an unsigned in host order to a vnet id.
- */
-static inline struct VnetId toVnetId(uint32_t vnetid){
- struct VnetId vnet = {};
- vnet.u.vnet32[VNETID_SIZE32 - 1] = htonl(vnetid);
- return vnet;
-}
-
-static inline int VnetId_eq(VnetId *id1, VnetId *id2){
- return memcmp(id1, id2, sizeof(VnetId)) == 0;
-}
-
-#endif /* _VNET_VARP_UTIL_H */
+++ /dev/null
-/*
- * Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-
-#ifdef __KERNEL__
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-
-#else
-
-#include "sys_kernel.h"
-#include "spinlock.h"
-#include "skbuff.h"
-
-#endif
-
-#include <vif.h>
-#include <varp.h>
-#include <varp_util.h>
-
-#include "allocate.h"
-#include "iostream.h"
-#include "hash_table.h"
-#include "timer_util.h"
-
-#define MODULE_NAME "VNET"
-#define DEBUG 1
-#undef DEBUG
-#include "debug.h"
-
-/** Vif table ttl - interval between sweeps of old vifs. */
-#define VIF_TABLE_TTL (60*HZ)
-
-/** Vif entry ttl - a vif entry older than this is removed. */
-#define VIF_ENTRY_TTL (60*HZ)
-
-/** Table of vifs indexed by VifKey. */
-HashTable *vif_table = NULL;
-rwlock_t vif_table_lock = RW_LOCK_UNLOCKED;
-struct timer_list vif_table_timer = {};
-int vif_table_sweeps = 0;
-
-#define vif_read_lock(flags) read_lock_irqsave(&vif_table_lock, (flags))
-#define vif_read_unlock(flags) read_unlock_irqrestore(&vif_table_lock, (flags))
-#define vif_write_lock(flags) write_lock_irqsave(&vif_table_lock, (flags))
-#define vif_write_unlock(flags) write_unlock_irqrestore(&vif_table_lock, (flags))
-
-void vif_entry_print(Vif *vif, IOStream *io){
- char vnetbuf[VNET_ID_BUF];
- unsigned long now = jiffies;
-
- IOStream_print(io, "(vif\n");
- IOStream_print(io, " (vnet %s)\n", VnetId_ntoa(&vif->vnet, vnetbuf));
- IOStream_print(io, " (vmac " MACFMT ")\n", MAC6TUPLE(vif->vmac.mac));
- IOStream_print(io, " (age %u)\n", now - vif->timestamp);
- IOStream_print(io, ")\n");
-}
-
-void vif_print(IOStream *io){
- HashTable_for_decl(entry);
- Vif *vif;
- unsigned long flags;
-
- vif_read_lock(flags);
- IOStream_print(io, "(viftable\n");
- IOStream_print(io, " (table_ttl %u)\n", VIF_TABLE_TTL);
- IOStream_print(io, " (entry_ttl %u)\n", VIF_ENTRY_TTL);
- IOStream_print(io, " (sweeps %d)\n", vif_table_sweeps);
- IOStream_print(io, ")\n");
-
- HashTable_for_each(entry, vif_table){
- vif = entry->value;
- vif_entry_print(vif, io);
- }
- vif_read_unlock(flags);
-}
-
-void vif_decref(Vif *vif){
- if(!vif) return;
- if(atomic_dec_and_test(&vif->refcount)){
- kfree(vif);
- }
-}
-
-void vif_incref(Vif *vif){
- if(!vif) return;
- atomic_inc(&vif->refcount);
-}
-
-/** Hash function for keys in the vif table.
- * Hashes the vnet id and mac.
- *
- * @param k key (VifKey)
- * @return hashcode
- */
-static Hashcode vif_key_hash_fn(void *k){
- return hash_hvoid(0, k, sizeof(VifKey));
-}
-
-/** Test equality for keys in the vif table.
- * Compares vnet and mac.
- *
- * @param k1 key to compare (VifKey)
- * @param k2 key to compare (VifKey)
- * @return 1 if equal, 0 otherwise
- */
-static int vif_key_equal_fn(void *k1, void *k2){
- return memcmp(k1, k2, sizeof(VifKey)) == 0;
-}
-
-/** Free an entry in the vif table.
- *
- * @param table containing table
- * @param entry entry to free
- */
-static void vif_entry_free_fn(HashTable *table, HTEntry *entry){
- Vif *vif;
- if(!entry) return;
- vif = entry->value;
- if(vif){
- vif_decref(vif);
- }
- HTEntry_free(entry);
-}
-
-/** Lookup a vif.
- * Caller must hold vif lock.
- *
- * @param vnet vnet id
- * @param mac MAC address
- * @return 0 on success, -ENOENT otherwise
- */
-static int _vif_lookup(VnetId *vnet, Vmac *vmac, Vif **vif){
- int err = 0;
- VifKey key = { .vnet = *vnet, .vmac = *vmac };
- HTEntry *entry = NULL;
-
- entry = HashTable_get_entry(vif_table, &key);
- if(entry){
- *vif = entry->value;
- vif_incref(*vif);
- } else {
- *vif = NULL;
- err = -ENOENT;
- }
- return err;
-}
-
-/** Lookup a vif.
- *
- * @param vnet vnet id
- * @param mac MAC address
- * @return 0 on success, -ENOENT otherwise
- */
-int vif_lookup(VnetId *vnet, Vmac *vmac, Vif **vif){
- unsigned long flags;
- int err;
-
- vif_read_lock(flags);
- err = _vif_lookup(vnet, vmac, vif);
- vif_read_unlock(flags);
- return err;
-}
-
-/** Create a new vif.
- * Entry must not exist.
- * Caller must hold vif lock.
- *
- * @param vnet vnet id
- * @param mac MAC address
- * @return 0 on success, negative error code otherwise
- */
-static int _vif_add(VnetId *vnet, Vmac *vmac, Vif **val){
- int err = 0;
- Vif *vif = NULL;
- HTEntry *entry;
- unsigned long now = jiffies;
-
- vif = ALLOCATE(Vif);
- if(!vif){
- err = -ENOMEM;
- goto exit;
- }
- atomic_set(&vif->refcount, 1);
- vif->vnet = *vnet;
- vif->vmac = *vmac;
- vif->timestamp = now;
- entry = HashTable_add(vif_table, vif, vif);
- if(!entry){
- err = -ENOMEM;
- deallocate(vif);
- vif = NULL;
- goto exit;
- }
- vif_incref(vif);
- exit:
- *val = (err ? NULL : vif);
- return err;
-}
-
-/** Delete a vif entry.
- *
- * @param vnet vnet id
- * @param mac MAC address
- * @return number of entries deleted, or negative error code
- */
-int vif_remove(VnetId *vnet, Vmac *vmac){
- int err = 0;
- VifKey key = { .vnet = *vnet, .vmac = *vmac };
- unsigned long flags;
-
- vif_write_lock(flags);
- err = HashTable_remove(vif_table, &key);
- vif_write_unlock(flags);
- return err;
-}
-
-/** Delete all vifs on a vnet.
- *
- * @param vnet vnet id
- * @return number of entries deleted
- */
-int vif_remove_vnet(VnetId *vnet){
- int count = 0;
- unsigned long flags;
- HashTable_for_decl(entry);
-
-
- vif_write_lock(flags);
- HashTable_for_each(entry, vif_table){
- Vif *vif = entry->value;
- if(VnetId_eq(&vif->vnet, vnet)){
- count += HashTable_remove(vif_table, vif);
- }
- }
- vif_write_unlock(flags);
- return count;
-}
-
-/** Purge the vif table.
- */
-void vif_purge(void){
- unsigned long flags;
- vif_write_lock(flags);
- HashTable_clear(vif_table);
- vif_write_unlock(flags);
-}
-
-/** Sweep old vif entries from the vif table.
- */
-void vif_sweep(void){
- HashTable_for_decl(entry);
- Vif *vif;
- int vif_count = 0;
- unsigned long now = jiffies;
- unsigned long old = VIF_ENTRY_TTL;
- unsigned long flags;
-
- vif_write_lock(flags);
- vif_table_sweeps++;
- HashTable_for_each(entry, vif_table){
- vif = entry->value;
- vif_count++;
- if(!(vif->flags & VIF_FLAG_PERSISTENT)
- && (now - vif->timestamp > old)){
- iprintf("> Sweeping:\n");
- vif_entry_print(vif, iostdout);
- HashTable_remove(vif_table, entry->key);
- }
- }
- vif_write_unlock(flags);
-}
-
-/** Create a new vif if it does not exist.
- * Caller must hold vif lock.
- *
- * @param vnet vnet id
- * @param mac MAC address
- * @return 0 on success, negative error code otherwise
- */
-int _vif_create(VnetId *vnet, Vmac *vmac, Vif **vif){
- int err = 0;
-
- if(_vif_lookup(vnet, vmac, vif) == 0){
- goto exit;
- }
- err = _vif_add(vnet, vmac, vif);
- exit:
- return err;
-}
-
-/** Create a new vif if it does not exist.
- *
- * @param vnet vnet id
- * @param mac MAC address
- * @return 0 on success, negative error code otherwise
- */
-int vif_create(VnetId *vnet, Vmac *vmac, int vflags, Vif **vif){
- int err = 0;
- unsigned long flags;
-
- vif_write_lock(flags);
- err = _vif_create(vnet, vmac, vif);
- if(!err && *vif){
- (*vif)->flags = vflags;
- }
- vif_write_unlock(flags);
- return err;
-}
-
-/** Update the timestamp for a vif.
- *
- * @param vnet vnet id
- * @param mac MAC address
- * @return 0 on success, negative error code otherwise
- */
-int vif_update(VnetId *vnet, Vmac *vmac){
- Vif *vif = NULL;
- int err = 0;
- unsigned long now = jiffies;
- unsigned long flags;
-
- vif_write_lock(flags);
- err = _vif_create(vnet, vmac, &vif);
- if(err) goto exit;
- vif->timestamp = now;
- vif_decref(vif);
- exit:
- vif_write_unlock(flags);
- return err;
-}
-
-static void vif_table_timer_fn(unsigned long arg){
- if(!vif_table) return;
- vif_sweep();
- timer_set(&vif_table_timer, VIF_TABLE_TTL);
-}
-
-/** Initialize the vif table.
- *
- * @return 0 on success, error code otherwise
- */
-int vif_init(void){
- int err = 0;
- vif_table = HashTable_new(0);
- if(!vif_table){
- err = -ENOMEM;
- goto exit;
- }
- vif_table->entry_free_fn = vif_entry_free_fn;
- vif_table->key_size = sizeof(VifKey);
- vif_table->key_hash_fn = vif_key_hash_fn;
- vif_table->key_equal_fn = vif_key_equal_fn;
-
- timer_init(&vif_table_timer, vif_table_timer_fn, 0);
- timer_set(&vif_table_timer, VIF_TABLE_TTL);
-
- exit:
- if(err < 0){
- eprintf("> vif_init err=%d\n", err);
- }
- return err;
-}
-
-void vif_exit(void){
- timer_cancel(&vif_table_timer);
- HashTable_free(vif_table);
- vif_table = NULL;
-}
+++ /dev/null
-/*
- * Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-#ifndef _VNET_VIF_H_
-#define _VNET_VIF_H_
-
-#ifdef __KERNEL__
-#include <asm/atomic.h>
-#else
-#include "spinlock.h"
-#endif
-
-#include <if_varp.h>
-struct IOStream;
-
-/** Key for entries in the vif table. */
-typedef struct VifKey {
- struct VnetId vnet;
- struct Vmac vmac;
-} VifKey;
-
-typedef struct Vif {
- struct VnetId vnet;
- struct Vmac vmac;
- atomic_t refcount;
- unsigned long timestamp;
- int flags;
-} Vif;
-
-enum {
- VIF_FLAG_PERSISTENT = 1,
-};
-
-extern void vif_print(struct IOStream *io);
-
-extern void vif_decref(struct Vif *vif);
-extern void vif_incref(struct Vif *vif);
-
-extern int vif_create(struct VnetId *vnet, struct Vmac *vmac, int flags, struct Vif **vif);
-extern int vif_lookup(struct VnetId *vnet, struct Vmac *vmac, struct Vif **vif);
-extern int vif_update(struct VnetId *vnet, struct Vmac *vmac);
-extern int vif_remove(struct VnetId *vnet, struct Vmac *vmac);
-extern void vif_purge(void);
-extern int vif_remove_vnet(struct VnetId *vnet);
-
-extern int vif_init(void);
-extern void vif_exit(void);
-
-#endif
+++ /dev/null
-/*
- * Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-
-#ifdef __KERNEL__
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/version.h>
-#include <linux/errno.h>
-
-#include <linux/string.h>
-#include <linux/spinlock.h>
-
-#include <linux/net.h>
-#include <linux/in.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-
-#include <linux/etherdevice.h>
-#include <net/ip.h>
-#include <net/protocol.h>
-#include <net/route.h>
-#include <linux/skbuff.h>
-#include <net/checksum.h>
-
-
-#else
-
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include "sys_kernel.h"
-#include "spinlock.h"
-#include "skbuff.h"
-
-#include <linux/ip.h> // For struct iphdr.
-
-extern int netif_rx(struct sk_buff *skb);
-
-#endif
-
-#include <tunnel.h>
-#include <sa.h>
-#include <varp.h>
-#include <if_varp.h>
-#include <esp.h>
-#include <etherip.h>
-#include <random.h>
-
-#include <skb_context.h>
-
-#include <skb_util.h>
-#include <vnet_dev.h>
-#include <vnet.h>
-#include <vnet_forward.h>
-#include <vif.h>
-#include <vnet_ioctl.h>
-#include <sa.h>
-#ifdef __KERNEL__
-#include <sa_algorithm.h>
-#endif
-
-#include "allocate.h"
-#include "iostream.h"
-#include "hash_table.h"
-#include "sys_net.h"
-#include "sys_string.h"
-
-#define MODULE_NAME "VNET"
-#define DEBUG 1
-#undef DEBUG
-#include "debug.h"
-
-/** Default vnet security level.
- */
-int vnet_security_default = SA_AUTH ; //| SA_CONF;
-
-/** The physical vnet. */
-Vnet *vnet_physical = NULL;
-
-/** Table of vnets indexed by id. */
-HashTable *vnet_table = NULL;
-
-rwlock_t vnet_lock = RW_LOCK_UNLOCKED;
-
-#define vnet_table_read_lock(flags) read_lock_irqsave(&vnet_lock, flags)
-#define vnet_table_read_unlock(flags) read_unlock_irqrestore(&vnet_lock, flags)
-#define vnet_table_write_lock(flags) write_lock_irqsave(&vnet_lock, flags)
-#define vnet_table_write_unlock(flags) write_unlock_irqrestore(&vnet_lock, flags)
-
-/** Decrement reference count, freeing if zero.
- *
- * @param info vnet (OK if null)
- */
-void Vnet_decref(Vnet *info){
- if(!info) return;
- if(atomic_dec_and_test(&info->refcount)){
- deallocate(info);
- }
-}
-
-/** Increment reference count.
- *
- * @param info vnet (OK if null)
- */
-void Vnet_incref(Vnet *info){
- if(!info) return;
- atomic_inc(&info->refcount);
-}
-
-void Vnet_print(Vnet *info, IOStream *io)
-{
- char vnetbuf[VNET_ID_BUF];
- char *security;
-
- if(info->security & SA_CONF){
- security = "conf";
- } else if(info->security & SA_AUTH){
- security = "auth";
- } else {
- security = "none";
- }
-
- IOStream_print(io, "(vnet");
- IOStream_print(io, " (id %s)", VnetId_ntoa(&info->vnet, vnetbuf));
- IOStream_print(io, " (vnetif %s)", info->device);
- IOStream_print(io, " (security %s)", security);
- IOStream_print(io, " (header %d)", info->header_n);
- IOStream_print(io, ")");
-}
-
-void vnet_print(IOStream *io)
-{
- HashTable_for_decl(entry);
- Vnet *info;
- unsigned long flags;
-
- vnet_table_read_lock(flags);
- HashTable_for_each(entry, vnet_table){
- info = entry->value;
- Vnet_print(info, io);
- IOStream_print(io, "\n");
- }
- vnet_table_read_unlock(flags);
-}
-
-/** Allocate a vnet, setting reference count to 1.
- *
- * @param info return parameter for vnet
- * @return 0 on success, error code otherwise
- */
-int Vnet_alloc(Vnet **info){
- int err = 0;
- *info = ALLOCATE(Vnet);
- if(*info){
- atomic_set(&(*info)->refcount, 1);
- } else {
- err = -ENOMEM;
- }
- return err;
-}
-
-/** Create the virtual interface for a vnet.
- *
- * @param info vnet
- * @return 0 on success, error code otherwise
- */
-int Vnet_create(Vnet *info){
- int err = 0;
-
- err = vnet_dev_add(info);
- if(err) goto exit;
- err = Vnet_add(info);
- exit:
- return err;
-}
-
-/** Add a vnet to the table under its vnet id.
- *
- * @param info vnet to add
- * @return 0 on success, error code otherwise
- */
-int Vnet_add(Vnet *info){
- int err = 0;
- HTEntry *entry = NULL;
- unsigned long flags;
-
- if(Vnet_lookup(&info->vnet, NULL) == 0){
- //todo: Delete existing vnet info?
- err = -EEXIST;
- goto exit;
- }
- Vnet_incref(info);
- vnet_table_write_lock(flags);
- entry = HashTable_add(vnet_table, &info->vnet, info);
- vnet_table_write_unlock(flags);
- if(!entry){
- err = -ENOMEM;
- vnet_dev_remove(info);
- Vnet_decref(info);
- }
- exit:
- return err;
-}
-
-/** Remove a vnet from the table.
- * Also removes all vifs and varp entries for the vnet.
- *
- * @param vnet id of vnet to remove
- * @return number of vnets removed
- */
-int Vnet_del(VnetId *vnet){
- int count;
- unsigned long flags;
- Vnet *info;
-
- vnet_table_write_lock(flags);
- info = HashTable_get(vnet_table, vnet);
- count = HashTable_remove(vnet_table, vnet);
- vnet_table_write_unlock(flags);
-
- varp_remove_vnet(vnet);
- vif_remove_vnet(vnet);
-
- if(info){
- // Can't do this in the hashtable entry free function because it runs
- // while we hold the vnet table lock, and the vnet tidy up calls
- // vnet_dev_remove(), which calls unregister_netdev(), which schedules.
- vnet_dev_remove(info);
- Vnet_decref(info);
- }
- return count;
-}
-
-/** Lookup a vnet by id.
- * References the vnet on success - the caller must decref.
- *
- * @param vnet vnet id
- * @param pinfo return parameter for vnet (or NULL)
- * @return 0 on sucess, -ENOENT if no vnet found
- */
-int Vnet_lookup(VnetId *vnet, Vnet **pinfo){
- int err = 0;
- unsigned long flags;
- Vnet *info;
-
- vnet_table_read_lock(flags);
- info = HashTable_get(vnet_table, vnet);
- if(info){
- if(pinfo){
- Vnet_incref(info);
- }
- } else {
- err = -ENOENT;
- }
- vnet_table_read_unlock(flags);
-
- if(pinfo){
- *pinfo = (err ? NULL : info);
- }
- return err;
-}
-
-static int vnet_key_equal_fn(void *k1, void *k2){
- return memcmp(k1, k2, sizeof(VnetId)) == 0;
-}
-
-static Hashcode vnet_key_hash_fn(void *k){
- return hash_hvoid(0, k, sizeof(VnetId));
-}
-
-/** Free an entry in the vnet table.
- *
- * @param table containing table
- * @param entry to free
- */
-static void vnet_entry_free_fn(HashTable *table, HTEntry *entry){
- if(!entry) return;
- HTEntry_free(entry);
-}
-
-void vnet_table_free(void){
- HashTable *vnt;
- HashTable_for_decl(entry);
-
- vnt = vnet_table;
- if(!vnt) return;
- vnet_table = NULL;
- HashTable_for_each(entry, vnt){
- Vnet *info = entry->value;
- vnet_dev_remove(info);
- Vnet_decref(info);
- }
- HashTable_free(vnt);
-}
-
-int vnet_table_init(void){
- int err = 0;
- vnet_table = HashTable_new(0);
- if(!vnet_table){
- err = -ENOMEM;
- goto exit;
- }
- vnet_table->key_size = sizeof(VnetId);
- vnet_table->key_equal_fn = vnet_key_equal_fn;
- vnet_table->key_hash_fn = vnet_key_hash_fn;
- vnet_table->entry_free_fn = vnet_entry_free_fn;
-
- err = Vnet_alloc(&vnet_physical);
- if(err) goto exit;
- vnet_physical->vnet = toVnetId(VNET_PHYS);
- vnet_physical->security = 0;
- err = Vnet_add(vnet_physical);
-
- exit:
- if(err){
- vnet_table_free();
- }
- return err;
-}
-
-/** Setup some vnet entries (for testing).
- * Vnet 1 is physical, vnets 2 to 10 are insecure, vnets above
- * 10 are secure.
- *
- * @return 0 on success, negative error code otherwise
- */
-static int vnet_setup(void){
- int err = 0;
- int i, n = 3;
- int security = vnet_security_default;
- uint32_t vnetid;
- Vnet *vnet;
-
- for(i=0; i<n; i++){
- err = Vnet_alloc(&vnet);
- if(err) break;
- vnetid = VNET_VIF + i;
- vnet->vnet = toVnetId(vnetid);
- snprintf(vnet->device, sizeof(vnet->device), "vnif%04x", vnetid);
- vnet->security = (vnetid > 10 ? security : 0);
- err = Vnet_create(vnet);
- Vnet_decref(vnet);
- if(err) break;
- }
- return err;
-}
-
-/** Initialize the vnet table and the physical vnet.
- *
- * @return 0 on success, error code otherwise
- */
-int vnet_init(void){
- int err = 0;
-
- err = vnet_forward_init();
- if(err) goto exit;
- err = vnet_table_init();
- if(err) goto exit;
- err = vnet_setup();
- if(err) goto exit;
- err = vif_init();
- if(err) goto exit;
- err = varp_init();
- exit:
- return err;
-}
-
-void vnet_exit(void){
- varp_exit();
- vif_exit();
- vnet_table_free();
- vnet_forward_exit();
-}
-
-#ifdef __KERNEL__
-inline int _skb_xmit(struct sk_buff *skb, uint32_t saddr){
- int err = 0;
- struct rtable *rt = NULL;
-
- dprintf("> src=%u.%u.%u.%u dst=%u.%u.%u.%u\n",
- NIPQUAD(skb->nh.iph->saddr),
- NIPQUAD(skb->nh.iph->daddr));
- skb->protocol = htons(ETH_P_IP);
- if(saddr){
- skb->nh.iph->saddr = 0;
- }
- err = skb_route(skb, &rt);
- if(err){
- wprintf("> skb_route=%d\n", err);
- wprintf("> dev=%s idx=%d src=%u.%u.%u.%u dst=%u.%u.%u.%u tos=%d\n",
- (skb->dev ? skb->dev->name : "???"),
- (skb->dev ? skb->dev->ifindex : -1),
- NIPQUAD(skb->nh.iph->saddr),
- NIPQUAD(skb->nh.iph->daddr),
- skb->nh.iph->tos);
-
- goto exit;
- }
- dst_release(skb->dst);
- skb->dst = &rt->u.dst;
- if(!skb->dev){
- skb->dev = rt->u.dst.dev;
- }
-
- ip_select_ident(skb->nh.iph, &rt->u.dst, NULL);
-
- if(saddr){
- skb->nh.iph->saddr = saddr;
- } else {
- if(!skb->nh.iph->saddr){
- skb->nh.iph->saddr = rt->rt_src;
- }
- }
-
- ip_send_check(skb->nh.iph);
-
-#if 1
- // Output to skb destination. Will use ip_output(), which fragments.
- // Slightly slower than neigh_compat_output() (marginal - 1%).
- err = dst_output(skb);
-#else
- // Sends direct to device via dev_queue_xmit(). No fragmentation?
- err = neigh_compat_output(skb);
-#endif
-
-#if 0
- if(needs_frags){
- err = ip_fragment(skb, ip_finish_output);
- } else {
- err = ip_finish_output(skb);
- }
-#endif
-
- exit:
- dprintf("< err=%d\n", err);
- return err;
-}
-
-#else
-
-extern int _skb_xmit(struct sk_buff *skb, uint32_t saddr);
-
-#endif
-
-int skb_xmit(struct sk_buff *skb){
- if(MULTICAST(skb->nh.iph->daddr)){
- vnet_forward_send(skb);
- }
- return _skb_xmit(skb, 0);
-}
-
-/** Called when a vif sends a packet to the network.
- * Encapsulates the packet for its vnet and forwards it.
- *
- * @param skb packet
- * @return 0 on success, error code otherwise
- *
- */
-int vnet_skb_send(struct sk_buff *skb, VnetId *vnet){
- VnetId vnet_phys = toVnetId(VNET_PHYS);
- int err = 0;
-
- //dprintf(">\n");
- skb->dev = NULL;
- if(!vnet || VnetId_eq(vnet, &vnet_phys)){
- // No vnet or physical vnet, send direct to the network.
- skb_xmit(skb);
- } else {
- // Update the vif table with the source MAC.
- vif_update(vnet, (Vmac*)eth_hdr(skb)->h_source);
- err = varp_output(skb, vnet);
- }
- //dprintf("< err=%d\n", err);
- return err;
-}
-
-/** Receive an skb for a vnet.
- * We make the skb come out of the vif for the vnet, and
- * let ethernet bridging forward it to related interfaces.
- *
- * The packet must have skb->mac.raw set and skb->data must point
- * after the device (ethernet) header.
- *
- * Return code 1 means we now own the packet - the caller must not free it.
- * Return code < 0 means an error - caller still owns the packet.
- *
- * @param skb packet
- * @param vnet packet vnet
- */
-int vnet_skb_recv(struct sk_buff *skb, Vnet *vnet){
- int err = 1;
-
- if(!vnet->dev){
- // No device for the vnet.
- err = -ENOTCONN;
- goto exit;
- }
- skb->dev = vnet->dev;
- vnet->stats.rx_packets++;
- vnet->stats.rx_bytes += skb->len;
- netif_rx(skb);
- exit:
- return err;
-}
-
-
-/** Check that a context has the correct properties w.r.t. a vnet.
- * The context must be secure if the vnet requires security.
- *
- * @param vnet vnet id
- * @param context context
- * @return 0 on success, error code otherwise
- *
- * @todo Need to check that the sa provides the correct security level.
- */
-int vnet_check_context(VnetId *vnet, SkbContext *context, Vnet **val){
- int err = 0;
- Vnet *info = NULL;
- SAState *sa = NULL;
-
- err = Vnet_lookup(vnet, &info);
- if(err){
- goto exit;
- }
- if(!info->security) goto exit;
- err = -EINVAL;
- if(!context){
- wprintf("> No security context\n");
- goto exit;
- }
- if(context->protocol != IPPROTO_ESP){
- wprintf("> Invalid protocol: wanted %d, got %d\n",
- IPPROTO_ESP, context->protocol);
- goto exit;
- }
- sa = context->data;
- //todo: Check security properties of the SA are correct w.r.t. the vnet.
- //Something like sa->security == info->security;
- err = 0;
- exit:
- *val = info;
- return err;
-}
-
-
-/** Create a tunnel for a vnet to a given address.
- *
- * @param vnet vnet id
- * @param addr destination address
- * @param tunnel return parameter
- * @return 0 on success, error code otherwise
- */
-static int vnet_tunnel_create(VnetId *vnet, VarpAddr *addr, Tunnel **tunnel){
- int err = 0;
- Vnet *info = NULL;
- Tunnel *base = NULL;
- Tunnel *sa_tunnel = NULL;
- Tunnel *eth_tunnel = NULL;
-
- err = Vnet_lookup(vnet, &info);
- if(err) goto exit;
- if(info->security){
- err = sa_tunnel_create(info, addr, base, &sa_tunnel);
- if(err) goto exit;
- base = sa_tunnel;
- }
- err = etherip_tunnel_create(vnet, addr, base, ð_tunnel);
- exit:
- Tunnel_decref(sa_tunnel);
- Vnet_decref(info);
- *tunnel = (err ? NULL : eth_tunnel);
- return err;
-}
-
-/** Lookup a tunnel for a vnet to a given address.
- * Uses an existing tunnel if there is one.
- *
- * @param vnet vnet id
- * @param addr care-of address
- * @param tunnel return parameter
- * @return 0 on success, error code otherwise
- */
-int vnet_tunnel_lookup(VnetId *vnet, VarpAddr *addr, Tunnel **tunnel){
- int err = 0;
- err = Tunnel_lookup(vnet, addr, tunnel);
- if(err){
- err = Tunnel_open(vnet, addr, vnet_tunnel_create, tunnel);
- }
- return err;
-}
-
-/** Send a packet on the appropriate tunnel.
- *
- * @param vnet vnet
- * @param addr tunnel endpoint
- * @param skb packet
- * @return 0 on success, error code otherwise
- */
-int vnet_tunnel_send(VnetId *vnet, VarpAddr *addr, struct sk_buff *skb){
- int err = 0;
- Tunnel *tunnel = NULL;
-
- err = vnet_tunnel_lookup(vnet, addr, &tunnel);
- if(err) {
- char vnetbuf[VNET_ID_BUF];
- char addrbuf[VARP_ADDR_BUF];
- wprintf("No tunnel: skb=%p vnet=%s addr=%s\n",
- skb,
- VnetId_ntoa(vnet, vnetbuf),
- VarpAddr_ntoa(addr, addrbuf));
- goto exit;
- }
- err = Tunnel_send(tunnel, skb);
- Tunnel_decref(tunnel);
- exit:
- return err;
-}
-
-#ifdef __KERNEL__
-
-/** Module parameter for vnet encapsulation. */
-static char *vnet_encaps = NULL;
-
-static void __exit vnet_module_exit(void){
- ProcFS_exit();
- sa_table_exit();
- vnet_exit();
- esp_module_exit();
- etherip_module_exit();
- tunnel_module_exit();
- random_module_exit();
-}
-
-/** Initialize the vnet module.
- * Failure is fatal.
- *
- * @return 0 on success, error code otherwise
- */
-static int __init vnet_module_init(void){
- int err = 0;
-
- if(vnet_encaps && !strcmp(vnet_encaps, "udp")){
- etherip_in_udp = 1;
- }
- dprintf(">\n");
- err = random_module_init();
- if(err) wprintf("> random_module_init err=%d\n", err);
- if(err) goto exit;
- err = tunnel_module_init();
- if(err) wprintf("> tunnel_module_init err=%d\n", err);
- if(err) goto exit;
- err = etherip_module_init();
- if(err) wprintf("> etherip_module_init err=%d\n", err);
- if(err) goto exit;
- err = esp_module_init();
- if(err) wprintf("> esp_module_init err=%d\n", err);
- if(err) goto exit;
- err = vnet_init();
- if(err) wprintf("> vnet_init err=%d\n", err);
- if(err) goto exit;
- sa_algorithm_probe_all();
- err = sa_table_init();
- if(err) wprintf("> sa_table_init err=%d\n", err);
- if(err) goto exit;
- ProcFS_init();
- exit:
- if(err < 0){
- vnet_module_exit();
- wprintf("< err=%d\n", err);
- }
- return err;
-}
-
-module_init(vnet_module_init);
-module_exit(vnet_module_exit);
-MODULE_LICENSE("GPL");
-
-module_param(vnet_encaps, charp, 0644);
-MODULE_PARM_DESC(vnet_encaps, "Vnet encapsulation: etherip or udp.");
-
-#endif
+++ /dev/null
-/*
- * Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-#ifndef __VNET_VNET_H__
-#define __VNET_VNET_H__
-
-#ifdef __KERNEL__
-
-#include <asm/atomic.h>
-#include <linux/skbuff.h>
-#include <linux/if.h>
-#include <linux/netdevice.h>
-
-#else
-
-#include <linux/netdevice.h> // struct net_device_stats
-
-struct net_device {
- char name[IFNAMSIZ];
- char tap[255];
- int tapfd;
-};
-
-#endif
-
-#include <if_varp.h>
-
-struct sk_buff;
-
-struct IOStream;
-struct Vmac;
-struct Vif;
-struct SkbContext;
-struct VarpAddr;
-struct Tunnel;
-struct SAState;
-
-/** Vnet property record. */
-typedef struct Vnet {
- /** Vnet id. */
- struct VnetId vnet;
- /** Reference count. */
- atomic_t refcount;
- /** Security flag. If true the vnet requires ESP. */
- int security;
- char device[IFNAMSIZ];
-
- struct net_device *dev;
-
- /** Max size of the header. */
- int header_n;
- int mtu;
- /** Statistics. */
- struct net_device_stats stats;
- int recursion;
-} Vnet;
-
-extern void vnet_print(struct IOStream *io);
-extern void Vnet_print(struct Vnet *info, struct IOStream *io);
-
-extern int Vnet_lookup(struct VnetId *vnet, struct Vnet **info);
-extern int Vnet_create(struct Vnet *info);
-extern int Vnet_add(struct Vnet *info);
-extern int Vnet_del(struct VnetId *vnet);
-extern void Vnet_incref(struct Vnet *info);
-extern void Vnet_decref(struct Vnet *info);
-extern int Vnet_alloc(struct Vnet **info);
-extern struct Vnet *vnet_physical;
-
-extern int skb_xmit(struct sk_buff *skb);
-extern int skb_xmit_fwd(struct sk_buff *skb);
-extern int vnet_skb_send(struct sk_buff *skb, struct VnetId *vnet);
-extern int vnet_skb_recv(struct sk_buff *skb, struct Vnet *vnet);
-
-extern int vnet_check_context(struct VnetId *vnet, struct SkbContext *context, struct Vnet **vinfo);
-
-extern int vnet_tunnel_open(struct VnetId *vnet, struct VarpAddr *addr, struct Tunnel **tunnel);
-extern int vnet_tunnel_lookup(struct VnetId *vnet, struct VarpAddr *addr, struct Tunnel **tunnel);
-extern int vnet_tunnel_send(struct VnetId *vnet, struct VarpAddr *addr, struct sk_buff *skb);
-
-extern int vnet_init(void);
-
-extern int vnet_sa_security(u32 spi, int protocol, u32 addr);
-extern int vnet_sa_create(u32 spi, int protocol, u32 addr, struct SAState **sa);
-
-enum {
- VNET_PHYS = 1,
- VNET_VIF = 2,
-};
-
-extern struct HashTable *vnet_table;
-
-#endif /* !__VNET_VNET_H__ */
+++ /dev/null
-/*
- * Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/in.h>
-#include <linux/tcp.h>
-#include <linux/udp.h>
-
-#include <net/ip.h>
-#include <net/protocol.h>
-
-#include <linux/if_arp.h>
-#include <linux/in6.h>
-#include <linux/inetdevice.h>
-#include <linux/arcdevice.h>
-#include <linux/if_bridge.h>
-
-#include <etherip.h>
-#include <vnet.h>
-#include <varp.h>
-#include <vif.h>
-#include <vnet_dev.h>
-#include <random.h>
-
-#define MODULE_NAME "VNET"
-#define DEBUG 1
-#undef DEBUG
-#include "debug.h"
-
-#if !defined(CONFIG_BRIDGE) && !defined(CONFIG_BRIDGE_MODULE)
-#warning Should configure Ethernet Bridging in kernel Network Options
-#endif
-
-#ifndef CONFIG_BRIDGE_NETFILTER
-#warning Should configure CONFIG_BRIDGE_NETFILTER in kernel
-#endif
-
-static void vnet_dev_destructor(struct net_device *dev){
- Vnet *vnet = dev->priv;
- if(vnet){
- if(vnet->dev == dev){
- vnet->dev = NULL;
- }
- dev->priv = NULL;
- Vnet_decref(vnet);
- }
- free_netdev(dev);
-}
-
-static struct net_device_stats *vnet_dev_get_stats(struct net_device *dev){
- static struct net_device_stats stats = {};
- Vnet *vnet = dev->priv;
- return (vnet ? &vnet->stats : &stats);
-}
-
-static int vnet_dev_change_mtu(struct net_device *dev, int mtu){
- int err = 0;
- Vnet *vnet = dev->priv;
- if (mtu < 68 || mtu > (vnet ? vnet->mtu : 1500)){
- err = -EINVAL;
- goto exit;
- }
- dev->mtu = mtu;
- exit:
- return err;
-}
-
-/** Remove the net device for a vnet.
- * Safe to call if the vnet or its dev are null.
- *
- * @param vnet vnet
- */
-void vnet_dev_remove(Vnet *vnet){
- if(vnet && vnet->dev){
- iprintf("> Removing vnet device %s\n", vnet->dev->name);
- unregister_netdev(vnet->dev);
- }
-}
-
-static int vnet_dev_open(struct net_device *dev){
- int err = 0;
-
- netif_start_queue(dev);
- return err;
-}
-
-static int vnet_dev_stop(struct net_device *dev){
- int err = 0;
-
- netif_stop_queue(dev);
- return err;
-}
-
-static int vnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev){
- int err = 0;
- Vnet *vnet = dev->priv;
- int len = 0;
-
- if(!skb){
- wprintf("> skb NULL!\n");
- return -EINVAL;
- }
- if(!vnet){
- return -ENOTCONN;
- }
- if(vnet->recursion++) {
- extern void print_skb(const char *msg, int count, struct sk_buff *skb);
- char vnetbuf[VNET_ID_BUF];
-
- vnet->stats.collisions++;
- vnet->stats.tx_errors++;
- wprintf("> recursion! vnet=%s\n", VnetId_ntoa(&vnet->vnet, vnetbuf));
- print_skb("RECURSION", 0, skb);
- varp_print(iostdout);
- kfree_skb(skb);
- goto exit;
- }
- if(!skb->mac.raw){
- skb->mac.raw = skb->data;
- }
- len = skb->len;
- // Must not use skb pointer after vnet_skb_send().
- err = vnet_skb_send(skb, &vnet->vnet);
- if(err < 0){
- vnet->stats.tx_errors++;
- } else {
- vnet->stats.tx_packets++;
- vnet->stats.tx_bytes += len;
- }
- exit:
- vnet->recursion--;
- return 0;
-}
-
-void vnet_dev_set_multicast_list(struct net_device *dev){
-}
-
-#if 0
-static int vnet_dev_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){
- int err = 0;
-
- return err;
-}
-
-void vnet_dev_tx_timeout(struct net_device *dev){
- //dev->trans_start = jiffies;
- //netif_wake_queue(dev);
-}
-
-static int (*eth_hard_header)(struct sk_buff *skb,
- struct net_device *dev, unsigned short type,
- void *daddr, void *saddr, unsigned len) = NULL;
-
-static int vnet_dev_hard_header(struct sk_buff *skb,
- struct net_device *dev, unsigned short type,
- void *daddr, void *saddr, unsigned len){
- int err = 0;
-
- err = eth_hard_header(skb, dev, type, daddr, saddr, len);
- if(err) goto exit;
- skb->mac.raw = skb->data;
- exit:
- return err;
-}
-#endif
-
-int vnet_device_mac(const char *device, unsigned char *mac){
- int err;
- struct net_device *dev;
-
- err = vnet_get_device(device, &dev);
- if(err) goto exit;
- memcpy(mac, dev->dev_addr, ETH_ALEN);
- dev_put(dev);
- exit:
- return err;
-}
-
-void vnet_dev_mac(unsigned char *mac){
- mac[0] = 0xAA;
- mac[1] = 0xFF;
- get_random_bytes(mac + 2, 4);
-}
-
-/** Initial setup of the device for a vnet.
- */
-static void vnet_dev_init(struct net_device *dev){
- ether_setup(dev);
-
-#if 0
- if(!eth_hard_header){
- eth_hard_header = dev->hard_header;
- }
- dev->hard_header = vnet_dev_hard_header;
- //dev->do_ioctl = vnet_dev_do_ioctl;
- //dev->tx_timeout = vnet_dev_tx_timeout;
- //dev->watchdog_timeo = TX_TIMEOUT;
-
-#endif
-
- dev->open = vnet_dev_open;
- dev->stop = vnet_dev_stop;
- dev->destructor = vnet_dev_destructor;
- dev->hard_start_xmit = vnet_dev_hard_start_xmit;
- dev->get_stats = vnet_dev_get_stats;
- dev->change_mtu = vnet_dev_change_mtu;
- dev->set_multicast_list = vnet_dev_set_multicast_list;
-
- dev->flags |= IFF_DEBUG;
- dev->flags |= IFF_PROMISC;
- dev->flags |= IFF_ALLMULTI;
-
- vnet_dev_mac(dev->dev_addr);
-}
-
-/** Complete the setup of the device for a vnet.
- * Associate the device and the vnet and set mtu etc.
- */
-static int vnet_dev_setup(Vnet *vnet, struct net_device *dev){
- int err;
-
- Vnet_incref(vnet);
- dev->priv = vnet;
- vnet->dev = dev;
- dev->hard_header_len += vnet->header_n;
- if(!etherip_in_udp){
- dev->mtu -= vnet->header_n;
- }
- vnet->mtu = dev->mtu;
- iprintf("> Adding vnet device %s\n", dev->name);
- err = register_netdev(dev);
- if(err){
- eprintf("> register_netdev(%s) = %d\n", dev->name, err);
- vnet_dev_destructor(dev);
- }
- return err;
-}
-
-static inline int roundupto(int n, int k){
- return k * ((n + k - 1) / k);
-}
-
-/** Add the interface (net device) for a vnet.
- * Sets the dev field of the vnet on success.
- * Does nothing if the vnet already has an interface.
- *
- * @param vnet vnet
- * @return 0 on success, error code otherwise
- */
-int vnet_dev_add(Vnet *vnet){
- int err = 0;
- struct net_device *dev = NULL;
-
- if(vnet->dev) goto exit;
- vnet->header_n = ETH_HLEN + sizeof(struct iphdr) + sizeof(struct etheriphdr);
- if(etherip_in_udp){
- vnet->header_n += sizeof(struct VnetMsgHdr);
- vnet->header_n += sizeof(struct udphdr);
- }
- vnet->header_n = roundupto(vnet->header_n, 4);
- dev = alloc_netdev(0, vnet->device, vnet_dev_init);
- if(!dev){
- err = -ENOMEM;
- goto exit;
- }
- err = vnet_dev_setup(vnet, dev);
- if(err) goto exit;
- rtnl_lock();
- dev_open(dev);
- rtnl_unlock();
-
- exit:
- return err;
-}
+++ /dev/null
-/*
- * Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-#ifndef _VNET_VNET_DEV_H_
-#define _VNET_VNET_DEV_H_
-
-struct Vnet;
-
-extern int vnet_dev_add(struct Vnet *vnet);
-extern void vnet_dev_remove(struct Vnet *vnet);
-
-#endif
+++ /dev/null
-/*
- * Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-
-#ifdef __KERNEL__
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/version.h>
-#include <linux/errno.h>
-
-#else
-
-#include "sys_kernel.h"
-#include "spinlock.h"
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#endif
-
-#include "vnet.h"
-#include "varp.h"
-#include "vif.h"
-#include "vnet_forward.h"
-#include "sa.h"
-
-#include "iostream.h"
-
-#ifdef __KERNEL__
-#include "kernel_stream.h"
-#else
-#include "file_stream.h"
-#endif
-
-#include "sxpr_util.h"
-#include "vnet_eval.h"
-
-#define MODULE_NAME "VNET"
-#define DEBUG 1
-#undef DEBUG
-#include "debug.h"
-
-/** Create a vnet.
- * It is an error if a vnet with the same id exists.
- *
- * @param vnet vnet id
- * @param device vnet device name
- * @param security security level
- * @return 0 on success, error code otherwise
- */
-static int ctrl_vnet_add(VnetId *vnet, char *device, int security){
- int err = 0;
- Vnet *vnetinfo = NULL;
-
- if(strlen(device) >= IFNAMSIZ){
- err = -EINVAL;
- goto exit;
- }
- if(Vnet_lookup(vnet, NULL) == 0){
- err = -EEXIST;
- goto exit;
- }
- err = Vnet_alloc(&vnetinfo);
- if(err) goto exit;
- vnetinfo->vnet = *vnet;
- vnetinfo->security = security;
- strcpy(vnetinfo->device, device);
- err = Vnet_create(vnetinfo);
- exit:
- if(vnetinfo) Vnet_decref(vnetinfo);
- return err;
-}
-
-/** Create an entry for a vif with the given vnet and vmac.
- *
- * @param vnet vnet id
- * @param vmac mac address
- * @return 0 on success, error code otherwise
- */
-static int ctrl_vif_add(VnetId *vnet, Vmac *vmac){
- int err = 0;
- Vif *vif = NULL;
-
- err = Vnet_lookup(vnet, NULL);
- if(err) goto exit;
- err = vif_create(vnet, vmac, 0, &vif);
- exit:
- if(vif) vif_decref(vif);
- return err;
-}
-
-/** Delete a vif.
- *
- * @param vnet vnet id
- * @param vmac mac address
- * @return 0 on success, error code otherwise
- */
-static int ctrl_vif_del(VnetId *vnet, Vmac *vmac){
- int err = 0;
- Vif *vif = NULL;
-
- err = Vnet_lookup(vnet, NULL);
- if(err) goto exit;
- err = vif_lookup(vnet, vmac, &vif);
- if(err) goto exit;
- vif_remove(vnet, vmac);
- exit:
- if(vif) vif_decref(vif);
- return err;
-}
-
-/** (varp.print)
- */
-static int eval_varp_print(Sxpr exp, IOStream *out, void *data){
- int err = 0;
- vnet_print(out);
- vif_print(out);
- varp_print(out);
- return err;
-}
-
-static int eval_varp_list(Sxpr exp, IOStream *out, void *data){
- int err = 0;
- varp_print(out);
- return err;
-}
-
-/** (varp.mcaddr (addr <addr>))
- */
-static int eval_varp_mcaddr(Sxpr exp, IOStream *out, void *data){
- int err =0;
- Sxpr oaddr = intern("addr");
- uint32_t addr;
-
- err = child_addr(exp, oaddr, &addr);
- if(err < 0) goto exit;
- varp_set_mcast_addr(addr);
- exit:
- return err;
-}
-
-/** (varp.flush)
- */
-static int eval_varp_flush(Sxpr exp, IOStream *out, void *data){
- int err = 0;
- varp_flush();
- return err;
-}
-
-/** (vnet.add (id <id>)
- * [(vnetif <name>)]
- * [(security { none | auth | conf } )]
- * )
- */
-int eval_vnet_add(Sxpr exp, IOStream *out, void *data){
- int err = 0;
- Sxpr oid = intern("id");
- Sxpr osecurity = intern("security");
- Sxpr ovnetif = intern("vnetif");
- Sxpr csecurity;
- VnetId vnet = {};
- char *device = NULL;
- char dev[IFNAMSIZ] = {};
- char *security = NULL;
- int sec;
-
- err = child_vnet(exp, oid, &vnet);
- if(err) goto exit;
- child_string(exp, ovnetif, &device);
- if(!device){
- snprintf(dev, IFNAMSIZ-1, "vnif%04x", ntohs(vnet.u.vnet16[VNETID_SIZE16 - 1]));
- device = dev;
- }
- csecurity = sxpr_child_value(exp, osecurity, intern("none"));
- err = stringof(csecurity, &security);
- if(err) goto exit;
- if(strcmp(security, "none")==0){
- sec = 0;
- } else if(strcmp(security, "auth")==0){
- sec = SA_AUTH;
- } else if(strcmp(security, "conf")==0){
- sec = SA_CONF;
- } else {
- err = -EINVAL;
- goto exit;
- }
- err = ctrl_vnet_add(&vnet, device, sec);
- exit:
- return err;
-}
-
-/** Delete a vnet.
- *
- * (vnet.del (id <id>))
- *
- * @param vnet vnet id
- * @return 0 on success, error code otherwise
- */
-static int eval_vnet_del(Sxpr exp, IOStream *out, void *data){
- int err = 0;
- Sxpr oid = intern("id");
- VnetId vnet = {};
-
- err = child_vnet(exp, oid, &vnet);
- if(err) goto exit;
- err = Vnet_del(&vnet);
- exit:
- return err;
-}
-
-static int eval_vnet_list(Sxpr exp, IOStream *out, void *data){
- int err = 0;
- vnet_print(out);
- return err;
-}
-
-/** (vif.add (vnet <vnet>) (vmac <macaddr>))
- */
-static int eval_vif_add(Sxpr exp, IOStream *out, void *data){
- int err = 0;
- Sxpr ovnet = intern("vnet");
- Sxpr ovmac = intern("vmac");
- VnetId vnet = {};
- Vmac vmac = {};
-
- err = child_vnet(exp, ovnet, &vnet);
- if(err) goto exit;
- err = child_mac(exp, ovmac, vmac.mac);
- if(err) goto exit;
- err = ctrl_vif_add(&vnet, &vmac);
- exit:
- return err;
-}
-
-/** (vif.del (vnet <vnet>) (vmac <macaddr>))
- */
-static int eval_vif_del(Sxpr exp, IOStream *out, void *data){
- int err = 0;
- Sxpr ovnet = intern("vnet");
- Sxpr ovmac = intern("vmac");
- VnetId vnet = {};
- Vmac vmac = {};
-
- err = child_vnet(exp, ovnet, &vnet);
- if(err) goto exit;
- err = child_mac(exp, ovmac, vmac.mac);
- if(err) goto exit;
- err = ctrl_vif_del(&vnet, &vmac);
- exit:
- return err;
-}
-
-static int eval_vif_list(Sxpr exp, IOStream *out, void *data){
- int err = 0;
- vif_print(out);
- return err;
-}
-
-/** Eval a vnet add request.
- *
- * (peer.add (addr <addr>) [(port <port>)])
- *
- * @param exp request
- * @param out output stream
- * @param data data
- * @return 0 on success, error code otherwise
- */
-int eval_peer_add(Sxpr exp, IOStream *out, void *data){
- int err = 0;
- Sxpr oaddr = intern("addr");
- Sxpr oport = intern("port");
- VarpAddr addr = { .family = AF_INET };
- int port;
-
- err = child_addr(exp, oaddr, &addr.u.ip4.s_addr);
- if(err < 0) goto exit;
- err = child_int(exp, oport, &port);
- if(err < 0){
- err = 0;
- port = varp_port;
- }
- if(err) goto exit;
- err = vnet_peer_add(&addr, port);
- exit:
- return err;
-}
-
-/** Eval a peer delete request.
- *
- * (peer.del (addr <addr>))
- *
- * @param vnetd vnetd
- * @param exp request
- * @param out output stream
- * @param data data
- * @return 0 on success, error code otherwise
- */
-static int eval_peer_del(Sxpr exp, IOStream *out, void *data){
- int err = 0;
- Sxpr oaddr = intern("addr");
- VarpAddr addr = { .family = AF_INET };
-
- err = child_addr(exp, oaddr, &addr.u.ip4.s_addr);
- if(err < 0) goto exit;
- err = vnet_peer_del(&addr);
- exit:
- return err;
-}
-
-/** Eval a peer list request.
- *
- * (peer.list)
- *
- * @param exp request
- * @param out output stream
- * @param data data
- * @return 0 on success, error code otherwise
- */
-static int eval_peer_list(Sxpr exp, IOStream *out, void *data){
- int err = 0;
- vnet_peer_print(out);
- return err;
-}
-
-int vnet_eval_defs(SxprEval *defs, Sxpr exp, IOStream *io, void *data){
- int err = 0;
- SxprEval *def;
-
- iprintf("> "); objprint(iostdout, exp, 0); IOStream_print(iostdout, "\n");
- err = -ENOSYS;
- for(def = defs; !NONEP(def->name); def++){
- if(sxpr_elementp(exp, def->name)){
- err = def->fn(exp, io, data);
- break;
- }
- }
- iprintf("< err=%d\n", err);
- return err;
-}
-
-int vnet_eval(Sxpr exp, IOStream *io, void *data){
- SxprEval defs[] = {
- { .name = intern("peer.add"), .fn = eval_peer_add },
- { .name = intern("peer.del"), .fn = eval_peer_del },
- { .name = intern("peer.list"), .fn = eval_peer_list },
- { .name = intern("varp.flush"), .fn = eval_varp_flush },
- { .name = intern("varp.list"), .fn = eval_varp_list },
- { .name = intern("varp.mcaddr"), .fn = eval_varp_mcaddr },
- { .name = intern("varp.print"), .fn = eval_varp_print },
- { .name = intern("vif.add"), .fn = eval_vif_add },
- { .name = intern("vif.del"), .fn = eval_vif_del },
- { .name = intern("vif.list"), .fn = eval_vif_list },
- { .name = intern("vnet.add"), .fn = eval_vnet_add },
- { .name = intern("vnet.del"), .fn = eval_vnet_del },
- { .name = intern("vnet.list"), .fn = eval_vnet_list },
- { .name = ONONE, .fn = NULL } };
- return vnet_eval_defs(defs, exp, io, data);
-}
+++ /dev/null
-/*
- * Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-#ifndef _VNET_EVAL_H_
-#define _VNET_EVAL_H_
-
-#include "sxpr.h"
-struct IOStream;
-
-typedef struct SxprEval {
- Sxpr name;
- int (*fn)(Sxpr, struct IOStream *, void *data);
-} SxprEval;
-
-extern int eval_peer_add(Sxpr exp, struct IOStream *out, void *data);
-extern int eval_vnet_add(Sxpr exp, struct IOStream *out, void *data);
-extern int vnet_eval_defs(SxprEval *defs, Sxpr exp, struct IOStream *out, void *data);
-extern int vnet_eval(Sxpr exp, struct IOStream *out, void *data);
-
-#endif /* ! _VNET_EVAL_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2005, 2006 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-#ifdef __KERNEL__
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <linux/version.h>
-#include <linux/spinlock.h>
-
-#include <linux/skbuff.h>
-#include <linux/net.h>
-#include <linux/netdevice.h>
-#include <linux/in.h>
-#include <linux/inet.h>
-#include <linux/netfilter_bridge.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/udp.h>
-
-#include <net/ip.h>
-#include <net/protocol.h>
-#include <net/route.h>
-#include <net/checksum.h>
-
-#else
-
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include "sys_kernel.h"
-#include "spinlock.h"
-#include "skbuff.h"
-#include <linux/ip.h>
-#include <linux/udp.h>
-
-#endif
-
-#include <varp.h>
-#include <if_varp.h>
-#include <varp.h>
-#include <skb_util.h>
-#include <skb_context.h>
-
-#include "allocate.h"
-#include "iostream.h"
-#include "hash_table.h"
-#include "vnet_forward.h"
-
-#define MODULE_NAME "VNET"
-#define DEBUG 1
-#undef DEBUG
-#include "debug.h"
-
-extern int _skb_xmit(struct sk_buff *skb, uint32_t saddr);
-
-typedef struct VnetPeer {
- struct VarpAddr addr;
- uint16_t port;
- atomic_t refcount;
- int tx_packets;
- int rx_packets;
-} VnetPeer;
-
-static HashTable *vnet_peer_table = NULL;
-static rwlock_t vnet_peer_table_lock = RW_LOCK_UNLOCKED;
-
-#define vnet_peer_read_lock(flags) read_lock_irqsave(&vnet_peer_table_lock, (flags))
-#define vnet_peer_read_unlock(flags) read_unlock_irqrestore(&vnet_peer_table_lock, (flags))
-#define vnet_peer_write_lock(flags) write_lock_irqsave(&vnet_peer_table_lock, (flags))
-#define vnet_peer_write_unlock(flags) write_unlock_irqrestore(&vnet_peer_table_lock, (flags))
-
-static void VnetPeer_decref(VnetPeer *peer){
- if(!peer) return;
- if(atomic_dec_and_test(&peer->refcount)){
- kfree(peer);
- }
-}
-
-static void VnetPeer_incref(VnetPeer *peer){
- if(!peer) return;
- atomic_inc(&peer->refcount);
-}
-
-static void VnetPeer_print(VnetPeer *peer, IOStream *io){
- char addrbuf[VARP_ADDR_BUF];
-
- IOStream_print(io, "(vnet_peer\n");
- IOStream_print(io, " (addr %s)\n", VarpAddr_ntoa(&peer->addr, addrbuf));
- IOStream_print(io, " (port %d)\n", htons(peer->port));
- IOStream_print(io, " (tx_packets %d)\n", peer->tx_packets);
- IOStream_print(io, " (rx_packets %d)\n", peer->tx_packets);
- IOStream_print(io, ")\n");
-}
-
-static int VnetPeer_forward(VnetPeer *peer, struct sk_buff *fwdskb){
- int err = 0;
- const int ip_n = sizeof(struct iphdr);
- const int udp_n = sizeof(struct udphdr);
- const int vnet_n = sizeof(struct VnetMsgHdr);
- int head_n = 16 + ip_n + udp_n + vnet_n;
- int push_n = 0;
- struct sk_buff *skb = NULL;
- struct VnetMsgHdr *vhdr;
- uint32_t saddr = 0;
- uint16_t sport = varp_port;
- uint32_t daddr = peer->addr.u.ip4.s_addr;
- uint16_t dport = varp_port;
-
- if(!fwdskb) goto exit;
- if(daddr == fwdskb->nh.iph->saddr){
- // Don't forward if the skb src addr is the peer addr.
- dprintf("> Forward loop on " IPFMT "\n", NIPQUAD(daddr));
- goto exit;
- }
- // On entry fwdskb->data should be at fwdskb->nh.raw (adjust if not).
- // Also fwdskb->h.raw and fwdskb->nh.raw are set.
- if(fwdskb->data > fwdskb->nh.raw){
- push_n = fwdskb->data - fwdskb->nh.raw;
- head_n += push_n;
- }
- // If has headroom, copies header (which incs ref on dst),
- // otherwise only clones header, which does not inc ref on dst.
- skb = skb_realloc_headroom(fwdskb, head_n);
- //skb = skb_copy_expand(fwdskb, head_n, 0, GFP_ATOMIC);
- if(!skb){
- err = -ENOMEM;
- goto exit;
- }
-
- if(push_n){
- skb_push(skb, push_n);
- }
-
-#ifdef DEBUG
- printk("\nOriginal packet:\n");
- print_iphdr(__FUNCTION__, skb);
- skb_print_bits(__FUNCTION__, skb, 0, skb->len);
-#endif
-
- skb->mac.raw = NULL;
- vhdr = (void*)skb_push(skb, vnet_n);
- vhdr->id = htons(VFWD_ID);
- vhdr->opcode = 0;
-
- // Setup the UDP header.
- skb->h.raw = skb_push(skb, udp_n);
- skb->h.uh->source = sport; // Source port.
- skb->h.uh->dest = dport; // Destination port.
- skb->h.uh->len = htons(skb->len); // Total packet length (bytes).
- skb->h.uh->check = 0;
-
- // Setup the IP header.
- skb->nh.raw = skb_push(skb, ip_n);
- skb->nh.iph->version = 4; // Standard version.
- skb->nh.iph->ihl = ip_n / 4; // IP header length (32-bit words).
- skb->nh.iph->tos = 0; // No special type-of-service.
- skb->nh.iph->tot_len = htons(skb->len); // Total packet length (bytes).
- skb->nh.iph->id = 0; // No flow id.
- skb->nh.iph->protocol = IPPROTO_UDP; // IP protocol number.
- skb->nh.iph->frag_off = 0;
- skb->nh.iph->ttl = 64; // Linux default time-to-live.
- skb->nh.iph->saddr = saddr; // Source address.
- skb->nh.iph->daddr = daddr; // Destination address.
- skb->nh.iph->check = 0;
-
-#ifdef DEBUG
- printk("\nWrapped packet:\n");
- print_iphdr(__FUNCTION__, skb);
- print_udphdr(__FUNCTION__, skb);
- skb_print_bits(__FUNCTION__, skb, 0, skb->len);
-#endif
-
- err = _skb_xmit(skb, saddr);
- peer->tx_packets++;
-
- exit:
- if(err < 0) kfree_skb(skb);
- return err;
-}
-
-int vnet_peer_get(VarpAddr *addr, VnetPeer **peer){
- unsigned long flags;
-
- vnet_peer_read_lock(flags);
- *peer = HashTable_get(vnet_peer_table, addr);
- VnetPeer_incref(*peer);
- vnet_peer_read_unlock(flags);
- return (*peer ? 0 : -ENOENT);
-}
-
-int vnet_peer_add(VarpAddr *addr, uint16_t port){
- int err = 0;
- unsigned long flags;
- VnetPeer *peer;
-
- vnet_peer_write_lock(flags);
- peer = HashTable_get(vnet_peer_table, addr);
- if(peer){
- VnetPeer_incref(peer);
- goto exit;
- }
- peer = ALLOCATE(VnetPeer);
- if(!peer){
- err = -ENOMEM;
- goto exit;
- }
- peer->addr = *addr;
- peer->port = port;
- VnetPeer_incref(peer);
- if(!HashTable_add(vnet_peer_table, &peer->addr, peer)){
- VnetPeer_decref(peer);
- err = -ENOMEM;
- }
- exit:
- vnet_peer_write_unlock(flags);
- return err;
-}
-
-int vnet_peer_del(VarpAddr *addr){
- int ret = 0;
- unsigned long flags;
-
- vnet_peer_write_lock(flags);
- ret = HashTable_remove(vnet_peer_table, addr);
- vnet_peer_write_unlock(flags);
- return ret;
-}
-
-void vnet_peer_print(IOStream *io){
- HashTable_for_decl(entry);
- unsigned long flags;
-
- if(!vnet_peer_table) return;
- vnet_peer_read_lock(flags);
- HashTable_for_each(entry, vnet_peer_table){
- VnetPeer *peer = entry->value;
- VnetPeer_print(peer, io);
- }
- vnet_peer_read_unlock(flags);
-}
-
-int vnet_forward_send(struct sk_buff *skb){
- int err = 0;
- unsigned long flags;
- HashTable_for_decl(entry);
- int count = 0;
-
- if(!vnet_peer_table){
- goto exit;
- }
- vnet_peer_read_lock(flags);
- HashTable_for_each(entry, vnet_peer_table){
- VnetPeer *peer = entry->value;
- VnetPeer_forward(peer, skb);
- count++;
- }
- vnet_peer_read_unlock(flags);
- exit:
- return err;
-}
-
-int vnet_forward_recv(struct sk_buff *skb){
- int err = 0;
- VarpAddr addr = { .family = AF_INET };
- VnetPeer *peer = NULL;
- unsigned char eth[ETH_HLEN] = {};
- struct sk_buff *recvskb;
-
- if(!vnet_peer_table){
- dprintf("> no table\n");
- return -ENOSYS;
- }
- // On entry mac.raw, h.raw, nh.raw are set.
- // skb->data points after the fwd vnet header, at the complete
- // forwarded packet (which has IP hdr, no eth hdr).
-
- // Save the eth hdr and source addr (peer).
- memcpy(eth, skb->mac.raw, ETH_HLEN);
- addr.u.ip4.s_addr = skb->nh.iph->saddr;
- err = vnet_peer_get(&addr, &peer);
- if(err){
- wprintf("> no peer for " IPFMT "\n", NIPQUAD(skb->nh.iph->saddr));
- goto exit;
- }
- peer->rx_packets++;
- skb->mac.raw = NULL;
- skb->nh.raw = skb->data;
- skb->h.raw = skb->data + sizeof(struct iphdr);
- if(!skb->nh.iph->saddr){
- skb->nh.iph->saddr = addr.u.ip4.s_addr;
- }
-#ifdef __KERNEL__
- // Fix IP options, checksum, skb dst, netfilter state.
- memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
- skb->dev = NULL;
- dst_release(skb->dst);
- skb->dst = NULL;
- nf_reset(skb);
-#endif // __KERNEL__
-
- skb->mac.raw = skb->nh.raw - ETH_HLEN;
- memcpy(skb->mac.raw, eth, ETH_HLEN);
-
- // Map destination mcast addresses to our mcast address.
- if(MULTICAST(skb->nh.iph->daddr)){
- skb->nh.iph->daddr = varp_mcast_addr;
- //xmit does this: ip_eth_mc_map(varp_mcast_addr, eth_hdr(skb)->h_dest);
- }
-
- // Handle (a copy of) it ourselves, because
- // if it is looped-back by xmit it will be ignored.
- recvskb = alloc_skb(skb->len, GFP_ATOMIC);
- if(recvskb){
- recvskb->protocol = htons(ETH_P_IP);
-
- recvskb->nh.raw = skb_put(recvskb, skb->len);
- recvskb->h.raw = recvskb->data + sizeof(struct iphdr);
- skb_copy_bits(skb, 0, recvskb->data, skb->len);
-
- // Data points at the unwrapped iphdr, but varp_handle_message()
- // expects it to point at the udphdr, so pull.
- skb_pull_vn(recvskb, sizeof(struct iphdr));
- if(varp_handle_message(recvskb) <= 0){
- kfree_skb(recvskb);
- }
- }
- err = _skb_xmit(skb, skb->nh.iph->saddr);
- if(err >= 0) err = 1;
- exit:
- return err;
-}
-
-/** Hash function for keys in the peer table.
- */
-static Hashcode peer_key_hash_fn(void *k){
- return hash_hvoid(0, k, sizeof(struct VarpAddr));
-}
-
-/** Equality function for keys in the peer table.
- */
-static int peer_key_equal_fn(void *k1, void *k2){
- return memcmp(k1, k2, sizeof(struct VarpAddr)) == 0;
-}
-
-static void peer_entry_free_fn(HashTable *table, HTEntry *entry){
- if(!entry) return;
- VnetPeer_decref((VnetPeer*)entry->value);
- HTEntry_free(entry);
-}
-
-int vnet_forward_init(void){
- int err = 0;
- if(vnet_peer_table) goto exit;
- vnet_peer_table = HashTable_new(0);
- if(!vnet_peer_table){
- err = -ENOMEM;
- goto exit;
- }
- vnet_peer_table->key_size = sizeof(struct VarpAddr);
- vnet_peer_table->key_equal_fn = peer_key_equal_fn;
- vnet_peer_table->key_hash_fn = peer_key_hash_fn;
- vnet_peer_table->entry_free_fn = peer_entry_free_fn;
- exit:
- return err;
-}
-
-void vnet_forward_exit(void){
- HashTable_free(vnet_peer_table);
- vnet_peer_table = NULL;
-}
+++ /dev/null
-/*
- * Copyright (C) 2005, 2006 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-#ifndef _VNET_FORWARD_H_
-#define _VNET_FORWARD_H_
-
-#include <if_varp.h>
-
-struct sk_buff;
-struct IOStream;
-
-extern int vnet_peer_add(struct VarpAddr *addr, uint16_t port);
-extern int vnet_peer_del(struct VarpAddr *addr);
-extern void vnet_peer_print(struct IOStream *io);
-
-extern int vnet_forward_send(struct sk_buff *skb);
-extern int vnet_forward_recv(struct sk_buff *skb);
-extern int vnet_forward_init(void);
-extern void vnet_forward_exit(void);
-
-#endif /* _VNET_FORWARD_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-#include <linux/config.h>
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-
-#include <asm/uaccess.h>
-
-#include <linux/slab.h>
-
-#include <linux/proc_fs.h>
-#include <linux/string.h>
-
-#include <linux/net.h>
-#include <linux/in.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-
-#include <sa.h>
-#include "vif.h"
-#include "vnet.h"
-#include "varp.h"
-#include "vnet_dev.h"
-#include "vnet_eval.h"
-#include "vnet_forward.h"
-
-#include "iostream.h"
-#include "kernel_stream.h"
-#include "mem_stream.h"
-#include "sys_string.h"
-#include "sys_net.h"
-#include "sxpr_parser.h"
-
-#define MODULE_NAME "VNET"
-#define DEBUG 1
-#undef DEBUG
-#include "debug.h"
-
-/** @file
- *
- * Kernel interface to files in /proc.
- * todo: Add a sysfs interface using kobject.
- */
-
-#define PROC_ROOT "/proc/"
-#define PROC_ROOT_LEN 6
-#define MODULE_ROOT PROC_ROOT "vnet"
-
-enum {
- VNET_POLICY = 1,
- VNET_VNETS,
- VNET_VIFS,
- VNET_VARP,
- VNET_PEERS,
-};
-
-typedef struct proc_dir_entry ProcEntry;
-typedef struct inode Inode;
-typedef struct file File;
-
-static int proc_open_fn(struct inode *inode, File *file);
-//static ssize_t proc_read_fn(File *file, char *buffer, size_t count, loff_t *offset);
-//static ssize_t proc_write_fn(File *file, const char *buffer, size_t count, loff_t *offset) ;
-//static int proc_flush_fn(File *file);
-static loff_t proc_lseek_fn(File * file, loff_t offset, int orig);
-static int proc_ioctl_fn(struct inode *inode, File *file, unsigned opcode, unsigned long arg);
-//static int proc_release_fn(struct inode *inode, File *file);
-
-static int ProcEntry_has_name(ProcEntry *entry, const char *name, int namelen){
- dprintf("> name=%.*s entry=%.*s\n", namelen, name, entry->namelen, entry->name);
- if(!entry || !entry->low_ino) return FALSE;
- if(entry->namelen != namelen) return FALSE;
- return memcmp(name, entry->name, namelen) == 0;
-}
-
-// Set f->f_error on error?
-// Does interface stop r/w on first error?
-// Is release called after an error?
-//
-
-static int proc_get_parser(File *file, Parser **val){
- int err = 0;
- Parser *parser = NULL;
- parser = file->private_data;
- if(!parser){
- parser = Parser_new();
- if(!parser){
- err = -ENOMEM;
- goto exit;
- }
- file->private_data = parser;
- }
- exit:
- *val = parser;
- return err;
-}
-
-static int proc_open_fn(Inode *inode, File *file){
- // User open.
- // Return errcode or 0 on success.
- // Can stuff data in file->private_data (void*).
- // Get entry from
- //ProcEntry *entry = (ProcEntry *)inode->u.generic_ip;
- //file->private_data = NULL;
- //file->f_dentry->d_ino is inode.
- // Check for user privilege - deny otherwise.
- // -EACCESS
- int err = 0;
- dprintf(">\n");
- file->private_data = NULL;
- return err;
-}
-
-static ssize_t proc_read_fn(File *file, char *buffer,
- size_t count, loff_t *offset){
- // User read.
- // Copy data to user buffer, increment offset by count, return count.
- dprintf(">\n");
- count = 0;
- //if(copy_to_user(buffer, data, count)){
- // return -EFAULT;
- //}
- //*offset += count;
- return count;
-}
-
-#if 0
-static ssize_t proc_write_fn(File *file, const char *buffer,
- size_t count, loff_t *offset) {
- return -EINVAL;
-}
-#endif
-
-
-#if 0
-static int proc_flush_fn(File *file){
- // User flush.
- int writing = (file->f_flags & O_ACCMODE) == O_WRONLY;
- int f_count = atomic_read(&file->f_count);
- if (writing && f_count == 1) {
- ProcEntry *pentry = (ProcEntry *)file->f_dentry->d_inode->u.generic_ip;
- // ...
- }
- return retval;
-}
-#endif
-
-#ifndef SEEK_SET
-enum {
- /** Offset from start. */
- SEEK_SET = 0,
- /** Offset from current position. */
- SEEK_CUR = 1,
- /** Offset from size of file. */
- SEEK_END = 2
-};
-#endif /* !SEEK_SET */
-
-static loff_t proc_lseek_fn(File * file, loff_t offset, int from){
- // User lseek.
- dprintf(">\n");
- switch(from){
- case SEEK_SET:
- break;
- case SEEK_CUR:
- offset += file->f_pos;
- break;
- case SEEK_END:
- return -EINVAL;
- default:
- return -EINVAL;
- }
- if(offset < 0) return -EINVAL;
- file->f_pos = offset;
- return offset;
-}
-
-static int proc_ioctl_fn(Inode *inode, File *file,
- unsigned opcode, unsigned long arg){
- // User ioctl.
- dprintf(">\n");
- return 0;
-}
-
-static ssize_t proc_policy_write_fn(File *file, const char *buffer,
- size_t count, loff_t *offset) {
- // User write.
- // Copy data into kernel space from buffer.
- // Increment offset by count, return count (or code).
- int err = 0;
- char *data = NULL;
- Parser *parser = NULL;
-
- err = proc_get_parser(file, &parser);
- if(err) goto exit;
- data = allocate(count);
- if(!data){
- err = -ENOMEM;
- goto exit;
- }
- err = copy_from_user(data, buffer, count);
- if(err) goto exit;
- *offset += count;
- err = Parser_input(parser, data, count);
- exit:
- deallocate(data);
- err = (err < 0 ? err : count);
- return err;
-}
-
-static int proc_policy_release_fn(Inode *inode, File *file){
- // User close.
- // Cleanup file->private_data, return errcode.
- int err = 0;
- Parser *parser = NULL;
- Sxpr obj, l;
-
- dprintf(">\n");
- err = proc_get_parser(file, &parser);
- if(err) goto exit;
- err = Parser_input(parser, NULL, 0);
- if(err) goto exit;
- obj = parser->val;
- for(l = obj; CONSP(l); l = CDR(l)){
- err = vnet_eval(CAR(l), iostdout, NULL);
- if(err) break;
- }
- exit:
- Parser_free(parser);
- file->private_data = NULL;
- dprintf("< err=%d\n", err);
- return err;
-}
-
-static int proc_io_open(Inode *inode, File *file, IOStream **val){
- int err = 0;
- IOStream *io = mem_stream_new();
- if(!io){
- err = -ENOMEM;
- goto exit;
- }
- file->private_data = io;
- exit:
- *val = (err ? NULL: io);
- return err;
-}
-
-static ssize_t proc_io_read_fn(File *file, char *buffer,
- size_t count, loff_t *offset){
- // User read.
- // Copy data to user buffer, increment offset by count, return count.
- int err = 0;
- char kbuf[1024] = {};
- int kbuf_n = sizeof(kbuf);
- int k, n = 0;
- char *ubuf = buffer;
- IOStream *io = file->private_data;
-
- dprintf(">\n");
- if(!io) goto exit;
- while(n < count){
- k = count - n;
- if(k > kbuf_n){
- k = kbuf_n;
- }
- k = IOStream_read(io, kbuf, k);
- if(k <= 0) break;
- if(copy_to_user(ubuf, kbuf, k)){
- err = -EFAULT;
- goto exit;
- }
- n += k;
- ubuf += k;
- }
- *offset += n;
- exit:
- return (err ? err : n);
-}
-
-static int proc_io_release_fn(Inode *inode, File *file){
- // User close.
- int err = 0;
- IOStream *io = file->private_data;
- if(io) IOStream_close(io);
- dprintf("< err=%d\n", err);
- return err;
-}
-
-static int proc_vnets_open_fn(Inode *inode, File *file){
- int err = 0;
- IOStream *io;
- if(proc_io_open(inode, file, &io)) goto exit;
- vnet_print(io);
- exit:
- return err;
-}
-
-static int proc_vifs_open_fn(Inode *inode, File *file){
- int err = 0;
- IOStream *io;
- if(proc_io_open(inode, file, &io)) goto exit;
- vif_print(io);
- exit:
- return err;
-}
-
-static int proc_peers_open_fn(Inode *inode, File *file){
- int err = 0;
- IOStream *io;
- if(proc_io_open(inode, file, &io)) goto exit;
- vnet_peer_print(io);
- exit:
- return err;
-}
-
-static int proc_varp_open_fn(Inode *inode, File *file){
- int err = 0;
- IOStream *io;
- if(proc_io_open(inode, file, &io)) goto exit;
- varp_print(io);
- exit:
- return err;
-}
-
-static struct file_operations proc_policy_ops = {
- open: proc_open_fn,
- read: proc_read_fn,
- write: proc_policy_write_fn,
- //flush: proc_flush_fn,
- llseek: proc_lseek_fn,
- ioctl: proc_ioctl_fn,
- release: proc_policy_release_fn,
-};
-
-static struct file_operations proc_vnets_ops = {
- open: proc_vnets_open_fn,
- read: proc_io_read_fn,
- release: proc_io_release_fn,
-};
-
-static struct file_operations proc_vifs_ops = {
- open: proc_vifs_open_fn,
- read: proc_io_read_fn,
- release: proc_io_release_fn,
-};
-
-static struct file_operations proc_peers_ops = {
- open: proc_peers_open_fn,
- read: proc_io_read_fn,
- release: proc_io_release_fn,
-};
-
-static struct file_operations proc_varp_ops = {
- open: proc_varp_open_fn,
- read: proc_io_read_fn,
- release: proc_io_release_fn,
-};
-
-static ProcEntry *proc_fs_root = &proc_root;
-
-static int proc_path_init(const char *path, const char **rest){
- int err = 0;
-
- if(!path){
- err = -EINVAL;
- goto exit;
- }
- if(*path == '/'){
- if(strncmp(PROC_ROOT, path, PROC_ROOT_LEN)){
- err = -EINVAL;
- } else {
- path += PROC_ROOT_LEN;
- }
- }
- exit:
- *rest = path;
- return err;
-}
-
-/** Parse a path relative to `dir'. If dir is null or the proc root
- * the path is relative to "/proc/", and the leading "/proc/" may be
- * supplied.
- *
- */
-static ProcEntry * ProcFS_lookup(const char *path, ProcEntry *dir){
- const char *pathptr = path, *next = NULL;
- ProcEntry *entry, *result = NULL;
- int pathlen;
-
- if(dir && (dir != proc_fs_root)){
- entry = dir;
- } else {
- if(proc_path_init(path, &pathptr)) goto exit;
- entry = proc_fs_root;
- }
- if(!pathptr || !*pathptr) goto exit;
- while(1){
- next = strchr(pathptr, '/');
- pathlen = (next ? next - pathptr : strlen(pathptr));
- for(entry = entry->subdir; entry ; entry = entry->next) {
- if(ProcEntry_has_name(entry, pathptr, pathlen)) break;
- }
- if (!entry) break;
- if(!next){
- result = entry;
- break;
- }
- pathptr = next + 1;
- }
- exit:
- return result;
-}
-
-static ProcEntry *ProcFS_register(const char *name, ProcEntry *dir,
- int val, struct file_operations *ops){
- mode_t mode = 0;
- ProcEntry *entry;
-
- entry = create_proc_entry(name, mode, dir);
- if(entry){
- entry->proc_fops = ops;
- entry->data = (void*)val; // Whatever data we need.
- }
- return entry;
-}
-
-static ProcEntry *ProcFS_mkdir(const char *name, ProcEntry *parent){
- ProcEntry *entry = NULL;
- entry = ProcFS_lookup(name, parent);
- if(!entry){
- const char *path;
- if(proc_path_init(name, &path)) goto exit;
- entry = proc_mkdir(path, parent);
- }
- exit:
- return entry;
-}
-
-static void ProcFS_remove(const char *name, ProcEntry *parent){
- remove_proc_entry(name, parent);
-}
-
-static void ProcFS_rmrec_entry(ProcEntry *entry){
- if(entry){
- // Don't want to remove /proc itself!
- if(entry->parent == entry) return;
- while(entry->subdir){
- ProcFS_rmrec_entry(entry->subdir);
- }
- dprintf("> remove %s\n", entry->name);
- ProcFS_remove(entry->name, entry->parent);
- }
-}
-
-static void ProcFS_rmrec(const char *name, ProcEntry *parent){
- ProcEntry *entry;
-
- dprintf("> name=%s\n", name);
- entry = ProcFS_lookup(name, parent);
- if(entry){
- ProcFS_rmrec_entry(entry);
- }
- dprintf("<\n");
-}
-
-void __init ProcFS_init(void){
- ProcEntry *root_entry;
- ProcEntry *policy_entry;
- ProcEntry *vnets_entry;
- ProcEntry *vifs_entry;
- ProcEntry *peers_entry;
- ProcEntry *varp_entry;
-
- dprintf(">\n");
- root_entry = ProcFS_mkdir(MODULE_ROOT, NULL);
- if(!root_entry) goto exit;
- policy_entry = ProcFS_register("policy", root_entry, VNET_POLICY, &proc_policy_ops);
- vnets_entry = ProcFS_register("vnets", root_entry, VNET_VNETS, &proc_vnets_ops);
- vifs_entry = ProcFS_register("vifs", root_entry, VNET_VIFS, &proc_vifs_ops);
- peers_entry = ProcFS_register("peers", root_entry, VNET_PEERS, &proc_peers_ops);
- varp_entry = ProcFS_register("varp", root_entry, VNET_VARP, &proc_varp_ops);
- exit:
- dprintf("<\n");
-}
-
-void __exit ProcFS_exit(void){
- dprintf(">\n");
- ProcFS_rmrec(MODULE_ROOT, NULL);
- dprintf("<\n");
-}
+++ /dev/null
-/*
- * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
- *
- * 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-1307 USA
- *
- */
-#ifndef _VNET_VNET_IOCTL_H_
-#define _VNET_VNET_IOCTL_H_
-
-extern void ProcFS_init(void);
-extern void ProcFS_exit(void);
-
-#endif /* ! _VNET_VNET_IOCTL_H_ */
+++ /dev/null
-# -*- mode: Makefile; -*-
-#----------------------------------------------------------------------------
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>.
-#
-# This library is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as
-# published by the Free Software Foundation; either version 2.1 of the
-# License, or (at your option) any later version. This library 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 Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this library; if not, write to the Free Software Foundation,
-# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#----------------------------------------------------------------------------
-
-VNET_ROOT ?= $(shell cd .. && pwd)
-include $(VNET_ROOT)/Make.env
-
-.PHONY: all
-all: vnetd
-
-#----------------------------------------------------------------------------
-
-# Comment out when outside xen.
-#include $(XEN_ROOT)/tools/Rules.mk
-
-INSTALL_PROG ?= $(INSTALL) -m0755 -p
-
-INCLUDES += -I$(LIBXUTIL_DIR)
-INCLUDES += -I$(VNET_MODULE_DIR)
-INCLUDES += -I$(shell pwd)
-
-#----------------------------------------------------------------------------
-# GC.
-
-INCLUDES += -I$(GC_INCLUDE)
-#LIBS += -L$(GC_LIB_DIR)
-CPPFLAGS += -D USE_GC
-
-# Sometimes linux/atomic.h is not #ifdef __KERNEL__.
-CPPFLAGS += -D __ARCH_I386_ATOMIC__
-
-#----------------------------------------------------------------------------
-CFLAGS += -O3
-CFLAGS += $(INCLUDES) $(LIBS)
-
-LDFLAGS += $(LIBS)
-
-# Dependencies. Gcc generates them for us.
-CFLAGS += -Wp,-MD,.$(@F).d
-PROG_DEP = .*.d
-
-vpath %.c $(LIBXUTIL_DIR)
-vpath %.c $(VNET_MODULE_DIR)
-
-IPATHS:=$(INCLUDES:-I=)
-vpath %.h $(IPATHS)
-
-#----------------------------------------------------------------------------
-VNETD_SRC:=
-VNETD_SRC+= connection.c
-VNETD_SRC+= select.c
-VNETD_SRC+= timer.c
-VNETD_SRC+= spinlock.c
-VNETD_SRC+= skbuff.c
-VNETD_SRC+= vnetd.c
-
-VNETD_SRC+= skb_util.c
-VNETD_SRC+= sxpr_util.c
-VNETD_SRC+= timer_util.c
-VNETD_SRC+= etherip.c
-VNETD_SRC+= vnet.c
-VNETD_SRC+= vnet_eval.c
-VNETD_SRC+= vnet_forward.c
-VNETD_SRC+= vif.c
-VNETD_SRC+= tunnel.c
-VNETD_SRC+= sa.c
-VNETD_SRC+= varp.c
-
-#----------------------------------------------------------------------------
-LIB_SRC:=
-LIB_SRC+= allocate.c
-LIB_SRC+= enum.c
-LIB_SRC+= file_stream.c
-LIB_SRC+= hash_table.c
-LIB_SRC+= iostream.c
-LIB_SRC+= lexis.c
-LIB_SRC+= socket_stream.c
-LIB_SRC+= string_stream.c
-LIB_SRC+= sxpr.c
-LIB_SRC+= sxpr_parser.c
-LIB_SRC+= sys_net.c
-LIB_SRC+= sys_string.c
-LIB_SRC+= util.c
-
-VNETD_SRC+=$(LIB_SRC)
-
-VNETD_OBJ := $(VNETD_SRC:.c=.o)
-
-#VNETD_LIBS:= $(GC_LIB_SO)
-#VNETD_LIBS:= -lgc
-VNETD_LIBS:= $(GC_LIB_A)
-
-vnetd: $(VNETD_OBJ)
- $(CC) $(CFLAGS) -o $@ $^ $(VNETD_LIBS) -ldl -lpthread
-
-.PHONY: install
-install: vnetd
- $(INSTALL_DIR) $(DESTDIR)$(SBINDIR)
- $(INSTALL_PROG) vnetd $(DESTDIR)$(SBINDIR)
-
-.PHONY: clean
-clean:
- -@$(RM) *.a *.o *~
- -@$(RM) vnetd
- -@$(RM) $(PROG_DEP)
-
--include $(PROG_DEP)
+++ /dev/null
-/*
- * Copyright (C) 2003 - 2004 Mike Wray <mike.wray@hp.com>.
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include "allocate.h"
-#include "connection.h"
-#include "file_stream.h"
-#include "socket_stream.h"
-
-#define MODULE_NAME "conn"
-#define DEBUG 1
-#undef DEBUG
-#include "debug.h"
-
-/** Initialize a file stream from a file desciptor.
- *
- * @param fd file descriptor
- * @param mode file mode
- * @param buffered make the stream buffered if 1, unbuffered if 0
- * @param io return parameter for the stream
- * @return 0 on success, error code otherwise
- */
-int stream_init(int fd, const char *mode, int buffered, IOStream **io){
- int err = 0;
- *io = file_stream_fdopen(fd, mode);
- if(!*io){
- err = -errno;
- perror("fdopen");
- goto exit;
- }
- if(!buffered){
- // Make unbuffered.
- err = file_stream_setvbuf(*io, NULL, _IONBF, 0);
- if(err){
- err = -errno;
- perror("setvbuf");
- goto exit;
- }
- }
- exit:
- if(err && *io){
- IOStream_close(*io);
- *io = NULL;
- }
- return err;
-}
-
-ConnList * ConnList_add(ConnList *l, Conn *conn){
- ConnList *v;
- v = ALLOCATE(ConnList);
- v->conn = conn;
- v->next =l;
- return v;
-}
-
-ConnList * ConnList_del(ConnList *l, Conn *conn){
- ConnList *prev, *curr, *next;
- for(prev = NULL, curr = l; curr; prev = curr, curr = next){
- next = curr->next;
- if(curr->conn == conn){
- if(prev){
- prev->next = curr->next;
- } else {
- l = curr->next;
- }
- }
- }
- return l;
-}
-
-void ConnList_close(ConnList *l){
- for( ; l; l = l->next){
- Conn_close(l->conn);
- }
-}
-
-void ConnList_select(ConnList *l, SelectSet *set){
- for( ; l; l = l->next){
- Conn_select(l->conn, set);
- }
-}
-
-/** Handle connections according to a select set.
- *
- * @param set indicates ready connections
- */
-ConnList * ConnList_handle(ConnList *l, SelectSet *set){
- ConnList *prev, *curr, *next;
- Conn *conn;
- int err;
-
- for(prev = NULL, curr = l; curr; prev = curr, curr = next){
- next = curr->next;
- conn = curr->conn;
- err = Conn_handle(conn, set);
- if(err){
- if(prev){
- prev->next = curr->next;
- } else {
- l = curr->next;
- }
- }
- }
- return l;
-}
-
-Conn *Conn_new(int (*fn)(Conn *conn, int mode), void *data){
- Conn *conn;
- conn = ALLOCATE(Conn);
- conn->fn = fn;
- conn->data = data;
- return conn;
-}
-
-int Conn_handler(Conn *conn, int mode){
- int err = 0;
- dprintf(">\n");
- if(conn->fn){
- err = conn->fn(conn, mode);
- } else {
- dprintf("> no handler\n");
- err = -ENOSYS;
- }
- if(err < 0){
- dprintf("> err=%d, closing %d\n", err, conn->sock);
- Conn_close(conn);
- }
- dprintf("< err=%d\n", err);
- return err;
-}
-
-int Conn_handle(Conn *conn, SelectSet *set){
- int err = 0;
- int mode = SelectSet_in(set, conn->sock);
-
- dprintf("> sock=%d mode=%d\n", conn->sock, mode);
- if(mode){
- err = Conn_handler(conn, mode);
-
- }
- return err;
-}
-
-void Conn_select(Conn *conn, SelectSet *set){
- dprintf("> sock=%d\n", conn->sock);
- SelectSet_add(set, conn->sock, conn->mode);
-}
-
-/** Initialize a connection.
- *
- * @param conn connection
- * @param sock socket
- * @param ipaddr ip address
- * @return 0 on success, error code otherwise
- */
-int Conn_init(Conn *conn, int sock, int type, int mode, struct sockaddr_in addr){
- int err = 0;
- conn->addr = addr;
- conn->type = type;
- conn->mode = mode;
- conn->sock = sock;
- if(type == SOCK_STREAM){
- err = stream_init(sock, "r", 0, &conn->in);
- if(err) goto exit;
- err = stream_init(sock, "w", 0, &conn->out);
- if(err) goto exit;
- } else {
- conn->in = socket_stream_new(sock);
- conn->out = socket_stream_new(sock);
- socket_stream_set_addr(conn->out, &addr);
- }
- exit:
- if(err) eprintf("< err=%d\n", err);
- return err;
-}
-
-/** Open a connection.
- *
- * @param conn connection
- * @param socktype socket type
- * @param ipaddr ip address to connect to
- * @param port port
- * @return 0 on success, error code otherwise
- */
-int Conn_connect(Conn *conn, int socktype, struct in_addr ipaddr, uint16_t port){
- int err = 0;
- int sock;
- struct sockaddr_in addr_in;
- struct sockaddr *addr = (struct sockaddr *)&addr_in;
- socklen_t addr_n = sizeof(addr_in);
- dprintf("> addr=%s:%d\n", inet_ntoa(ipaddr), ntohs(port));
- sock = socket(AF_INET, socktype, 0);
- if(sock < 0){
- err = -errno;
- goto exit;
- }
- addr_in.sin_family = AF_INET;
- addr_in.sin_addr = ipaddr;
- addr_in.sin_port = port;
- err = connect(sock, addr, addr_n);
- if(err) goto exit;
- err = Conn_init(conn, sock, socktype, 0, addr_in);
- exit:
- if(err){
- perror("Conn_connect");
- eprintf("< err=%d\n", err);
- }
- return err;
-}
-
-/** Close a connection.
- *
- * @param conn connection
- */
-void Conn_close(Conn *conn){
- if(!conn) return;
- if(conn->in) IOStream_close(conn->in);
- if(conn->out) IOStream_close(conn->out);
- shutdown(conn->sock, 2);
-}
-
-/** Set socket option to reuse address.
- */
-int setsock_reuse(int sock, int val){
- int err = 0;
- err = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
- if(err < 0){
- err = -errno;
- perror("setsockopt SO_REUSEADDR");
- }
- return err;
-}
-
-/** Set socket broadcast option.
- */
-int setsock_broadcast(int sock, int val){
- int err = 0;
- err = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val));
- if(err < 0){
- err = -errno;
- perror("setsockopt SO_BROADCAST");
- }
- return err;
-}
-
-/** Join a socket to a multicast group.
- */
-int setsock_multicast(int sock, uint32_t iaddr, uint32_t maddr){
- int err = 0;
- struct ip_mreqn mreq = {};
- int mloop = 0;
- // See 'man 7 ip' for these options.
- mreq.imr_multiaddr.s_addr = maddr; // IP multicast address.
- mreq.imr_address.s_addr = iaddr; // Interface IP address.
- mreq.imr_ifindex = 0; // Interface index (0 means any).
- err = setsockopt(sock, SOL_IP, IP_MULTICAST_LOOP, &mloop, sizeof(mloop));
- if(err < 0){
- err = -errno;
- perror("setsockopt IP_MULTICAST_LOOP");
- goto exit;
- }
- err = setsockopt(sock, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
- if(err < 0){
- err = -errno;
- perror("setsockopt IP_ADD_MEMBERSHIP");
- goto exit;
- }
- exit:
- return err;
-}
-
-/** Set a socket's multicast ttl (default is 1).
- */
-int setsock_multicast_ttl(int sock, uint8_t ttl){
- int err = 0;
- err = setsockopt(sock, SOL_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
- if(err < 0){
- err = -errno;
- perror("setsockopt IP_MULTICAST_TTL");
- }
- return err;
-}
-
-int setsock_pktinfo(int sock, int val){
- int err = 0;
- err = setsockopt(sock, SOL_IP, IP_PKTINFO, &val, sizeof(val));
- if(err < 0){
- err = -errno;
- perror("setsockopt IP_PKTINFO");
- }
- return err;
-}
-
-char * socket_flags(int flags){
- static char s[6];
- int i = 0;
- s[i++] = (flags & VSOCK_CONNECT ? 'c' : '-');
- s[i++] = (flags & VSOCK_BIND ? 'b' : '-');
- s[i++] = (flags & VSOCK_REUSE ? 'r' : '-');
- s[i++] = (flags & VSOCK_BROADCAST ? 'B' : '-');
- s[i++] = (flags & VSOCK_MULTICAST ? 'M' : '-');
- s[i++] = '\0';
- return s;
-}
-
-/** Create a socket.
- * The flags can include VSOCK_REUSE, VSOCK_BROADCAST, VSOCK_CONNECT.
- *
- * @param socktype socket type
- * @param saddr address
- * @param port port
- * @param flags flags
- * @param val return value for the socket connection
- * @return 0 on success, error code otherwise
- */
-int create_socket(int socktype, uint32_t saddr, uint32_t port, int flags, int *val){
- int err = 0;
- int sock = 0;
- struct sockaddr_in addr_in;
- struct sockaddr *addr = (struct sockaddr *)&addr_in;
- socklen_t addr_n = sizeof(addr_in);
- int reuse, bcast;
-
- //dprintf(">\n");
- reuse = (flags & VSOCK_REUSE);
- bcast = (flags & VSOCK_BROADCAST);
- addr_in.sin_family = AF_INET;
- addr_in.sin_addr.s_addr = saddr;
- addr_in.sin_port = port;
- dprintf("> flags=%s addr=%s port=%d\n", socket_flags(flags),
- inet_ntoa(addr_in.sin_addr), ntohs(addr_in.sin_port));
-
- sock = socket(AF_INET, socktype, 0);
- if(sock < 0){
- err = -errno;
- goto exit;
- }
- if(reuse){
- err = setsock_reuse(sock, reuse);
- if(err < 0) goto exit;
- }
- if(bcast){
- err = setsock_broadcast(sock, bcast);
- if(err < 0) goto exit;
- }
- if(flags & VSOCK_CONNECT){
- err = connect(sock, addr, addr_n);
- if(err < 0){
- err = -errno;
- perror("connect");
- goto exit;
- }
- }
- if(flags & VSOCK_BIND){
- err = bind(sock, addr, addr_n);
- if(err < 0){
- err = -errno;
- perror("bind");
- goto exit;
- }
- }
- {
- struct sockaddr_in self = {};
- socklen_t self_n = sizeof(self);
- getsockname(sock, (struct sockaddr *)&self, &self_n);
- dprintf("> sockname sock=%d addr=%s port=%d reuse=%d bcast=%d\n",
- sock, inet_ntoa(self.sin_addr), ntohs(self.sin_port),
- reuse, bcast);
- }
- exit:
- *val = (err ? -1 : sock);
- //dprintf("< err=%d\n", err);
- return err;
-}
-
-int Conn_socket(int socktype, uint32_t saddr, uint32_t port, int flags, Conn **val){
- int err;
- int sock;
- struct sockaddr_in addr_in;
- Conn *conn;
-
- err = create_socket(socktype, saddr, port, flags, &sock);
- if(err) goto exit;
- conn = Conn_new(NULL, NULL);
- addr_in.sin_family = AF_INET;
- addr_in.sin_addr.s_addr = saddr;
- addr_in.sin_port = port;
- Conn_init(conn, sock, socktype, 0, addr_in);
- exit:
- *val = (err ? NULL : conn);
- return err;
-}
+++ /dev/null
-/*
- * Copyright (C) 2003 - 2004 Mike Wray <mike.wray@hp.com>.
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef _VNET_CONNECTION_H_
-#define _VNET_CONNECTION_H_
-
-#include <netinet/in.h>
-
-#include "iostream.h"
-#include "select.h"
-
-/** A connection.
- * The underlying transport is a socket.
- * Contains in and out streams using the socket.
- */
-typedef struct Conn {
- struct sockaddr_in addr;
- int sock;
- int type;
- int mode; // select mode
- IOStream *in;
- IOStream *out;
- int (*fn)(struct Conn *conn, int mode);
- void *data;
-} Conn;
-
-typedef struct ConnList {
- Conn *conn;
- struct ConnList *next;
-} ConnList;
-
-extern ConnList * ConnList_add(ConnList *l, Conn *conn);
-extern ConnList * ConnList_del(ConnList *l, Conn *conn);
-extern void ConnList_close(ConnList *l);
-extern void ConnList_select(ConnList *l, SelectSet *set);
-extern ConnList * ConnList_handle(ConnList *l, SelectSet *set);
-
-extern Conn * Conn_new(int (*fn)(struct Conn *conn, int mode), void *data);
-extern int Conn_init(Conn *conn, int sock, int type, int mode, struct sockaddr_in addr);
-extern int Conn_connect(Conn *conn, int type, struct in_addr ipaddr, uint16_t port);
-extern void Conn_select(Conn *conn, SelectSet *set);
-extern int Conn_handle(Conn *conn, SelectSet *set);
-extern void Conn_close(Conn *conn);
-extern int Conn_socket(int socktype, uint32_t saddr, uint32_t port, int flags, Conn **val);
-
-/** Socket flags. */
-enum {
- VSOCK_REUSE = 1,
- VSOCK_BIND = 2,
- VSOCK_CONNECT = 4,
- VSOCK_BROADCAST = 8,
- VSOCK_MULTICAST = 16,
- };
-
-extern int create_socket(int socktype, uint32_t saddr, uint32_t port, int flags, int *sock);
-extern int setsock_reuse(int sock, int val);
-extern int setsock_broadcast(int sock, int val);
-extern int setsock_multicast(int sock, uint32_t iaddr, uint32_t maddr);
-extern int setsock_multicast_ttl(int sock, uint8_t ttl);
-extern int setsock_pktinfo(int sock, int val);
-extern char * socket_flags(int flags);
-
-#endif /* ! _VNET_CONNECTION_H_ */
+++ /dev/null
-#ifndef _VNETD_LIST_H_
-#define _VNETD_LIST_H_
-
-/* Taken from Linux kernel code, but de-kernelized for userspace. */
-#include <stddef.h>
-
-/*
- * These are non-NULL pointers that will result in page faults
- * under normal circumstances, used to verify that nobody uses
- * non-initialized list entries.
- */
-#define LIST_POISON1 ((void *) 0x00100100)
-#define LIST_POISON2 ((void *) 0x00200200)
-
-#define container_of(ptr, type, member) ({ \
- const typeof( ((type *)0)->member ) *__mptr = (ptr); \
- (type *)( (char *)__mptr - offsetof(type,member) );})
-
-/*
- * Simple doubly linked list implementation.
- *
- * Some of the internal functions ("__xxx") are useful when
- * manipulating whole lists rather than single entries, as
- * sometimes we already know the next/prev entries and we can
- * generate better code by using them directly rather than
- * using the generic single-entry routines.
- */
-
-struct list_head {
- struct list_head *next, *prev;
-};
-
-#define LIST_HEAD_INIT(name) { &(name), &(name) }
-
-#define LIST_HEAD(name) \
- struct list_head name = LIST_HEAD_INIT(name)
-
-#define INIT_LIST_HEAD(ptr) do { \
- (ptr)->next = (ptr); (ptr)->prev = (ptr); \
-} while (0)
-
-/*
- * Insert a new entry between two known consecutive entries.
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
- */
-static inline void __list_add(struct list_head *new,
- struct list_head *prev,
- struct list_head *next)
-{
- next->prev = new;
- new->next = next;
- new->prev = prev;
- prev->next = new;
-}
-
-/**
- * list_add - add a new entry
- * @new: new entry to be added
- * @head: list head to add it after
- *
- * Insert a new entry after the specified head.
- * This is good for implementing stacks.
- */
-static inline void list_add(struct list_head *new, struct list_head *head)
-{
- __list_add(new, head, head->next);
-}
-
-/**
- * list_add_tail - add a new entry
- * @new: new entry to be added
- * @head: list head to add it before
- *
- * Insert a new entry before the specified head.
- * This is useful for implementing queues.
- */
-static inline void list_add_tail(struct list_head *new, struct list_head *head)
-{
- __list_add(new, head->prev, head);
-}
-
-/*
- * Delete a list entry by making the prev/next entries
- * point to each other.
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
- */
-static inline void __list_del(struct list_head * prev, struct list_head * next)
-{
- next->prev = prev;
- prev->next = next;
-}
-
-/**
- * list_del - deletes entry from list.
- * @entry: the element to delete from the list.
- * Note: list_empty on entry does not return true after this, the entry is
- * in an undefined state.
- */
-static inline void list_del(struct list_head *entry)
-{
- __list_del(entry->prev, entry->next);
- entry->next = LIST_POISON1;
- entry->prev = LIST_POISON2;
-}
-
-/**
- * list_del_rcu - deletes entry from list without re-initialization
- * @entry: the element to delete from the list.
- *
- * Note: list_empty on entry does not return true after this,
- * the entry is in an undefined state. It is useful for RCU based
- * lockfree traversal.
- *
- * In particular, it means that we can not poison the forward
- * pointers that may still be used for walking the list.
- */
-static inline void list_del_rcu(struct list_head *entry)
-{
- __list_del(entry->prev, entry->next);
- entry->prev = LIST_POISON2;
-}
-
-/**
- * list_del_init - deletes entry from list and reinitialize it.
- * @entry: the element to delete from the list.
- */
-static inline void list_del_init(struct list_head *entry)
-{
- __list_del(entry->prev, entry->next);
- INIT_LIST_HEAD(entry);
-}
-
-/**
- * list_move - delete from one list and add as another's head
- * @list: the entry to move
- * @head: the head that will precede our entry
- */
-static inline void list_move(struct list_head *list, struct list_head *head)
-{
- __list_del(list->prev, list->next);
- list_add(list, head);
-}
-
-/**
- * list_move_tail - delete from one list and add as another's tail
- * @list: the entry to move
- * @head: the head that will follow our entry
- */
-static inline void list_move_tail(struct list_head *list,
- struct list_head *head)
-{
- __list_del(list->prev, list->next);
- list_add_tail(list, head);
-}
-
-/**
- * list_empty - tests whether a list is empty
- * @head: the list to test.
- */
-static inline int list_empty(struct list_head *head)
-{
- return head->next == head;
-}
-
-static inline void __list_splice(struct list_head *list,
- struct list_head *head)
-{
- struct list_head *first = list->next;
- struct list_head *last = list->prev;
- struct list_head *at = head->next;
-
- first->prev = head;
- head->next = first;
-
- last->next = at;
- at->prev = last;
-}
-
-/**
- * list_splice - join two lists
- * @list: the new list to add.
- * @head: the place to add it in the first list.
- */
-static inline void list_splice(struct list_head *list, struct list_head *head)
-{
- if (!list_empty(list))
- __list_splice(list, head);
-}
-
-/**
- * list_splice_init - join two lists and reinitialise the emptied list.
- * @list: the new list to add.
- * @head: the place to add it in the first list.
- *
- * The list at @list is reinitialised
- */
-static inline void list_splice_init(struct list_head *list,
- struct list_head *head)
-{
- if (!list_empty(list)) {
- __list_splice(list, head);
- INIT_LIST_HEAD(list);
- }
-}
-
-/**
- * list_entry - get the struct for this entry
- * @ptr: the &struct list_head pointer.
- * @type: the type of the struct this is embedded in.
- * @member: the name of the list_struct within the struct.
- */
-#define list_entry(ptr, type, member) \
- container_of(ptr, type, member)
-
-/**
- * list_for_each - iterate over a list
- * @pos: the &struct list_head to use as a loop counter.
- * @head: the head for your list.
- */
-#define list_for_each(pos, head) \
- for (pos = (head)->next; pos != (head); pos = pos->next)
-
-/**
- * list_for_each_prev - iterate over a list backwards
- * @pos: the &struct list_head to use as a loop counter.
- * @head: the head for your list.
- */
-#define list_for_each_prev(pos, head) \
- for (pos = (head)->prev; pos != (head); pos = pos->prev)
-
-/**
- * list_for_each_safe - iterate over a list safe against removal of list entry
- * @pos: the &struct list_head to use as a loop counter.
- * @n: another &struct list_head to use as temporary storage
- * @head: the head for your list.
- */
-#define list_for_each_safe(pos, n, head) \
- for (pos = (head)->next, n = pos->next; pos != (head); \
- pos = n, n = pos->next)
-
-/**
- * list_for_each_entry - iterate over list of given type
- * @pos: the type * to use as a loop counter.
- * @head: the head for your list.
- * @member: the name of the list_struct within the struct.
- */
-#define list_for_each_entry(pos, head, member) \
- for (pos = list_entry((head)->next, typeof(*pos), member); \
- &pos->member != (head); \
- pos = list_entry(pos->member.next, typeof(*pos), member))
-
-/**
- * list_for_each_entry_reverse - iterate backwards over list of given type.
- * @pos: the type * to use as a loop counter.
- * @head: the head for your list.
- * @member: the name of the list_struct within the struct.
- */
-#define list_for_each_entry_reverse(pos, head, member) \
- for (pos = list_entry((head)->prev, typeof(*pos), member); \
- &pos->member != (head); \
- pos = list_entry(pos->member.prev, typeof(*pos), member))
-
-
-/**
- * list_for_each_entry_safe - iterate over list of given type safe against
- * removal of list entry
- * @pos: the type * to use as a loop counter.
- * @n: another type * to use as temporary storage
- * @head: the head for your list.
- * @member: the name of the list_struct within the struct.
- */
-#define list_for_each_entry_safe(pos, n, head, member) \
- for (pos = list_entry((head)->next, typeof(*pos), member), \
- n = list_entry(pos->member.next, typeof(*pos), member); \
- &pos->member != (head); \
- pos = n, n = list_entry(n->member.next, typeof(*n), member))
-
-
-
-#endif /* _VNETD_LIST_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2003 - 2004 Mike Wray <mike.wray@hp.com>.
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-
-#include "select.h"
-
-#define MODULE_NAME "select"
-#define DEBUG
-#undef DEBUG
-#include "debug.h"
-
-/** Zero all the file descriptor sets.
- *
- * @param set select set
- * @param fd file descriptor
- * @return 0 on success, -1 otherwise
- */
-void SelectSet_zero(SelectSet *set){
- set->n = 0;
- FD_ZERO(&set->rd);
- FD_ZERO(&set->wr);
- FD_ZERO(&set->er);
-}
-
-/** Add a file descriptor to the set.
- *
- * @param set select set
- * @param fd file descriptor
- * @param mode mask of sets to add to
- * @return 0 on success, -1 otherwise
- */
-void SelectSet_add(SelectSet *set, int fd, int mode){
- if(fd < 0) return;
- if(mode & SELECT_READ){
- SelectSet_add_read(set, fd);
- }
- if(mode & SELECT_WRITE){
- SelectSet_add_write(set, fd);
- }
- if(mode & SELECT_ERROR){
- SelectSet_add_error(set, fd);
- }
-}
-
-/** Add a file descriptor to the write set.
- *
- * @param set select set
- * @param fd file descriptor
- * @return 0 on success, -1 otherwise
- */
-void SelectSet_add_read(SelectSet *set, int fd){
- dprintf("> fd=%d\n", fd);
- if(fd < 0) return;
- FD_SET(fd, &set->rd);
- if(fd > set->n) set->n = fd;
-}
-
-/** Add a file descriptor to the write set.
- *
- * @param set select set
- * @param fd file descriptor
- * @return 0 on success, -1 otherwise
- */
-void SelectSet_add_write(SelectSet *set, int fd){
- dprintf("> fd=%d\n", fd);
- if(fd < 0) return;
- FD_SET(fd, &set->wr);
- if(fd > set->n) set->n = fd;
-}
-
-/** Add a file descriptor to the error set.
- *
- * @param set select set
- * @param fd file descriptor
- * @return 0 on success, -1 otherwise
- */
-void SelectSet_add_error(SelectSet *set, int fd){
- dprintf("> fd=%d\n", fd);
- if(fd < 0) return;
- FD_SET(fd, &set->er);
- if(fd > set->n) set->n = fd;
-}
-
-/** Select on file descriptors.
- *
- * @param set select set
- * @param timeout timeout (may be NULL for no timeout)
- * @return 0 on success, -1 otherwise
- */
-int SelectSet_select(SelectSet *set, struct timeval *timeout){
- return select(set->n+1, &set->rd, &set->wr, &set->er, timeout);
-}
+++ /dev/null
-/*
- * Copyright (C) 2003 - 2004 Mike Wray <mike.wray@hp.com>.
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef _VFC_SELECT_H_
-#define _VFC_SELECT_H_
-
-/** Set of file descriptors for select.
- */
-typedef struct SelectSet {
- int n;
- fd_set rd, wr, er;
-} SelectSet;
-
-enum {
- SELECT_READ = 1,
- SELECT_WRITE = 2,
- SELECT_ERROR = 4,
-};
-
-extern void SelectSet_zero(SelectSet *set);
-extern void SelectSet_add(SelectSet *set, int fd, int mode);
-extern void SelectSet_add_read(SelectSet *set, int fd);
-extern void SelectSet_add_write(SelectSet *set, int fd);
-extern void SelectSet_add_error(SelectSet *set, int fd);
-extern int SelectSet_select(SelectSet *set, struct timeval *timeout);
-
-static inline int SelectSet_in(SelectSet *set, int fd){
- return ((fd >= 0)
- ? ((FD_ISSET(fd, &set->rd) ? SELECT_READ : 0) |
- (FD_ISSET(fd, &set->wr) ? SELECT_WRITE : 0) |
- (FD_ISSET(fd, &set->er) ? SELECT_ERROR : 0))
- : 0);
-}
-
-static inline int SelectSet_in_read(SelectSet *set, int fd){
- return (fd >= 0) && FD_ISSET(fd, &set->rd);
-}
-
-static inline int SelectSet_in_write(SelectSet *set, int fd){
- return (fd >= 0) && FD_ISSET(fd, &set->wr);
-}
-
-static inline int SelectSet_in_err(SelectSet *set, int fd){
- return (fd >= 0) && FD_ISSET(fd, &set->er);
-}
-
-#endif /* ! _VFC_SELECT_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2005 Mike Wray <mike.wray@hp.com>.
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <stdlib.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include "connection.h"
-#include "selector.h"
-
-#define MODULE_NAME "select"
-#define DEBUG 1
-#undef DEBUG
-#include "debug.h"
-
-void Selector_init(Selector *sel){
- INIT_LIST_HEAD(&sel->list);
-}
-
-/** Close a selector and remove it from its list.
- *
- * @param sel selector (may be null)
- */
-void Selector_close(Selector *sel){
- if(!sel) return;
- dprintf(">\n");
- if(sel->close){
- sel->close(sel);
- }
- if(sel->list.next
- && sel->list.next != LIST_POISON1
- && !list_empty(&sel->list)){
- list_del_init(&sel->list);
- }
-}
-
-/** Add a selector to a select set.
- * The selector is closed if it has no 'select' function,
- * or it has one and it returns an error.
- *
- * @param sel selector
- * @param set select set
- */
-int Selector_select(Selector *sel, SelectSet *set){
- int err = -EINVAL;
- dprintf(">\n");
- if(sel->select){
- err = sel->select(sel, set);
- }
- if(err){
- Selector_close(sel);
- }
- return err;
-}
-
-/** Call a selector with a select set.
- * The selector is closed if it has no 'selected' function,
- * or it has one and it returns an error.
- *
- * @param sel selector
- * @param set select set
- */
-int Selector_selected(Selector *sel, SelectSet *set){
- int err = -EINVAL;
- dprintf(">\n");
- if(sel->selected){
- err = sel->selected(sel, set);
- }
- if(err){
- Selector_close(sel);
- }
- return err;
-}
-
-int conn_select_fn(Selector *sel, SelectSet *set){
- int err = -EINVAL;
- Conn *conn = sel->data;
-
- dprintf(">\n");
- if(conn){
- err = 0;
- SelectSet_add(set, conn->sock, conn->mode);
- }
- return err;
-}
-
-int conn_selected_fn(Selector *sel, SelectSet *set){
- int err = -EINVAL;
- Conn *conn = sel->data;
-
- dprintf(">\n");
- if(conn){
- err = Conn_handle(conn, set);
- }
- return err;
-}
-
-void conn_close_fn(Selector *sel){
- Conn *conn = sel->data;
-
- wprintf("> sel=%p\n", sel);
- if(conn){
- Conn_close(conn);
- }
-}
-
-void Selector_conn_init(Selector *sel, Conn *conn,
- int mode, void *data,
- int (*fn)(struct Conn *conn, int mode)){
- conn->mode = SELECT_READ;
- conn->data = data;
- conn->fn = fn;
- sel->data = conn;
- sel->select = conn_select_fn;
- sel->close = conn_close_fn;
- sel->selected = conn_selected_fn;
-}
-
+++ /dev/null
-/*
- * Copyright (C) 2005 Mike Wray <mike.wray@hp.com>.
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _VNETD_SELECTOR_H_
-#define _VNETD_SELECTOR_H_
-
-#include "list.h"
-#include "select.h"
-
-struct Conn;
-
-typedef struct Selector {
-
- /** List the selector is linked into (if any). */
- struct list_head list;
-
- /** Function called by Selector_select() to add a selector to a select set.
- * The selector is closed if this returns an error (non-zero).
- */
- int (*select)(struct Selector *sel, struct SelectSet *set);
-
- /** Function called by Selector_selected() to notify a selector of select set.
- * The selector is closed if this returns an error (non-zero).
- */
- int (*selected)(struct Selector *sel, struct SelectSet *set);
-
- /** Function called by Selector_close() to close a selector.
- */
- void (*close)(struct Selector *sel);
-
- /** User data. */
- void *data;
-
-} Selector;
-
-void Selector_init(struct Selector *sel);
-void Selector_close(struct Selector *sel);
-int Selector_select(struct Selector *sel, struct SelectSet *set);
-int Selector_selected(struct Selector *sel, struct SelectSet *set);
-
-int conn_select_fn(struct Selector *sel, struct SelectSet *set);
-int conn_selected_fn(struct Selector *sel, struct SelectSet *set);
-void conn_close_fn(struct Selector *sel);
-void Selector_conn_init(struct Selector *sel, struct Conn *conn,
- int mode, void *data,
- int (*fn)(struct Conn *conn, int mode));
-
-#endif /* _VNETD_SELECTOR_H_ */
+++ /dev/null
-/*
- * Routines having to do with the 'struct sk_buff' memory handlers.
- *
- * Authors: Alan Cox <iiitac@pyr.swan.ac.uk>
- * Florian La Roche <rzsfl@rz.uni-sb.de>
- *
- * Fixes:
- * Alan Cox : Fixed the worst of the load
- * balancer bugs.
- * Dave Platt : Interrupt stacking fix.
- * Richard Kooijman : Timestamp fixes.
- * Alan Cox : Changed buffer format.
- * Alan Cox : destructor hook for AF_UNIX etc.
- * Linus Torvalds : Better skb_clone.
- * Alan Cox : Added skb_copy.
- * Alan Cox : Added all the changed routines Linus
- * only put in the headers
- * Ray VanTassle : Fixed --skb->lock in free
- * Alan Cox : skb_copy copy arp field
- * Andi Kleen : slabified it.
- * Robert Olsson : Removed skb_head_pool
- *
- * 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.
- */
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#include "allocate.h"
-#include "debug.h"
-#include "skbuff.h"
-
-#define SKB_DATA_ALIGN(size) ((((size) + 7) >> 3) << 3)
-
-/**
- * skb_over_panic - private function
- * @skb: buffer
- * @sz: size
- * @here: address
- *
- * Out of line support code for skb_put(). Not user callable.
- */
-void skb_over_panic(struct sk_buff *skb, int sz, void *here)
-{
- eprintf("skput:over: %p:%d put:%d\n", here, skb->len, sz);
- BUG();
-}
-
-/**
- * skb_under_panic - private function
- * @skb: buffer
- * @sz: size
- * @here: address
- *
- * Out of line support code for skb_push(). Not user callable.
- */
-
-void skb_under_panic(struct sk_buff *skb, int sz, void *here)
-{
- eprintf("skput:under: %p:%d put:%d\n", here, skb->len, sz);
- BUG();
-}
-
-/**
- * alloc_skb - allocate a network buffer
- * @size: size to allocate
- * @gfp_mask: allocation mask
- *
- * Allocate a new &sk_buff. The returned buffer has no headroom and a
- * tail room of size bytes. The object has a reference count of one.
- * The return is the buffer. On a failure the return is %NULL.
- */
-struct sk_buff *alloc_skb(unsigned int size, int gfp_mask)
-{
- struct sk_buff *skb;
- u8 *data;
-
- /* Get the HEAD */
- skb = ALLOCATE(struct sk_buff);
- if (!skb)
- goto out;
-
- /* Get the DATA. Size must match skb_add_mtu(). */
- size = SKB_DATA_ALIGN(size);
- data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
- if (!data)
- goto nodata;
-
- memset(skb, 0, offsetof(struct sk_buff, truesize));
- skb->truesize = size + sizeof(struct sk_buff);
- atomic_set(&skb->users, 1);
- skb->head = data;
- skb->data = data;
- skb->tail = data;
- skb->end = data + size;
- skb->list = NULL;
-
- atomic_set(&(skb_shinfo(skb)->dataref), 1);
- skb_shinfo(skb)->nr_frags = 0;
- skb_shinfo(skb)->tso_size = 0;
- skb_shinfo(skb)->tso_segs = 0;
- skb_shinfo(skb)->frag_list = NULL;
-out:
- return skb;
-nodata:
- kfree(skb);
- skb = NULL;
- goto out;
-}
-
-
-void skb_release_data(struct sk_buff *skb)
-{
- kfree(skb->head);
-}
-
-/*
- * Free an skbuff by memory without cleaning the state.
- */
-void kfree_skbmem(struct sk_buff *skb)
-{
- skb_release_data(skb);
- kfree(skb);
-}
-
-/**
- * __kfree_skb - private function
- * @skb: buffer
- *
- * Free an sk_buff. Release anything attached to the buffer.
- * Clean the state. This is an internal helper function. Users should
- * always call kfree_skb
- */
-
-void __kfree_skb(struct sk_buff *skb)
-{
- if (skb->list) {
- wprintf("Warning: kfree_skb passed an skb still "
- "on a list.\n");
- //BUG();
- }
-
- if(skb->destructor) {
- skb->destructor(skb);
- }
- kfree_skbmem(skb);
-}
-
-
-/**
- * skb_clone - duplicate an sk_buff
- * @skb: buffer to clone
- * @gfp_mask: allocation priority
- *
- * Duplicate an &sk_buff. The new one is not owned by a socket. Both
- * copies share the same packet data but not structure. The new
- * buffer has a reference count of 1. If the allocation fails the
- * function returns %NULL otherwise the new buffer is returned.
- *
- * If this function is called from an interrupt gfp_mask() must be
- * %GFP_ATOMIC.
- */
-
-struct sk_buff *skb_clone(struct sk_buff *skb, int gfp_mask)
-{
- return pskb_copy(skb, gfp_mask);
-}
-
-static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
-{
- /*
- * Shift between the two data areas in bytes
- */
- unsigned long offset = new->data - old->data;
-
- new->list = NULL;
- new->protocol = old->protocol;
- new->h.raw = old->h.raw + offset;
- new->nh.raw = old->nh.raw + offset;
- new->mac.raw = old->mac.raw + offset;
- new->pkt_type = old->pkt_type;
- new->destructor = NULL;
- atomic_set(&new->users, 1);
-}
-
-
-/**
- * pskb_expand_head - reallocate header of &sk_buff
- * @skb: buffer to reallocate
- * @nhead: room to add at head
- * @ntail: room to add at tail
- * @gfp_mask: allocation priority
- *
- * Expands (or creates identical copy, if &nhead and &ntail are zero)
- * header of skb. &sk_buff itself is not changed. &sk_buff MUST have
- * reference count of 1. Returns zero in the case of success or error,
- * if expansion failed. In the last case, &sk_buff is not changed.
- *
- * All the pointers pointing into skb header may change and must be
- * reloaded after call to this function.
- */
-
-int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, int gfp_mask)
-{
- u8 *data;
- int size = nhead + (skb->end - skb->head) + ntail;
- long off;
-
- if (skb_shared(skb))
- BUG();
-
- size = SKB_DATA_ALIGN(size);
-
- data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
- if (!data)
- goto nodata;
-
- /* Copy only real data... and, alas, header. This should be
- * optimized for the cases when header is void. */
- memcpy(data + nhead, skb->head, skb->tail - skb->head);
- memcpy(data + size, skb->end, sizeof(struct skb_shared_info));
-
- skb_release_data(skb);
-
- off = (data + nhead) - skb->head;
-
- skb->head = data;
- skb->end = data + size;
- skb->data += off;
- skb->tail += off;
- skb->mac.raw += off;
- skb->h.raw += off;
- skb->nh.raw += off;
- return 0;
-
-nodata:
- return -ENOMEM;
-}
-
-struct sk_buff *pskb_copy(struct sk_buff *skb, int gfp_mask)
-{
- /*
- * Allocate the copy buffer
- */
- struct sk_buff *n = alloc_skb(skb->end - skb->head, gfp_mask);
-
- if (!n)
- goto out;
-
- /* Set the data pointer */
- skb_reserve(n, skb->data - skb->head);
- /* Set the tail pointer and length */
- skb_put(n, skb_headlen(skb));
- /* Copy the bytes */
- memcpy(n->data, skb->data, n->len);
-
- n->data_len = skb->data_len;
- n->len = skb->len;
-
- copy_skb_header(n, skb);
-out:
- return n;
-}
-
-/* Make private copy of skb with writable head and some headroom */
-
-struct sk_buff *skb_realloc_headroom(struct sk_buff *skb, unsigned int headroom)
-{
- struct sk_buff *skb2;
- int delta = headroom - skb_headroom(skb);
-
- if (delta <= 0)
- skb2 = pskb_copy(skb, GFP_ATOMIC);
- else {
- skb2 = skb_copy_expand(skb, headroom, 0, GFP_ATOMIC);
- }
- return skb2;
-}
-
-
-/**
- * skb_copy_expand - copy and expand sk_buff
- * @skb: buffer to copy
- * @newheadroom: new free bytes at head
- * @newtailroom: new free bytes at tail
- * @gfp_mask: allocation priority
- *
- * Make a copy of both an &sk_buff and its data and while doing so
- * allocate additional space.
- *
- * This is used when the caller wishes to modify the data and needs a
- * private copy of the data to alter as well as more space for new fields.
- * Returns %NULL on failure or the pointer to the buffer
- * on success. The returned buffer has a reference count of 1.
- *
- * You must pass %GFP_ATOMIC as the allocation priority if this function
- * is called from an interrupt.
- *
- * BUG ALERT: ip_summed is not copied. Why does this work? Is it used
- * only by netfilter in the cases when checksum is recalculated? --ANK
- */
-struct sk_buff *skb_copy_expand(const struct sk_buff *skb,
- int newheadroom, int newtailroom, int gfp_mask)
-{
- /*
- * Allocate the copy buffer
- */
- struct sk_buff *n = alloc_skb(newheadroom + skb->len + newtailroom,
- gfp_mask);
- int head_copy_len, head_copy_off;
-
- if (!n)
- return NULL;
-
- skb_reserve(n, newheadroom);
-
- /* Set the tail pointer and length */
- skb_put(n, skb->len);
-
- head_copy_len = skb_headroom(skb);
- head_copy_off = 0;
- if (newheadroom <= head_copy_len)
- head_copy_len = newheadroom;
- else
- head_copy_off = newheadroom - head_copy_len;
-
- /* Copy the linear header and data. */
- if (skb_copy_bits(skb, -head_copy_len, n->head + head_copy_off,
- skb->len + head_copy_len))
- BUG();
-
- copy_skb_header(n, skb);
-
- return n;
-}
-
-
-/* Copy some data bits from skb to kernel buffer. */
-
-int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len)
-{
- int copy;
- int start = skb_headlen(skb);
-
- if (offset > (int)skb->len - len)
- goto fault;
-
- /* Copy header. */
- if ((copy = start - offset) > 0) {
- if (copy > len)
- copy = len;
- memcpy(to, skb->data + offset, copy);
- if ((len -= copy) == 0)
- return 0;
- offset += copy;
- to += copy;
- }
-
- if (!len)
- return 0;
-
-fault:
- return -EFAULT;
-}
-
-
-/**
- * skb_dequeue - remove from the head of the queue
- * @list: list to dequeue from
- *
- * Remove the head of the list. The list lock is taken so the function
- * may be used safely with other locking list functions. The head item is
- * returned or %NULL if the list is empty.
- */
-
-struct sk_buff *skb_dequeue(struct sk_buff_head *list)
-{
- unsigned long flags;
- struct sk_buff *result;
-
- spin_lock_irqsave(&list->lock, flags);
- result = __skb_dequeue(list);
- spin_unlock_irqrestore(&list->lock, flags);
- return result;
-}
-
-/**
- * skb_dequeue_tail - remove from the tail of the queue
- * @list: list to dequeue from
- *
- * Remove the tail of the list. The list lock is taken so the function
- * may be used safely with other locking list functions. The tail item is
- * returned or %NULL if the list is empty.
- */
-struct sk_buff *skb_dequeue_tail(struct sk_buff_head *list)
-{
- unsigned long flags;
- struct sk_buff *result;
-
- spin_lock_irqsave(&list->lock, flags);
- result = __skb_dequeue_tail(list);
- spin_unlock_irqrestore(&list->lock, flags);
- return result;
-}
-
-/**
- * skb_queue_purge - empty a list
- * @list: list to empty
- *
- * Delete all buffers on an &sk_buff list. Each buffer is removed from
- * the list and one reference dropped. This function takes the list
- * lock and is atomic with respect to other list locking functions.
- */
-void skb_queue_purge(struct sk_buff_head *list)
-{
- struct sk_buff *skb;
- while ((skb = skb_dequeue(list)) != NULL)
- kfree_skb(skb);
-}
-
-/**
- * skb_queue_head - queue a buffer at the list head
- * @list: list to use
- * @newsk: buffer to queue
- *
- * Queue a buffer at the start of the list. This function takes the
- * list lock and can be used safely with other locking &sk_buff functions
- * safely.
- *
- * A buffer cannot be placed on two lists at the same time.
- */
-void skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&list->lock, flags);
- __skb_queue_head(list, newsk);
- spin_unlock_irqrestore(&list->lock, flags);
-}
-
-/**
- * skb_queue_tail - queue a buffer at the list tail
- * @list: list to use
- * @newsk: buffer to queue
- *
- * Queue a buffer at the tail of the list. This function takes the
- * list lock and can be used safely with other locking &sk_buff functions
- * safely.
- *
- * A buffer cannot be placed on two lists at the same time.
- */
-void skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&list->lock, flags);
- __skb_queue_tail(list, newsk);
- spin_unlock_irqrestore(&list->lock, flags);
-}
-/**
- * skb_unlink - remove a buffer from a list
- * @skb: buffer to remove
- *
- * Place a packet after a given packet in a list. The list locks are taken
- * and this function is atomic with respect to other list locked calls
- *
- * Works even without knowing the list it is sitting on, which can be
- * handy at times. It also means that THE LIST MUST EXIST when you
- * unlink. Thus a list must have its contents unlinked before it is
- * destroyed.
- */
-void skb_unlink(struct sk_buff *skb)
-{
- struct sk_buff_head *list = skb->list;
-
- if (list) {
- unsigned long flags;
-
- spin_lock_irqsave(&list->lock, flags);
- if (skb->list == list)
- __skb_unlink(skb, skb->list);
- spin_unlock_irqrestore(&list->lock, flags);
- }
-}
-
-
-/**
- * skb_append - append a buffer
- * @old: buffer to insert after
- * @newsk: buffer to insert
- *
- * Place a packet after a given packet in a list. The list locks are taken
- * and this function is atomic with respect to other list locked calls.
- * A buffer cannot be placed on two lists at the same time.
- */
-
-void skb_append(struct sk_buff *old, struct sk_buff *newsk)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&old->list->lock, flags);
- __skb_append(old, newsk);
- spin_unlock_irqrestore(&old->list->lock, flags);
-}
-
-
-/**
- * skb_insert - insert a buffer
- * @old: buffer to insert before
- * @newsk: buffer to insert
- *
- * Place a packet before a given packet in a list. The list locks are taken
- * and this function is atomic with respect to other list locked calls
- * A buffer cannot be placed on two lists at the same time.
- */
-
-void skb_insert(struct sk_buff *old, struct sk_buff *newsk)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&old->list->lock, flags);
- __skb_insert(newsk, old->prev, old, old->list);
- spin_unlock_irqrestore(&old->list->lock, flags);
-}
-
+++ /dev/null
-/*
- * Definitions for the 'struct sk_buff' memory handlers.
- *
- * Authors:
- * Alan Cox, <gw4pts@gw4pts.ampr.org>
- * Florian La Roche, <rzsfl@rz.uni-sb.de>
- *
- * 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.
- */
-
-#ifndef _VNET_SKBUFF_H
-#define _VNET_SKBUFF_H
-
-#include "sys_kernel.h"
-#include "spinlock.h"
-
-struct sk_buff;
-
-struct sk_buff_head {
- /* These two members must be first. */
- struct sk_buff *next;
- struct sk_buff *prev;
-
- __u32 qlen;
- spinlock_t lock;
-};
-
-
-
-#define MAX_SKB_FRAGS 8 // (65536/PAGE_SIZE + 2)
-
-typedef struct skb_frag_struct skb_frag_t;
-
-struct skb_frag_struct {
- //struct page *page;
- void *page;
- __u16 page_offset;
- __u16 size;
-};
-
-/* This data is invariant across clones and lives at
- * the end of the header data, ie. at skb->end.
- */
-struct skb_shared_info {
- atomic_t dataref;
- unsigned int nr_frags;
- unsigned short tso_size;
- unsigned short tso_segs;
- struct sk_buff *frag_list;
- skb_frag_t frags[MAX_SKB_FRAGS];
-};
-
-struct sk_buff {
- /* These two members must be first. */
- struct sk_buff *next;
- struct sk_buff *prev;
-
- struct sk_buff_head *list;
- struct net_device *dev;
-
- union {
- struct tcphdr *th;
- struct udphdr *uh;
- struct icmphdr *icmph;
- struct igmphdr *igmph;
- struct iphdr *ipiph;
- struct ipv6hdr *ipv6h;
- unsigned char *raw;
- } h;
-
- union {
- struct iphdr *iph;
- struct ipv6hdr *ipv6h;
- struct arphdr *arph;
- unsigned char *raw;
- } nh;
-
- union {
- unsigned char *raw;
- } mac;
-
- unsigned int len,
- data_len;
- unsigned char pkt_type;
- unsigned short protocol;
-
- void (*destructor)(struct sk_buff *skb);
-
- /* These elements must be at the end, see alloc_skb() for details. */
- unsigned int truesize;
- atomic_t users;
- unsigned char *head,
- *data,
- *tail,
- *end;
-};
-
-extern void skb_over_panic(struct sk_buff *skb, int len,
- void *here);
-extern void skb_under_panic(struct sk_buff *skb, int len,
- void *here);
-
-#define skb_shinfo(SKB) ((struct skb_shared_info *)((SKB)->end))
-
-extern void __kfree_skb(struct sk_buff *skb);
-extern struct sk_buff *alloc_skb(unsigned int size, int priority);
-extern struct sk_buff *skb_clone(struct sk_buff *skb, int priority);
-extern struct sk_buff *pskb_copy(struct sk_buff *skb, int gfp_mask);
-extern struct sk_buff *skb_realloc_headroom(struct sk_buff *skb,
- unsigned int headroom);
-extern struct sk_buff *skb_copy_expand(const struct sk_buff *skb,
- int newheadroom, int newtailroom,
- int priority);
-
-extern int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len);
-
-static inline void kfree_skb(struct sk_buff *skb)
-{
- if (atomic_read(&skb->users) == 1 || atomic_dec_and_test(&skb->users))
- __kfree_skb(skb);
-}
-
-static inline void dev_kfree_skb(struct sk_buff *skb)
-{
- kfree_skb(skb);
-}
-
-static inline int skb_cloned(const struct sk_buff *skb)
-{
- return 0;
-}
-
-/**
- * skb_shared - is the buffer shared
- * @skb: buffer to check
- *
- * Returns true if more than one person has a reference to this
- * buffer.
- */
-static inline int skb_shared(const struct sk_buff *skb)
-{
- return atomic_read(&skb->users) != 1;
-}
-
-/**
- * skb_peek
- * @list_: list to peek at
- *
- * Peek an &sk_buff. Unlike most other operations you _MUST_
- * be careful with this one. A peek leaves the buffer on the
- * list and someone else may run off with it. You must hold
- * the appropriate locks or have a private queue to do this.
- *
- * Returns %NULL for an empty list or a pointer to the head element.
- * The reference count is not incremented and the reference is therefore
- * volatile. Use with caution.
- */
-static inline struct sk_buff *skb_peek(struct sk_buff_head *list_)
-{
- struct sk_buff *list = ((struct sk_buff *)list_)->next;
- if (list == (struct sk_buff *)list_)
- list = NULL;
- return list;
-}
-
-/**
- * skb_peek_tail
- * @list_: list to peek at
- *
- * Peek an &sk_buff. Unlike most other operations you _MUST_
- * be careful with this one. A peek leaves the buffer on the
- * list and someone else may run off with it. You must hold
- * the appropriate locks or have a private queue to do this.
- *
- * Returns %NULL for an empty list or a pointer to the tail element.
- * The reference count is not incremented and the reference is therefore
- * volatile. Use with caution.
- */
-static inline struct sk_buff *skb_peek_tail(struct sk_buff_head *list_)
-{
- struct sk_buff *list = ((struct sk_buff *)list_)->prev;
- if (list == (struct sk_buff *)list_)
- list = NULL;
- return list;
-}
-
-/**
- * skb_queue_len - get queue length
- * @list_: list to measure
- *
- * Return the length of an &sk_buff queue.
- */
-static inline __u32 skb_queue_len(const struct sk_buff_head *list_)
-{
- return list_->qlen;
-}
-
-static inline void skb_queue_head_init(struct sk_buff_head *list)
-{
- spin_lock_init(&list->lock);
- list->prev = list->next = (struct sk_buff *)list;
- list->qlen = 0;
-}
-
-/*
- * Insert an sk_buff at the start of a list.
- *
- * The "__skb_xxxx()" functions are the non-atomic ones that
- * can only be called with interrupts disabled.
- */
-
-/**
- * __skb_queue_head - queue a buffer at the list head
- * @list: list to use
- * @newsk: buffer to queue
- *
- * Queue a buffer at the start of a list. This function takes no locks
- * and you must therefore hold required locks before calling it.
- *
- * A buffer cannot be placed on two lists at the same time.
- */
-extern void skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk);
-static inline void __skb_queue_head(struct sk_buff_head *list,
- struct sk_buff *newsk)
-{
- struct sk_buff *prev, *next;
-
- newsk->list = list;
- list->qlen++;
- prev = (struct sk_buff *)list;
- next = prev->next;
- newsk->next = next;
- newsk->prev = prev;
- next->prev = prev->next = newsk;
-}
-
-/**
- * __skb_queue_tail - queue a buffer at the list tail
- * @list: list to use
- * @newsk: buffer to queue
- *
- * Queue a buffer at the end of a list. This function takes no locks
- * and you must therefore hold required locks before calling it.
- *
- * A buffer cannot be placed on two lists at the same time.
- */
-extern void skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk);
-static inline void __skb_queue_tail(struct sk_buff_head *list,
- struct sk_buff *newsk)
-{
- struct sk_buff *prev, *next;
-
- newsk->list = list;
- list->qlen++;
- next = (struct sk_buff *)list;
- prev = next->prev;
- newsk->next = next;
- newsk->prev = prev;
- next->prev = prev->next = newsk;
-}
-
-
-/**
- * __skb_dequeue - remove from the head of the queue
- * @list: list to dequeue from
- *
- * Remove the head of the list. This function does not take any locks
- * so must be used with appropriate locks held only. The head item is
- * returned or %NULL if the list is empty.
- */
-extern struct sk_buff *skb_dequeue(struct sk_buff_head *list);
-static inline struct sk_buff *__skb_dequeue(struct sk_buff_head *list)
-{
- struct sk_buff *next, *prev, *result;
-
- prev = (struct sk_buff *) list;
- next = prev->next;
- result = NULL;
- if (next != prev) {
- result = next;
- next = next->next;
- list->qlen--;
- next->prev = prev;
- prev->next = next;
- result->next = result->prev = NULL;
- result->list = NULL;
- }
- return result;
-}
-
-
-/*
- * Insert a packet on a list.
- */
-extern void skb_insert(struct sk_buff *old, struct sk_buff *newsk);
-static inline void __skb_insert(struct sk_buff *newsk,
- struct sk_buff *prev, struct sk_buff *next,
- struct sk_buff_head *list)
-{
- newsk->next = next;
- newsk->prev = prev;
- next->prev = prev->next = newsk;
- newsk->list = list;
- list->qlen++;
-}
-
-/*
- * Place a packet after a given packet in a list.
- */
-extern void skb_append(struct sk_buff *old, struct sk_buff *newsk);
-static inline void __skb_append(struct sk_buff *old, struct sk_buff *newsk)
-{
- __skb_insert(newsk, old, old->next, old->list);
-}
-
-/*
- * remove sk_buff from list. _Must_ be called atomically, and with
- * the list known..
- */
-extern void skb_unlink(struct sk_buff *skb);
-static inline void __skb_unlink(struct sk_buff *skb, struct sk_buff_head *list)
-{
- struct sk_buff *next, *prev;
-
- list->qlen--;
- next = skb->next;
- prev = skb->prev;
- skb->next = skb->prev = NULL;
- skb->list = NULL;
- next->prev = prev;
- prev->next = next;
-}
-
-
-/* XXX: more streamlined implementation */
-
-/**
- * __skb_dequeue_tail - remove from the tail of the queue
- * @list: list to dequeue from
- *
- * Remove the tail of the list. This function does not take any locks
- * so must be used with appropriate locks held only. The tail item is
- * returned or %NULL if the list is empty.
- */
-extern struct sk_buff *skb_dequeue_tail(struct sk_buff_head *list);
-static inline struct sk_buff *__skb_dequeue_tail(struct sk_buff_head *list)
-{
- struct sk_buff *skb = skb_peek_tail(list);
- if (skb)
- __skb_unlink(skb, list);
- return skb;
-}
-
-
-/*
- * Add data to an sk_buff
- */
-static inline unsigned char *__skb_put(struct sk_buff *skb, unsigned int len)
-{
- unsigned char *tmp = skb->tail;
- skb->tail += len;
- skb->len += len;
- return tmp;
-}
-
-/**
- * skb_put - add data to a buffer
- * @skb: buffer to use
- * @len: amount of data to add
- *
- * This function extends the used data area of the buffer. If this would
- * exceed the total buffer size the kernel will panic. A pointer to the
- * first byte of the extra data is returned.
- */
-static inline unsigned char *skb_put(struct sk_buff *skb, unsigned int len)
-{
- unsigned char *tmp = skb->tail;
- skb->tail += len;
- skb->len += len;
- if (unlikely(skb->tail>skb->end))
- skb_over_panic(skb, len, current_text_addr());
- return tmp;
-}
-
-static inline unsigned char *__skb_push(struct sk_buff *skb, unsigned int len)
-{
- skb->data -= len;
- skb->len += len;
- return skb->data;
-}
-
-/**
- * skb_push - add data to the start of a buffer
- * @skb: buffer to use
- * @len: amount of data to add
- *
- * This function extends the used data area of the buffer at the buffer
- * start. If this would exceed the total buffer headroom the kernel will
- * panic. A pointer to the first byte of the extra data is returned.
- */
-static inline unsigned char *skb_push(struct sk_buff *skb, unsigned int len)
-{
- skb->data -= len;
- skb->len += len;
- if (unlikely(skb->data<skb->head)){
- skb_under_panic(skb, len, current_text_addr());
- }
- return skb->data;
-}
-
-static inline unsigned char *__skb_pull(struct sk_buff *skb, unsigned int len)
-{
- skb->len -= len;
- //BUG_ON(skb->len < skb->data_len);
- return skb->data += len;
-}
-
-/**
- * skb_pull - remove data from the start of a buffer
- * @skb: buffer to use
- * @len: amount of data to remove
- *
- * This function removes data from the start of a buffer, returning
- * the memory to the headroom. A pointer to the next data in the buffer
- * is returned. Once the data has been pulled future pushes will overwrite
- * the old data.
- */
-static inline unsigned char *skb_pull(struct sk_buff *skb, unsigned int len)
-{
- return unlikely(len > skb->len) ? NULL : __skb_pull(skb, len);
-}
-
-static inline int pskb_may_pull(struct sk_buff *skb, unsigned int len)
-{
- return (len <= skb->len);
-}
-
-static inline unsigned int skb_headlen(const struct sk_buff *skb)
-{
- return skb->len - skb->data_len;
-}
-
-/**
- * skb_headroom - bytes at buffer head
- * @skb: buffer to check
- *
- * Return the number of bytes of free space at the head of an &sk_buff.
- */
-static inline int skb_headroom(const struct sk_buff *skb)
-{
- return skb->data - skb->head;
-}
-
-/**
- * skb_tailroom - bytes at buffer end
- * @skb: buffer to check
- *
- * Return the number of bytes of free space at the tail of an sk_buff
- */
-static inline int skb_tailroom(const struct sk_buff *skb)
-{
- return skb->end - skb->tail;
-}
-
-/**
- * skb_reserve - adjust headroom
- * @skb: buffer to alter
- * @len: bytes to move
- *
- * Increase the headroom of an empty &sk_buff by reducing the tail
- * room. This is only allowed for an empty buffer.
- */
-static inline void skb_reserve(struct sk_buff *skb, unsigned int len)
-{
- skb->data += len;
- skb->tail += len;
-}
-
-/**
- * __skb_queue_purge - empty a list
- * @list: list to empty
- *
- * Delete all buffers on an &sk_buff list. Each buffer is removed from
- * the list and one reference dropped. This function does not take the
- * list lock and the caller must hold the relevant locks to use it.
- */
-extern void skb_queue_purge(struct sk_buff_head *list);
-static inline void __skb_queue_purge(struct sk_buff_head *list)
-{
- struct sk_buff *skb;
- while ((skb = __skb_dequeue(list)) != NULL)
- kfree_skb(skb);
-}
-
-/**
- * __dev_alloc_skb - allocate an skbuff for sending
- * @length: length to allocate
- * @gfp_mask: get_free_pages mask, passed to alloc_skb
- *
- * Allocate a new &sk_buff and assign it a usage count of one. The
- * buffer has unspecified headroom built in. Users should allocate
- * the headroom they think they need without accounting for the
- * built in space. The built in space is used for optimisations.
- *
- * %NULL is returned in there is no free memory.
- */
-static inline struct sk_buff *__dev_alloc_skb(unsigned int length,
- int gfp_mask)
-{
- struct sk_buff *skb = alloc_skb(length + 16, gfp_mask);
- if (likely(skb))
- skb_reserve(skb, 16);
- return skb;
-}
-
-/**
- * dev_alloc_skb - allocate an skbuff for sending
- * @length: length to allocate
- *
- * Allocate a new &sk_buff and assign it a usage count of one. The
- * buffer has unspecified headroom built in. Users should allocate
- * the headroom they think they need without accounting for the
- * built in space. The built in space is used for optimisations.
- *
- * %NULL is returned in there is no free memory. Although this function
- * allocates memory it can be called from an interrupt.
- */
-static inline struct sk_buff *dev_alloc_skb(unsigned int length)
-{
- return __dev_alloc_skb(length, GFP_ATOMIC);
-}
-
-#define MULTICAST(x) (((x) & htonl(0xf0000000)) == htonl(0xe0000000))
-
-#endif /* _VNET_SKBUFF_H */
+++ /dev/null
-#include "spinlock.h"
-
-int atomic_read(const atomic_t *v){
- return v->val;
-}
-
-int atomic_dec_and_test(atomic_t *v){
- if(v->val > 0){
- v->val--;
- return v->val == 0;
- }
- return 0;
-}
-
-void atomic_inc(atomic_t *v){
- v->val++;
-}
-
-void atomic_set(atomic_t *v, int x){
- v->val = x;
-}
-
-void spin_lock_init(spinlock_t *lock){
- *lock = (spinlock_t){};
-}
-
-unsigned long _spin_lock_irqsave(spinlock_t *lock){
- lock->val++;
- return 0;
-}
-
-void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags){
- lock->val--;
-}
-
-unsigned long _read_lock_irqsave(rwlock_t *lock){
- lock->val++;
- return 0;
-}
-
-void read_unlock_irqrestore(rwlock_t *lock, unsigned long flags){
- lock->val--;
-}
-
-unsigned long _write_lock_irqsave(rwlock_t *lock){
- lock->val++;
- return 0;
-}
-
-void write_unlock_irqrestore(rwlock_t *lock, unsigned long flags){
- lock->val--;
-}
-
-void init_MUTEX(struct semaphore *sem){
- *sem = (struct semaphore){ .count = 1 };
-}
-
-void down(struct semaphore *sem){
- sem->count--;
-}
-
-void up(struct semaphore *sem){
- sem->count++;
-}
-
+++ /dev/null
-#ifndef _VNET_SPINLOCK_H_
-#define _VNET_SPINLOCK_H_
-
-typedef struct atomic_t {
- unsigned val;
-} atomic_t;
-
-int atomic_read(const atomic_t *v);
-int atomic_dec_and_test(atomic_t *v);
-void atomic_inc(atomic_t *v);
-void atomic_set(atomic_t *v, int x);
-
-typedef struct spinlock_t {
- unsigned val;
-} spinlock_t;
-
-#define SPIN_LOCK_UNLOCKED ((struct spinlock_t){})
-
-void spin_lock_init(spinlock_t *lock);
-
-unsigned long _spin_lock_irqsave(spinlock_t *lock);
-#define spin_lock_irqsave(lock, flags) flags = _spin_lock_irqsave(lock)
-void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags);
-
-typedef struct rwlock_t{
- unsigned val;
-} rwlock_t;
-
-#define RW_LOCK_UNLOCKED ((struct rwlock_t){})
-
-unsigned long _read_lock_irqsave(rwlock_t *lock);
-#define read_lock_irqsave(lock, flags) flags = _read_lock_irqsave(lock)
-void read_unlock_irqrestore(rwlock_t *lock, unsigned long flags);
-
-unsigned long _write_lock_irqsave(rwlock_t *lock);
-#define write_lock_irqsave(lock, flags) flags = _write_lock_irqsave(lock)
-void write_unlock_irqrestore(rwlock_t *lock, unsigned long flags);
-
-struct semaphore {
- int count;
-};
-
-void init_MUTEX(struct semaphore *sem);
-void down(struct semaphore *sem);
-void up(struct semaphore *sem);
-
-#endif /* ! _VNET_SPINLOCK_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2005 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef _VNET_SYS_KERNEL_H_
-#define _VNET_SYS_KERNEL_H_
-
-/** @file Compatibility replacements for some kernel defs.
- */
-
-#include <assert.h>
-#include <asm/types.h>
-//#include <sys/types.h>
-#include <unistd.h>
-
-#define printk printf
-
-#define likely(x) x
-#define unlikely(x) x
-#define current_text_addr() NULL
-
-#define BUG_ON(x) assert(x)
-#define BUG() BUG_ON(1)
-#define kmalloc(n, m) allocate_type(n, m)
-#define kfree(p) deallocate(p)
-#define in_atomic() 0
-
-#define __init
-#define __exit
-
-#define module_init(x)
-#define module_exit(x)
-#define MODULE_LICENSE(x)
-#define MODULE_PARM(v, t)
-#define module_param(v, t, s)
-#define MODULE_PARM_DESC(v, s)
-
-enum {
- GFP_USER,
- GFP_ATOMIC,
- GFP_KERNEL,
-};
-
-typedef signed char s8;
-typedef unsigned char u8;
-
-typedef signed short s16;
-typedef unsigned short u16;
-
-typedef signed int s32;
-typedef unsigned int u32;
-
-typedef signed long long s64;
-typedef unsigned long long u64;
-
-#include "allocate.h"
-
-#endif /* ! _VNET_SYS_KERNEL_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <sys/time.h>
-#include <time.h>
-
-#include "allocate.h"
-#include "timer.h"
-
-#define MODULE_NAME "TIMER"
-#undef DEBUG
-#define DEBUG 1
-#include "debug.h"
-
-static Timer *timers = NULL;
-
-/** Get the time now as a double (in seconds).
- * Returns zero if could not get the time.
- *
- * @return time now
- */
-double time_now(void){
- struct timeval time;
- if(gettimeofday(&time, NULL)) return 0.0;
- return (double)time.tv_sec + (1.0e-6 * (double)time.tv_usec);
-}
-
-/** Set the process real-time timer to go off at a given expiry time.
- * The timer will not be set to go off in less than 10 ms
- * (even if the expiry time is sooner, or in the past).
- *
- * @param expiry time (in seconds)
- * @return 0 on success, error code otherwise
- */
-static int itimer_set(double expiry){
- struct itimerval val = {};
- struct itimerval old = {};
- double now, delay;
- int err = 0;
-
- if(expiry == 0.0){
- val.it_value.tv_sec = 0;
- val.it_value.tv_usec = 0;
- } else {
- now = time_now();
- delay = expiry - now;
- if(delay < 0.01) delay = 0.01;
- val.it_value.tv_sec = (long)delay;
- val.it_value.tv_usec = (long)((delay - (double)(long)delay) * 1.0e6);
- }
- err = setitimer(ITIMER_REAL, &val, &old);
- return err;
-}
-
-void Timer_free(Timer *z){
-#ifndef USE_GC
- if(!z) return;
- deallocate(z);
-#endif
-}
-
-/** Process any expired timers.
- * Calls the functions of expired timers and removes them
- * from the timer list.
- * Reschedules the interval timer for the earliest expiring timer
- * (if any).
- *
- * Should not be called from within the SIGALRM handler - set
- * a flag there and call it later.
- *
- * @return 0 on success, error code otherwise.
- */
-int process_timers(void){
- double now = time_now();
- Timer *curr, *next;
- for(curr = timers; curr; curr = next){
- next = curr->next;
- if(curr->expiry > now) break;
- if(curr->fn) curr->fn(curr->data);
- }
- timers = curr;
- itimer_set((curr ? curr->expiry : 0));
- return 0;
-}
-
-void Timer_add(Timer *timer){
- // Insert timer in list ordered by (increasing) expiry time.
- Timer *prev, *curr, *next;
- prev = NULL;
- for(curr = timers; curr; prev = curr, curr = next){
- next = curr->next;
- if(timer->expiry < curr->expiry) break;
- }
- if(prev){
- prev->next = timer;
- } else {
- timers = timer;
- }
- timer->next = curr;
-
- // Set interval timer to go off for earliest expiry time.
- itimer_set(timer->expiry);
-}
-
-Timer * Timer_set(double delay, TimerFn *fn, unsigned long data){
- // Get 'now'.
- double now = time_now();
- Timer *timer = NULL;
- timer = ALLOCATE(Timer);
- if(!timer) goto exit;
- // Add delay to now to get expiry time.
- timer->expiry = now + delay;
- timer->fn = fn;
- timer->data = data;
-
- Timer_add(timer);
- exit:
- return timer;
-}
-
-int Timer_cancel(Timer *timer){
- // Remove timer from list.
- int err = -ENOENT;
- Timer *prev, *curr, *next;
- for(prev = NULL, curr = timers; curr; prev = curr, curr = next){
- next = curr->next;
- if(curr == timer){
- err = 0;
- if(prev){
- prev->next = curr->next;
- } else {
- timers = curr->next;
- }
- curr->next = NULL;
- break;
- }
- }
- return err;
-}
-
+++ /dev/null
-/*
- * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _VNET_TIMER_H_
-#define _VNET_TIMER_H_
-
-struct Timer;
-
-typedef void TimerFn(unsigned long);
-
-typedef struct Timer {
- struct Timer *next;
- TimerFn *fn;
- unsigned long data;
- double expiry;
-} Timer;
-
-extern void timer_alarm(void);
-extern double time_now(void);
-extern int process_timers(void);
-extern Timer * Timer_set(double delay, TimerFn *fn, unsigned long data);
-extern void Timer_add(Timer *timer);
-extern int Timer_cancel(Timer *timer);
-
-#endif /* ! _VNET_TIMER_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2005, 2006 Mike Wray <mike.wray@hp.com>.
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <stdlib.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <getopt.h>
-#include <errno.h>
-#include <time.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <string.h>
-
-#include <signal.h>
-#include <sys/wait.h>
-#include <sys/select.h>
-
-#include <asm/types.h> // For __u32 etc.
-
-#include <linux/ip.h> // For struct iphdr.
-#include <linux/udp.h> // For struct udphdr.
-
-#include <linux/if.h>
-#include <linux/if_ether.h>
-#include <linux/if_tun.h>
-
-#include "sys_kernel.h"
-#include "skbuff.h"
-#include "spinlock.h"
-
-#include "allocate.h"
-
-#include "file_stream.h"
-#include "string_stream.h"
-#include "socket_stream.h"
-#include "sys_net.h"
-
-#include "enum.h"
-#include "sxpr.h"
-#include "sxpr_parser.h"
-
-#include "connection.h"
-#include "select.h"
-#include "timer.h"
-
-#include "if_etherip.h"
-#include "if_varp.h"
-#include "varp.h"
-#include "vnet.h"
-#include "vnet_dev.h"
-#include "vnet_eval.h"
-#include "vnet_forward.h"
-#include "tunnel.h"
-#include "etherip.h"
-#include "sxpr_util.h"
-
-#define MODULE_NAME "VNETD"
-#define DEBUG 1
-#undef DEBUG
-#include "debug.h"
-
-#define PROGRAM "vnetd"
-#define VERSION "1.0"
-
-typedef struct Vnetd {
- unsigned long port;
- int ttl;
- int verbose;
- int etherip;
-
- int udp_sock;
- struct sockaddr_in udp_sock_addr;
- int mcast_sock;
- struct sockaddr_in mcast_sock_addr;
- int etherip_sock;
- struct sockaddr_in etherip_sock_addr;
- int unix_sock;
- char *unix_path;
-
- int raw_sock;
-
- struct sockaddr_in ucast_addr;
- struct sockaddr_in mcast_addr;
-
- HashTable *vnet_table;
-
- ConnList *conns;
-
-} Vnetd;
-
-Vnetd _vnetd = {}, *vnetd = &_vnetd;
-
-uint32_t vnetd_intf_addr(Vnetd *vnetd){
- return vnetd->ucast_addr.sin_addr.s_addr;
-}
-
-uint32_t vnetd_mcast_addr(Vnetd *vnetd){
- return vnetd->mcast_addr.sin_addr.s_addr;
-}
-
-void vnetd_set_mcast_addr(Vnetd *vnetd, uint32_t addr){
- varp_mcast_addr = addr;
- vnetd->mcast_addr.sin_addr.s_addr = addr;
-}
-
-uint16_t vnetd_mcast_port(Vnetd *vnetd){
- return vnetd->mcast_addr.sin_port;
-}
-
-uint32_t vnetd_addr(void){
- return vnetd_intf_addr(vnetd);
-}
-
-/** Open tap device.
- */
-int tap_open(struct net_device *dev){
- int err;
- /* IFF_TAP : Ethernet tap device.
- * IFF_NO_PI : Don't add packet info struct when reading.
- * IFF_ONE_QUEUE: Drop packets when the dev queue is full. The driver uses
- * the queue size from the device, which defaults to 1000 for etherdev.
- * If not set the driver stops the device queue when it goes over
- * TUN_READQ_SIZE, which is 10. Broken - makes the device stall
- * under load.
- */
- struct ifreq ifr = { };
- ifr.ifr_flags = (IFF_TAP | IFF_NO_PI | IFF_ONE_QUEUE);
-
- dprintf(">\n");
- dev->tapfd = open("/dev/net/tun", O_RDWR);
- if(dev->tapfd < 0){
- err = -errno;
- perror("open");
- goto exit;
- }
- strcpy(ifr.ifr_name, dev->name);
- err = ioctl(dev->tapfd, TUNSETIFF, (void *)&ifr);
- if(err < 0){
- err = -errno;
- perror("ioctl");
- goto exit;
- }
- strcpy(dev->name, ifr.ifr_name);
- dprintf("> dev=%s\n", dev->name);
- // Make it non-blocking.
- fcntl(dev->tapfd, F_SETFL, O_NONBLOCK);
-
- exit:
- if(err && (dev->tapfd >= 0)){
- close(dev->tapfd);
- dev->tapfd = -1;
- }
- dprintf("< err=%d\n", err);
- return err;
-}
-
-/** Close tap device.
- */
-int tap_close(struct net_device *dev){
- int err = 0;
-
- if(dev->tapfd >= 0){
- err = close(dev->tapfd);
- dev->tapfd = -1;
- }
- return err;
-}
-
-/** Open vnif tap device for a vnet.
- */
-int vnet_dev_add(struct Vnet *vnet){
- int err = 0;
- struct net_device *dev = ALLOCATE(struct net_device);
- strcpy(dev->name, vnet->device);
- err = tap_open(dev);
- if(err){
- wprintf("> Unable to open tap device.\n"
- "The tun module must be loaded and\n"
- "the vnet kernel module must not be loaded.\n");
- deallocate(dev);
- goto exit;
- }
- vnet->dev = dev;
- exit:
- return err;
-}
-
-/** Close vnif tap device for a vnet.
- */
-void vnet_dev_remove(struct Vnet *vnet){
- if(vnet->dev){
- tap_close(vnet->dev);
- deallocate(vnet->dev);
- vnet->dev = NULL;
- }
-}
-
-/** Receive decapsulated ethernet packet on skb->dev.
- * Always succeeds. The skb must not be referred to after
- * this is called.
- */
-int netif_rx(struct sk_buff *skb){
- int err = 0, n, k;
- struct net_device *dev = skb->dev;
- if(!dev){
- err = -ENODEV;
- goto exit;
- }
- n = skb->tail - skb->mac.raw;
- k = write(dev->tapfd, skb->mac.raw, n);
- if(k < 0){
- err = -errno;
- perror("write");
- } else if(k < n){
- //todo: What?
- }
- exit:
- kfree_skb(skb);
- return err;
-}
-
-static const int SKB_SIZE = 1700;
-
-struct sk_buff *skb_new(void){
- return alloc_skb(SKB_SIZE, GFP_ATOMIC);
-}
-
-/** Receive a packet and fill-in source and destination addresses.
- * Just like recvfrom() but adds the destination address.
- * The socket must have the IP_PKTINFO option set so that the
- * destination address information is available.
- *
- * @param sock socket
- * @param buf receive buffer
- * @param len size of buffer
- * @param flags receive flags
- * @param from source address
- * @param fromlen size of source address
- * @param dest destination address
- * @param destlen size of destination address
- * @return number of bytes read on success, negative otherwise
- */
-int recvfromdest(int sock, void *buf, size_t len, int flags,
- struct sockaddr *from, socklen_t *fromlen,
- struct sockaddr *dest, socklen_t *destlen){
- int ret = 0;
- struct iovec iov;
- struct msghdr msg;
- struct cmsghdr *cmsg;
- char cbuf[1024];
- struct in_pktinfo *info;
- struct sockaddr_in *dest_in = (struct sockaddr_in *)dest;
-
- //dest_in->sin_family = AF_INET;
- //dest_in->sin_port = 0;
- getsockname(sock, dest, destlen);
-
- iov.iov_base = buf;
- iov.iov_len = len;
- msg.msg_name = from;
- msg.msg_namelen = *fromlen;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = cbuf;
- msg.msg_controllen = sizeof(cbuf);
-
- ret = recvmsg(sock, &msg, flags);
- if(ret < 0) goto exit;
- *fromlen = msg.msg_namelen;
-
- for(cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)){
- if((cmsg->cmsg_level == SOL_IP) && (cmsg->cmsg_type == IP_PKTINFO)){
- info = (void*)CMSG_DATA(cmsg);
- dest_in->sin_addr = info->ipi_addr;
- break;
- }
- }
-
- exit:
- return ret;
-}
-
-/** Read an skb from a udp socket and fill in its headers.
- */
-int skb_recv_udp(int sock, int flags,
- struct sockaddr_in *peer, socklen_t *peer_n,
- struct sockaddr_in *dest, socklen_t *dest_n,
- struct sk_buff **pskb){
- int err = 0, n;
- struct sk_buff *skb = skb_new();
-
- skb->mac.raw = skb->data;
- skb_reserve(skb, ETH_HLEN);
- skb->nh.raw = skb->data;
- skb_reserve(skb, sizeof(struct iphdr));
- // Rcvr wants skb->data pointing at the udphdr.
- skb->h.raw = skb_put(skb, sizeof(struct udphdr));
- n = recvfromdest(sock, skb->tail, skb_tailroom(skb), flags,
- (struct sockaddr *)peer, peer_n,
- (struct sockaddr *)dest, dest_n);
- if(n < 0){
- err = -errno;
- //perror("recvfrom");
- goto exit;
- }
- dprintf("> peer=%s:%d\n", inet_ntoa(peer->sin_addr), ntohs(peer->sin_port));
- dprintf("> dest=%s:%d\n", inet_ntoa(dest->sin_addr), ntohs(dest->sin_port));
- skb_put(skb, n);
- skb->protocol = skb->nh.iph->protocol = IPPROTO_UDP;
- skb->nh.iph->saddr = peer->sin_addr.s_addr;
- skb->h.uh->source = peer->sin_port;
- skb->nh.iph->daddr = dest->sin_addr.s_addr;
- skb->h.uh->dest = dest->sin_port;
- exit:
- if(err < 0){
- kfree_skb(skb);
- *pskb = NULL;
- } else {
- *pskb = skb;
- }
- return (err < 0 ? err : n);
-}
-
-/** Read an skb fom a raw socket and fill in its headers.
- */
-int skb_recv_raw(int sock, int flags,
- struct sockaddr_in *peer, socklen_t *peer_n,
- struct sockaddr_in *dest, socklen_t *dest_n,
- struct sk_buff **pskb){
- int err = 0, n;
- struct sk_buff *skb = skb_new();
-
- skb->mac.raw = skb->data;
- skb_reserve(skb, ETH_HLEN);
- skb->nh.raw = skb->data;
- skb_reserve(skb, sizeof(struct iphdr));
- // Rcvr wants skb->data pointing after ip hdr, at raw protocol hdr.
- n = recvfromdest(sock, skb->tail, skb_tailroom(skb), flags,
- (struct sockaddr *)peer, peer_n,
- (struct sockaddr *)dest, dest_n);
- if(n < 0){
- err = -errno;
- //perror("recvfrom");
- goto exit;
- }
- skb_put(skb, n);
- // On a raw socket the port in the address is the protocol.
- skb->protocol = skb->nh.iph->protocol = peer->sin_port;
- skb->nh.iph->saddr = peer->sin_addr.s_addr;
- skb->nh.iph->daddr = dest->sin_addr.s_addr;
- exit:
- if(err < 0){
- kfree_skb(skb);
- *pskb = NULL;
- } else {
- *pskb = skb;
- }
- return (err < 0 ? err : n);
-}
-
-/** Read an skb from a file descriptor.
- * Used for skbs coming to us from the tap device.
- * The skb content is an ethernet frame.
- */
-int skb_read(int fd, struct sk_buff **pskb){
- int err = 0, n;
- struct sk_buff *skb = skb_new();
-
- // Reserve space for the headers we will add.
- skb_reserve(skb, 100);
- // Rcvr will want ethhdr on the skb.
- skb->mac.raw = skb->tail;
- n = read(fd, skb->tail, skb_tailroom(skb));
- if(n < 0){
- err = -errno;
- //perror("read");
- goto exit;
- }
- skb_put(skb, n);
- exit:
- if(err < 0){
- kfree_skb(skb);
- *pskb = NULL;
- } else {
- *pskb = skb;
- }
- return (err < 0 ? err : n);
-}
-
-/** Read an skb from the tap device for a vnet and send it.
- */
-int vnet_read(Vnet *vnet){
- int err;
- struct sk_buff *skb = NULL;
-
- err = skb_read(vnet->dev->tapfd, &skb);
- if(err < 0) goto exit;
- err = vnet_skb_send(skb, &vnet->vnet);
- exit:
- if(skb) kfree_skb(skb);
- return (err < 0 ? err : 0);
-}
-
-/** Transmit an skb to the network.
- */
-int _skb_xmit(struct sk_buff *skb, uint32_t saddr){
- int err = 0;
- int sock;
- unsigned char *data;
- struct sockaddr_in addr = { .sin_family = AF_INET };
- int flags = 0;
-
- if(saddr){
- dprintf("> Raw IP send\n");
- sock = vnetd->raw_sock;
- skb->nh.iph->saddr = saddr;
- addr.sin_addr.s_addr = skb->nh.iph->daddr;
- // Should be the protocol, but is ignored. See raw(7) man page.
- addr.sin_port = 0;
- // Data includes the ip header.
- data = (void*)(skb->nh.iph);
- } else {
- switch(skb->nh.iph->protocol){
- case IPPROTO_UDP:
- dprintf("> protocol=UDP\n");
- sock = vnetd->udp_sock;
- // Data comes after the udp header.
- data = (void*)(skb->h.uh + 1);
- addr.sin_addr.s_addr = skb->nh.iph->daddr;
- addr.sin_port = skb->h.uh->dest;
- break;
- case IPPROTO_ETHERIP:
- dprintf("> protocol=ETHERIP\n");
- if(vnetd->etherip_sock < 0){
- err = -ENOSYS;
- goto exit;
- }
- sock = vnetd->etherip_sock;
- // Data comes after the ip header.
- data = (void*)(skb->nh.iph + 1);
- addr.sin_addr.s_addr = skb->nh.iph->daddr;
- // Should be the protocol, but is ignored. See raw(7) man page.
- addr.sin_port = 0;
- break;
- default:
- err = -ENOSYS;
- wprintf("> protocol=%d, %d\n", skb->nh.iph->protocol, skb->protocol);
- goto exit;
- }
- }
-
- dprintf("> sending %d bytes to %s:%d protocol=%d\n",
- skb->tail - data,
- inet_ntoa(addr.sin_addr),
- ntohs(addr.sin_port),
- skb->nh.iph->protocol);
-
- err = sendto(sock, data, skb->tail - data, flags,
- (struct sockaddr *)&addr, sizeof(addr));
- if(err < 0){
- err = -errno;
- perror("sendto");
- }
- exit:
- if(err >= 0){
- // Caller will assume skb freed if no error.
- kfree_skb(skb);
- err = 0;
- }
- dprintf("< err=%d\n", err);
- return err;
-}
-
-int varp_open(uint32_t mcaddr, uint16_t port){
- return 0;
-}
-
-void varp_close(void){
-}
-
-/** Create a raw socket.
- *
- * @param protocol protocol
- * @param flags flags (VSOCK_*)
- * @param mcaddr multicast addr used with flag VSOCK_MULTICAST
- * @param sock return value for the socket
- */
-int vnetd_raw_socket(Vnetd *vnetd, int protocol, int flags,
- uint32_t mcaddr, int *sock){
- int err;
- int bcast = (flags & VSOCK_BROADCAST);
-
- err = *sock = socket(AF_INET, SOCK_RAW, protocol);
- if(err < 0){
- err = -errno;
- perror("socket");
- goto exit;
- }
- if(bcast){
- err = setsock_broadcast(*sock, bcast);
- if(err < 0) goto exit;
- }
- if(flags & VSOCK_MULTICAST){
- err = setsock_multicast(*sock, INADDR_ANY, mcaddr);
- if(err < 0) goto exit;
- }
- //todo ?? fcntl(*sock, F_SETFL, O_NONBLOCK);
- exit:
- return err;
-}
-
-int get_dev_address(char *dev, unsigned long *addr){
- int err = 0;
- int sock = -1;
- struct ifreq ifreq = {};
- struct sockaddr_in *in_addr;
-
- sock = socket(AF_INET, SOCK_DGRAM, 0);
- if(sock < 0){
- err = -errno;
- goto exit;
- }
- strncpy(ifreq.ifr_name, dev, IFNAMSIZ);
- err = ioctl(sock, SIOCGIFADDR, &ifreq);
- if(err){
- err = -errno;
- goto exit;
- }
- in_addr = (struct sockaddr_in *) &ifreq.ifr_addr;
- *addr = in_addr->sin_addr.s_addr;
- //iprintf("> dev=%s addr=%s\n", dev, inet_ntoa(in_addr->sin_addr));
- exit:
- if(sock >= 0) close(sock);
- return err;
-}
-
-int get_intf_address(unsigned long *addr){
- int err = 0;
- char *devs[] = { "xen-br0", "eth0", "eth1", "eth2", NULL };
- char **dev;
-
- for(dev = devs; *dev; dev++){
- err = get_dev_address(*dev, addr);
- if(err == 0) goto exit;
- }
- err = -ENOSYS;
- exit:
- return err;
-}
-
-/** Get our own address. So we can ignore broadcast traffic
- * we sent ourselves.
- *
- * @param addr
- * @return 0 on success, error code otherwise
- */
-int get_self_addr(struct sockaddr_in *addr){
- int err = 0;
- char hostname[1024] = {};
- unsigned long saddr;
-
- err = gethostname(hostname, sizeof(hostname) - 1);
- if(err){
- err = -errno;
- perror("gethostname");
- goto exit;
- }
- err = get_host_address(hostname, &saddr);
- if(err) goto exit;
- addr->sin_addr.s_addr = saddr;
- if(saddr == htonl(INADDR_LOOPBACK)){
- err = get_intf_address(&saddr);
- if(err) goto exit;
- }
- addr->sin_addr.s_addr = saddr;
- err = 0;
- exit:
- return err;
-}
-
-static int eval_vnetd_mcaddr(Sxpr exp, IOStream *out, void *data){
- int err = 0;
- Vnetd *vnetd = data;
- Sxpr oaddr = intern("addr");
- Sxpr ottl = intern("ttl");
- uint32_t addr;
- int ttl;
-
- err = child_addr(exp, oaddr, &addr);
- if(err < 0) goto exit;
- vnetd_set_mcast_addr(vnetd, addr);
- if(child_int(exp, ottl, &ttl) == 0){
- vnetd->ttl = ttl;
- }
- exit:
- return err;
-}
-
-static int vnetd_eval_io(Vnetd *vnetd, Parser *parser, SxprEval *defs,
- IOStream *in, IOStream *out){
- int err = 0;
- char buf[1024];
- int k, n = sizeof(buf) - 1;
-
- for( ; ; ){
- k = IOStream_read(in, buf, n);
- if(k < 0){
- err = k;
- goto exit;
- }
- err = Parser_input(parser, buf, k);
- if(err < 0) goto exit;
- while(Parser_ready(parser)){
- Sxpr exp = Parser_get_val(parser);
- if(NONEP(exp)) break;
- err = vnet_eval_defs(defs, exp, out, vnetd);
- if(err) goto exit;
- }
- if(Parser_at_eof(parser)) break;
- }
- exit:
- return err;
-}
-
-static int vnetd_configure(Vnetd *vnetd, char *file){
- int err = 0;
- Parser *parser = NULL;
- IOStream *io = NULL;
- SxprEval defs[] = {
- { .name = intern("peer.add"), .fn = eval_peer_add },
- { .name = intern("varp.mcaddr"), .fn = eval_vnetd_mcaddr },
- { .name = intern("vnet.add"), .fn = eval_vnet_add },
- { .name = ONONE, .fn = NULL } };
-
- parser = Parser_new();
- io = file_stream_fopen(file, "rb");
- if(!io){
- err = -errno;
- goto exit;
- }
- vnetd_eval_io(vnetd, parser, defs, io, iostdout);
- exit:
- if(io) IOStream_close(io);
- Parser_free(parser);
- return err;
-}
-
-#define OPT_MCADDR 'a'
-#define KEY_MCADDR "varp_mcaddr"
-#define DOC_MCADDR "<addr>\n\t VARP multicast address"
-
-#define OPT_FILE 'f'
-#define KEY_FILE "file"
-#define DOC_FILE "<file>\n\t Configuration file to load"
-
-#define OPT_HELP 'h'
-#define KEY_HELP "help"
-#define DOC_HELP "\n\tprint help"
-
-#define OPT_VERSION 'v'
-#define KEY_VERSION "version"
-#define DOC_VERSION "\n\tprint version"
-
-#define OPT_VERBOSE 'V'
-#define KEY_VERBOSE "verbose"
-#define DOC_VERBOSE "\n\tverbose flag"
-
-/** Print a usage message.
- * Prints to stdout if err is zero, and exits with 0.
- * Prints to stderr if err is non-zero, and exits with 1.
- *
- * @param err error code
- */
-static void usage(int err){
- FILE *out = (err ? stderr : stdout);
-
- fprintf(out, "Usage: %s [options]\n", PROGRAM);
- fprintf(out, "-%c, --%s %s\n", OPT_MCADDR, KEY_MCADDR, DOC_MCADDR);
- fprintf(out, "-%c, --%s %s\n", OPT_FILE, KEY_FILE, DOC_FILE);
- fprintf(out, "-%c, --%s %s\n", OPT_VERBOSE, KEY_VERBOSE, DOC_VERBOSE);
- fprintf(out, "-%c, --%s %s\n", OPT_VERSION, KEY_VERSION, DOC_VERSION);
- fprintf(out, "-%c, --%s %s\n", OPT_HELP, KEY_HELP, DOC_HELP);
- exit(err ? 1 : 0);
-}
-
-/** Short options. Options followed by ':' take an argument. */
-static char *short_opts = (char[]){
- OPT_MCADDR, ':',
- OPT_FILE, ':',
- OPT_HELP,
- OPT_VERSION,
- OPT_VERBOSE,
- 0 };
-
-/** Long options. */
-static struct option const long_opts[] = {
- { KEY_MCADDR, required_argument, NULL, OPT_MCADDR },
- { KEY_FILE, required_argument, NULL, OPT_FILE },
- { KEY_HELP, no_argument, NULL, OPT_HELP },
- { KEY_VERSION, no_argument, NULL, OPT_VERSION },
- { KEY_VERBOSE, no_argument, NULL, OPT_VERBOSE },
- { NULL, 0, NULL, 0 }
-};
-
-static int vnetd_getopts(Vnetd *vnetd, int argc, char *argv[]){
- int err = 0;
- int key = 0;
- int long_index = 0;
-
- while(1){
- key = getopt_long(argc, argv, short_opts, long_opts, &long_index);
- if(key == -1) break;
- switch(key){
- case OPT_MCADDR: {
- unsigned long addr;
- err = get_inet_addr(optarg, &addr);
- if(err) goto exit;
- vnetd_set_mcast_addr(vnetd, addr);
- break; }
- case OPT_FILE:
- err = vnetd_configure(vnetd, optarg);
- if(err) goto exit;
- break;
- case OPT_HELP:
- usage(0);
- break;
- case OPT_VERBOSE:
- vnetd->verbose = true;
- break;
- case OPT_VERSION:
- iprintf("> %s %s\n", PROGRAM, VERSION);
- exit(0);
- break;
- default:
- usage(EINVAL);
- break;
- }
- }
- exit:
- return err;
-}
-
-/** Initialise vnetd params.
- *
- * @param vnetd vnetd
- */
-static int vnetd_init(Vnetd *vnetd, int argc, char *argv[]){
- int err = 0;
-
- // Use etherip-in-udp encapsulation.
- etherip_in_udp = true;
-
- *vnetd = (Vnetd){};
- vnetd->port = htons(VARP_PORT);
- vnetd->verbose = false;
- vnetd->ttl = 1; // Default multicast ttl.
- vnetd->etherip = true;
- vnetd->udp_sock = -1;
- vnetd->mcast_sock = -1;
- vnetd->etherip_sock = -1;
- vnetd_set_mcast_addr(vnetd, htonl(VARP_MCAST_ADDR));
- vnetd->mcast_addr.sin_port = vnetd->port;
- vnetd->unix_path = "/tmp/vnetd";
-
- vnetd_getopts(vnetd, argc, argv);
-
- err = get_self_addr(&vnetd->ucast_addr);
- vnetd->ucast_addr.sin_port = vnetd->port;
- dprintf("> mcaddr=%s\n", inet_ntoa(vnetd->mcast_addr.sin_addr));
- dprintf("> addr =%s\n", inet_ntoa(vnetd->ucast_addr.sin_addr));
- return err;
-}
-
-static void vnet_select(Vnetd *vnetd, SelectSet *set){
- HashTable_for_decl(entry);
-
- HashTable_for_each(entry, vnetd->vnet_table){
- Vnet *vnet = entry->value;
- struct net_device *dev = vnet->dev;
- if(!dev) continue;
- if(dev->tapfd < 0) continue;
- SelectSet_add(set, dev->tapfd, SELECT_READ);
- }
-}
-
-static void vnet_handle(Vnetd *vnetd, SelectSet *set){
- HashTable_for_decl(entry);
-
- HashTable_for_each(entry, vnetd->vnet_table){
- Vnet *vnet = entry->value;
- struct net_device *dev = vnet->dev;
- if(!dev) continue;
- if(dev->tapfd < 0) continue;
- if(SelectSet_in_read(set, dev->tapfd)){
- int n;
- for(n = 64; n > 0; --n){
- if(vnet_read(vnet) < 0) break;
- }
- }
- }
-}
-
-static int vnetd_handle_udp(Vnetd *vnetd, struct sockaddr_in *addr, int sock){
- int err = 0, n = 0;
- struct sockaddr_in peer, dest;
- socklen_t peer_n = sizeof(peer), dest_n = sizeof(dest);
- int flags = MSG_DONTWAIT;
- struct sk_buff *skb = NULL;
-
- dest = *addr;
- n = skb_recv_udp(sock, flags, &peer, &peer_n, &dest, &dest_n, &skb);
- if(n < 0){
- err = n;
- goto exit;
- }
- dprintf("> Received %d bytes from=%s:%d dest=%s:%d\n",
- n,
- inet_ntoa(peer.sin_addr), htons(peer.sin_port),
- inet_ntoa(dest.sin_addr), htons(dest.sin_port));
- if(peer.sin_addr.s_addr == vnetd_intf_addr(vnetd)){
- dprintf("> Ignoring message from self.\n");
- goto exit;
- }
- if(dest.sin_addr.s_addr == vnetd_mcast_addr(vnetd)){
- vnet_forward_send(skb);
- }
- err = varp_handle_message(skb);
-
- exit:
- if(skb) kfree_skb(skb);
- return err;
-}
-
-static int vnetd_handle_etherip(Vnetd *vnetd, struct sockaddr_in *addr, int sock){
- int err = 0, n = 0;
- struct sockaddr_in peer, dest;
- socklen_t peer_n = sizeof(peer), dest_n = sizeof(dest);
- int flags = 0;
- struct sk_buff *skb = NULL;
-
- dest = *addr;
- n = skb_recv_raw(sock, flags, &peer, &peer_n, &dest, &dest_n, &skb);
- if(n < 0){
- err = n;
- goto exit;
- }
- dprintf("> Received %d bytes from=%s:%d dest=%s:%d\n",
- n,
- inet_ntoa(peer.sin_addr), htons(peer.sin_port),
- inet_ntoa(dest.sin_addr), htons(dest.sin_port));
- if(peer.sin_addr.s_addr == vnetd_intf_addr(vnetd)){
- dprintf("> Ignoring message from self.\n");
- goto exit;
- }
- err = etherip_protocol_recv(skb);
- exit:
- if(skb) kfree_skb(skb);
- return err;
-}
-
-typedef struct ConnClient {
- Vnetd *vnetd;
- Parser *parser;
-} ConnClient;
-
-static int conn_handle_fn(Conn *conn, int mode){
- int err;
- ConnClient *client = conn->data;
- char data[1024] = {};
- int k;
- int done = false;
-
- k = IOStream_read(conn->in, data, sizeof(data));
- if(k < 0){
- err = k;
- goto exit;
- }
- if(!client->parser){
- err = -ENOSYS;
- goto exit;
- }
- if((k == 0) && Parser_at_eof(client->parser)){
- err = -EINVAL;
- goto exit;
- }
- err = Parser_input(client->parser, data, k);
- if(err < 0) goto exit;
- while(Parser_ready(client->parser)){
- Sxpr sxpr = Parser_get_val(client->parser);
- err = vnet_eval(sxpr, conn->out, NULL);
- if(err) goto exit;
- done = true;
- }
- if(done || Parser_at_eof(client->parser)){
- // Close at EOF.
- err = -EIO;
- }
- exit:
- if(err < 0){
- Parser_free(client->parser);
- client->parser = NULL;
- }
- return (err < 0 ? err : 0);
-}
-
-static int vnetd_handle_unix(Vnetd *vnetd, int sock){
- int err;
- ConnClient *client = NULL;
- Conn *conn = NULL;
- struct sockaddr_un peer = {};
- socklen_t peer_n = sizeof(peer);
- int peersock;
-
- peersock = accept(sock, (struct sockaddr *)&peer, &peer_n);
- if(peersock < 0){
- perror("accept");
- err = -errno;
- goto exit;
- }
- // We want non-blocking i/o.
- fcntl(peersock, F_SETFL, O_NONBLOCK);
- client = ALLOCATE(ConnClient);
- client->vnetd = vnetd;
- client->parser = Parser_new();
- conn = Conn_new(conn_handle_fn, client);
- err = Conn_init(conn, peersock, SOCK_STREAM, SELECT_READ,
- (struct sockaddr_in){});
- if(err) goto exit;
- vnetd->conns = ConnList_add(vnetd->conns, conn);
- exit:
- if(err){
- Conn_close(conn);
- close(peersock);
- }
- if(err < 0) wprintf("< err=%d\n", err);
- return err;
-}
-
-static void vnetd_select(Vnetd *vnetd, SelectSet *set){
- SelectSet_add(set, vnetd->unix_sock, SELECT_READ);
- SelectSet_add(set, vnetd->udp_sock, SELECT_READ);
- SelectSet_add(set, vnetd->mcast_sock, SELECT_READ);
- if(vnetd->etherip_sock >= 0){
- SelectSet_add(set, vnetd->etherip_sock, SELECT_READ);
- }
- vnet_select(vnetd, set);
- ConnList_select(vnetd->conns, set);
-}
-
-static void vnetd_handle(Vnetd *vnetd, SelectSet *set){
- if(SelectSet_in_read(set, vnetd->unix_sock)){
- vnetd_handle_unix(vnetd, vnetd->unix_sock);
- }
- if(SelectSet_in_read(set, vnetd->udp_sock)){
- int n;
-
- for(n = 256; n > 0; --n){
- if(vnetd_handle_udp(vnetd, &vnetd->udp_sock_addr, vnetd->udp_sock) < 0){
- break;
- }
- }
- }
- if(SelectSet_in_read(set, vnetd->mcast_sock)){
- vnetd_handle_udp(vnetd, &vnetd->mcast_sock_addr, vnetd->mcast_sock);
- }
- if((vnetd->etherip_sock >= 0) &&
- SelectSet_in_read(set, vnetd->etherip_sock)){
- vnetd_handle_etherip(vnetd, &vnetd->etherip_sock_addr, vnetd->etherip_sock);
- }
- vnet_handle(vnetd, set);
- vnetd->conns = ConnList_handle(vnetd->conns, set);
-}
-
-/** Counter for timer alarms.
- */
-static unsigned timer_alarms = 0;
-
-static int vnetd_main(Vnetd *vnetd){
- int err = 0;
- SelectSet _set = {}, *set = &_set;
- struct timeval _timeout = {}, *timeout = &_timeout;
-
- vnetd->vnet_table = vnet_table;
-
- for( ; ; ){
- timeout->tv_sec = 0;
- timeout->tv_usec = 500000;
- SelectSet_zero(set);
- vnetd_select(vnetd, set);
- err = SelectSet_select(set, timeout);
- if(err == 0) continue;
- if(err < 0){
- switch(errno){
- case EINTR:
- if(timer_alarms){
- timer_alarms = 0;
- process_timers();
- }
- continue;
- case EBADF:
- continue;
- default:
- perror("select");
- goto exit;
- }
- }
- vnetd_handle(vnetd, set);
- }
- exit:
- return err;
-}
-
-static int getsockaddr(int sock, struct sockaddr_in *addr){
- socklen_t addr_n = sizeof(struct sockaddr_in);
- return getsockname(sock, (struct sockaddr*)addr, &addr_n);
-}
-
-static int vnetd_etherip_sock(Vnetd *vnetd){
- int err = 0;
-
- if(!vnetd->etherip) goto exit;
- err = vnetd_raw_socket(vnetd, IPPROTO_ETHERIP,
- (VSOCK_BROADCAST | VSOCK_MULTICAST),
- vnetd_mcast_addr(vnetd),
- &vnetd->etherip_sock);
- if(err < 0) goto exit;
- err = setsock_pktinfo(vnetd->etherip_sock, true);
- if(err < 0) goto exit;
- getsockaddr(vnetd->etherip_sock, &vnetd->etherip_sock_addr);
- exit:
- return err;
-}
-
-static int vnetd_udp_sock(Vnetd *vnetd){
- int err;
- uint32_t mcaddr = vnetd_mcast_addr(vnetd);
-
- err = create_socket(SOCK_DGRAM, INADDR_ANY, vnetd->port,
- (VSOCK_BIND | VSOCK_REUSE),
- &vnetd->udp_sock);
- if(err < 0) goto exit;
- err = setsock_pktinfo(vnetd->udp_sock, true);
- if(err < 0) goto exit;
- getsockaddr(vnetd->udp_sock, &vnetd->udp_sock_addr);
- vnetd->mcast_sock_addr.sin_addr.s_addr = vnetd_intf_addr(vnetd);
-
- err = create_socket(SOCK_DGRAM, mcaddr, vnetd_mcast_port(vnetd),
- (VSOCK_REUSE | VSOCK_BROADCAST | VSOCK_MULTICAST),
- &vnetd->mcast_sock);
- if(err < 0) goto exit;
- err = setsock_pktinfo(vnetd->udp_sock, true);
- if(err < 0) goto exit;
- err = setsock_multicast(vnetd->mcast_sock, INADDR_ANY, mcaddr);
- if(err < 0) goto exit;
- err = setsock_multicast_ttl(vnetd->mcast_sock, vnetd->ttl);
- if(err < 0) goto exit;
- getsockaddr(vnetd->mcast_sock, &vnetd->mcast_sock_addr);
- vnetd->mcast_sock_addr.sin_addr.s_addr = mcaddr;
-
- exit:
- if(err < 0){
- close(vnetd->udp_sock);
- close(vnetd->mcast_sock);
- vnetd->udp_sock = -1;
- vnetd->mcast_sock = -1;
- }
- return err;
-}
-
-static int vnetd_raw_sock(Vnetd *vnetd){
- int err;
-
- err = vnetd_raw_socket(vnetd, IPPROTO_RAW,
- (VSOCK_BROADCAST),
- vnetd_mcast_addr(vnetd),
- &vnetd->raw_sock);
- if(err){
- close(vnetd->raw_sock);
- vnetd->raw_sock = -1;
- }
- return err;
-}
-
-static int vnetd_unix_sock(Vnetd *vnetd){
- int err = 0;
- struct sockaddr_un addr = { .sun_family = AF_UNIX };
- socklen_t addr_n;
-
- vnetd->unix_sock = socket(addr.sun_family, SOCK_STREAM, 0);
- if(vnetd->unix_sock < 0){
- err = -errno;
- perror("unix socket");
- goto exit;
- }
- unlink(vnetd->unix_path);
- strcpy(addr.sun_path, vnetd->unix_path);
- addr_n = sizeof(addr) - sizeof(addr.sun_path) + strlen(vnetd->unix_path) + 1;
- err = bind(vnetd->unix_sock, (struct sockaddr *)&addr, addr_n);
- if(err < 0){
- err = -errno;
- perror("unix bind");
- goto exit;
- }
- err = listen(vnetd->unix_sock, 5);
- if(err < 0){
- err = -errno;
- perror("unix listen");
- }
- exit:
- return err;
-}
-
-/** Handle SIGPIPE.
- *
- * @param code signal code
- * @param info signal info
- * @param data
- */
-static void sigaction_SIGPIPE(int code, siginfo_t *info, void *data){
- dprintf("> SIGPIPE\n");
-}
-
-/** Handle SIGALRM.
- *
- * @param code signal code
- * @param info signal info
- * @param data
- */
-static void sigaction_SIGALRM(int code, siginfo_t *info, void *data){
- timer_alarms++;
-}
-
-/** Type for signal handling functions. */
-typedef void SignalAction(int code, siginfo_t *info, void *data);
-
-/** Install a handler for a signal.
- *
- * @param signum signal
- * @param action handler
- * @return 0 on success, error code otherwise
- */
-static int catch_signal(int signum, SignalAction *action){
- int err = 0;
- struct sigaction sig = {};
- dprintf(">\n");
- sig.sa_sigaction = action;
- sig.sa_flags = SA_SIGINFO;
- err = sigaction(signum, &sig, NULL);
- if(err){
- err = -errno;
- perror("sigaction");
- }
- return err;
-}
-
-int main(int argc, char *argv[]){
- int err = 0;
-
- err = tunnel_module_init();
- if(err < 0) goto exit;
- err = vnet_init();
- if(err < 0) goto exit;
- err = vnetd_init(vnetd, argc, argv);
- if(err < 0) goto exit;
- err = catch_signal(SIGPIPE, sigaction_SIGPIPE);
- if(err < 0) goto exit;
- err = catch_signal(SIGALRM, sigaction_SIGALRM);
- if(err < 0) goto exit;
- err = vnetd_etherip_sock(vnetd);
- if(err < 0) goto exit;
- err = vnetd_udp_sock(vnetd);
- if(err < 0) goto exit;
- err = vnetd_raw_sock(vnetd);
- if(err < 0) goto exit;
- err = vnetd_unix_sock(vnetd);
- if(err < 0) goto exit;
- err = vnetd_main(vnetd);
-exit:
- return (err ? 1 : 0);
-}