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.
12 import multiprocessing
22 from pyroute2 import NDB
24 from pyroute2.netlink import NLA_F_NESTED
25 from pyroute2.netlink import NLM_F_ACK
26 from pyroute2.netlink import NLM_F_DUMP
27 from pyroute2.netlink import NLM_F_REQUEST
28 from pyroute2.netlink import genlmsg
29 from pyroute2.netlink import nla
30 from pyroute2.netlink import nlmsg_atoms
31 from pyroute2.netlink.event import EventSocket
32 from pyroute2.netlink.exceptions import NetlinkError
33 from pyroute2.netlink.generic import GenericNetlinkSocket
34 from pyroute2.netlink.nlsocket import Marshal
36 import pyroute2.iproute
38 except ModuleNotFoundError:
39 print("Need to install the python pyroute2 package >= 0.6.")
43 OVS_DATAPATH_FAMILY = "ovs_datapath"
44 OVS_VPORT_FAMILY = "ovs_vport"
45 OVS_FLOW_FAMILY = "ovs_flow"
46 OVS_PACKET_FAMILY = "ovs_packet"
47 OVS_METER_FAMILY = "ovs_meter"
48 OVS_CT_LIMIT_FAMILY = "ovs_ct_limit"
50 OVS_DATAPATH_VERSION = 2
66 UINT32_MAX = 0xFFFFFFFF
69 outstr = ":".join(["%02X" % i for i in mac])
73 def strcspn(str1, str2):
76 if str2.find(char) != -1:
82 def strspn(str1, str2):
85 if str2.find(char) == -1:
91 def intparse(statestr, defmask="0xffffffff"):
92 totalparse = strspn(statestr, "0123456789abcdefABCDEFx/")
94 count = strspn(statestr, "x0123456789abcdefABCDEF")
96 firstnum = statestr[:count]
97 if firstnum[-1] == "/":
98 firstnum = firstnum[:-1]
102 if defmask is not None:
104 if statestr[count] == "/":
105 secondnum = statestr[count + 1 :] # this is wrong...
106 m = int(secondnum, 0)
108 return statestr[totalparse + 1 :], k, m
111 def parse_flags(flag_str, flag_vals):
115 if len(flag_str) == 0:
116 return flag_str, bitResult, maskResult
118 if flag_str[0].isdigit():
120 while flag_str[idx].isdigit() or flag_str[idx] == "x":
122 digits = flag_str[:idx]
123 flag_str = flag_str[idx:]
125 bitResult = int(digits, 0)
126 maskResult = int(digits, 0)
128 while len(flag_str) > 0 and (flag_str[0] == "+" or flag_str[0] == "-"):
129 if flag_str[0] == "+":
131 elif flag_str[0] == "-":
134 flag_str = flag_str[1:]
138 flag_str[flag_len] != "+"
139 and flag_str[flag_len] != "-"
140 and flag_str[flag_len] != ","
141 and flag_str[flag_len] != ")"
145 flag = flag_str[0:flag_len]
147 if flag in flag_vals:
148 if maskResult & flag_vals[flag]:
150 "Flag %s set once, cannot be set in multiples" % flag
154 bitResult |= flag_vals[flag]
156 maskResult |= flag_vals[flag]
158 raise KeyError("Missing flag value: %s" % flag)
160 flag_str = flag_str[flag_len:]
162 return flag_str, bitResult, maskResult
165 def parse_ct_state(statestr):
177 return parse_flags(statestr, ct_flags)
180 def convert_mac(data):
182 mac_split = mac.split(":")
183 ret = bytearray([int(i, 16) for i in mac_split])
186 mac_str, _, mask_str = data.partition('/')
189 mac_str = mask_str = "00:00:00:00:00:00"
191 mask_str = "FF:FF:FF:FF:FF:FF"
193 return to_bytes(mac_str), to_bytes(mask_str)
195 def convert_ipv4(data):
196 ip, _, mask = data.partition('/')
203 mask = (0xFFFFFFFF << (32 - int(mask))) & 0xFFFFFFFF
205 return int(ipaddress.IPv4Address(ip)), int(ipaddress.IPv4Address(mask))
207 def convert_ipv6(data):
208 ip, _, mask = data.partition('/')
213 mask = 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'
215 mask = ipaddress.IPv6Network("::/" + mask).hostmask
217 return ipaddress.IPv6Address(ip).packed, ipaddress.IPv6Address(mask).packed
219 def convert_int(size):
220 def convert_int_sized(data):
221 value, _, mask = data.partition('/')
226 return int(value, 0), pow(2, size) - 1
228 return int(value, 0), int(mask, 0)
230 return convert_int_sized
232 def parse_starts_block(block_str, scanstr, returnskipped, scanregex=False):
234 m = re.search(scanstr, block_str)
240 block_str = block_str[len(m.group(0)) :]
244 if block_str.startswith(scanstr):
246 block_str = block_str[len(scanstr) :]
256 def parse_extract_field(
257 block_str, fieldstr, scanfmt, convert, masked=False, defval=None
259 if fieldstr and not block_str.startswith(fieldstr):
260 return block_str, defval
263 str_skiplen = len(fieldstr)
264 str_skipped = block_str[str_skiplen:]
266 return str_skipped, defval
269 str_skipped = block_str
271 m = re.search(scanfmt, str_skipped)
273 raise ValueError("Bad fmt string")
277 data = convert(m.group(0))
279 str_skipped = str_skipped[len(m.group(0)) :]
281 if str_skipped[0] == "/":
282 raise ValueError("Masking support TBD...")
284 str_skipped = str_skipped[strspn(str_skipped, ", ") :]
285 return str_skipped, data
288 def parse_attrs(actstr, attr_desc):
289 """Parses the given action string and returns a list of netlink
290 attributes based on a list of attribute descriptions.
292 Each element in the attribute description list is a tuple such as:
293 (name, attr_name, parse_func)
295 name: is the string representing the attribute
296 attr_name: is the name of the attribute as defined in the uAPI.
297 parse_func: is a callable accepting a string and returning either
298 a single object (the parsed attribute value) or a tuple of
299 two values (the parsed attribute value and the remaining string)
301 Returns a list of attributes and the remaining string.
303 def parse_attr(actstr, key, func):
304 actstr = actstr[len(key) :]
313 pos = strcspn(actstr, ",)")
314 ret = func(actstr[:pos])
318 if isinstance(ret, tuple):
319 (datum, actstr) = ret
322 actstr = actstr[strcspn(actstr, ",)"):]
325 if not actstr or actstr[0] != ")":
326 raise ValueError("Action contains unbalanced parentheses")
330 actstr = actstr[strspn(actstr, ", ") :]
335 attr_desc = list(attr_desc)
336 while actstr and actstr[0] != ")" and attr_desc:
338 for i, (key, attr, func) in enumerate(attr_desc):
339 if actstr.startswith(key):
340 datum, actstr = parse_attr(actstr, key, func)
341 attrs.append([attr, datum])
346 raise ValueError("Unknown attribute: '%s'" % actstr)
348 actstr = actstr[strspn(actstr, ", ") :]
351 raise ValueError("Action string contains extra garbage or has "
352 "unbalanced parenthesis: '%s'" % actstr)
354 return attrs, actstr[1:]
357 class ovs_dp_msg(genlmsg):
358 # include the OVS version
359 # We need a custom header rather than just being able to rely on
360 # genlmsg because fields ends up not expressing everything correctly
361 # if we use the canonical example of setting fields = (('customfield',),)
362 fields = genlmsg.fields + (("dpifindex", "I"),)
365 class ovsactions(nla):
366 nla_flags = NLA_F_NESTED
369 ("OVS_ACTION_ATTR_UNSPEC", "none"),
370 ("OVS_ACTION_ATTR_OUTPUT", "uint32"),
371 ("OVS_ACTION_ATTR_USERSPACE", "userspace"),
372 ("OVS_ACTION_ATTR_SET", "ovskey"),
373 ("OVS_ACTION_ATTR_PUSH_VLAN", "none"),
374 ("OVS_ACTION_ATTR_POP_VLAN", "flag"),
375 ("OVS_ACTION_ATTR_SAMPLE", "sample"),
376 ("OVS_ACTION_ATTR_RECIRC", "uint32"),
377 ("OVS_ACTION_ATTR_HASH", "none"),
378 ("OVS_ACTION_ATTR_PUSH_MPLS", "none"),
379 ("OVS_ACTION_ATTR_POP_MPLS", "flag"),
380 ("OVS_ACTION_ATTR_SET_MASKED", "ovskey"),
381 ("OVS_ACTION_ATTR_CT", "ctact"),
382 ("OVS_ACTION_ATTR_TRUNC", "uint32"),
383 ("OVS_ACTION_ATTR_PUSH_ETH", "none"),
384 ("OVS_ACTION_ATTR_POP_ETH", "flag"),
385 ("OVS_ACTION_ATTR_CT_CLEAR", "flag"),
386 ("OVS_ACTION_ATTR_PUSH_NSH", "none"),
387 ("OVS_ACTION_ATTR_POP_NSH", "flag"),
388 ("OVS_ACTION_ATTR_METER", "none"),
389 ("OVS_ACTION_ATTR_CLONE", "recursive"),
390 ("OVS_ACTION_ATTR_CHECK_PKT_LEN", "none"),
391 ("OVS_ACTION_ATTR_ADD_MPLS", "none"),
392 ("OVS_ACTION_ATTR_DEC_TTL", "none"),
393 ("OVS_ACTION_ATTR_DROP", "uint32"),
394 ("OVS_ACTION_ATTR_PSAMPLE", "psample"),
398 nla_flags = NLA_F_NESTED
401 ("OVS_PSAMPLE_ATTR_UNSPEC", "none"),
402 ("OVS_PSAMPLE_ATTR_GROUP", "uint32"),
403 ("OVS_PSAMPLE_ATTR_COOKIE", "array(uint8)"),
406 def dpstr(self, more=False):
407 args = "group=%d" % self.get_attr("OVS_PSAMPLE_ATTR_GROUP")
409 cookie = self.get_attr("OVS_PSAMPLE_ATTR_COOKIE")
411 args += ",cookie(%s)" % \
412 "".join(format(x, "02x") for x in cookie)
414 return "psample(%s)" % args
416 def parse(self, actstr):
418 ("group", "OVS_PSAMPLE_ATTR_GROUP", int),
419 ("cookie", "OVS_PSAMPLE_ATTR_COOKIE",
420 lambda x: list(bytearray.fromhex(x)))
423 attrs, actstr = parse_attrs(actstr, desc)
426 self["attrs"].append(attr)
431 nla_flags = NLA_F_NESTED
434 ("OVS_SAMPLE_ATTR_UNSPEC", "none"),
435 ("OVS_SAMPLE_ATTR_PROBABILITY", "uint32"),
436 ("OVS_SAMPLE_ATTR_ACTIONS", "ovsactions"),
439 def dpstr(self, more=False):
442 args.append("sample={:.2f}%".format(
443 100 * self.get_attr("OVS_SAMPLE_ATTR_PROBABILITY") /
446 actions = self.get_attr("OVS_SAMPLE_ATTR_ACTIONS")
448 args.append("actions(%s)" % actions.dpstr(more))
450 return "sample(%s)" % ",".join(args)
452 def parse(self, actstr):
453 def parse_nested_actions(actstr):
454 subacts = ovsactions()
455 parsed_len = subacts.parse(actstr)
456 return subacts, actstr[parsed_len :]
458 def percent_to_rate(percent):
459 percent = float(percent.strip('%'))
460 return int(math.floor(UINT32_MAX * (percent / 100.0) + .5))
463 ("sample", "OVS_SAMPLE_ATTR_PROBABILITY", percent_to_rate),
464 ("actions", "OVS_SAMPLE_ATTR_ACTIONS", parse_nested_actions),
466 attrs, actstr = parse_attrs(actstr, desc)
469 self["attrs"].append(attr)
474 nla_flags = NLA_F_NESTED
477 ("OVS_CT_ATTR_NONE", "none"),
478 ("OVS_CT_ATTR_COMMIT", "flag"),
479 ("OVS_CT_ATTR_ZONE", "uint16"),
480 ("OVS_CT_ATTR_MARK", "none"),
481 ("OVS_CT_ATTR_LABELS", "none"),
482 ("OVS_CT_ATTR_HELPER", "asciiz"),
483 ("OVS_CT_ATTR_NAT", "natattr"),
484 ("OVS_CT_ATTR_FORCE_COMMIT", "flag"),
485 ("OVS_CT_ATTR_EVENTMASK", "uint32"),
486 ("OVS_CT_ATTR_TIMEOUT", "asciiz"),
490 nla_flags = NLA_F_NESTED
493 ("OVS_NAT_ATTR_NONE", "none"),
494 ("OVS_NAT_ATTR_SRC", "flag"),
495 ("OVS_NAT_ATTR_DST", "flag"),
496 ("OVS_NAT_ATTR_IP_MIN", "ipaddr"),
497 ("OVS_NAT_ATTR_IP_MAX", "ipaddr"),
498 ("OVS_NAT_ATTR_PROTO_MIN", "uint16"),
499 ("OVS_NAT_ATTR_PROTO_MAX", "uint16"),
500 ("OVS_NAT_ATTR_PERSISTENT", "flag"),
501 ("OVS_NAT_ATTR_PROTO_HASH", "flag"),
502 ("OVS_NAT_ATTR_PROTO_RANDOM", "flag"),
505 def dpstr(self, more=False):
508 if self.get_attr("OVS_NAT_ATTR_SRC"):
510 elif self.get_attr("OVS_NAT_ATTR_DST"):
513 print_str += "XXX-unknown-nat"
515 if self.get_attr("OVS_NAT_ATTR_IP_MIN") or self.get_attr(
516 "OVS_NAT_ATTR_IP_MAX"
518 if self.get_attr("OVS_NAT_ATTR_IP_MIN"):
519 print_str += "=%s," % str(
520 self.get_attr("OVS_NAT_ATTR_IP_MIN")
523 if self.get_attr("OVS_NAT_ATTR_IP_MAX"):
524 print_str += "-%s," % str(
525 self.get_attr("OVS_NAT_ATTR_IP_MAX")
530 if self.get_attr("OVS_NAT_ATTR_PROTO_MIN"):
531 print_str += "proto_min=%d," % self.get_attr(
532 "OVS_NAT_ATTR_PROTO_MIN"
535 if self.get_attr("OVS_NAT_ATTR_PROTO_MAX"):
536 print_str += "proto_max=%d," % self.get_attr(
537 "OVS_NAT_ATTR_PROTO_MAX"
540 if self.get_attr("OVS_NAT_ATTR_PERSISTENT"):
541 print_str += "persistent,"
542 if self.get_attr("OVS_NAT_ATTR_HASH"):
544 if self.get_attr("OVS_NAT_ATTR_RANDOM"):
545 print_str += "random"
549 def dpstr(self, more=False):
552 if self.get_attr("OVS_CT_ATTR_COMMIT") is not None:
553 print_str += "commit,"
554 if self.get_attr("OVS_CT_ATTR_ZONE") is not None:
555 print_str += "zone=%d," % self.get_attr("OVS_CT_ATTR_ZONE")
556 if self.get_attr("OVS_CT_ATTR_HELPER") is not None:
557 print_str += "helper=%s," % self.get_attr("OVS_CT_ATTR_HELPER")
558 if self.get_attr("OVS_CT_ATTR_NAT") is not None:
559 print_str += self.get_attr("OVS_CT_ATTR_NAT").dpstr(more)
561 if self.get_attr("OVS_CT_ATTR_FORCE_COMMIT") is not None:
562 print_str += "force,"
563 if self.get_attr("OVS_CT_ATTR_EVENTMASK") is not None:
564 print_str += "emask=0x%X," % self.get_attr(
565 "OVS_CT_ATTR_EVENTMASK"
567 if self.get_attr("OVS_CT_ATTR_TIMEOUT") is not None:
568 print_str += "timeout=%s" % self.get_attr(
569 "OVS_CT_ATTR_TIMEOUT"
574 class userspace(nla):
575 nla_flags = NLA_F_NESTED
578 ("OVS_USERSPACE_ATTR_UNUSED", "none"),
579 ("OVS_USERSPACE_ATTR_PID", "uint32"),
580 ("OVS_USERSPACE_ATTR_USERDATA", "array(uint8)"),
581 ("OVS_USERSPACE_ATTR_EGRESS_TUN_PORT", "uint32"),
584 def dpstr(self, more=False):
585 print_str = "userspace("
586 if self.get_attr("OVS_USERSPACE_ATTR_PID") is not None:
587 print_str += "pid=%d," % self.get_attr(
588 "OVS_USERSPACE_ATTR_PID"
590 if self.get_attr("OVS_USERSPACE_ATTR_USERDATA") is not None:
591 print_str += "userdata="
592 for f in self.get_attr("OVS_USERSPACE_ATTR_USERDATA"):
593 print_str += "%x." % f
594 if self.get_attr("OVS_USERSPACE_ATTR_EGRESS_TUN_PORT") is not None:
595 print_str += "egress_tun_port=%d" % self.get_attr(
596 "OVS_USERSPACE_ATTR_EGRESS_TUN_PORT"
601 def parse(self, actstr):
603 ("pid", "OVS_USERSPACE_ATTR_PID", int),
604 ("userdata", "OVS_USERSPACE_ATTR_USERDATA",
605 lambda x: list(bytearray.fromhex(x))),
606 ("egress_tun_port", "OVS_USERSPACE_ATTR_EGRESS_TUN_PORT", int)
609 attrs, actstr = parse_attrs(actstr, attrs_desc)
611 self["attrs"].append(attr)
615 def dpstr(self, more=False):
618 for field in self["attrs"]:
619 if field[1] == "none" or self.get_attr(field[0]) is None:
624 if field[0] == "OVS_ACTION_ATTR_OUTPUT":
625 print_str += "%d" % int(self.get_attr(field[0]))
626 elif field[0] == "OVS_ACTION_ATTR_RECIRC":
627 print_str += "recirc(0x%x)" % int(self.get_attr(field[0]))
628 elif field[0] == "OVS_ACTION_ATTR_TRUNC":
629 print_str += "trunc(%d)" % int(self.get_attr(field[0]))
630 elif field[0] == "OVS_ACTION_ATTR_DROP":
631 print_str += "drop(%d)" % int(self.get_attr(field[0]))
632 elif field[0] == "OVS_ACTION_ATTR_CT_CLEAR":
633 print_str += "ct_clear"
634 elif field[0] == "OVS_ACTION_ATTR_POP_VLAN":
635 print_str += "pop_vlan"
636 elif field[0] == "OVS_ACTION_ATTR_POP_ETH":
637 print_str += "pop_eth"
638 elif field[0] == "OVS_ACTION_ATTR_POP_NSH":
639 print_str += "pop_nsh"
640 elif field[0] == "OVS_ACTION_ATTR_POP_MPLS":
641 print_str += "pop_mpls"
643 datum = self.get_attr(field[0])
644 if field[0] == "OVS_ACTION_ATTR_CLONE":
645 print_str += "clone("
646 print_str += datum.dpstr(more)
648 elif field[0] == "OVS_ACTION_ATTR_SET" or \
649 field[0] == "OVS_ACTION_ATTR_SET_MASKED":
653 if field[0] == "OVS_ACTION_ATTR_SET_MASKED":
654 print_str += "_masked"
658 print_str += field.dpstr(mask, more)
662 print_str += datum.dpstr(more)
664 print_str += "{ATTR: %s not decoded}" % field[0]
668 def parse(self, actstr):
669 totallen = len(actstr)
670 while len(actstr) != 0:
673 if actstr.startswith("drop"):
674 # If no reason is provided, the implicit drop is used (i.e no
675 # action). If some reason is given, an explicit action is used.
677 if actstr.startswith("drop("):
680 actstr, reason = parse_extract_field(
689 if reason is not None:
690 self["attrs"].append(["OVS_ACTION_ATTR_DROP", reason])
693 actstr = actstr[len("drop"): ]
694 return (totallen - len(actstr))
696 elif parse_starts_block(actstr, r"^(\d+)", False, True):
697 actstr, output = parse_extract_field(
698 actstr, None, r"(\d+)", lambda x: int(x), False, "0"
700 self["attrs"].append(["OVS_ACTION_ATTR_OUTPUT", output])
702 elif parse_starts_block(actstr, "recirc(", False):
703 actstr, recircid = parse_extract_field(
712 self["attrs"].append(["OVS_ACTION_ATTR_RECIRC", recircid])
716 ("ct_clear", "OVS_ACTION_ATTR_CT_CLEAR"),
717 ("pop_vlan", "OVS_ACTION_ATTR_POP_VLAN"),
718 ("pop_eth", "OVS_ACTION_ATTR_POP_ETH"),
719 ("pop_nsh", "OVS_ACTION_ATTR_POP_NSH"),
722 for flat_act in parse_flat_map:
723 if parse_starts_block(actstr, flat_act[0], False):
724 actstr = actstr[len(flat_act[0]):]
725 self["attrs"].append([flat_act[1], True])
726 actstr = actstr[strspn(actstr, ", ") :]
729 if parse_starts_block(actstr, "clone(", False):
731 subacts = ovsactions()
732 actstr = actstr[len("clone("):]
733 parsedLen = subacts.parse(actstr)
735 self["attrs"].append(("OVS_ACTION_ATTR_CLONE", subacts))
736 actstr = actstr[parsedLen:]
738 elif parse_starts_block(actstr, "set(", False):
741 actstr = actstr[len("set("):]
742 actstr = k.parse(actstr, None)
743 self["attrs"].append(("OVS_ACTION_ATTR_SET", k))
744 if not actstr.startswith(")"):
745 actstr = ")" + actstr
747 elif parse_starts_block(actstr, "set_masked(", False):
751 actstr = actstr[len("set_masked("):]
752 actstr = k.parse(actstr, m)
753 self["attrs"].append(("OVS_ACTION_ATTR_SET_MASKED", [k, m]))
754 if not actstr.startswith(")"):
755 actstr = ")" + actstr
757 elif parse_starts_block(actstr, "ct(", False):
759 actstr = actstr[len("ct(") :]
760 ctact = ovsactions.ctact()
763 ("commit", "OVS_CT_ATTR_COMMIT", None),
764 ("force_commit", "OVS_CT_ATTR_FORCE_COMMIT", None),
765 ("zone", "OVS_CT_ATTR_ZONE", int),
766 ("mark", "OVS_CT_ATTR_MARK", int),
767 ("helper", "OVS_CT_ATTR_HELPER", lambda x, y: str(x)),
768 ("timeout", "OVS_CT_ATTR_TIMEOUT", lambda x, y: str(x)),
770 if actstr.startswith(scan[0]):
771 actstr = actstr[len(scan[0]) :]
772 if scan[2] is not None:
774 raise ValueError("Invalid ct attr")
776 pos = strcspn(actstr, ",)")
777 datum = scan[2](actstr[:pos], 0)
778 ctact["attrs"].append([scan[1], datum])
779 actstr = actstr[pos:]
781 ctact["attrs"].append([scan[1], None])
782 actstr = actstr[strspn(actstr, ", ") :]
783 # it seems strange to put this here, but nat() is a complex
784 # sub-action and this lets it sit anywhere in the ct() action
785 if actstr.startswith("nat"):
787 natact = ovsactions.ctact.natattr()
789 if actstr.startswith("("):
793 if actstr.startswith("src"):
794 t = "OVS_NAT_ATTR_SRC"
796 elif actstr.startswith("dst"):
797 t = "OVS_NAT_ATTR_DST"
800 actstr, ip_block_min = parse_extract_field(
801 actstr, "=", r"([0-9a-fA-F\.]+)", str, False
803 actstr, ip_block_max = parse_extract_field(
804 actstr, "-", r"([0-9a-fA-F\.]+)", str, False
807 actstr, proto_min = parse_extract_field(
808 actstr, ":", r"(\d+)", int, False
810 actstr, proto_max = parse_extract_field(
811 actstr, "-", r"(\d+)", int, False
815 natact["attrs"].append([t, None])
817 if ip_block_min is not None:
818 natact["attrs"].append(
819 ["OVS_NAT_ATTR_IP_MIN", ip_block_min]
821 if ip_block_max is not None:
822 natact["attrs"].append(
823 ["OVS_NAT_ATTR_IP_MAX", ip_block_max]
825 if proto_min is not None:
826 natact["attrs"].append(
827 ["OVS_NAT_ATTR_PROTO_MIN", proto_min]
829 if proto_max is not None:
830 natact["attrs"].append(
831 ["OVS_NAT_ATTR_PROTO_MAX", proto_max]
835 ("persistent", "OVS_NAT_ATTR_PERSISTENT"),
836 ("hash", "OVS_NAT_ATTR_PROTO_HASH"),
837 ("random", "OVS_NAT_ATTR_PROTO_RANDOM"),
839 if actstr.startswith(natscan[0]):
840 actstr = actstr[len(natscan[0]) :]
841 natact["attrs"].append([natscan[1], None])
842 actstr = actstr[strspn(actstr, ", ") :]
844 ctact["attrs"].append(["OVS_CT_ATTR_NAT", natact])
845 actstr = actstr[strspn(actstr, ", ") :]
847 self["attrs"].append(["OVS_ACTION_ATTR_CT", ctact])
850 elif parse_starts_block(actstr, "sample(", False):
851 sampleact = self.sample()
852 actstr = sampleact.parse(actstr[len("sample(") : ])
853 self["attrs"].append(["OVS_ACTION_ATTR_SAMPLE", sampleact])
856 elif parse_starts_block(actstr, "psample(", False):
857 psampleact = self.psample()
858 actstr = psampleact.parse(actstr[len("psample(") : ])
859 self["attrs"].append(["OVS_ACTION_ATTR_PSAMPLE", psampleact])
862 elif parse_starts_block(actstr, "userspace(", False):
863 uact = self.userspace()
864 actstr = uact.parse(actstr[len("userspace(") : ])
865 self["attrs"].append(["OVS_ACTION_ATTR_USERSPACE", uact])
868 elif parse_starts_block(actstr, "trunc(", False):
870 actstr, val = parse_extract_field(
878 self["attrs"].append(["OVS_ACTION_ATTR_TRUNC", val])
881 actstr = actstr[strspn(actstr, ", ") :]
882 while parencount > 0:
884 actstr = actstr[strspn(actstr, " "):]
885 if len(actstr) and actstr[0] != ")":
886 raise ValueError("Action str: '%s' unbalanced" % actstr)
889 if len(actstr) and actstr[0] == ")":
890 return (totallen - len(actstr))
892 actstr = actstr[strspn(actstr, ", ") :]
895 raise ValueError("Action str: '%s' not supported" % actstr)
897 return (totallen - len(actstr))
901 nla_flags = NLA_F_NESTED
903 ("OVS_KEY_ATTR_UNSPEC", "none"),
904 ("OVS_KEY_ATTR_ENCAP", "none"),
905 ("OVS_KEY_ATTR_PRIORITY", "uint32"),
906 ("OVS_KEY_ATTR_IN_PORT", "uint32"),
907 ("OVS_KEY_ATTR_ETHERNET", "ethaddr"),
908 ("OVS_KEY_ATTR_VLAN", "uint16"),
909 ("OVS_KEY_ATTR_ETHERTYPE", "be16"),
910 ("OVS_KEY_ATTR_IPV4", "ovs_key_ipv4"),
911 ("OVS_KEY_ATTR_IPV6", "ovs_key_ipv6"),
912 ("OVS_KEY_ATTR_TCP", "ovs_key_tcp"),
913 ("OVS_KEY_ATTR_UDP", "ovs_key_udp"),
914 ("OVS_KEY_ATTR_ICMP", "ovs_key_icmp"),
915 ("OVS_KEY_ATTR_ICMPV6", "ovs_key_icmpv6"),
916 ("OVS_KEY_ATTR_ARP", "ovs_key_arp"),
917 ("OVS_KEY_ATTR_ND", "ovs_key_nd"),
918 ("OVS_KEY_ATTR_SKB_MARK", "uint32"),
919 ("OVS_KEY_ATTR_TUNNEL", "ovs_key_tunnel"),
920 ("OVS_KEY_ATTR_SCTP", "ovs_key_sctp"),
921 ("OVS_KEY_ATTR_TCP_FLAGS", "be16"),
922 ("OVS_KEY_ATTR_DP_HASH", "uint32"),
923 ("OVS_KEY_ATTR_RECIRC_ID", "uint32"),
924 ("OVS_KEY_ATTR_MPLS", "array(ovs_key_mpls)"),
925 ("OVS_KEY_ATTR_CT_STATE", "uint32"),
926 ("OVS_KEY_ATTR_CT_ZONE", "uint16"),
927 ("OVS_KEY_ATTR_CT_MARK", "uint32"),
928 ("OVS_KEY_ATTR_CT_LABELS", "none"),
929 ("OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4", "ovs_key_ct_tuple_ipv4"),
930 ("OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6", "ovs_key_ct_tuple_ipv6"),
931 ("OVS_KEY_ATTR_NSH", "none"),
932 ("OVS_KEY_ATTR_PACKET_TYPE", "none"),
933 ("OVS_KEY_ATTR_ND_EXTENSIONS", "none"),
934 ("OVS_KEY_ATTR_TUNNEL_INFO", "none"),
935 ("OVS_KEY_ATTR_IPV6_EXTENSIONS", "none"),
938 class ovs_key_proto(nla):
945 ("src", "src", "%d", lambda x: int(x) if x else 0,
947 ("dst", "dst", "%d", lambda x: int(x) if x else 0,
960 self.proto_str = protostr
970 def parse(self, flowstr, typeInst):
971 if not flowstr.startswith(self.proto_str):
977 flowstr = flowstr[len(self.proto_str) :]
978 if flowstr.startswith("("):
979 flowstr = flowstr[1:]
983 for f in self.fields_map:
984 if flowstr.startswith(f[1]):
985 # the following assumes that the field looks
986 # something like 'field.' where '.' is a
987 # character that we don't exactly care about.
988 flowstr = flowstr[len(f[1]) + 1 :]
991 if c == "," or c == ")":
994 data = flowstr[:splitchar]
995 flowstr = flowstr[splitchar:]
1000 k[f[0]], m[f[0]] = f[4](data)
1002 k[f[0]] = f[3](data)
1003 m[f[0]] = f[3](data)
1005 flowstr = flowstr[strspn(flowstr, ", ") :]
1006 if len(flowstr) == 0:
1007 return flowstr, k, m
1009 flowstr = flowstr[strspn(flowstr, "), ") :]
1011 return flowstr, k, m
1013 def dpstr(self, masked=None, more=False):
1014 outstr = self.proto_str + "("
1016 for f in self.fields_map:
1020 outstr += "%s=" % f[0]
1021 if isinstance(f[2], str):
1022 outstr += f[2] % self[f[1]]
1024 outstr += f[2](self[f[1]])
1026 elif more or f[3](masked[f[1]]) != 0:
1027 outstr += "%s=" % f[0]
1028 if isinstance(f[2], str):
1029 outstr += f[2] % self[f[1]]
1031 outstr += f[2](self[f[1]])
1033 if isinstance(f[2], str):
1034 outstr += f[2] % masked[f[1]]
1036 outstr += f[2](masked[f[1]])
1041 class ethaddr(ovs_key_proto):
1052 lambda x: int.from_bytes(x, "big"),
1059 lambda x: int.from_bytes(x, "big"),
1072 ovskey.ovs_key_proto.__init__(
1082 class ovs_key_ipv4(ovs_key_proto):
1096 lambda x: str(ipaddress.IPv4Address(x)),
1103 lambda x: str(ipaddress.IPv4Address(x)),
1107 ("proto", "proto", "%d", lambda x: int(x) if x else 0,
1109 ("tos", "tos", "%d", lambda x: int(x) if x else 0,
1111 ("ttl", "ttl", "%d", lambda x: int(x) if x else 0,
1113 ("frag", "frag", "%d", lambda x: int(x) if x else 0,
1125 ovskey.ovs_key_proto.__init__(
1135 class ovs_key_ipv6(ovs_key_proto):
1150 lambda x: str(ipaddress.IPv6Address(x)),
1151 lambda x: ipaddress.IPv6Address(x).packed if x else 0,
1157 lambda x: str(ipaddress.IPv6Address(x)),
1158 lambda x: ipaddress.IPv6Address(x).packed if x else 0,
1161 ("label", "label", "%d", lambda x: int(x) if x else 0),
1162 ("proto", "proto", "%d", lambda x: int(x) if x else 0),
1163 ("tclass", "tclass", "%d", lambda x: int(x) if x else 0),
1164 ("hlimit", "hlimit", "%d", lambda x: int(x) if x else 0),
1165 ("frag", "frag", "%d", lambda x: int(x) if x else 0),
1176 ovskey.ovs_key_proto.__init__(
1186 class ovs_key_tcp(ovs_key_proto):
1195 ovskey.ovs_key_proto.__init__(
1205 class ovs_key_udp(ovs_key_proto):
1214 ovskey.ovs_key_proto.__init__(
1224 class ovs_key_sctp(ovs_key_proto):
1233 ovskey.ovs_key_proto.__init__(
1243 class ovs_key_icmp(ovs_key_proto):
1250 ("type", "type", "%d", lambda x: int(x) if x else 0),
1251 ("code", "code", "%d", lambda x: int(x) if x else 0),
1262 ovskey.ovs_key_proto.__init__(
1272 class ovs_key_icmpv6(ovs_key_icmp):
1281 ovskey.ovs_key_proto.__init__(
1291 class ovs_key_arp(ovs_key_proto):
1305 lambda x: str(ipaddress.IPv4Address(x)),
1312 lambda x: str(ipaddress.IPv4Address(x)),
1316 ("op", "op", "%d", lambda x: int(x) if x else 0),
1321 lambda x: int.from_bytes(x, "big"),
1328 lambda x: int.from_bytes(x, "big"),
1341 ovskey.ovs_key_proto.__init__(
1351 class ovs_key_nd(ovs_key_proto):
1362 lambda x: str(ipaddress.IPv6Address(x)),
1365 ("sll", "sll", macstr, lambda x: int.from_bytes(x, "big")),
1366 ("tll", "tll", macstr, lambda x: int.from_bytes(x, "big")),
1377 ovskey.ovs_key_proto.__init__(
1387 class ovs_key_ct_tuple_ipv4(ovs_key_proto):
1400 lambda x: str(ipaddress.IPv4Address(x)),
1407 lambda x: str(ipaddress.IPv4Address(x)),
1411 ("tp_src", "tp_src", "%d", int),
1412 ("tp_dst", "tp_dst", "%d", int),
1413 ("proto", "proto", "%d", int),
1424 ovskey.ovs_key_proto.__init__(
1434 class ovs_key_ct_tuple_ipv6(nla):
1447 lambda x: str(ipaddress.IPv6Address(x)),
1453 lambda x: str(ipaddress.IPv6Address(x)),
1456 ("tp_src", "tp_src", "%d", int),
1457 ("tp_dst", "tp_dst", "%d", int),
1458 ("proto", "proto", "%d", int),
1469 ovskey.ovs_key_proto.__init__(
1479 class ovs_key_tunnel(nla):
1480 nla_flags = NLA_F_NESTED
1483 ("OVS_TUNNEL_KEY_ATTR_ID", "be64"),
1484 ("OVS_TUNNEL_KEY_ATTR_IPV4_SRC", "ipaddr"),
1485 ("OVS_TUNNEL_KEY_ATTR_IPV4_DST", "ipaddr"),
1486 ("OVS_TUNNEL_KEY_ATTR_TOS", "uint8"),
1487 ("OVS_TUNNEL_KEY_ATTR_TTL", "uint8"),
1488 ("OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT", "flag"),
1489 ("OVS_TUNNEL_KEY_ATTR_CSUM", "flag"),
1490 ("OVS_TUNNEL_KEY_ATTR_OAM", "flag"),
1491 ("OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS", "array(uint32)"),
1492 ("OVS_TUNNEL_KEY_ATTR_TP_SRC", "be16"),
1493 ("OVS_TUNNEL_KEY_ATTR_TP_DST", "be16"),
1494 ("OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS", "none"),
1495 ("OVS_TUNNEL_KEY_ATTR_IPV6_SRC", "ipaddr"),
1496 ("OVS_TUNNEL_KEY_ATTR_IPV6_DST", "ipaddr"),
1497 ("OVS_TUNNEL_KEY_ATTR_PAD", "none"),
1498 ("OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS", "none"),
1499 ("OVS_TUNNEL_KEY_ATTR_IPV4_INFO_BRIDGE", "flag"),
1502 def parse(self, flowstr, mask=None):
1503 if not flowstr.startswith("tunnel("):
1506 k = ovskey.ovs_key_tunnel()
1507 if mask is not None:
1508 mask = ovskey.ovs_key_tunnel()
1510 flowstr = flowstr[len("tunnel("):]
1515 ("tun_id=", r"(\d+)", int, "OVS_TUNNEL_KEY_ATTR_ID",
1516 0xffffffffffffffff, None, None),
1518 ("src=", r"([0-9a-fA-F\.]+)", str,
1519 "OVS_TUNNEL_KEY_ATTR_IPV4_SRC", "255.255.255.255", "0.0.0.0",
1521 ("dst=", r"([0-9a-fA-F\.]+)", str,
1522 "OVS_TUNNEL_KEY_ATTR_IPV4_DST", "255.255.255.255", "0.0.0.0",
1525 ("ipv6_src=", r"([0-9a-fA-F:]+)", str,
1526 "OVS_TUNNEL_KEY_ATTR_IPV6_SRC",
1527 "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", "::", True),
1528 ("ipv6_dst=", r"([0-9a-fA-F:]+)", str,
1529 "OVS_TUNNEL_KEY_ATTR_IPV6_DST",
1530 "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", "::", True),
1532 ("tos=", r"(\d+)", int, "OVS_TUNNEL_KEY_ATTR_TOS", 255, 0,
1534 ("ttl=", r"(\d+)", int, "OVS_TUNNEL_KEY_ATTR_TTL", 255, 0,
1537 ("tp_src=", r"(\d+)", int, "OVS_TUNNEL_KEY_ATTR_TP_SRC",
1539 ("tp_dst=", r"(\d+)", int, "OVS_TUNNEL_KEY_ATTR_TP_DST",
1543 forced_include = ["OVS_TUNNEL_KEY_ATTR_TTL"]
1545 for prefix, regex, typ, attr_name, mask_val, default_val, v46_flag in fields:
1546 flowstr, value = parse_extract_field(flowstr, prefix, regex, typ, False)
1548 raise Exception("Bad list value in tunnel fields")
1550 if value is None and attr_name in forced_include:
1552 mask_val = default_val
1554 if value is not None:
1555 if v46_flag is not None:
1556 if v6_address is None:
1557 v6_address = v46_flag
1558 if v46_flag != v6_address:
1559 raise ValueError("Cannot mix v6 and v4 addresses")
1560 k["attrs"].append([attr_name, value])
1561 if mask is not None:
1562 mask["attrs"].append([attr_name, mask_val])
1564 if v46_flag is not None:
1565 if v6_address is None or v46_flag != v6_address:
1567 if mask is not None:
1568 mask["attrs"].append([attr_name, default_val])
1570 if k["attrs"][0][0] != "OVS_TUNNEL_KEY_ATTR_ID":
1571 raise ValueError("Needs a tunid set")
1573 if flowstr.startswith("flags("):
1574 flowstr = flowstr[len("flags("):]
1575 flagspos = flowstr.find(")")
1576 flags = flowstr[:flagspos]
1577 flowstr = flowstr[flagspos + 1:]
1580 "df": "OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT",
1581 "csum": "OVS_TUNNEL_KEY_ATTR_CSUM",
1582 "oam": "OVS_TUNNEL_KEY_ATTR_OAM"
1585 for flag in flags.split("|"):
1586 if flag in flag_attrs:
1587 k["attrs"].append([flag_attrs[flag], True])
1588 if mask is not None:
1589 mask["attrs"].append([flag_attrs[flag], True])
1591 flowstr = flowstr[strspn(flowstr, ", ") :]
1592 return flowstr, k, mask
1594 def dpstr(self, mask=None, more=False):
1595 print_str = "tunnel("
1598 for k in self["attrs"]:
1600 if k[0] == "OVS_TUNNEL_KEY_ATTR_ID":
1601 print_str += "tun_id=%d" % k[1]
1602 elif k[0] == "OVS_TUNNEL_KEY_ATTR_IPV4_SRC":
1603 print_str += "src=%s" % k[1]
1604 elif k[0] == "OVS_TUNNEL_KEY_ATTR_IPV4_DST":
1605 print_str += "dst=%s" % k[1]
1606 elif k[0] == "OVS_TUNNEL_KEY_ATTR_IPV6_SRC":
1607 print_str += "ipv6_src=%s" % k[1]
1608 elif k[0] == "OVS_TUNNEL_KEY_ATTR_IPV6_DST":
1609 print_str += "ipv6_dst=%s" % k[1]
1610 elif k[0] == "OVS_TUNNEL_KEY_ATTR_TOS":
1611 print_str += "tos=%d" % k[1]
1612 elif k[0] == "OVS_TUNNEL_KEY_ATTR_TTL":
1613 print_str += "ttl=%d" % k[1]
1614 elif k[0] == "OVS_TUNNEL_KEY_ATTR_TP_SRC":
1615 print_str += "tp_src=%d" % k[1]
1616 elif k[0] == "OVS_TUNNEL_KEY_ATTR_TP_DST":
1617 print_str += "tp_dst=%d" % k[1]
1618 elif k[0] == "OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT":
1620 flagsattrs.append("df")
1621 elif k[0] == "OVS_TUNNEL_KEY_ATTR_CSUM":
1623 flagsattrs.append("csum")
1624 elif k[0] == "OVS_TUNNEL_KEY_ATTR_OAM":
1626 flagsattrs.append("oam")
1632 print_str += "flags(" + "|".join(flagsattrs) + ")"
1636 class ovs_key_mpls(nla):
1637 fields = (("lse", ">I"),)
1639 def parse(self, flowstr, mask=None):
1641 ("OVS_KEY_ATTR_PRIORITY", "skb_priority", intparse),
1642 ("OVS_KEY_ATTR_SKB_MARK", "skb_mark", intparse),
1643 ("OVS_KEY_ATTR_RECIRC_ID", "recirc_id", intparse),
1644 ("OVS_KEY_ATTR_TUNNEL", "tunnel", ovskey.ovs_key_tunnel),
1645 ("OVS_KEY_ATTR_DP_HASH", "dp_hash", intparse),
1646 ("OVS_KEY_ATTR_CT_STATE", "ct_state", parse_ct_state),
1647 ("OVS_KEY_ATTR_CT_ZONE", "ct_zone", intparse),
1648 ("OVS_KEY_ATTR_CT_MARK", "ct_mark", intparse),
1649 ("OVS_KEY_ATTR_IN_PORT", "in_port", intparse),
1651 "OVS_KEY_ATTR_ETHERNET",
1656 "OVS_KEY_ATTR_ETHERTYPE",
1658 lambda x: intparse(x, "0xffff"),
1661 "OVS_KEY_ATTR_IPV4",
1663 ovskey.ovs_key_ipv4,
1666 "OVS_KEY_ATTR_IPV6",
1668 ovskey.ovs_key_ipv6,
1686 "OVS_KEY_ATTR_ICMP",
1688 ovskey.ovs_key_icmp,
1691 "OVS_KEY_ATTR_TCP_FLAGS",
1693 lambda x: parse_flags(x, None),
1696 fld = field[1] + "("
1697 if not flowstr.startswith(fld):
1700 if not isinstance(field[2], types.FunctionType):
1702 flowstr, k, m = nk.parse(flowstr, field[2])
1704 flowstr = flowstr[len(fld) :]
1705 flowstr, k, m = field[2](flowstr)
1707 if m and mask is not None:
1708 mask["attrs"].append([field[0], m])
1709 self["attrs"].append([field[0], k])
1711 flowstr = flowstr[strspn(flowstr, "), ") :]
1715 def dpstr(self, mask=None, more=False):
1720 "OVS_KEY_ATTR_PRIORITY",
1727 "OVS_KEY_ATTR_SKB_MARK",
1734 "OVS_KEY_ATTR_RECIRC_ID",
1741 "OVS_KEY_ATTR_DP_HASH",
1748 "OVS_KEY_ATTR_TUNNEL",
1755 "OVS_KEY_ATTR_CT_STATE",
1762 "OVS_KEY_ATTR_CT_ZONE",
1769 "OVS_KEY_ATTR_CT_MARK",
1776 "OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4",
1783 "OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6",
1790 "OVS_KEY_ATTR_IN_PORT",
1796 ("OVS_KEY_ATTR_ETHERNET", None, None, False, False),
1798 "OVS_KEY_ATTR_ETHERTYPE",
1801 lambda x: int(x) == 0xFFFF,
1804 ("OVS_KEY_ATTR_IPV4", None, None, False, False),
1805 ("OVS_KEY_ATTR_IPV6", None, None, False, False),
1806 ("OVS_KEY_ATTR_ARP", None, None, False, False),
1807 ("OVS_KEY_ATTR_TCP", None, None, False, False),
1809 "OVS_KEY_ATTR_TCP_FLAGS",
1815 ("OVS_KEY_ATTR_UDP", None, None, False, False),
1816 ("OVS_KEY_ATTR_SCTP", None, None, False, False),
1817 ("OVS_KEY_ATTR_ICMP", None, None, False, False),
1818 ("OVS_KEY_ATTR_ICMPV6", None, None, False, False),
1819 ("OVS_KEY_ATTR_ND", None, None, False, False),
1821 v = self.get_attr(field[0])
1823 m = None if mask is None else mask.get_attr(field[0])
1824 if field[4] is False:
1825 print_str += v.dpstr(m, more)
1828 if m is None or field[3](m):
1829 print_str += field[1] + "("
1830 print_str += field[2] % v
1832 elif more or m != 0:
1833 print_str += field[1] + "("
1834 print_str += (field[2] % v) + "/" + (field[2] % m)
1840 class OvsPacket(GenericNetlinkSocket):
1841 OVS_PACKET_CMD_MISS = 1 # Flow table miss
1842 OVS_PACKET_CMD_ACTION = 2 # USERSPACE action
1843 OVS_PACKET_CMD_EXECUTE = 3 # Apply actions to packet
1845 class ovs_packet_msg(ovs_dp_msg):
1847 ("OVS_PACKET_ATTR_UNSPEC", "none"),
1848 ("OVS_PACKET_ATTR_PACKET", "array(uint8)"),
1849 ("OVS_PACKET_ATTR_KEY", "ovskey"),
1850 ("OVS_PACKET_ATTR_ACTIONS", "ovsactions"),
1851 ("OVS_PACKET_ATTR_USERDATA", "none"),
1852 ("OVS_PACKET_ATTR_EGRESS_TUN_KEY", "none"),
1853 ("OVS_PACKET_ATTR_UNUSED1", "none"),
1854 ("OVS_PACKET_ATTR_UNUSED2", "none"),
1855 ("OVS_PACKET_ATTR_PROBE", "none"),
1856 ("OVS_PACKET_ATTR_MRU", "uint16"),
1857 ("OVS_PACKET_ATTR_LEN", "uint32"),
1858 ("OVS_PACKET_ATTR_HASH", "uint64"),
1862 GenericNetlinkSocket.__init__(self)
1863 self.bind(OVS_PACKET_FAMILY, OvsPacket.ovs_packet_msg)
1865 def upcall_handler(self, up=None):
1866 print("listening on upcall packet handler:", self.epid)
1873 if msg["cmd"] == OvsPacket.OVS_PACKET_CMD_MISS:
1875 elif msg["cmd"] == OvsPacket.OVS_PACKET_CMD_ACTION:
1877 elif msg["cmd"] == OvsPacket.OVS_PACKET_CMD_EXECUTE:
1880 print("Unkonwn cmd: %d" % msg["cmd"])
1881 except NetlinkError as ne:
1885 class OvsDatapath(GenericNetlinkSocket):
1886 OVS_DP_F_VPORT_PIDS = 1 << 1
1887 OVS_DP_F_DISPATCH_UPCALL_PER_CPU = 1 << 3
1889 class dp_cmd_msg(ovs_dp_msg):
1891 Message class that will be used to communicate with the kernel module.
1895 ("OVS_DP_ATTR_UNSPEC", "none"),
1896 ("OVS_DP_ATTR_NAME", "asciiz"),
1897 ("OVS_DP_ATTR_UPCALL_PID", "array(uint32)"),
1898 ("OVS_DP_ATTR_STATS", "dpstats"),
1899 ("OVS_DP_ATTR_MEGAFLOW_STATS", "megaflowstats"),
1900 ("OVS_DP_ATTR_USER_FEATURES", "uint32"),
1901 ("OVS_DP_ATTR_PAD", "none"),
1902 ("OVS_DP_ATTR_MASKS_CACHE_SIZE", "uint32"),
1903 ("OVS_DP_ATTR_PER_CPU_PIDS", "array(uint32)"),
1914 class megaflowstats(nla):
1919 ("cache_hits", "=Q"),
1924 GenericNetlinkSocket.__init__(self)
1925 self.bind(OVS_DATAPATH_FAMILY, OvsDatapath.dp_cmd_msg)
1927 def info(self, dpname, ifindex=0):
1928 msg = OvsDatapath.dp_cmd_msg()
1929 msg["cmd"] = OVS_DP_CMD_GET
1930 msg["version"] = OVS_DATAPATH_VERSION
1932 msg["dpifindex"] = ifindex
1933 msg["attrs"].append(["OVS_DP_ATTR_NAME", dpname])
1936 reply = self.nlm_request(
1937 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST
1940 except NetlinkError as ne:
1941 if ne.code == errno.ENODEV:
1949 self, dpname, shouldUpcall=False, versionStr=None, p=OvsPacket()
1951 msg = OvsDatapath.dp_cmd_msg()
1952 msg["cmd"] = OVS_DP_CMD_NEW
1953 if versionStr is None:
1954 msg["version"] = OVS_DATAPATH_VERSION
1956 msg["version"] = int(versionStr.split(":")[0], 0)
1958 msg["dpifindex"] = 0
1959 msg["attrs"].append(["OVS_DP_ATTR_NAME", dpname])
1962 if versionStr is not None and versionStr.find(":") != -1:
1963 dpfeatures = int(versionStr.split(":")[1], 0)
1965 if versionStr is None or versionStr.find(":") == -1:
1966 dpfeatures |= OvsDatapath.OVS_DP_F_DISPATCH_UPCALL_PER_CPU
1967 dpfeatures &= ~OvsDatapath.OVS_DP_F_VPORT_PIDS
1969 nproc = multiprocessing.cpu_count()
1971 for i in range(1, nproc):
1972 procarray += [int(p.epid)]
1973 msg["attrs"].append(["OVS_DP_ATTR_UPCALL_PID", procarray])
1974 msg["attrs"].append(["OVS_DP_ATTR_USER_FEATURES", dpfeatures])
1975 if not shouldUpcall:
1976 msg["attrs"].append(["OVS_DP_ATTR_UPCALL_PID", [0]])
1979 reply = self.nlm_request(
1980 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK
1983 except NetlinkError as ne:
1984 if ne.code == errno.EEXIST:
1991 def destroy(self, dpname):
1992 msg = OvsDatapath.dp_cmd_msg()
1993 msg["cmd"] = OVS_DP_CMD_DEL
1994 msg["version"] = OVS_DATAPATH_VERSION
1996 msg["dpifindex"] = 0
1997 msg["attrs"].append(["OVS_DP_ATTR_NAME", dpname])
2000 reply = self.nlm_request(
2001 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK
2004 except NetlinkError as ne:
2005 if ne.code == errno.ENODEV:
2013 class OvsVport(GenericNetlinkSocket):
2014 OVS_VPORT_TYPE_NETDEV = 1
2015 OVS_VPORT_TYPE_INTERNAL = 2
2016 OVS_VPORT_TYPE_GRE = 3
2017 OVS_VPORT_TYPE_VXLAN = 4
2018 OVS_VPORT_TYPE_GENEVE = 5
2020 class ovs_vport_msg(ovs_dp_msg):
2022 ("OVS_VPORT_ATTR_UNSPEC", "none"),
2023 ("OVS_VPORT_ATTR_PORT_NO", "uint32"),
2024 ("OVS_VPORT_ATTR_TYPE", "uint32"),
2025 ("OVS_VPORT_ATTR_NAME", "asciiz"),
2026 ("OVS_VPORT_ATTR_OPTIONS", "vportopts"),
2027 ("OVS_VPORT_ATTR_UPCALL_PID", "array(uint32)"),
2028 ("OVS_VPORT_ATTR_STATS", "vportstats"),
2029 ("OVS_VPORT_ATTR_PAD", "none"),
2030 ("OVS_VPORT_ATTR_IFINDEX", "uint32"),
2031 ("OVS_VPORT_ATTR_NETNSID", "uint32"),
2034 class vportopts(nla):
2036 ("OVS_TUNNEL_ATTR_UNSPEC", "none"),
2037 ("OVS_TUNNEL_ATTR_DST_PORT", "uint16"),
2038 ("OVS_TUNNEL_ATTR_EXTENSION", "none"),
2041 class vportstats(nla):
2043 ("rx_packets", "=Q"),
2044 ("tx_packets", "=Q"),
2047 ("rx_errors", "=Q"),
2048 ("tx_errors", "=Q"),
2049 ("rx_dropped", "=Q"),
2050 ("tx_dropped", "=Q"),
2053 def type_to_str(vport_type):
2054 if vport_type == OvsVport.OVS_VPORT_TYPE_NETDEV:
2056 elif vport_type == OvsVport.OVS_VPORT_TYPE_INTERNAL:
2058 elif vport_type == OvsVport.OVS_VPORT_TYPE_GRE:
2060 elif vport_type == OvsVport.OVS_VPORT_TYPE_VXLAN:
2062 elif vport_type == OvsVport.OVS_VPORT_TYPE_GENEVE:
2064 raise ValueError("Unknown vport type:%d" % vport_type)
2066 def str_to_type(vport_type):
2067 if vport_type == "netdev":
2068 return OvsVport.OVS_VPORT_TYPE_NETDEV
2069 elif vport_type == "internal":
2070 return OvsVport.OVS_VPORT_TYPE_INTERNAL
2071 elif vport_type == "gre":
2072 return OvsVport.OVS_VPORT_TYPE_INTERNAL
2073 elif vport_type == "vxlan":
2074 return OvsVport.OVS_VPORT_TYPE_VXLAN
2075 elif vport_type == "geneve":
2076 return OvsVport.OVS_VPORT_TYPE_GENEVE
2077 raise ValueError("Unknown vport type: '%s'" % vport_type)
2079 def __init__(self, packet=OvsPacket()):
2080 GenericNetlinkSocket.__init__(self)
2081 self.bind(OVS_VPORT_FAMILY, OvsVport.ovs_vport_msg)
2082 self.upcall_packet = packet
2084 def info(self, vport_name, dpifindex=0, portno=None):
2085 msg = OvsVport.ovs_vport_msg()
2087 msg["cmd"] = OVS_VPORT_CMD_GET
2088 msg["version"] = OVS_DATAPATH_VERSION
2090 msg["dpifindex"] = dpifindex
2093 msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_name])
2095 msg["attrs"].append(["OVS_VPORT_ATTR_PORT_NO", portno])
2098 reply = self.nlm_request(
2099 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST
2102 except NetlinkError as ne:
2103 if ne.code == errno.ENODEV:
2109 def attach(self, dpindex, vport_ifname, ptype, dport, lwt):
2110 msg = OvsVport.ovs_vport_msg()
2112 msg["cmd"] = OVS_VPORT_CMD_NEW
2113 msg["version"] = OVS_DATAPATH_VERSION
2115 msg["dpifindex"] = dpindex
2116 port_type = OvsVport.str_to_type(ptype)
2118 msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_ifname])
2119 msg["attrs"].append(
2120 ["OVS_VPORT_ATTR_UPCALL_PID", [self.upcall_packet.epid]]
2123 TUNNEL_DEFAULTS = [("geneve", 6081),
2126 for tnl in TUNNEL_DEFAULTS:
2132 vportopt = OvsVport.ovs_vport_msg.vportopts()
2133 vportopt["attrs"].append(
2134 ["OVS_TUNNEL_ATTR_DST_PORT", socket.htons(dport)]
2136 msg["attrs"].append(
2137 ["OVS_VPORT_ATTR_OPTIONS", vportopt]
2140 port_type = OvsVport.OVS_VPORT_TYPE_NETDEV
2141 ipr = pyroute2.iproute.IPRoute()
2143 if tnl[0] == "geneve":
2144 ipr.link("add", ifname=vport_ifname, kind=tnl[0],
2146 geneve_collect_metadata=True,
2147 geneve_udp_zero_csum6_rx=1)
2148 elif tnl[0] == "vxlan":
2149 ipr.link("add", ifname=vport_ifname, kind=tnl[0],
2150 vxlan_learning=0, vxlan_collect_metadata=1,
2151 vxlan_udp_zero_csum6_rx=1, vxlan_port=dport)
2153 msg["attrs"].append(["OVS_VPORT_ATTR_TYPE", port_type])
2156 reply = self.nlm_request(
2157 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK
2160 except NetlinkError as ne:
2161 if ne.code == errno.EEXIST:
2167 def reset_upcall(self, dpindex, vport_ifname, p=None):
2168 msg = OvsVport.ovs_vport_msg()
2170 msg["cmd"] = OVS_VPORT_CMD_SET
2171 msg["version"] = OVS_DATAPATH_VERSION
2173 msg["dpifindex"] = dpindex
2174 msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_ifname])
2177 p = self.upcall_packet
2179 self.upcall_packet = p
2181 msg["attrs"].append(["OVS_VPORT_ATTR_UPCALL_PID", [p.epid]])
2184 reply = self.nlm_request(
2185 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK
2188 except NetlinkError as ne:
2192 def detach(self, dpindex, vport_ifname):
2193 msg = OvsVport.ovs_vport_msg()
2195 msg["cmd"] = OVS_VPORT_CMD_DEL
2196 msg["version"] = OVS_DATAPATH_VERSION
2198 msg["dpifindex"] = dpindex
2199 msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_ifname])
2202 reply = self.nlm_request(
2203 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK
2206 except NetlinkError as ne:
2207 if ne.code == errno.ENODEV:
2213 def upcall_handler(self, handler=None):
2214 self.upcall_packet.upcall_handler(handler)
2217 class OvsFlow(GenericNetlinkSocket):
2218 class ovs_flow_msg(ovs_dp_msg):
2220 ("OVS_FLOW_ATTR_UNSPEC", "none"),
2221 ("OVS_FLOW_ATTR_KEY", "ovskey"),
2222 ("OVS_FLOW_ATTR_ACTIONS", "ovsactions"),
2223 ("OVS_FLOW_ATTR_STATS", "flowstats"),
2224 ("OVS_FLOW_ATTR_TCP_FLAGS", "uint8"),
2225 ("OVS_FLOW_ATTR_USED", "uint64"),
2226 ("OVS_FLOW_ATTR_CLEAR", "none"),
2227 ("OVS_FLOW_ATTR_MASK", "ovskey"),
2228 ("OVS_FLOW_ATTR_PROBE", "none"),
2229 ("OVS_FLOW_ATTR_UFID", "array(uint32)"),
2230 ("OVS_FLOW_ATTR_UFID_FLAGS", "uint32"),
2233 class flowstats(nla):
2239 def dpstr(self, more=False):
2240 ufid = self.get_attr("OVS_FLOW_ATTR_UFID")
2242 if ufid is not None:
2244 "ufid:{:08x}-{:04x}-{:04x}-{:04x}-{:04x}{:08x}".format(
2254 key_field = self.get_attr("OVS_FLOW_ATTR_KEY")
2256 if key_field is not None:
2259 mask_field = self.get_attr("OVS_FLOW_ATTR_MASK")
2261 if mask_field is not None:
2262 maskmsg = mask_field
2264 acts_field = self.get_attr("OVS_FLOW_ATTR_ACTIONS")
2266 if acts_field is not None:
2267 actsmsg = acts_field
2272 print_str += ufid_str + ","
2274 if keymsg is not None:
2275 print_str += keymsg.dpstr(maskmsg, more)
2277 stats = self.get_attr("OVS_FLOW_ATTR_STATS")
2279 print_str += " packets:0, bytes:0,"
2281 print_str += " packets:%d, bytes:%d," % (
2286 used = self.get_attr("OVS_FLOW_ATTR_USED")
2287 print_str += " used:"
2289 print_str += "never,"
2291 used_time = int(used)
2292 cur_time_sec = time.clock_gettime(time.CLOCK_MONOTONIC)
2293 used_time = (cur_time_sec * 1000) - used_time
2294 print_str += "{}s,".format(used_time / 1000)
2296 print_str += " actions:"
2299 or "attrs" not in actsmsg
2300 or len(actsmsg["attrs"]) == 0
2304 print_str += actsmsg.dpstr(more)
2308 def parse(self, flowstr, actstr, dpidx=0):
2309 OVS_UFID_F_OMIT_KEY = 1 << 0
2310 OVS_UFID_F_OMIT_MASK = 1 << 1
2311 OVS_UFID_F_OMIT_ACTIONS = 1 << 2
2315 self["reserved"] = 0
2316 self["dpifindex"] = 0
2318 if flowstr.startswith("ufid:"):
2320 while flowstr[count] != ",":
2322 ufidstr = flowstr[5:count]
2323 flowstr = flowstr[count + 1 :]
2325 ufidstr = str(uuid.uuid4())
2326 uuidRawObj = uuid.UUID(ufidstr).fields
2328 self["attrs"].append(
2330 "OVS_FLOW_ATTR_UFID",
2333 uuidRawObj[1] << 16 | uuidRawObj[2],
2335 | uuidRawObj[4] << 16
2336 | uuidRawObj[5] & (0xFF << 32) >> 32,
2337 uuidRawObj[5] & (0xFFFFFFFF),
2341 self["attrs"].append(
2343 "OVS_FLOW_ATTR_UFID_FLAGS",
2346 | OVS_UFID_F_OMIT_MASK
2347 | OVS_UFID_F_OMIT_ACTIONS
2355 self["attrs"].append(["OVS_FLOW_ATTR_KEY", k])
2356 self["attrs"].append(["OVS_FLOW_ATTR_MASK", m])
2360 self["attrs"].append(["OVS_FLOW_ATTR_ACTIONS", a])
2363 GenericNetlinkSocket.__init__(self)
2365 self.bind(OVS_FLOW_FAMILY, OvsFlow.ovs_flow_msg)
2367 def add_flow(self, dpifindex, flowmsg):
2369 Send a new flow message to the kernel.
2371 dpifindex should be a valid datapath obtained by calling
2372 into the OvsDatapath lookup
2374 flowmsg is a flow object obtained by calling a dpparse
2377 flowmsg["cmd"] = OVS_FLOW_CMD_NEW
2378 flowmsg["version"] = OVS_DATAPATH_VERSION
2379 flowmsg["reserved"] = 0
2380 flowmsg["dpifindex"] = dpifindex
2383 reply = self.nlm_request(
2386 msg_flags=NLM_F_REQUEST | NLM_F_ACK,
2389 except NetlinkError as ne:
2394 def del_flows(self, dpifindex):
2396 Send a del message to the kernel that will drop all flows.
2398 dpifindex should be a valid datapath obtained by calling
2399 into the OvsDatapath lookup
2402 flowmsg = OvsFlow.ovs_flow_msg()
2403 flowmsg["cmd"] = OVS_FLOW_CMD_DEL
2404 flowmsg["version"] = OVS_DATAPATH_VERSION
2405 flowmsg["reserved"] = 0
2406 flowmsg["dpifindex"] = dpifindex
2409 reply = self.nlm_request(
2412 msg_flags=NLM_F_REQUEST | NLM_F_ACK,
2415 except NetlinkError as ne:
2420 def dump(self, dpifindex, flowspec=None):
2422 Returns a list of messages containing flows.
2424 dpifindex should be a valid datapath obtained by calling
2425 into the OvsDatapath lookup
2427 flowpsec is a string which represents a flow in the dpctl
2430 msg = OvsFlow.ovs_flow_msg()
2432 msg["cmd"] = OVS_FLOW_CMD_GET
2433 msg["version"] = OVS_DATAPATH_VERSION
2435 msg["dpifindex"] = dpifindex
2437 msg_flags = NLM_F_REQUEST | NLM_F_ACK
2438 if flowspec is None:
2439 msg_flags |= NLM_F_DUMP
2443 rep = self.nlm_request(
2446 msg_flags=msg_flags,
2448 except NetlinkError as ne:
2452 def miss(self, packetmsg):
2453 seq = packetmsg["header"]["sequence_number"]
2455 key_field = packetmsg.get_attr("OVS_PACKET_ATTR_KEY")
2456 if key_field is not None:
2457 keystr = key_field.dpstr(None, True)
2459 pktdata = packetmsg.get_attr("OVS_PACKET_ATTR_PACKET")
2460 pktpres = "yes" if pktdata is not None else "no"
2462 print("MISS upcall[%d/%s]: %s" % (seq, pktpres, keystr), flush=True)
2464 def execute(self, packetmsg):
2465 print("userspace execute command", flush=True)
2467 def action(self, packetmsg):
2468 print("userspace action command", flush=True)
2471 class psample_sample(genlmsg):
2473 ("PSAMPLE_ATTR_IIFINDEX", "none"),
2474 ("PSAMPLE_ATTR_OIFINDEX", "none"),
2475 ("PSAMPLE_ATTR_ORIGSIZE", "none"),
2476 ("PSAMPLE_ATTR_SAMPLE_GROUP", "uint32"),
2477 ("PSAMPLE_ATTR_GROUP_SEQ", "none"),
2478 ("PSAMPLE_ATTR_SAMPLE_RATE", "uint32"),
2479 ("PSAMPLE_ATTR_DATA", "array(uint8)"),
2480 ("PSAMPLE_ATTR_GROUP_REFCOUNT", "none"),
2481 ("PSAMPLE_ATTR_TUNNEL", "none"),
2482 ("PSAMPLE_ATTR_PAD", "none"),
2483 ("PSAMPLE_ATTR_OUT_TC", "none"),
2484 ("PSAMPLE_ATTR_OUT_TC_OCC", "none"),
2485 ("PSAMPLE_ATTR_LATENCY", "none"),
2486 ("PSAMPLE_ATTR_TIMESTAMP", "none"),
2487 ("PSAMPLE_ATTR_PROTO", "none"),
2488 ("PSAMPLE_ATTR_USER_COOKIE", "array(uint8)"),
2494 for (attr, value) in self["attrs"]:
2495 if attr == "PSAMPLE_ATTR_SAMPLE_GROUP":
2496 fields.append("group:%d" % value)
2497 if attr == "PSAMPLE_ATTR_SAMPLE_RATE":
2498 fields.append("rate:%d" % value)
2499 if attr == "PSAMPLE_ATTR_USER_COOKIE":
2500 value = "".join(format(x, "02x") for x in value)
2501 fields.append("cookie:%s" % value)
2502 if attr == "PSAMPLE_ATTR_DATA" and len(value) > 0:
2503 data = "data:%s" % "".join(format(x, "02x") for x in value)
2505 return ("%s %s" % (",".join(fields), data)).strip()
2508 class psample_msg(Marshal):
2509 PSAMPLE_CMD_SAMPLE = 0
2510 PSAMPLE_CMD_GET_GROUP = 1
2511 PSAMPLE_CMD_NEW_GROUP = 2
2512 PSAMPLE_CMD_DEL_GROUP = 3
2513 PSAMPLE_CMD_SET_FILTER = 4
2514 msg_map = {PSAMPLE_CMD_SAMPLE: psample_sample}
2517 class PsampleEvent(EventSocket):
2518 genl_family = "psample"
2519 mcast_groups = ["packets"]
2520 marshal_class = psample_msg
2522 def read_samples(self):
2523 print("listening for psample events", flush=True)
2526 for msg in self.get():
2527 print(msg.dpstr(), flush=True)
2528 except NetlinkError as ne:
2532 def print_ovsdp_full(dp_lookup_rep, ifindex, ndb=NDB(), vpl=OvsVport()):
2533 dp_name = dp_lookup_rep.get_attr("OVS_DP_ATTR_NAME")
2534 base_stats = dp_lookup_rep.get_attr("OVS_DP_ATTR_STATS")
2535 megaflow_stats = dp_lookup_rep.get_attr("OVS_DP_ATTR_MEGAFLOW_STATS")
2536 user_features = dp_lookup_rep.get_attr("OVS_DP_ATTR_USER_FEATURES")
2537 masks_cache_size = dp_lookup_rep.get_attr("OVS_DP_ATTR_MASKS_CACHE_SIZE")
2539 print("%s:" % dp_name)
2541 " lookups: hit:%d missed:%d lost:%d"
2542 % (base_stats["hit"], base_stats["missed"], base_stats["lost"])
2544 print(" flows:%d" % base_stats["flows"])
2545 pkts = base_stats["hit"] + base_stats["missed"]
2546 avg = (megaflow_stats["mask_hit"] / pkts) if pkts != 0 else 0.0
2548 " masks: hit:%d total:%d hit/pkt:%f"
2549 % (megaflow_stats["mask_hit"], megaflow_stats["masks"], avg)
2552 print(" masks-cache: size:%d" % masks_cache_size)
2554 if user_features is not None:
2555 print(" features: 0x%X" % user_features)
2558 for iface in ndb.interfaces:
2559 rep = vpl.info(iface.ifname, ifindex)
2562 vpo = rep.get_attr("OVS_VPORT_ATTR_OPTIONS")
2564 dpo = vpo.get_attr("OVS_TUNNEL_ATTR_DST_PORT")
2566 opts += " tnl-dport:%s" % socket.ntohs(dpo)
2568 " port %d: %s (%s%s)"
2570 rep.get_attr("OVS_VPORT_ATTR_PORT_NO"),
2571 rep.get_attr("OVS_VPORT_ATTR_NAME"),
2572 OvsVport.type_to_str(rep.get_attr("OVS_VPORT_ATTR_TYPE")),
2579 nlmsg_atoms.ovskey = ovskey
2580 nlmsg_atoms.ovsactions = ovsactions
2582 # version check for pyroute2
2583 prverscheck = pyroute2.__version__.split(".")
2584 if int(prverscheck[0]) == 0 and int(prverscheck[1]) < 6:
2585 print("Need to upgrade the python pyroute2 package to >= 0.6.")
2588 parser = argparse.ArgumentParser()
2589 parser.add_argument(
2593 help="Increment 'verbose' output counter.",
2596 subparsers = parser.add_subparsers(dest="subcommand")
2598 showdpcmd = subparsers.add_parser("show")
2599 showdpcmd.add_argument(
2600 "showdp", metavar="N", type=str, nargs="?", help="Datapath Name"
2603 adddpcmd = subparsers.add_parser("add-dp")
2604 adddpcmd.add_argument("adddp", help="Datapath Name")
2605 adddpcmd.add_argument(
2608 action="store_true",
2609 help="Leave open a reader for upcalls",
2611 adddpcmd.add_argument(
2615 help="Specify a custom version / feature string",
2618 deldpcmd = subparsers.add_parser("del-dp")
2619 deldpcmd.add_argument("deldp", help="Datapath Name")
2621 addifcmd = subparsers.add_parser("add-if")
2622 addifcmd.add_argument("dpname", help="Datapath Name")
2623 addifcmd.add_argument("addif", help="Interface name for adding")
2624 addifcmd.add_argument(
2627 action="store_true",
2628 help="Leave open a reader for upcalls",
2630 addifcmd.add_argument(
2635 choices=["netdev", "internal", "geneve", "vxlan"],
2636 help="Interface type (default netdev)",
2638 addifcmd.add_argument(
2643 help="Destination port (0 for default)"
2645 addifcmd.add_argument(
2650 help="Use LWT infrastructure instead of vport (default true)."
2652 delifcmd = subparsers.add_parser("del-if")
2653 delifcmd.add_argument("dpname", help="Datapath Name")
2654 delifcmd.add_argument("delif", help="Interface name for adding")
2655 delifcmd.add_argument("-d",
2657 type=bool, default=False,
2658 help="Delete the link as well.")
2660 dumpflcmd = subparsers.add_parser("dump-flows")
2661 dumpflcmd.add_argument("dumpdp", help="Datapath Name")
2663 addflcmd = subparsers.add_parser("add-flow")
2664 addflcmd.add_argument("flbr", help="Datapath name")
2665 addflcmd.add_argument("flow", help="Flow specification")
2666 addflcmd.add_argument("acts", help="Flow actions")
2668 delfscmd = subparsers.add_parser("del-flows")
2669 delfscmd.add_argument("flsbr", help="Datapath name")
2671 subparsers.add_parser("psample-events")
2673 args = parser.parse_args()
2675 if args.verbose > 0:
2676 if args.verbose > 1:
2677 logging.basicConfig(level=logging.DEBUG)
2680 ovsdp = OvsDatapath()
2681 ovsvp = OvsVport(ovspk)
2685 sys.setrecursionlimit(100000)
2687 if args.subcommand == "psample-events":
2688 PsampleEvent().read_samples()
2690 if hasattr(args, "showdp"):
2692 for iface in ndb.interfaces:
2694 if args.showdp is None:
2695 rep = ovsdp.info(iface.ifname, 0)
2696 elif args.showdp == iface.ifname:
2697 rep = ovsdp.info(iface.ifname, 0)
2701 print_ovsdp_full(rep, iface.index, ndb, ovsvp)
2705 if args.showdp is not None:
2706 msg += ":'%s'" % args.showdp
2708 elif hasattr(args, "adddp"):
2709 rep = ovsdp.create(args.adddp, args.upcall, args.versioning, ovspk)
2711 print("DP '%s' already exists" % args.adddp)
2713 print("DP '%s' added" % args.adddp)
2715 ovspk.upcall_handler(ovsflow)
2716 elif hasattr(args, "deldp"):
2717 ovsdp.destroy(args.deldp)
2718 elif hasattr(args, "addif"):
2719 rep = ovsdp.info(args.dpname, 0)
2721 print("DP '%s' not found." % args.dpname)
2723 dpindex = rep["dpifindex"]
2724 rep = ovsvp.attach(rep["dpifindex"], args.addif, args.ptype,
2725 args.dport, args.lwt)
2726 msg = "vport '%s'" % args.addif
2727 if rep and rep["header"]["error"] is None:
2730 msg += " failed to add."
2733 rep = ovsvp.reset_upcall(dpindex, args.addif, ovspk)
2734 ovsvp.upcall_handler(ovsflow)
2735 elif hasattr(args, "delif"):
2736 rep = ovsdp.info(args.dpname, 0)
2738 print("DP '%s' not found." % args.dpname)
2740 rep = ovsvp.detach(rep["dpifindex"], args.delif)
2741 msg = "vport '%s'" % args.delif
2742 if rep and rep["header"]["error"] is None:
2745 msg += " failed to remove."
2747 ipr = pyroute2.iproute.IPRoute()
2748 ipr.link("del", index=ipr.link_lookup(ifname=args.delif)[0])
2749 elif hasattr(args, "dumpdp"):
2750 rep = ovsdp.info(args.dumpdp, 0)
2752 print("DP '%s' not found." % args.dumpdp)
2754 rep = ovsflow.dump(rep["dpifindex"])
2756 print(flow.dpstr(True if args.verbose > 0 else False))
2757 elif hasattr(args, "flbr"):
2758 rep = ovsdp.info(args.flbr, 0)
2760 print("DP '%s' not found." % args.flbr)
2762 flow = OvsFlow.ovs_flow_msg()
2763 flow.parse(args.flow, args.acts, rep["dpifindex"])
2764 ovsflow.add_flow(rep["dpifindex"], flow)
2765 elif hasattr(args, "flsbr"):
2766 rep = ovsdp.info(args.flsbr, 0)
2768 print("DP '%s' not found." % args.flsbr)
2769 ovsflow.del_flows(rep["dpifindex"])
2774 if __name__ == "__main__":
2775 sys.exit(main(sys.argv))