| 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 |  | 
 | 88 | SIOCSHWTSTAMP: | 
 | 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 |  | 
 | 118 | /* possible values for hwtstamp_config->tx_type */ | 
 | 119 | enum { | 
 | 120 | 	/* | 
 | 121 | 	 * no outgoing packet will need hardware time stamping; | 
 | 122 | 	 * should a packet arrive which asks for it, no hardware | 
 | 123 | 	 * time stamping will be done | 
 | 124 | 	 */ | 
 | 125 | 	HWTSTAMP_TX_OFF, | 
 | 126 |  | 
 | 127 | 	/* | 
 | 128 | 	 * enables hardware time stamping for outgoing packets; | 
 | 129 | 	 * the sender of the packet decides which are to be | 
 | 130 | 	 * time stamped by setting SOF_TIMESTAMPING_TX_SOFTWARE | 
 | 131 | 	 * before sending the packet | 
 | 132 | 	 */ | 
 | 133 | 	HWTSTAMP_TX_ON, | 
 | 134 | }; | 
 | 135 |  | 
 | 136 | /* possible values for hwtstamp_config->rx_filter */ | 
 | 137 | enum { | 
 | 138 | 	/* time stamp no incoming packet at all */ | 
 | 139 | 	HWTSTAMP_FILTER_NONE, | 
 | 140 |  | 
 | 141 | 	/* time stamp any incoming packet */ | 
 | 142 | 	HWTSTAMP_FILTER_ALL, | 
 | 143 |  | 
| Patrick Loschmidt | 6929869 | 2010-04-07 21:52:07 -0700 | [diff] [blame] | 144 | 	/* return value: time stamp all packets requested plus some others */ | 
 | 145 | 	HWTSTAMP_FILTER_SOME, | 
| Patrick Ohly | cb9eff0 | 2009-02-12 05:03:36 +0000 | [diff] [blame] | 146 |  | 
 | 147 | 	/* PTP v1, UDP, any kind of event packet */ | 
 | 148 | 	HWTSTAMP_FILTER_PTP_V1_L4_EVENT, | 
 | 149 |  | 
| Patrick Loschmidt | 6929869 | 2010-04-07 21:52:07 -0700 | [diff] [blame] | 150 | 	/* for the complete list of values, please check | 
 | 151 | 	 * the include file /include/linux/net_tstamp.h | 
 | 152 | 	 */ | 
| Patrick Ohly | cb9eff0 | 2009-02-12 05:03:36 +0000 | [diff] [blame] | 153 | }; | 
 | 154 |  | 
 | 155 |  | 
 | 156 | DEVICE IMPLEMENTATION | 
 | 157 |  | 
 | 158 | A driver which supports hardware time stamping must support the | 
| Patrick Loschmidt | 6929869 | 2010-04-07 21:52:07 -0700 | [diff] [blame] | 159 | SIOCSHWTSTAMP ioctl and update the supplied struct hwtstamp_config with | 
 | 160 | the actual values as described in the section on SIOCSHWTSTAMP. | 
 | 161 |  | 
 | 162 | Time stamps for received packets must be stored in the skb. To get a pointer | 
 | 163 | to the shared time stamp structure of the skb call skb_hwtstamps(). Then | 
 | 164 | set the time stamps in the structure: | 
 | 165 |  | 
 | 166 | struct skb_shared_hwtstamps { | 
 | 167 | 	/* hardware time stamp transformed into duration | 
 | 168 | 	 * since arbitrary point in time | 
 | 169 | 	 */ | 
 | 170 | 	ktime_t	hwtstamp; | 
 | 171 | 	ktime_t	syststamp; /* hwtstamp transformed to system time base */ | 
 | 172 | }; | 
| Patrick Ohly | cb9eff0 | 2009-02-12 05:03:36 +0000 | [diff] [blame] | 173 |  | 
 | 174 | Time stamps for outgoing packets are to be generated as follows: | 
| Patrick Loschmidt | 6929869 | 2010-04-07 21:52:07 -0700 | [diff] [blame] | 175 | - In hard_start_xmit(), check if skb_tx(skb)->hardware is set no-zero. | 
 | 176 |   If yes, then the driver is expected to do hardware time stamping. | 
| Patrick Ohly | cb9eff0 | 2009-02-12 05:03:36 +0000 | [diff] [blame] | 177 | - If this is possible for the skb and requested, then declare | 
| Patrick Loschmidt | 6929869 | 2010-04-07 21:52:07 -0700 | [diff] [blame] | 178 |   that the driver is doing the time stamping by setting the field | 
 | 179 |   skb_tx(skb)->in_progress non-zero. You might want to keep a pointer | 
 | 180 |   to the associated skb for the next step and not free the skb. A driver | 
 | 181 |   not supporting hardware time stamping doesn't do that. A driver must | 
 | 182 |   never touch sk_buff::tstamp! It is used to store software generated | 
 | 183 |   time stamps by the network subsystem. | 
| Patrick Ohly | cb9eff0 | 2009-02-12 05:03:36 +0000 | [diff] [blame] | 184 | - As soon as the driver has sent the packet and/or obtained a | 
 | 185 |   hardware time stamp for it, it passes the time stamp back by | 
 | 186 |   calling skb_hwtstamp_tx() with the original skb, the raw | 
| Patrick Loschmidt | 6929869 | 2010-04-07 21:52:07 -0700 | [diff] [blame] | 187 |   hardware time stamp. skb_hwtstamp_tx() clones the original skb and | 
 | 188 |   adds the timestamps, therefore the original skb has to be freed now. | 
 | 189 |   If obtaining the hardware time stamp somehow fails, then the driver | 
 | 190 |   should not fall back to software time stamping. The rationale is that | 
 | 191 |   this would occur at a later time in the processing pipeline than other | 
 | 192 |   software time stamping and therefore could lead to unexpected deltas | 
 | 193 |   between time stamps. | 
 | 194 | - If the driver did not call set skb_tx(skb)->in_progress, then | 
| Patrick Ohly | cb9eff0 | 2009-02-12 05:03:36 +0000 | [diff] [blame] | 195 |   dev_hard_start_xmit() checks whether software time stamping | 
 | 196 |   is wanted as fallback and potentially generates the time stamp. |