# Copyright (C) 2010, 2011 Miroslav Lichvar <mlichvar@redhat.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, see <http://www.gnu.org/licenses/>.
[ -n "$CLKNETSIM_TMPDIR" ] || CLKNETSIM_TMPDIR=tmp
client_pids=""
start_client() {
local node=$1 client=$2 config=$3 suffix=$4 opts=$5
local args=() line lastpid
rm -f $CLKNETSIM_TMPDIR/log.$node $CLKNETSIM_TMPDIR/conf.$node
[ $client = chrony ] && client=chronyd
[ $client = ntp ] && client=ntpd
if ! which $client$suffix &> /dev/null; then
echo "can't find $client$suffix in PATH"
return 1
fi
case $client in
chronyd)
cat > $CLKNETSIM_TMPDIR/conf.$node <<-EOF
pidfile $CLKNETSIM_TMPDIR/pidfile.$node
allow
cmdallow
bindcmdaddress 0.0.0.0
$config
EOF
args=(-d -f $CLKNETSIM_TMPDIR/conf.$node $opts)
;;
ntpd)
cat > $CLKNETSIM_TMPDIR/conf.$node <<-EOF
pidfile $CLKNETSIM_TMPDIR/pidfile.$node
restrict default
$config
EOF
args=(-n -c $CLKNETSIM_TMPDIR/conf.$node $opts)
;;
ptp4l)
cat > $CLKNETSIM_TMPDIR/conf.$node <<-EOF
[global]
$config
EOF
args=(-f $CLKNETSIM_TMPDIR/conf.$node $opts)
;;
chronyc)
args=($opts -m)
while read line; do args+=("$line"); done <<< "$config"
;;
pmc)
args=($opts)
while read line; do args+=("$line"); done <<< "$config"
;;
ntpq)
while read line; do args+=(-c "$line"); done <<< "$config"
args+=($opts)
;;
sntp)
args=(-K /dev/null $opts $config)
;;
ntpdate)
args=($opts $config)
;;
busybox)
args=(ntpd -ddd -n)
while read line; do args+=(-p "$line"); done <<< "$config"
args+=($opts)
;;
phc2sys)
args=(-s /dev/ptp0 -O 0 $opts $config)
;;
nsm)
args=($opts)
while read line; do args+=("$line"); done <<< "$config"
;;
*)
echo "unknown client $client"
exit 1
;;
esac
LD_PRELOAD=$CLKNETSIM_PATH/clknetsim.so \
CLKNETSIM_NODE=$node CLKNETSIM_SOCKET=$CLKNETSIM_TMPDIR/sock \
$client_wrapper $client$suffix "${args[@]}" &> $CLKNETSIM_TMPDIR/log.$node &
lastpid=$!
disown $lastpid
client_pids="$client_pids $lastpid"
}
start_server() {
local nodes=$1 ret=0
shift
$server_wrapper $CLKNETSIM_PATH/clknetsim "$@" -s $CLKNETSIM_TMPDIR/sock \
$CLKNETSIM_TMPDIR/conf $nodes > $CLKNETSIM_TMPDIR/stats 2> $CLKNETSIM_TMPDIR/log
if [ $? -ne 0 ]; then
echo clknetsim failed 1>&2
ret=1
fi
kill $client_pids &> /dev/null
client_pids=" "
return $ret
}
generate_seq() {
$CLKNETSIM_PATH/clknetsim -G "$@"
}
generate_config1() {
local nodes=$1 offset=$2 freqexpr=$3 delayexprup=$4 delayexprdown=$5 refclockexpr=$6 i
for i in `seq 2 $nodes`; do
echo "node${i}_offset = $offset"
echo "node${i}_freq = $freqexpr"
echo "node${i}_delay1 = $delayexprup"
if [ -n "$delayexprdown" ]; then
echo "node1_delay${i} = $delayexprdown"
else
echo "node1_delay${i} = $delayexprup"
fi
[ -n "$refclockexpr" ] && echo "node${i}_refclock = $refclockexpr"
done > $CLKNETSIM_TMPDIR/conf
}
generate_config2() {
local nodes=$1 offset=$2 freqexpr=$3 delayexpr=$4 i j
for i in `seq 2 $nodes`; do
echo "node${i}_offset = $offset"
echo "node${i}_freq = $freqexpr"
for j in `seq 1 $nodes`; do
[ $i -eq $j ] && continue
echo "node${i}_delay${j} = $delayexpr"
echo "node${j}_delay${i} = $delayexpr"
done
done > $CLKNETSIM_TMPDIR/conf
}
generate_config3() {
local topnodes=$1 nodes=$2 offset=$3 freqexpr=$4 delayexprup=$5 delayexprdown=$6 i j
for i in `seq $[$topnodes + 1] $nodes`; do
echo "node${i}_offset = $offset"
echo "node${i}_freq = $freqexpr"
for j in `seq 1 $topnodes`; do
[ $i -eq $j ] && continue
echo "node${i}_delay${j} = $delayexprup"
if [ -n "$delayexprdown" ]; then
echo "node${j}_delay${i} = $delayexprdown"
else
echo "node${j}_delay${i} = $delayexprup"
fi
done
done > $CLKNETSIM_TMPDIR/conf
}
generate_config4() {
local stablenodes=$1 subnets=$2 offset=$3 freqexpr=$4 delayexpr=$5
local subnet i j added
echo "$subnets" | tr '|' '\n' | while read subnet; do
for i in $subnet; do
if ! [[ " $stablenodes $added " =~ [^0-9]$i[^0-9] ]]; then
echo "node${i}_offset = $offset"
echo "node${i}_freq = $freqexpr"
fi
for j in $subnet; do
[ $i -eq $j ] && continue
echo "node${i}_delay${j} = $delayexpr"
done
added="$added $i"
done
done > $CLKNETSIM_TMPDIR/conf
}
find_sync() {
local offlog=$1 freqlog=$2 index=$3 offsync=$4 freqsync=$5 smooth=$6
[ -z "$smooth" ] && smooth=0.05
paste <(cut -f $index $1) <(cut -f $index $2) | awk '
BEGIN {
lastnonsync = -1
time = 0
}
{
off = $1 < 0 ? -$1 : $1
freq = $2 < 0 ? -$2 : $2
if (avgoff == 0.0 && avgfreq == 0.0) {
avgoff = off
avgfreq = freq
} else {
avgoff += '$smooth' * (off - avgoff)
avgfreq += '$smooth' * (freq - avgfreq)
}
if (avgoff > '$offsync' || avgfreq > '$freqsync') {
lastnonsync = time
}
time++
} END {
if (lastnonsync < time) {
print lastnonsync + 1
} else {
print -1
}
}'
}
get_stat() {
local statname=$1 index=$2
if [ -z "$index" ]; then
echo $(cat $CLKNETSIM_TMPDIR/stats | grep "^$statname:" | cut -f 2)
else
cat $CLKNETSIM_TMPDIR/stats | grep "^$statname:" | cut -f 2 |
head -n $index | tail -n 1
fi
}
check_stat() {
local value=$1 min=$2 max=$3 tolerance=$4
[ -z "$tolerance" ] && tolerance=0.0
awk "
BEGIN {
eq = (\"$value\" == \"inf\" ||
$value + $value / 1e6 + $tolerance >= $min) &&
(\"$max\" == \"inf\" ||
(\"$value\" != \"inf\" &&
$value - $value / 1e6 - $tolerance <= $max))
exit !eq
}"
}
if [ -z "$CLKNETSIM_PATH" ]; then
echo CLKNETSIM_PATH not set 2>&1
exit 1
fi
if [ ! -x "$CLKNETSIM_PATH/clknetsim" -o ! -e "$CLKNETSIM_PATH/clknetsim.so" ]; then
echo "can't find clknetsim or clknetsim.so in $CLKNETSIM_PATH"
exit 1
fi
[ -d $CLKNETSIM_TMPDIR ] || mkdir $CLKNETSIM_TMPDIR