On 09/28/2017 08:25 AM, Brandon Streiff wrote: > Forward the rx/tx timestamp machinery from the dsa infrastructure to the > switch driver. > > On the rx side, defer delivery of skbs until we have an rx timestamp. > This mimicks the behavior of skb_defer_rx_timestamp. The implementation > does have to thread through the tagging protocol handlers because > it is where that we know which switch and port the skb goes to. > > On the tx side, identify PTP packets, clone them, and pass them to the > underlying switch driver before we transmit. This mimicks the behavior > of skb_tx_timestamp. > > Signed-off-by: Brandon Streiff <brandon.stre...@ni.com> > --- > include/net/dsa.h | 13 +++++++++++-- > net/dsa/dsa.c | 39 ++++++++++++++++++++++++++++++++++++++- > net/dsa/slave.c | 25 +++++++++++++++++++++++++ > net/dsa/tag_brcm.c | 6 +++++- > net/dsa/tag_dsa.c | 6 +++++- > net/dsa/tag_edsa.c | 6 +++++- > net/dsa/tag_ksz.c | 6 +++++- > net/dsa/tag_lan9303.c | 6 +++++- > net/dsa/tag_mtk.c | 6 +++++- > net/dsa/tag_qca.c | 6 +++++- > net/dsa/tag_trailer.c | 6 +++++- > 11 files changed, 114 insertions(+), 11 deletions(-) > > diff --git a/include/net/dsa.h b/include/net/dsa.h > index 1163af1..4daf7f7 100644 > --- a/include/net/dsa.h > +++ b/include/net/dsa.h > @@ -101,11 +101,14 @@ struct dsa_platform_data { > }; > > struct packet_type; > +struct dsa_switch; > > struct dsa_device_ops { > struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev); > struct sk_buff *(*rcv)(struct sk_buff *skb, struct net_device *dev, > - struct packet_type *pt); > + struct packet_type *pt, > + struct dsa_switch **src_dev, > + int *src_port); > int (*flow_dissect)(const struct sk_buff *skb, __be16 *proto, > int *offset); > }; > @@ -134,7 +137,9 @@ struct dsa_switch_tree { > /* Copy of tag_ops->rcv for faster access in hot path */ > struct sk_buff * (*rcv)(struct sk_buff *skb, > struct net_device *dev, > - struct packet_type *pt); > + struct packet_type *pt, > + struct dsa_switch **src_dev, > + int *src_port); > > /* > * The switch port to which the CPU is attached. > @@ -449,6 +454,10 @@ struct dsa_switch_ops { > struct ifreq *ifr); > int (*port_hwtstamp_set)(struct dsa_switch *ds, int port, > struct ifreq *ifr); > + void (*port_txtstamp)(struct dsa_switch *ds, int port, > + struct sk_buff *clone, unsigned int type); > + bool (*port_rxtstamp)(struct dsa_switch *ds, int port, > + struct sk_buff *skb, unsigned int type); > }; > > struct dsa_switch_driver { > diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c > index 81c852e..42e7286 100644 > --- a/net/dsa/dsa.c > +++ b/net/dsa/dsa.c > @@ -22,6 +22,7 @@ > #include <linux/netdevice.h> > #include <linux/sysfs.h> > #include <linux/phy_fixed.h> > +#include <linux/ptp_classify.h> > #include <linux/gpio/consumer.h> > #include <linux/etherdevice.h> > > @@ -157,6 +158,37 @@ struct net_device *dsa_dev_to_net_device(struct device > *dev) > } > EXPORT_SYMBOL_GPL(dsa_dev_to_net_device); > > +/* Determine if we should defer delivery of skb until we have a rx timestamp. > + * > + * Called from dsa_switch_rcv. For now, this will only work if tagging is > + * enabled on the switch. Normally the MAC driver would retrieve the hardware > + * timestamp when it reads the packet out of the hardware. However in a DSA > + * switch, the DSA driver owning the interface to which the packet is > + * delivered is never notified unless we do so here. > + */ > +static bool dsa_skb_defer_rx_timestamp(struct dsa_switch *ds, int port, > + struct sk_buff *skb)
You should not need the port information here because it's already implied from skb->dev which points to the DSA slave network device, see below. > +{ > + unsigned int type; > + > + if (skb_headroom(skb) < ETH_HLEN) > + return false; Are you positive this is necessary? Because we called dst->rcv() we have called eth_type_trans() which already made sure about that > + > + __skb_push(skb, ETH_HLEN); > + > + type = ptp_classify_raw(skb); > + > + __skb_pull(skb, ETH_HLEN); > + > + if (type == PTP_CLASS_NONE) > + return false; > + > + if (likely(ds->ops->port_rxtstamp)) > + return ds->ops->port_rxtstamp(ds, port, skb, type); > + > + return false; > +} Can we also have a fast-path bypass in case time stamping is not supported by the switch so we don't have to even try to classify this packet only to realize we don't have a port_rxtsamp() operation later? You can either gate this with a compile-time option, or use e.g: a static key or something like an early test? > + > static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev, > struct packet_type *pt, struct net_device *unused) > { > @@ -164,6 +196,8 @@ static int dsa_switch_rcv(struct sk_buff *skb, struct > net_device *dev, > struct sk_buff *nskb = NULL; > struct pcpu_sw_netstats *s; > struct dsa_slave_priv *p; > + struct dsa_switch *ds = NULL; > + int source_port; > > if (unlikely(dst == NULL)) { > kfree_skb(skb); > @@ -174,7 +208,7 @@ static int dsa_switch_rcv(struct sk_buff *skb, struct > net_device *dev, > if (!skb) > return 0; > > - nskb = dst->rcv(skb, dev, pt); > + nskb = dst->rcv(skb, dev, pt, &ds, &source_port); I don't think this is necessary, what dst->rcv() does is actually properly assign skb->dev to the correct dsa slave network device, which has the information about the port number already in its private context. > if (!nskb) { > kfree_skb(skb); > return 0; > @@ -192,6 +226,9 @@ static int dsa_switch_rcv(struct sk_buff *skb, struct > net_device *dev, > s->rx_bytes += skb->len; > u64_stats_update_end(&s->syncp); > > + if (dsa_skb_defer_rx_timestamp(ds, source_port, skb)) > + return 0; Can we just propagate an integer return value from dsa_skb_defer_rx_timestamp()? > + > netif_receive_skb(skb); > > return 0; > diff --git a/net/dsa/slave.c b/net/dsa/slave.c > index 2cf6a83..a278335 100644 > --- a/net/dsa/slave.c > +++ b/net/dsa/slave.c > @@ -22,6 +22,7 @@ > #include <net/tc_act/tc_mirred.h> > #include <linux/if_bridge.h> > #include <linux/netpoll.h> > +#include <linux/ptp_classify.h> > > #include "dsa_priv.h" > > @@ -407,6 +408,25 @@ static inline netdev_tx_t > dsa_slave_netpoll_send_skb(struct net_device *dev, > return NETDEV_TX_OK; > } > > +static void dsa_skb_tx_timestamp(struct dsa_slave_priv *p, > + struct sk_buff *skb) > +{ > + struct dsa_switch *ds = p->dp->ds; > + struct sk_buff *clone; > + unsigned int type; > + > + type = ptp_classify_raw(skb); > + if (type == PTP_CLASS_NONE) > + return; If we don't have a port_txtstamp option, is there even value in classifying this packet? -- Florian