Skip to content

Commit

Permalink
net: gptp: Initial core IEEE 802.1AS support
Browse files Browse the repository at this point in the history
Core IEEE 802.1AS-2011 (gPTP) support and application interface.

Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
Signed-off-by: Julien Chevrier <julien.chevrier@intel.com>
  • Loading branch information
jukkar committed Jun 28, 2018
1 parent e69c058 commit 45b06a2
Show file tree
Hide file tree
Showing 23 changed files with 6,792 additions and 0 deletions.
6 changes: 6 additions & 0 deletions doc/api/networking.rst
Expand Up @@ -108,6 +108,12 @@ Hostname Configuration Library
.. doxygengroup:: net_hostname
:project: Zephyr

generic Precision Time Protocol (gPTP)
**************************************

.. doxygengroup:: gptp
:project: Zephyr

Network technologies
********************

Expand Down
51 changes: 51 additions & 0 deletions include/net/ethernet.h
Expand Up @@ -44,6 +44,7 @@ struct net_eth_addr {
#define NET_ETH_PTYPE_IP 0x0800
#define NET_ETH_PTYPE_IPV6 0x86dd
#define NET_ETH_PTYPE_VLAN 0x8100
#define NET_ETH_PTYPE_PTP 0x88f7

#define NET_ETH_MINIMAL_FRAME_SIZE 60

Expand Down Expand Up @@ -188,6 +189,14 @@ struct ethernet_context {
struct net_if *iface;
} carrier_mgmt;

#if defined(CONFIG_NET_GPTP)
/** The gPTP port number for this network device. We need to store the
* port number here so that we do not need to fetch it for every
* incoming gPTP packet.
*/
int port;
#endif

#if defined(CONFIG_NET_VLAN)
/** Flag that tells whether how many VLAN tags are enabled for this
* context. The same information can be dug from the vlan array but
Expand Down Expand Up @@ -259,6 +268,22 @@ static inline bool net_eth_is_addr_multicast(struct net_eth_addr *addr)
return false;
}

static inline bool net_eth_is_addr_lldp_multicast(struct net_eth_addr *addr)
{
#if defined(CONFIG_NET_GPTP)
if (addr->addr[0] == 0x01 &&
addr->addr[1] == 0x80 &&
addr->addr[2] == 0xc2 &&
addr->addr[3] == 0x00 &&
addr->addr[4] == 0x00 &&
addr->addr[5] == 0x0e) {
return true;
}
#endif

return false;
}

const struct net_eth_addr *net_eth_broadcast_addr(void);

/**
Expand Down Expand Up @@ -424,6 +449,32 @@ void net_eth_carrier_off(struct net_if *iface);
*/
struct device *net_eth_get_ptp_clock(struct net_if *iface);

#if defined(CONFIG_NET_GPTP)
/**
* @brief Return gPTP port number attached to this interface.
*
* @param iface Network interface
*
* @return Port number, no such port if < 0
*/
int net_eth_get_ptp_port(struct net_if *iface);

/**
* @brief Set gPTP port number attached to this interface.
*
* @param iface Network interface
* @param port Port number to set
*/
void net_eth_set_ptp_port(struct net_if *iface, int port);
#else
static inline int net_eth_get_ptp_port(struct net_if *iface)
{
ARG_UNUSED(iface);

return -ENODEV;
}
#endif /* CONFIG_NET_GPTP */

#ifdef __cplusplus
}
#endif
Expand Down
296 changes: 296 additions & 0 deletions include/net/gptp.h
@@ -0,0 +1,296 @@
/*
* Copyright (c) 2017 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/

/**
* @file
* @brief Public functions for the Precision Time Protocol Stack.
*
*/

#ifndef __GPTP_H
#define __GPTP_H

/**
* @brief generic Precision Time Protocol (gPTP) support
* @defgroup gptp gPTP support
* @ingroup networking
* @{
*/

#include <net/net_core.h>
#include <net/ptp_time.h>

