Commit 2723ad02 authored by Alessandro Rubini's avatar Alessandro Rubini

Merge branch 'latency-test'

parents 1a4665dd 965efd02
......@@ -106,6 +106,10 @@ config W1
boolean
default y
config LATENCY_ETHTYPE
int
default 0
# The other ones can be set by non-developers
config IP
......@@ -396,6 +400,21 @@ config LEGACY_EEPROM
boolean
default !SDB_STORAGE
config LATENCY_PROBE
depends on DEVELOPER
bool "Build the latency probe mechanism (send/recv)"
help
The latency prober sends two frames to broadcast and
then the timestamp of their departure time. The receiver
measures the network latency and reports it.
If this option is set, the receiver is always running. The
sender is built but must be activated by the latency shell cmd.
config LATENCY_ETHTYPE
depends on LATENCY_PROBE
int "Ethtype to use for latency probing"
# This is needed to size the pp_instance data strucuture. Instead of
# including the ppsi autoconf.h, with duplicate definitions, define it
# here, as we know what the value is
......
......@@ -6,6 +6,7 @@ CONFIG_WR_NODE=y
CONFIG_PRINT_BUFSIZE=128
# CONFIG_PRINTF_XINT is not set
CONFIG_RAMSIZE=131072
CONFIG_TEMP_POLL_INTERVAL=15
CONFIG_PLL_VERBOSE=y
CONFIG_PFILTER_VERBOSE=y
CONFIG_WRC_VERBOSE=y
......@@ -14,11 +15,15 @@ CONFIG_VLAN_NR=10
CONFIG_VLAN_1_FOR_CLASS7=20
CONFIG_VLAN_2_FOR_CLASS7=30
CONFIG_VLAN_FOR_CLASS6=100
# CONFIG_HOST_PROCESS is not set
CONFIG_LM32=y
CONFIG_EMBEDDED_NODE=y
# CONFIG_WR_NODE_PCS16 is not set
CONFIG_STACKSIZE=2048
CONFIG_PPSI=y
CONFIG_UART=y
CONFIG_W1=y
CONFIG_LATENCY_ETHTYPE=4455
CONFIG_IP=y
CONFIG_CMD_CONFIG=y
CONFIG_SYSLOG=y
......@@ -26,13 +31,15 @@ CONFIG_BUILD_INIT=y
CONFIG_INIT_COMMAND="help"
CONFIG_HAS_BUILD_INIT=1
CONFIG_HAS_FLASH_INIT=1
CONFIG_FLASH_INIT=y
#
# wrpc-sw is tainted if you change the following options
#
CONFIG_DEVELOPER=y
CONFIG_TEMP_HIGH_THRESHOLD=70
CONFIG_TEMP_HIGH_RAPPEL=60
CONFIG_CMD_LL=y
CONFIG_FLASH_INIT=y
CONFIG_CHECK_RESET=y
CONFIG_SPLL_FIFO_LOG=y
CONFIG_PRINTF_FULL=y
......@@ -41,6 +48,8 @@ CONFIG_PRINTF_FULL=y
CONFIG_DETERMINISTIC_BINARY=y
CONFIG_UART_SW=y
CONFIG_NET_VERBOSE=y
CONFIG_FAKE_TEMPERATURES=y
CONFIG_SDB_STORAGE=y
# CONFIG_LEGACY_EEPROM is not set
CONFIG_LATENCY_PROBE=y
CONFIG_VLAN_ARRAY_SIZE=1
......@@ -61,6 +61,7 @@ void pfilter_init_default(void)
uint64_t cmd_word;
int i;
static int inited;
uint32_t latency_ethtype = CONFIG_LATENCY_ETHTYPE;
/* If vlan, use rule-set 1, else rule-set 0 */
s = rule_sets + (wrc_vlan_number != 0);
......@@ -114,6 +115,22 @@ void pfilter_init_default(void)
pfilter_verbose("fixing MAC adress in rule: use %s\n",
format_mac(buf, mac));
/*
* Patch in the "latency" ethtype too. This is set at build time
* so there's not need to remember the place or the value.
*/
if (latency_ethtype == 0)
latency_ethtype = 0x88f7; /* reuse PTPv2 type: turn into NOP */
for (v = vini + 1; v < vend; v += 2) {
if (((*v >> 13) & 0xffff) == 0xcafe
&& (*v & 0x7) == OR) {
pfilter_verbose("fixing latency eth_type: use 0x%x\n",
latency_ethtype);
*v &= ~(0xffff << 13);
*v |= latency_ethtype << 13;
}
}
/* If this is the VLAN rule-set, patch the vlan number too */
for (v = vini + 1; v < vend; v += 2) {
if (((*v >> 13) & 0xffff) == 0x0aaa
......
......@@ -55,6 +55,7 @@ struct sockq {
struct wrpc_socket {
struct wr_sockaddr bind_addr;
mac_addr_t local_mac;
uint16_t prio;
uint32_t phase_transition;
uint32_t dmtd_phase;
......
/*
* This work is part of the White Rabbit project
*
* Copyright (C) 2016 GSI (www.gsi.de)
* Author: Alessandro Rubini <a.rubini@gsi.de>
*
* Released according to the GNU GPL, version 2 or any later version.
*/
#include <wrc.h>
#include <wrpc.h>
#include <ptpd_netif.h>
#include <shell.h>
#include "ipv4.h"
/* latency probe: we need to enqueue 3 short frames: 64*3+overhead = 256 */
static uint8_t __latency_queue[256];
static struct wrpc_socket *latency_socket, __static_latency_socket = {
.queue.buff = __latency_queue,
.queue.size = sizeof(__latency_queue),
};
static struct wr_sockaddr latency_addr = {
.mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, /* for binding */
.mac_dest = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, /* for sending */
.ethertype = 0, /* htons(CONFIG_LATENCY_ETHTYPE) -- not constant! */
};
static void latency_init(void)
{
latency_addr.ethertype = htons(CONFIG_LATENCY_ETHTYPE);
latency_socket = ptpd_netif_create_socket(&__static_latency_socket,
&latency_addr,
PTPD_SOCK_RAW_ETHERNET, 0);
}
static struct latency_frame {
uint32_t type; /* 1, 2, 3 */
uint32_t sequence;
struct wr_timestamp ts1, ts2;
} frame;
static uint16_t prev_sequence, prev_type;
static void ts_sub(struct wr_timestamp *t2, struct wr_timestamp *t1,
struct wr_timestamp *res)
{
int64_t resll; /* every field is signed: good */
resll = t2->sec - t1->sec;
resll *= 1000 * 1000 * 1000;
resll += t2->nsec - t1->nsec;
resll *= 1000;
resll += t2->phase - t1->phase;
/* seconds must be 0 and result must be positive */
res->sec = 0;
res->phase = __div64_32((uint64_t *)&resll, 1000);
res->nsec = resll;
}
static void latency_warning(void) {
pp_printf("lat: unexpected %i.%i after %i.%i\n",
frame.sequence, frame.type, prev_sequence, prev_type);
}
static int latency_poll_rx(void)
{
static struct wr_timestamp ts[2];
static int nframes;
struct wr_timestamp ts_tmp, lat[2];
struct wr_sockaddr addr;
int len;
len = ptpd_netif_recvfrom(latency_socket, &addr,
&frame, sizeof(frame), &ts_tmp);
if (len < sizeof(frame))
return 0;
/* check sequence and type is ok */
switch(frame.type) {
case 1:
if (frame.sequence != prev_sequence + 1 || prev_type != 3)
latency_warning();
ts[0] = ts_tmp; /* 0 is always valid, it's a new set */
nframes = 1;
ts[1].sec = 0; /* but still incomplete info */
break;
case 2:
if (frame.sequence != prev_sequence || prev_type != 1) {
latency_warning();
} else {
ts[1] = ts_tmp;
nframes++;
}
break;
case 3:
if (frame.sequence != prev_sequence || prev_type != 2) {
latency_warning();
} else {
nframes++;
}
break;
}
prev_sequence = frame.sequence;
prev_type = frame.type;
if (frame.type != 3 || nframes != 3)
return 1;
net_verbose("ts_rx 1: %9li.%09i.%03i\n", (long)ts[0].sec,
ts[0].nsec, ts[0].phase);
net_verbose("ts_tx 1: %9li.%09i.%03i\n", (long)frame.ts1.sec,
frame.ts1.nsec, frame.ts1.phase);
net_verbose("ts_rx 2: %9li.%09i.%03i\n", (long)ts[1].sec,
ts[1].nsec, ts[1].phase);
net_verbose("ts_tx 2: %9li.%09i.%03i\n", (long)frame.ts2.sec,
frame.ts2.nsec, frame.ts2.phase);
ts_sub(ts + 0, &frame.ts1, lat + 0);
ts_sub(ts + 1, &frame.ts2, lat + 1);
pp_printf("lat: %9i %6i.%03i %6i.%03i\n",
frame.sequence,
lat[0].nsec, lat[0].phase,
lat[1].nsec, lat[1].phase);
return 1;
}
static int latency_poll_tx(void)
{
static uint32_t sequence;
static uint32_t lasts;
/* Send three frames -- lazily in native byte order */
memset(&frame, 0, sizeof(frame));
frame.sequence = sequence++;
frame.type = 1;
latency_socket->prio = 7;
ptpd_netif_sendto(latency_socket, &latency_addr, &frame, sizeof(frame),
&frame.ts1);
frame.type = 2;
latency_socket->prio = 6;
ptpd_netif_sendto(latency_socket, &latency_addr, &frame, sizeof(frame),
&frame.ts2);
frame.type = 3;
latency_socket->prio = 0;
ptpd_netif_sendto(latency_socket, &latency_addr, &frame, sizeof(frame),
NULL);
/* Every 10s remind we are sending ltest */
if (!lasts) {
lasts = frame.ts2.sec;
} else if (frame.ts2.sec - lasts >= 10) {
lasts = frame.ts2.sec;
pp_printf("latency: seq %9i sent @ %9i\n",
sequence, lasts);
}
return 1;
}
static uint32_t lastt;
static uint32_t latency_period_ms;
static int latency_poll(void)
{
if (!latency_period_ms)
return latency_poll_rx();
/* Periodically send the frames */
if (task_not_yet(&lastt, latency_period_ms))
return 0;
return latency_poll_tx();
}
DEFINE_WRC_TASK(uptime) = {
.name = "latency-probe",
.init = latency_init,
.job = latency_poll,
};
static int cmd_ltest(const char *args[])
{
int v = 0, v1 = 0;
if (args[1]) {
fromdec(args[1], &v1); /* ms */
}
if (args[0]) {
fromdec(args[0], &v);
latency_period_ms = v * 1000 + v1;
lastt = 0; /* reset, so it fires immediately */
}
pp_printf("%i.%03i\n", latency_period_ms / 1000,
latency_period_ms % 1000);
return 0;
}
DEFINE_WRC_COMMAND(ltest) = {
.name = "ltest",
.exec = cmd_ltest,
};
......@@ -8,3 +8,4 @@ obj-$(CONFIG_WR_NODE) += lib/net.o
obj-$(CONFIG_IP) += lib/ipv4.o lib/arp.o lib/icmp.o lib/udp.o lib/bootp.o
obj-$(CONFIG_SYSLOG) += lib/syslog.o
obj-$(CONFIG_LATENCY_PROBE) += lib/latency.o
......@@ -284,7 +284,7 @@ int ptpd_netif_sendto(struct wrpc_socket * sock, struct wr_sockaddr *to, void *d
memcpy(hdr.srcmac, s->local_mac, 6);
if (wrc_vlan_number) {
hdr.ethtype = htons(0x8100);
hdr.tag = htons(wrc_vlan_number);
hdr.tag = htons(wrc_vlan_number | (sock->prio << 13));
hdr.ethtype_2 = sock->bind_addr.ethertype; /* net order */
} else {
hdr.ethtype = sock->bind_addr.ethertype;
......
......@@ -216,6 +216,7 @@ enum pf_symbolic_regs {
FRAME_OUR_VLAN,
FRAME_TYPE_IPV4,
FRAME_TYPE_PTP2,
FRAME_TYPE_LATENCY,
FRAME_TYPE_ARP,
FRAME_ICMP,
FRAME_UDP,
......@@ -398,8 +399,9 @@ void pfilter_init_novlan(char *fname)
pfilter_cmp(6, 0x8100, 0xffff, MOV, R_TMP);
pfilter_logic2(R_DROP, R_TMP, MOV, R_ZERO);
/* Identify some Ethertypes used later. */
/* Identify some Ethertypes used later -- type latency is 0xcafe */
pfilter_cmp(6, 0x88f7, 0xffff, MOV, FRAME_TYPE_PTP2);
pfilter_cmp(6, 0xcafe, 0xffff, OR, FRAME_TYPE_PTP2);
pfilter_cmp(6, 0x0800, 0xffff, MOV, FRAME_TYPE_IPV4);
pfilter_cmp(6, 0x0806, 0xffff, MOV, FRAME_TYPE_ARP);
......@@ -411,7 +413,7 @@ void pfilter_init_novlan(char *fname)
pfilter_cmp(11, 0x0011, 0x00ff, MOV, FRAME_UDP);
pfilter_logic2(FRAME_UDP, FRAME_UDP, AND, FRAME_IP_OK);
/* For CPU: arp broadcast or icmp unicast or ptp */
/* For CPU: arp broadcast or icmp unicast or ptp (or latency) */
pfilter_logic3(FRAME_FOR_CPU, FRAME_BROADCAST, AND, FRAME_TYPE_ARP, OR, FRAME_TYPE_PTP2);
pfilter_logic3(FRAME_FOR_CPU, FRAME_IP_OK, AND, FRAME_ICMP, OR, FRAME_FOR_CPU);
......@@ -481,8 +483,9 @@ void pfilter_init_vlan(char *fname)
/* Compare with our vlan (fake number 0xaaa) */
pfilter_cmp(7, 0x0aaa, 0x0fff, MOV, FRAME_OUR_VLAN);
/* Identify some Ethertypes used later. */
/* Identify some Ethertypes used later -- type latency is 0xcafe */
pfilter_cmp(8, 0x88f7, 0xffff, MOV, FRAME_TYPE_PTP2);
pfilter_cmp(8, 0xcafe, 0xffff, OR, FRAME_TYPE_PTP2);
pfilter_cmp(8, 0x0800, 0xffff, MOV, FRAME_TYPE_IPV4);
pfilter_cmp(8, 0x0806, 0xffff, MOV, FRAME_TYPE_ARP);
......
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