1 /*
2 * Copyright (C) 2013-2021 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 * This code is a complete clean re-write of the stress tool by
19 * Colin Ian King <colin.king@canonical.com> and attempts to be
20 * backwardly compatible with the stress tool by Amos Waterland
21 * <apw@rossby.metr.ou.edu> but has more stress tests and more
22 * functionality.
23 *
24 */
25 #include "stress-ng.h"
26
27 static const stress_help_t help[] = {
28 { NULL, "netdev N", "start N workers exercising netdevice ioctls" },
29 { NULL, "netdev-ops N", "stop netdev workers after N bogo operations" },
30 { NULL, NULL, NULL }
31 };
32
33 #if defined(__linux__) && \
34 defined(SIOCGIFCONF) && \
35 defined(HAVE_IFCONF)
36
37 /*
38 * As per man 7 netdevice advise, workaround glibc 2.1 missing
39 * ifr_newname
40 */
41 #ifndef ifr_newname
42 #define ifr_newname ifr_ifru.ifru_slave
43 #endif
44
45 /*
46 * stress_netdev_check()
47 * helper to perform netdevice ioctl and check for failure
48 */
stress_netdev_check(const stress_args_t * args,struct ifreq * ifr,const int fd,const unsigned long cmd,const char * cmd_name)49 static void stress_netdev_check(
50 const stress_args_t *args,
51 struct ifreq *ifr,
52 const int fd,
53 const unsigned long cmd,
54 const char *cmd_name)
55 {
56 if (ioctl(fd, cmd, ifr) < 0) {
57 if ((errno != ENOTTY) &&
58 (errno != EINVAL) &&
59 (errno != EADDRNOTAVAIL) &&
60 (errno != EOPNOTSUPP) &&
61 (errno != EBUSY) &&
62 (errno != EPERM))
63 pr_fail("%s: interface '%s' ioctl %s failed, errno=%d (%s)\n",
64 args->name, ifr->ifr_name, cmd_name,
65 errno, strerror(errno));
66 }
67 }
68
69 #define STRESS_NETDEV_CHECK(args, ifr, fd, cmd) \
70 stress_netdev_check(args, ifr, fd, cmd, #cmd)
71
72 /*
73 * stress_netdev
74 * stress netdev
75 */
stress_netdev(const stress_args_t * args)76 static int stress_netdev(const stress_args_t *args)
77 {
78 int fd, rc = EXIT_SUCCESS;
79
80 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
81 pr_fail("%s: socket failed, errno=%d (%s)\n",
82 args->name, errno, strerror(errno));
83 /* failed, kick parent to finish */
84 return EXIT_NO_RESOURCE;
85 }
86
87 stress_set_proc_state(args->name, STRESS_STATE_RUN);
88
89 do {
90 int i, n;
91 struct ifconf ifc;
92
93 /* Get list of transport layer addresses */
94 (void)memset(&ifc, 0, sizeof(ifc));
95 rc = ioctl(fd, SIOCGIFCONF, &ifc);
96 if (rc < 0) {
97 pr_fail("%s: ioctl SIOCGIFCONF failed, errno=%d (%s)\n",
98 args->name, errno, strerror(errno));
99 rc = EXIT_FAILURE;
100 break;
101 }
102
103 /* Do we have any? We should normally have at least lo */
104 n = ifc.ifc_len / (int)sizeof(struct ifreq);
105 if (!n) {
106 if (args->instance == 0)
107 pr_dbg_skip("%s: no network interfaces found, skipping.\n",
108 args->name);
109 break;
110 }
111
112 /* Allocate buffer for the addresses */
113 ifc.ifc_buf = malloc((size_t)ifc.ifc_len);
114 if (!ifc.ifc_buf) {
115 pr_fail("%s: out of memory allocating interface buffer\n",
116 args->name);
117 rc = EXIT_NO_RESOURCE;
118 }
119
120 /* Fetch the addresses */
121 if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) {
122 pr_fail("%s: ioctl SIOCGIFCONF failed, errno=%d (%s)\n",
123 args->name, errno, strerror(errno));
124 rc = EXIT_FAILURE;
125 break;
126 }
127
128 /* And get info on each network device */
129 for (i = 0; i < n; i++) {
130 struct ifreq *ifr = &ifc.ifc_req[i];
131
132 #if defined(SIOCGIFINDEX)
133 /* We got the name, check it's index */
134 if (ioctl(fd, SIOCGIFINDEX, ifr) < 0)
135 continue;
136 #endif
137
138 #if defined(SIOCGIFNAME)
139 ifr->ifr_ifindex = i;
140 /* Get name */
141 if (ioctl(fd, SIOCGIFNAME, ifr) < 0)
142 continue;
143
144 /* Check index is sane */
145 if (ifr->ifr_ifindex != i) {
146 pr_fail("%s: interface '%s' returned index %d, expected %d\n",
147 args->name, ifr->ifr_name,
148 ifr->ifr_ifindex, i);
149 }
150 #endif
151
152 #if defined(SIOCGIFFLAGS)
153 /* Get flags */
154 STRESS_NETDEV_CHECK(args, ifr, fd, SIOCGIFFLAGS);
155 #endif
156
157 #if defined(SIOCGIFPFLAGS)
158 /* Get extended flags */
159 STRESS_NETDEV_CHECK(args, ifr, fd, SIOCGIFPFLAGS);
160 #endif
161
162 #if defined(SIOCGIFADDR)
163 /* Get address */
164 STRESS_NETDEV_CHECK(args, ifr, fd, SIOCGIFADDR);
165 #endif
166
167 #if defined(SIOCGIFNETMASK)
168 /* Get netmask */
169 STRESS_NETDEV_CHECK(args, ifr, fd, SIOCGIFNETMASK);
170 #endif
171
172 #if defined(SIOCGIFMETRIC)
173 /* Get metric (currently not supported) */
174 STRESS_NETDEV_CHECK(args, ifr, fd, SIOCGIFMETRIC);
175 #endif
176
177 #if defined(SIOCGIFMTU)
178 /* Get the MTU */
179 STRESS_NETDEV_CHECK(args, ifr, fd, SIOCGIFMTU);
180 #endif
181
182 #if defined(SIOCGIFHWADDR)
183 /* Get the hardware address */
184 STRESS_NETDEV_CHECK(args, ifr, fd, SIOCGIFHWADDR);
185 #endif
186
187 #if defined(SIOCGIFMAP)
188 /* Get the hardware parameters */
189 STRESS_NETDEV_CHECK(args, ifr, fd, SIOCGIFMAP);
190 #endif
191
192 #if defined(SIOCGIFTXQLEN)
193 /* Get the transmit queue length */
194 STRESS_NETDEV_CHECK(args, ifr, fd, SIOCGIFTXQLEN);
195 #endif
196
197 #if defined(SIOCGIFDSTADDR)
198 /* Get the destination address */
199 STRESS_NETDEV_CHECK(args, ifr, fd, SIOCGIFDSTADDR);
200 #endif
201
202 #if defined(SIOCGIFBRDADDR)
203 /* Get the broadcast address */
204 STRESS_NETDEV_CHECK(args, ifr, fd, SIOCGIFBRDADDR);
205 #endif
206 #if defined(SIOCGMIIPHY) && 0
207 /* Get from current PHY, disabled for now */
208 STRESS_NETDEV_CHECK(args, ifr, fd, SIOCGMIIPHY);
209 #endif
210 #if defined(SIOCGMIIREG) && 0
211 /* Get reg, disabled for now */
212 STRESS_NETDEV_CHECK(args, ifr, fd, SIOCGMIIREG);
213 #endif
214 #if defined(SIOCSIFFLAGS) && 0
215 /* Get flags, disabled for now */
216 STRESS_NETDEV_CHECK(args, ifr, fd, SIOCSIFFLAGS);
217 #endif
218 #if defined(SIOCSIFMETRIC) && 0
219 /* Get metric, disabled for now */
220 STRESS_NETDEV_CHECK(args, ifr, fd, SIOCSIFMETRIC);
221 #endif
222 #if defined(SIOCGIFMEM)
223 /* Get memory space, not implemented */
224 STRESS_NETDEV_CHECK(args, ifr, fd, SIOCGIFMEM);
225 #endif
226 #if defined(SIOCGIFLINK)
227 /* Get if link, not implemented */
228 STRESS_NETDEV_CHECK(args, ifr, fd, SIOCGIFLINK);
229 #endif
230 }
231 free(ifc.ifc_buf);
232 inc_counter(args);
233 } while (keep_stressing(args));
234
235 stress_set_proc_state(args->name, STRESS_STATE_DEINIT);
236
237 (void)close(fd);
238
239 return rc;
240 }
241
242 stressor_info_t stress_netdev_info = {
243 .stressor = stress_netdev,
244 .class = CLASS_NETWORK,
245 .help = help
246 };
247 #else
248 stressor_info_t stress_netdev_info = {
249 .stressor = stress_not_implemented,
250 .class = CLASS_NETWORK,
251 .help = help
252 };
253 #endif
254