2 # SPDX-License-Identifier: GPL-2.0
4 # Controls the openvswitch module. Part of the kselftest suite, but
5 # can be used for some diagnostic purpose as well.
11 import multiprocessing
20 from pyroute2 import NDB
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
33 except ModuleNotFoundError:
34 print("Need to install the python pyroute2 package >= 0.6.")
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"
45 OVS_DATAPATH_VERSION = 2
63 outstr = ":".join(["%02X" % i for i in mac])
67 def strcspn(str1, str2):
70 if str2.find(char) != -1:
76 def strspn(str1, str2):
79 if str2.find(char) == -1:
85 def intparse(statestr, defmask="0xffffffff"):
86 totalparse = strspn(statestr, "0123456789abcdefABCDEFx/")
88 count = strspn(statestr, "x0123456789abcdefABCDEF")
90 firstnum = statestr[:count]
91 if firstnum[-1] == "/":
92 firstnum = firstnum[:-1]
96 if defmask is not None:
98 if statestr[count] == "/":
99 secondnum = statestr[count + 1 :] # this is wrong...
100 m = int(secondnum, 0)
102 return statestr[totalparse + 1 :], k, m
105 def parse_flags(flag_str, flag_vals):
109 if len(flag_str) == 0:
110 return flag_str, bitResult, maskResult
112 if flag_str[0].isdigit():
114 while flag_str[idx].isdigit() or flag_str[idx] == "x":
116 digits = flag_str[:idx]
117 flag_str = flag_str[idx:]
119 bitResult = int(digits, 0)
120 maskResult = int(digits, 0)
122 while len(flag_str) > 0 and (flag_str[0] == "+" or flag_str[0] == "-"):
123 if flag_str[0] == "+":
125 elif flag_str[0] == "-":
128 flag_str = flag_str[1:]
132 flag_str[flag_len] != "+"
133 and flag_str[flag_len] != "-"
134 and flag_str[flag_len] != ","
135 and flag_str[flag_len] != ")"
139 flag = flag_str[0:flag_len]
141 if flag in flag_vals:
142 if maskResult & flag_vals[flag]:
144 "Flag %s set once, cannot be set in multiples" % flag
148 bitResult |= flag_vals[flag]
150 maskResult |= flag_vals[flag]
152 raise KeyError("Missing flag value: %s" % flag)
154 flag_str = flag_str[flag_len:]
156 return flag_str, bitResult, maskResult
159 def parse_ct_state(statestr):
171 return parse_flags(statestr, ct_flags)
174 def convert_mac(data):
176 mac_split = mac.split(":")
177 ret = bytearray([int(i, 16) for i in mac_split])
180 mac_str, _, mask_str = data.partition('/')
183 mac_str = mask_str = "00:00:00:00:00:00"
185 mask_str = "FF:FF:FF:FF:FF:FF"
187 return to_bytes(mac_str), to_bytes(mask_str)
189 def convert_ipv4(data):
190 ip, _, mask = data.partition('/')
197 mask = (0xFFFFFFFF << (32 - int(mask))) & 0xFFFFFFFF
199 return int(ipaddress.IPv4Address(ip)), int(ipaddress.IPv4Address(mask))
201 def convert_int(size):
202 def convert_int_sized(data):
203 value, _, mask = data.partition('/')
208 return int(value, 0), pow(2, size) - 1
210 return int(value, 0), int(mask, 0)
212 return convert_int_sized
214 def parse_starts_block(block_str, scanstr, returnskipped, scanregex=False):
216 m = re.search(scanstr, block_str)
222 block_str = block_str[len(m.group(0)) :]
226 if block_str.startswith(scanstr):
228 block_str = block_str[len(scanstr) :]
238 def parse_extract_field(
239 block_str, fieldstr, scanfmt, convert, masked=False, defval=None
241 if fieldstr and not block_str.startswith(fieldstr):
242 return block_str, defval
245 str_skiplen = len(fieldstr)
246 str_skipped = block_str[str_skiplen:]
248 return str_skipped, defval
251 str_skipped = block_str
253 m = re.search(scanfmt, str_skipped)
255 raise ValueError("Bad fmt string")
259 data = convert(m.group(0))
261 str_skipped = str_skipped[len(m.group(0)) :]
263 if str_skipped[0] == "/":
264 raise ValueError("Masking support TBD...")
266 str_skipped = str_skipped[strspn(str_skipped, ", ") :]
267 return str_skipped, data
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"),)
278 class ovsactions(nla):
279 nla_flags = NLA_F_NESTED
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"),
310 nla_flags = NLA_F_NESTED
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"),
326 nla_flags = NLA_F_NESTED
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"),
341 def dpstr(self, more=False):
344 if self.get_attr("OVS_NAT_ATTR_SRC"):
346 elif self.get_attr("OVS_NAT_ATTR_DST"):
349 print_str += "XXX-unknown-nat"
351 if self.get_attr("OVS_NAT_ATTR_IP_MIN") or self.get_attr(
352 "OVS_NAT_ATTR_IP_MAX"
354 if self.get_attr("OVS_NAT_ATTR_IP_MIN"):
355 print_str += "=%s," % str(
356 self.get_attr("OVS_NAT_ATTR_IP_MIN")
359 if self.get_attr("OVS_NAT_ATTR_IP_MAX"):
360 print_str += "-%s," % str(
361 self.get_attr("OVS_NAT_ATTR_IP_MAX")
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"
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"
376 if self.get_attr("OVS_NAT_ATTR_PERSISTENT"):
377 print_str += "persistent,"
378 if self.get_attr("OVS_NAT_ATTR_HASH"):
380 if self.get_attr("OVS_NAT_ATTR_RANDOM"):
381 print_str += "random"
385 def dpstr(self, more=False):
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)
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"
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"
410 class userspace(nla):
411 nla_flags = NLA_F_NESTED
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"),
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"
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"
437 def dpstr(self, more=False):
440 for field in self.nla_map:
441 if field[1] == "none" or self.get_attr(field[0]) is None:
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"
467 datum = self.get_attr(field[0])
468 print_str += datum.dpstr(more)
472 def parse(self, actstr):
473 while len(actstr) != 0:
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(
486 if reason is not None:
487 self["attrs"].append(["OVS_ACTION_ATTR_DROP", reason])
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"
496 self["attrs"].append(["OVS_ACTION_ATTR_OUTPUT", output])
498 elif parse_starts_block(actstr, "recirc(", False):
499 actstr, recircid = parse_extract_field(
507 self["attrs"].append(["OVS_ACTION_ATTR_RECIRC", recircid])
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"),
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, ", ") :]
524 if parse_starts_block(actstr, "ct(", False):
525 actstr = actstr[len("ct(") :]
526 ctact = ovsactions.ctact()
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)),
536 if actstr.startswith(scan[0]):
537 actstr = actstr[len(scan[0]) :]
538 if scan[2] is not None:
540 raise ValueError("Invalid ct attr")
542 pos = strcspn(actstr, ",)")
543 datum = scan[2](actstr[:pos], 0)
544 ctact["attrs"].append([scan[1], datum])
545 actstr = actstr[pos:]
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"):
553 natact = ovsactions.ctact.natattr()
555 if actstr.startswith("("):
558 if actstr.startswith("src"):
559 t = "OVS_NAT_ATTR_SRC"
561 elif actstr.startswith("dst"):
562 t = "OVS_NAT_ATTR_DST"
565 actstr, ip_block_min = parse_extract_field(
566 actstr, "=", "([0-9a-fA-F\.]+)", str, False
568 actstr, ip_block_max = parse_extract_field(
569 actstr, "-", "([0-9a-fA-F\.]+)", str, False
572 actstr, proto_min = parse_extract_field(
573 actstr, ":", "(\d+)", int, False
575 actstr, proto_max = parse_extract_field(
576 actstr, "-", "(\d+)", int, False
580 natact["attrs"].append([t, None])
582 if ip_block_min is not None:
583 natact["attrs"].append(
584 ["OVS_NAT_ATTR_IP_MIN", ip_block_min]
586 if ip_block_max is not None:
587 natact["attrs"].append(
588 ["OVS_NAT_ATTR_IP_MAX", ip_block_max]
590 if proto_min is not None:
591 natact["attrs"].append(
592 ["OVS_NAT_ATTR_PROTO_MIN", proto_min]
594 if proto_max is not None:
595 natact["attrs"].append(
596 ["OVS_NAT_ATTR_PROTO_MAX", proto_max]
600 ("persistent", "OVS_NAT_ATTR_PERSISTENT"),
601 ("hash", "OVS_NAT_ATTR_PROTO_HASH"),
602 ("random", "OVS_NAT_ATTR_PROTO_RANDOM"),
604 if actstr.startswith(natscan[0]):
605 actstr = actstr[len(natscan[0]) :]
606 natact["attrs"].append([natscan[1], None])
607 actstr = actstr[strspn(actstr, ", ") :]
609 ctact["attrs"].append(["OVS_CT_ATTR_NAT", natact])
610 actstr = actstr[strspn(actstr, ",) ") :]
612 self["attrs"].append(["OVS_ACTION_ATTR_CT", ctact])
615 actstr = actstr[strspn(actstr, "), ") :]
617 raise ValueError("Action str: '%s' not supported" % actstr)
621 nla_flags = NLA_F_NESTED
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"),
658 class ovs_key_proto(nla):
665 ("src", "src", "%d", lambda x: int(x) if x else 0,
667 ("dst", "dst", "%d", lambda x: int(x) if x else 0,
680 self.proto_str = protostr
690 def parse(self, flowstr, typeInst):
691 if not flowstr.startswith(self.proto_str):
697 flowstr = flowstr[len(self.proto_str) :]
698 if flowstr.startswith("("):
699 flowstr = flowstr[1:]
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 :]
711 if c == "," or c == ")":
714 data = flowstr[:splitchar]
715 flowstr = flowstr[splitchar:]
720 k[f[0]], m[f[0]] = f[4](data)
725 flowstr = flowstr[strspn(flowstr, ", ") :]
726 if len(flowstr) == 0:
729 flowstr = flowstr[strspn(flowstr, "), ") :]
733 def dpstr(self, masked=None, more=False):
734 outstr = self.proto_str + "("
736 for f in self.fields_map:
740 outstr += "%s=" % f[0]
741 if isinstance(f[2], str):
742 outstr += f[2] % self[f[1]]
744 outstr += f[2](self[f[1]])
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]]
751 outstr += f[2](self[f[1]])
753 if isinstance(f[2], str):
754 outstr += f[2] % masked[f[1]]
756 outstr += f[2](masked[f[1]])
761 class ethaddr(ovs_key_proto):
772 lambda x: int.from_bytes(x, "big"),
779 lambda x: int.from_bytes(x, "big"),
792 ovskey.ovs_key_proto.__init__(
802 class ovs_key_ipv4(ovs_key_proto):
816 lambda x: str(ipaddress.IPv4Address(x)),
823 lambda x: str(ipaddress.IPv4Address(x)),
827 ("proto", "proto", "%d", lambda x: int(x) if x else 0,
829 ("tos", "tos", "%d", lambda x: int(x) if x else 0,
831 ("ttl", "ttl", "%d", lambda x: int(x) if x else 0,
833 ("frag", "frag", "%d", lambda x: int(x) if x else 0,
845 ovskey.ovs_key_proto.__init__(
855 class ovs_key_ipv6(ovs_key_proto):
870 lambda x: str(ipaddress.IPv6Address(x)),
871 lambda x: int.from_bytes(x, "big"),
872 lambda x: ipaddress.IPv6Address(x),
877 lambda x: str(ipaddress.IPv6Address(x)),
878 lambda x: int.from_bytes(x, "big"),
879 lambda x: ipaddress.IPv6Address(x),
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),
896 ovskey.ovs_key_proto.__init__(
906 class ovs_key_tcp(ovs_key_proto):
915 ovskey.ovs_key_proto.__init__(
925 class ovs_key_udp(ovs_key_proto):
934 ovskey.ovs_key_proto.__init__(
944 class ovs_key_sctp(ovs_key_proto):
953 ovskey.ovs_key_proto.__init__(
963 class ovs_key_icmp(ovs_key_proto):
970 ("type", "type", "%d", lambda x: int(x) if x else 0),
971 ("code", "code", "%d", lambda x: int(x) if x else 0),
982 ovskey.ovs_key_proto.__init__(
992 class ovs_key_icmpv6(ovs_key_icmp):
1001 ovskey.ovs_key_proto.__init__(
1011 class ovs_key_arp(ovs_key_proto):
1025 lambda x: str(ipaddress.IPv4Address(x)),
1032 lambda x: str(ipaddress.IPv4Address(x)),
1036 ("op", "op", "%d", lambda x: int(x) if x else 0),
1041 lambda x: int.from_bytes(x, "big"),
1048 lambda x: int.from_bytes(x, "big"),
1061 ovskey.ovs_key_proto.__init__(
1071 class ovs_key_nd(ovs_key_proto):
1082 lambda x: str(ipaddress.IPv6Address(x)),
1083 lambda x: int.from_bytes(x, "big"),
1085 ("sll", "sll", macstr, lambda x: int.from_bytes(x, "big")),
1086 ("tll", "tll", macstr, lambda x: int.from_bytes(x, "big")),
1097 ovskey.ovs_key_proto.__init__(
1107 class ovs_key_ct_tuple_ipv4(ovs_key_proto):
1120 lambda x: str(ipaddress.IPv4Address(x)),
1127 lambda x: str(ipaddress.IPv4Address(x)),
1131 ("tp_src", "tp_src", "%d", int),
1132 ("tp_dst", "tp_dst", "%d", int),
1133 ("proto", "proto", "%d", int),
1144 ovskey.ovs_key_proto.__init__(
1154 class ovs_key_ct_tuple_ipv6(nla):
1167 lambda x: str(ipaddress.IPv6Address(x)),
1168 lambda x: int.from_bytes(x, "big", convertmac),
1173 lambda x: str(ipaddress.IPv6Address(x)),
1174 lambda x: int.from_bytes(x, "big"),
1176 ("tp_src", "tp_src", "%d", int),
1177 ("tp_dst", "tp_dst", "%d", int),
1178 ("proto", "proto", "%d", int),
1189 ovskey.ovs_key_proto.__init__(
1199 class ovs_key_mpls(nla):
1200 fields = (("lse", ">I"),)
1202 def parse(self, flowstr, mask=None):
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),
1213 "OVS_KEY_ATTR_ETHERNET",
1218 "OVS_KEY_ATTR_ETHERTYPE",
1220 lambda x: intparse(x, "0xffff"),
1223 "OVS_KEY_ATTR_IPV4",
1225 ovskey.ovs_key_ipv4,
1228 "OVS_KEY_ATTR_IPV6",
1230 ovskey.ovs_key_ipv6,
1248 "OVS_KEY_ATTR_ICMP",
1250 ovskey.ovs_key_icmp,
1253 "OVS_KEY_ATTR_TCP_FLAGS",
1255 lambda x: parse_flags(x, None),
1258 fld = field[1] + "("
1259 if not flowstr.startswith(fld):
1262 if not isinstance(field[2], types.FunctionType):
1264 flowstr, k, m = nk.parse(flowstr, field[2])
1266 flowstr = flowstr[len(fld) :]
1267 flowstr, k, m = field[2](flowstr)
1269 if m and mask is not None:
1270 mask["attrs"].append([field[0], m])
1271 self["attrs"].append([field[0], k])
1273 flowstr = flowstr[strspn(flowstr, "),") :]
1277 def dpstr(self, mask=None, more=False):
1282 "OVS_KEY_ATTR_PRIORITY",
1289 "OVS_KEY_ATTR_SKB_MARK",
1296 "OVS_KEY_ATTR_RECIRC_ID",
1303 "OVS_KEY_ATTR_DP_HASH",
1310 "OVS_KEY_ATTR_CT_STATE",
1317 "OVS_KEY_ATTR_CT_ZONE",
1324 "OVS_KEY_ATTR_CT_MARK",
1331 "OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4",
1338 "OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6",
1345 "OVS_KEY_ATTR_IN_PORT",
1351 ("OVS_KEY_ATTR_ETHERNET", None, None, False, False),
1353 "OVS_KEY_ATTR_ETHERTYPE",
1356 lambda x: int(x) == 0xFFFF,
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),
1364 "OVS_KEY_ATTR_TCP_FLAGS",
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),
1376 v = self.get_attr(field[0])
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)
1383 if m is None or field[3](m):
1384 print_str += field[1] + "("
1385 print_str += field[2] % v
1387 elif more or m != 0:
1388 print_str += field[1] + "("
1389 print_str += (field[2] % v) + "/" + (field[2] % m)
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
1400 class ovs_packet_msg(ovs_dp_msg):
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"),
1417 GenericNetlinkSocket.__init__(self)
1418 self.bind(OVS_PACKET_FAMILY, OvsPacket.ovs_packet_msg)
1420 def upcall_handler(self, up=None):
1421 print("listening on upcall packet handler:", self.epid)
1428 if msg["cmd"] == OvsPacket.OVS_PACKET_CMD_MISS:
1430 elif msg["cmd"] == OvsPacket.OVS_PACKET_CMD_ACTION:
1432 elif msg["cmd"] == OvsPacket.OVS_PACKET_CMD_EXECUTE:
1435 print("Unkonwn cmd: %d" % msg["cmd"])
1436 except NetlinkError as ne:
1440 class OvsDatapath(GenericNetlinkSocket):
1441 OVS_DP_F_VPORT_PIDS = 1 << 1
1442 OVS_DP_F_DISPATCH_UPCALL_PER_CPU = 1 << 3
1444 class dp_cmd_msg(ovs_dp_msg):
1446 Message class that will be used to communicate with the kernel module.
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)"),
1469 class megaflowstats(nla):
1474 ("cache_hits", "=Q"),
1479 GenericNetlinkSocket.__init__(self)
1480 self.bind(OVS_DATAPATH_FAMILY, OvsDatapath.dp_cmd_msg)
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
1487 msg["dpifindex"] = ifindex
1488 msg["attrs"].append(["OVS_DP_ATTR_NAME", dpname])
1491 reply = self.nlm_request(
1492 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST
1495 except NetlinkError as ne:
1496 if ne.code == errno.ENODEV:
1504 self, dpname, shouldUpcall=False, versionStr=None, p=OvsPacket()
1506 msg = OvsDatapath.dp_cmd_msg()
1507 msg["cmd"] = OVS_DP_CMD_NEW
1508 if versionStr is None:
1509 msg["version"] = OVS_DATAPATH_VERSION
1511 msg["version"] = int(versionStr.split(":")[0], 0)
1513 msg["dpifindex"] = 0
1514 msg["attrs"].append(["OVS_DP_ATTR_NAME", dpname])
1517 if versionStr is not None and versionStr.find(":") != -1:
1518 dpfeatures = int(versionStr.split(":")[1], 0)
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
1524 nproc = multiprocessing.cpu_count()
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]])
1534 reply = self.nlm_request(
1535 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK
1538 except NetlinkError as ne:
1539 if ne.code == errno.EEXIST:
1546 def destroy(self, dpname):
1547 msg = OvsDatapath.dp_cmd_msg()
1548 msg["cmd"] = OVS_DP_CMD_DEL
1549 msg["version"] = OVS_DATAPATH_VERSION
1551 msg["dpifindex"] = 0
1552 msg["attrs"].append(["OVS_DP_ATTR_NAME", dpname])
1555 reply = self.nlm_request(
1556 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK
1559 except NetlinkError as ne:
1560 if ne.code == errno.ENODEV:
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
1575 class ovs_vport_msg(ovs_dp_msg):
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"),
1589 class vportstats(nla):
1591 ("rx_packets", "=Q"),
1592 ("tx_packets", "=Q"),
1595 ("rx_errors", "=Q"),
1596 ("tx_errors", "=Q"),
1597 ("rx_dropped", "=Q"),
1598 ("tx_dropped", "=Q"),
1601 def type_to_str(vport_type):
1602 if vport_type == OvsVport.OVS_VPORT_TYPE_NETDEV:
1604 elif vport_type == OvsVport.OVS_VPORT_TYPE_INTERNAL:
1606 elif vport_type == OvsVport.OVS_VPORT_TYPE_GRE:
1608 elif vport_type == OvsVport.OVS_VPORT_TYPE_VXLAN:
1610 elif vport_type == OvsVport.OVS_VPORT_TYPE_GENEVE:
1612 raise ValueError("Unknown vport type:%d" % vport_type)
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)
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
1632 def info(self, vport_name, dpifindex=0, portno=None):
1633 msg = OvsVport.ovs_vport_msg()
1635 msg["cmd"] = OVS_VPORT_CMD_GET
1636 msg["version"] = OVS_DATAPATH_VERSION
1638 msg["dpifindex"] = dpifindex
1641 msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_name])
1643 msg["attrs"].append(["OVS_VPORT_ATTR_PORT_NO", portno])
1646 reply = self.nlm_request(
1647 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST
1650 except NetlinkError as ne:
1651 if ne.code == errno.ENODEV:
1657 def attach(self, dpindex, vport_ifname, ptype):
1658 msg = OvsVport.ovs_vport_msg()
1660 msg["cmd"] = OVS_VPORT_CMD_NEW
1661 msg["version"] = OVS_DATAPATH_VERSION
1663 msg["dpifindex"] = dpindex
1664 port_type = OvsVport.str_to_type(ptype)
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]]
1673 reply = self.nlm_request(
1674 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK
1677 except NetlinkError as ne:
1678 if ne.code == errno.EEXIST:
1684 def reset_upcall(self, dpindex, vport_ifname, p=None):
1685 msg = OvsVport.ovs_vport_msg()
1687 msg["cmd"] = OVS_VPORT_CMD_SET
1688 msg["version"] = OVS_DATAPATH_VERSION
1690 msg["dpifindex"] = dpindex
1691 msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_ifname])
1694 p = self.upcall_packet
1696 self.upcall_packet = p
1698 msg["attrs"].append(["OVS_VPORT_ATTR_UPCALL_PID", [p.epid]])
1701 reply = self.nlm_request(
1702 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK
1705 except NetlinkError as ne:
1709 def detach(self, dpindex, vport_ifname):
1710 msg = OvsVport.ovs_vport_msg()
1712 msg["cmd"] = OVS_VPORT_CMD_DEL
1713 msg["version"] = OVS_DATAPATH_VERSION
1715 msg["dpifindex"] = dpindex
1716 msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_ifname])
1719 reply = self.nlm_request(
1720 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK
1723 except NetlinkError as ne:
1724 if ne.code == errno.ENODEV:
1730 def upcall_handler(self, handler=None):
1731 self.upcall_packet.upcall_handler(handler)
1734 class OvsFlow(GenericNetlinkSocket):
1735 class ovs_flow_msg(ovs_dp_msg):
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"),
1750 class flowstats(nla):
1756 def dpstr(self, more=False):
1757 ufid = self.get_attr("OVS_FLOW_ATTR_UFID")
1759 if ufid is not None:
1761 "ufid:{:08x}-{:04x}-{:04x}-{:04x}-{:04x}{:08x}".format(
1771 key_field = self.get_attr("OVS_FLOW_ATTR_KEY")
1773 if key_field is not None:
1776 mask_field = self.get_attr("OVS_FLOW_ATTR_MASK")
1778 if mask_field is not None:
1779 maskmsg = mask_field
1781 acts_field = self.get_attr("OVS_FLOW_ATTR_ACTIONS")
1783 if acts_field is not None:
1784 actsmsg = acts_field
1789 print_str += ufid_str + ","
1791 if keymsg is not None:
1792 print_str += keymsg.dpstr(maskmsg, more)
1794 stats = self.get_attr("OVS_FLOW_ATTR_STATS")
1796 print_str += " packets:0, bytes:0,"
1798 print_str += " packets:%d, bytes:%d," % (
1803 used = self.get_attr("OVS_FLOW_ATTR_USED")
1804 print_str += " used:"
1806 print_str += "never,"
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)
1813 print_str += " actions:"
1816 or "attrs" not in actsmsg
1817 or len(actsmsg["attrs"]) == 0
1821 print_str += actsmsg.dpstr(more)
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
1832 self["reserved"] = 0
1833 self["dpifindex"] = 0
1835 if flowstr.startswith("ufid:"):
1837 while flowstr[count] != ",":
1839 ufidstr = flowstr[5:count]
1840 flowstr = flowstr[count + 1 :]
1842 ufidstr = str(uuid.uuid4())
1843 uuidRawObj = uuid.UUID(ufidstr).fields
1845 self["attrs"].append(
1847 "OVS_FLOW_ATTR_UFID",
1850 uuidRawObj[1] << 16 | uuidRawObj[2],
1852 | uuidRawObj[4] << 16
1853 | uuidRawObj[5] & (0xFF << 32) >> 32,
1854 uuidRawObj[5] & (0xFFFFFFFF),
1858 self["attrs"].append(
1860 "OVS_FLOW_ATTR_UFID_FLAGS",
1863 | OVS_UFID_F_OMIT_MASK
1864 | OVS_UFID_F_OMIT_ACTIONS
1872 self["attrs"].append(["OVS_FLOW_ATTR_KEY", k])
1873 self["attrs"].append(["OVS_FLOW_ATTR_MASK", m])
1877 self["attrs"].append(["OVS_FLOW_ATTR_ACTIONS", a])
1880 GenericNetlinkSocket.__init__(self)
1882 self.bind(OVS_FLOW_FAMILY, OvsFlow.ovs_flow_msg)
1884 def add_flow(self, dpifindex, flowmsg):
1886 Send a new flow message to the kernel.
1888 dpifindex should be a valid datapath obtained by calling
1889 into the OvsDatapath lookup
1891 flowmsg is a flow object obtained by calling a dpparse
1894 flowmsg["cmd"] = OVS_FLOW_CMD_NEW
1895 flowmsg["version"] = OVS_DATAPATH_VERSION
1896 flowmsg["reserved"] = 0
1897 flowmsg["dpifindex"] = dpifindex
1900 reply = self.nlm_request(
1903 msg_flags=NLM_F_REQUEST | NLM_F_ACK,
1906 except NetlinkError as ne:
1911 def del_flows(self, dpifindex):
1913 Send a del message to the kernel that will drop all flows.
1915 dpifindex should be a valid datapath obtained by calling
1916 into the OvsDatapath lookup
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
1926 reply = self.nlm_request(
1929 msg_flags=NLM_F_REQUEST | NLM_F_ACK,
1932 except NetlinkError as ne:
1937 def dump(self, dpifindex, flowspec=None):
1939 Returns a list of messages containing flows.
1941 dpifindex should be a valid datapath obtained by calling
1942 into the OvsDatapath lookup
1944 flowpsec is a string which represents a flow in the dpctl
1947 msg = OvsFlow.ovs_flow_msg()
1949 msg["cmd"] = OVS_FLOW_CMD_GET
1950 msg["version"] = OVS_DATAPATH_VERSION
1952 msg["dpifindex"] = dpifindex
1954 msg_flags = NLM_F_REQUEST | NLM_F_ACK
1955 if flowspec is None:
1956 msg_flags |= NLM_F_DUMP
1960 rep = self.nlm_request(
1963 msg_flags=msg_flags,
1965 except NetlinkError as ne:
1969 def miss(self, packetmsg):
1970 seq = packetmsg["header"]["sequence_number"]
1972 key_field = packetmsg.get_attr("OVS_PACKET_ATTR_KEY")
1973 if key_field is not None:
1974 keystr = key_field.dpstr(None, True)
1976 pktdata = packetmsg.get_attr("OVS_PACKET_ATTR_PACKET")
1977 pktpres = "yes" if pktdata is not None else "no"
1979 print("MISS upcall[%d/%s]: %s" % (seq, pktpres, keystr), flush=True)
1981 def execute(self, packetmsg):
1982 print("userspace execute command")
1984 def action(self, packetmsg):
1985 print("userspace action command")
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")
1995 print("%s:" % dp_name)
1997 " lookups: hit:%d missed:%d lost:%d"
1998 % (base_stats["hit"], base_stats["missed"], base_stats["lost"])
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
2004 " masks: hit:%d total:%d hit/pkt:%f"
2005 % (megaflow_stats["mask_hit"], megaflow_stats["masks"], avg)
2008 print(" masks-cache: size:%d" % masks_cache_size)
2010 if user_features is not None:
2011 print(" features: 0x%X" % user_features)
2014 for iface in ndb.interfaces:
2015 rep = vpl.info(iface.ifname, ifindex)
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")),
2028 nlmsg_atoms.ovskey = ovskey
2029 nlmsg_atoms.ovsactions = ovsactions
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.")
2037 parser = argparse.ArgumentParser()
2038 parser.add_argument(
2042 help="Increment 'verbose' output counter.",
2045 subparsers = parser.add_subparsers()
2047 showdpcmd = subparsers.add_parser("show")
2048 showdpcmd.add_argument(
2049 "showdp", metavar="N", type=str, nargs="?", help="Datapath Name"
2052 adddpcmd = subparsers.add_parser("add-dp")
2053 adddpcmd.add_argument("adddp", help="Datapath Name")
2054 adddpcmd.add_argument(
2057 action="store_true",
2058 help="Leave open a reader for upcalls",
2060 adddpcmd.add_argument(
2064 help="Specify a custom version / feature string",
2067 deldpcmd = subparsers.add_parser("del-dp")
2068 deldpcmd.add_argument("deldp", help="Datapath Name")
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(
2076 action="store_true",
2077 help="Leave open a reader for upcalls",
2079 addifcmd.add_argument(
2084 choices=["netdev", "internal"],
2085 help="Interface type (default netdev)",
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")
2091 dumpflcmd = subparsers.add_parser("dump-flows")
2092 dumpflcmd.add_argument("dumpdp", help="Datapath Name")
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")
2099 delfscmd = subparsers.add_parser("del-flows")
2100 delfscmd.add_argument("flsbr", help="Datapath name")
2102 args = parser.parse_args()
2104 if args.verbose > 0:
2105 if args.verbose > 1:
2106 logging.basicConfig(level=logging.DEBUG)
2109 ovsdp = OvsDatapath()
2110 ovsvp = OvsVport(ovspk)
2114 if hasattr(args, "showdp"):
2116 for iface in ndb.interfaces:
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)
2125 print_ovsdp_full(rep, iface.index, ndb, ovsvp)
2129 if args.showdp is not None:
2130 msg += ":'%s'" % args.showdp
2132 elif hasattr(args, "adddp"):
2133 rep = ovsdp.create(args.adddp, args.upcall, args.versioning, ovspk)
2135 print("DP '%s' already exists" % args.adddp)
2137 print("DP '%s' added" % args.adddp)
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)
2145 print("DP '%s' not found." % args.dpname)
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:
2153 msg += " failed to add."
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)
2161 print("DP '%s' not found." % args.dpname)
2163 rep = ovsvp.detach(rep["dpifindex"], args.delif)
2164 msg = "vport '%s'" % args.delif
2165 if rep and rep["header"]["error"] is None:
2168 msg += " failed to remove."
2169 elif hasattr(args, "dumpdp"):
2170 rep = ovsdp.info(args.dumpdp, 0)
2172 print("DP '%s' not found." % args.dumpdp)
2174 rep = ovsflow.dump(rep["dpifindex"])
2176 print(flow.dpstr(True if args.verbose > 0 else False))
2177 elif hasattr(args, "flbr"):
2178 rep = ovsdp.info(args.flbr, 0)
2180 print("DP '%s' not found." % args.flbr)
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)
2188 print("DP '%s' not found." % args.flsbr)
2189 ovsflow.del_flows(rep["dpifindex"])
2194 if __name__ == "__main__":
2195 sys.exit(main(sys.argv))