remove VNET from 2.2

This commit is contained in:
root 2010-11-11 18:33:44 -08:00 committed by anthony
parent a6abbe4637
commit 57c4c132ef
124 changed files with 2 additions and 25356 deletions

View File

@ -74,19 +74,6 @@ Group: System Environment/Libraries
The Cloud.com server libraries provide a set of Java classes used
in the Cloud.com Stack.
%package vnet
Summary: Cloud.com-specific virtual network daemon
Requires: python
Requires: %{name}-daemonize = %{version}-%{release}
Requires: %{name}-python = %{version}-%{release}
Requires: net-tools
Requires: bridge-utils
Obsoletes: vmops-vnet < %{version}-%{release}
Group: System Environment/Daemons
%description vnet
The Cloud.com virtual network daemon manages virtual networks used in the
Cloud.com Stack.
%package agent-scripts
Summary: Cloud.com agent scripts
# FIXME nuke the archdependency
@ -217,7 +204,6 @@ Requires: java >= 1.6.0
Requires: %{name}-utils = %{version}-%{release}, %{name}-core = %{version}-%{release}, %{name}-deps = %{version}-%{release}
Requires: %{name}-agent-libs = %{version}-%{release}
Requires: %{name}-agent-scripts = %{version}-%{release}
Requires: %{name}-vnet = %{version}-%{release}
Requires: python
Requires: %{name}-python = %{version}-%{release}
Requires: commons-httpclient
@ -439,21 +425,6 @@ else
/sbin/service %{name}-console-proxy condrestart >/dev/null 2>&1 || true
fi
%preun vnet
if [ "$1" == "0" ] ; then
/sbin/chkconfig --del %{name}-vnetd > /dev/null 2>&1 || true
/sbin/service %{name}-vnetd stop > /dev/null 2>&1 || true
fi
%post vnet
if [ "$1" == "1" ] ; then
/sbin/chkconfig --add %{name}-vnetd > /dev/null 2>&1 || true
/sbin/chkconfig --level 345 %{name}-vnetd on > /dev/null 2>&1 || true
else
/sbin/service %{name}-vnetd condrestart >/dev/null 2>&1 || true
fi
%files utils
%defattr(0644,root,root,0755)
%{_javadir}/%{name}-utils.jar
@ -520,12 +491,6 @@ fi
%defattr(0644,root,root,0755)
%{_javadir}/%{name}-core.jar
%files vnet
%defattr(0644,root,root,0755)
%attr(0755,root,root) %{_sbindir}/%{name}-vnetd
%attr(0755,root,root) %{_sbindir}/%{name}-vn
%attr(0755,root,root) %{_initrddir}/%{name}-vnetd
%files python
%defattr(0644,root,root,0755)
%{_prefix}/lib*/python*/site-packages/%{name}*

View File

@ -1,3 +0,0 @@
/usr/sbin/cloud-vn
/usr/sbin/cloud-vnetd
/etc/init.d/cloud-vnetd

View File

@ -1,13 +0,0 @@
#!/bin/sh -e
case "$1" in
configure)
if [ "$2" = "" ] ; then # no recently configured version, this is a first install
/usr/sbin/update-rc.d cloud-vnet defaults || true
fi
;;
esac
#DEBHELPER#

12
debian/control vendored
View File

