[Intel-wired-lan] [RFC v2 net-next 1/2] rtnetlink: Add new RTM_GETSYNCESTATE message to get SyncE status
Maciej Machnikowski
maciej.machnikowski at intel.com
Sun Aug 29 08:05:11 UTC 2021
This patch adds the new RTM_GETSYNCESTATE message to query the status
of SyncE syntonization on the device.
Initial implementation returns:
- SyncE DPLL state
- Source of signal driving SyncE DPLL (SyncE, GNSS, PTP or External)
- Current index of Pin driving the DPLL
SyncE state read needs to be implemented as ndo_get_synce_state function.
This patch is SyncE-oriented. Future implementation can add additional
functionality for reading different DPLL states using the same structure.
Signed-off-by: Maciej Machnikowski <maciej.machnikowski at intel.com>
---
include/linux/netdevice.h | 6 +++
include/uapi/linux/if_link.h | 43 +++++++++++++++++++
include/uapi/linux/rtnetlink.h | 11 +++--
net/core/rtnetlink.c | 77 ++++++++++++++++++++++++++++++++++
security/selinux/nlmsgtab.c | 3 +-
5 files changed, 135 insertions(+), 5 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 6fd3a4d42668..a091a35706a7 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1344,6 +1344,8 @@ struct netdev_net_notifier {
* The caller must be under RCU read context.
* int (*ndo_fill_forward_path)(struct net_device_path_ctx *ctx, struct net_device_path *path);
* Get the forwarding path to reach the real device from the HW destination address
+ * int (*ndo_get_synce_state)(struct net_device *dev, struct if_synce_state_msg *state)
+ * Get state of physical layer frequency syntonization (SyncE)
*/
struct net_device_ops {
int (*ndo_init)(struct net_device *dev);
@@ -1563,6 +1565,10 @@ struct net_device_ops {
struct net_device * (*ndo_get_peer_dev)(struct net_device *dev);
int (*ndo_fill_forward_path)(struct net_device_path_ctx *ctx,
struct net_device_path *path);
+ int (*ndo_get_synce_state)(struct net_device *dev,
+ enum if_synce_state *state,
+ enum if_synce_src *src,
+ u8 *pin_idx);
};
/**
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index eebd3894fe89..1fcb9c71dc7c 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -1273,4 +1273,47 @@ enum {
#define IFLA_MCTP_MAX (__IFLA_MCTP_MAX - 1)
+/* SyncE section */
+
+enum if_synce_state {
+ IF_SYNCE_STATE_INVALID = 0,
+ IF_SYNCE_STATE_FREERUN,
+ IF_SYNCE_STATE_LOCKACQ,
+ IF_SYNCE_STATE_LOCKREC,
+ IF_SYNCE_STATE_LOCKED,
+ IF_SYNCE_STATE_HOLDOVER,
+ IF_SYNCE_STATE_OPEN_LOOP,
+ __IF_SYNCE_STATE_MAX,
+};
+
+#define IF_SYNCE_STATE_MAX (__IF_SYNCE_STATE_MAX - 1)
+
+enum if_synce_src {
+ IF_SYNCE_SRC_INVALID = 0,
+ IF_SYNCE_SRC_UNKNOWN,
+ IF_SYNCE_SRC_SYNCE,
+ IF_SYNCE_SRC_GNSS,
+ IF_SYNCE_SRC_PTP,
+ IF_SYNCE_SRC_EXT,
+ __IF_SYNCE_SRC_MAX,
+};
+
+#define IF_SYNCE_PIN_UNKNOWN 0xFF
+
+struct if_synce_state_msg {
+ __u32 ifindex;
+ __u8 state;
+ __u8 src;
+ __u8 pin;
+ __u8 pad;
+};
+
+enum {
+ IFLA_SYNCE_UNSPEC,
+ IFLA_SYNCE_STATE,
+ __IFLA_SYNCE_MAX,
+};
+
+#define IFLA_SYNCE_MAX (__IFLA_SYNCE_MAX - 1)
+
#endif /* _UAPI_LINUX_IF_LINK_H */
diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h
index 5888492a5257..cd68045c475b 100644
--- a/include/uapi/linux/rtnetlink.h
+++ b/include/uapi/linux/rtnetlink.h
@@ -185,6 +185,9 @@ enum {
RTM_GETNEXTHOPBUCKET,
#define RTM_GETNEXTHOPBUCKET RTM_GETNEXTHOPBUCKET
+ RTM_GETSYNCESTATE = 120,
+#define RTM_GETSYNCESTATE RTM_GETSYNCESTATE
+
__RTM_MAX,
#define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1)
};
@@ -193,7 +196,7 @@ enum {
#define RTM_NR_FAMILIES (RTM_NR_MSGTYPES >> 2)
#define RTM_FAM(cmd) (((cmd) - RTM_BASE) >> 2)
-/*
+/*
Generic structure for encapsulation of optional route information.
It is reminiscent of sockaddr, but with sa_family replaced
with attribute type.
@@ -233,7 +236,7 @@ struct rtmsg {
unsigned char rtm_table; /* Routing table id */
unsigned char rtm_protocol; /* Routing protocol; see below */
- unsigned char rtm_scope; /* See below */
+ unsigned char rtm_scope; /* See below */
unsigned char rtm_type; /* See below */
unsigned rtm_flags;
@@ -555,7 +558,7 @@ struct ifinfomsg {
};
/********************************************************************
- * prefix information
+ * prefix information
****/
struct prefixmsg {
@@ -569,7 +572,7 @@ struct prefixmsg {
unsigned char prefix_pad3;
};
-enum
+enum
{
PREFIX_UNSPEC,
PREFIX_ADDRESS,
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 972c8cb303a5..8c9638421049 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -5468,6 +5468,81 @@ static int rtnl_stats_dump(struct sk_buff *skb, struct netlink_callback *cb)
return skb->len;
}
+static int rtnl_fill_synce_state(struct sk_buff *msg, struct net_device *dev,
+ u32 portid, u32 seq,
+ struct netlink_callback *cb,
+ int flags)
+{
+ const struct net_device_ops *ops = dev->netdev_ops;
+ struct if_synce_state_msg *state;
+ struct nlmsghdr *nlh;
+
+ ASSERT_RTNL();
+
+ nlh = nlmsg_put(msg, portid, seq, RTM_GETSYNCESTATE,
+ sizeof(*state), flags);
+ if (!nlh)
+ return -EMSGSIZE;
+
+ state = nlmsg_data(nlh);
+
+ if (ops->ndo_get_synce_state) {
+ enum if_synce_state sync_state;
+ enum if_synce_src src;
+ int err;
+ u8 pin;
+
+ err = ops->ndo_get_synce_state(dev, &sync_state, &src, &pin);
+ if (err)
+ return err;
+
+ memset(state, 0, sizeof(*state));
+
+ state->ifindex = dev->ifindex;
+ state->state = (u8)sync_state;
+ state->pin = pin;
+ state->src = (u8)src;
+
+ return 0;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static int rtnl_synce_state_get(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct netlink_ext_ack *extack)
+{
+ struct net *net = sock_net(skb->sk);
+ struct if_synce_state_msg *state;
+ struct net_device *dev = NULL;
+ struct sk_buff *nskb;
+ u32 filter_mask;
+ int err;
+
+ state = nlmsg_data(nlh);
+ if (state->ifindex > 0)
+ dev = __dev_get_by_index(net, state->ifindex);
+ else
+ return -EINVAL;
+
+ nskb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!nskb)
+ return -ENOBUFS;
+
+ if (!dev)
+ return -ENODEV;
+
+ err = rtnl_fill_synce_state(nskb, dev,
+ NETLINK_CB(skb).portid, nlh->nlmsg_seq,
+ NULL, filter_mask);
+ if (err < 0)
+ kfree_skb(nskb);
+ else
+ err = rtnl_unicast(nskb, net, NETLINK_CB(skb).portid);
+
+ return err;
+}
+
/* Process one rtnetlink message. */
static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
@@ -5693,4 +5768,6 @@ void __init rtnetlink_init(void)
rtnl_register(PF_UNSPEC, RTM_GETSTATS, rtnl_stats_get, rtnl_stats_dump,
0);
+
+ rtnl_register(PF_UNSPEC, RTM_GETSYNCESTATE, rtnl_synce_state_get, NULL, 0);
}
diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c
index d59276f48d4f..b4bea120f2af 100644
--- a/security/selinux/nlmsgtab.c
+++ b/security/selinux/nlmsgtab.c
@@ -91,6 +91,7 @@ static const struct nlmsg_perm nlmsg_route_perms[] =
{ RTM_NEWNEXTHOPBUCKET, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_DELNEXTHOPBUCKET, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_GETNEXTHOPBUCKET, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_GETSYNCESTATE, NETLINK_ROUTE_SOCKET__NLMSG_READ },
};
static const struct nlmsg_perm nlmsg_tcpdiag_perms[] =
@@ -174,7 +175,7 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm)
* structures at the top of this file with the new mappings
* before updating the BUILD_BUG_ON() macro!
*/
- BUILD_BUG_ON(RTM_MAX != (RTM_NEWNEXTHOPBUCKET + 3));
+ BUILD_BUG_ON(RTM_MAX != (RTM_GETSYNCESTATE + 3));
err = nlmsg_perm(nlmsg_type, perm, nlmsg_route_perms,
sizeof(nlmsg_route_perms));
break;
--
2.26.3
More information about the Intel-wired-lan
mailing list