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
))