@ -49,16 +49,6 @@ Description: Cloud.com server library
The Cloud.com server libraries provide a set of Java classes used
in the Cloud.com Cloud Stack.
Package: cloud-vnet
Provides: vmops-vnet
Conflicts: vmops-vnet
Replaces: vmops-vnet
Architecture: any
Depends: cloud-daemonize (= ${source:Version}), cloud-python (= ${source:Version}), python, bridge-utils, net-tools
Description: Cloud.com-specific virtual network daemon
The Cloud.com virtual network daemon manages virtual networks used in the
Cloud.com Cloud Stack.
Package: cloud-agent-scripts
Provides: vmops-agent-scripts, vmops-console, cloud-console, vmops-console-proxy
Conflicts: vmops-agent-scripts, vmops-console, cloud-console, vmops-console-proxy
@ -151,7 +141,7 @@ Provides: vmops-agent
Conflicts: vmops-agent
Replaces: vmops-agent
Architecture: any
Depends: openjdk-6-jre, cloud-utils (= ${source:Version}), cloud-core (= ${source:Version}), cloud-deps (= ${source:Version}), python, cloud-python (= ${source:Version}), cloud-agent-libs (= ${source:Version}), cloud-agent-scripts (= ${source:Version}), cloud-vnet (= ${source:Version}), libcommons-httpclient-java, libcommons-collections-java, libcommons-dbcp-java, libcommons-pool-java, libcommons-logging-java, libvirt0, cloud-daemonize, sysvinit-utils, chkconfig, qemu-kvm, libvirt-bin, cgroup-bin, augeas-tools, uuid-runtime, rsync, grep, iproute
Depends: openjdk-6-jre, cloud-utils (= ${source:Version}), cloud-core (= ${source:Version}), cloud-deps (= ${source:Version}), python, cloud-python (= ${source:Version}), cloud-agent-libs (= ${source:Version}), cloud-agent-scripts (= ${source:Version}), libcommons-httpclient-java, libcommons-collections-java, libcommons-dbcp-java, libcommons-pool-java, libcommons-logging-java, libvirt0, cloud-daemonize, sysvinit-utils, chkconfig, qemu-kvm, libvirt-bin, cgroup-bin, augeas-tools, uuid-runtime, rsync, grep, iproute
Description: Cloud.com agent
The Cloud.com agent is in charge of managing shared computing resources in
a Cloud.com Cloud Stack-powered cloud. Install this package if this computer

View File

@ -1,85 +0,0 @@
#!/bin/bash
# chkconfig: 35 99 05
# description: CloudStack Virtual Network Daemon
# WARNING: if this script is changed, then all other initscripts MUST BE changed to match it as well
. /etc/rc.d/init.d/functions
whatami=cloud-vnetd
# set environment variables
SHORTNAME="$whatami"
PIDFILE=@PIDDIR@/"$whatami".pid
LOCKFILE=@LOCKDIR@/"$SHORTNAME"
LOGFILE=@LOCALSTATEDIR@/log/cloud/vnetd.log
PROGNAME="CloudStack Virtual Network Daemon"
unset OPTIONS
[ -r @SYSCONFDIR@/sysconfig/"$SHORTNAME" ] && source @SYSCONFDIR@/sysconfig/"$SHORTNAME"
DAEMONIZE=@BINDIR@/@PACKAGE@-daemonize
PROG=@SBINDIR@/$SHORTNAME
start() {
echo -n $"Starting $PROGNAME: "
daemon --check=$SHORTNAME --pidfile=${PIDFILE} "$DAEMONIZE" \
-n "$SHORTNAME" -p "$PIDFILE" -l "$LOGFILE" "$PROG" $OPTIONS
RETVAL=$?
echo
[ $RETVAL = 0 ] && touch ${LOCKFILE}
return $RETVAL
}
stop() {
echo -n $"Stopping $PROGNAME: "
killproc -p ${PIDFILE} $SHORTNAME # -d 10 $SHORTNAME
RETVAL=$?
echo
[ $RETVAL = 0 ] && rm -f ${LOCKFILE} ${PIDFILE}
}
recreate_vnets() {
for br in `ip link | grep vnbr | cut -d":" -f2| cut --complement -c1`;
do
vnetid=0000:0000:0000:0000:0000:0000:0000:`echo $br | cut -c5-`
vn vnet-create -b $br $vnetid &> /dev/null;
done
}
# See how we were called.
case "$1" in
start)
start
sleep 1
recreate_vnets
;;
stop)
stop
;;
status)
status -p ${PIDFILE} $SHORTNAME
RETVAL=$?
;;
restart)
stop
sleep 2
start
recreate_vnets
;;
condrestart)
if status -p ${PIDFILE} $SHORTNAME >&/dev/null; then
stop
sleep 2
start
recreate_vnets
fi
;;
*)
echo $"Usage: $whatami {start|stop|restart|condrestart|status|help}"
RETVAL=3
esac
exit $RETVAL

View File

