diff options
author | Patrick Ohly <patrick.ohly@intel.com> | 2009-02-12 00:03:37 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-02-16 01:43:34 -0500 |
commit | ac45f602ee3d1b6f326f68bc0c2591ceebf05ba4 (patch) | |
tree | c92c86bd0d89b844a3794c0e441aa2fccb36725f /net/core/dev.c | |
parent | cb9eff097831007afb30d64373f29d99825d0068 (diff) |
net: infrastructure for hardware time stamping
The additional per-packet information (16 bytes for time stamps, 1
byte for flags) is stored for all packets in the skb_shared_info
struct. This implementation detail is hidden from users of that
information via skb_* accessor functions. A separate struct resp.
union is used for the additional information so that it can be
stored/copied easily outside of skb_shared_info.
Compared to previous implementations (reusing the tstamp field
depending on the context, optional additional structures) this
is the simplest solution. It does not extend sk_buff itself.
TX time stamping is implemented in software if the device driver
doesn't support hardware time stamping.
The new semantic for hardware/software time stamping around
ndo_start_xmit() is based on two assumptions about existing
network device drivers which don't support hardware time
stamping and know nothing about it:
- they leave the new skb_shared_tx unmodified
- the keep the connection to the originating socket in skb->sk
alive, i.e., don't call skb_orphan()
Given that skb_shared_tx is new, the first assumption is safe.
The second is only true for some drivers. As a result, software
TX time stamping currently works with the bnx2 driver, but not
with the unmodified igb driver (the two drivers this patch series
was tested with).
Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/dev.c')
-rw-r--r-- | net/core/dev.c | 32 |
1 files changed, 30 insertions, 2 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 1e27a67df24..d20c28e839d 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -1672,10 +1672,21 @@ static int dev_gso_segment(struct sk_buff *skb) | |||
1672 | return 0; | 1672 | return 0; |
1673 | } | 1673 | } |
1674 | 1674 | ||
1675 | static void tstamp_tx(struct sk_buff *skb) | ||
1676 | { | ||
1677 | union skb_shared_tx *shtx = | ||
1678 | skb_tx(skb); | ||
1679 | if (unlikely(shtx->software && | ||
1680 | !shtx->in_progress)) { | ||
1681 | skb_tstamp_tx(skb, NULL); | ||
1682 | } | ||
1683 | } | ||
1684 | |||
1675 | int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, | 1685 | int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, |
1676 | struct netdev_queue *txq) | 1686 | struct netdev_queue *txq) |
1677 | { | 1687 | { |
1678 | const struct net_device_ops *ops = dev->netdev_ops; | 1688 | const struct net_device_ops *ops = dev->netdev_ops; |
1689 | int rc; | ||
1679 | 1690 | ||
1680 | prefetch(&dev->netdev_ops->ndo_start_xmit); | 1691 | prefetch(&dev->netdev_ops->ndo_start_xmit); |
1681 | if (likely(!skb->next)) { | 1692 | if (likely(!skb->next)) { |
@@ -1689,13 +1700,29 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, | |||
1689 | goto gso; | 1700 | goto gso; |
1690 | } | 1701 | } |
1691 | 1702 | ||
1692 | return ops->ndo_start_xmit(skb, dev); | 1703 | rc = ops->ndo_start_xmit(skb, dev); |
1704 | /* | ||
1705 | * TODO: if skb_orphan() was called by | ||
1706 | * dev->hard_start_xmit() (for example, the unmodified | ||
1707 | * igb driver does that; bnx2 doesn't), then | ||
1708 | * skb_tx_software_timestamp() will be unable to send | ||
1709 | * back the time stamp. | ||
1710 | * | ||
1711 | * How can this be prevented? Always create another | ||
1712 | * reference to the socket before calling | ||
1713 | * dev->hard_start_xmit()? Prevent that skb_orphan() | ||
1714 | * does anything in dev->hard_start_xmit() by clearing | ||
1715 | * the skb destructor before the call and restoring it | ||
1716 | * afterwards, then doing the skb_orphan() ourselves? | ||
1717 | */ | ||
1718 | if (likely(!rc)) | ||
1719 | tstamp_tx(skb); | ||
1720 | return rc; | ||
1693 | } | 1721 | } |
1694 | 1722 | ||
1695 | gso: | 1723 | gso: |
1696 | do { | 1724 | do { |
1697 | struct sk_buff *nskb = skb->next; | 1725 | struct sk_buff *nskb = skb->next; |
1698 | int rc; | ||
1699 | 1726 | ||
1700 | skb->next = nskb->next; | 1727 | skb->next = nskb->next; |
1701 | nskb->next = NULL; | 1728 | nskb->next = NULL; |
@@ -1705,6 +1732,7 @@ gso: | |||
1705 | skb->next = nskb; | 1732 | skb->next = nskb; |
1706 | return rc; | 1733 | return rc; |
1707 | } | 1734 | } |
1735 | tstamp_tx(skb); | ||
1708 | if (unlikely(netif_tx_queue_stopped(txq) && skb->next)) | 1736 | if (unlikely(netif_tx_queue_stopped(txq) && skb->next)) |
1709 | return NETDEV_TX_BUSY; | 1737 | return NETDEV_TX_BUSY; |
1710 | } while (skb->next); | 1738 | } while (skb->next); |