1 # can_socket_blocking.txt
3 # The purpose of this experiment is to show:
4 # 1) "Nonblocking behaviour" (return value of -ENOBUFS) of write() call to
5 # CAN socket (with default settings set to BLOCKING).
6 # This can be caused by:
7 # -- Amount of data sent to a device is much higher than
8 # the device is capable of sending (i.e. frames are dropped by the
10 # -- Amount of data sent to a qdisc (default pfifo gets its size from
11 # txqueuelen parameter of a device) is much higher than the qdisc
12 # can handle -- this leads to packet drop.
14 # 2) Possibility of blocking behaviour of write() call when internal socket
15 # buffer (SO_SNDBUF option) is smaller than qdiscs buffer. (3rd part of
16 # the experiment tries to show that write is "really blocked" -- that this
17 # desired behaviour is not caused only in the manner that none ot the
19 ################################################################################
21 # Set the same for all parts of the experiment
22 $ sudo ip link set can0 txqueuelen 50
24 ################################################################################
25 ##### Default cangen #####
26 ################################################################################
28 $ ip link show dev can0
29 3: can0: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UNKNOWN qlen 50
32 $ ./cangen -g 0 can0 -I i -L 1 -D i -v -v
91 write: No buffer space available
93 $ strace -o cangen.strace -r ./cangen -g 0 can0 -I 125 -L 1 -D i
94 write: No buffer space available
96 $ cat cangen.strace | tail -30
97 0.000082 write(3, "%\1\0\0\1\0\0\0\27\6\0\0\0\0\0\0", 16) = 16
98 0.000091 write(3, "%\1\0\0\1\0\0\0\30\6\0\0\0\0\0\0", 16) = 16
99 0.000082 write(3, "%\1\0\0\1\0\0\0\31\6\0\0\0\0\0\0", 16) = 16
100 0.000082 write(3, "%\1\0\0\1\0\0\0\32\6\0\0\0\0\0\0", 16) = 16
101 0.000081 write(3, "%\1\0\0\1\0\0\0\33\6\0\0\0\0\0\0", 16) = 16
102 0.000082 write(3, "%\1\0\0\1\0\0\0\34\6\0\0\0\0\0\0", 16) = 16
103 0.000081 write(3, "%\1\0\0\1\0\0\0\35\6\0\0\0\0\0\0", 16) = 16
104 0.000082 write(3, "%\1\0\0\1\0\0\0\36\6\0\0\0\0\0\0", 16) = 16
105 0.000050 write(3, "%\1\0\0\1\0\0\0\37\6\0\0\0\0\0\0", 16) = 16
106 0.000082 write(3, "%\1\0\0\1\0\0\0 \6\0\0\0\0\0\0", 16) = 16
107 0.000082 write(3, "%\1\0\0\1\0\0\0!\6\0\0\0\0\0\0", 16) = 16
108 0.000081 write(3, "%\1\0\0\1\0\0\0\"\6\0\0\0\0\0\0", 16) = 16
109 0.000082 write(3, "%\1\0\0\1\0\0\0#\6\0\0\0\0\0\0", 16) = 16
110 0.000082 write(3, "%\1\0\0\1\0\0\0$\6\0\0\0\0\0\0", 16) = 16
111 0.000082 write(3, "%\1\0\0\1\0\0\0%\6\0\0\0\0\0\0", 16) = 16
112 0.000082 write(3, "%\1\0\0\1\0\0\0&\6\0\0\0\0\0\0", 16) = 16
113 0.000081 write(3, "%\1\0\0\1\0\0\0'\6\0\0\0\0\0\0", 16) = 16
114 0.000080 write(3, "%\1\0\0\1\0\0\0(\6\0\0\0\0\0\0", 16) = 16
115 0.000081 write(3, "%\1\0\0\1\0\0\0)\6\0\0\0\0\0\0", 16) = -1 ENOBUFS (No buffer space available)
117 0.000076 fcntl64(4, F_GETFL) = 0x8002 (flags O_RDWR|O_LARGEFILE)
118 0.000177 brk(0) = 0x804e000
119 0.000067 brk(0x806f000) = 0x806f000
120 0.000092 fstat64(4, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
121 0.000151 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7840000
122 0.000079 _llseek(4, 0, 0xbff26d08, SEEK_CUR) = -1 ESPIPE (Illegal seek)
123 0.000107 write(4, "write: No buffer space available"..., 33) = 33
124 0.000095 close(4) = 0
125 0.000066 munmap(0xb7840000, 4096) = 0
126 0.000100 exit_group(1) = ?
129 ################################################################################
130 ##### Cangen with setting of SO_SNDBUF option #####
131 ################################################################################
134 diff --git a/can-utils/cangen.c b/can-utils/cangen.c
135 index 95dfa46..db3fde2 100644
136 --- a/can-utils/cangen.c
137 +++ b/can-utils/cangen.c
138 @@ -105 +105,3 @@ void print_usage(char *prg)
139 - "printing sent CAN frames)\n\n");
140 + "printing sent CAN frames)\n");
141 + fprintf(stderr, " -b (set SO_SNDBUF value of a buffer "
142 + "-- the kernel doubles this value)\n\n");
143 @@ -144,0 +147 @@ int main(int argc, char **argv)
145 @@ -168 +171 @@ int main(int argc, char **argv)
146 - while ((opt = getopt(argc, argv, "ig:eI:L:D:xp:n:vh?")) != -1) {
147 + while ((opt = getopt(argc, argv, "ig:eI:L:D:xp:n:vb:h?")) != -1) {
148 @@ -226,0 +230,4 @@ int main(int argc, char **argv)
150 + snd_buf = atoi(optarg);
153 @@ -301,0 +309,8 @@ int main(int argc, char **argv)
155 + setsockopt(s, SOL_SOCKET, SO_SNDBUF, &snd_buf, sizeof(snd_buf));
158 + getsockopt(s, SOL_SOCKET, SO_SNDBUF, &snd_buf, &len);
159 + printf("SO_SNDBUF: %d\n", snd_buf);
163 $ ip link show dev can0
164 3: can0: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UNKNOWN qlen 50
167 # There is no ENOBUFS error
168 $ ./cangen -b 1024 -g 0 can0 -I 123 -L 1 -D i -v -v | head -10000 | wc -l
172 ################################################################################
173 ##### Throttling of outgoing traffic with TBF #####
174 ################################################################################
177 $ sudo tc qdisc del dev can0 root
179 $ strace -o cangen.strace -r ./cangen -b 1024 -g 0 can0 -I 125 -L 1 -D i
181 $ cat cangen.strace | tail -30
182 0.000079 write(3, "%\1\0\0\1\0\0\0\276.\0\0\0\0\0\0", 16) = 16
183 0.000079 write(3, "%\1\0\0\1\0\0\0\277.\0\0\0\0\0\0", 16) = 16
184 0.000079 write(3, "%\1\0\0\1\0\0\0\300.\0\0\0\0\0\0", 16) = 16
185 0.000078 write(3, "%\1\0\0\1\0\0\0\301.\0\0\0\0\0\0", 16) = 16
186 0.000078 write(3, "%\1\0\0\1\0\0\0\302.\0\0\0\0\0\0", 16) = 16
187 0.000079 write(3, "%\1\0\0\1\0\0\0\303.\0\0\0\0\0\0", 16) = 16
188 0.000079 write(3, "%\1\0\0\1\0\0\0\304.\0\0\0\0\0\0", 16) = 16
189 0.000077 write(3, "%\1\0\0\1\0\0\0\305.\0\0\0\0\0\0", 16) = 16
190 0.000047 write(3, "%\1\0\0\1\0\0\0\306.\0\0\0\0\0\0", 16) = 16
191 0.000079 write(3, "%\1\0\0\1\0\0\0\307.\0\0\0\0\0\0", 16) = 16
192 0.000079 write(3, "%\1\0\0\1\0\0\0\310.\0\0\0\0\0\0", 16) = 16
193 0.000078 write(3, "%\1\0\0\1\0\0\0\311.\0\0\0\0\0\0", 16) = 16
194 0.000078 write(3, "%\1\0\0\1\0\0\0\312.\0\0\0\0\0\0", 16) = 16
195 0.000341 write(3, "%\1\0\0\1\0\0\0\313.\0\0\0\0\0\0", 16) = 16
196 0.000077 write(3, "%\1\0\0\1\0\0\0\314.\0\0\0\0\0\0", 16) = 16
197 0.000079 write(3, "%\1\0\0\1\0\0\0\315.\0\0\0\0\0\0", 16) = 16
198 0.000078 write(3, "%\1\0\0\1\0\0\0\316.\0\0\0\0\0\0", 16) = 16
199 0.000078 write(3, "%\1\0\0\1\0\0\0\317.\0\0\0\0\0\0", 16) = 16
200 0.000047 write(3, "%\1\0\0\1\0\0\0\320.\0\0\0\0\0\0", 16) = 16
201 0.000080 write(3, "%\1\0\0\1\0\0\0\321.\0\0\0\0\0\0", 16) = 16
202 0.000352 write(3, "%\1\0\0\1\0\0\0\322.\0\0\0\0\0\0", 16) = 16
203 0.000087 write(3, "%\1\0\0\1\0\0\0\323.\0\0\0\0\0\0", 16) = 16
204 0.000080 write(3, "%\1\0\0\1\0\0\0\324.\0\0\0\0\0\0", 16) = 16
205 0.000078 write(3, "%\1\0\0\1\0\0\0\325.\0\0\0\0\0\0", 16) = 16
206 0.000079 write(3, "%\1\0\0\1\0\0\0\326.\0\0\0\0\0\0", 16) = 16
207 0.000078 write(3, "%\1\0\0\1\0\0\0\327.\0\0\0\0\0\0", 16) = 16
208 0.000114 --- SIGINT (Interrupt) @ 0 (0) ---
209 0.000072 sigreturn() = ? (mask now [])
210 0.000096 close(3) = 0
211 0.000102 exit_group(0) = ?
217 $ sudo tc qdisc add dev can0 root tbf rate 1kbit burst 1kbit latency 50ms
219 $ strace -o cangen.strace -r ./cangen -b 1024 -g 0 can0 -I 125 -L 1 -D i
221 # Each 5th write blocks for a while
222 $ cat cangen.strace | tail -30
223 0.000048 write(3, "%\1\0\0\1\0\0\0\16\0\0\0\0\0\0\0", 16) = 16
224 0.000047 write(3, "%\1\0\0\1\0\0\0\17\0\0\0\0\0\0\0", 16) = 16
225 0.511054 write(3, "%\1\0\0\1\0\0\0\20\0\0\0\0\0\0\0", 16) = 16
226 0.000081 write(3, "%\1\0\0\1\0\0\0\21\0\0\0\0\0\0\0", 16) = 16
227 0.000047 write(3, "%\1\0\0\1\0\0\0\22\0\0\0\0\0\0\0", 16) = 16
228 0.000048 write(3, "%\1\0\0\1\0\0\0\23\0\0\0\0\0\0\0", 16) = 16
229 0.511835 write(3, "%\1\0\0\1\0\0\0\24\0\0\0\0\0\0\0", 16) = 16
230 0.000104 write(3, "%\1\0\0\1\0\0\0\25\0\0\0\0\0\0\0", 16) = 16
231 0.000050 write(3, "%\1\0\0\1\0\0\0\26\0\0\0\0\0\0\0", 16) = 16
232 0.000047 write(3, "%\1\0\0\1\0\0\0\27\0\0\0\0\0\0\0", 16) = 16
233 0.511787 write(3, "%\1\0\0\1\0\0\0\30\0\0\0\0\0\0\0", 16) = 16
234 0.000078 write(3, "%\1\0\0\1\0\0\0\31\0\0\0\0\0\0\0", 16) = 16
235 0.000049 write(3, "%\1\0\0\1\0\0\0\32\0\0\0\0\0\0\0", 16) = 16
236 0.000048 write(3, "%\1\0\0\1\0\0\0\33\0\0\0\0\0\0\0", 16) = 16
237 0.511823 write(3, "%\1\0\0\1\0\0\0\34\0\0\0\0\0\0\0", 16) = 16
238 0.000080 write(3, "%\1\0\0\1\0\0\0\35\0\0\0\0\0\0\0", 16) = 16
239 0.000048 write(3, "%\1\0\0\1\0\0\0\36\0\0\0\0\0\0\0", 16) = 16
240 0.000049 write(3, "%\1\0\0\1\0\0\0\37\0\0\0\0\0\0\0", 16) = 16
241 0.511859 write(3, "%\1\0\0\1\0\0\0 \0\0\0\0\0\0\0", 16) = 16
242 0.000057 write(3, "%\1\0\0\1\0\0\0!\0\0\0\0\0\0\0", 16) = 16
243 0.000048 write(3, "%\1\0\0\1\0\0\0\"\0\0\0\0\0\0\0", 16) = 16
244 0.000048 write(3, "%\1\0\0\1\0\0\0#\0\0\0\0\0\0\0", 16) = 16
245 0.511819 write(3, "%\1\0\0\1\0\0\0$\0\0\0\0\0\0\0", 16) = 16
246 0.000085 write(3, "%\1\0\0\1\0\0\0%\0\0\0\0\0\0\0", 16) = 16
247 0.000047 write(3, "%\1\0\0\1\0\0\0&\0\0\0\0\0\0\0", 16) = 16
248 0.000048 write(3, "%\1\0\0\1\0\0\0'\0\0\0\0\0\0\0", 16) = 16
249 0.234341 --- SIGINT (Interrupt) @ 0 (0) ---
250 0.000036 sigreturn() = ? (mask now [])
251 0.000064 close(3) = 0
252 0.000069 exit_group(0) = ?
255 # Setting socket as O_NONBLOCK
256 # Observing behaviour with throttled outgoing traffic
259 diff --git a/can-utils/cangen.c b/can-utils/cangen.c
260 index 69b6323..0295f75 100644
261 --- a/can-utils/cangen.c
262 +++ b/can-utils/cangen.c
265 @@ -311,0 +313,2 @@ int main(int argc, char **argv)
266 + fcntl(s, F_SETFL, O_NONBLOCK);
269 $ strace -o cangen.strace -r ./cangen -b 1024 -g 0 can0 -I 125 -L 1 -D i
270 write: Resource temporarily unavailable
272 $ cat cangen.strace | tail -30
273 0.000043 setsockopt(3, SOL_SOCKET, SO_SNDBUF, [1024], 4) = 0
274 0.000043 fcntl64(3, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
275 0.000042 bind(3, {sa_family=0x1d /* AF_??? */, sa_data="\0\0\3\0\0\0\1\0\0\0\3708z\267"}, 16) = 0
276 0.000058 write(3, "%\1\0\0\1\0\0\0\0\0\0\0\0\0\0\0", 16) = 16
277 0.000065 write(3, "%\1\0\0\1\0\0\0\1\0\0\0\0\0\0\0", 16) = 16
278 0.000092 write(3, "%\1\0\0\1\0\0\0\2\0\0\0\0\0\0\0", 16) = 16
279 0.000083 write(3, "%\1\0\0\1\0\0\0\3\0\0\0\0\0\0\0", 16) = 16
280 0.000082 write(3, "%\1\0\0\1\0\0\0\4\0\0\0\0\0\0\0", 16) = 16
281 0.000082 write(3, "%\1\0\0\1\0\0\0\5\0\0\0\0\0\0\0", 16) = 16
282 0.000081 write(3, "%\1\0\0\1\0\0\0\6\0\0\0\0\0\0\0", 16) = 16
283 0.000081 write(3, "%\1\0\0\1\0\0\0\7\0\0\0\0\0\0\0", 16) = 16
284 0.000081 write(3, "%\1\0\0\1\0\0\0\10\0\0\0\0\0\0\0", 16) = 16
285 0.000079 write(3, "%\1\0\0\1\0\0\0\t\0\0\0\0\0\0\0", 16) = 16
286 0.000050 write(3, "%\1\0\0\1\0\0\0\n\0\0\0\0\0\0\0", 16) = 16
287 0.000047 write(3, "%\1\0\0\1\0\0\0\v\0\0\0\0\0\0\0", 16) = 16
288 0.000048 write(3, "%\1\0\0\1\0\0\0\f\0\0\0\0\0\0\0", 16) = 16
289 0.000047 write(3, "%\1\0\0\1\0\0\0\r\0\0\0\0\0\0\0", 16) = 16
290 0.000047 write(3, "%\1\0\0\1\0\0\0\16\0\0\0\0\0\0\0", 16) = 16
291 0.000048 write(3, "%\1\0\0\1\0\0\0\17\0\0\0\0\0\0\0", 16) = -1 EAGAIN (Resource temporarily unavailable)
293 0.000040 fcntl64(4, F_GETFL) = 0x8002 (flags O_RDWR|O_LARGEFILE)
294 0.000101 brk(0) = 0x804e000
295 0.000035 brk(0x806f000) = 0x806f000
296 0.000059 fstat64(4, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 4), ...}) = 0
297 0.000079 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7784000
298 0.000047 _llseek(4, 0, 0xbfbb37f8, SEEK_CUR) = -1 ESPIPE (Illegal seek)
299 0.000079 write(4, "write: Resource temporarily unav"..., 40) = 40
300 0.000059 close(4) = 0
301 0.000036 munmap(0xb7784000, 4096) = 0
302 0.000061 exit_group(1) = ?