@ -1,85 +0,0 @@
#!/bin/bash
# chkconfig: 35 99 05
# description: CloudStack Virtual Network Daemon
# WARNING: if this script is changed, then all other initscripts MUST BE changed to match it as well
. /etc/rc.d/init.d/functions
whatami=cloud-vnetd
# set environment variables
SHORTNAME="$whatami"
PIDFILE=@PIDDIR@/"$whatami".pid
LOCKFILE=@LOCKDIR@/"$SHORTNAME"
LOGFILE=@LOCALSTATEDIR@/log/cloud/vnetd.log
PROGNAME="CloudStack Virtual Network Daemon"
unset OPTIONS
[ -r @SYSCONFDIR@/sysconfig/"$SHORTNAME" ] && source @SYSCONFDIR@/sysconfig/"$SHORTNAME"
DAEMONIZE=@BINDIR@/@PACKAGE@-daemonize
PROG=@SBINDIR@/$SHORTNAME
start() {
echo -n $"Starting $PROGNAME: "
daemon --check=$SHORTNAME --pidfile=${PIDFILE} "$DAEMONIZE" \
-n "$SHORTNAME" -p "$PIDFILE" -l "$LOGFILE" "$PROG" $OPTIONS
RETVAL=$?
echo
[ $RETVAL = 0 ] && touch ${LOCKFILE}
return $RETVAL
}
stop() {
echo -n $"Stopping $PROGNAME: "
killproc -p ${PIDFILE} $SHORTNAME # -d 10 $SHORTNAME
RETVAL=$?
echo
[ $RETVAL = 0 ] && rm -f ${LOCKFILE} ${PIDFILE}
}
recreate_vnets() {
for br in `ip link | grep vnbr | cut -d":" -f2| cut --complement -c1`;
do
vnetid=0000:0000:0000:0000:0000:0000:0000:`echo $br | cut -c5-`
vn vnet-create -b $br $vnetid &> /dev/null;
done
}
# See how we were called.
case "$1" in
start)
start
sleep 1
recreate_vnets
;;
stop)
stop
;;
status)
status -p ${PIDFILE} $SHORTNAME
RETVAL=$?
;;
restart)
stop
sleep 2
start
recreate_vnets
;;
condrestart)
if status -p ${PIDFILE} $SHORTNAME >&/dev/null; then
stop
sleep 2
start
recreate_vnets
fi
;;
*)
echo $"Usage: $whatami {start|stop|restart|condrestart|status|help}"
RETVAL=3
esac
exit $RETVAL

View File

@ -1,104 +0,0 @@
#!/bin/bash
# chkconfig: 35 99 05
# description: CloudStack Virtual Network Daemon
# WARNING: if this script is changed, then all other initscripts MUST BE changed to match it as well
. /lib/lsb/init-functions
. /etc/default/rcS
whatami=cloud-vnetd
# set environment variables
SHORTNAME="$whatami"
PIDFILE=@PIDDIR@/"$whatami".pid
LOCKFILE=@LOCKDIR@/"$SHORTNAME"
LOGFILE=@LOCALSTATEDIR@/log/cloud/vnetd.log
PROGNAME="CloudStack Virtual Network Daemon"
unset OPTIONS
[ -r @SYSCONFDIR@/default/"$SHORTNAME" ] && source @SYSCONFDIR@/default/"$SHORTNAME"
DAEMONIZE=@BINDIR@/@PACKAGE@-daemonize
PROG=@SBINDIR@/$SHORTNAME
start() {
log_daemon_msg $"Starting $PROGNAME" "$SHORTNAME"
if [ -s "$PIDFILE" ] && kill -0 $(cat "$PIDFILE") >/dev/null 2>&1; then
log_progress_msg "apparently already running"
log_end_msg 0
exit 0
fi
if "$DAEMONIZE" -n "$SHORTNAME" -p "$PIDFILE" -l "$LOGFILE" "$PROG" $OPTIONS
RETVAL=$?
then
rc=0
sleep 1
if ! kill -0 $(cat "$PIDFILE") >/dev/null 2>&1; then
log_failure_msg "$PROG failed to start"
rc=1
fi
else
rc=1
fi
if [ $rc -eq 0 ]; then
log_end_msg 0
else
log_end_msg 1
rm -f "$PIDFILE"
fi
}
stop() {
echo -n $"Stopping $PROGNAME" "$SHORTNAME"
start-stop-daemon --stop --quiet --oknodo --pidfile "$PIDFILE"
log_end_msg $?
rm -f "$PIDFILE"
}
recreate_vnets() {
for br in `ip link | grep vnbr | cut -d":" -f2| cut --complement -c1`;
do
vnetid=0000:0000:0000:0000:0000:0000:0000:`echo $br | cut -c5-`
vn vnet-create -b $br $vnetid &> /dev/null;
done
}
# See how we were called.
case "$1" in
start)
start
sleep 1
recreate_vnets
;;
stop)
stop
;;
status)
status_of_proc -p "$PIDFILE" "$PROG" "$SHORTNAME"
RETVAL=$?
;;
restart)
stop
sleep 2
start
recreate_vnets
;;
condrestart)
if [ -f "$PIDFILE" ] ; then
stop
sleep 2
start
recreate_vnets
fi
;;
*)
echo $"Usage: $whatami {start|stop|restart|condrestart|status|help}"
RETVAL=3
esac
exit $RETVAL

