mirror of https://github.com/apache/cloudstack.git
remove VNET from 2.2
This commit is contained in:
parent
a6abbe4637
commit
57c4c132ef
35
cloud.spec
35
cloud.spec
|
|
@ -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}*
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
/usr/sbin/cloud-vn
|
||||
/usr/sbin/cloud-vnetd
|
||||
/etc/init.d/cloud-vnetd
|
||||
|
|
@ -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#
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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()
|
||||
|
||||
|
|
@ -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.
|
||||
|
|
@ -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>
|
||||
|
|
@ -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
|
||||
|
|
@ -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.'
|
||||
|
|
@ -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)
|
||||
|
||||
|
|
@ -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.
|
||||
|
|
@ -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.
|
||||
|
|
@ -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.
|
||||
|
||||
|
||||
|
|
@ -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:
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
#!/bin/sh
|
||||
scriptdir=/etc/xen/scripts/
|
||||
|
||||
case ${1} in
|
||||
start)
|
||||
${scriptdir}/vnet-insert
|
||||
;;
|
||||
esac
|
||||
|
||||
${scriptdir}/network-bridge "$@"
|
||||
|
|
@ -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 "$@"
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
# Vnet configuration for a vnet with id 97 and no security.
|
||||
(vnet (id 97) (bridge vnet97) (vnetif vnif97) (security none))
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
# Vnet configuration for a vnet with id 98 and message authentication.
|
||||
(vnet (id 98) (bridge vnet98) (vnetif vnif98) (security auth))
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
# Vnet configuration for a vnet with id 99 and message confidentiality.
|
||||
(vnet (id 99) (bridge vnet99) (vnif vnetif99) (security conf))
|
||||
|
|
@ -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)
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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_ */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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__ */
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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];
|
||||
}
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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_ */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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_ */
|
||||
|
||||
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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:
|
||||
|
|
@ -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()
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
#============================================================================
|
||||
|
||||
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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))
|
||||
|
|
@ -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)
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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__ */
|
||||
|
|
@ -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(ðerip_protocol, IPPROTO_ETHERIP);
|
||||
}
|
||||
|
||||
static int etherip_protocol_del(void){
|
||||
return inet_del_protocol(ðerip_protocol, IPPROTO_ETHERIP);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
#else
|
||||
//============================================================================
|
||||
// Code for 2.4 kernel.
|
||||
|
||||
/** Etherip protocol. */
|
||||
static struct inet_protocol etherip_protocol = {
|
||||
.name = "ETHERIP",
|
||||
.protocol = IPPROTO_ETHERIP,
|
||||
.handler = etherip_protocol_recv,
|
||||
.err_handler = etherip_protocol_icmp_err,
|
||||
};
|
||||
|
||||
static int etherip_protocol_add(void){
|
||||
inet_add_protocol(ðerip_protocol);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int etherip_protocol_del(void){
|
||||
return inet_del_protocol(ðerip_protocol);
|
||||
}
|
||||
|
||||
#endif
|
||||
//============================================================================
|
||||
|
||||
|
||||
/** Initialize the etherip module.
|
||||
* Registers the etherip protocol.
|
||||
*
|
||||
* @return 0 on success, error code otherwise
|
||||
*/
|
||||
int __init etherip_module_init(void) {
|
||||
int err = 0;
|
||||
etherip_protocol_add();
|
||||
return err;
|
||||
}
|
||||
|
||||
/** Finalize the etherip module.
|
||||
* Deregisters the etherip protocol.
|
||||
*/
|
||||
void __exit etherip_module_exit(void) {
|
||||
if(etherip_protocol_del() < 0){
|
||||
printk(KERN_INFO "%s: can't remove etherip protocol\n", __FUNCTION__);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __KERNEL__
|
||||
|
|
@ -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
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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) */
|
||||
|
|
@ -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){
|
||||
}
|
||||
|
||||
|
|
@ -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__ */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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__ */
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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__ */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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__ */
|
||||
|
|
@ -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));
|
||||
}
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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, ð_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
|
||||
|
|
@ -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__ */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
Loading…
Reference in New Issue