#ifdef __cplusplus
extern "C" {
#endif

#define GPTP_CLOCK_ACCURACY_UNKNOWN 0xFE

#define GPTP_OFFSET_SCALED_LOG_VAR_UNKNOWN 0x436A

#define GPTP_PRIORITY1_NON_GM_CAPABLE 255
#define GPTP_PRIORITY2_DEFAULT 248

/**
* @brief Scaled Nanoseconds.
*/
struct gptp_scaled_ns {
/** High half. */
s32_t high;

/** Low half. */
s64_t low;
} __packed;

/**
* @brief UScaled Nanoseconds.
*/
struct gptp_uscaled_ns {
/** High half. */
u32_t high;

/** Low half. */
u64_t low;
} __packed;

#if defined(CONFIG_NEWLIB_LIBC)
#include <math.h>

#define GPTP_POW2(exp) pow(2, exp)
#else

static inline double _gptp_pow2(int exp)
{
double res;

if (exp >= 0) {
res = 1 << exp;
} else {
res = 1.0;

while (exp++) {
res /= 2;
}
}

return res;
}

#define GPTP_POW2(exp) _gptp_pow2(exp)
#endif

/* Message types. Event messages have BIT(3) set to 0, and general messages
* have that bit set to 1. IEEE 802.1AS chapter 10.5.2.2.2
*/
#define GPTP_SYNC_MESSAGE 0x00
#define GPTP_DELAY_REQ_MESSAGE 0x01
#define GPTP_PATH_DELAY_REQ_MESSAGE 0x02
#define GPTP_PATH_DELAY_RESP_MESSAGE 0x03
#define GPTP_FOLLOWUP_MESSAGE 0x08
#define GPTP_DELAY_RESP_MESSAGE 0x09
#define GPTP_PATH_DELAY_FOLLOWUP_MESSAGE 0x0a
#define GPTP_ANNOUNCE_MESSAGE 0x0b
#define GPTP_SIGNALING_MESSAGE 0x0c
#define GPTP_MANAGEMENT_MESSAGE 0x0d

#define GPTP_IS_EVENT_MSG(msg_type) (!((msg_type) & BIT(3)))

#define GPTP_CLOCK_ID_LEN 8

/**
* @brief Port Identity.
*/
struct gptp_port_identity {
/** Clock identity of the port. */
u8_t clk_id[GPTP_CLOCK_ID_LEN];

/** Number of the port. */
u16_t port_number;
} __packed;

struct gptp_flags {
union {
/** Byte access. */
u8_t octets[2];

/** Whole field access. */
u16_t all;
};
} __packed;

struct gptp_hdr {
/** Type of the message. */
u8_t message_type:4;

/** Transport specific, always 1. */
u8_t transport_specific:4;

/** Version of the PTP, always 2. */
u8_t ptp_version:4;

/** Reserved field. */
u8_t reserved0:4;

/** Total length of the message from the header to the last TLV. */
u16_t message_length;

/** Domain number, always 0. */
u8_t domain_number;

/** Reserved field. */
u8_t reserved1;

/** Message flags. */
struct gptp_flags flags;

/** Correction Field. The content depends of the message type. */
s64_t correction_field;

/** Reserved field. */
u32_t reserved2;

/** Port Identity of the sender. */
struct gptp_port_identity port_id;

/** Sequence Id. */
u16_t sequence_id;

/** Control value. Sync: 0, Follow-up: 2, Others: 5. */
u8_t control;

/** Message Interval in Log2 for Sync and Announce messages. */
s8_t log_msg_interval;
} __packed;

/*
* TODO: k_uptime_get need to be replaced by the MAC ptp_clock.
* The ptp_clock access infrastructure is not ready yet
* so use it for the time being.
* k_uptime time precision is in ms.
*/
#define GPTP_GET_CURRENT_TIME_NANOSECOND() (k_uptime_get() * 1000000)
#define GPTP_GET_CURRENT_TIME_USCALED_NS(uscaled_ns_ptr) \
do { \
(uscaled_ns_ptr)->low = \
GPTP_GET_CURRENT_TIME_NANOSECOND() << 16; \
(uscaled_ns_ptr)->high = 0; \
} while (0)

/**
* @typedef gptp_phase_dis_callback_t
* @brief Define callback that is called after a phase discontinuity has been
* sent by the grandmaster.
* @param "u8_t *gm_identity" A pointer to first element of a
* ClockIdentity array. The size of the array is GPTP_CLOCK_ID_LEN.
* @param "u16_t *gm_time_base" A pointer to the value of timeBaseIndicator
* of the current grandmaster.
* @param "struct scaled_ns *last_gm_ph_change" A pointer to the value of
* lastGmPhaseChange received from grandmaster.
* @param "double *last_gm_freq_change" A pointer to the value of
* lastGmFreqChange received from the grandmaster.
*/
typedef void (*gptp_phase_dis_callback_t)(
u8_t *gm_identity,
u16_t *time_base,
struct gptp_scaled_ns *last_gm_ph_change,
double *last_gm_freq_change);

/**
* @brief Phase discontinuity callback structure.
*
* Stores the phase discontinuity callback information. Caller must make sure
* that the variable pointed by this is valid during the lifetime of
* registration. Typically this means that the variable cannot be
* allocated from stack.
*/
struct gptp_phase_dis_cb {
/** Node information for the slist. */
sys_snode_t node;

/** Phase discontinuity callback. */
gptp_phase_dis_callback_t cb;
};

/**
* @brief Register a phase discontinuity callback.
*
* @param phase_dis Caller specified handler for the callback.
* @param cb Callback to register.
*/
void gptp_register_phase_dis_cb(struct gptp_phase_dis_cb *phase_dis,
gptp_phase_dis_callback_t cb);

/**
* @brief Unregister a phase discontinuity callback.
*
* @param phase_dis Caller specified handler for the callback.
*/
void gptp_unregister_phase_dis_cb(struct gptp_phase_dis_cb *phase_dis);

/**
* @brief Call a phase discontinuity callback function.
*/
void gptp_call_phase_dis_cb(void);

/**
* @brief Get gPTP time.
*
* @param slave_time A pointer to structure where timestamp will be saved.
* @param gm_present A pointer to a boolean where status of the
* presence of a grand master will be saved.
*
* @return Error code. 0 if no error.
*/
int gptp_event_capture(struct net_ptp_time *slave_time, bool *gm_present);

/**
* @brief Utility function to print clock id to a user supplied buffer.
*
* @param clk_id Clock id
* @param output Output buffer
* @param output_len Output buffer len
*
* @return Pointer to output buffer
*/
char *gptp_sprint_clock_id(const u8_t *clk_id, char *output,
size_t output_len);

/**
* @typedef gptp_port_cb_t
* @brief Callback used while iterating over gPTP ports
*
* @param port Port number
* @param iface Pointer to network interface
* @param user_data A valid pointer to user data or NULL
*/
typedef void (*gptp_port_cb_t)(int port, struct net_if *iface,
void *user_data);

/**
* @brief Go through all the gPTP ports and call callback for each of them.
*
* @param cb User-supplied callback function to call
* @param user_data User specified data
*/
void gptp_foreach_port(gptp_port_cb_t cb, void *user_data);

/**
* @brief Get gPTP domain.
* @details This contains all the configuration / status of the gPTP domain.
*
* @return Pointer to domain or NULL if not found.
*/
struct gptp_domain *gptp_get_domain(void);

#ifdef __cplusplus
}
#endif

/**
* @}
*/

#endif /* __GPTP_H */
2 changes: 2 additions & 0 deletions include/net/net_ip.h
Expand Up @@ -62,8 +62,10 @@ enum net_sock_type {

#define ntohs(x) sys_be16_to_cpu(x)
#define ntohl(x) sys_be32_to_cpu(x)
#define ntohll(x) sys_be64_to_cpu(x)
#define htons(x) sys_cpu_to_be16(x)
#define htonl(x) sys_cpu_to_be32(x)
#define htonll(x) sys_cpu_to_be64(x)

/** IPv6 address structure */
struct in6_addr {
Expand Down

0 comments on commit 45b06a2

Please sign in to comment.