View File

@ -1,904 +0,0 @@
#!/usr/bin/env python
# -*- 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
sys.path.insert(0,"@PYTHONDIR@")
from getopt import getopt, GetoptError
#from xen.xend import sxp
#from xen.xend.PrettyPrint import prettyprint
import cloud_sxp as sxp
from cloud_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()

View File

@ -1,55 +0,0 @@
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.

View File

@ -1,15 +0,0 @@
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>

View File

@ -1,28 +0,0 @@
# -*- 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

View File

@ -1,89 +0,0 @@
# -*- 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/$@
.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.'

View File

@ -1,51 +0,0 @@
#!/usr/bin/make -f
# -*- mode: Makefile; -*-
XEN_ROOT = ../../..
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)

View File

@ -1,176 +0,0 @@
=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.

View File

@ -1,72 +0,0 @@
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.

View File

@ -1,167 +0,0 @@
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.

View File

@ -1,18 +0,0 @@
# -*- mode: Makefile; -*-
#============================================================================
XEN_ROOT = ../../..
include $(XEN_ROOT)/tools/Rules.mk
XEN_SCRIPT_DIR = $(DESTDIR)/etc/xen/scripts
.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:

View File

@ -1,10 +0,0 @@
#!/bin/sh
scriptdir=/etc/xen/scripts/
case ${1} in
start)
${scriptdir}/vnet-insert
;;
esac
${scriptdir}/network-bridge "$@"

View File

@ -1,28 +0,0 @@
#!/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 "$@"

View File

@ -1,2 +0,0 @@
# Vnet configuration for a vnet with id 97 and no security.
(vnet (id 97) (bridge vnet97) (vnetif vnif97) (security none))

View File

@ -1,2 +0,0 @@
# Vnet configuration for a vnet with id 98 and message authentication.
(vnet (id 98) (bridge vnet98) (vnetif vnif98) (security auth))

View File

@ -1,2 +0,0 @@
# Vnet configuration for a vnet with id 99 and message confidentiality.
(vnet (id 99) (bridge vnet99) (vnif vnetif99) (security conf))

View File

@ -1,86 +0,0 @@
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)
CFLAGS += -Werror -fno-strict-aliasing $(call cc-option,$(CC),-fgnu89-inline,)
CFLAGS += -O3
#CFLAGS += -g
# Get gcc to generate the dependencies for us.
CFLAGS += -Wp,-MD,.$(@F).d
DEPS = .*.d
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_CFLAGS) -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)

View File

@ -1,116 +0,0 @@
/*
* 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);
}
}

View File

@ -1,45 +0,0 @@
/*
* 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_ */

View File

@ -1,72 +0,0 @@
/*
* 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_ */

View File

@ -1,61 +0,0 @@
/*
* 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;
}

View File

@ -1,30 +0,0 @@
/*
* 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_ */

View File

@ -1,184 +0,0 @@
/*
* 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

View File

@ -1,36 +0,0 @@
/*
* 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_ */

View File

@ -1,234 +0,0 @@
/*
* 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 <errno.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){
int cnt = 0;
unsigned char *ptr = (unsigned char*)buf;
while (n) {
if ((cnt = fwrite((const void *)(ptr), sizeof(unsigned char), n, get_file(s))) < 0) {
if (errno == EINTR)
continue;
else
return -1;
}
n -= cnt;
ptr += cnt;
}
return n;
}
/** 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

View File

@ -1,35 +0,0 @@
/*
* 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_ */

View File

@ -1,174 +0,0 @@
/*
* 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

View File

@ -1,30 +0,0 @@
/*
* 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_ */

View File

@ -1,658 +0,0 @@
/*
* 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);
}
}

View File

@ -1,240 +0,0 @@
/*
* 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_ */

View File

@ -1,55 +0,0 @@
/*
* 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;
}

View File

@ -1,269 +0,0 @@
/*
* 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_ */

View File

