Commit 3ef53ace authored by Alessandro Rubini's avatar Alessandro Rubini

Merge branch 'drop-frames'

parents d7091dd8 07ce9e52
......@@ -7,10 +7,12 @@ CFLAGS += -Itools
OBJ-y += $A/unix-startup.o \
$A/main-loop.o \
$A/unix-io.o \
$A/unix-conf.o \
lib/cmdline.o \
lib/conf.o \
lib/libc-functions.o \
lib/dump-funcs.o \
lib/drop.o \
lib/div64.o
# The user can set TIME=, but we pick unix time by default
......
......@@ -113,12 +113,19 @@ void unix_main_loop(struct pp_globals *ppg)
PP_MAX_FRAME_LENGTH - 4,
&ppi->last_rcv_time);
if (i == -2) {
continue; /* dropped */
}
if (i == -1) {
pp_diag(ppi, frames, 1,
"Receive Error %i: %s\n",
errno, strerror(errno));
continue;
}
if (i < PP_MINIMUM_LENGTH) {
pp_diag(ppi, frames, 1,
"Error or short frame: "
"%d < %d\n", i,
PP_MINIMUM_LENGTH
);
"Short frame: %d < %d\n", i,
PP_MINIMUM_LENGTH);
continue;
}
......
/*
* Copyright (C) 2014 CERN (www.cern.ch)
* Author: Alessandro Rubini
*
* Released according to GNU LGPL, version 2.1 or any later
*/
#include <ppsi/ppsi.h>
static int f_rxdrop(int lineno, struct pp_globals *ppg, union pp_cfg_arg *arg)
{
ppg->rxdrop = arg->i;
return 0;
}
static int f_txdrop(int lineno, struct pp_globals *ppg, union pp_cfg_arg *arg)
{
ppg->txdrop = arg->i;
return 0;
}
struct pp_argline pp_arch_arglines[] = {
{ f_rxdrop, "rx-drop", ARG_INT},
{ f_txdrop, "tx-drop", ARG_INT},
{}
};
......@@ -17,6 +17,7 @@
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <sys/timex.h>
#include <ppsi/ppsi.h>
......@@ -34,6 +35,7 @@ int main(int argc, char **argv)
{
struct pp_globals *ppg;
struct pp_instance *ppi;
unsigned long seed;
struct timex t;
int i;
......@@ -103,6 +105,11 @@ int main(int argc, char **argv)
pp_init_globals(ppg, &__pp_default_rt_opts);
seed = time(NULL);
if (getenv("PPSI_DROP_SEED"))
seed = atoi(getenv("PPSI_DROP_SEED"));
ppsi_drop_init(ppg, seed);
unix_main_loop(ppg);
return 0; /* never reached */
}
......@@ -8,10 +8,12 @@ OBJ-y += $A/wrs-startup.o \
$A/wrs-io.o \
$A/wrs-calibration.o \
$A/wrs-ipcserver.o \
arch-unix/unix-conf.o \
lib/cmdline.o \
lib/conf.o \
lib/libc-functions.o \
lib/dump-funcs.o \
lib/drop.o \
lib/div64.o
# The user can set TIME=, but wrs is default
......
......@@ -151,12 +151,19 @@ void wrs_main_loop(struct pp_globals *ppg)
PP_MAX_FRAME_LENGTH - 4,
&ppi->last_rcv_time);
if (i == -2) {
continue; /* dropped */
}
if (i == -1) {
pp_diag(ppi, frames, 1,
"Receive Error %i: %s\n",
errno, strerror(errno));
continue;
}
if (i < PP_MINIMUM_LENGTH) {
pp_diag(ppi, frames, 1,
"Error or short frame: "
"%d < %d\n", i,
PP_MINIMUM_LENGTH
);
"Short frame: %d < %d\n", i,
PP_MINIMUM_LENGTH);
continue;
}
......
......@@ -64,6 +64,7 @@ int main(int argc, char **argv)
struct pp_globals *ppg;
struct pp_instance *ppi;
struct wr_dsport *wrp;
unsigned long seed;
struct timex t;
int i, hal_retries;
......@@ -182,6 +183,11 @@ int main(int argc, char **argv)
pp_init_globals(ppg, &__pp_default_rt_opts);
seed = time(NULL);
if (getenv("PPSI_DROP_SEED"))
seed = atoi(getenv("PPSI_DROP_SEED"));
ppsi_drop_init(ppg, seed);
wrs_main_loop(ppg);
return 0; /* never reached */
}
......@@ -35,7 +35,7 @@
@setchapternewpage off
@set update-month March 2014
@set update-month July 2014
@set release __RELEASE_GIT_ID__
@finalout
......@@ -427,11 +427,56 @@ may document the keywords, if the time allows it.
configuration options. This applies to the priorities, intervals and
thresholds, as well as the @i{slave-only} flag.
@c ==========================================================================
@node Configuring Faults
@section Configuring Faults
Configuration, for @t{arch-unix} and @t{arch-wrs}, allows to provide
some fault injection.
In particular, the program allows dropping frames, in both the TX and RX
paths. The configuration values state how many frames are dropped every
1000. Dropping is randomized, but the user can set the seed to ensure
a repeatable dropping sequence.
Dropping transmitted frames is performed by reporting success (and the
timestamp), while no frame is actually sent. A diagnostic message
is generated at @t{frames} level 1, but other than than that nothing
happens. Actually, @t{arch-wrs} needs to actually send a frame in
order to get a timestamp back; in this case the program modifies the
frame, to use a wrong Ethernet type or a wrong UDP port.
Dropping received frames is performed by actually receiving (and
timestamping), but returning a special error code to the caller.
Again, PPSi creates a diagnostic message at @t{frames} level 1.
The following configuration lines are supported:
@table @code
@item rx-drop <value>
@itemx tx-drop <value>
Drop @i{value} frames every 1000 frames received or sent.
The randomized sequence is global.
@end table
The randomization see can be passed by pre-setting the environment
variable @t{PPSI_DROP_SEED} to a decimal numeric value. For example:
@smallexample
export PPSI_DROP_SEED=33
@end smallexample
@noindent
before starting the daemon.
@c ==========================================================================
@node Configuring the Simulator
@section Configuring the Simulator
To tun the PPSi simulator you need to rely on diagnostics and specific
To run the PPSi simulator you need to rely on diagnostics and specific
configuration items. The configuration items are defined in
@i{arch-sim/sim-conf.c} and are not individually documented here at
this point.
......
......@@ -213,6 +213,8 @@ struct pp_globals {
int max_links;
struct pp_globals_cfg cfg;
int rxdrop, txdrop; /* fault injection, per thousand */
void *arch_data; /* if arch needs it */
/* FIXME Here include all is common to many interfaces */
};
......
......@@ -389,4 +389,9 @@ extern pp_action pp_initializing, pp_faulty, pp_disabled, pp_listening,
/* The engine */
extern int pp_state_machine(struct pp_instance *ppi, uint8_t *packet, int plen);
/* Frame-drop support -- rx before tx, alphabetically */
extern void ppsi_drop_init(struct pp_globals *ppg, unsigned long seed);
extern int ppsi_drop_rx(void);
extern int ppsi_drop_tx(void);
#endif /* __PPSI_PPSI_H__ */
/*
* Copyright (C) 2014 CERN (www.cern.ch)
* Authors: Alessandro Rubini
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*/
#include <ppsi/ppsi.h>
/* Always rx before tx (alphabetic) */
struct ppsi_drop {
unsigned long rxrand, txrand;
int rxrate, txrate;
};
static struct ppsi_drop d;
static inline unsigned long drop_this(unsigned long *p, int rate)
{
/* hash the value, according to the TYPE_0 rule of glibc */
*p = ((*p * 1103515245) + 12345) & 0x7fffffff;
return (*p % 1000) < rate;
}
void ppsi_drop_init(struct pp_globals *ppg, unsigned long seed)
{
/* lazily, avoid passing globals every time */
d.rxrand = seed;
d.txrand = seed + 1;
d.rxrate = ppg->rxdrop;
d.txrate = ppg->txdrop;
}
int ppsi_drop_rx(void)
{
if (d.rxrate)
return drop_this(&d.rxrand, d.rxrate);
return 0;
}
int ppsi_drop_tx(void)
{
if (d.txrate)
return drop_this(&d.txrand, d.txrate);
return 0;
}
......@@ -87,6 +87,12 @@ static int unix_recv_msg(struct pp_instance *ppi, int fd, void *pkt, int len,
*/
ppi->t_ops->get(ppi, t);
}
if (ppsi_drop_rx()) {
pp_diag(ppi, frames, 1, "Drop received frame\n");
return -2;
}
/* This is not really hw... */
pp_diag(ppi, time, 2, "recv stamp: %i.%09i (%s)\n",
(int)t->seconds, (int)t->nanoseconds, tv ? "kernel" : "user");
......@@ -132,6 +138,14 @@ static int unix_net_send(struct pp_instance *ppi, void *pkt, int len,
struct ethhdr *hdr = pkt;
int ret;
/* To fake a network frame loss, set the timestamp and do not send */
if (ppsi_drop_tx()) {
if (t)
ppi->t_ops->get(ppi, t);
pp_diag(ppi, frames, 1, "Drop sent frame\n");
return len;
}
if (ppi->ethernet_mode) {
hdr->h_proto = htons(ETH_P_1588);
......@@ -358,6 +372,7 @@ static int unix_net_init(struct pp_instance *ppi)
if (unix_open_ch(ppi, ppi->iface_name, i))
return -1;
}
return 0;
}
......
......@@ -223,7 +223,7 @@ static int wrs_recv_msg(struct pp_instance *ppi, int fd, void *pkt, int len,
if (!WR_DSPOR(ppi)->wrModeOn) {
/* for non-wr-mode any reported stamp is correct */
t->correct = 1;
return ret;
goto drop;
}
if (s->dmtd_phase_valid)
{
......@@ -233,6 +233,12 @@ static int wrs_recv_msg(struct pp_instance *ppi, int fd, void *pkt, int len,
}
}
drop:
if (ppsi_drop_rx()) {
pp_diag(ppi, frames, 1, "Drop received frame\n");
return -2;
}
return ret;
}
......@@ -344,13 +350,22 @@ int wrs_net_send(struct pp_instance *ppi, void *pkt, int len,
struct sockaddr_in addr;
struct ethhdr *hdr = pkt;
struct wrs_socket *s;
int ret, fd;
int ret, fd, drop;
s = (struct wrs_socket *)NP(ppi)->ch[PP_NP_GEN].arch_data;
/*
* To fake a packet loss, we must corrupt the frame; we need
* to transmit it for real, if we want to get back our
* hardware stamp. Thus, remember if we drop, and use this info.
*/
drop = ppsi_drop_tx();
if (ppi->ethernet_mode) {
fd = NP(ppi)->ch[PP_NP_GEN].fd;
hdr->h_proto = htons(ETH_P_1588);
if (drop)
hdr->h_proto++;
memcpy(hdr->h_dest, PP_MCAST_MACADDRESS, ETH_ALEN);
/* raw socket implementation always uses gen socket */
......@@ -361,6 +376,10 @@ int wrs_net_send(struct pp_instance *ppi, void *pkt, int len,
ret = send(fd, hdr, len, 0);
poll_tx_timestamp(ppi, s, fd, t);
if (drop) /* avoid messaging about stamps that are not used */
goto drop_msg;
if (pp_diag_allow(ppi, frames, 2))
dump_1588pkt("send: ", pkt, len, t);
pp_diag(ppi, time, 1, "send stamp: (correct %i) %9li.%09li\n",
......@@ -374,15 +393,24 @@ int wrs_net_send(struct pp_instance *ppi, void *pkt, int len,
addr.sin_family = AF_INET;
addr.sin_port = htons(chtype == PP_NP_GEN ? PP_GEN_PORT : PP_EVT_PORT);
addr.sin_addr.s_addr = NP(ppi)->mcast_addr;
if (drop)
addr.sin_port = 3200;
ret = sendto(fd, pkt, len, 0,
(struct sockaddr *)&addr, sizeof(struct sockaddr_in));
poll_tx_timestamp(ppi, s, fd, t);
if (drop) /* like above: skil messages about timestamps */
goto drop_msg;
if (pp_diag_allow(ppi, frames, 2))
dump_payloadpkt("send: ", pkt, len, t);
pp_diag(ppi, time, 1, "send stamp: (correct %i) %9li.%09li\n",
t->correct, (long)t->seconds,
(long)t->nanoseconds);
drop_msg:
if (drop)
pp_diag(ppi, frames, 1, "Drop sent frame\n");
return ret;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment