blob: be800d0e7a841abfbc60545cf63fe33219db0c35 [file] [log] [blame]
Jakub Kicinski417ec262017-12-01 15:09:00 -08001#!/usr/bin/python3
2
3# Copyright (C) 2017 Netronome Systems, Inc.
4#
5# This software is licensed under the GNU General License Version 2,
6# June 1991 as shown in the file COPYING in the top-level directory of this
7# source tree.
8#
9# THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS"
10# WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
11# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
12# FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
13# OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
14# THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
15
16from datetime import datetime
17import argparse
18import json
19import os
20import pprint
Jakub Kicinski752d7b42017-12-27 18:39:11 -080021import random
22import string
Jakub Kicinski7fedbb72018-01-17 19:13:31 -080023import struct
Jakub Kicinski417ec262017-12-01 15:09:00 -080024import subprocess
25import time
26
27logfile = None
28log_level = 1
Quentin Monnetcaf95222018-01-23 11:22:53 -080029skip_extack = False
Jakub Kicinski417ec262017-12-01 15:09:00 -080030bpf_test_dir = os.path.dirname(os.path.realpath(__file__))
31pp = pprint.PrettyPrinter()
32devs = [] # devices we created for clean up
33files = [] # files to be removed
Jakub Kicinski752d7b42017-12-27 18:39:11 -080034netns = [] # net namespaces to be removed
Jakub Kicinski417ec262017-12-01 15:09:00 -080035
36def log_get_sec(level=0):
37 return "*" * (log_level + level)
38
39def log_level_inc(add=1):
40 global log_level
41 log_level += add
42
43def log_level_dec(sub=1):
44 global log_level
45 log_level -= sub
46
47def log_level_set(level):
48 global log_level
49 log_level = level
50
51def log(header, data, level=None):
52 """
53 Output to an optional log.
54 """
55 if logfile is None:
56 return
57 if level is not None:
58 log_level_set(level)
59
60 if not isinstance(data, str):
61 data = pp.pformat(data)
62
63 if len(header):
64 logfile.write("\n" + log_get_sec() + " ")
65 logfile.write(header)
66 if len(header) and len(data.strip()):
67 logfile.write("\n")
68 logfile.write(data)
69
70def skip(cond, msg):
71 if not cond:
72 return
73 print("SKIP: " + msg)
74 log("SKIP: " + msg, "", level=1)
75 os.sys.exit(0)
76
77def fail(cond, msg):
78 if not cond:
79 return
80 print("FAIL: " + msg)
81 log("FAIL: " + msg, "", level=1)
82 os.sys.exit(1)
83
84def start_test(msg):
85 log(msg, "", level=1)
86 log_level_inc()
87 print(msg)
88
89def cmd(cmd, shell=True, include_stderr=False, background=False, fail=True):
90 """
91 Run a command in subprocess and return tuple of (retval, stdout);
92 optionally return stderr as well as third value.
93 """
94 proc = subprocess.Popen(cmd, shell=shell, stdout=subprocess.PIPE,
95 stderr=subprocess.PIPE)
96 if background:
97 msg = "%s START: %s" % (log_get_sec(1),
98 datetime.now().strftime("%H:%M:%S.%f"))
99 log("BKG " + proc.args, msg)
100 return proc
101
102 return cmd_result(proc, include_stderr=include_stderr, fail=fail)
103
104def cmd_result(proc, include_stderr=False, fail=False):
105 stdout, stderr = proc.communicate()
106 stdout = stdout.decode("utf-8")
107 stderr = stderr.decode("utf-8")
108 proc.stdout.close()
109 proc.stderr.close()
110
111 stderr = "\n" + stderr
112 if stderr[-1] == "\n":
113 stderr = stderr[:-1]
114
115 sec = log_get_sec(1)
116 log("CMD " + proc.args,
117 "RETCODE: %d\n%s STDOUT:\n%s%s STDERR:%s\n%s END: %s" %
118 (proc.returncode, sec, stdout, sec, stderr,
119 sec, datetime.now().strftime("%H:%M:%S.%f")))
120
121 if proc.returncode != 0 and fail:
122 if len(stderr) > 0 and stderr[-1] == "\n":
123 stderr = stderr[:-1]
124 raise Exception("Command failed: %s\n%s" % (proc.args, stderr))
125
126 if include_stderr:
127 return proc.returncode, stdout, stderr
128 else:
129 return proc.returncode, stdout
130
131def rm(f):
132 cmd("rm -f %s" % (f))
133 if f in files:
134 files.remove(f)
135
Quentin Monnetcaf95222018-01-23 11:22:53 -0800136def tool(name, args, flags, JSON=True, ns="", fail=True, include_stderr=False):
Jakub Kicinski417ec262017-12-01 15:09:00 -0800137 params = ""
138 if JSON:
139 params += "%s " % (flags["json"])
140
Jakub Kicinski752d7b42017-12-27 18:39:11 -0800141 if ns != "":
142 ns = "ip netns exec %s " % (ns)
143
Quentin Monnetcaf95222018-01-23 11:22:53 -0800144 if include_stderr:
145 ret, stdout, stderr = cmd(ns + name + " " + params + args,
146 fail=fail, include_stderr=True)
147 else:
148 ret, stdout = cmd(ns + name + " " + params + args,
149 fail=fail, include_stderr=False)
150
151 if JSON and len(stdout.strip()) != 0:
152 out = json.loads(stdout)
153 else:
154 out = stdout
155
156 if include_stderr:
157 return ret, out, stderr
Jakub Kicinski417ec262017-12-01 15:09:00 -0800158 else:
159 return ret, out
160
Jakub Kicinski752d7b42017-12-27 18:39:11 -0800161def bpftool(args, JSON=True, ns="", fail=True):
162 return tool("bpftool", args, {"json":"-p"}, JSON=JSON, ns=ns, fail=fail)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800163
Jakub Kicinski752d7b42017-12-27 18:39:11 -0800164def bpftool_prog_list(expected=None, ns=""):
165 _, progs = bpftool("prog show", JSON=True, ns=ns, fail=True)
Jakub Kicinski47cf52a2018-06-14 11:06:56 -0700166 # Remove the base progs
167 for p in base_progs:
168 if p in progs:
169 progs.remove(p)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800170 if expected is not None:
171 if len(progs) != expected:
172 fail(True, "%d BPF programs loaded, expected %d" %
173 (len(progs), expected))
174 return progs
175
Jakub Kicinski7fedbb72018-01-17 19:13:31 -0800176def bpftool_map_list(expected=None, ns=""):
177 _, maps = bpftool("map show", JSON=True, ns=ns, fail=True)
Jakub Kicinski47cf52a2018-06-14 11:06:56 -0700178 # Remove the base maps
179 for m in base_maps:
180 if m in maps:
181 maps.remove(m)
Jakub Kicinski7fedbb72018-01-17 19:13:31 -0800182 if expected is not None:
183 if len(maps) != expected:
184 fail(True, "%d BPF maps loaded, expected %d" %
185 (len(maps), expected))
186 return maps
187
Jakub Kicinski417ec262017-12-01 15:09:00 -0800188def bpftool_prog_list_wait(expected=0, n_retry=20):
189 for i in range(n_retry):
190 nprogs = len(bpftool_prog_list())
191 if nprogs == expected:
192 return
193 time.sleep(0.05)
194 raise Exception("Time out waiting for program counts to stabilize want %d, have %d" % (expected, nprogs))
195
Jakub Kicinski7fedbb72018-01-17 19:13:31 -0800196def bpftool_map_list_wait(expected=0, n_retry=20):
197 for i in range(n_retry):
198 nmaps = len(bpftool_map_list())
199 if nmaps == expected:
200 return
201 time.sleep(0.05)
202 raise Exception("Time out waiting for map counts to stabilize want %d, have %d" % (expected, nmaps))
203
Quentin Monnetcaf95222018-01-23 11:22:53 -0800204def ip(args, force=False, JSON=True, ns="", fail=True, include_stderr=False):
Jakub Kicinski417ec262017-12-01 15:09:00 -0800205 if force:
206 args = "-force " + args
Quentin Monnetcaf95222018-01-23 11:22:53 -0800207 return tool("ip", args, {"json":"-j"}, JSON=JSON, ns=ns,
208 fail=fail, include_stderr=include_stderr)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800209
Quentin Monnetcaf95222018-01-23 11:22:53 -0800210def tc(args, JSON=True, ns="", fail=True, include_stderr=False):
211 return tool("tc", args, {"json":"-p"}, JSON=JSON, ns=ns,
212 fail=fail, include_stderr=include_stderr)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800213
214def ethtool(dev, opt, args, fail=True):
215 return cmd("ethtool %s %s %s" % (opt, dev["ifname"], args), fail=fail)
216
217def bpf_obj(name, sec=".text", path=bpf_test_dir,):
218 return "obj %s sec %s" % (os.path.join(path, name), sec)
219
220def bpf_pinned(name):
221 return "pinned %s" % (name)
222
223def bpf_bytecode(bytecode):
224 return "bytecode \"%s\"" % (bytecode)
225
Jakub Kicinski752d7b42017-12-27 18:39:11 -0800226def mknetns(n_retry=10):
227 for i in range(n_retry):
228 name = ''.join([random.choice(string.ascii_letters) for i in range(8)])
229 ret, _ = ip("netns add %s" % (name), fail=False)
230 if ret == 0:
231 netns.append(name)
232 return name
233 return None
234
Jakub Kicinski7fedbb72018-01-17 19:13:31 -0800235def int2str(fmt, val):
236 ret = []
237 for b in struct.pack(fmt, val):
238 ret.append(int(b))
239 return " ".join(map(lambda x: str(x), ret))
240
241def str2int(strtab):
242 inttab = []
243 for i in strtab:
244 inttab.append(int(i, 16))
245 ba = bytearray(inttab)
246 if len(strtab) == 4:
247 fmt = "I"
248 elif len(strtab) == 8:
249 fmt = "Q"
250 else:
251 raise Exception("String array of len %d can't be unpacked to an int" %
252 (len(strtab)))
253 return struct.unpack(fmt, ba)[0]
254
Jakub Kicinski417ec262017-12-01 15:09:00 -0800255class DebugfsDir:
256 """
257 Class for accessing DebugFS directories as a dictionary.
258 """
259
260 def __init__(self, path):
261 self.path = path
262 self._dict = self._debugfs_dir_read(path)
263
264 def __len__(self):
265 return len(self._dict.keys())
266
267 def __getitem__(self, key):
268 if type(key) is int:
269 key = list(self._dict.keys())[key]
270 return self._dict[key]
271
272 def __setitem__(self, key, value):
273 log("DebugFS set %s = %s" % (key, value), "")
274 log_level_inc()
275
276 cmd("echo '%s' > %s/%s" % (value, self.path, key))
277 log_level_dec()
278
279 _, out = cmd('cat %s/%s' % (self.path, key))
280 self._dict[key] = out.strip()
281
282 def _debugfs_dir_read(self, path):
283 dfs = {}
284
285 log("DebugFS state for %s" % (path), "")
286 log_level_inc(add=2)
287
288 _, out = cmd('ls ' + path)
289 for f in out.split():
290 p = os.path.join(path, f)
291 if os.path.isfile(p):
292 _, out = cmd('cat %s/%s' % (path, f))
293 dfs[f] = out.strip()
294 elif os.path.isdir(p):
295 dfs[f] = DebugfsDir(p)
296 else:
297 raise Exception("%s is neither file nor directory" % (p))
298
299 log_level_dec()
300 log("DebugFS state", dfs)
301 log_level_dec()
302
303 return dfs
304
305class NetdevSim:
306 """
307 Class for netdevsim netdevice and its attributes.
308 """
309
310 def __init__(self):
311 self.dev = self._netdevsim_create()
312 devs.append(self)
313
Jakub Kicinski752d7b42017-12-27 18:39:11 -0800314 self.ns = ""
315
Jakub Kicinski417ec262017-12-01 15:09:00 -0800316 self.dfs_dir = '/sys/kernel/debug/netdevsim/%s' % (self.dev['ifname'])
317 self.dfs_refresh()
318
319 def __getitem__(self, key):
320 return self.dev[key]
321
322 def _netdevsim_create(self):
323 _, old = ip("link show")
324 ip("link add sim%d type netdevsim")
325 _, new = ip("link show")
326
327 for dev in new:
328 f = filter(lambda x: x["ifname"] == dev["ifname"], old)
329 if len(list(f)) == 0:
330 return dev
331
332 raise Exception("failed to create netdevsim device")
333
334 def remove(self):
335 devs.remove(self)
Jakub Kicinski752d7b42017-12-27 18:39:11 -0800336 ip("link del dev %s" % (self.dev["ifname"]), ns=self.ns)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800337
338 def dfs_refresh(self):
339 self.dfs = DebugfsDir(self.dfs_dir)
340 return self.dfs
341
342 def dfs_num_bound_progs(self):
343 path = os.path.join(self.dfs_dir, "bpf_bound_progs")
344 _, progs = cmd('ls %s' % (path))
345 return len(progs.split())
346
347 def dfs_get_bound_progs(self, expected):
348 progs = DebugfsDir(os.path.join(self.dfs_dir, "bpf_bound_progs"))
349 if expected is not None:
350 if len(progs) != expected:
351 fail(True, "%d BPF programs bound, expected %d" %
352 (len(progs), expected))
353 return progs
354
355 def wait_for_flush(self, bound=0, total=0, n_retry=20):
356 for i in range(n_retry):
357 nbound = self.dfs_num_bound_progs()
358 nprogs = len(bpftool_prog_list())
359 if nbound == bound and nprogs == total:
360 return
361 time.sleep(0.05)
362 raise Exception("Time out waiting for program counts to stabilize want %d/%d, have %d bound, %d loaded" % (bound, total, nbound, nprogs))
363
Jakub Kicinski752d7b42017-12-27 18:39:11 -0800364 def set_ns(self, ns):
365 name = "1" if ns == "" else ns
366 ip("link set dev %s netns %s" % (self.dev["ifname"], name), ns=self.ns)
367 self.ns = ns
368
Jakub Kicinski417ec262017-12-01 15:09:00 -0800369 def set_mtu(self, mtu, fail=True):
370 return ip("link set dev %s mtu %d" % (self.dev["ifname"], mtu),
371 fail=fail)
372
Quentin Monnet9045bdc2018-01-23 11:22:55 -0800373 def set_xdp(self, bpf, mode, force=False, JSON=True, verbose=False,
Quentin Monnetcaf95222018-01-23 11:22:53 -0800374 fail=True, include_stderr=False):
Quentin Monnet9045bdc2018-01-23 11:22:55 -0800375 if verbose:
376 bpf += " verbose"
Jakub Kicinski417ec262017-12-01 15:09:00 -0800377 return ip("link set dev %s xdp%s %s" % (self.dev["ifname"], mode, bpf),
Quentin Monnetcaf95222018-01-23 11:22:53 -0800378 force=force, JSON=JSON,
379 fail=fail, include_stderr=include_stderr)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800380
Quentin Monnetcaf95222018-01-23 11:22:53 -0800381 def unset_xdp(self, mode, force=False, JSON=True,
382 fail=True, include_stderr=False):
Jakub Kicinski417ec262017-12-01 15:09:00 -0800383 return ip("link set dev %s xdp%s off" % (self.dev["ifname"], mode),
Quentin Monnetcaf95222018-01-23 11:22:53 -0800384 force=force, JSON=JSON,
385 fail=fail, include_stderr=include_stderr)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800386
387 def ip_link_show(self, xdp):
388 _, link = ip("link show dev %s" % (self['ifname']))
389 if len(link) > 1:
390 raise Exception("Multiple objects on ip link show")
391 if len(link) < 1:
392 return {}
393 fail(xdp != "xdp" in link,
394 "XDP program not reporting in iplink (reported %s, expected %s)" %
395 ("xdp" in link, xdp))
396 return link[0]
397
398 def tc_add_ingress(self):
399 tc("qdisc add dev %s ingress" % (self['ifname']))
400
401 def tc_del_ingress(self):
402 tc("qdisc del dev %s ingress" % (self['ifname']))
403
404 def tc_flush_filters(self, bound=0, total=0):
405 self.tc_del_ingress()
406 self.tc_add_ingress()
407 self.wait_for_flush(bound=bound, total=total)
408
409 def tc_show_ingress(self, expected=None):
410 # No JSON support, oh well...
411 flags = ["skip_sw", "skip_hw", "in_hw"]
412 named = ["protocol", "pref", "chain", "handle", "id", "tag"]
413
414 args = "-s filter show dev %s ingress" % (self['ifname'])
415 _, out = tc(args, JSON=False)
416
417 filters = []
418 lines = out.split('\n')
419 for line in lines:
420 words = line.split()
421 if "handle" not in words:
422 continue
423 fltr = {}
424 for flag in flags:
425 fltr[flag] = flag in words
426 for name in named:
427 try:
428 idx = words.index(name)
429 fltr[name] = words[idx + 1]
430 except ValueError:
431 pass
432 filters.append(fltr)
433
434 if expected is not None:
435 fail(len(filters) != expected,
436 "%d ingress filters loaded, expected %d" %
437 (len(filters), expected))
438 return filters
439
Jakub Kicinski6d2d58f2018-01-23 11:22:56 -0800440 def cls_filter_op(self, op, qdisc="ingress", prio=None, handle=None,
Jakub Kicinskibaf6a072018-01-25 14:00:53 -0800441 chain=None, cls="", params="",
Jakub Kicinski6d2d58f2018-01-23 11:22:56 -0800442 fail=True, include_stderr=False):
443 spec = ""
444 if prio is not None:
445 spec += " prio %d" % (prio)
446 if handle:
447 spec += " handle %s" % (handle)
Jakub Kicinskibaf6a072018-01-25 14:00:53 -0800448 if chain is not None:
449 spec += " chain %d" % (chain)
Jakub Kicinski6d2d58f2018-01-23 11:22:56 -0800450
451 return tc("filter {op} dev {dev} {qdisc} {spec} {cls} {params}"\
452 .format(op=op, dev=self['ifname'], qdisc=qdisc, spec=spec,
453 cls=cls, params=params),
454 fail=fail, include_stderr=include_stderr)
455
456 def cls_bpf_add_filter(self, bpf, op="add", prio=None, handle=None,
Jakub Kicinskibaf6a072018-01-25 14:00:53 -0800457 chain=None, da=False, verbose=False,
Jakub Kicinski6d2d58f2018-01-23 11:22:56 -0800458 skip_sw=False, skip_hw=False,
459 fail=True, include_stderr=False):
460 cls = "bpf " + bpf
461
Jakub Kicinski417ec262017-12-01 15:09:00 -0800462 params = ""
463 if da:
464 params += " da"
Quentin Monnet9045bdc2018-01-23 11:22:55 -0800465 if verbose:
466 params += " verbose"
Jakub Kicinski417ec262017-12-01 15:09:00 -0800467 if skip_sw:
468 params += " skip_sw"
469 if skip_hw:
470 params += " skip_hw"
Jakub Kicinski6d2d58f2018-01-23 11:22:56 -0800471
472 return self.cls_filter_op(op=op, prio=prio, handle=handle, cls=cls,
Jakub Kicinskibaf6a072018-01-25 14:00:53 -0800473 chain=chain, params=params,
Jakub Kicinski6d2d58f2018-01-23 11:22:56 -0800474 fail=fail, include_stderr=include_stderr)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800475
476 def set_ethtool_tc_offloads(self, enable, fail=True):
477 args = "hw-tc-offload %s" % ("on" if enable else "off")
478 return ethtool(self, "-K", args, fail=fail)
479
480################################################################################
481def clean_up():
Jakub Kicinski7fedbb72018-01-17 19:13:31 -0800482 global files, netns, devs
483
Jakub Kicinski417ec262017-12-01 15:09:00 -0800484 for dev in devs:
485 dev.remove()
486 for f in files:
487 cmd("rm -f %s" % (f))
Jakub Kicinski752d7b42017-12-27 18:39:11 -0800488 for ns in netns:
489 cmd("ip netns delete %s" % (ns))
Jakub Kicinski7fedbb72018-01-17 19:13:31 -0800490 files = []
491 netns = []
Jakub Kicinski417ec262017-12-01 15:09:00 -0800492
493def pin_prog(file_name, idx=0):
494 progs = bpftool_prog_list(expected=(idx + 1))
495 prog = progs[idx]
496 bpftool("prog pin id %d %s" % (prog["id"], file_name))
497 files.append(file_name)
498
499 return file_name, bpf_pinned(file_name)
500
Jakub Kicinski7fedbb72018-01-17 19:13:31 -0800501def pin_map(file_name, idx=0, expected=1):
502 maps = bpftool_map_list(expected=expected)
503 m = maps[idx]
504 bpftool("map pin id %d %s" % (m["id"], file_name))
505 files.append(file_name)
506
507 return file_name, bpf_pinned(file_name)
508
509def check_dev_info_removed(prog_file=None, map_file=None):
510 bpftool_prog_list(expected=0)
511 ret, err = bpftool("prog show pin %s" % (prog_file), fail=False)
512 fail(ret == 0, "Showing prog with removed device did not fail")
513 fail(err["error"].find("No such device") == -1,
514 "Showing prog with removed device expected ENODEV, error is %s" %
515 (err["error"]))
516
517 bpftool_map_list(expected=0)
518 ret, err = bpftool("map show pin %s" % (map_file), fail=False)
519 fail(ret == 0, "Showing map with removed device did not fail")
520 fail(err["error"].find("No such device") == -1,
521 "Showing map with removed device expected ENODEV, error is %s" %
522 (err["error"]))
523
524def check_dev_info(other_ns, ns, prog_file=None, map_file=None, removed=False):
525 progs = bpftool_prog_list(expected=1, ns=ns)
Jakub Kicinski752d7b42017-12-27 18:39:11 -0800526 prog = progs[0]
527
528 fail("dev" not in prog.keys(), "Device parameters not reported")
529 dev = prog["dev"]
530 fail("ifindex" not in dev.keys(), "Device parameters not reported")
531 fail("ns_dev" not in dev.keys(), "Device parameters not reported")
532 fail("ns_inode" not in dev.keys(), "Device parameters not reported")
533
Jakub Kicinski7fedbb72018-01-17 19:13:31 -0800534 if not other_ns:
Jakub Kicinski752d7b42017-12-27 18:39:11 -0800535 fail("ifname" not in dev.keys(), "Ifname not reported")
536 fail(dev["ifname"] != sim["ifname"],
537 "Ifname incorrect %s vs %s" % (dev["ifname"], sim["ifname"]))
538 else:
539 fail("ifname" in dev.keys(), "Ifname is reported for other ns")
Jakub Kicinski7fedbb72018-01-17 19:13:31 -0800540
541 maps = bpftool_map_list(expected=2, ns=ns)
542 for m in maps:
543 fail("dev" not in m.keys(), "Device parameters not reported")
544 fail(dev != m["dev"], "Map's device different than program's")
Jakub Kicinski752d7b42017-12-27 18:39:11 -0800545
Quentin Monnetcaf95222018-01-23 11:22:53 -0800546def check_extack(output, reference, args):
547 if skip_extack:
548 return
549 lines = output.split("\n")
550 comp = len(lines) >= 2 and lines[1] == reference
551 fail(not comp, "Missing or incorrect netlink extack message")
552
553def check_extack_nsim(output, reference, args):
554 check_extack(output, "Error: netdevsim: " + reference, args)
555
Jakub Kicinski2fb89a32018-01-25 14:00:52 -0800556def check_no_extack(res, needle):
557 fail((res[1] + res[2]).count(needle) or (res[1] + res[2]).count("Warning:"),
558 "Found '%s' in command output, leaky extack?" % (needle))
559
Quentin Monnet9045bdc2018-01-23 11:22:55 -0800560def check_verifier_log(output, reference):
561 lines = output.split("\n")
562 for l in reversed(lines):
563 if l == reference:
564 return
565 fail(True, "Missing or incorrect message from netdevsim in verifier log")
566
Jakub Kicinski2fb89a32018-01-25 14:00:52 -0800567def test_spurios_extack(sim, obj, skip_hw, needle):
568 res = sim.cls_bpf_add_filter(obj, prio=1, handle=1, skip_hw=skip_hw,
569 include_stderr=True)
570 check_no_extack(res, needle)
571 res = sim.cls_bpf_add_filter(obj, op="replace", prio=1, handle=1,
572 skip_hw=skip_hw, include_stderr=True)
573 check_no_extack(res, needle)
574 res = sim.cls_filter_op(op="delete", prio=1, handle=1, cls="bpf",
575 include_stderr=True)
576 check_no_extack(res, needle)
577
578
Jakub Kicinski417ec262017-12-01 15:09:00 -0800579# Parse command line
580parser = argparse.ArgumentParser()
581parser.add_argument("--log", help="output verbose log to given file")
582args = parser.parse_args()
583if args.log:
584 logfile = open(args.log, 'w+')
585 logfile.write("# -*-Org-*-")
586
587log("Prepare...", "", level=1)
588log_level_inc()
589
590# Check permissions
591skip(os.getuid() != 0, "test must be run as root")
592
593# Check tools
594ret, progs = bpftool("prog", fail=False)
595skip(ret != 0, "bpftool not installed")
Jakub Kicinski47cf52a2018-06-14 11:06:56 -0700596base_progs = progs
597_, base_maps = bpftool("map")
Jakub Kicinski417ec262017-12-01 15:09:00 -0800598
599# Check netdevsim
600ret, out = cmd("modprobe netdevsim", fail=False)
601skip(ret != 0, "netdevsim module could not be loaded")
602
603# Check debugfs
604_, out = cmd("mount")
605if out.find("/sys/kernel/debug type debugfs") == -1:
606 cmd("mount -t debugfs none /sys/kernel/debug")
607
608# Check samples are compiled
Jakub Kicinski7fedbb72018-01-17 19:13:31 -0800609samples = ["sample_ret0.o", "sample_map_ret0.o"]
Jakub Kicinski417ec262017-12-01 15:09:00 -0800610for s in samples:
611 ret, out = cmd("ls %s/%s" % (bpf_test_dir, s), fail=False)
612 skip(ret != 0, "sample %s/%s not found, please compile it" %
613 (bpf_test_dir, s))
614
Quentin Monnetcaf95222018-01-23 11:22:53 -0800615# Check if iproute2 is built with libmnl (needed by extack support)
616_, _, err = cmd("tc qdisc delete dev lo handle 0",
617 fail=False, include_stderr=True)
618if err.find("Error: Failed to find qdisc with specified handle.") == -1:
619 print("Warning: no extack message in iproute2 output, libmnl missing?")
620 log("Warning: no extack message in iproute2 output, libmnl missing?", "")
621 skip_extack = True
622
Jakub Kicinski752d7b42017-12-27 18:39:11 -0800623# Check if net namespaces seem to work
624ns = mknetns()
625skip(ns is None, "Could not create a net namespace")
626cmd("ip netns delete %s" % (ns))
627netns = []
628
Jakub Kicinski417ec262017-12-01 15:09:00 -0800629try:
630 obj = bpf_obj("sample_ret0.o")
631 bytecode = bpf_bytecode("1,6 0 0 4294967295,")
632
633 start_test("Test destruction of generic XDP...")
634 sim = NetdevSim()
635 sim.set_xdp(obj, "generic")
636 sim.remove()
637 bpftool_prog_list_wait(expected=0)
638
639 sim = NetdevSim()
640 sim.tc_add_ingress()
641
642 start_test("Test TC non-offloaded...")
643 ret, _ = sim.cls_bpf_add_filter(obj, skip_hw=True, fail=False)
644 fail(ret != 0, "Software TC filter did not load")
645
646 start_test("Test TC non-offloaded isn't getting bound...")
647 ret, _ = sim.cls_bpf_add_filter(obj, fail=False)
648 fail(ret != 0, "Software TC filter did not load")
649 sim.dfs_get_bound_progs(expected=0)
650
651 sim.tc_flush_filters()
652
653 start_test("Test TC offloads are off by default...")
Quentin Monnetcaf95222018-01-23 11:22:53 -0800654 ret, _, err = sim.cls_bpf_add_filter(obj, skip_sw=True,
655 fail=False, include_stderr=True)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800656 fail(ret == 0, "TC filter loaded without enabling TC offloads")
Quentin Monnetcaf95222018-01-23 11:22:53 -0800657 check_extack(err, "Error: TC offload is disabled on net device.", args)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800658 sim.wait_for_flush()
659
660 sim.set_ethtool_tc_offloads(True)
661 sim.dfs["bpf_tc_non_bound_accept"] = "Y"
662
663 start_test("Test TC offload by default...")
664 ret, _ = sim.cls_bpf_add_filter(obj, fail=False)
665 fail(ret != 0, "Software TC filter did not load")
666 sim.dfs_get_bound_progs(expected=0)
667 ingress = sim.tc_show_ingress(expected=1)
668 fltr = ingress[0]
669 fail(not fltr["in_hw"], "Filter not offloaded by default")
670
671 sim.tc_flush_filters()
672
673 start_test("Test TC cBPF bytcode tries offload by default...")
674 ret, _ = sim.cls_bpf_add_filter(bytecode, fail=False)
675 fail(ret != 0, "Software TC filter did not load")
676 sim.dfs_get_bound_progs(expected=0)
677 ingress = sim.tc_show_ingress(expected=1)
678 fltr = ingress[0]
679 fail(not fltr["in_hw"], "Bytecode not offloaded by default")
680
681 sim.tc_flush_filters()
682 sim.dfs["bpf_tc_non_bound_accept"] = "N"
683
684 start_test("Test TC cBPF unbound bytecode doesn't offload...")
Quentin Monnetcaf95222018-01-23 11:22:53 -0800685 ret, _, err = sim.cls_bpf_add_filter(bytecode, skip_sw=True,
686 fail=False, include_stderr=True)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800687 fail(ret == 0, "TC bytecode loaded for offload")
Quentin Monnetcaf95222018-01-23 11:22:53 -0800688 check_extack_nsim(err, "netdevsim configured to reject unbound programs.",
689 args)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800690 sim.wait_for_flush()
691
Jakub Kicinskibaf6a072018-01-25 14:00:53 -0800692 start_test("Test non-0 chain offload...")
693 ret, _, err = sim.cls_bpf_add_filter(obj, chain=1, prio=1, handle=1,
694 skip_sw=True,
695 fail=False, include_stderr=True)
696 fail(ret == 0, "Offloaded a filter to chain other than 0")
697 check_extack(err, "Error: Driver supports only offload of chain 0.", args)
698 sim.tc_flush_filters()
699
Jakub Kicinski6d2d58f2018-01-23 11:22:56 -0800700 start_test("Test TC replace...")
701 sim.cls_bpf_add_filter(obj, prio=1, handle=1)
702 sim.cls_bpf_add_filter(obj, op="replace", prio=1, handle=1)
703 sim.cls_filter_op(op="delete", prio=1, handle=1, cls="bpf")
704
705 sim.cls_bpf_add_filter(obj, prio=1, handle=1, skip_sw=True)
706 sim.cls_bpf_add_filter(obj, op="replace", prio=1, handle=1, skip_sw=True)
707 sim.cls_filter_op(op="delete", prio=1, handle=1, cls="bpf")
708
709 sim.cls_bpf_add_filter(obj, prio=1, handle=1, skip_hw=True)
710 sim.cls_bpf_add_filter(obj, op="replace", prio=1, handle=1, skip_hw=True)
711 sim.cls_filter_op(op="delete", prio=1, handle=1, cls="bpf")
712
713 start_test("Test TC replace bad flags...")
714 for i in range(3):
715 for j in range(3):
716 ret, _ = sim.cls_bpf_add_filter(obj, op="replace", prio=1, handle=1,
717 skip_sw=(j == 1), skip_hw=(j == 2),
718 fail=False)
719 fail(bool(ret) != bool(j),
720 "Software TC incorrect load in replace test, iteration %d" %
721 (j))
722 sim.cls_filter_op(op="delete", prio=1, handle=1, cls="bpf")
723
Jakub Kicinski2fb89a32018-01-25 14:00:52 -0800724 start_test("Test spurious extack from the driver...")
725 test_spurios_extack(sim, obj, False, "netdevsim")
726 test_spurios_extack(sim, obj, True, "netdevsim")
727
728 sim.set_ethtool_tc_offloads(False)
729
730 test_spurios_extack(sim, obj, False, "TC offload is disabled")
731 test_spurios_extack(sim, obj, True, "TC offload is disabled")
732
733 sim.set_ethtool_tc_offloads(True)
734
Jakub Kicinski6d2d58f2018-01-23 11:22:56 -0800735 sim.tc_flush_filters()
736
Jakub Kicinski417ec262017-12-01 15:09:00 -0800737 start_test("Test TC offloads work...")
Quentin Monnet9045bdc2018-01-23 11:22:55 -0800738 ret, _, err = sim.cls_bpf_add_filter(obj, verbose=True, skip_sw=True,
739 fail=False, include_stderr=True)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800740 fail(ret != 0, "TC filter did not load with TC offloads enabled")
Quentin Monnet9045bdc2018-01-23 11:22:55 -0800741 check_verifier_log(err, "[netdevsim] Hello from netdevsim!")
Jakub Kicinski417ec262017-12-01 15:09:00 -0800742
743 start_test("Test TC offload basics...")
744 dfs = sim.dfs_get_bound_progs(expected=1)
745 progs = bpftool_prog_list(expected=1)
746 ingress = sim.tc_show_ingress(expected=1)
747
748 dprog = dfs[0]
749 prog = progs[0]
750 fltr = ingress[0]
751 fail(fltr["skip_hw"], "TC does reports 'skip_hw' on offloaded filter")
752 fail(not fltr["in_hw"], "TC does not report 'in_hw' for offloaded filter")
753 fail(not fltr["skip_sw"], "TC does not report 'skip_sw' back")
754
755 start_test("Test TC offload is device-bound...")
756 fail(str(prog["id"]) != fltr["id"], "Program IDs don't match")
757 fail(prog["tag"] != fltr["tag"], "Program tags don't match")
758 fail(fltr["id"] != dprog["id"], "Program IDs don't match")
759 fail(dprog["state"] != "xlated", "Offloaded program state not translated")
760 fail(dprog["loaded"] != "Y", "Offloaded program is not loaded")
761
762 start_test("Test disabling TC offloads is rejected while filters installed...")
763 ret, _ = sim.set_ethtool_tc_offloads(False, fail=False)
764 fail(ret == 0, "Driver should refuse to disable TC offloads with filters installed...")
765
766 start_test("Test qdisc removal frees things...")
767 sim.tc_flush_filters()
768 sim.tc_show_ingress(expected=0)
769
770 start_test("Test disabling TC offloads is OK without filters...")
771 ret, _ = sim.set_ethtool_tc_offloads(False, fail=False)
772 fail(ret != 0,
773 "Driver refused to disable TC offloads without filters installed...")
774
775 sim.set_ethtool_tc_offloads(True)
776
777 start_test("Test destroying device gets rid of TC filters...")
778 sim.cls_bpf_add_filter(obj, skip_sw=True)
779 sim.remove()
780 bpftool_prog_list_wait(expected=0)
781
782 sim = NetdevSim()
783 sim.set_ethtool_tc_offloads(True)
784
785 start_test("Test destroying device gets rid of XDP...")
786 sim.set_xdp(obj, "offload")
787 sim.remove()
788 bpftool_prog_list_wait(expected=0)
789
790 sim = NetdevSim()
791 sim.set_ethtool_tc_offloads(True)
792
793 start_test("Test XDP prog reporting...")
794 sim.set_xdp(obj, "drv")
795 ipl = sim.ip_link_show(xdp=True)
796 progs = bpftool_prog_list(expected=1)
797 fail(ipl["xdp"]["prog"]["id"] != progs[0]["id"],
798 "Loaded program has wrong ID")
799
800 start_test("Test XDP prog replace without force...")
801 ret, _ = sim.set_xdp(obj, "drv", fail=False)
802 fail(ret == 0, "Replaced XDP program without -force")
803 sim.wait_for_flush(total=1)
804
805 start_test("Test XDP prog replace with force...")
806 ret, _ = sim.set_xdp(obj, "drv", force=True, fail=False)
807 fail(ret != 0, "Could not replace XDP program with -force")
808 bpftool_prog_list_wait(expected=1)
809 ipl = sim.ip_link_show(xdp=True)
810 progs = bpftool_prog_list(expected=1)
811 fail(ipl["xdp"]["prog"]["id"] != progs[0]["id"],
812 "Loaded program has wrong ID")
Jakub Kicinski752d7b42017-12-27 18:39:11 -0800813 fail("dev" in progs[0].keys(),
814 "Device parameters reported for non-offloaded program")
Jakub Kicinski417ec262017-12-01 15:09:00 -0800815
816 start_test("Test XDP prog replace with bad flags...")
Quentin Monnetcaf95222018-01-23 11:22:53 -0800817 ret, _, err = sim.set_xdp(obj, "offload", force=True,
818 fail=False, include_stderr=True)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800819 fail(ret == 0, "Replaced XDP program with a program in different mode")
Quentin Monnetcaf95222018-01-23 11:22:53 -0800820 check_extack_nsim(err, "program loaded with different flags.", args)
821 ret, _, err = sim.set_xdp(obj, "", force=True,
822 fail=False, include_stderr=True)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800823 fail(ret == 0, "Replaced XDP program with a program in different mode")
Quentin Monnetcaf95222018-01-23 11:22:53 -0800824 check_extack_nsim(err, "program loaded with different flags.", args)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800825
826 start_test("Test XDP prog remove with bad flags...")
Quentin Monnetcaf95222018-01-23 11:22:53 -0800827 ret, _, err = sim.unset_xdp("offload", force=True,
828 fail=False, include_stderr=True)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800829 fail(ret == 0, "Removed program with a bad mode mode")
Quentin Monnetcaf95222018-01-23 11:22:53 -0800830 check_extack_nsim(err, "program loaded with different flags.", args)
831 ret, _, err = sim.unset_xdp("", force=True,
832 fail=False, include_stderr=True)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800833 fail(ret == 0, "Removed program with a bad mode mode")
Quentin Monnetcaf95222018-01-23 11:22:53 -0800834 check_extack_nsim(err, "program loaded with different flags.", args)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800835
836 start_test("Test MTU restrictions...")
837 ret, _ = sim.set_mtu(9000, fail=False)
838 fail(ret == 0,
839 "Driver should refuse to increase MTU to 9000 with XDP loaded...")
840 sim.unset_xdp("drv")
841 bpftool_prog_list_wait(expected=0)
842 sim.set_mtu(9000)
Quentin Monnetcaf95222018-01-23 11:22:53 -0800843 ret, _, err = sim.set_xdp(obj, "drv", fail=False, include_stderr=True)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800844 fail(ret == 0, "Driver should refuse to load program with MTU of 9000...")
Quentin Monnetcaf95222018-01-23 11:22:53 -0800845 check_extack_nsim(err, "MTU too large w/ XDP enabled.", args)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800846 sim.set_mtu(1500)
847
848 sim.wait_for_flush()
849 start_test("Test XDP offload...")
Quentin Monnet9045bdc2018-01-23 11:22:55 -0800850 _, _, err = sim.set_xdp(obj, "offload", verbose=True, include_stderr=True)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800851 ipl = sim.ip_link_show(xdp=True)
852 link_xdp = ipl["xdp"]["prog"]
853 progs = bpftool_prog_list(expected=1)
854 prog = progs[0]
855 fail(link_xdp["id"] != prog["id"], "Loaded program has wrong ID")
Quentin Monnet9045bdc2018-01-23 11:22:55 -0800856 check_verifier_log(err, "[netdevsim] Hello from netdevsim!")
Jakub Kicinski417ec262017-12-01 15:09:00 -0800857
858 start_test("Test XDP offload is device bound...")
859 dfs = sim.dfs_get_bound_progs(expected=1)
860 dprog = dfs[0]
861
862 fail(prog["id"] != link_xdp["id"], "Program IDs don't match")
863 fail(prog["tag"] != link_xdp["tag"], "Program tags don't match")
864 fail(str(link_xdp["id"]) != dprog["id"], "Program IDs don't match")
865 fail(dprog["state"] != "xlated", "Offloaded program state not translated")
866 fail(dprog["loaded"] != "Y", "Offloaded program is not loaded")
867
868 start_test("Test removing XDP program many times...")
869 sim.unset_xdp("offload")
870 sim.unset_xdp("offload")
871 sim.unset_xdp("drv")
872 sim.unset_xdp("drv")
873 sim.unset_xdp("")
874 sim.unset_xdp("")
875 bpftool_prog_list_wait(expected=0)
876
877 start_test("Test attempt to use a program for a wrong device...")
878 sim2 = NetdevSim()
879 sim2.set_xdp(obj, "offload")
880 pin_file, pinned = pin_prog("/sys/fs/bpf/tmp")
881
Quentin Monnetcaf95222018-01-23 11:22:53 -0800882 ret, _, err = sim.set_xdp(pinned, "offload",
883 fail=False, include_stderr=True)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800884 fail(ret == 0, "Pinned program loaded for a different device accepted")
Quentin Monnetcaf95222018-01-23 11:22:53 -0800885 check_extack_nsim(err, "program bound to different dev.", args)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800886 sim2.remove()
Quentin Monnetcaf95222018-01-23 11:22:53 -0800887 ret, _, err = sim.set_xdp(pinned, "offload",
888 fail=False, include_stderr=True)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800889 fail(ret == 0, "Pinned program loaded for a removed device accepted")
Quentin Monnetcaf95222018-01-23 11:22:53 -0800890 check_extack_nsim(err, "xdpoffload of non-bound program.", args)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800891 rm(pin_file)
892 bpftool_prog_list_wait(expected=0)
893
894 start_test("Test mixing of TC and XDP...")
895 sim.tc_add_ingress()
896 sim.set_xdp(obj, "offload")
Quentin Monnetcaf95222018-01-23 11:22:53 -0800897 ret, _, err = sim.cls_bpf_add_filter(obj, skip_sw=True,
898 fail=False, include_stderr=True)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800899 fail(ret == 0, "Loading TC when XDP active should fail")
Quentin Monnetcaf95222018-01-23 11:22:53 -0800900 check_extack_nsim(err, "driver and netdev offload states mismatch.", args)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800901 sim.unset_xdp("offload")
902 sim.wait_for_flush()
903
904 sim.cls_bpf_add_filter(obj, skip_sw=True)
Quentin Monnetcaf95222018-01-23 11:22:53 -0800905 ret, _, err = sim.set_xdp(obj, "offload", fail=False, include_stderr=True)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800906 fail(ret == 0, "Loading XDP when TC active should fail")
Quentin Monnetcaf95222018-01-23 11:22:53 -0800907 check_extack_nsim(err, "TC program is already loaded.", args)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800908
909 start_test("Test binding TC from pinned...")
910 pin_file, pinned = pin_prog("/sys/fs/bpf/tmp")
911 sim.tc_flush_filters(bound=1, total=1)
912 sim.cls_bpf_add_filter(pinned, da=True, skip_sw=True)
913 sim.tc_flush_filters(bound=1, total=1)
914
915 start_test("Test binding XDP from pinned...")
916 sim.set_xdp(obj, "offload")
917 pin_file, pinned = pin_prog("/sys/fs/bpf/tmp2", idx=1)
918
919 sim.set_xdp(pinned, "offload", force=True)
920 sim.unset_xdp("offload")
921 sim.set_xdp(pinned, "offload", force=True)
922 sim.unset_xdp("offload")
923
924 start_test("Test offload of wrong type fails...")
925 ret, _ = sim.cls_bpf_add_filter(pinned, da=True, skip_sw=True, fail=False)
926 fail(ret == 0, "Managed to attach XDP program to TC")
927
928 start_test("Test asking for TC offload of two filters...")
929 sim.cls_bpf_add_filter(obj, da=True, skip_sw=True)
Quentin Monnetcaf95222018-01-23 11:22:53 -0800930 ret, _, err = sim.cls_bpf_add_filter(obj, da=True, skip_sw=True,
931 fail=False, include_stderr=True)
David S. Millerfba961a2017-12-22 11:16:31 -0500932 fail(ret == 0, "Managed to offload two TC filters at the same time")
Quentin Monnetcaf95222018-01-23 11:22:53 -0800933 check_extack_nsim(err, "driver and netdev offload states mismatch.", args)
Jakub Kicinski417ec262017-12-01 15:09:00 -0800934
935 sim.tc_flush_filters(bound=2, total=2)
936
937 start_test("Test if netdev removal waits for translation...")
938 delay_msec = 500
939 sim.dfs["bpf_bind_verifier_delay"] = delay_msec
940 start = time.time()
941 cmd_line = "tc filter add dev %s ingress bpf %s da skip_sw" % \
942 (sim['ifname'], obj)
943 tc_proc = cmd(cmd_line, background=True, fail=False)
944 # Wait for the verifier to start
945 while sim.dfs_num_bound_progs() <= 2:
946 pass
947 sim.remove()
948 end = time.time()
949 ret, _ = cmd_result(tc_proc, fail=False)
950 time_diff = end - start
951 log("Time", "start:\t%s\nend:\t%s\ndiff:\t%s" % (start, end, time_diff))
952
953 fail(ret == 0, "Managed to load TC filter on a unregistering device")
954 delay_sec = delay_msec * 0.001
955 fail(time_diff < delay_sec, "Removal process took %s, expected %s" %
956 (time_diff, delay_sec))
957
Jakub Kicinski752d7b42017-12-27 18:39:11 -0800958 # Remove all pinned files and reinstantiate the netdev
959 clean_up()
960 bpftool_prog_list_wait(expected=0)
961
962 sim = NetdevSim()
Jakub Kicinski7fedbb72018-01-17 19:13:31 -0800963 map_obj = bpf_obj("sample_map_ret0.o")
964 start_test("Test loading program with maps...")
965 sim.set_xdp(map_obj, "offload", JSON=False) # map fixup msg breaks JSON
Jakub Kicinski752d7b42017-12-27 18:39:11 -0800966
967 start_test("Test bpftool bound info reporting (own ns)...")
968 check_dev_info(False, "")
969
970 start_test("Test bpftool bound info reporting (other ns)...")
971 ns = mknetns()
972 sim.set_ns(ns)
973 check_dev_info(True, "")
974
975 start_test("Test bpftool bound info reporting (remote ns)...")
976 check_dev_info(False, ns)
977
978 start_test("Test bpftool bound info reporting (back to own ns)...")
979 sim.set_ns("")
980 check_dev_info(False, "")
981
Jakub Kicinski7fedbb72018-01-17 19:13:31 -0800982 prog_file, _ = pin_prog("/sys/fs/bpf/tmp_prog")
983 map_file, _ = pin_map("/sys/fs/bpf/tmp_map", idx=1, expected=2)
Jakub Kicinski752d7b42017-12-27 18:39:11 -0800984 sim.remove()
985
986 start_test("Test bpftool bound info reporting (removed dev)...")
Jakub Kicinski7fedbb72018-01-17 19:13:31 -0800987 check_dev_info_removed(prog_file=prog_file, map_file=map_file)
988
989 # Remove all pinned files and reinstantiate the netdev
990 clean_up()
991 bpftool_prog_list_wait(expected=0)
992
993 sim = NetdevSim()
994
995 start_test("Test map update (no flags)...")
996 sim.set_xdp(map_obj, "offload", JSON=False) # map fixup msg breaks JSON
997 maps = bpftool_map_list(expected=2)
998 array = maps[0] if maps[0]["type"] == "array" else maps[1]
999 htab = maps[0] if maps[0]["type"] == "hash" else maps[1]
1000 for m in maps:
1001 for i in range(2):
1002 bpftool("map update id %d key %s value %s" %
1003 (m["id"], int2str("I", i), int2str("Q", i * 3)))
1004
1005 for m in maps:
1006 ret, _ = bpftool("map update id %d key %s value %s" %
1007 (m["id"], int2str("I", 3), int2str("Q", 3 * 3)),
1008 fail=False)
1009 fail(ret == 0, "added too many entries")
1010
1011 start_test("Test map update (exists)...")
1012 for m in maps:
1013 for i in range(2):
1014 bpftool("map update id %d key %s value %s exist" %
1015 (m["id"], int2str("I", i), int2str("Q", i * 3)))
1016
1017 for m in maps:
1018 ret, err = bpftool("map update id %d key %s value %s exist" %
1019 (m["id"], int2str("I", 3), int2str("Q", 3 * 3)),
1020 fail=False)
1021 fail(ret == 0, "updated non-existing key")
1022 fail(err["error"].find("No such file or directory") == -1,
1023 "expected ENOENT, error is '%s'" % (err["error"]))
1024
1025 start_test("Test map update (noexist)...")
1026 for m in maps:
1027 for i in range(2):
1028 ret, err = bpftool("map update id %d key %s value %s noexist" %
1029 (m["id"], int2str("I", i), int2str("Q", i * 3)),
1030 fail=False)
1031 fail(ret == 0, "updated existing key")
1032 fail(err["error"].find("File exists") == -1,
1033 "expected EEXIST, error is '%s'" % (err["error"]))
1034
1035 start_test("Test map dump...")
1036 for m in maps:
1037 _, entries = bpftool("map dump id %d" % (m["id"]))
1038 for i in range(2):
1039 key = str2int(entries[i]["key"])
1040 fail(key != i, "expected key %d, got %d" % (key, i))
1041 val = str2int(entries[i]["value"])
1042 fail(val != i * 3, "expected value %d, got %d" % (val, i * 3))
1043
1044 start_test("Test map getnext...")
1045 for m in maps:
1046 _, entry = bpftool("map getnext id %d" % (m["id"]))
1047 key = str2int(entry["next_key"])
1048 fail(key != 0, "next key %d, expected %d" % (key, 0))
1049 _, entry = bpftool("map getnext id %d key %s" %
1050 (m["id"], int2str("I", 0)))
1051 key = str2int(entry["next_key"])
1052 fail(key != 1, "next key %d, expected %d" % (key, 1))
1053 ret, err = bpftool("map getnext id %d key %s" %
1054 (m["id"], int2str("I", 1)), fail=False)
1055 fail(ret == 0, "got next key past the end of map")
1056 fail(err["error"].find("No such file or directory") == -1,
1057 "expected ENOENT, error is '%s'" % (err["error"]))
1058
1059 start_test("Test map delete (htab)...")
1060 for i in range(2):
1061 bpftool("map delete id %d key %s" % (htab["id"], int2str("I", i)))
1062
1063 start_test("Test map delete (array)...")
1064 for i in range(2):
1065 ret, err = bpftool("map delete id %d key %s" %
1066 (htab["id"], int2str("I", i)), fail=False)
1067 fail(ret == 0, "removed entry from an array")
1068 fail(err["error"].find("No such file or directory") == -1,
1069 "expected ENOENT, error is '%s'" % (err["error"]))
1070
1071 start_test("Test map remove...")
1072 sim.unset_xdp("offload")
1073 bpftool_map_list_wait(expected=0)
1074 sim.remove()
1075
1076 sim = NetdevSim()
1077 sim.set_xdp(map_obj, "offload", JSON=False) # map fixup msg breaks JSON
1078 sim.remove()
1079 bpftool_map_list_wait(expected=0)
1080
1081 start_test("Test map creation fail path...")
1082 sim = NetdevSim()
1083 sim.dfs["bpf_map_accept"] = "N"
1084 ret, _ = sim.set_xdp(map_obj, "offload", JSON=False, fail=False)
1085 fail(ret == 0,
1086 "netdevsim didn't refuse to create a map with offload disabled")
Jakub Kicinski752d7b42017-12-27 18:39:11 -08001087
Jakub Kicinski417ec262017-12-01 15:09:00 -08001088 print("%s: OK" % (os.path.basename(__file__)))
1089
1090finally:
1091 log("Clean up...", "", level=1)
1092 log_level_inc()
1093 clean_up()