@ -1,178 +0,0 @@
/*
* 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__ */

View File

@ -1,29 +0,0 @@
/*
* 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_ */

View File

@ -1,94 +0,0 @@
/*
* 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];
}

View File

@ -1,128 +0,0 @@
/*
* 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_ */

View File

@ -1,324 +0,0 @@
/*
* 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;
}

View File

@ -1,32 +0,0 @@
/*
* 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_ */

View File

@ -1,230 +0,0 @@
/*
* 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

View File

@ -1,53 +0,0 @@
/*
* 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_ */

View File

@ -1,162 +0,0 @@
/*
* 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;
}

View File

@ -1,45 +0,0 @@
/*
* 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_ */

File diff suppressed because it is too large Load Diff

View File

@ -1,440 +0,0 @@
/*
* 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_ */

File diff suppressed because it is too large Load Diff

View File

@ -1,160 +0,0 @@
/*
* 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_ */

View File

@ -1,319 +0,0 @@
/*
* 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;
}

View File

@ -1,78 +0,0 @@
/*
* 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_ */

View File

@ -1,218 +0,0 @@
/*
* 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;
}

View File

@ -1,95 +0,0 @@
/*
* 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.
*/
/*============================================================================*/
#define _GNU_SOURCE
#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_ */

View File

@ -1,106 +0,0 @@
/*
* 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
}

View File

@ -1,28 +0,0 @@
/*
* 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_ */

View File

@ -1,15 +0,0 @@
# -*- mode: Makefile; -*-
#============================================================================
XEN_ROOT = ../../..
include $(XEN_ROOT)/tools/Rules.mk
.PHONY: all
all:
.PHONY: install
install:
$(INSTALL_DIR) $(DESTDIR)$(SBINDIR)
$(INSTALL_PROG) vn $(DESTDIR)$(SBINDIR)
.PHONY: clean
clean:

View File

@ -1,904 +0,0 @@
#!/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
sys.path.append('/usr/lib/python')
sys.path.append('/usr/lib64/python')
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()

View File

@ -1,39 +0,0 @@
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

View File

@ -1,71 +0,0 @@
# -*- 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
#============================================================================

View File

@ -1,98 +0,0 @@
# -*- 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)

View File

@ -1,60 +0,0 @@
# -*- 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
export KERNEL_MINOR=$(shell echo $(LINUX_VERSION) |cut -d"-" -f1 |cut -d"." -f3)
$(warning KERNEL_MINOR $(KERNEL_MINOR))
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

View File

@ -1,51 +0,0 @@
# -*- 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))

View File

@ -1,62 +0,0 @@
# -*- 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 += etherip.c
VNET_SRC += random.c
VNET_SRC += sa.c
VNET_SRC += esp.c
ifeq ($(KERNEL_MINOR),18)
VNET_SRC += sa_algorithm.c
endif
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)

View File

@ -1,903 +0,0 @@
/*
* 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"
#if ((LINUX_VERSION_CODE != KERNEL_VERSION(2,6,18) ) || !defined(CONFIG_CRYPTO_HMAC))
#warning No esp transform -
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

View File

@ -1,120 +0,0 @@
/*
* 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__ */

View File

