Patrick Ohly | cb9eff0 | 2009-02-12 05:03:36 +0000 | [diff] [blame] | 1 | The existing interfaces for getting network packages time stamped are: |
| 2 | |
| 3 | * SO_TIMESTAMP |
| 4 | Generate time stamp for each incoming packet using the (not necessarily |
| 5 | monotonous!) system time. Result is returned via recv_msg() in a |
| 6 | control message as timeval (usec resolution). |
| 7 | |
| 8 | * SO_TIMESTAMPNS |
| 9 | Same time stamping mechanism as SO_TIMESTAMP, but returns result as |
| 10 | timespec (nsec resolution). |
| 11 | |
| 12 | * IP_MULTICAST_LOOP + SO_TIMESTAMP[NS] |
| 13 | Only for multicasts: approximate send time stamp by receiving the looped |
| 14 | packet and using its receive time stamp. |
| 15 | |
| 16 | The following interface complements the existing ones: receive time |
| 17 | stamps can be generated and returned for arbitrary packets and much |
| 18 | closer to the point where the packet is really sent. Time stamps can |
| 19 | be generated in software (as before) or in hardware (if the hardware |
| 20 | has such a feature). |
| 21 | |
| 22 | SO_TIMESTAMPING: |
| 23 | |
| 24 | Instructs the socket layer which kind of information is wanted. The |
| 25 | parameter is an integer with some of the following bits set. Setting |
| 26 | other bits is an error and doesn't change the current state. |
| 27 | |
| 28 | SOF_TIMESTAMPING_TX_HARDWARE: try to obtain send time stamp in hardware |
| 29 | SOF_TIMESTAMPING_TX_SOFTWARE: if SOF_TIMESTAMPING_TX_HARDWARE is off or |
| 30 | fails, then do it in software |
| 31 | SOF_TIMESTAMPING_RX_HARDWARE: return the original, unmodified time stamp |
| 32 | as generated by the hardware |
| 33 | SOF_TIMESTAMPING_RX_SOFTWARE: if SOF_TIMESTAMPING_RX_HARDWARE is off or |
| 34 | fails, then do it in software |
| 35 | SOF_TIMESTAMPING_RAW_HARDWARE: return original raw hardware time stamp |
| 36 | SOF_TIMESTAMPING_SYS_HARDWARE: return hardware time stamp transformed to |
| 37 | the system time base |
| 38 | SOF_TIMESTAMPING_SOFTWARE: return system time stamp generated in |
| 39 | software |
| 40 | |
| 41 | SOF_TIMESTAMPING_TX/RX determine how time stamps are generated. |
| 42 | SOF_TIMESTAMPING_RAW/SYS determine how they are reported in the |
| 43 | following control message: |
Patrick Loschmidt | 6929869 | 2010-04-07 21:52:07 -0700 | [diff] [blame] | 44 | |
| 45 | struct scm_timestamping { |
| 46 | struct timespec systime; |
| 47 | struct timespec hwtimetrans; |
| 48 | struct timespec hwtimeraw; |
| 49 | }; |
Patrick Ohly | cb9eff0 | 2009-02-12 05:03:36 +0000 | [diff] [blame] | 50 | |
| 51 | recvmsg() can be used to get this control message for regular incoming |
| 52 | packets. For send time stamps the outgoing packet is looped back to |
| 53 | the socket's error queue with the send time stamp(s) attached. It can |
| 54 | be received with recvmsg(flags=MSG_ERRQUEUE). The call returns the |
| 55 | original outgoing packet data including all headers preprended down to |
| 56 | and including the link layer, the scm_timestamping control message and |
| 57 | a sock_extended_err control message with ee_errno==ENOMSG and |
| 58 | ee_origin==SO_EE_ORIGIN_TIMESTAMPING. A socket with such a pending |
| 59 | bounced packet is ready for reading as far as select() is concerned. |
Patrick Ohly | 51f31ca | 2009-02-12 05:03:39 +0000 | [diff] [blame] | 60 | If the outgoing packet has to be fragmented, then only the first |
| 61 | fragment is time stamped and returned to the sending socket. |
Patrick Ohly | cb9eff0 | 2009-02-12 05:03:36 +0000 | [diff] [blame] | 62 | |
| 63 | All three values correspond to the same event in time, but were |
| 64 | generated in different ways. Each of these values may be empty (= all |
| 65 | zero), in which case no such value was available. If the application |
| 66 | is not interested in some of these values, they can be left blank to |
| 67 | avoid the potential overhead of calculating them. |
| 68 | |
| 69 | systime is the value of the system time at that moment. This |
| 70 | corresponds to the value also returned via SO_TIMESTAMP[NS]. If the |
| 71 | time stamp was generated by hardware, then this field is |
| 72 | empty. Otherwise it is filled in if SOF_TIMESTAMPING_SOFTWARE is |
| 73 | set. |
| 74 | |
| 75 | hwtimeraw is the original hardware time stamp. Filled in if |
| 76 | SOF_TIMESTAMPING_RAW_HARDWARE is set. No assumptions about its |
| 77 | relation to system time should be made. |
| 78 | |
| 79 | hwtimetrans is the hardware time stamp transformed so that it |
| 80 | corresponds as good as possible to system time. This correlation is |
| 81 | not perfect; as a consequence, sorting packets received via different |
| 82 | NICs by their hwtimetrans may differ from the order in which they were |
| 83 | received. hwtimetrans may be non-monotonic even for the same NIC. |
| 84 | Filled in if SOF_TIMESTAMPING_SYS_HARDWARE is set. Requires support |
| 85 | by the network device and will be empty without that support. |
| 86 | |
| 87 | |
Ben Hutchings | fd468c7 | 2013-11-14 01:19:29 +0000 | [diff] [blame] | 88 | SIOCSHWTSTAMP, SIOCGHWTSTAMP: |
Patrick Ohly | cb9eff0 | 2009-02-12 05:03:36 +0000 | [diff] [blame] | 89 | |
| 90 | Hardware time stamping must also be initialized for each device driver |
Patrick Loschmidt | 6929869 | 2010-04-07 21:52:07 -0700 | [diff] [blame] | 91 | that is expected to do hardware time stamping. The parameter is defined in |
| 92 | /include/linux/net_tstamp.h as: |
Patrick Ohly | cb9eff0 | 2009-02-12 05:03:36 +0000 | [diff] [blame] | 93 | |
| 94 | struct hwtstamp_config { |
Patrick Loschmidt | 6929869 | 2010-04-07 21:52:07 -0700 | [diff] [blame] | 95 | int flags; /* no flags defined right now, must be zero */ |
| 96 | int tx_type; /* HWTSTAMP_TX_* */ |
| 97 | int rx_filter; /* HWTSTAMP_FILTER_* */ |
Patrick Ohly | cb9eff0 | 2009-02-12 05:03:36 +0000 | [diff] [blame] | 98 | }; |
| 99 | |
| 100 | Desired behavior is passed into the kernel and to a specific device by |
| 101 | calling ioctl(SIOCSHWTSTAMP) with a pointer to a struct ifreq whose |
| 102 | ifr_data points to a struct hwtstamp_config. The tx_type and |
| 103 | rx_filter are hints to the driver what it is expected to do. If |
| 104 | the requested fine-grained filtering for incoming packets is not |
| 105 | supported, the driver may time stamp more than just the requested types |
| 106 | of packets. |
| 107 | |
| 108 | A driver which supports hardware time stamping shall update the struct |
| 109 | with the actual, possibly more permissive configuration. If the |
| 110 | requested packets cannot be time stamped, then nothing should be |
| 111 | changed and ERANGE shall be returned (in contrast to EINVAL, which |
| 112 | indicates that SIOCSHWTSTAMP is not supported at all). |
| 113 | |
| 114 | Only a processes with admin rights may change the configuration. User |
| 115 | space is responsible to ensure that multiple processes don't interfere |
| 116 | with each other and that the settings are reset. |
| 117 | |
Ben Hutchings | fd468c7 | 2013-11-14 01:19:29 +0000 | [diff] [blame] | 118 | Any process can read the actual configuration by passing this |
| 119 | structure to ioctl(SIOCGHWTSTAMP) in the same way. However, this has |
| 120 | not been implemented in all drivers. |
| 121 | |
Patrick Ohly | cb9eff0 | 2009-02-12 05:03:36 +0000 | [diff] [blame] | 122 | /* possible values for hwtstamp_config->tx_type */ |
| 123 | enum { |
| 124 | /* |
| 125 | * no outgoing packet will need hardware time stamping; |
| 126 | * should a packet arrive which asks for it, no hardware |
| 127 | * time stamping will be done |
| 128 | */ |
| 129 | HWTSTAMP_TX_OFF, |
| 130 | |
| 131 | /* |
| 132 | * enables hardware time stamping for outgoing packets; |
| 133 | * the sender of the packet decides which are to be |
| 134 | * time stamped by setting SOF_TIMESTAMPING_TX_SOFTWARE |
| 135 | * before sending the packet |
| 136 | */ |
| 137 | HWTSTAMP_TX_ON, |
| 138 | }; |
| 139 | |
| 140 | /* possible values for hwtstamp_config->rx_filter */ |
| 141 | enum { |
| 142 | /* time stamp no incoming packet at all */ |
| 143 | HWTSTAMP_FILTER_NONE, |
| 144 | |
| 145 | /* time stamp any incoming packet */ |
| 146 | HWTSTAMP_FILTER_ALL, |
| 147 | |
Patrick Loschmidt | 6929869 | 2010-04-07 21:52:07 -0700 | [diff] [blame] | 148 | /* return value: time stamp all packets requested plus some others */ |
| 149 | HWTSTAMP_FILTER_SOME, |
Patrick Ohly | cb9eff0 | 2009-02-12 05:03:36 +0000 | [diff] [blame] | 150 | |
| 151 | /* PTP v1, UDP, any kind of event packet */ |
| 152 | HWTSTAMP_FILTER_PTP_V1_L4_EVENT, |
| 153 | |
Patrick Loschmidt | 6929869 | 2010-04-07 21:52:07 -0700 | [diff] [blame] | 154 | /* for the complete list of values, please check |
| 155 | * the include file /include/linux/net_tstamp.h |
| 156 | */ |
Patrick Ohly | cb9eff0 | 2009-02-12 05:03:36 +0000 | [diff] [blame] | 157 | }; |
| 158 | |
| 159 | |
| 160 | DEVICE IMPLEMENTATION |
| 161 | |
| 162 | A driver which supports hardware time stamping must support the |
Patrick Loschmidt | 6929869 | 2010-04-07 21:52:07 -0700 | [diff] [blame] | 163 | SIOCSHWTSTAMP ioctl and update the supplied struct hwtstamp_config with |
Ben Hutchings | fd468c7 | 2013-11-14 01:19:29 +0000 | [diff] [blame] | 164 | the actual values as described in the section on SIOCSHWTSTAMP. It |
| 165 | should also support SIOCGHWTSTAMP. |
Patrick Loschmidt | 6929869 | 2010-04-07 21:52:07 -0700 | [diff] [blame] | 166 | |
| 167 | Time stamps for received packets must be stored in the skb. To get a pointer |
| 168 | to the shared time stamp structure of the skb call skb_hwtstamps(). Then |
| 169 | set the time stamps in the structure: |
| 170 | |
| 171 | struct skb_shared_hwtstamps { |
| 172 | /* hardware time stamp transformed into duration |
| 173 | * since arbitrary point in time |
| 174 | */ |
| 175 | ktime_t hwtstamp; |
| 176 | ktime_t syststamp; /* hwtstamp transformed to system time base */ |
| 177 | }; |
Patrick Ohly | cb9eff0 | 2009-02-12 05:03:36 +0000 | [diff] [blame] | 178 | |
| 179 | Time stamps for outgoing packets are to be generated as follows: |
Oliver Hartkopp | 2244d07 | 2010-08-17 08:59:14 +0000 | [diff] [blame] | 180 | - In hard_start_xmit(), check if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) |
| 181 | is set no-zero. If yes, then the driver is expected to do hardware time |
| 182 | stamping. |
Patrick Ohly | cb9eff0 | 2009-02-12 05:03:36 +0000 | [diff] [blame] | 183 | - If this is possible for the skb and requested, then declare |
Oliver Hartkopp | 2244d07 | 2010-08-17 08:59:14 +0000 | [diff] [blame] | 184 | that the driver is doing the time stamping by setting the flag |
| 185 | SKBTX_IN_PROGRESS in skb_shinfo(skb)->tx_flags , e.g. with |
| 186 | |
| 187 | skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; |
| 188 | |
| 189 | You might want to keep a pointer to the associated skb for the next step |
| 190 | and not free the skb. A driver not supporting hardware time stamping doesn't |
| 191 | do that. A driver must never touch sk_buff::tstamp! It is used to store |
| 192 | software generated time stamps by the network subsystem. |
Patrick Ohly | cb9eff0 | 2009-02-12 05:03:36 +0000 | [diff] [blame] | 193 | - As soon as the driver has sent the packet and/or obtained a |
| 194 | hardware time stamp for it, it passes the time stamp back by |
| 195 | calling skb_hwtstamp_tx() with the original skb, the raw |
Patrick Loschmidt | 6929869 | 2010-04-07 21:52:07 -0700 | [diff] [blame] | 196 | hardware time stamp. skb_hwtstamp_tx() clones the original skb and |
| 197 | adds the timestamps, therefore the original skb has to be freed now. |
| 198 | If obtaining the hardware time stamp somehow fails, then the driver |
| 199 | should not fall back to software time stamping. The rationale is that |
| 200 | this would occur at a later time in the processing pipeline than other |
| 201 | software time stamping and therefore could lead to unexpected deltas |
| 202 | between time stamps. |
Oliver Hartkopp | 2244d07 | 2010-08-17 08:59:14 +0000 | [diff] [blame] | 203 | - If the driver did not set the SKBTX_IN_PROGRESS flag (see above), then |
Patrick Ohly | cb9eff0 | 2009-02-12 05:03:36 +0000 | [diff] [blame] | 204 | dev_hard_start_xmit() checks whether software time stamping |
| 205 | is wanted as fallback and potentially generates the time stamp. |