Commit bc172173 authored by Alessandro Rubini's avatar Alessandro Rubini

Merge branch 'vlan-unix-wrs'

parents 594beec6 d37136ea
......@@ -6,6 +6,8 @@ choice
config ARCH_UNIX
bool "Unix (Linux and likely other systems)"
select HAS_VLAN
select HAS_MULTIPLE_VLAN
help
ARCH=unix supports standard Unix system calls, although
the code most likely includes some Linux dependencies.
......@@ -33,6 +35,7 @@ config ARCH_BARE_X86_64
config ARCH_WRPC
bool "White Rabbit PTP Core (WR Node)"
select CONFIG_EXT_WR
select HAS_VLAN
help
Build PPSi for use in the WRPC environment (SPEC card or similar
one). This is a freestanding build, without operating system.
......@@ -41,6 +44,8 @@ config ARCH_WRPC
config ARCH_WRS
bool "White Rabbit Switch"
select CONFIG_EXT_WR
select HAS_VLAN
select HAS_MULTIPLE_VLAN
help
Build PPSi for use in the WR switch. The computer is a standard
ARM-Linux host with hardware timestamping and internal PLLs
......@@ -106,3 +111,45 @@ config WRPCSW_ROOT
string "Source location of wrpc-sw"
depends on ARCH_WRPC
default "../wrpc-sw"
# Vlan support: not all architectures have it, so this is set by them
config HAS_VLAN
bool
config HAS_MULTIPLE_VLAN
bool
config VLAN
bool "Enable VLAN support for raw Ethernet"
depends on HAS_VLAN || HAS_MULTIPLE_VLAN
default y
help
PPSI is able to directly emit and receive tagged frames,
with some architectures (if you see this option, it means
the architecture you selected has such support). A
designated master port can send announce on several VLANs,
but the other roles (designated slave or auto) can only bind
to a single VLAN. This choice is a tradeoff between code
complexity and flexibility.
Please note that you can always create several PTP ports that
act on different VLANs on the same physical port, and you can
also run VLAN support in your OS without special PPSI code.
Please see the PPSI documentation for details.
config MAX_VLANS_PER_PORT
int "Maximum number of VLANs per port"
depends on HAS_MULTIPLE_VLAN
default 32
help
This configuration option is mainly used to support
the special case of 1 VLAN per port, useful for
microcontroller-class architectures. Hosted builds
feature a bigger default, because they have no size constraints.
# I want a number, to be used without ifdef
config VLAN_ARRAY_SIZE
int
default 0 if !VLAN
default 1 if !HAS_MULTIPLE_VLAN
default MAX_VLANS_PER_PORT
......@@ -92,7 +92,7 @@ void sim_main_loop(struct pp_globals *ppg)
sim_set_global_DS(ppi);
tmp_ns = 1000LL * 1000LL * pp_state_machine(ppi,
ppi->rx_ptp, i - NP(ppi)->ptp_offset);
ppi->rx_ptp, i - ppi->rx_offset);
if (tmp_ns < delay_ns)
delay_ns = tmp_ns;
......
......@@ -106,6 +106,7 @@ int main(int argc, char **argv)
for (i = 0; i < ppg->max_links; i++) {
ppi = INST(ppg, i);
ppi->glbs = ppg; // must be done before using sim_set_global_DS
ppi->vlans_array_len = CONFIG_VLAN_ARRAY_SIZE;
if (sim_ppi_init(ppi, i))
return -1;
}
......@@ -145,8 +146,8 @@ int main(int argc, char **argv)
if (ppi->proto == PPSI_PROTO_RAW)
pp_printf("Warning: simulator doesn't support raw "
"ethernet. Using UDP\n");
NP(ppi)->ch[PP_NP_GEN].fd = -1;
NP(ppi)->ch[PP_NP_EVT].fd = -1;
ppi->ch[PP_NP_GEN].fd = -1;
ppi->ch[PP_NP_EVT].fd = -1;
ppi->t_ops = &DEFAULT_TIME_OPS;
ppi->n_ops = &DEFAULT_NET_OPS;
if (pp_sim_is_master(ppi))
......
......@@ -49,13 +49,6 @@ void unix_main_loop(struct pp_globals *ppg)
ppi = INST(ppg, j);
/*
* If we are sending or receiving raw ethernet frames,
* the ptp payload is one-eth-header bytes into the frame
*/
if (ppi->proto == PPSI_PROTO_RAW)
NP(ppi)->ptp_offset = ETH_HLEN;
/*
* The main loop here is based on select. While we are not
* doing anything else but the protocol, this allows extra stuff
......@@ -107,8 +100,8 @@ void unix_main_loop(struct pp_globals *ppg)
int tmp_d;
ppi = INST(ppg, j);
if ((NP(ppi)->ch[PP_NP_GEN].pkt_present) ||
(NP(ppi)->ch[PP_NP_EVT].pkt_present)) {
if ((ppi->ch[PP_NP_GEN].pkt_present) ||
(ppi->ch[PP_NP_EVT].pkt_present)) {
i = __recv_and_count(ppi, ppi->rx_frame,
PP_MAX_FRAME_LENGTH - 4,
......@@ -131,7 +124,7 @@ void unix_main_loop(struct pp_globals *ppg)
}
tmp_d = pp_state_machine(ppi, ppi->rx_ptp,
i - NP(ppi)->ptp_offset);
i - ppi->rx_offset);
if ((delay_ms == -1) || (tmp_d < delay_ms))
delay_ms = tmp_d;
......
......@@ -84,10 +84,11 @@ int main(int argc, char **argv)
for (i = 0; i < ppg->nlinks; i++) {
ppi = INST(ppg, i);
NP(ppi)->ch[PP_NP_EVT].fd = -1;
NP(ppi)->ch[PP_NP_GEN].fd = -1;
ppi->ch[PP_NP_EVT].fd = -1;
ppi->ch[PP_NP_GEN].fd = -1;
ppi->glbs = ppg;
ppi->vlans_array_len = CONFIG_VLAN_ARRAY_SIZE,
ppi->iface_name = ppi->cfg.iface_name;
ppi->port_name = ppi->cfg.port_name;
......
......@@ -78,6 +78,7 @@ struct pp_instance ppi_static = {
.portDS = &portDS,
.n_ops = &wrpc_net_ops,
.t_ops = &wrpc_time_ops,
.vlans_array_len = CONFIG_VLAN_ARRAY_SIZE,
.proto = PP_DEFAULT_PROTO,
.iface_name = "wr1",
.port_name = "wr1",
......
......@@ -88,13 +88,6 @@ void wrs_main_loop(struct pp_globals *ppg)
ppi = INST(ppg, j);
/*
* If we are sending or receiving raw ethernet frames,
* the ptp payload is one-eth-header bytes into the frame
*/
if (ppi->proto == PPSI_PROTO_RAW)
NP(ppi)->ptp_offset = ETH_HLEN;
/*
* The main loop here is based on select. While we are not
* doing anything else but the protocol, this allows extra stuff
......@@ -148,8 +141,8 @@ void wrs_main_loop(struct pp_globals *ppg)
int tmp_d;
ppi = INST(ppg, j);
if ((NP(ppi)->ch[PP_NP_GEN].pkt_present) ||
(NP(ppi)->ch[PP_NP_EVT].pkt_present)) {
if ((ppi->ch[PP_NP_GEN].pkt_present) ||
(ppi->ch[PP_NP_EVT].pkt_present)) {
i = __recv_and_count(ppi, ppi->rx_frame,
PP_MAX_FRAME_LENGTH - 4,
......@@ -172,7 +165,7 @@ void wrs_main_loop(struct pp_globals *ppg)
}
tmp_d = pp_state_machine(ppi, ppi->rx_ptp,
i - NP(ppi)->ptp_offset);
i - ppi->rx_offset);
if ((delay_ms == -1) || (tmp_d < delay_ms))
delay_ms = tmp_d;
......
......@@ -199,10 +199,11 @@ int main(int argc, char **argv)
}
for (i = 0; i < ppg->nlinks; i++) {
ppi = INST(ppg, i);
NP(ppi)->ch[PP_NP_EVT].fd = -1;
NP(ppi)->ch[PP_NP_GEN].fd = -1;
ppi->ch[PP_NP_EVT].fd = -1;
ppi->ch[PP_NP_GEN].fd = -1;
ppi->glbs = ppg;
ppi->vlans_array_len = CONFIG_VLAN_ARRAY_SIZE;
ppi->iface_name = ppi->cfg.iface_name;
ppi->port_name = ppi->cfg.port_name;
ppi->portDS = calloc(1, sizeof(*ppi->portDS));
......
......@@ -508,6 +508,125 @@ transmission jitter, you can run like this:
@end smallexample
@c ##########################################################################
@node VLAN Support
@chapter VLAN Support
PPSi can support vlans, or use support the Operating System offers.
@c ==========================================================================
@node OS VLAN
@section OS VLAN
If the OS supports vlans, PPSi can rely on it. For example a
Linux-based architecture can be configured to run on interface
@t{eth0.20} and thus work on vlan 20. In this case, use of
@i{vconfig} is left to the user, and nothing special is performed by
PPSi itself, nor any special configuration is needed. In this setup
both raw Ethernet and UDP can be used.
@c ==========================================================================
@node PPSi VLAN
@section PPSi VLAN
Freestanding architectures, like the WR PTP Core (@t{arch-wrpc}) can't
rely on the underlying Operating System, so the daemon must read and
write vlan Ethernet headers by itself -- in this situation UDP is not
supported, unless your own architecture's network operations build and
decode IP and UDP headers (in official PPSi no such support is there).
Another situation where PPSi should deal with vlans directly is when
you want a port to be master on several vlans at the same time, but
this is only supported for @i{mandated} masters, at this point in
time. A mandated master is a port configured as ``@t{role master}''
in the configuration file. If you want to run multiple vlans on the
same physical ports, without forcing the port to be a mandated master,
you can create multiple PTP interfaces, one per vlan, all relying on
the same physical port (or different OS-specific vlan ports).
When running a fully-PTP network in end-to-end mode, you won't usually
need to configure multiple vlans on a single port. In particular, this
never happens in a White Rabbit network, because each link connects
two clocks, without any non-compliant switches in the middle.
However, if you have
transparent clocks or normal switches, you may want to behave
as a master for the whole network connected to your port, which may
be split in several vlans. Clearly this only applies to a @i{trunk}
port in your PTP switch or workstation.
To support this we rely on @i{Kconfig} and architecture-specific
code, in the following way.
@itemize @bullet
@item Each architecture states, in @t{Kconfig}, whether it supports
vlans (@t{HAS_VLAN}) and multiple vlans (@t{HAS_MULTIPLE_VLAN}).
@item The configuration parser (@t{lib/conf.c}) accepts a @t{vlan}
keyword, specifying one or more vlans. If several, they are
comma-separated.
@item Configuration fails (and PPSi refuses to start) if the architecture
has no vlan support, or of multiple vlans are specified for an
architecture that supports one vlan only.
@item Configuration fails also if several vlans are specified for
a port that is not a mandated master.
@end itemize
When only one vlan is specified, the network operations for the
architecture are responsible: they must do the right thing. Currently,
@t{wrpc} builds and decodes Ethernet frames (FIXME: NOT YET), ignoring
any received frame not belonging to the proper vlan. Code for @t{wrs} and
@t{unix} handles a single vlan like multiple ones; I thought
about automatically creating the vlan-specific interface, but that
would be very Linux-specific and I see no real need for it.
When multiple vlans are specified for a master port, current code
(i.e. @t{arch-wrs} and @t{arch-unix}) binds to @t{ETH_P_ALL}, in order
to receive all frames from that interface, and thus be able to tell
which vlan they belong to. A multiple-vlan master sends announce and
sync (plus follow-up) to all vlans at the same time, and will reply to
delay requests using the same vlan it receives it from. Frames from
other vlans, as well as non-PTP frames, are ignored.
Because of the @t{ETH_P_ALL} binding, a multiple-vlan master port will
receive all the non-PTP traffic that flows on the interface. Please be
warned that this may increase the load on your PPSi process. With the
current release of the White Rabbit Switch this is not a problem,
because the switching core routes only PTP frames to the CPU. This
applies to single-vlan ports, because PPSi is not creating the
Linux-specific interface to have the kernel select traffic for us.
@c ==========================================================================
@node Note about vlans in Linux
@section Note about vlans in Linux
The choices described above depend on how vlans work in Linux (the
architecture we use in the White Rabbit Switch, and the one we support
in @t{arch-unix}).
If a packet socket is bound to a specific Ethernet protocol (for
example, the PTP Ethernet type, 0x88f7), on a generic Ethernet port
like @t{eth0}, it receives all frames for that @i{ethertype}, whether
or not they are tagged on the wire. To our knowledge there is no way,
in this situation, to tell whether the frame was tagged, and which tag
were there if any. Only traffic to vlan-specific ports, like
@t{eth0.20}, si guaranteed to belong to vlan 20 (or a double-tagged
frame, whose external tag is 20).
Only a socket bound to all @i{ethertypes} (i.e. @t{ETH_P_ALL}) is able
to receive auxiliary metadata that reports whether the frame was
tagged and which tag it was carrying.
The behavior above depends on how hardware acceleration for tags work,
and even if it is suboptimal for this use case, we don't know about
alternatives. Thus, a PPSi port configured for vlan frames, is bound
to the base ethernet port, but it must receive all @i{ethertypes}.
If this is not ok for your configuration, you can create your own
vlan-aware Linux port and bind to it. It works correctly with smaller
CPU overhead, but more administrative work.
@c ##########################################################################
@node PTP Clock Class
@chapter PTP Clock Class
......
......@@ -62,7 +62,6 @@ struct pp_channel {
};
void *arch_data; /* Other arch-private info, if any */
unsigned char addr[6]; /* Our own MAC address */
unsigned char peer[6]; /* Our peer's MAC address */
int pkt_present;
};
......@@ -102,24 +101,12 @@ struct pp_servo {
struct pp_avg_fltr mpd_fltr;
};
/*
* Net Path. Struct which contains the network configuration parameters and
* the event/general channels (sockets on most platforms, see above)
*/
enum {
enum { /* The two sockets. They are called "net path" for historical reasons */
PP_NP_GEN = 0,
PP_NP_EVT,
__NR_PP_NP,
};
struct pp_net_path {
struct pp_channel ch[__NR_PP_NP]; /* general and event ch */
Integer32 mcast_addr; /* FIXME: only ipv4/udp */
int ptp_offset;
};
/*
* Struct containg the result of ppsi.conf parsing: one for each link
* (see lib/conf.c). Actually, protocol and role are in the main ppi.
......@@ -159,7 +146,11 @@ struct pp_instance {
void *tx_frame, *rx_frame, *tx_ptp, *rx_ptp;
/* The net_path used to be allocated separately, but there's no need */
struct pp_net_path np;
struct pp_channel ch[__NR_PP_NP]; /* general and event ch */
Integer32 mcast_addr; /* only ipv4/udp */
int tx_offset, rx_offset; /* ptp payload vs send/recv */
unsigned char peer[6]; /* Our peer's MAC address */
uint16_t peer_vid; /* Our peer's VID (for PROTO_VLAN) */
/* Times, for the various offset computations */
TimeInternal t1, t2, t3, t4; /* *the* stamps */
......@@ -185,7 +176,9 @@ struct pp_instance {
char *iface_name; /* for direct actions on hardware */
char *port_name; /* for diagnostics, mainly */
int port_idx;
int vlans_array_len; /* those looking at shared mem must check */
int vlans[CONFIG_VLAN_ARRAY_SIZE];
int nvlans; /* according to configuration */
struct pp_instance_cfg cfg;
unsigned long ptp_tx_count;
......
......@@ -35,6 +35,15 @@ extern int pp_sprintf(char *s, const char *fmt, ...)
extern int pp_vsprintf(char *buf, const char *, va_list)
__attribute__ ((format (printf, 2, 0)));
/* This structure is never defined, it seems */
struct pp_vlanhdr {
uint8_t h_dest[6];
uint8_t h_source[6];
uint16_t h_tpid;
uint16_t h_tci;
uint16_t h_proto;
};
/* We use data sets a lot, so have these helpers */
static inline struct pp_globals *GLBS(struct pp_instance *ppi)
......@@ -88,9 +97,13 @@ static inline struct DSTimeProperties *DSPRO(struct pp_instance *ppi)
return GLBS(ppi)->timePropertiesDS;
}
static inline struct pp_net_path *NP(struct pp_instance *ppi)
/* We used to have a "netpath" structure. Keep this until we merge pdelay */
static struct pp_instance *NP(struct pp_instance *ppi)
__attribute__((deprecated));
static inline struct pp_instance *NP(struct pp_instance *ppi)
{
return &ppi->np;
return ppi;
}
static inline struct pp_servo *SRV(struct pp_instance *ppi)
......@@ -98,21 +111,8 @@ static inline struct pp_servo *SRV(struct pp_instance *ppi)
return GLBS(ppi)->servo;
}
/* Sometimes (e.g., raw ethernet frames), we need to consider an offset */
static inline void *pp_get_header(struct pp_instance *ppi, void *ptp_payload)
{
return ptp_payload - NP(ppi)->ptp_offset;
}
static inline void *pp_get_payload(struct pp_instance *ppi, void *frame_ptr)
{
return frame_ptr + NP(ppi)->ptp_offset;
}
extern void pp_prepare_pointers(struct pp_instance *ppi);
/*
* Each extension should fill this structure that is used to augment
* the standard states and avoid code duplications. Please remember
......@@ -316,6 +316,7 @@ extern int pp_config_file(struct pp_globals *ppg, int force, char *fname);
#define PPSI_PROTO_RAW 0
#define PPSI_PROTO_UDP 1
#define PPSI_PROTO_VLAN 2 /* Actually: vlan over raw eth */
#define PPSI_ROLE_AUTO 0
#define PPSI_ROLE_MASTER 1
......
......@@ -41,6 +41,7 @@ static struct pp_instance ppi_static = {
.t_ops = &bare_time_ops,
.iface_name = "eth0",
.port_name = "eth0",
.vlans_array_len = CONFIG_VLAN_ARRAY_SIZE,
.proto = PP_DEFAULT_PROTO,
.__tx_buffer = __tx_buffer,
.__rx_buffer = __rx_buffer,
......
......@@ -24,8 +24,6 @@ void bare_main_loop(struct pp_instance *ppi)
{
int delay_ms;
NP(ppi)->ptp_offset = 14;
/*
* The main loop here is based on select. While we are not
* doing anything else but the protocol, this allows extra stuff
......@@ -44,11 +42,11 @@ void bare_main_loop(struct pp_instance *ppi)
again:
FD_ZERO(&set);
FD_SET(NP(ppi)->ch[PP_NP_GEN].fd, &set);
FD_SET(NP(ppi)->ch[PP_NP_EVT].fd, &set);
maxfd = NP(ppi)->ch[PP_NP_GEN].fd;
if (NP(ppi)->ch[PP_NP_EVT].fd > maxfd)
maxfd = NP(ppi)->ch[PP_NP_EVT].fd;
FD_SET(ppi->ch[PP_NP_GEN].fd, &set);
FD_SET(ppi->ch[PP_NP_EVT].fd, &set);
maxfd = ppi->ch[PP_NP_GEN].fd;
if (ppi->ch[PP_NP_EVT].fd > maxfd)
maxfd = ppi->ch[PP_NP_EVT].fd;
i = sys_select(maxfd + 1, &set, NULL, NULL, &tv);
if (i < 0 && bare_errno != 4 /* EINTR */)
......@@ -77,6 +75,6 @@ void bare_main_loop(struct pp_instance *ppi)
goto again;
delay_ms = pp_state_machine(ppi, ppi->rx_ptp,
i - NP(ppi)->ptp_offset);
i - ppi->rx_offset);
}
}
......@@ -118,10 +118,76 @@ static int f_diag(int lineno, struct pp_globals *ppg, union pp_cfg_arg *arg)
return 0;
}
/* VLAN support is per-port, and it depends on configuration itmes */
static int f_vlan(int lineno, struct pp_globals *ppg, union pp_cfg_arg *arg)
{
struct pp_instance *ppi = CUR_PPI(ppg);
int i, n, *v;
char ch, *s;
CHECK_PPI(1);
/* Refuse to add vlan support in non-raw mode */
if (ppi->proto == PPSI_PROTO_UDP) {
pp_printf("config line %i: VLANs with UDP: not supported\n",
lineno);
return -1;
}
/* If there is no support, just warn */
if (CONFIG_VLAN_ARRAY_SIZE == 0) {
pp_printf("Warning: config line %i ignored:"
" this PPSI binary has no VLAN support\n",
lineno);
return 0;
}
if (ppi->nvlans)
pp_printf("Warning: config line %i overrides "
"previous vlan settings\n", lineno);
s = arg->s;
for (v = ppi->vlans, n = 0; n < CONFIG_VLAN_ARRAY_SIZE; n++, v++) {
i = sscanf(s, "%i %c", v, &ch);
if (!i)
break;
if (*v > 4095 || *v < 0) {
pp_printf("config line %i: vlan out of range: %i "
"(valid is 0..4095)\n", lineno, *v);
return -1;
}
if (i == 2 && ch != ',') {
pp_printf("config line %i: unexpected char '%c' "
"after %i\n", lineno, ch, *v);
return -1;
}
if (i == 2)
s = strchr(s, ',') + 1;
else break;
}
if (n == CONFIG_VLAN_ARRAY_SIZE) {
pp_printf("config line %i: too many vlans (%i): max is %i\n",
lineno, n + 1, CONFIG_VLAN_ARRAY_SIZE);
return -1;
}
ppi->nvlans = n + 1; /* item "n" has been assigend too, 0-based */
for (i = 0; i < ppi->nvlans; i++)
pp_diag(NULL, config, 2, " parsed vlan %4i for %s (%s)\n",
ppi->vlans[i], ppi->cfg.port_name, ppi->cfg.iface_name);
pp_diag(NULL, config, 2, "role %i\n", ppi->role);
if (ppi->role != PPSI_ROLE_MASTER && ppi->nvlans > 1) {
pp_printf("config line %i: too many vlans (%i) for slave "
"or auto role\n", lineno, ppi->nvlans);
return -1;
}
ppi->proto = PPSI_PROTO_VLAN;
return 0;
}
/* These are the tables for the parser */
static struct pp_argname arg_proto[] = {
{"raw", PPSI_PROTO_RAW},
{"udp", PPSI_PROTO_UDP},
/* PROTO_VLAN is an internal modification of PROTO_RAW */
{},
};
static struct pp_argname arg_role[] = {
......@@ -143,6 +209,7 @@ static struct pp_argline pp_global_arglines[] = {
{ f_proto, "proto", ARG_NAMES, arg_proto},
{ f_role, "role", ARG_NAMES, arg_role},
{ f_ext, "extension", ARG_NAMES, arg_ext},
{ f_vlan, "vlan", ARG_STR},
{ f_diag, "diagnostics", ARG_STR},
{ f_class, "clock-class", ARG_INT},
{ f_accuracy, "clock-accuracy", ARG_INT},
......
......@@ -41,3 +41,14 @@ struct udphdr {
uint16_t len;
uint16_t check;
};
#ifndef __PPSI_PPSI_H__
/* from ppsi.h -- never defined elsewhere */
struct pp_vlanhdr {
uint8_t h_dest[6];
uint8_t h_source[6];
uint16_t h_tpid;
uint16_t h_tci;
uint16_t h_proto;
};
#endif /* __PPSI_PPSI_H__ */
......@@ -12,9 +12,7 @@
#include <ppsi/lib.h>
#include "wr-constants.h"
#define WRS_PPSI_SHMEM_VERSION 6 /* added fields n_err_state, n_err_offset,
* n_err_rtt, n_err_deltas to
* wr_servo_state_t */
#define WRS_PPSI_SHMEM_VERSION 11 /* peer is per-ppi, not per-chan */
/*
* This structure is used as extension-specific data in the DSPort
......
......@@ -7,6 +7,13 @@
*/
#include <ppsi/ppsi.h>
#include "common-fun.h"
#include "../lib/network_types.h"
#ifdef CONFIG_ARCH_WRS
#define ARCH_IS_WRS 1
#else
#define ARCH_IS_WRS 0
#endif
static void *msg_copy_header(MsgHeader *dest, MsgHeader *src)
{
......@@ -25,12 +32,35 @@ static void *__align_pointer(void *p)
void pp_prepare_pointers(struct pp_instance *ppi)
{
ppi->tx_ptp = __align_pointer(pp_get_payload(ppi, ppi->__tx_buffer));
ppi->rx_ptp = __align_pointer(pp_get_payload(ppi, ppi->__rx_buffer));
/*
* Horrible thing: when we receive vlan, we get standard eth header,
* but when we send we must fill the complete vlan header.
* So we reserve a different number of bytes.
*/
switch(ppi->proto) {
case PPSI_PROTO_RAW:
ppi->tx_offset = ETH_HLEN; /* 14, I know! */
ppi->rx_offset = ETH_HLEN;
break;
case PPSI_PROTO_VLAN:
ppi->tx_offset = sizeof(struct pp_vlanhdr);
/* Hack warning: with wrs we get the whole header */
if (ARCH_IS_WRS)
ppi->rx_offset = sizeof(struct pp_vlanhdr);
else
ppi->rx_offset = ETH_HLEN;
break;
case PPSI_PROTO_UDP:
ppi->tx_offset = 0;
ppi->rx_offset = 0;
break;
}
ppi->tx_ptp = __align_pointer(ppi->__tx_buffer + ppi->tx_offset);
ppi->rx_ptp = __align_pointer(ppi->__rx_buffer + ppi->rx_offset);
/* Now that ptp payload is aligned, get back the header */
ppi->tx_frame = pp_get_header(ppi, ppi->tx_ptp);
ppi->rx_frame = pp_get_header(ppi, ppi->rx_ptp);
ppi->tx_frame = ppi->tx_ptp - ppi->tx_offset;
ppi->rx_frame = ppi->rx_ptp - ppi->rx_offset;
if (0) { /* enable to verify... it works for me though */
pp_printf("%p -> %p %p\n",
......
......@@ -38,7 +38,7 @@ int st_com_slave_handle_followup(struct pp_instance *ppi, unsigned char *buf,
static inline int __send_and_log(struct pp_instance *ppi, int msglen,
int msgtype, int chtype)
{
if (ppi->n_ops->send(ppi, ppi->tx_frame, msglen + NP(ppi)->ptp_offset,
if (ppi->n_ops->send(ppi, ppi->tx_frame, msglen + ppi->tx_offset,
&ppi->last_snt_time, chtype, 0) < msglen) {
pp_diag(ppi, frames, 1, "%s(%d) Message can't be sent\n",
pp_msg_names[msgtype], msgtype);
......
......@@ -24,7 +24,7 @@ int pp_initializing(struct pp_instance *ppi, unsigned char *pkt, int plen)
/* Clock identity comes from mac address with 0xff:0xfe intermixed */
id = (unsigned char *)&DSDEF(ppi)->clockIdentity;
mac = NP(ppi)->ch[PP_NP_GEN].addr;
mac = ppi->ch[PP_NP_GEN].addr;
id[0] = mac[0];
id[1] = mac[1];
id[2] = mac[2];
......
......@@ -9,6 +9,57 @@
#include <ppsi/ppsi.h>
#include "common-fun.h"
/* Local functions that build to nothing when Kconfig selects 0/1 vlans */
static int pp_master_issue_announce(struct pp_instance *ppi)
{
int i, vlan = 0;
if (CONFIG_VLAN_ARRAY_SIZE && ppi->nvlans == 1)
vlan = ppi->vlans[0];
if (CONFIG_VLAN_ARRAY_SIZE <= 1 || ppi->nvlans <= 1) {
ppi->peer_vid = vlan;
return msg_issue_announce(ppi);
}
/*
* If Kconfig selected 0/1 vlans, this code is not built.
* If we have several vlans, we replace peer_vid and proceed;
*/
for (i = 0; i < ppi->nvlans; i++) {
ppi->peer_vid = ppi->vlans[i];
msg_issue_announce(ppi);
/* ignore errors: each vlan is separate */
}
return 0;
}
static int pp_master_issue_sync_followup(struct pp_instance *ppi)
{
int i, vlan = 0;
if (CONFIG_VLAN_ARRAY_SIZE && ppi->nvlans == 1)
vlan = ppi->vlans[0];
if (CONFIG_VLAN_ARRAY_SIZE <= 1 || ppi->nvlans <= 1) {
ppi->peer_vid = vlan;
return msg_issue_sync_followup(ppi);
}
/*
* If Kconfig selected 0/1 vlans, this code is not built.
* If we have several vlans, we replace peer_vid and proceed;
*/
for (i = 0; i < ppi->nvlans; i++) {
ppi->peer_vid = ppi->vlans[i];
msg_issue_sync_followup(ppi);
/* ignore errors: each vlan is separate */
}
return 0;
}
/* The real state function, relying on the two above for sending */
int pp_master(struct pp_instance *ppi, unsigned char *pkt, int plen)
{
int msgtype, d1, d2;
......@@ -20,7 +71,7 @@ int pp_master(struct pp_instance *ppi, unsigned char *pkt, int plen)
DSPOR(ppi)->logAnnounceInterval);
/* Send an announce immediately, when becomes master */
if ((e = msg_issue_announce(ppi)) < 0)
if ((e = pp_master_issue_announce(ppi)) < 0)
goto out;
}
......@@ -28,12 +79,15 @@ int pp_master(struct pp_instance *ppi, unsigned char *pkt, int plen)
/* Restart the timeout for next time */
pp_timeout_rand(ppi, PP_TO_SYNC, DSPOR(ppi)->logSyncInterval);
if ((e = msg_issue_sync_followup(ppi) < 0))
if ((e = pp_master_issue_sync_followup(ppi) < 0))
goto out;
}
if (pp_timeout_z(ppi, PP_TO_ANN_INTERVAL)) {
if ((e = pp_master_issue_announce(ppi) < 0))
goto out;
/* Restart the timeout for next time */
pp_timeout_rand(ppi, PP_TO_ANN_INTERVAL,
DSPOR(ppi)->logAnnounceInterval);
......
......@@ -18,7 +18,7 @@ static int bare_net_recv(struct pp_instance *ppi, void *pkt, int len,
if (t)
ppi->t_ops->get(ppi, t);
ret = sys_recv(NP(ppi)->ch[PP_NP_GEN].fd, pkt, len, 0);
ret = sys_recv(ppi->ch[PP_NP_GEN].fd, pkt, len, 0);
if (ret > 0 && pp_diag_allow(ppi, frames, 2))
dump_1588pkt("recv: ", pkt, ret, t);
return ret;
......@@ -35,12 +35,12 @@ static int bare_net_send(struct pp_instance *ppi, void *pkt, int len,
memcpy(hdr->h_dest, PP_MCAST_MACADDRESS, 6);
/* raw socket implementation always uses gen socket */
memcpy(hdr->h_source, NP(ppi)->ch[PP_NP_GEN].addr, 6);
memcpy(hdr->h_source, ppi->ch[PP_NP_GEN].addr, 6);
if (t)
ppi->t_ops->get(ppi, t);
ret = sys_send(NP(ppi)->ch[chtype].fd, pkt, len, 0);
ret = sys_send(ppi->ch[chtype].fd, pkt, len, 0);
if (ret > 0 && pp_diag_allow(ppi, frames, 2))
dump_1588pkt("send: ", pkt, len, t);
return ret;
......@@ -82,9 +82,9 @@ static int bare_open_ch(struct pp_instance *ppi, char *ifname)
if (sys_ioctl(sock, SIOCGIFHWADDR, &ifr) < 0)
goto err_out;
memcpy(NP(ppi)->ch[PP_NP_GEN].addr,
memcpy(ppi->ch[PP_NP_GEN].addr,
ifr.ifr_ifru.ifru_hwaddr.sa_data, 6);
memcpy(NP(ppi)->ch[PP_NP_EVT].addr,
memcpy(ppi->ch[PP_NP_EVT].addr,
ifr.ifr_ifru.ifru_hwaddr.sa_data, 6);
/* bind */
......@@ -106,8 +106,8 @@ static int bare_open_ch(struct pp_instance *ppi, char *ifname)
sys_setsockopt(sock, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
&pmr, sizeof(pmr)); /* lazily ignore errors */
NP(ppi)->ch[PP_NP_GEN].fd = sock;
NP(ppi)->ch[PP_NP_EVT].fd = sock;
ppi->ch[PP_NP_GEN].fd = sock;
ppi->ch[PP_NP_EVT].fd = sock;
/* make timestamps available through recvmsg() -- FIXME: hw? */
sys_setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP,
......@@ -128,14 +128,14 @@ err_out:
static int bare_net_exit(struct pp_instance *ppi)
{
return sys_shutdown(NP(ppi)->ch[PP_NP_GEN].fd, SHUT_RDWR);
return sys_shutdown(ppi->ch[PP_NP_GEN].fd, SHUT_RDWR);
}
/* This function must be able to be called twice, and clean-up internally */
static int bare_net_init(struct pp_instance *ppi)
{
/* Here, socket may not be 0 (do we have stdin even if bare) */
if (NP(ppi)->ch[PP_NP_GEN].fd)
if (ppi->ch[PP_NP_GEN].fd)
bare_net_exit(ppi);
/* The buffer is inside ppi, but we need to set pointers and align */
......
......@@ -145,7 +145,7 @@ static int sim_net_recv(struct pp_instance *ppi, void *pkt, int len,
if (data->n_pending <= 0)
return 0;
ch = &(NP(ppi)->ch[data->pending->chtype]);
ch = &(ppi->ch[data->pending->chtype]);
ret = -1;
if (ch->pkt_present > 0) {
......@@ -181,12 +181,12 @@ static int sim_net_send(struct pp_instance *ppi, void *pkt, int len,
PP_SLAVE_GEN_PORT :
PP_SLAVE_EVT_PORT);
addr.sin_addr.s_addr = NP(ppi)->mcast_addr;
addr.sin_addr.s_addr = ppi->mcast_addr;
if (t)
ppi->t_ops->get(ppi, t);
ret = sendto(NP(ppi)->ch[chtype].fd, pkt, len, 0,
ret = sendto(ppi->ch[chtype].fd, pkt, len, 0,
(struct sockaddr *)&addr, sizeof(struct sockaddr_in));
if (pp_diag_allow(ppi, frames, 2))
dump_payloadpkt("send: ", pkt, len, t);
......@@ -219,7 +219,7 @@ static int sim_net_send(struct pp_instance *ppi, void *pkt, int len,
pending.delay_ns = data->n_delay.t_prop_ns + jit_ns;
insert_pending(SIM_PPG_ARCH(ppi->glbs), &pending);
NP(data->other_ppi)->ch[chtype].pkt_present++;
data->other_ppi->ch[chtype].pkt_present++;
return ret;
}
......@@ -230,11 +230,11 @@ static int sim_net_exit(struct pp_instance *ppi)
/* only UDP */
for (i = PP_NP_GEN; i <= PP_NP_EVT; i++) {
fd = NP(ppi)->ch[i].fd;
fd = ppi->ch[i].fd;
if (fd < 0)
continue;
close(fd);
NP(ppi)->ch[i].fd = -1;
ppi->ch[i].fd = -1;
}
return 0;
}
......@@ -253,7 +253,7 @@ static int sim_open_ch(struct pp_instance *ppi, char *ifname, int chtype)
if (sock < 0)
goto err_out;
NP(ppi)->ch[chtype].fd = sock;
ppi->ch[chtype].fd = sock;
temp = 1; /* allow address reuse */
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &temp, sizeof(int)) < 0)
......@@ -278,21 +278,21 @@ static int sim_open_ch(struct pp_instance *ppi, char *ifname, int chtype)
sizeof(struct sockaddr_in)) < 0)
goto err_out;
NP(ppi)->ch[chtype].fd = sock;
ppi->ch[chtype].fd = sock;
/*
* Standard ppsi state machine is designed to drop packets coming from
* itself, based on the clockIdentity. This hack avoids this behaviour,
* changing the clockIdentity of the master.
*/
if (pp_sim_is_master(ppi))
memset(NP(ppi)->ch[chtype].addr, 111, 1);
memset(ppi->ch[chtype].addr, 111, 1);
return 0;
err_out:
pp_printf("%s: %s: %s\n", __func__, context, strerror(errno));
if (sock >= 0)
close(sock);
NP(ppi)->ch[chtype].fd = -1;
ppi->ch[chtype].fd = -1;
return -1;
}
......@@ -300,7 +300,7 @@ static int sim_net_init(struct pp_instance *ppi)
{
int i;
if (NP(ppi)->ch[0].fd > 0)
if (ppi->ch[0].fd > 0)
sim_net_exit(ppi);
/* The buffer is inside ppi, but we need to set pointers and align */
......
This diff is collapsed.
......@@ -26,10 +26,10 @@ static int wrpc_open_ch(struct pp_instance *ppi)
return -1;
ptpd_netif_get_hw_addr(sock, &mac);
memcpy(NP(ppi)->ch[PP_NP_EVT].addr, &mac, sizeof(mac_addr_t));
NP(ppi)->ch[PP_NP_EVT].custom = sock;
memcpy(NP(ppi)->ch[PP_NP_GEN].addr, &mac, sizeof(mac_addr_t));
NP(ppi)->ch[PP_NP_GEN].custom = sock;
memcpy(ppi->ch[PP_NP_EVT].addr, &mac, sizeof(mac_addr_t));
ppi->ch[PP_NP_EVT].custom = sock;
memcpy(ppi->ch[PP_NP_GEN].addr, &mac, sizeof(mac_addr_t));
ppi->ch[PP_NP_GEN].custom = sock;
return 0;
}
......@@ -42,7 +42,7 @@ static int wrpc_net_recv(struct pp_instance *ppi, void *pkt, int len,
wr_socket_t *sock;
wr_timestamp_t wr_ts;
wr_sockaddr_t addr;
sock = NP(ppi)->ch[PP_NP_EVT].custom;
sock = ppi->ch[PP_NP_EVT].custom;
got = ptpd_netif_recvfrom(sock, &addr, pkt, len, &wr_ts);
if (t) {
......@@ -74,7 +74,7 @@ static int wrpc_net_send(struct pp_instance *ppi, void *pkt, int len,
wr_socket_t *sock;
wr_timestamp_t wr_ts;
wr_sockaddr_t addr;
sock = NP(ppi)->ch[PP_NP_EVT].custom;
sock = ppi->ch[PP_NP_EVT].custom;
addr.ethertype = ETH_P_1588;
memcpy(&addr.mac, PP_MCAST_MACADDRESS, sizeof(mac_addr_t));
......@@ -102,14 +102,14 @@ static int wrpc_net_send(struct pp_instance *ppi, void *pkt, int len,
static int wrpc_net_exit(struct pp_instance *ppi)
{
ptpd_netif_close_socket(NP(ppi)->ch[PP_NP_EVT].custom);
ptpd_netif_close_socket(ppi->ch[PP_NP_EVT].custom);
return 0;
}
/* This function must be able to be called twice, and clean-up internally */
static int wrpc_net_init(struct pp_instance *ppi)
{
if (NP(ppi)->ch[PP_NP_EVT].custom)
if (ppi->ch[PP_NP_EVT].custom)
wrpc_net_exit(ppi);
pp_prepare_pointers(ppi);
wrpc_open_ch(ppi);
......
......@@ -158,20 +158,24 @@ static void wrs_linearize_rx_timestamp(TimeInternal *ts,
static int wrs_recv_msg(struct pp_instance *ppi, int fd, void *pkt, int len,
TimeInternal *t)
TimeInternal *t)
{
struct ethhdr *hdr = pkt;
struct pp_vlanhdr *vhdr = pkt;
struct wrs_socket *s;
struct msghdr msg;
struct iovec entry;
struct sockaddr_ll from_addr;
struct {
int i;
union {
struct cmsghdr cm;
char control[1024];
} control;
struct cmsghdr *cmsg;
struct scm_timestamping *sts = NULL;
struct tpacket_auxdata *aux = NULL;
s = (struct wrs_socket*)NP(ppi)->ch[PP_NP_GEN].arch_data;
s = (struct wrs_socket*)ppi->ch[PP_NP_GEN].arch_data;
memset(&msg, 0, sizeof(msg));
msg.msg_iov = &entry;
......@@ -205,8 +209,11 @@ static int wrs_recv_msg(struct pp_instance *ppi, int fd, void *pkt, int len,
if(cmsg->cmsg_level == SOL_SOCKET
&& cmsg->cmsg_type == SO_TIMESTAMPING)
sts = (struct scm_timestamping *) dp;
sts = (struct scm_timestamping *)dp;
if (cmsg->cmsg_level == SOL_PACKET &&
cmsg->cmsg_type == PACKET_AUXDATA)
aux = (struct tpacket_auxdata *)dp;
}
if(sts && t)
......@@ -233,6 +240,43 @@ static int wrs_recv_msg(struct pp_instance *ppi, int fd, void *pkt, int len,
}
drop:
if (aux) {
printf("aux: %x proto %x\n", aux->tp_vlan_tci,
ntohs(hdr->h_proto));
if (0) {
fprintf(stderr,
"PPSi error: unexpected auxiliary data\n");
errno = EINVAL;
return -1;
}
}
/*
* While on PC-class ethernet driver we see the internal frame,
* our simple WR driver returns the whole frame. No aux pointer
* is there, at this point in time. So unroll vlan header.
*/
if (vhdr->h_tpid == htons(0x8100)) {
int vlan = ntohs(vhdr->h_tci) & 0xfff;
/* With PROTO_VLAN, we bound to ETH_P_ALL: we got all frames */
if (vhdr->h_proto != htons(ETH_P_1588))
return -2; /* like "dropped", so no error message */
/* Also, we got the vlan, and we can discard it if not ours */
for (i = 0; i < ppi->nvlans; i++)
if (ppi->vlans[i] == vlan)
break; /* ok */
if (i == ppi->nvlans)
return -2; /* not ours: say it's dropped */
ppi->peer_vid = ppi->vlans[i];
} else {
if (hdr->h_proto != htons(ETH_P_1588))
return -2; /* again: drop unrelated frames */
ppi->peer_vid = 0;
}
if (ppsi_drop_rx()) {
pp_diag(ppi, frames, 1, "Drop received frame\n");
return -2;
......@@ -245,27 +289,44 @@ int wrs_net_recv(struct pp_instance *ppi, void *pkt, int len,
TimeInternal *t)
{
struct pp_channel *ch1, *ch2;
struct ethhdr *hdr = pkt;
int ret = -1;
if (ppi->proto == PPSI_PROTO_RAW) {
int fd = NP(ppi)->ch[PP_NP_GEN].fd;
ret = wrs_recv_msg(ppi, fd, pkt, len, t);
if (ret > 0 && pp_diag_allow(ppi, frames, 2))
switch(ppi->proto) {
case PPSI_PROTO_RAW:
case PPSI_PROTO_VLAN:
ch2 = ppi->ch + PP_NP_GEN;
ret = wrs_recv_msg(ppi, ch2->fd, pkt, len, t);
if (ret <= 0)
return ret;
memcpy(ppi->peer, hdr->h_source, ETH_ALEN);
if (pp_diag_allow(ppi, frames, 2)) {
if (ppi->proto == PPSI_PROTO_VLAN)
pp_printf("recv: VLAN %i\n", ppi->peer_vid);
dump_1588pkt("recv: ", pkt, ret, t);
} else {
}
break;
case PPSI_PROTO_UDP:
/* UDP: always handle EVT msgs before GEN */
ch1 = &(NP(ppi)->ch[PP_NP_EVT]);
ch2 = &(NP(ppi)->ch[PP_NP_GEN]);
ch1 = &(ppi->ch[PP_NP_EVT]);
ch2 = &(ppi->ch[PP_NP_GEN]);
if (ch1->pkt_present)
ret = wrs_recv_msg(ppi, ch1->fd, pkt, len, t);
else if (ch2->pkt_present)
ret = wrs_recv_msg(ppi, ch2->fd, pkt, len, t);
if (ret > 0 && pp_diag_allow(ppi, frames, 2))
if (ret < 0)
break;
if (pp_diag_allow(ppi, frames, 2))
dump_payloadpkt("recv: ", pkt, ret, t);
break;
default:
return -1;
}
if (ret < 0)
return ret;
pp_diag(ppi, time, 1, "recv stamp: (correct %i) %9li.%09li\n",
......@@ -337,10 +398,10 @@ static void poll_tx_timestamp(struct pp_instance *ppi, void *pkt, int len,
/*
* Raw frames return "sock_extended_err" too, telling this is
* a tx timestamp. Udp doesn't so don't check in udp mode
* a tx timestamp. UDP does not; so don't check in udp mode
* (the pointer is only checked for non-null)
*/
if (!(ppi->proto == PPSI_PROTO_RAW))
if (!(ppi->proto != PPSI_PROTO_UDP))
serr = (void *)1;
for (cmsg = CMSG_FIRSTHDR(&msg);
......@@ -372,10 +433,16 @@ int wrs_net_send(struct pp_instance *ppi, void *pkt, int len,
{
struct sockaddr_in addr;
struct ethhdr *hdr = pkt;
struct pp_vlanhdr *vhdr = pkt;
struct pp_channel *ch = ppi->ch + chtype;
static uint16_t udpport[] = {
[PP_NP_GEN] = PP_GEN_PORT,
[PP_NP_EVT] = PP_EVT_PORT,
};
struct wrs_socket *s;
int ret, fd, drop;
s = (struct wrs_socket *)NP(ppi)->ch[PP_NP_GEN].arch_data;
s = (struct wrs_socket *)ppi->ch[PP_NP_GEN].arch_data;
/*
* To fake a packet loss, we must corrupt the frame; we need
......@@ -384,24 +451,25 @@ int wrs_net_send(struct pp_instance *ppi, void *pkt, int len,
*/
drop = ppsi_drop_tx();
if (ppi->proto == PPSI_PROTO_RAW) {
fd = NP(ppi)->ch[PP_NP_GEN].fd;
switch (ppi->proto) {
case PPSI_PROTO_RAW:
/* raw socket implementation always uses gen socket */
ch = ppi->ch + PP_NP_GEN;
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 */
memcpy(hdr->h_source, NP(ppi)->ch[PP_NP_GEN].addr, ETH_ALEN);
memcpy(hdr->h_source, ch->addr, ETH_ALEN);
if (t)
ppi->t_ops->get(ppi, t);
ret = send(fd, hdr, len, 0);
poll_tx_timestamp(ppi, pkt, len, s, fd, t);
ret = send(ch->fd, hdr, len, 0);
poll_tx_timestamp(ppi, pkt, len, s, ch->fd, t);
if (drop) /* avoid messaging about stamps that are not used */
goto drop_msg;
break;
if (pp_diag_allow(ppi, frames, 2))
dump_1588pkt("send: ", pkt, len, t);
......@@ -409,28 +477,62 @@ int wrs_net_send(struct pp_instance *ppi, void *pkt, int len,
t->correct, (long)t->seconds,
(long)t->nanoseconds);
return ret;
}
/* else: UDP */
fd = NP(ppi)->ch[chtype].fd;
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, pkt, len, s, fd, t);
case PPSI_PROTO_VLAN:
/* similar to sending raw frames, but w/ different header */
ch = ppi->ch + PP_NP_GEN;
vhdr->h_proto = htons(ETH_P_1588);
vhdr->h_tci = htons(ppi->peer_vid); /* prio is 0 */
vhdr->h_tpid = htons(0x8100);
if (drop)
hdr->h_proto++;
if (drop) /* like above: skil messages about timestamps */
goto drop_msg;
memcpy(vhdr->h_dest, PP_MCAST_MACADDRESS, ETH_ALEN);
memcpy(vhdr->h_source, ch->addr, ETH_ALEN);
if (t)
ppi->t_ops->get(ppi, t);
if (len < 64)
len = 64;
ret = send(ch->fd, vhdr, len, 0);
poll_tx_timestamp(ppi, pkt, len, s, ch->fd, t);
if (drop) /* avoid messaging about stamps that are not used */
break;
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",
t->correct, (long)t->seconds,
(long)t->nanoseconds);
return ret;
case PPSI_PROTO_UDP:
fd = ppi->ch[chtype].fd;
addr.sin_family = AF_INET;
addr.sin_port = htons(udpport[chtype]);
addr.sin_addr.s_addr = 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, pkt, len, s, fd, t);
if (drop) /* like above: skil messages about timestamps */
break;
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);
return ret;
default:
return -1;
}
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");
......@@ -478,7 +580,7 @@ static int wrs_net_init(struct pp_instance *ppi)
int r, i;
struct hal_port_state *p;
if (NP(ppi)->ch[PP_NP_GEN].arch_data)
if (ppi->ch[PP_NP_GEN].arch_data)
wrs_net_exit(ppi);
/* Generic OS work is done by standard Unix stuff */
......@@ -512,15 +614,15 @@ static int wrs_net_init(struct pp_instance *ppi)
s->dmtd_phase_valid = 0;
NP(ppi)->ch[PP_NP_GEN].arch_data = s;
NP(ppi)->ch[PP_NP_EVT].arch_data = s;
ppi->ch[PP_NP_GEN].arch_data = s;
ppi->ch[PP_NP_EVT].arch_data = s;
tmo_init(&s->dmtd_update_tmo, DMTD_UPDATE_INTERVAL);
for (i = PP_NP_GEN, r = 0; i <= PP_NP_EVT && r == 0; i++)
r = wrs_enable_timestamps(ppi, NP(ppi)->ch[i].fd);
r = wrs_enable_timestamps(ppi, ppi->ch[i].fd);
if (r) {
NP(ppi)->ch[PP_NP_GEN].arch_data = NULL;
NP(ppi)->ch[PP_NP_EVT].arch_data = NULL;
ppi->ch[PP_NP_GEN].arch_data = NULL;
ppi->ch[PP_NP_EVT].arch_data = NULL;
free(s);
}
return r;
......@@ -529,9 +631,9 @@ static int wrs_net_init(struct pp_instance *ppi)
static int wrs_net_exit(struct pp_instance *ppi)
{
unix_net_ops.exit(ppi);
free(NP(ppi)->ch[PP_NP_GEN].arch_data);
NP(ppi)->ch[PP_NP_GEN].arch_data = NULL;
NP(ppi)->ch[PP_NP_EVT].arch_data = NULL;
free(ppi->ch[PP_NP_GEN].arch_data);
ppi->ch[PP_NP_GEN].arch_data = NULL;
ppi->ch[PP_NP_EVT].arch_data = NULL;
return 0;
}
......
......@@ -9,7 +9,8 @@ STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
CFLAGS = -Wall -ggdb -I../include
include ../.config
CFLAGS = -Wall -ggdb -I../include -I../arch-$(CONFIG_ARCH)/include
PROGS = ptpdump adjtime jmptime chktime adjrate
LDFLAGS += -lrt
......
......@@ -51,15 +51,25 @@ static void dump_time(char *prefix, struct TimeInternal *ti)
}
#endif
static void dump_eth(char *prefix, struct ethhdr *eth)
/* Returns the header size, used by the caller to adjust the next pointer */
static int dump_eth(char *prefix, struct ethhdr *eth)
{
unsigned char *d = eth->h_dest;
unsigned char *s = eth->h_source;
int proto = ntohs(eth->h_proto);
struct pp_vlanhdr *vhdr = (void *)eth;
int ret = sizeof(*eth);
if (proto == 0x8100) {
ret = sizeof(*vhdr);
proto = ntohs(vhdr->h_proto);
printf("%sVLAN %i\n", prefix, ntohs(vhdr->h_tci) & 0xfff);
}
printf("%sETH: %04x (%02x:%02x:%02x:%02x:%02x:%02x -> "
"%02x:%02x:%02x:%02x:%02x:%02x)\n", prefix, ntohs(eth->h_proto),
"%02x:%02x:%02x:%02x:%02x:%02x)\n", prefix, proto,
s[0], s[1], s[2], s[3], s[4], s[5],
d[0], d[1], d[2], d[3], d[4], d[5]);
return ret;
}
static void dump_ip(char *prefix, struct iphdr *ip)
......@@ -169,7 +179,7 @@ static void dump_payload(char *prefix, void *pl, int len)
if (version != 2) {
printf("%sVERSION: unsupported (%i)\n", prefix, version);
return;
goto out;
}
printf("%sVERSION: %i (type %i, len %i, domain %i)\n", prefix,
version, messageType,
......@@ -211,7 +221,7 @@ static void dump_payload(char *prefix, void *pl, int len)
donelen = 44;
break;
#if __STDC_HOSTED__ /* Avoid pdelay dump withing ppsi, we don't use it */
#if __STDC_HOSTED__ /* Avoid pdelay dump within ppsi, we don't use it */
CASE(E, PDELAY_REQ);
dump_msg_sync_etc(prefix, "MSG-PDELAY_REQ: ", msg_specific);
donelen = 54;
......@@ -247,7 +257,7 @@ static void dump_payload(char *prefix, void *pl, int len)
}
donelen += dump_tlv(prefix, pl + donelen, n);
}
out:
/* Finally, binary dump of it all */
dumpstruct(prefix, "DUMP: ", "payload", pl, len);
}
......@@ -256,16 +266,22 @@ static void dump_payload(char *prefix, void *pl, int len)
int dump_udppkt(char *prefix, void *buf, int len, struct TimeInternal *ti)
{
struct ethhdr *eth = buf;
struct iphdr *ip = buf + ETH_HLEN;
struct udphdr *udp = (void *)(ip + 1);
void *payload = (void *)(udp + 1);
struct iphdr *ip;
struct udphdr *udp;
void *payload;
if (ti)
dump_time(prefix, ti);
dump_eth(prefix, eth);
ip = buf + dump_eth(prefix, eth);
dump_ip(prefix, ip);
udp = (void *)(ip + 1);
dump_udp(prefix, udp);
payload = (void *)(udp + 1);
dump_payload(prefix, payload, len - (payload - buf));
return 0;
}
......@@ -282,11 +298,12 @@ int dump_payloadpkt(char *prefix, void *buf, int len, struct TimeInternal *ti)
int dump_1588pkt(char *prefix, void *buf, int len, struct TimeInternal *ti)
{
struct ethhdr *eth = buf;
void *payload = (void *)(eth + 1);
void *payload;
if (ti)
dump_time(prefix, ti);
dump_eth(prefix, eth);
payload = buf + dump_eth(prefix, eth);
dump_payload(prefix, payload, len - (payload - buf));
return 0;
}
......@@ -89,6 +89,7 @@ int main(int argc, char **argv)
/* Ok, now we are promiscuous. Just read stuff forever */
while(1) {
struct ethhdr *eth;
struct pp_vlanhdr *vhdr;
struct iphdr *ip;
static unsigned char prev[1500];
static int prevlen;
......@@ -98,7 +99,7 @@ int main(int argc, char **argv)
struct sockaddr_in from;
socklen_t fromlen = sizeof(from);
int len;
int len, proto;
len = recvfrom(sock, buf, sizeof(buf), MSG_TRUNC,
(struct sockaddr *) &from, &fromlen);
......@@ -120,7 +121,15 @@ int main(int argc, char **argv)
continue;
eth = (void *)buf;
ip = (void *)(buf + ETH_HLEN);
switch(ntohs(eth->h_proto)) {
proto = ntohs(eth->h_proto);
if (proto == 0x8100) { /* VLAN is visible (e.g.: outgoing) */
vhdr = (void *)buf;
proto = ntohs(vhdr->h_proto);
ip = (void *)(buf + sizeof(*vhdr));
}
switch(proto) {
case ETH_P_IP:
{
struct udphdr *udp = (void *)(ip + 1);
......
#ifndef __PTPDUMP_H__
#define __PTPDUMP_H__
#include <ppsi/ppsi.h>
#if __STDC_HOSTED__
#include <time.h>
#include <sys/time.h>
......@@ -8,7 +9,6 @@
#include <netinet/udp.h> /* struct udphdr */
#include <linux/if_ether.h> /* struct ethhdr */
#else
#include <ppsi/ppsi.h>
#include "../lib/network_types.h"
#define printf pp_printf
#endif
......
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