@ -1,488 +0,0 @@
/*
* 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){
dprintf("> 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.
#ifdef __KERNEL__
__pskb_pull(skb, etherip_n);
skb_reset_mac_header(skb);
#else
skb->mac.raw = skb_pull_vn(skb, etherip_n);
#endif
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.
#ifndef __KERNEL__
skb->nh.raw = skb_pull_vn(skb, ETH_HLEN);
skb->h.raw = skb->nh.raw + sizeof(struct iphdr);
#else
__pskb_pull(skb, ETH_HLEN);
skb_reset_network_header(skb);
skb_set_transport_header(skb, sizeof(struct iphdr));
#endif
#ifdef __KERNEL__
// Fix IP options, checksum, skb dst, netfilter state.
memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
//fixme CHECKSUM_HW no longer defined - check replacing with CHECKSUM_COMPLETE.
/* if(skb->ip_summed == CHECKSUM_HW){ */
/* skb->ip_summed = CHECKSUM_NONE; */
/* } */
if(skb->ip_summed == CHECKSUM_HW){
skb->ip_summed = CHECKSUM_NONE;
}
dst_release(skb->dst);
skb->dst = NULL;
nf_reset(skb);
#ifdef CONFIG_BRIDGE_NETFILTER
if(skb->nf_bridge){
// Stop the eth header being clobbered by nf_bridge_maybe_copy_header().
nf_bridge_save_header(skb);
}
#endif
#endif // __KERNEL__
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(&etherip_protocol, IPPROTO_ETHERIP);
}
static int etherip_protocol_del(void){
return inet_del_protocol(&etherip_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(&etherip_protocol);
return 0;
}
static int etherip_protocol_del(void){
return inet_del_protocol(&etherip_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__

View File

@ -1,38 +0,0 @@
/*
* 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

View File

@ -1,83 +0,0 @@
/*
* 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_ */

View File

@ -1,105 +0,0 @@
/*
* 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 */

View File

@ -1,329 +0,0 @@
/* 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) */

View File

@ -1,87 +0,0 @@
/*
* 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){
}

View File

@ -1,28 +0,0 @@
/*
* 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__ */

View File

@ -1,756 +0,0 @@
/*
* 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;
}

View File

@ -1,215 +0,0 @@
/*
* 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__ */

View File

@ -1,367 +0,0 @@
/*
* 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");
}

View File

@ -1,63 +0,0 @@
/*
* 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__ */

View File

@ -1,92 +0,0 @@
/*
* 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;
}

View File

@ -1,87 +0,0 @@
/*
* 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__ */

View File

@ -1,579 +0,0 @@
/*
* 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>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21) )
#include <linux/highmem.h>
static inline void *kmap_skb_frag(const skb_frag_t *frag)
{
#ifdef CONFIG_HIGHMEM
BUG_ON(in_irq());
local_bh_disable();
#endif
return kmap_atomic(frag->page, KM_SKB_DATA_SOFTIRQ);
}
static inline void kunmap_skb_frag(void *vaddr)
{
kunmap_atomic(vaddr, KM_SKB_DATA_SOFTIRQ);
#ifdef CONFIG_HIGHMEM
local_bh_enable();
#endif
}
#endif
#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));
}

View File

@ -1,154 +0,0 @@
/*
* 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_ */

View File

@ -1,119 +0,0 @@
/*
* 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;
}

View File

@ -1,36 +0,0 @@
/*
* 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_ */

View File

@ -1,76 +0,0 @@
/*
* 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/jiffies.h>
#include <linux/posix-timers.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

View File

@ -1,41 +0,0 @@
/*
* 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_ */

View File

@ -1,270 +0,0 @@
/*
* 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);
}

View File

@ -1,113 +0,0 @@
/*
* 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__ */

File diff suppressed because it is too large Load Diff

View File

@ -1,161 +0,0 @@
/*
* 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 */

View File

@ -1,901 +0,0 @@
/*
* 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 <linux/kthread.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;
#define _GNU_SOURCE
#include <linux/unistd.h>
#include <linux/syscalls.h>
#define MODULE_NAME "VARP"
#define DEBUG 1
#undef DEBUG
#include "debug.h"
/** @file
* Support for the VARP udp sockets.
*/
extern int syscall(int number, ...);
#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. */
#if (LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) )
static inline _syscall3(int, fcntl,
unsigned int, fd,
unsigned int, cmd,
unsigned long, arg)
#endif
/* 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);
}
#elif defined(__x86_64__)
int socket(int family, int type, int protocol){
struct socket* sock;
int err;
int err2;
err = sock_create_kern(family, type, protocol, &sock);
if (err < 0) goto exit;
dprintf("sock_create err=%d\n",err);
err = sock_map_fd(sock);
if ((sock = sockfd_lookup(err, &err2 )) == NULL)
dprintf("sock_create lookup err\n");
exit:
return err;
}
int bind(int fd, struct sockaddr *address, int addrlen){
struct socket *sock;
int err;
if((sock = sockfd_lookup(fd, &err))!=NULL)
{
err = sock->ops->bind (sock, (struct sockaddr *)address,addrlen);
}
return err;
}
int connect(int fd, struct sockaddr *address, int addrlen){
struct socket *sock;
int err;
sock = sockfd_lookup(fd, &err);
if (!sock)
goto out;
err = sock->ops->connect(sock, (struct sockaddr *) address, addrlen,
sock->file->f_flags);
out:
return err;
}
int setsockopt(int fd, int level, int optname, void *optval, int optlen){
int err;
struct socket *sock;
if (optlen < 0)
return -EINVAL;
if ((sock = sockfd_lookup(fd, &err)) != NULL)
{
if (level == SOL_SOCKET)
err=sock_setsockopt(sock,level,optname,optval,optlen);
else
err=sock->ops->setsockopt(sock, level, optname, optval, optlen);
}
return err;
}
int shutdown(int fd, int how){
int err;
#if 1
struct socket *sock;
//for multicast sockets, shutdown returns ENOTCONN
if ((sock = sockfd_lookup(fd, &err)) !=NULL)
{
err = sock->ops->shutdown(sock, how);
sock_release(sock);
}
#endif
err=sys_close(fd);
return err;
}
#if 0
int sendto(int fd, void * buff, size_t len,
unsigned flags, struct sockaddr *addr,
int addr_len){
return syscall(__NR_sendto, fd, buff, len, flags, addr, addr_len);
}
int recvfrom(int fd, void * ubuf, size_t size,
unsigned flags, struct sockaddr *addr,
int *addr_len){
return syscall(__NR_recvfrom, fd, ubuf, size, flags, addr, addr_len);
}
int getsockopt(int fd, int level, int optname, void *optval, int *optlen){
return syscall(__NR_getsockopt, fd, level, optname, optval, optlen);
}
int getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len){
return syscall(__NR_getsockname, fd, usockaddr, usockaddr_len);
}
#endif
#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 (LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) )
if(flags & VSOCK_NONBLOCK){
err = fcntl(sock, F_SETFL, O_NONBLOCK);
if(err < 0) goto exit;
}
#endif
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, 2);
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;
int err;
struct ip_mreqn mreq = {};
oldfs = change_fs(KERNEL_DS);
if(varp_mcast_sock >= 0){
mreq.imr_multiaddr.s_addr = htonl(VARP_MCAST_ADDR);
mreq.imr_address.s_addr = INADDR_ANY;
mreq.imr_ifindex = 0;
err =setsockopt(varp_mcast_sock, SOL_IP,IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
if(err < 0){
eprintf("> setsockopt IP_MULTICAST_DROP: %d %d\n", err, errno);
}
shutdown(varp_mcast_sock, 2);
varp_mcast_sock = -1;
}
if(varp_ucast_sock >= 0){
err=shutdown(varp_ucast_sock, 2);
if(err){
eprintf("> ucast sock shutdown err=%d\n", err);
}
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(TASK_COMM_LEN), "vnet_varp");
err = varp_sockets_open(htonl(VARP_MCAST_ADDR), htons(VARP_PORT));
if(err) goto exit;
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();
exit:
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;
struct task_struct* task;
//MOD_INC_USE_COUNT;
dprintf(">\n");
atomic_set(&varp_run, 1);
atomic_set(&varp_state, VARP_STATE_NONE);
#if 1
task = kthread_run(varp_main, (void*)NULL, "vnet_varpd");
if (IS_ERR(task) < 0) {
eprintf("> Unable to start varp main thread\n");
goto exit;
}
#endif
#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;
}

View File

@ -1,77 +0,0 @@
/*
* 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;
}

View File

@ -1,95 +0,0 @@
/*
* 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, VARP_ADDR_BUF-1, "%u.%u.%u.%u",
NIPQUAD(addr->u.ip4));
break;
case AF_INET6:
snprintf(buf, VARP_ADDR_BUF-1,"%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, VNET_ID_BUF-1, "%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 */

View File

@ -1,389 +0,0 @@
/*
* 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>
#include <linux/jiffies.h>
#include <linux/timer.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;
}

View File

@ -1,64 +0,0 @@
/*
* 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

View File

@ -1,712 +0,0 @@
/*
* 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.
*/
#ifdef __KERNEL__
#if (LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) )
int vnet_security_default = SA_AUTH ; //| SA_CONF;
#else
int vnet_security_default = 0;
#endif
#else
int vnet_security_default = 0;
#endif
/** 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, 16, "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 = vif_init();
if(err) goto exit;
err = varp_init();
if(err) goto exit;
err = vnet_setup();
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, &eth_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;
#ifdef __KERNEL__
#if (LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) )
sa_algorithm_probe_all();
#endif
#endif
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

View File

@ -1,108 +0,0 @@
/*
* 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__ */

View File

@ -1,296 +0,0 @@
/*
* 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;
}

View File

@ -1,27 +0,0 @@
/*
* 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

Some files were not shown because too many files have changed in this diff Show More