]> git.ipfire.org Git - thirdparty/kernel/stable.git/blob - tools/testing/selftests/net/openvswitch/ovs-dpctl.py
Merge tag 'kvm-x86-docs-6.7' of https://github.com/kvm-x86/linux into HEAD
[thirdparty/kernel/stable.git] / tools / testing / selftests / net / openvswitch / ovs-dpctl.py
1 #!/usr/bin/env python3
2 # SPDX-License-Identifier: GPL-2.0
3
4 # Controls the openvswitch module. Part of the kselftest suite, but
5 # can be used for some diagnostic purpose as well.
6
7 import argparse
8 import errno
9 import ipaddress
10 import logging
11 import multiprocessing
12 import re
13 import struct
14 import sys
15 import time
16 import types
17 import uuid
18
19 try:
20 from pyroute2 import NDB
21
22 from pyroute2.netlink import NLA_F_NESTED
23 from pyroute2.netlink import NLM_F_ACK
24 from pyroute2.netlink import NLM_F_DUMP
25 from pyroute2.netlink import NLM_F_REQUEST
26 from pyroute2.netlink import genlmsg
27 from pyroute2.netlink import nla
28 from pyroute2.netlink import nlmsg_atoms
29 from pyroute2.netlink.exceptions import NetlinkError
30 from pyroute2.netlink.generic import GenericNetlinkSocket
31 import pyroute2
32
33 except ModuleNotFoundError:
34 print("Need to install the python pyroute2 package >= 0.6.")
35 sys.exit(0)
36
37
38 OVS_DATAPATH_FAMILY = "ovs_datapath"
39 OVS_VPORT_FAMILY = "ovs_vport"
40 OVS_FLOW_FAMILY = "ovs_flow"
41 OVS_PACKET_FAMILY = "ovs_packet"
42 OVS_METER_FAMILY = "ovs_meter"
43 OVS_CT_LIMIT_FAMILY = "ovs_ct_limit"
44
45 OVS_DATAPATH_VERSION = 2
46 OVS_DP_CMD_NEW = 1
47 OVS_DP_CMD_DEL = 2
48 OVS_DP_CMD_GET = 3
49 OVS_DP_CMD_SET = 4
50
51 OVS_VPORT_CMD_NEW = 1
52 OVS_VPORT_CMD_DEL = 2
53 OVS_VPORT_CMD_GET = 3
54 OVS_VPORT_CMD_SET = 4
55
56 OVS_FLOW_CMD_NEW = 1
57 OVS_FLOW_CMD_DEL = 2
58 OVS_FLOW_CMD_GET = 3
59 OVS_FLOW_CMD_SET = 4
60
61
62 def macstr(mac):
63 outstr = ":".join(["%02X" % i for i in mac])
64 return outstr
65
66
67 def strcspn(str1, str2):
68 tot = 0
69 for char in str1:
70 if str2.find(char) != -1:
71 return tot
72 tot += 1
73 return tot
74
75
76 def strspn(str1, str2):
77 tot = 0
78 for char in str1:
79 if str2.find(char) == -1:
80 return tot
81 tot += 1
82 return tot
83
84
85 def intparse(statestr, defmask="0xffffffff"):
86 totalparse = strspn(statestr, "0123456789abcdefABCDEFx/")
87 # scan until "/"
88 count = strspn(statestr, "x0123456789abcdefABCDEF")
89
90 firstnum = statestr[:count]
91 if firstnum[-1] == "/":
92 firstnum = firstnum[:-1]
93 k = int(firstnum, 0)
94
95 m = None
96 if defmask is not None:
97 secondnum = defmask
98 if statestr[count] == "/":
99 secondnum = statestr[count + 1 :] # this is wrong...
100 m = int(secondnum, 0)
101
102 return statestr[totalparse + 1 :], k, m
103
104
105 def parse_flags(flag_str, flag_vals):
106 bitResult = 0
107 maskResult = 0
108
109 if len(flag_str) == 0:
110 return flag_str, bitResult, maskResult
111
112 if flag_str[0].isdigit():
113 idx = 0
114 while flag_str[idx].isdigit() or flag_str[idx] == "x":
115 idx += 1
116 digits = flag_str[:idx]
117 flag_str = flag_str[idx:]
118
119 bitResult = int(digits, 0)
120 maskResult = int(digits, 0)
121
122 while len(flag_str) > 0 and (flag_str[0] == "+" or flag_str[0] == "-"):
123 if flag_str[0] == "+":
124 setFlag = True
125 elif flag_str[0] == "-":
126 setFlag = False
127
128 flag_str = flag_str[1:]
129
130 flag_len = 0
131 while (
132 flag_str[flag_len] != "+"
133 and flag_str[flag_len] != "-"
134 and flag_str[flag_len] != ","
135 and flag_str[flag_len] != ")"
136 ):
137 flag_len += 1
138
139 flag = flag_str[0:flag_len]
140
141 if flag in flag_vals:
142 if maskResult & flag_vals[flag]:
143 raise KeyError(
144 "Flag %s set once, cannot be set in multiples" % flag
145 )
146
147 if setFlag:
148 bitResult |= flag_vals[flag]
149
150 maskResult |= flag_vals[flag]
151 else:
152 raise KeyError("Missing flag value: %s" % flag)
153
154 flag_str = flag_str[flag_len:]
155
156 return flag_str, bitResult, maskResult
157
158
159 def parse_ct_state(statestr):
160 ct_flags = {
161 "new": 1 << 0,
162 "est": 1 << 1,
163 "rel": 1 << 2,
164 "rpl": 1 << 3,
165 "inv": 1 << 4,
166 "trk": 1 << 5,
167 "snat": 1 << 6,
168 "dnat": 1 << 7,
169 }
170
171 return parse_flags(statestr, ct_flags)
172
173
174 def convert_mac(data):
175 def to_bytes(mac):
176 mac_split = mac.split(":")
177 ret = bytearray([int(i, 16) for i in mac_split])
178 return bytes(ret)
179
180 mac_str, _, mask_str = data.partition('/')
181
182 if not mac_str:
183 mac_str = mask_str = "00:00:00:00:00:00"
184 elif not mask_str:
185 mask_str = "FF:FF:FF:FF:FF:FF"
186
187 return to_bytes(mac_str), to_bytes(mask_str)
188
189 def convert_ipv4(data):
190 ip, _, mask = data.partition('/')
191
192 if not ip:
193 ip = mask = 0
194 elif not mask:
195 mask = 0xFFFFFFFF
196 elif mask.isdigit():
197 mask = (0xFFFFFFFF << (32 - int(mask))) & 0xFFFFFFFF
198
199 return int(ipaddress.IPv4Address(ip)), int(ipaddress.IPv4Address(mask))
200
201 def convert_int(size):
202 def convert_int_sized(data):
203 value, _, mask = data.partition('/')
204
205 if not value:
206 return 0, 0
207 elif not mask:
208 return int(value, 0), pow(2, size) - 1
209 else:
210 return int(value, 0), int(mask, 0)
211
212 return convert_int_sized
213
214 def parse_starts_block(block_str, scanstr, returnskipped, scanregex=False):
215 if scanregex:
216 m = re.search(scanstr, block_str)
217 if m is None:
218 if returnskipped:
219 return block_str
220 return False
221 if returnskipped:
222 block_str = block_str[len(m.group(0)) :]
223 return block_str
224 return True
225
226 if block_str.startswith(scanstr):
227 if returnskipped:
228 block_str = block_str[len(scanstr) :]
229 else:
230 return True
231
232 if returnskipped:
233 return block_str
234
235 return False
236
237
238 def parse_extract_field(
239 block_str, fieldstr, scanfmt, convert, masked=False, defval=None
240 ):
241 if fieldstr and not block_str.startswith(fieldstr):
242 return block_str, defval
243
244 if fieldstr:
245 str_skiplen = len(fieldstr)
246 str_skipped = block_str[str_skiplen:]
247 if str_skiplen == 0:
248 return str_skipped, defval
249 else:
250 str_skiplen = 0
251 str_skipped = block_str
252
253 m = re.search(scanfmt, str_skipped)
254 if m is None:
255 raise ValueError("Bad fmt string")
256
257 data = m.group(0)
258 if convert:
259 data = convert(m.group(0))
260
261 str_skipped = str_skipped[len(m.group(0)) :]
262 if masked:
263 if str_skipped[0] == "/":
264 raise ValueError("Masking support TBD...")
265
266 str_skipped = str_skipped[strspn(str_skipped, ", ") :]
267 return str_skipped, data
268
269
270 class ovs_dp_msg(genlmsg):
271 # include the OVS version
272 # We need a custom header rather than just being able to rely on
273 # genlmsg because fields ends up not expressing everything correctly
274 # if we use the canonical example of setting fields = (('customfield',),)
275 fields = genlmsg.fields + (("dpifindex", "I"),)
276
277
278 class ovsactions(nla):
279 nla_flags = NLA_F_NESTED
280
281 nla_map = (
282 ("OVS_ACTION_ATTR_UNSPEC", "none"),
283 ("OVS_ACTION_ATTR_OUTPUT", "uint32"),
284 ("OVS_ACTION_ATTR_USERSPACE", "userspace"),
285 ("OVS_ACTION_ATTR_SET", "none"),
286 ("OVS_ACTION_ATTR_PUSH_VLAN", "none"),
287 ("OVS_ACTION_ATTR_POP_VLAN", "flag"),
288 ("OVS_ACTION_ATTR_SAMPLE", "none"),
289 ("OVS_ACTION_ATTR_RECIRC", "uint32"),
290 ("OVS_ACTION_ATTR_HASH", "none"),
291 ("OVS_ACTION_ATTR_PUSH_MPLS", "none"),
292 ("OVS_ACTION_ATTR_POP_MPLS", "flag"),
293 ("OVS_ACTION_ATTR_SET_MASKED", "none"),
294 ("OVS_ACTION_ATTR_CT", "ctact"),
295 ("OVS_ACTION_ATTR_TRUNC", "uint32"),
296 ("OVS_ACTION_ATTR_PUSH_ETH", "none"),
297 ("OVS_ACTION_ATTR_POP_ETH", "flag"),
298 ("OVS_ACTION_ATTR_CT_CLEAR", "flag"),
299 ("OVS_ACTION_ATTR_PUSH_NSH", "none"),
300 ("OVS_ACTION_ATTR_POP_NSH", "flag"),
301 ("OVS_ACTION_ATTR_METER", "none"),
302 ("OVS_ACTION_ATTR_CLONE", "none"),
303 ("OVS_ACTION_ATTR_CHECK_PKT_LEN", "none"),
304 ("OVS_ACTION_ATTR_ADD_MPLS", "none"),
305 ("OVS_ACTION_ATTR_DEC_TTL", "none"),
306 ("OVS_ACTION_ATTR_DROP", "uint32"),
307 )
308
309 class ctact(nla):
310 nla_flags = NLA_F_NESTED
311
312 nla_map = (
313 ("OVS_CT_ATTR_NONE", "none"),
314 ("OVS_CT_ATTR_COMMIT", "flag"),
315 ("OVS_CT_ATTR_ZONE", "uint16"),
316 ("OVS_CT_ATTR_MARK", "none"),
317 ("OVS_CT_ATTR_LABELS", "none"),
318 ("OVS_CT_ATTR_HELPER", "asciiz"),
319 ("OVS_CT_ATTR_NAT", "natattr"),
320 ("OVS_CT_ATTR_FORCE_COMMIT", "flag"),
321 ("OVS_CT_ATTR_EVENTMASK", "uint32"),
322 ("OVS_CT_ATTR_TIMEOUT", "asciiz"),
323 )
324
325 class natattr(nla):
326 nla_flags = NLA_F_NESTED
327
328 nla_map = (
329 ("OVS_NAT_ATTR_NONE", "none"),
330 ("OVS_NAT_ATTR_SRC", "flag"),
331 ("OVS_NAT_ATTR_DST", "flag"),
332 ("OVS_NAT_ATTR_IP_MIN", "ipaddr"),
333 ("OVS_NAT_ATTR_IP_MAX", "ipaddr"),
334 ("OVS_NAT_ATTR_PROTO_MIN", "uint16"),
335 ("OVS_NAT_ATTR_PROTO_MAX", "uint16"),
336 ("OVS_NAT_ATTR_PERSISTENT", "flag"),
337 ("OVS_NAT_ATTR_PROTO_HASH", "flag"),
338 ("OVS_NAT_ATTR_PROTO_RANDOM", "flag"),
339 )
340
341 def dpstr(self, more=False):
342 print_str = "nat("
343
344 if self.get_attr("OVS_NAT_ATTR_SRC"):
345 print_str += "src"
346 elif self.get_attr("OVS_NAT_ATTR_DST"):
347 print_str += "dst"
348 else:
349 print_str += "XXX-unknown-nat"
350
351 if self.get_attr("OVS_NAT_ATTR_IP_MIN") or self.get_attr(
352 "OVS_NAT_ATTR_IP_MAX"
353 ):
354 if self.get_attr("OVS_NAT_ATTR_IP_MIN"):
355 print_str += "=%s," % str(
356 self.get_attr("OVS_NAT_ATTR_IP_MIN")
357 )
358
359 if self.get_attr("OVS_NAT_ATTR_IP_MAX"):
360 print_str += "-%s," % str(
361 self.get_attr("OVS_NAT_ATTR_IP_MAX")
362 )
363 else:
364 print_str += ","
365
366 if self.get_attr("OVS_NAT_ATTR_PROTO_MIN"):
367 print_str += "proto_min=%d," % self.get_attr(
368 "OVS_NAT_ATTR_PROTO_MIN"
369 )
370
371 if self.get_attr("OVS_NAT_ATTR_PROTO_MAX"):
372 print_str += "proto_max=%d," % self.get_attr(
373 "OVS_NAT_ATTR_PROTO_MAX"
374 )
375
376 if self.get_attr("OVS_NAT_ATTR_PERSISTENT"):
377 print_str += "persistent,"
378 if self.get_attr("OVS_NAT_ATTR_HASH"):
379 print_str += "hash,"
380 if self.get_attr("OVS_NAT_ATTR_RANDOM"):
381 print_str += "random"
382 print_str += ")"
383 return print_str
384
385 def dpstr(self, more=False):
386 print_str = "ct("
387
388 if self.get_attr("OVS_CT_ATTR_COMMIT") is not None:
389 print_str += "commit,"
390 if self.get_attr("OVS_CT_ATTR_ZONE") is not None:
391 print_str += "zone=%d," % self.get_attr("OVS_CT_ATTR_ZONE")
392 if self.get_attr("OVS_CT_ATTR_HELPER") is not None:
393 print_str += "helper=%s," % self.get_attr("OVS_CT_ATTR_HELPER")
394 if self.get_attr("OVS_CT_ATTR_NAT") is not None:
395 print_str += self.get_attr("OVS_CT_ATTR_NAT").dpstr(more)
396 print_str += ","
397 if self.get_attr("OVS_CT_ATTR_FORCE_COMMIT") is not None:
398 print_str += "force,"
399 if self.get_attr("OVS_CT_ATTR_EVENTMASK") is not None:
400 print_str += "emask=0x%X," % self.get_attr(
401 "OVS_CT_ATTR_EVENTMASK"
402 )
403 if self.get_attr("OVS_CT_ATTR_TIMEOUT") is not None:
404 print_str += "timeout=%s" % self.get_attr(
405 "OVS_CT_ATTR_TIMEOUT"
406 )
407 print_str += ")"
408 return print_str
409
410 class userspace(nla):
411 nla_flags = NLA_F_NESTED
412
413 nla_map = (
414 ("OVS_USERSPACE_ATTR_UNUSED", "none"),
415 ("OVS_USERSPACE_ATTR_PID", "uint32"),
416 ("OVS_USERSPACE_ATTR_USERDATA", "array(uint8)"),
417 ("OVS_USERSPACE_ATTR_EGRESS_TUN_PORT", "uint32"),
418 )
419
420 def dpstr(self, more=False):
421 print_str = "userspace("
422 if self.get_attr("OVS_USERSPACE_ATTR_PID") is not None:
423 print_str += "pid=%d," % self.get_attr(
424 "OVS_USERSPACE_ATTR_PID"
425 )
426 if self.get_attr("OVS_USERSPACE_ATTR_USERDATA") is not None:
427 print_str += "userdata="
428 for f in self.get_attr("OVS_USERSPACE_ATTR_USERDATA"):
429 print_str += "%x." % f
430 if self.get_attr("OVS_USERSPACE_ATTR_TUN_PORT") is not None:
431 print_str += "egress_tun_port=%d" % self.get_attr(
432 "OVS_USERSPACE_ATTR_TUN_PORT"
433 )
434 print_str += ")"
435 return print_str
436
437 def dpstr(self, more=False):
438 print_str = ""
439
440 for field in self.nla_map:
441 if field[1] == "none" or self.get_attr(field[0]) is None:
442 continue
443 if print_str != "":
444 print_str += ","
445
446 if field[1] == "uint32":
447 if field[0] == "OVS_ACTION_ATTR_OUTPUT":
448 print_str += "%d" % int(self.get_attr(field[0]))
449 elif field[0] == "OVS_ACTION_ATTR_RECIRC":
450 print_str += "recirc(0x%x)" % int(self.get_attr(field[0]))
451 elif field[0] == "OVS_ACTION_ATTR_TRUNC":
452 print_str += "trunc(%d)" % int(self.get_attr(field[0]))
453 elif field[0] == "OVS_ACTION_ATTR_DROP":
454 print_str += "drop(%d)" % int(self.get_attr(field[0]))
455 elif field[1] == "flag":
456 if field[0] == "OVS_ACTION_ATTR_CT_CLEAR":
457 print_str += "ct_clear"
458 elif field[0] == "OVS_ACTION_ATTR_POP_VLAN":
459 print_str += "pop_vlan"
460 elif field[0] == "OVS_ACTION_ATTR_POP_ETH":
461 print_str += "pop_eth"
462 elif field[0] == "OVS_ACTION_ATTR_POP_NSH":
463 print_str += "pop_nsh"
464 elif field[0] == "OVS_ACTION_ATTR_POP_MPLS":
465 print_str += "pop_mpls"
466 else:
467 datum = self.get_attr(field[0])
468 print_str += datum.dpstr(more)
469
470 return print_str
471
472 def parse(self, actstr):
473 while len(actstr) != 0:
474 parsed = False
475 if actstr.startswith("drop"):
476 # If no reason is provided, the implicit drop is used (i.e no
477 # action). If some reason is given, an explicit action is used.
478 actstr, reason = parse_extract_field(
479 actstr,
480 "drop(",
481 "([0-9]+)",
482 lambda x: int(x, 0),
483 False,
484 None,
485 )
486 if reason is not None:
487 self["attrs"].append(["OVS_ACTION_ATTR_DROP", reason])
488 parsed = True
489 else:
490 return
491
492 elif parse_starts_block(actstr, "^(\d+)", False, True):
493 actstr, output = parse_extract_field(
494 actstr, None, "(\d+)", lambda x: int(x), False, "0"
495 )
496 self["attrs"].append(["OVS_ACTION_ATTR_OUTPUT", output])
497 parsed = True
498 elif parse_starts_block(actstr, "recirc(", False):
499 actstr, recircid = parse_extract_field(
500 actstr,
501 "recirc(",
502 "([0-9a-fA-Fx]+)",
503 lambda x: int(x, 0),
504 False,
505 0,
506 )
507 self["attrs"].append(["OVS_ACTION_ATTR_RECIRC", recircid])
508 parsed = True
509
510 parse_flat_map = (
511 ("ct_clear", "OVS_ACTION_ATTR_CT_CLEAR"),
512 ("pop_vlan", "OVS_ACTION_ATTR_POP_VLAN"),
513 ("pop_eth", "OVS_ACTION_ATTR_POP_ETH"),
514 ("pop_nsh", "OVS_ACTION_ATTR_POP_NSH"),
515 )
516
517 for flat_act in parse_flat_map:
518 if parse_starts_block(actstr, flat_act[0], False):
519 actstr += len(flat_act[0])
520 self["attrs"].append([flat_act[1]])
521 actstr = actstr[strspn(actstr, ", ") :]
522 parsed = True
523
524 if parse_starts_block(actstr, "ct(", False):
525 actstr = actstr[len("ct(") :]
526 ctact = ovsactions.ctact()
527
528 for scan in (
529 ("commit", "OVS_CT_ATTR_COMMIT", None),
530 ("force_commit", "OVS_CT_ATTR_FORCE_COMMIT", None),
531 ("zone", "OVS_CT_ATTR_ZONE", int),
532 ("mark", "OVS_CT_ATTR_MARK", int),
533 ("helper", "OVS_CT_ATTR_HELPER", lambda x, y: str(x)),
534 ("timeout", "OVS_CT_ATTR_TIMEOUT", lambda x, y: str(x)),
535 ):
536 if actstr.startswith(scan[0]):
537 actstr = actstr[len(scan[0]) :]
538 if scan[2] is not None:
539 if actstr[0] != "=":
540 raise ValueError("Invalid ct attr")
541 actstr = actstr[1:]
542 pos = strcspn(actstr, ",)")
543 datum = scan[2](actstr[:pos], 0)
544 ctact["attrs"].append([scan[1], datum])
545 actstr = actstr[pos:]
546 else:
547 ctact["attrs"].append([scan[1], None])
548 actstr = actstr[strspn(actstr, ", ") :]
549 # it seems strange to put this here, but nat() is a complex
550 # sub-action and this lets it sit anywhere in the ct() action
551 if actstr.startswith("nat"):
552 actstr = actstr[3:]
553 natact = ovsactions.ctact.natattr()
554
555 if actstr.startswith("("):
556 t = None
557 actstr = actstr[1:]
558 if actstr.startswith("src"):
559 t = "OVS_NAT_ATTR_SRC"
560 actstr = actstr[3:]
561 elif actstr.startswith("dst"):
562 t = "OVS_NAT_ATTR_DST"
563 actstr = actstr[3:]
564
565 actstr, ip_block_min = parse_extract_field(
566 actstr, "=", "([0-9a-fA-F\.]+)", str, False
567 )
568 actstr, ip_block_max = parse_extract_field(
569 actstr, "-", "([0-9a-fA-F\.]+)", str, False
570 )
571
572 actstr, proto_min = parse_extract_field(
573 actstr, ":", "(\d+)", int, False
574 )
575 actstr, proto_max = parse_extract_field(
576 actstr, "-", "(\d+)", int, False
577 )
578
579 if t is not None:
580 natact["attrs"].append([t, None])
581
582 if ip_block_min is not None:
583 natact["attrs"].append(
584 ["OVS_NAT_ATTR_IP_MIN", ip_block_min]
585 )
586 if ip_block_max is not None:
587 natact["attrs"].append(
588 ["OVS_NAT_ATTR_IP_MAX", ip_block_max]
589 )
590 if proto_min is not None:
591 natact["attrs"].append(
592 ["OVS_NAT_ATTR_PROTO_MIN", proto_min]
593 )
594 if proto_max is not None:
595 natact["attrs"].append(
596 ["OVS_NAT_ATTR_PROTO_MAX", proto_max]
597 )
598
599 for natscan in (
600 ("persistent", "OVS_NAT_ATTR_PERSISTENT"),
601 ("hash", "OVS_NAT_ATTR_PROTO_HASH"),
602 ("random", "OVS_NAT_ATTR_PROTO_RANDOM"),
603 ):
604 if actstr.startswith(natscan[0]):
605 actstr = actstr[len(natscan[0]) :]
606 natact["attrs"].append([natscan[1], None])
607 actstr = actstr[strspn(actstr, ", ") :]
608
609 ctact["attrs"].append(["OVS_CT_ATTR_NAT", natact])
610 actstr = actstr[strspn(actstr, ",) ") :]
611
612 self["attrs"].append(["OVS_ACTION_ATTR_CT", ctact])
613 parsed = True
614
615 actstr = actstr[strspn(actstr, "), ") :]
616 if not parsed:
617 raise ValueError("Action str: '%s' not supported" % actstr)
618
619
620 class ovskey(nla):
621 nla_flags = NLA_F_NESTED
622 nla_map = (
623 ("OVS_KEY_ATTR_UNSPEC", "none"),
624 ("OVS_KEY_ATTR_ENCAP", "none"),
625 ("OVS_KEY_ATTR_PRIORITY", "uint32"),
626 ("OVS_KEY_ATTR_IN_PORT", "uint32"),
627 ("OVS_KEY_ATTR_ETHERNET", "ethaddr"),
628 ("OVS_KEY_ATTR_VLAN", "uint16"),
629 ("OVS_KEY_ATTR_ETHERTYPE", "be16"),
630 ("OVS_KEY_ATTR_IPV4", "ovs_key_ipv4"),
631 ("OVS_KEY_ATTR_IPV6", "ovs_key_ipv6"),
632 ("OVS_KEY_ATTR_TCP", "ovs_key_tcp"),
633 ("OVS_KEY_ATTR_UDP", "ovs_key_udp"),
634 ("OVS_KEY_ATTR_ICMP", "ovs_key_icmp"),
635 ("OVS_KEY_ATTR_ICMPV6", "ovs_key_icmpv6"),
636 ("OVS_KEY_ATTR_ARP", "ovs_key_arp"),
637 ("OVS_KEY_ATTR_ND", "ovs_key_nd"),
638 ("OVS_KEY_ATTR_SKB_MARK", "uint32"),
639 ("OVS_KEY_ATTR_TUNNEL", "none"),
640 ("OVS_KEY_ATTR_SCTP", "ovs_key_sctp"),
641 ("OVS_KEY_ATTR_TCP_FLAGS", "be16"),
642 ("OVS_KEY_ATTR_DP_HASH", "uint32"),
643 ("OVS_KEY_ATTR_RECIRC_ID", "uint32"),
644 ("OVS_KEY_ATTR_MPLS", "array(ovs_key_mpls)"),
645 ("OVS_KEY_ATTR_CT_STATE", "uint32"),
646 ("OVS_KEY_ATTR_CT_ZONE", "uint16"),
647 ("OVS_KEY_ATTR_CT_MARK", "uint32"),
648 ("OVS_KEY_ATTR_CT_LABELS", "none"),
649 ("OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4", "ovs_key_ct_tuple_ipv4"),
650 ("OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6", "ovs_key_ct_tuple_ipv6"),
651 ("OVS_KEY_ATTR_NSH", "none"),
652 ("OVS_KEY_ATTR_PACKET_TYPE", "none"),
653 ("OVS_KEY_ATTR_ND_EXTENSIONS", "none"),
654 ("OVS_KEY_ATTR_TUNNEL_INFO", "none"),
655 ("OVS_KEY_ATTR_IPV6_EXTENSIONS", "none"),
656 )
657
658 class ovs_key_proto(nla):
659 fields = (
660 ("src", "!H"),
661 ("dst", "!H"),
662 )
663
664 fields_map = (
665 ("src", "src", "%d", lambda x: int(x) if x else 0,
666 convert_int(16)),
667 ("dst", "dst", "%d", lambda x: int(x) if x else 0,
668 convert_int(16)),
669 )
670
671 def __init__(
672 self,
673 protostr,
674 data=None,
675 offset=None,
676 parent=None,
677 length=None,
678 init=None,
679 ):
680 self.proto_str = protostr
681 nla.__init__(
682 self,
683 data=data,
684 offset=offset,
685 parent=parent,
686 length=length,
687 init=init,
688 )
689
690 def parse(self, flowstr, typeInst):
691 if not flowstr.startswith(self.proto_str):
692 return None, None
693
694 k = typeInst()
695 m = typeInst()
696
697 flowstr = flowstr[len(self.proto_str) :]
698 if flowstr.startswith("("):
699 flowstr = flowstr[1:]
700
701 keybits = b""
702 maskbits = b""
703 for f in self.fields_map:
704 if flowstr.startswith(f[1]):
705 # the following assumes that the field looks
706 # something like 'field.' where '.' is a
707 # character that we don't exactly care about.
708 flowstr = flowstr[len(f[1]) + 1 :]
709 splitchar = 0
710 for c in flowstr:
711 if c == "," or c == ")":
712 break
713 splitchar += 1
714 data = flowstr[:splitchar]
715 flowstr = flowstr[splitchar:]
716 else:
717 data = ""
718
719 if len(f) > 4:
720 k[f[0]], m[f[0]] = f[4](data)
721 else:
722 k[f[0]] = f[3](data)
723 m[f[0]] = f[3](data)
724
725 flowstr = flowstr[strspn(flowstr, ", ") :]
726 if len(flowstr) == 0:
727 return flowstr, k, m
728
729 flowstr = flowstr[strspn(flowstr, "), ") :]
730
731 return flowstr, k, m
732
733 def dpstr(self, masked=None, more=False):
734 outstr = self.proto_str + "("
735 first = False
736 for f in self.fields_map:
737 if first:
738 outstr += ","
739 if masked is None:
740 outstr += "%s=" % f[0]
741 if isinstance(f[2], str):
742 outstr += f[2] % self[f[1]]
743 else:
744 outstr += f[2](self[f[1]])
745 first = True
746 elif more or f[3](masked[f[1]]) != 0:
747 outstr += "%s=" % f[0]
748 if isinstance(f[2], str):
749 outstr += f[2] % self[f[1]]
750 else:
751 outstr += f[2](self[f[1]])
752 outstr += "/"
753 if isinstance(f[2], str):
754 outstr += f[2] % masked[f[1]]
755 else:
756 outstr += f[2](masked[f[1]])
757 first = True
758 outstr += ")"
759 return outstr
760
761 class ethaddr(ovs_key_proto):
762 fields = (
763 ("src", "!6s"),
764 ("dst", "!6s"),
765 )
766
767 fields_map = (
768 (
769 "src",
770 "src",
771 macstr,
772 lambda x: int.from_bytes(x, "big"),
773 convert_mac,
774 ),
775 (
776 "dst",
777 "dst",
778 macstr,
779 lambda x: int.from_bytes(x, "big"),
780 convert_mac,
781 ),
782 )
783
784 def __init__(
785 self,
786 data=None,
787 offset=None,
788 parent=None,
789 length=None,
790 init=None,
791 ):
792 ovskey.ovs_key_proto.__init__(
793 self,
794 "eth",
795 data=data,
796 offset=offset,
797 parent=parent,
798 length=length,
799 init=init,
800 )
801
802 class ovs_key_ipv4(ovs_key_proto):
803 fields = (
804 ("src", "!I"),
805 ("dst", "!I"),
806 ("proto", "B"),
807 ("tos", "B"),
808 ("ttl", "B"),
809 ("frag", "B"),
810 )
811
812 fields_map = (
813 (
814 "src",
815 "src",
816 lambda x: str(ipaddress.IPv4Address(x)),
817 int,
818 convert_ipv4,
819 ),
820 (
821 "dst",
822 "dst",
823 lambda x: str(ipaddress.IPv4Address(x)),
824 int,
825 convert_ipv4,
826 ),
827 ("proto", "proto", "%d", lambda x: int(x) if x else 0,
828 convert_int(8)),
829 ("tos", "tos", "%d", lambda x: int(x) if x else 0,
830 convert_int(8)),
831 ("ttl", "ttl", "%d", lambda x: int(x) if x else 0,
832 convert_int(8)),
833 ("frag", "frag", "%d", lambda x: int(x) if x else 0,
834 convert_int(8)),
835 )
836
837 def __init__(
838 self,
839 data=None,
840 offset=None,
841 parent=None,
842 length=None,
843 init=None,
844 ):
845 ovskey.ovs_key_proto.__init__(
846 self,
847 "ipv4",
848 data=data,
849 offset=offset,
850 parent=parent,
851 length=length,
852 init=init,
853 )
854
855 class ovs_key_ipv6(ovs_key_proto):
856 fields = (
857 ("src", "!16s"),
858 ("dst", "!16s"),
859 ("label", "!I"),
860 ("proto", "B"),
861 ("tclass", "B"),
862 ("hlimit", "B"),
863 ("frag", "B"),
864 )
865
866 fields_map = (
867 (
868 "src",
869 "src",
870 lambda x: str(ipaddress.IPv6Address(x)),
871 lambda x: int.from_bytes(x, "big"),
872 lambda x: ipaddress.IPv6Address(x),
873 ),
874 (
875 "dst",
876 "dst",
877 lambda x: str(ipaddress.IPv6Address(x)),
878 lambda x: int.from_bytes(x, "big"),
879 lambda x: ipaddress.IPv6Address(x),
880 ),
881 ("label", "label", "%d", int),
882 ("proto", "proto", "%d", int),
883 ("tclass", "tclass", "%d", int),
884 ("hlimit", "hlimit", "%d", int),
885 ("frag", "frag", "%d", int),
886 )
887
888 def __init__(
889 self,
890 data=None,
891 offset=None,
892 parent=None,
893 length=None,
894 init=None,
895 ):
896 ovskey.ovs_key_proto.__init__(
897 self,
898 "ipv6",
899 data=data,
900 offset=offset,
901 parent=parent,
902 length=length,
903 init=init,
904 )
905
906 class ovs_key_tcp(ovs_key_proto):
907 def __init__(
908 self,
909 data=None,
910 offset=None,
911 parent=None,
912 length=None,
913 init=None,
914 ):
915 ovskey.ovs_key_proto.__init__(
916 self,
917 "tcp",
918 data=data,
919 offset=offset,
920 parent=parent,
921 length=length,
922 init=init,
923 )
924
925 class ovs_key_udp(ovs_key_proto):
926 def __init__(
927 self,
928 data=None,
929 offset=None,
930 parent=None,
931 length=None,
932 init=None,
933 ):
934 ovskey.ovs_key_proto.__init__(
935 self,
936 "udp",
937 data=data,
938 offset=offset,
939 parent=parent,
940 length=length,
941 init=init,
942 )
943
944 class ovs_key_sctp(ovs_key_proto):
945 def __init__(
946 self,
947 data=None,
948 offset=None,
949 parent=None,
950 length=None,
951 init=None,
952 ):
953 ovskey.ovs_key_proto.__init__(
954 self,
955 "sctp",
956 data=data,
957 offset=offset,
958 parent=parent,
959 length=length,
960 init=init,
961 )
962
963 class ovs_key_icmp(ovs_key_proto):
964 fields = (
965 ("type", "B"),
966 ("code", "B"),
967 )
968
969 fields_map = (
970 ("type", "type", "%d", lambda x: int(x) if x else 0),
971 ("code", "code", "%d", lambda x: int(x) if x else 0),
972 )
973
974 def __init__(
975 self,
976 data=None,
977 offset=None,
978 parent=None,
979 length=None,
980 init=None,
981 ):
982 ovskey.ovs_key_proto.__init__(
983 self,
984 "icmp",
985 data=data,
986 offset=offset,
987 parent=parent,
988 length=length,
989 init=init,
990 )
991
992 class ovs_key_icmpv6(ovs_key_icmp):
993 def __init__(
994 self,
995 data=None,
996 offset=None,
997 parent=None,
998 length=None,
999 init=None,
1000 ):
1001 ovskey.ovs_key_proto.__init__(
1002 self,
1003 "icmpv6",
1004 data=data,
1005 offset=offset,
1006 parent=parent,
1007 length=length,
1008 init=init,
1009 )
1010
1011 class ovs_key_arp(ovs_key_proto):
1012 fields = (
1013 ("sip", "!I"),
1014 ("tip", "!I"),
1015 ("op", "!H"),
1016 ("sha", "!6s"),
1017 ("tha", "!6s"),
1018 ("pad", "xx"),
1019 )
1020
1021 fields_map = (
1022 (
1023 "sip",
1024 "sip",
1025 lambda x: str(ipaddress.IPv4Address(x)),
1026 int,
1027 convert_ipv4,
1028 ),
1029 (
1030 "tip",
1031 "tip",
1032 lambda x: str(ipaddress.IPv4Address(x)),
1033 int,
1034 convert_ipv4,
1035 ),
1036 ("op", "op", "%d", lambda x: int(x) if x else 0),
1037 (
1038 "sha",
1039 "sha",
1040 macstr,
1041 lambda x: int.from_bytes(x, "big"),
1042 convert_mac,
1043 ),
1044 (
1045 "tha",
1046 "tha",
1047 macstr,
1048 lambda x: int.from_bytes(x, "big"),
1049 convert_mac,
1050 ),
1051 )
1052
1053 def __init__(
1054 self,
1055 data=None,
1056 offset=None,
1057 parent=None,
1058 length=None,
1059 init=None,
1060 ):
1061 ovskey.ovs_key_proto.__init__(
1062 self,
1063 "arp",
1064 data=data,
1065 offset=offset,
1066 parent=parent,
1067 length=length,
1068 init=init,
1069 )
1070
1071 class ovs_key_nd(ovs_key_proto):
1072 fields = (
1073 ("target", "!16s"),
1074 ("sll", "!6s"),
1075 ("tll", "!6s"),
1076 )
1077
1078 fields_map = (
1079 (
1080 "target",
1081 "target",
1082 lambda x: str(ipaddress.IPv6Address(x)),
1083 lambda x: int.from_bytes(x, "big"),
1084 ),
1085 ("sll", "sll", macstr, lambda x: int.from_bytes(x, "big")),
1086 ("tll", "tll", macstr, lambda x: int.from_bytes(x, "big")),
1087 )
1088
1089 def __init__(
1090 self,
1091 data=None,
1092 offset=None,
1093 parent=None,
1094 length=None,
1095 init=None,
1096 ):
1097 ovskey.ovs_key_proto.__init__(
1098 self,
1099 "nd",
1100 data=data,
1101 offset=offset,
1102 parent=parent,
1103 length=length,
1104 init=init,
1105 )
1106
1107 class ovs_key_ct_tuple_ipv4(ovs_key_proto):
1108 fields = (
1109 ("src", "!I"),
1110 ("dst", "!I"),
1111 ("tp_src", "!H"),
1112 ("tp_dst", "!H"),
1113 ("proto", "B"),
1114 )
1115
1116 fields_map = (
1117 (
1118 "src",
1119 "src",
1120 lambda x: str(ipaddress.IPv4Address(x)),
1121 int,
1122 convert_ipv4,
1123 ),
1124 (
1125 "dst",
1126 "dst",
1127 lambda x: str(ipaddress.IPv4Address(x)),
1128 int,
1129 convert_ipv4,
1130 ),
1131 ("tp_src", "tp_src", "%d", int),
1132 ("tp_dst", "tp_dst", "%d", int),
1133 ("proto", "proto", "%d", int),
1134 )
1135
1136 def __init__(
1137 self,
1138 data=None,
1139 offset=None,
1140 parent=None,
1141 length=None,
1142 init=None,
1143 ):
1144 ovskey.ovs_key_proto.__init__(
1145 self,
1146 "ct_tuple4",
1147 data=data,
1148 offset=offset,
1149 parent=parent,
1150 length=length,
1151 init=init,
1152 )
1153
1154 class ovs_key_ct_tuple_ipv6(nla):
1155 fields = (
1156 ("src", "!16s"),
1157 ("dst", "!16s"),
1158 ("tp_src", "!H"),
1159 ("tp_dst", "!H"),
1160 ("proto", "B"),
1161 )
1162
1163 fields_map = (
1164 (
1165 "src",
1166 "src",
1167 lambda x: str(ipaddress.IPv6Address(x)),
1168 lambda x: int.from_bytes(x, "big", convertmac),
1169 ),
1170 (
1171 "dst",
1172 "dst",
1173 lambda x: str(ipaddress.IPv6Address(x)),
1174 lambda x: int.from_bytes(x, "big"),
1175 ),
1176 ("tp_src", "tp_src", "%d", int),
1177 ("tp_dst", "tp_dst", "%d", int),
1178 ("proto", "proto", "%d", int),
1179 )
1180
1181 def __init__(
1182 self,
1183 data=None,
1184 offset=None,
1185 parent=None,
1186 length=None,
1187 init=None,
1188 ):
1189 ovskey.ovs_key_proto.__init__(
1190 self,
1191 "ct_tuple6",
1192 data=data,
1193 offset=offset,
1194 parent=parent,
1195 length=length,
1196 init=init,
1197 )
1198
1199 class ovs_key_mpls(nla):
1200 fields = (("lse", ">I"),)
1201
1202 def parse(self, flowstr, mask=None):
1203 for field in (
1204 ("OVS_KEY_ATTR_PRIORITY", "skb_priority", intparse),
1205 ("OVS_KEY_ATTR_SKB_MARK", "skb_mark", intparse),
1206 ("OVS_KEY_ATTR_RECIRC_ID", "recirc_id", intparse),
1207 ("OVS_KEY_ATTR_DP_HASH", "dp_hash", intparse),
1208 ("OVS_KEY_ATTR_CT_STATE", "ct_state", parse_ct_state),
1209 ("OVS_KEY_ATTR_CT_ZONE", "ct_zone", intparse),
1210 ("OVS_KEY_ATTR_CT_MARK", "ct_mark", intparse),
1211 ("OVS_KEY_ATTR_IN_PORT", "in_port", intparse),
1212 (
1213 "OVS_KEY_ATTR_ETHERNET",
1214 "eth",
1215 ovskey.ethaddr,
1216 ),
1217 (
1218 "OVS_KEY_ATTR_ETHERTYPE",
1219 "eth_type",
1220 lambda x: intparse(x, "0xffff"),
1221 ),
1222 (
1223 "OVS_KEY_ATTR_IPV4",
1224 "ipv4",
1225 ovskey.ovs_key_ipv4,
1226 ),
1227 (
1228 "OVS_KEY_ATTR_IPV6",
1229 "ipv6",
1230 ovskey.ovs_key_ipv6,
1231 ),
1232 (
1233 "OVS_KEY_ATTR_ARP",
1234 "arp",
1235 ovskey.ovs_key_arp,
1236 ),
1237 (
1238 "OVS_KEY_ATTR_TCP",
1239 "tcp",
1240 ovskey.ovs_key_tcp,
1241 ),
1242 (
1243 "OVS_KEY_ATTR_UDP",
1244 "udp",
1245 ovskey.ovs_key_udp,
1246 ),
1247 (
1248 "OVS_KEY_ATTR_ICMP",
1249 "icmp",
1250 ovskey.ovs_key_icmp,
1251 ),
1252 (
1253 "OVS_KEY_ATTR_TCP_FLAGS",
1254 "tcp_flags",
1255 lambda x: parse_flags(x, None),
1256 ),
1257 ):
1258 fld = field[1] + "("
1259 if not flowstr.startswith(fld):
1260 continue
1261
1262 if not isinstance(field[2], types.FunctionType):
1263 nk = field[2]()
1264 flowstr, k, m = nk.parse(flowstr, field[2])
1265 else:
1266 flowstr = flowstr[len(fld) :]
1267 flowstr, k, m = field[2](flowstr)
1268
1269 if m and mask is not None:
1270 mask["attrs"].append([field[0], m])
1271 self["attrs"].append([field[0], k])
1272
1273 flowstr = flowstr[strspn(flowstr, "),") :]
1274
1275 return flowstr
1276
1277 def dpstr(self, mask=None, more=False):
1278 print_str = ""
1279
1280 for field in (
1281 (
1282 "OVS_KEY_ATTR_PRIORITY",
1283 "skb_priority",
1284 "%d",
1285 lambda x: False,
1286 True,
1287 ),
1288 (
1289 "OVS_KEY_ATTR_SKB_MARK",
1290 "skb_mark",
1291 "%d",
1292 lambda x: False,
1293 True,
1294 ),
1295 (
1296 "OVS_KEY_ATTR_RECIRC_ID",
1297 "recirc_id",
1298 "0x%08X",
1299 lambda x: False,
1300 True,
1301 ),
1302 (
1303 "OVS_KEY_ATTR_DP_HASH",
1304 "dp_hash",
1305 "0x%08X",
1306 lambda x: False,
1307 True,
1308 ),
1309 (
1310 "OVS_KEY_ATTR_CT_STATE",
1311 "ct_state",
1312 "0x%04x",
1313 lambda x: False,
1314 True,
1315 ),
1316 (
1317 "OVS_KEY_ATTR_CT_ZONE",
1318 "ct_zone",
1319 "0x%04x",
1320 lambda x: False,
1321 True,
1322 ),
1323 (
1324 "OVS_KEY_ATTR_CT_MARK",
1325 "ct_mark",
1326 "0x%08x",
1327 lambda x: False,
1328 True,
1329 ),
1330 (
1331 "OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4",
1332 None,
1333 None,
1334 False,
1335 False,
1336 ),
1337 (
1338 "OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6",
1339 None,
1340 None,
1341 False,
1342 False,
1343 ),
1344 (
1345 "OVS_KEY_ATTR_IN_PORT",
1346 "in_port",
1347 "%d",
1348 lambda x: True,
1349 True,
1350 ),
1351 ("OVS_KEY_ATTR_ETHERNET", None, None, False, False),
1352 (
1353 "OVS_KEY_ATTR_ETHERTYPE",
1354 "eth_type",
1355 "0x%04x",
1356 lambda x: int(x) == 0xFFFF,
1357 True,
1358 ),
1359 ("OVS_KEY_ATTR_IPV4", None, None, False, False),
1360 ("OVS_KEY_ATTR_IPV6", None, None, False, False),
1361 ("OVS_KEY_ATTR_ARP", None, None, False, False),
1362 ("OVS_KEY_ATTR_TCP", None, None, False, False),
1363 (
1364 "OVS_KEY_ATTR_TCP_FLAGS",
1365 "tcp_flags",
1366 "0x%04x",
1367 lambda x: False,
1368 True,
1369 ),
1370 ("OVS_KEY_ATTR_UDP", None, None, False, False),
1371 ("OVS_KEY_ATTR_SCTP", None, None, False, False),
1372 ("OVS_KEY_ATTR_ICMP", None, None, False, False),
1373 ("OVS_KEY_ATTR_ICMPV6", None, None, False, False),
1374 ("OVS_KEY_ATTR_ND", None, None, False, False),
1375 ):
1376 v = self.get_attr(field[0])
1377 if v is not None:
1378 m = None if mask is None else mask.get_attr(field[0])
1379 if field[4] is False:
1380 print_str += v.dpstr(m, more)
1381 print_str += ","
1382 else:
1383 if m is None or field[3](m):
1384 print_str += field[1] + "("
1385 print_str += field[2] % v
1386 print_str += "),"
1387 elif more or m != 0:
1388 print_str += field[1] + "("
1389 print_str += (field[2] % v) + "/" + (field[2] % m)
1390 print_str += "),"
1391
1392 return print_str
1393
1394
1395 class OvsPacket(GenericNetlinkSocket):
1396 OVS_PACKET_CMD_MISS = 1 # Flow table miss
1397 OVS_PACKET_CMD_ACTION = 2 # USERSPACE action
1398 OVS_PACKET_CMD_EXECUTE = 3 # Apply actions to packet
1399
1400 class ovs_packet_msg(ovs_dp_msg):
1401 nla_map = (
1402 ("OVS_PACKET_ATTR_UNSPEC", "none"),
1403 ("OVS_PACKET_ATTR_PACKET", "array(uint8)"),
1404 ("OVS_PACKET_ATTR_KEY", "ovskey"),
1405 ("OVS_PACKET_ATTR_ACTIONS", "ovsactions"),
1406 ("OVS_PACKET_ATTR_USERDATA", "none"),
1407 ("OVS_PACKET_ATTR_EGRESS_TUN_KEY", "none"),
1408 ("OVS_PACKET_ATTR_UNUSED1", "none"),
1409 ("OVS_PACKET_ATTR_UNUSED2", "none"),
1410 ("OVS_PACKET_ATTR_PROBE", "none"),
1411 ("OVS_PACKET_ATTR_MRU", "uint16"),
1412 ("OVS_PACKET_ATTR_LEN", "uint32"),
1413 ("OVS_PACKET_ATTR_HASH", "uint64"),
1414 )
1415
1416 def __init__(self):
1417 GenericNetlinkSocket.__init__(self)
1418 self.bind(OVS_PACKET_FAMILY, OvsPacket.ovs_packet_msg)
1419
1420 def upcall_handler(self, up=None):
1421 print("listening on upcall packet handler:", self.epid)
1422 while True:
1423 try:
1424 msgs = self.get()
1425 for msg in msgs:
1426 if not up:
1427 continue
1428 if msg["cmd"] == OvsPacket.OVS_PACKET_CMD_MISS:
1429 up.miss(msg)
1430 elif msg["cmd"] == OvsPacket.OVS_PACKET_CMD_ACTION:
1431 up.action(msg)
1432 elif msg["cmd"] == OvsPacket.OVS_PACKET_CMD_EXECUTE:
1433 up.execute(msg)
1434 else:
1435 print("Unkonwn cmd: %d" % msg["cmd"])
1436 except NetlinkError as ne:
1437 raise ne
1438
1439
1440 class OvsDatapath(GenericNetlinkSocket):
1441 OVS_DP_F_VPORT_PIDS = 1 << 1
1442 OVS_DP_F_DISPATCH_UPCALL_PER_CPU = 1 << 3
1443
1444 class dp_cmd_msg(ovs_dp_msg):
1445 """
1446 Message class that will be used to communicate with the kernel module.
1447 """
1448
1449 nla_map = (
1450 ("OVS_DP_ATTR_UNSPEC", "none"),
1451 ("OVS_DP_ATTR_NAME", "asciiz"),
1452 ("OVS_DP_ATTR_UPCALL_PID", "array(uint32)"),
1453 ("OVS_DP_ATTR_STATS", "dpstats"),
1454 ("OVS_DP_ATTR_MEGAFLOW_STATS", "megaflowstats"),
1455 ("OVS_DP_ATTR_USER_FEATURES", "uint32"),
1456 ("OVS_DP_ATTR_PAD", "none"),
1457 ("OVS_DP_ATTR_MASKS_CACHE_SIZE", "uint32"),
1458 ("OVS_DP_ATTR_PER_CPU_PIDS", "array(uint32)"),
1459 )
1460
1461 class dpstats(nla):
1462 fields = (
1463 ("hit", "=Q"),
1464 ("missed", "=Q"),
1465 ("lost", "=Q"),
1466 ("flows", "=Q"),
1467 )
1468
1469 class megaflowstats(nla):
1470 fields = (
1471 ("mask_hit", "=Q"),
1472 ("masks", "=I"),
1473 ("padding", "=I"),
1474 ("cache_hits", "=Q"),
1475 ("pad1", "=Q"),
1476 )
1477
1478 def __init__(self):
1479 GenericNetlinkSocket.__init__(self)
1480 self.bind(OVS_DATAPATH_FAMILY, OvsDatapath.dp_cmd_msg)
1481
1482 def info(self, dpname, ifindex=0):
1483 msg = OvsDatapath.dp_cmd_msg()
1484 msg["cmd"] = OVS_DP_CMD_GET
1485 msg["version"] = OVS_DATAPATH_VERSION
1486 msg["reserved"] = 0
1487 msg["dpifindex"] = ifindex
1488 msg["attrs"].append(["OVS_DP_ATTR_NAME", dpname])
1489
1490 try:
1491 reply = self.nlm_request(
1492 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST
1493 )
1494 reply = reply[0]
1495 except NetlinkError as ne:
1496 if ne.code == errno.ENODEV:
1497 reply = None
1498 else:
1499 raise ne
1500
1501 return reply
1502
1503 def create(
1504 self, dpname, shouldUpcall=False, versionStr=None, p=OvsPacket()
1505 ):
1506 msg = OvsDatapath.dp_cmd_msg()
1507 msg["cmd"] = OVS_DP_CMD_NEW
1508 if versionStr is None:
1509 msg["version"] = OVS_DATAPATH_VERSION
1510 else:
1511 msg["version"] = int(versionStr.split(":")[0], 0)
1512 msg["reserved"] = 0
1513 msg["dpifindex"] = 0
1514 msg["attrs"].append(["OVS_DP_ATTR_NAME", dpname])
1515
1516 dpfeatures = 0
1517 if versionStr is not None and versionStr.find(":") != -1:
1518 dpfeatures = int(versionStr.split(":")[1], 0)
1519 else:
1520 if versionStr is None or versionStr.find(":") == -1:
1521 dpfeatures |= OvsDatapath.OVS_DP_F_DISPATCH_UPCALL_PER_CPU
1522 dpfeatures &= ~OvsDatapath.OVS_DP_F_VPORT_PIDS
1523
1524 nproc = multiprocessing.cpu_count()
1525 procarray = []
1526 for i in range(1, nproc):
1527 procarray += [int(p.epid)]
1528 msg["attrs"].append(["OVS_DP_ATTR_UPCALL_PID", procarray])
1529 msg["attrs"].append(["OVS_DP_ATTR_USER_FEATURES", dpfeatures])
1530 if not shouldUpcall:
1531 msg["attrs"].append(["OVS_DP_ATTR_UPCALL_PID", [0]])
1532
1533 try:
1534 reply = self.nlm_request(
1535 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK
1536 )
1537 reply = reply[0]
1538 except NetlinkError as ne:
1539 if ne.code == errno.EEXIST:
1540 reply = None
1541 else:
1542 raise ne
1543
1544 return reply
1545
1546 def destroy(self, dpname):
1547 msg = OvsDatapath.dp_cmd_msg()
1548 msg["cmd"] = OVS_DP_CMD_DEL
1549 msg["version"] = OVS_DATAPATH_VERSION
1550 msg["reserved"] = 0
1551 msg["dpifindex"] = 0
1552 msg["attrs"].append(["OVS_DP_ATTR_NAME", dpname])
1553
1554 try:
1555 reply = self.nlm_request(
1556 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK
1557 )
1558 reply = reply[0]
1559 except NetlinkError as ne:
1560 if ne.code == errno.ENODEV:
1561 reply = None
1562 else:
1563 raise ne
1564
1565 return reply
1566
1567
1568 class OvsVport(GenericNetlinkSocket):
1569 OVS_VPORT_TYPE_NETDEV = 1
1570 OVS_VPORT_TYPE_INTERNAL = 2
1571 OVS_VPORT_TYPE_GRE = 3
1572 OVS_VPORT_TYPE_VXLAN = 4
1573 OVS_VPORT_TYPE_GENEVE = 5
1574
1575 class ovs_vport_msg(ovs_dp_msg):
1576 nla_map = (
1577 ("OVS_VPORT_ATTR_UNSPEC", "none"),
1578 ("OVS_VPORT_ATTR_PORT_NO", "uint32"),
1579 ("OVS_VPORT_ATTR_TYPE", "uint32"),
1580 ("OVS_VPORT_ATTR_NAME", "asciiz"),
1581 ("OVS_VPORT_ATTR_OPTIONS", "none"),
1582 ("OVS_VPORT_ATTR_UPCALL_PID", "array(uint32)"),
1583 ("OVS_VPORT_ATTR_STATS", "vportstats"),
1584 ("OVS_VPORT_ATTR_PAD", "none"),
1585 ("OVS_VPORT_ATTR_IFINDEX", "uint32"),
1586 ("OVS_VPORT_ATTR_NETNSID", "uint32"),
1587 )
1588
1589 class vportstats(nla):
1590 fields = (
1591 ("rx_packets", "=Q"),
1592 ("tx_packets", "=Q"),
1593 ("rx_bytes", "=Q"),
1594 ("tx_bytes", "=Q"),
1595 ("rx_errors", "=Q"),
1596 ("tx_errors", "=Q"),
1597 ("rx_dropped", "=Q"),
1598 ("tx_dropped", "=Q"),
1599 )
1600
1601 def type_to_str(vport_type):
1602 if vport_type == OvsVport.OVS_VPORT_TYPE_NETDEV:
1603 return "netdev"
1604 elif vport_type == OvsVport.OVS_VPORT_TYPE_INTERNAL:
1605 return "internal"
1606 elif vport_type == OvsVport.OVS_VPORT_TYPE_GRE:
1607 return "gre"
1608 elif vport_type == OvsVport.OVS_VPORT_TYPE_VXLAN:
1609 return "vxlan"
1610 elif vport_type == OvsVport.OVS_VPORT_TYPE_GENEVE:
1611 return "geneve"
1612 raise ValueError("Unknown vport type:%d" % vport_type)
1613
1614 def str_to_type(vport_type):
1615 if vport_type == "netdev":
1616 return OvsVport.OVS_VPORT_TYPE_NETDEV
1617 elif vport_type == "internal":
1618 return OvsVport.OVS_VPORT_TYPE_INTERNAL
1619 elif vport_type == "gre":
1620 return OvsVport.OVS_VPORT_TYPE_INTERNAL
1621 elif vport_type == "vxlan":
1622 return OvsVport.OVS_VPORT_TYPE_VXLAN
1623 elif vport_type == "geneve":
1624 return OvsVport.OVS_VPORT_TYPE_GENEVE
1625 raise ValueError("Unknown vport type: '%s'" % vport_type)
1626
1627 def __init__(self, packet=OvsPacket()):
1628 GenericNetlinkSocket.__init__(self)
1629 self.bind(OVS_VPORT_FAMILY, OvsVport.ovs_vport_msg)
1630 self.upcall_packet = packet
1631
1632 def info(self, vport_name, dpifindex=0, portno=None):
1633 msg = OvsVport.ovs_vport_msg()
1634
1635 msg["cmd"] = OVS_VPORT_CMD_GET
1636 msg["version"] = OVS_DATAPATH_VERSION
1637 msg["reserved"] = 0
1638 msg["dpifindex"] = dpifindex
1639
1640 if portno is None:
1641 msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_name])
1642 else:
1643 msg["attrs"].append(["OVS_VPORT_ATTR_PORT_NO", portno])
1644
1645 try:
1646 reply = self.nlm_request(
1647 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST
1648 )
1649 reply = reply[0]
1650 except NetlinkError as ne:
1651 if ne.code == errno.ENODEV:
1652 reply = None
1653 else:
1654 raise ne
1655 return reply
1656
1657 def attach(self, dpindex, vport_ifname, ptype):
1658 msg = OvsVport.ovs_vport_msg()
1659
1660 msg["cmd"] = OVS_VPORT_CMD_NEW
1661 msg["version"] = OVS_DATAPATH_VERSION
1662 msg["reserved"] = 0
1663 msg["dpifindex"] = dpindex
1664 port_type = OvsVport.str_to_type(ptype)
1665
1666 msg["attrs"].append(["OVS_VPORT_ATTR_TYPE", port_type])
1667 msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_ifname])
1668 msg["attrs"].append(
1669 ["OVS_VPORT_ATTR_UPCALL_PID", [self.upcall_packet.epid]]
1670 )
1671
1672 try:
1673 reply = self.nlm_request(
1674 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK
1675 )
1676 reply = reply[0]
1677 except NetlinkError as ne:
1678 if ne.code == errno.EEXIST:
1679 reply = None
1680 else:
1681 raise ne
1682 return reply
1683
1684 def reset_upcall(self, dpindex, vport_ifname, p=None):
1685 msg = OvsVport.ovs_vport_msg()
1686
1687 msg["cmd"] = OVS_VPORT_CMD_SET
1688 msg["version"] = OVS_DATAPATH_VERSION
1689 msg["reserved"] = 0
1690 msg["dpifindex"] = dpindex
1691 msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_ifname])
1692
1693 if p == None:
1694 p = self.upcall_packet
1695 else:
1696 self.upcall_packet = p
1697
1698 msg["attrs"].append(["OVS_VPORT_ATTR_UPCALL_PID", [p.epid]])
1699
1700 try:
1701 reply = self.nlm_request(
1702 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK
1703 )
1704 reply = reply[0]
1705 except NetlinkError as ne:
1706 raise ne
1707 return reply
1708
1709 def detach(self, dpindex, vport_ifname):
1710 msg = OvsVport.ovs_vport_msg()
1711
1712 msg["cmd"] = OVS_VPORT_CMD_DEL
1713 msg["version"] = OVS_DATAPATH_VERSION
1714 msg["reserved"] = 0
1715 msg["dpifindex"] = dpindex
1716 msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_ifname])
1717
1718 try:
1719 reply = self.nlm_request(
1720 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK
1721 )
1722 reply = reply[0]
1723 except NetlinkError as ne:
1724 if ne.code == errno.ENODEV:
1725 reply = None
1726 else:
1727 raise ne
1728 return reply
1729
1730 def upcall_handler(self, handler=None):
1731 self.upcall_packet.upcall_handler(handler)
1732
1733
1734 class OvsFlow(GenericNetlinkSocket):
1735 class ovs_flow_msg(ovs_dp_msg):
1736 nla_map = (
1737 ("OVS_FLOW_ATTR_UNSPEC", "none"),
1738 ("OVS_FLOW_ATTR_KEY", "ovskey"),
1739 ("OVS_FLOW_ATTR_ACTIONS", "ovsactions"),
1740 ("OVS_FLOW_ATTR_STATS", "flowstats"),
1741 ("OVS_FLOW_ATTR_TCP_FLAGS", "uint8"),
1742 ("OVS_FLOW_ATTR_USED", "uint64"),
1743 ("OVS_FLOW_ATTR_CLEAR", "none"),
1744 ("OVS_FLOW_ATTR_MASK", "ovskey"),
1745 ("OVS_FLOW_ATTR_PROBE", "none"),
1746 ("OVS_FLOW_ATTR_UFID", "array(uint32)"),
1747 ("OVS_FLOW_ATTR_UFID_FLAGS", "uint32"),
1748 )
1749
1750 class flowstats(nla):
1751 fields = (
1752 ("packets", "=Q"),
1753 ("bytes", "=Q"),
1754 )
1755
1756 def dpstr(self, more=False):
1757 ufid = self.get_attr("OVS_FLOW_ATTR_UFID")
1758 ufid_str = ""
1759 if ufid is not None:
1760 ufid_str = (
1761 "ufid:{:08x}-{:04x}-{:04x}-{:04x}-{:04x}{:08x}".format(
1762 ufid[0],
1763 ufid[1] >> 16,
1764 ufid[1] & 0xFFFF,
1765 ufid[2] >> 16,
1766 ufid[2] & 0,
1767 ufid[3],
1768 )
1769 )
1770
1771 key_field = self.get_attr("OVS_FLOW_ATTR_KEY")
1772 keymsg = None
1773 if key_field is not None:
1774 keymsg = key_field
1775
1776 mask_field = self.get_attr("OVS_FLOW_ATTR_MASK")
1777 maskmsg = None
1778 if mask_field is not None:
1779 maskmsg = mask_field
1780
1781 acts_field = self.get_attr("OVS_FLOW_ATTR_ACTIONS")
1782 actsmsg = None
1783 if acts_field is not None:
1784 actsmsg = acts_field
1785
1786 print_str = ""
1787
1788 if more:
1789 print_str += ufid_str + ","
1790
1791 if keymsg is not None:
1792 print_str += keymsg.dpstr(maskmsg, more)
1793
1794 stats = self.get_attr("OVS_FLOW_ATTR_STATS")
1795 if stats is None:
1796 print_str += " packets:0, bytes:0,"
1797 else:
1798 print_str += " packets:%d, bytes:%d," % (
1799 stats["packets"],
1800 stats["bytes"],
1801 )
1802
1803 used = self.get_attr("OVS_FLOW_ATTR_USED")
1804 print_str += " used:"
1805 if used is None:
1806 print_str += "never,"
1807 else:
1808 used_time = int(used)
1809 cur_time_sec = time.clock_gettime(time.CLOCK_MONOTONIC)
1810 used_time = (cur_time_sec * 1000) - used_time
1811 print_str += "{}s,".format(used_time / 1000)
1812
1813 print_str += " actions:"
1814 if (
1815 actsmsg is None
1816 or "attrs" not in actsmsg
1817 or len(actsmsg["attrs"]) == 0
1818 ):
1819 print_str += "drop"
1820 else:
1821 print_str += actsmsg.dpstr(more)
1822
1823 return print_str
1824
1825 def parse(self, flowstr, actstr, dpidx=0):
1826 OVS_UFID_F_OMIT_KEY = 1 << 0
1827 OVS_UFID_F_OMIT_MASK = 1 << 1
1828 OVS_UFID_F_OMIT_ACTIONS = 1 << 2
1829
1830 self["cmd"] = 0
1831 self["version"] = 0
1832 self["reserved"] = 0
1833 self["dpifindex"] = 0
1834
1835 if flowstr.startswith("ufid:"):
1836 count = 5
1837 while flowstr[count] != ",":
1838 count += 1
1839 ufidstr = flowstr[5:count]
1840 flowstr = flowstr[count + 1 :]
1841 else:
1842 ufidstr = str(uuid.uuid4())
1843 uuidRawObj = uuid.UUID(ufidstr).fields
1844
1845 self["attrs"].append(
1846 [
1847 "OVS_FLOW_ATTR_UFID",
1848 [
1849 uuidRawObj[0],
1850 uuidRawObj[1] << 16 | uuidRawObj[2],
1851 uuidRawObj[3] << 24
1852 | uuidRawObj[4] << 16
1853 | uuidRawObj[5] & (0xFF << 32) >> 32,
1854 uuidRawObj[5] & (0xFFFFFFFF),
1855 ],
1856 ]
1857 )
1858 self["attrs"].append(
1859 [
1860 "OVS_FLOW_ATTR_UFID_FLAGS",
1861 int(
1862 OVS_UFID_F_OMIT_KEY
1863 | OVS_UFID_F_OMIT_MASK
1864 | OVS_UFID_F_OMIT_ACTIONS
1865 ),
1866 ]
1867 )
1868
1869 k = ovskey()
1870 m = ovskey()
1871 k.parse(flowstr, m)
1872 self["attrs"].append(["OVS_FLOW_ATTR_KEY", k])
1873 self["attrs"].append(["OVS_FLOW_ATTR_MASK", m])
1874
1875 a = ovsactions()
1876 a.parse(actstr)
1877 self["attrs"].append(["OVS_FLOW_ATTR_ACTIONS", a])
1878
1879 def __init__(self):
1880 GenericNetlinkSocket.__init__(self)
1881
1882 self.bind(OVS_FLOW_FAMILY, OvsFlow.ovs_flow_msg)
1883
1884 def add_flow(self, dpifindex, flowmsg):
1885 """
1886 Send a new flow message to the kernel.
1887
1888 dpifindex should be a valid datapath obtained by calling
1889 into the OvsDatapath lookup
1890
1891 flowmsg is a flow object obtained by calling a dpparse
1892 """
1893
1894 flowmsg["cmd"] = OVS_FLOW_CMD_NEW
1895 flowmsg["version"] = OVS_DATAPATH_VERSION
1896 flowmsg["reserved"] = 0
1897 flowmsg["dpifindex"] = dpifindex
1898
1899 try:
1900 reply = self.nlm_request(
1901 flowmsg,
1902 msg_type=self.prid,
1903 msg_flags=NLM_F_REQUEST | NLM_F_ACK,
1904 )
1905 reply = reply[0]
1906 except NetlinkError as ne:
1907 print(flowmsg)
1908 raise ne
1909 return reply
1910
1911 def del_flows(self, dpifindex):
1912 """
1913 Send a del message to the kernel that will drop all flows.
1914
1915 dpifindex should be a valid datapath obtained by calling
1916 into the OvsDatapath lookup
1917 """
1918
1919 flowmsg = OvsFlow.ovs_flow_msg()
1920 flowmsg["cmd"] = OVS_FLOW_CMD_DEL
1921 flowmsg["version"] = OVS_DATAPATH_VERSION
1922 flowmsg["reserved"] = 0
1923 flowmsg["dpifindex"] = dpifindex
1924
1925 try:
1926 reply = self.nlm_request(
1927 flowmsg,
1928 msg_type=self.prid,
1929 msg_flags=NLM_F_REQUEST | NLM_F_ACK,
1930 )
1931 reply = reply[0]
1932 except NetlinkError as ne:
1933 print(flowmsg)
1934 raise ne
1935 return reply
1936
1937 def dump(self, dpifindex, flowspec=None):
1938 """
1939 Returns a list of messages containing flows.
1940
1941 dpifindex should be a valid datapath obtained by calling
1942 into the OvsDatapath lookup
1943
1944 flowpsec is a string which represents a flow in the dpctl
1945 format.
1946 """
1947 msg = OvsFlow.ovs_flow_msg()
1948
1949 msg["cmd"] = OVS_FLOW_CMD_GET
1950 msg["version"] = OVS_DATAPATH_VERSION
1951 msg["reserved"] = 0
1952 msg["dpifindex"] = dpifindex
1953
1954 msg_flags = NLM_F_REQUEST | NLM_F_ACK
1955 if flowspec is None:
1956 msg_flags |= NLM_F_DUMP
1957 rep = None
1958
1959 try:
1960 rep = self.nlm_request(
1961 msg,
1962 msg_type=self.prid,
1963 msg_flags=msg_flags,
1964 )
1965 except NetlinkError as ne:
1966 raise ne
1967 return rep
1968
1969 def miss(self, packetmsg):
1970 seq = packetmsg["header"]["sequence_number"]
1971 keystr = "(none)"
1972 key_field = packetmsg.get_attr("OVS_PACKET_ATTR_KEY")
1973 if key_field is not None:
1974 keystr = key_field.dpstr(None, True)
1975
1976 pktdata = packetmsg.get_attr("OVS_PACKET_ATTR_PACKET")
1977 pktpres = "yes" if pktdata is not None else "no"
1978
1979 print("MISS upcall[%d/%s]: %s" % (seq, pktpres, keystr), flush=True)
1980
1981 def execute(self, packetmsg):
1982 print("userspace execute command")
1983
1984 def action(self, packetmsg):
1985 print("userspace action command")
1986
1987
1988 def print_ovsdp_full(dp_lookup_rep, ifindex, ndb=NDB(), vpl=OvsVport()):
1989 dp_name = dp_lookup_rep.get_attr("OVS_DP_ATTR_NAME")
1990 base_stats = dp_lookup_rep.get_attr("OVS_DP_ATTR_STATS")
1991 megaflow_stats = dp_lookup_rep.get_attr("OVS_DP_ATTR_MEGAFLOW_STATS")
1992 user_features = dp_lookup_rep.get_attr("OVS_DP_ATTR_USER_FEATURES")
1993 masks_cache_size = dp_lookup_rep.get_attr("OVS_DP_ATTR_MASKS_CACHE_SIZE")
1994
1995 print("%s:" % dp_name)
1996 print(
1997 " lookups: hit:%d missed:%d lost:%d"
1998 % (base_stats["hit"], base_stats["missed"], base_stats["lost"])
1999 )
2000 print(" flows:%d" % base_stats["flows"])
2001 pkts = base_stats["hit"] + base_stats["missed"]
2002 avg = (megaflow_stats["mask_hit"] / pkts) if pkts != 0 else 0.0
2003 print(
2004 " masks: hit:%d total:%d hit/pkt:%f"
2005 % (megaflow_stats["mask_hit"], megaflow_stats["masks"], avg)
2006 )
2007 print(" caches:")
2008 print(" masks-cache: size:%d" % masks_cache_size)
2009
2010 if user_features is not None:
2011 print(" features: 0x%X" % user_features)
2012
2013 # port print out
2014 for iface in ndb.interfaces:
2015 rep = vpl.info(iface.ifname, ifindex)
2016 if rep is not None:
2017 print(
2018 " port %d: %s (%s)"
2019 % (
2020 rep.get_attr("OVS_VPORT_ATTR_PORT_NO"),
2021 rep.get_attr("OVS_VPORT_ATTR_NAME"),
2022 OvsVport.type_to_str(rep.get_attr("OVS_VPORT_ATTR_TYPE")),
2023 )
2024 )
2025
2026
2027 def main(argv):
2028 nlmsg_atoms.ovskey = ovskey
2029 nlmsg_atoms.ovsactions = ovsactions
2030
2031 # version check for pyroute2
2032 prverscheck = pyroute2.__version__.split(".")
2033 if int(prverscheck[0]) == 0 and int(prverscheck[1]) < 6:
2034 print("Need to upgrade the python pyroute2 package to >= 0.6.")
2035 sys.exit(0)
2036
2037 parser = argparse.ArgumentParser()
2038 parser.add_argument(
2039 "-v",
2040 "--verbose",
2041 action="count",
2042 help="Increment 'verbose' output counter.",
2043 default=0,
2044 )
2045 subparsers = parser.add_subparsers()
2046
2047 showdpcmd = subparsers.add_parser("show")
2048 showdpcmd.add_argument(
2049 "showdp", metavar="N", type=str, nargs="?", help="Datapath Name"
2050 )
2051
2052 adddpcmd = subparsers.add_parser("add-dp")
2053 adddpcmd.add_argument("adddp", help="Datapath Name")
2054 adddpcmd.add_argument(
2055 "-u",
2056 "--upcall",
2057 action="store_true",
2058 help="Leave open a reader for upcalls",
2059 )
2060 adddpcmd.add_argument(
2061 "-V",
2062 "--versioning",
2063 required=False,
2064 help="Specify a custom version / feature string",
2065 )
2066
2067 deldpcmd = subparsers.add_parser("del-dp")
2068 deldpcmd.add_argument("deldp", help="Datapath Name")
2069
2070 addifcmd = subparsers.add_parser("add-if")
2071 addifcmd.add_argument("dpname", help="Datapath Name")
2072 addifcmd.add_argument("addif", help="Interface name for adding")
2073 addifcmd.add_argument(
2074 "-u",
2075 "--upcall",
2076 action="store_true",
2077 help="Leave open a reader for upcalls",
2078 )
2079 addifcmd.add_argument(
2080 "-t",
2081 "--ptype",
2082 type=str,
2083 default="netdev",
2084 choices=["netdev", "internal"],
2085 help="Interface type (default netdev)",
2086 )
2087 delifcmd = subparsers.add_parser("del-if")
2088 delifcmd.add_argument("dpname", help="Datapath Name")
2089 delifcmd.add_argument("delif", help="Interface name for adding")
2090
2091 dumpflcmd = subparsers.add_parser("dump-flows")
2092 dumpflcmd.add_argument("dumpdp", help="Datapath Name")
2093
2094 addflcmd = subparsers.add_parser("add-flow")
2095 addflcmd.add_argument("flbr", help="Datapath name")
2096 addflcmd.add_argument("flow", help="Flow specification")
2097 addflcmd.add_argument("acts", help="Flow actions")
2098
2099 delfscmd = subparsers.add_parser("del-flows")
2100 delfscmd.add_argument("flsbr", help="Datapath name")
2101
2102 args = parser.parse_args()
2103
2104 if args.verbose > 0:
2105 if args.verbose > 1:
2106 logging.basicConfig(level=logging.DEBUG)
2107
2108 ovspk = OvsPacket()
2109 ovsdp = OvsDatapath()
2110 ovsvp = OvsVport(ovspk)
2111 ovsflow = OvsFlow()
2112 ndb = NDB()
2113
2114 if hasattr(args, "showdp"):
2115 found = False
2116 for iface in ndb.interfaces:
2117 rep = None
2118 if args.showdp is None:
2119 rep = ovsdp.info(iface.ifname, 0)
2120 elif args.showdp == iface.ifname:
2121 rep = ovsdp.info(iface.ifname, 0)
2122
2123 if rep is not None:
2124 found = True
2125 print_ovsdp_full(rep, iface.index, ndb, ovsvp)
2126
2127 if not found:
2128 msg = "No DP found"
2129 if args.showdp is not None:
2130 msg += ":'%s'" % args.showdp
2131 print(msg)
2132 elif hasattr(args, "adddp"):
2133 rep = ovsdp.create(args.adddp, args.upcall, args.versioning, ovspk)
2134 if rep is None:
2135 print("DP '%s' already exists" % args.adddp)
2136 else:
2137 print("DP '%s' added" % args.adddp)
2138 if args.upcall:
2139 ovspk.upcall_handler(ovsflow)
2140 elif hasattr(args, "deldp"):
2141 ovsdp.destroy(args.deldp)
2142 elif hasattr(args, "addif"):
2143 rep = ovsdp.info(args.dpname, 0)
2144 if rep is None:
2145 print("DP '%s' not found." % args.dpname)
2146 return 1
2147 dpindex = rep["dpifindex"]
2148 rep = ovsvp.attach(rep["dpifindex"], args.addif, args.ptype)
2149 msg = "vport '%s'" % args.addif
2150 if rep and rep["header"]["error"] is None:
2151 msg += " added."
2152 else:
2153 msg += " failed to add."
2154 if args.upcall:
2155 if rep is None:
2156 rep = ovsvp.reset_upcall(dpindex, args.addif, ovspk)
2157 ovsvp.upcall_handler(ovsflow)
2158 elif hasattr(args, "delif"):
2159 rep = ovsdp.info(args.dpname, 0)
2160 if rep is None:
2161 print("DP '%s' not found." % args.dpname)
2162 return 1
2163 rep = ovsvp.detach(rep["dpifindex"], args.delif)
2164 msg = "vport '%s'" % args.delif
2165 if rep and rep["header"]["error"] is None:
2166 msg += " removed."
2167 else:
2168 msg += " failed to remove."
2169 elif hasattr(args, "dumpdp"):
2170 rep = ovsdp.info(args.dumpdp, 0)
2171 if rep is None:
2172 print("DP '%s' not found." % args.dumpdp)
2173 return 1
2174 rep = ovsflow.dump(rep["dpifindex"])
2175 for flow in rep:
2176 print(flow.dpstr(True if args.verbose > 0 else False))
2177 elif hasattr(args, "flbr"):
2178 rep = ovsdp.info(args.flbr, 0)
2179 if rep is None:
2180 print("DP '%s' not found." % args.flbr)
2181 return 1
2182 flow = OvsFlow.ovs_flow_msg()
2183 flow.parse(args.flow, args.acts, rep["dpifindex"])
2184 ovsflow.add_flow(rep["dpifindex"], flow)
2185 elif hasattr(args, "flsbr"):
2186 rep = ovsdp.info(args.flsbr, 0)
2187 if rep is None:
2188 print("DP '%s' not found." % args.flsbr)
2189 ovsflow.del_flows(rep["dpifindex"])
2190
2191 return 0
2192
2193
2194 if __name__ == "__main__":
2195 sys.exit(main(sys.argv))