Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1#!/usr/bin/env python3
2# SPDX-License-Identifier: GPL-2.0
3
4# Controls the openvswitch module. Part of the kselftest suite, but
5# can be used for some diagnostic purpose as well.
6
7import argparse
8import errno
9import ipaddress
10import logging
11import multiprocessing
12import struct
13import sys
14import time
15
16try:
17 from pyroute2 import NDB
18
19 from pyroute2.netlink import NLA_F_NESTED
20 from pyroute2.netlink import NLM_F_ACK
21 from pyroute2.netlink import NLM_F_DUMP
22 from pyroute2.netlink import NLM_F_REQUEST
23 from pyroute2.netlink import genlmsg
24 from pyroute2.netlink import nla
25 from pyroute2.netlink import nlmsg_atoms
26 from pyroute2.netlink.exceptions import NetlinkError
27 from pyroute2.netlink.generic import GenericNetlinkSocket
28except ModuleNotFoundError:
29 print("Need to install the python pyroute2 package.")
30 sys.exit(0)
31
32
33OVS_DATAPATH_FAMILY = "ovs_datapath"
34OVS_VPORT_FAMILY = "ovs_vport"
35OVS_FLOW_FAMILY = "ovs_flow"
36OVS_PACKET_FAMILY = "ovs_packet"
37OVS_METER_FAMILY = "ovs_meter"
38OVS_CT_LIMIT_FAMILY = "ovs_ct_limit"
39
40OVS_DATAPATH_VERSION = 2
41OVS_DP_CMD_NEW = 1
42OVS_DP_CMD_DEL = 2
43OVS_DP_CMD_GET = 3
44OVS_DP_CMD_SET = 4
45
46OVS_VPORT_CMD_NEW = 1
47OVS_VPORT_CMD_DEL = 2
48OVS_VPORT_CMD_GET = 3
49OVS_VPORT_CMD_SET = 4
50
51OVS_FLOW_CMD_NEW = 1
52OVS_FLOW_CMD_DEL = 2
53OVS_FLOW_CMD_GET = 3
54OVS_FLOW_CMD_SET = 4
55
56
57def macstr(mac):
58 outstr = ":".join(["%02X" % i for i in mac])
59 return outstr
60
61
62def convert_mac(mac_str, mask=False):
63 if mac_str is None or mac_str == "":
64 mac_str = "00:00:00:00:00:00"
65 if mask is True and mac_str != "00:00:00:00:00:00":
66 mac_str = "FF:FF:FF:FF:FF:FF"
67 mac_split = mac_str.split(":")
68 ret = bytearray([int(i, 16) for i in mac_split])
69 return bytes(ret)
70
71
72def convert_ipv4(ip, mask=False):
73 if ip is None:
74 ip = 0
75 if mask is True:
76 if ip != 0:
77 ip = int(ipaddress.IPv4Address(ip)) & 0xFFFFFFFF
78
79 return int(ipaddress.IPv4Address(ip))
80
81
82class ovs_dp_msg(genlmsg):
83 # include the OVS version
84 # We need a custom header rather than just being able to rely on
85 # genlmsg because fields ends up not expressing everything correctly
86 # if we use the canonical example of setting fields = (('customfield',),)
87 fields = genlmsg.fields + (("dpifindex", "I"),)
88
89
90class ovsactions(nla):
91 nla_flags = NLA_F_NESTED
92
93 nla_map = (
94 ("OVS_ACTION_ATTR_UNSPEC", "none"),
95 ("OVS_ACTION_ATTR_OUTPUT", "uint32"),
96 ("OVS_ACTION_ATTR_USERSPACE", "userspace"),
97 ("OVS_ACTION_ATTR_SET", "none"),
98 ("OVS_ACTION_ATTR_PUSH_VLAN", "none"),
99 ("OVS_ACTION_ATTR_POP_VLAN", "flag"),
100 ("OVS_ACTION_ATTR_SAMPLE", "none"),
101 ("OVS_ACTION_ATTR_RECIRC", "uint32"),
102 ("OVS_ACTION_ATTR_HASH", "none"),
103 ("OVS_ACTION_ATTR_PUSH_MPLS", "none"),
104 ("OVS_ACTION_ATTR_POP_MPLS", "flag"),
105 ("OVS_ACTION_ATTR_SET_MASKED", "none"),
106 ("OVS_ACTION_ATTR_CT", "ctact"),
107 ("OVS_ACTION_ATTR_TRUNC", "uint32"),
108 ("OVS_ACTION_ATTR_PUSH_ETH", "none"),
109 ("OVS_ACTION_ATTR_POP_ETH", "flag"),
110 ("OVS_ACTION_ATTR_CT_CLEAR", "flag"),
111 ("OVS_ACTION_ATTR_PUSH_NSH", "none"),
112 ("OVS_ACTION_ATTR_POP_NSH", "flag"),
113 ("OVS_ACTION_ATTR_METER", "none"),
114 ("OVS_ACTION_ATTR_CLONE", "none"),
115 ("OVS_ACTION_ATTR_CHECK_PKT_LEN", "none"),
116 ("OVS_ACTION_ATTR_ADD_MPLS", "none"),
117 ("OVS_ACTION_ATTR_DEC_TTL", "none"),
118 )
119
120 class ctact(nla):
121 nla_flags = NLA_F_NESTED
122
123 nla_map = (
124 ("OVS_CT_ATTR_NONE", "none"),
125 ("OVS_CT_ATTR_COMMIT", "flag"),
126 ("OVS_CT_ATTR_ZONE", "uint16"),
127 ("OVS_CT_ATTR_MARK", "none"),
128 ("OVS_CT_ATTR_LABELS", "none"),
129 ("OVS_CT_ATTR_HELPER", "asciiz"),
130 ("OVS_CT_ATTR_NAT", "natattr"),
131 ("OVS_CT_ATTR_FORCE_COMMIT", "flag"),
132 ("OVS_CT_ATTR_EVENTMASK", "uint32"),
133 ("OVS_CT_ATTR_TIMEOUT", "asciiz"),
134 )
135
136 class natattr(nla):
137 nla_flags = NLA_F_NESTED
138
139 nla_map = (
140 ("OVS_NAT_ATTR_NONE", "none"),
141 ("OVS_NAT_ATTR_SRC", "flag"),
142 ("OVS_NAT_ATTR_DST", "flag"),
143 ("OVS_NAT_ATTR_IP_MIN", "ipaddr"),
144 ("OVS_NAT_ATTR_IP_MAX", "ipaddr"),
145 ("OVS_NAT_ATTR_PROTO_MIN", "uint16"),
146 ("OVS_NAT_ATTR_PROTO_MAX", "uint16"),
147 ("OVS_NAT_ATTR_PERSISTENT", "flag"),
148 ("OVS_NAT_ATTR_PROTO_HASH", "flag"),
149 ("OVS_NAT_ATTR_PROTO_RANDOM", "flag"),
150 )
151
152 def dpstr(self, more=False):
153 print_str = "nat("
154
155 if self.get_attr("OVS_NAT_ATTR_SRC"):
156 print_str += "src"
157 elif self.get_attr("OVS_NAT_ATTR_DST"):
158 print_str += "dst"
159 else:
160 print_str += "XXX-unknown-nat"
161
162 if self.get_attr("OVS_NAT_ATTR_IP_MIN") or self.get_attr(
163 "OVS_NAT_ATTR_IP_MAX"
164 ):
165 if self.get_attr("OVS_NAT_ATTR_IP_MIN"):
166 print_str += "=%s," % str(
167 self.get_attr("OVS_NAT_ATTR_IP_MIN")
168 )
169
170 if self.get_attr("OVS_NAT_ATTR_IP_MAX"):
171 print_str += "-%s," % str(
172 self.get_attr("OVS_NAT_ATTR_IP_MAX")
173 )
174 else:
175 print_str += ","
176
177 if self.get_attr("OVS_NAT_ATTR_PROTO_MIN"):
178 print_str += "proto_min=%d," % self.get_attr(
179 "OVS_NAT_ATTR_PROTO_MIN"
180 )
181
182 if self.get_attr("OVS_NAT_ATTR_PROTO_MAX"):
183 print_str += "proto_max=%d," % self.get_attr(
184 "OVS_NAT_ATTR_PROTO_MAX"
185 )
186
187 if self.get_attr("OVS_NAT_ATTR_PERSISTENT"):
188 print_str += "persistent,"
189 if self.get_attr("OVS_NAT_ATTR_HASH"):
190 print_str += "hash,"
191 if self.get_attr("OVS_NAT_ATTR_RANDOM"):
192 print_str += "random"
193 print_str += ")"
194 return print_str
195
196 def dpstr(self, more=False):
197 print_str = "ct("
198
199 if self.get_attr("OVS_CT_ATTR_COMMIT") is not None:
200 print_str += "commit,"
201 if self.get_attr("OVS_CT_ATTR_ZONE") is not None:
202 print_str += "zone=%d," % self.get_attr("OVS_CT_ATTR_ZONE")
203 if self.get_attr("OVS_CT_ATTR_HELPER") is not None:
204 print_str += "helper=%s," % self.get_attr("OVS_CT_ATTR_HELPER")
205 if self.get_attr("OVS_CT_ATTR_NAT") is not None:
206 print_str += self.get_attr("OVS_CT_ATTR_NAT").dpstr(more)
207 print_str += ","
208 if self.get_attr("OVS_CT_ATTR_FORCE_COMMIT") is not None:
209 print_str += "force,"
210 if self.get_attr("OVS_CT_ATTR_EVENTMASK") is not None:
211 print_str += "emask=0x%X," % self.get_attr(
212 "OVS_CT_ATTR_EVENTMASK"
213 )
214 if self.get_attr("OVS_CT_ATTR_TIMEOUT") is not None:
215 print_str += "timeout=%s" % self.get_attr(
216 "OVS_CT_ATTR_TIMEOUT"
217 )
218 print_str += ")"
219 return print_str
220
221 class userspace(nla):
222 nla_flags = NLA_F_NESTED
223
224 nla_map = (
225 ("OVS_USERSPACE_ATTR_UNUSED", "none"),
226 ("OVS_USERSPACE_ATTR_PID", "uint32"),
227 ("OVS_USERSPACE_ATTR_USERDATA", "array(uint8)"),
228 ("OVS_USERSPACE_ATTR_EGRESS_TUN_PORT", "uint32"),
229 )
230
231 def dpstr(self, more=False):
232 print_str = "userspace("
233 if self.get_attr("OVS_USERSPACE_ATTR_PID") is not None:
234 print_str += "pid=%d," % self.get_attr(
235 "OVS_USERSPACE_ATTR_PID"
236 )
237 if self.get_attr("OVS_USERSPACE_ATTR_USERDATA") is not None:
238 print_str += "userdata="
239 for f in self.get_attr("OVS_USERSPACE_ATTR_USERDATA"):
240 print_str += "%x." % f
241 if self.get_attr("OVS_USERSPACE_ATTR_TUN_PORT") is not None:
242 print_str += "egress_tun_port=%d" % self.get_attr(
243 "OVS_USERSPACE_ATTR_TUN_PORT"
244 )
245 print_str += ")"
246 return print_str
247
248 def dpstr(self, more=False):
249 print_str = ""
250
251 for field in self.nla_map:
252 if field[1] == "none" or self.get_attr(field[0]) is None:
253 continue
254 if print_str != "":
255 print_str += ","
256
257 if field[1] == "uint32":
258 if field[0] == "OVS_ACTION_ATTR_OUTPUT":
259 print_str += "%d" % int(self.get_attr(field[0]))
260 elif field[0] == "OVS_ACTION_ATTR_RECIRC":
261 print_str += "recirc(0x%x)" % int(self.get_attr(field[0]))
262 elif field[0] == "OVS_ACTION_ATTR_TRUNC":
263 print_str += "trunc(%d)" % int(self.get_attr(field[0]))
264 elif field[1] == "flag":
265 if field[0] == "OVS_ACTION_ATTR_CT_CLEAR":
266 print_str += "ct_clear"
267 elif field[0] == "OVS_ACTION_ATTR_POP_VLAN":
268 print_str += "pop_vlan"
269 elif field[0] == "OVS_ACTION_ATTR_POP_ETH":
270 print_str += "pop_eth"
271 elif field[0] == "OVS_ACTION_ATTR_POP_NSH":
272 print_str += "pop_nsh"
273 elif field[0] == "OVS_ACTION_ATTR_POP_MPLS":
274 print_str += "pop_mpls"
275 else:
276 datum = self.get_attr(field[0])
277 print_str += datum.dpstr(more)
278
279 return print_str
280
281
282class ovskey(nla):
283 nla_flags = NLA_F_NESTED
284 nla_map = (
285 ("OVS_KEY_ATTR_UNSPEC", "none"),
286 ("OVS_KEY_ATTR_ENCAP", "none"),
287 ("OVS_KEY_ATTR_PRIORITY", "uint32"),
288 ("OVS_KEY_ATTR_IN_PORT", "uint32"),
289 ("OVS_KEY_ATTR_ETHERNET", "ethaddr"),
290 ("OVS_KEY_ATTR_VLAN", "uint16"),
291 ("OVS_KEY_ATTR_ETHERTYPE", "be16"),
292 ("OVS_KEY_ATTR_IPV4", "ovs_key_ipv4"),
293 ("OVS_KEY_ATTR_IPV6", "ovs_key_ipv6"),
294 ("OVS_KEY_ATTR_TCP", "ovs_key_tcp"),
295 ("OVS_KEY_ATTR_UDP", "ovs_key_udp"),
296 ("OVS_KEY_ATTR_ICMP", "ovs_key_icmp"),
297 ("OVS_KEY_ATTR_ICMPV6", "ovs_key_icmpv6"),
298 ("OVS_KEY_ATTR_ARP", "ovs_key_arp"),
299 ("OVS_KEY_ATTR_ND", "ovs_key_nd"),
300 ("OVS_KEY_ATTR_SKB_MARK", "uint32"),
301 ("OVS_KEY_ATTR_TUNNEL", "none"),
302 ("OVS_KEY_ATTR_SCTP", "ovs_key_sctp"),
303 ("OVS_KEY_ATTR_TCP_FLAGS", "be16"),
304 ("OVS_KEY_ATTR_DP_HASH", "uint32"),
305 ("OVS_KEY_ATTR_RECIRC_ID", "uint32"),
306 ("OVS_KEY_ATTR_MPLS", "array(ovs_key_mpls)"),
307 ("OVS_KEY_ATTR_CT_STATE", "uint32"),
308 ("OVS_KEY_ATTR_CT_ZONE", "uint16"),
309 ("OVS_KEY_ATTR_CT_MARK", "uint32"),
310 ("OVS_KEY_ATTR_CT_LABELS", "none"),
311 ("OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4", "ovs_key_ct_tuple_ipv4"),
312 ("OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6", "ovs_key_ct_tuple_ipv6"),
313 ("OVS_KEY_ATTR_NSH", "none"),
314 ("OVS_KEY_ATTR_PACKET_TYPE", "none"),
315 ("OVS_KEY_ATTR_ND_EXTENSIONS", "none"),
316 ("OVS_KEY_ATTR_TUNNEL_INFO", "none"),
317 ("OVS_KEY_ATTR_IPV6_EXTENSIONS", "none"),
318 )
319
320 class ovs_key_proto(nla):
321 fields = (
322 ("src", "!H"),
323 ("dst", "!H"),
324 )
325
326 fields_map = (
327 ("src", "src", "%d", lambda x: int(x) if x is not None else 0),
328 ("dst", "dst", "%d", lambda x: int(x) if x is not None else 0),
329 )
330
331 def __init__(
332 self,
333 protostr,
334 data=None,
335 offset=None,
336 parent=None,
337 length=None,
338 init=None,
339 ):
340 self.proto_str = protostr
341 nla.__init__(
342 self,
343 data=data,
344 offset=offset,
345 parent=parent,
346 length=length,
347 init=init,
348 )
349
350 def dpstr(self, masked=None, more=False):
351 outstr = self.proto_str + "("
352 first = False
353 for f in self.fields_map:
354 if first:
355 outstr += ","
356 if masked is None:
357 outstr += "%s=" % f[0]
358 if isinstance(f[2], str):
359 outstr += f[2] % self[f[1]]
360 else:
361 outstr += f[2](self[f[1]])
362 first = True
363 elif more or f[3](masked[f[1]]) != 0:
364 outstr += "%s=" % f[0]
365 if isinstance(f[2], str):
366 outstr += f[2] % self[f[1]]
367 else:
368 outstr += f[2](self[f[1]])
369 outstr += "/"
370 if isinstance(f[2], str):
371 outstr += f[2] % masked[f[1]]
372 else:
373 outstr += f[2](masked[f[1]])
374 first = True
375 outstr += ")"
376 return outstr
377
378 class ethaddr(ovs_key_proto):
379 fields = (
380 ("src", "!6s"),
381 ("dst", "!6s"),
382 )
383
384 fields_map = (
385 (
386 "src",
387 "src",
388 macstr,
389 lambda x: int.from_bytes(x, "big"),
390 convert_mac,
391 ),
392 (
393 "dst",
394 "dst",
395 macstr,
396 lambda x: int.from_bytes(x, "big"),
397 convert_mac,
398 ),
399 )
400
401 def __init__(
402 self,
403 data=None,
404 offset=None,
405 parent=None,
406 length=None,
407 init=None,
408 ):
409 ovskey.ovs_key_proto.__init__(
410 self,
411 "eth",
412 data=data,
413 offset=offset,
414 parent=parent,
415 length=length,
416 init=init,
417 )
418
419 class ovs_key_ipv4(ovs_key_proto):
420 fields = (
421 ("src", "!I"),
422 ("dst", "!I"),
423 ("proto", "B"),
424 ("tos", "B"),
425 ("ttl", "B"),
426 ("frag", "B"),
427 )
428
429 fields_map = (
430 (
431 "src",
432 "src",
433 lambda x: str(ipaddress.IPv4Address(x)),
434 int,
435 convert_ipv4,
436 ),
437 (
438 "dst",
439 "dst",
440 lambda x: str(ipaddress.IPv4Address(x)),
441 int,
442 convert_ipv4,
443 ),
444 ("proto", "proto", "%d", lambda x: int(x) if x is not None else 0),
445 ("tos", "tos", "%d", lambda x: int(x) if x is not None else 0),
446 ("ttl", "ttl", "%d", lambda x: int(x) if x is not None else 0),
447 ("frag", "frag", "%d", lambda x: int(x) if x is not None else 0),
448 )
449
450 def __init__(
451 self,
452 data=None,
453 offset=None,
454 parent=None,
455 length=None,
456 init=None,
457 ):
458 ovskey.ovs_key_proto.__init__(
459 self,
460 "ipv4",
461 data=data,
462 offset=offset,
463 parent=parent,
464 length=length,
465 init=init,
466 )
467
468 class ovs_key_ipv6(ovs_key_proto):
469 fields = (
470 ("src", "!16s"),
471 ("dst", "!16s"),
472 ("label", "!I"),
473 ("proto", "B"),
474 ("tclass", "B"),
475 ("hlimit", "B"),
476 ("frag", "B"),
477 )
478
479 fields_map = (
480 (
481 "src",
482 "src",
483 lambda x: str(ipaddress.IPv6Address(x)),
484 lambda x: int.from_bytes(x, "big"),
485 lambda x: ipaddress.IPv6Address(x),
486 ),
487 (
488 "dst",
489 "dst",
490 lambda x: str(ipaddress.IPv6Address(x)),
491 lambda x: int.from_bytes(x, "big"),
492 lambda x: ipaddress.IPv6Address(x),
493 ),
494 ("label", "label", "%d", int),
495 ("proto", "proto", "%d", int),
496 ("tclass", "tclass", "%d", int),
497 ("hlimit", "hlimit", "%d", int),
498 ("frag", "frag", "%d", int),
499 )
500
501 def __init__(
502 self,
503 data=None,
504 offset=None,
505 parent=None,
506 length=None,
507 init=None,
508 ):
509 ovskey.ovs_key_proto.__init__(
510 self,
511 "ipv6",
512 data=data,
513 offset=offset,
514 parent=parent,
515 length=length,
516 init=init,
517 )
518
519 class ovs_key_tcp(ovs_key_proto):
520 def __init__(
521 self,
522 data=None,
523 offset=None,
524 parent=None,
525 length=None,
526 init=None,
527 ):
528 ovskey.ovs_key_proto.__init__(
529 self,
530 "tcp",
531 data=data,
532 offset=offset,
533 parent=parent,
534 length=length,
535 init=init,
536 )
537
538 class ovs_key_udp(ovs_key_proto):
539 def __init__(
540 self,
541 data=None,
542 offset=None,
543 parent=None,
544 length=None,
545 init=None,
546 ):
547 ovskey.ovs_key_proto.__init__(
548 self,
549 "udp",
550 data=data,
551 offset=offset,
552 parent=parent,
553 length=length,
554 init=init,
555 )
556
557 class ovs_key_sctp(ovs_key_proto):
558 def __init__(
559 self,
560 data=None,
561 offset=None,
562 parent=None,
563 length=None,
564 init=None,
565 ):
566 ovskey.ovs_key_proto.__init__(
567 self,
568 "sctp",
569 data=data,
570 offset=offset,
571 parent=parent,
572 length=length,
573 init=init,
574 )
575
576 class ovs_key_icmp(ovs_key_proto):
577 fields = (
578 ("type", "B"),
579 ("code", "B"),
580 )
581
582 fields_map = (
583 ("type", "type", "%d", int),
584 ("code", "code", "%d", int),
585 )
586
587 def __init__(
588 self,
589 data=None,
590 offset=None,
591 parent=None,
592 length=None,
593 init=None,
594 ):
595 ovskey.ovs_key_proto.__init__(
596 self,
597 "icmp",
598 data=data,
599 offset=offset,
600 parent=parent,
601 length=length,
602 init=init,
603 )
604
605 class ovs_key_icmpv6(ovs_key_icmp):
606 def __init__(
607 self,
608 data=None,
609 offset=None,
610 parent=None,
611 length=None,
612 init=None,
613 ):
614 ovskey.ovs_key_proto.__init__(
615 self,
616 "icmpv6",
617 data=data,
618 offset=offset,
619 parent=parent,
620 length=length,
621 init=init,
622 )
623
624 class ovs_key_arp(ovs_key_proto):
625 fields = (
626 ("sip", "!I"),
627 ("tip", "!I"),
628 ("op", "!H"),
629 ("sha", "!6s"),
630 ("tha", "!6s"),
631 ("pad", "xx"),
632 )
633
634 fields_map = (
635 (
636 "sip",
637 "sip",
638 lambda x: str(ipaddress.IPv4Address(x)),
639 int,
640 convert_ipv4,
641 ),
642 (
643 "tip",
644 "tip",
645 lambda x: str(ipaddress.IPv4Address(x)),
646 int,
647 convert_ipv4,
648 ),
649 ("op", "op", "%d", lambda x: int(x) if x is not None else 0),
650 (
651 "sha",
652 "sha",
653 macstr,
654 lambda x: int.from_bytes(x, "big"),
655 convert_mac,
656 ),
657 (
658 "tha",
659 "tha",
660 macstr,
661 lambda x: int.from_bytes(x, "big"),
662 convert_mac,
663 ),
664 )
665
666 def __init__(
667 self,
668 data=None,
669 offset=None,
670 parent=None,
671 length=None,
672 init=None,
673 ):
674 ovskey.ovs_key_proto.__init__(
675 self,
676 "arp",
677 data=data,
678 offset=offset,
679 parent=parent,
680 length=length,
681 init=init,
682 )
683
684 class ovs_key_nd(ovs_key_proto):
685 fields = (
686 ("target", "!16s"),
687 ("sll", "!6s"),
688 ("tll", "!6s"),
689 )
690
691 fields_map = (
692 (
693 "target",
694 "target",
695 lambda x: str(ipaddress.IPv6Address(x)),
696 lambda x: int.from_bytes(x, "big"),
697 ),
698 ("sll", "sll", macstr, lambda x: int.from_bytes(x, "big")),
699 ("tll", "tll", macstr, lambda x: int.from_bytes(x, "big")),
700 )
701
702 def __init__(
703 self,
704 data=None,
705 offset=None,
706 parent=None,
707 length=None,
708 init=None,
709 ):
710 ovskey.ovs_key_proto.__init__(
711 self,
712 "nd",
713 data=data,
714 offset=offset,
715 parent=parent,
716 length=length,
717 init=init,
718 )
719
720 class ovs_key_ct_tuple_ipv4(ovs_key_proto):
721 fields = (
722 ("src", "!I"),
723 ("dst", "!I"),
724 ("tp_src", "!H"),
725 ("tp_dst", "!H"),
726 ("proto", "B"),
727 )
728
729 fields_map = (
730 (
731 "src",
732 "src",
733 lambda x: str(ipaddress.IPv4Address(x)),
734 int,
735 ),
736 (
737 "dst",
738 "dst",
739 lambda x: str(ipaddress.IPv6Address(x)),
740 int,
741 ),
742 ("tp_src", "tp_src", "%d", int),
743 ("tp_dst", "tp_dst", "%d", int),
744 ("proto", "proto", "%d", int),
745 )
746
747 def __init__(
748 self,
749 data=None,
750 offset=None,
751 parent=None,
752 length=None,
753 init=None,
754 ):
755 ovskey.ovs_key_proto.__init__(
756 self,
757 "ct_tuple4",
758 data=data,
759 offset=offset,
760 parent=parent,
761 length=length,
762 init=init,
763 )
764
765 class ovs_key_ct_tuple_ipv6(nla):
766 fields = (
767 ("src", "!16s"),
768 ("dst", "!16s"),
769 ("tp_src", "!H"),
770 ("tp_dst", "!H"),
771 ("proto", "B"),
772 )
773
774 fields_map = (
775 (
776 "src",
777 "src",
778 lambda x: str(ipaddress.IPv6Address(x)),
779 lambda x: int.from_bytes(x, "big", convertmac),
780 ),
781 (
782 "dst",
783 "dst",
784 lambda x: str(ipaddress.IPv6Address(x)),
785 lambda x: int.from_bytes(x, "big"),
786 ),
787 ("tp_src", "tp_src", "%d", int),
788 ("tp_dst", "tp_dst", "%d", int),
789 ("proto", "proto", "%d", int),
790 )
791
792 def __init__(
793 self,
794 data=None,
795 offset=None,
796 parent=None,
797 length=None,
798 init=None,
799 ):
800 ovskey.ovs_key_proto.__init__(
801 self,
802 "ct_tuple6",
803 data=data,
804 offset=offset,
805 parent=parent,
806 length=length,
807 init=init,
808 )
809
810 class ovs_key_mpls(nla):
811 fields = (("lse", ">I"),)
812
813 def dpstr(self, mask=None, more=False):
814 print_str = ""
815
816 for field in (
817 (
818 "OVS_KEY_ATTR_PRIORITY",
819 "skb_priority",
820 "%d",
821 lambda x: False,
822 True,
823 ),
824 (
825 "OVS_KEY_ATTR_SKB_MARK",
826 "skb_mark",
827 "%d",
828 lambda x: False,
829 True,
830 ),
831 (
832 "OVS_KEY_ATTR_RECIRC_ID",
833 "recirc_id",
834 "0x%08X",
835 lambda x: False,
836 True,
837 ),
838 (
839 "OVS_KEY_ATTR_DP_HASH",
840 "dp_hash",
841 "0x%08X",
842 lambda x: False,
843 True,
844 ),
845 (
846 "OVS_KEY_ATTR_CT_STATE",
847 "ct_state",
848 "0x%04x",
849 lambda x: False,
850 True,
851 ),
852 (
853 "OVS_KEY_ATTR_CT_ZONE",
854 "ct_zone",
855 "0x%04x",
856 lambda x: False,
857 True,
858 ),
859 (
860 "OVS_KEY_ATTR_CT_MARK",
861 "ct_mark",
862 "0x%08x",
863 lambda x: False,
864 True,
865 ),
866 (
867 "OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4",
868 None,
869 None,
870 False,
871 False,
872 ),
873 (
874 "OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6",
875 None,
876 None,
877 False,
878 False,
879 ),
880 (
881 "OVS_KEY_ATTR_IN_PORT",
882 "in_port",
883 "%d",
884 lambda x: True,
885 True,
886 ),
887 ("OVS_KEY_ATTR_ETHERNET", None, None, False, False),
888 (
889 "OVS_KEY_ATTR_ETHERTYPE",
890 "eth_type",
891 "0x%04x",
892 lambda x: int(x) == 0xFFFF,
893 True,
894 ),
895 ("OVS_KEY_ATTR_IPV4", None, None, False, False),
896 ("OVS_KEY_ATTR_IPV6", None, None, False, False),
897 ("OVS_KEY_ATTR_ARP", None, None, False, False),
898 ("OVS_KEY_ATTR_TCP", None, None, False, False),
899 (
900 "OVS_KEY_ATTR_TCP_FLAGS",
901 "tcp_flags",
902 "0x%04x",
903 lambda x: False,
904 True,
905 ),
906 ("OVS_KEY_ATTR_UDP", None, None, False, False),
907 ("OVS_KEY_ATTR_SCTP", None, None, False, False),
908 ("OVS_KEY_ATTR_ICMP", None, None, False, False),
909 ("OVS_KEY_ATTR_ICMPV6", None, None, False, False),
910 ("OVS_KEY_ATTR_ND", None, None, False, False),
911 ):
912 v = self.get_attr(field[0])
913 if v is not None:
914 m = None if mask is None else mask.get_attr(field[0])
915 if field[4] is False:
916 print_str += v.dpstr(m, more)
917 print_str += ","
918 else:
919 if m is None or field[3](m):
920 print_str += field[1] + "("
921 print_str += field[2] % v
922 print_str += "),"
923 elif more or m != 0:
924 print_str += field[1] + "("
925 print_str += (field[2] % v) + "/" + (field[2] % m)
926 print_str += "),"
927
928 return print_str
929
930
931class OvsPacket(GenericNetlinkSocket):
932 OVS_PACKET_CMD_MISS = 1 # Flow table miss
933 OVS_PACKET_CMD_ACTION = 2 # USERSPACE action
934 OVS_PACKET_CMD_EXECUTE = 3 # Apply actions to packet
935
936 class ovs_packet_msg(ovs_dp_msg):
937 nla_map = (
938 ("OVS_PACKET_ATTR_UNSPEC", "none"),
939 ("OVS_PACKET_ATTR_PACKET", "array(uint8)"),
940 ("OVS_PACKET_ATTR_KEY", "ovskey"),
941 ("OVS_PACKET_ATTR_ACTIONS", "ovsactions"),
942 ("OVS_PACKET_ATTR_USERDATA", "none"),
943 ("OVS_PACKET_ATTR_EGRESS_TUN_KEY", "none"),
944 ("OVS_PACKET_ATTR_UNUSED1", "none"),
945 ("OVS_PACKET_ATTR_UNUSED2", "none"),
946 ("OVS_PACKET_ATTR_PROBE", "none"),
947 ("OVS_PACKET_ATTR_MRU", "uint16"),
948 ("OVS_PACKET_ATTR_LEN", "uint32"),
949 ("OVS_PACKET_ATTR_HASH", "uint64"),
950 )
951
952 def __init__(self):
953 GenericNetlinkSocket.__init__(self)
954 self.bind(OVS_PACKET_FAMILY, OvsPacket.ovs_packet_msg)
955
956 def upcall_handler(self, up=None):
957 print("listening on upcall packet handler:", self.epid)
958 while True:
959 try:
960 msgs = self.get()
961 for msg in msgs:
962 if not up:
963 continue
964 if msg["cmd"] == OvsPacket.OVS_PACKET_CMD_MISS:
965 up.miss(msg)
966 elif msg["cmd"] == OvsPacket.OVS_PACKET_CMD_ACTION:
967 up.action(msg)
968 elif msg["cmd"] == OvsPacket.OVS_PACKET_CMD_EXECUTE:
969 up.execute(msg)
970 else:
971 print("Unkonwn cmd: %d" % msg["cmd"])
972 except NetlinkError as ne:
973 raise ne
974
975
976class OvsDatapath(GenericNetlinkSocket):
977 OVS_DP_F_VPORT_PIDS = 1 << 1
978 OVS_DP_F_DISPATCH_UPCALL_PER_CPU = 1 << 3
979
980 class dp_cmd_msg(ovs_dp_msg):
981 """
982 Message class that will be used to communicate with the kernel module.
983 """
984
985 nla_map = (
986 ("OVS_DP_ATTR_UNSPEC", "none"),
987 ("OVS_DP_ATTR_NAME", "asciiz"),
988 ("OVS_DP_ATTR_UPCALL_PID", "array(uint32)"),
989 ("OVS_DP_ATTR_STATS", "dpstats"),
990 ("OVS_DP_ATTR_MEGAFLOW_STATS", "megaflowstats"),
991 ("OVS_DP_ATTR_USER_FEATURES", "uint32"),
992 ("OVS_DP_ATTR_PAD", "none"),
993 ("OVS_DP_ATTR_MASKS_CACHE_SIZE", "uint32"),
994 ("OVS_DP_ATTR_PER_CPU_PIDS", "array(uint32)"),
995 )
996
997 class dpstats(nla):
998 fields = (
999 ("hit", "=Q"),
1000 ("missed", "=Q"),
1001 ("lost", "=Q"),
1002 ("flows", "=Q"),
1003 )
1004
1005 class megaflowstats(nla):
1006 fields = (
1007 ("mask_hit", "=Q"),
1008 ("masks", "=I"),
1009 ("padding", "=I"),
1010 ("cache_hits", "=Q"),
1011 ("pad1", "=Q"),
1012 )
1013
1014 def __init__(self):
1015 GenericNetlinkSocket.__init__(self)
1016 self.bind(OVS_DATAPATH_FAMILY, OvsDatapath.dp_cmd_msg)
1017
1018 def info(self, dpname, ifindex=0):
1019 msg = OvsDatapath.dp_cmd_msg()
1020 msg["cmd"] = OVS_DP_CMD_GET
1021 msg["version"] = OVS_DATAPATH_VERSION
1022 msg["reserved"] = 0
1023 msg["dpifindex"] = ifindex
1024 msg["attrs"].append(["OVS_DP_ATTR_NAME", dpname])
1025
1026 try:
1027 reply = self.nlm_request(
1028 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST
1029 )
1030 reply = reply[0]
1031 except NetlinkError as ne:
1032 if ne.code == errno.ENODEV:
1033 reply = None
1034 else:
1035 raise ne
1036
1037 return reply
1038
1039 def create(
1040 self, dpname, shouldUpcall=False, versionStr=None, p=OvsPacket()
1041 ):
1042 msg = OvsDatapath.dp_cmd_msg()
1043 msg["cmd"] = OVS_DP_CMD_NEW
1044 if versionStr is None:
1045 msg["version"] = OVS_DATAPATH_VERSION
1046 else:
1047 msg["version"] = int(versionStr.split(":")[0], 0)
1048 msg["reserved"] = 0
1049 msg["dpifindex"] = 0
1050 msg["attrs"].append(["OVS_DP_ATTR_NAME", dpname])
1051
1052 dpfeatures = 0
1053 if versionStr is not None and versionStr.find(":") != -1:
1054 dpfeatures = int(versionStr.split(":")[1], 0)
1055 else:
1056 if versionStr is None or versionStr.find(":") == -1:
1057 dpfeatures |= OvsDatapath.OVS_DP_F_DISPATCH_UPCALL_PER_CPU
1058 dpfeatures &= ~OvsDatapath.OVS_DP_F_VPORT_PIDS
1059
1060 nproc = multiprocessing.cpu_count()
1061 procarray = []
1062 for i in range(1, nproc):
1063 procarray += [int(p.epid)]
1064 msg["attrs"].append(["OVS_DP_ATTR_UPCALL_PID", procarray])
1065 msg["attrs"].append(["OVS_DP_ATTR_USER_FEATURES", dpfeatures])
1066 if not shouldUpcall:
1067 msg["attrs"].append(["OVS_DP_ATTR_UPCALL_PID", [0]])
1068
1069 try:
1070 reply = self.nlm_request(
1071 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK
1072 )
1073 reply = reply[0]
1074 except NetlinkError as ne:
1075 if ne.code == errno.EEXIST:
1076 reply = None
1077 else:
1078 raise ne
1079
1080 return reply
1081
1082 def destroy(self, dpname):
1083 msg = OvsDatapath.dp_cmd_msg()
1084 msg["cmd"] = OVS_DP_CMD_DEL
1085 msg["version"] = OVS_DATAPATH_VERSION
1086 msg["reserved"] = 0
1087 msg["dpifindex"] = 0
1088 msg["attrs"].append(["OVS_DP_ATTR_NAME", dpname])
1089
1090 try:
1091 reply = self.nlm_request(
1092 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK
1093 )
1094 reply = reply[0]
1095 except NetlinkError as ne:
1096 if ne.code == errno.ENODEV:
1097 reply = None
1098 else:
1099 raise ne
1100
1101 return reply
1102
1103
1104class OvsVport(GenericNetlinkSocket):
1105 OVS_VPORT_TYPE_NETDEV = 1
1106 OVS_VPORT_TYPE_INTERNAL = 2
1107 OVS_VPORT_TYPE_GRE = 3
1108 OVS_VPORT_TYPE_VXLAN = 4
1109 OVS_VPORT_TYPE_GENEVE = 5
1110
1111 class ovs_vport_msg(ovs_dp_msg):
1112 nla_map = (
1113 ("OVS_VPORT_ATTR_UNSPEC", "none"),
1114 ("OVS_VPORT_ATTR_PORT_NO", "uint32"),
1115 ("OVS_VPORT_ATTR_TYPE", "uint32"),
1116 ("OVS_VPORT_ATTR_NAME", "asciiz"),
1117 ("OVS_VPORT_ATTR_OPTIONS", "none"),
1118 ("OVS_VPORT_ATTR_UPCALL_PID", "array(uint32)"),
1119 ("OVS_VPORT_ATTR_STATS", "vportstats"),
1120 ("OVS_VPORT_ATTR_PAD", "none"),
1121 ("OVS_VPORT_ATTR_IFINDEX", "uint32"),
1122 ("OVS_VPORT_ATTR_NETNSID", "uint32"),
1123 )
1124
1125 class vportstats(nla):
1126 fields = (
1127 ("rx_packets", "=Q"),
1128 ("tx_packets", "=Q"),
1129 ("rx_bytes", "=Q"),
1130 ("tx_bytes", "=Q"),
1131 ("rx_errors", "=Q"),
1132 ("tx_errors", "=Q"),
1133 ("rx_dropped", "=Q"),
1134 ("tx_dropped", "=Q"),
1135 )
1136
1137 def type_to_str(vport_type):
1138 if vport_type == OvsVport.OVS_VPORT_TYPE_NETDEV:
1139 return "netdev"
1140 elif vport_type == OvsVport.OVS_VPORT_TYPE_INTERNAL:
1141 return "internal"
1142 elif vport_type == OvsVport.OVS_VPORT_TYPE_GRE:
1143 return "gre"
1144 elif vport_type == OvsVport.OVS_VPORT_TYPE_VXLAN:
1145 return "vxlan"
1146 elif vport_type == OvsVport.OVS_VPORT_TYPE_GENEVE:
1147 return "geneve"
1148 raise ValueError("Unknown vport type:%d" % vport_type)
1149
1150 def str_to_type(vport_type):
1151 if vport_type == "netdev":
1152 return OvsVport.OVS_VPORT_TYPE_NETDEV
1153 elif vport_type == "internal":
1154 return OvsVport.OVS_VPORT_TYPE_INTERNAL
1155 elif vport_type == "gre":
1156 return OvsVport.OVS_VPORT_TYPE_INTERNAL
1157 elif vport_type == "vxlan":
1158 return OvsVport.OVS_VPORT_TYPE_VXLAN
1159 elif vport_type == "geneve":
1160 return OvsVport.OVS_VPORT_TYPE_GENEVE
1161 raise ValueError("Unknown vport type: '%s'" % vport_type)
1162
1163 def __init__(self, packet=OvsPacket()):
1164 GenericNetlinkSocket.__init__(self)
1165 self.bind(OVS_VPORT_FAMILY, OvsVport.ovs_vport_msg)
1166 self.upcall_packet = packet
1167
1168 def info(self, vport_name, dpifindex=0, portno=None):
1169 msg = OvsVport.ovs_vport_msg()
1170
1171 msg["cmd"] = OVS_VPORT_CMD_GET
1172 msg["version"] = OVS_DATAPATH_VERSION
1173 msg["reserved"] = 0
1174 msg["dpifindex"] = dpifindex
1175
1176 if portno is None:
1177 msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_name])
1178 else:
1179 msg["attrs"].append(["OVS_VPORT_ATTR_PORT_NO", portno])
1180
1181 try:
1182 reply = self.nlm_request(
1183 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST
1184 )
1185 reply = reply[0]
1186 except NetlinkError as ne:
1187 if ne.code == errno.ENODEV:
1188 reply = None
1189 else:
1190 raise ne
1191 return reply
1192
1193 def attach(self, dpindex, vport_ifname, ptype):
1194 msg = OvsVport.ovs_vport_msg()
1195
1196 msg["cmd"] = OVS_VPORT_CMD_NEW
1197 msg["version"] = OVS_DATAPATH_VERSION
1198 msg["reserved"] = 0
1199 msg["dpifindex"] = dpindex
1200 port_type = OvsVport.str_to_type(ptype)
1201
1202 msg["attrs"].append(["OVS_VPORT_ATTR_TYPE", port_type])
1203 msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_ifname])
1204 msg["attrs"].append(
1205 ["OVS_VPORT_ATTR_UPCALL_PID", [self.upcall_packet.epid]]
1206 )
1207
1208 try:
1209 reply = self.nlm_request(
1210 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK
1211 )
1212 reply = reply[0]
1213 except NetlinkError as ne:
1214 if ne.code == errno.EEXIST:
1215 reply = None
1216 else:
1217 raise ne
1218 return reply
1219
1220 def reset_upcall(self, dpindex, vport_ifname, p=None):
1221 msg = OvsVport.ovs_vport_msg()
1222
1223 msg["cmd"] = OVS_VPORT_CMD_SET
1224 msg["version"] = OVS_DATAPATH_VERSION
1225 msg["reserved"] = 0
1226 msg["dpifindex"] = dpindex
1227 msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_ifname])
1228
1229 if p == None:
1230 p = self.upcall_packet
1231 else:
1232 self.upcall_packet = p
1233
1234 msg["attrs"].append(["OVS_VPORT_ATTR_UPCALL_PID", [p.epid]])
1235
1236 try:
1237 reply = self.nlm_request(
1238 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK
1239 )
1240 reply = reply[0]
1241 except NetlinkError as ne:
1242 raise ne
1243 return reply
1244
1245 def detach(self, dpindex, vport_ifname):
1246 msg = OvsVport.ovs_vport_msg()
1247
1248 msg["cmd"] = OVS_VPORT_CMD_DEL
1249 msg["version"] = OVS_DATAPATH_VERSION
1250 msg["reserved"] = 0
1251 msg["dpifindex"] = dpindex
1252 msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_ifname])
1253
1254 try:
1255 reply = self.nlm_request(
1256 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK
1257 )
1258 reply = reply[0]
1259 except NetlinkError as ne:
1260 if ne.code == errno.ENODEV:
1261 reply = None
1262 else:
1263 raise ne
1264 return reply
1265
1266 def upcall_handler(self, handler=None):
1267 self.upcall_packet.upcall_handler(handler)
1268
1269
1270class OvsFlow(GenericNetlinkSocket):
1271 class ovs_flow_msg(ovs_dp_msg):
1272 nla_map = (
1273 ("OVS_FLOW_ATTR_UNSPEC", "none"),
1274 ("OVS_FLOW_ATTR_KEY", "ovskey"),
1275 ("OVS_FLOW_ATTR_ACTIONS", "ovsactions"),
1276 ("OVS_FLOW_ATTR_STATS", "flowstats"),
1277 ("OVS_FLOW_ATTR_TCP_FLAGS", "uint8"),
1278 ("OVS_FLOW_ATTR_USED", "uint64"),
1279 ("OVS_FLOW_ATTR_CLEAR", "none"),
1280 ("OVS_FLOW_ATTR_MASK", "ovskey"),
1281 ("OVS_FLOW_ATTR_PROBE", "none"),
1282 ("OVS_FLOW_ATTR_UFID", "array(uint32)"),
1283 ("OVS_FLOW_ATTR_UFID_FLAGS", "uint32"),
1284 )
1285
1286 class flowstats(nla):
1287 fields = (
1288 ("packets", "=Q"),
1289 ("bytes", "=Q"),
1290 )
1291
1292 def dpstr(self, more=False):
1293 ufid = self.get_attr("OVS_FLOW_ATTR_UFID")
1294 ufid_str = ""
1295 if ufid is not None:
1296 ufid_str = (
1297 "ufid:{:08x}-{:04x}-{:04x}-{:04x}-{:04x}{:08x}".format(
1298 ufid[0],
1299 ufid[1] >> 16,
1300 ufid[1] & 0xFFFF,
1301 ufid[2] >> 16,
1302 ufid[2] & 0,
1303 ufid[3],
1304 )
1305 )
1306
1307 key_field = self.get_attr("OVS_FLOW_ATTR_KEY")
1308 keymsg = None
1309 if key_field is not None:
1310 keymsg = key_field
1311
1312 mask_field = self.get_attr("OVS_FLOW_ATTR_MASK")
1313 maskmsg = None
1314 if mask_field is not None:
1315 maskmsg = mask_field
1316
1317 acts_field = self.get_attr("OVS_FLOW_ATTR_ACTIONS")
1318 actsmsg = None
1319 if acts_field is not None:
1320 actsmsg = acts_field
1321
1322 print_str = ""
1323
1324 if more:
1325 print_str += ufid_str + ","
1326
1327 if keymsg is not None:
1328 print_str += keymsg.dpstr(maskmsg, more)
1329
1330 stats = self.get_attr("OVS_FLOW_ATTR_STATS")
1331 if stats is None:
1332 print_str += " packets:0, bytes:0,"
1333 else:
1334 print_str += " packets:%d, bytes:%d," % (
1335 stats["packets"],
1336 stats["bytes"],
1337 )
1338
1339 used = self.get_attr("OVS_FLOW_ATTR_USED")
1340 print_str += " used:"
1341 if used is None:
1342 print_str += "never,"
1343 else:
1344 used_time = int(used)
1345 cur_time_sec = time.clock_gettime(time.CLOCK_MONOTONIC)
1346 used_time = (cur_time_sec * 1000) - used_time
1347 print_str += "{}s,".format(used_time / 1000)
1348
1349 print_str += " actions:"
1350 if (
1351 actsmsg is None
1352 or "attrs" not in actsmsg
1353 or len(actsmsg["attrs"]) == 0
1354 ):
1355 print_str += "drop"
1356 else:
1357 print_str += actsmsg.dpstr(more)
1358
1359 return print_str
1360
1361 def __init__(self):
1362 GenericNetlinkSocket.__init__(self)
1363
1364 self.bind(OVS_FLOW_FAMILY, OvsFlow.ovs_flow_msg)
1365
1366 def dump(self, dpifindex, flowspec=None):
1367 """
1368 Returns a list of messages containing flows.
1369
1370 dpifindex should be a valid datapath obtained by calling
1371 into the OvsDatapath lookup
1372
1373 flowpsec is a string which represents a flow in the dpctl
1374 format.
1375 """
1376 msg = OvsFlow.ovs_flow_msg()
1377
1378 msg["cmd"] = OVS_FLOW_CMD_GET
1379 msg["version"] = OVS_DATAPATH_VERSION
1380 msg["reserved"] = 0
1381 msg["dpifindex"] = dpifindex
1382
1383 msg_flags = NLM_F_REQUEST | NLM_F_ACK
1384 if flowspec is None:
1385 msg_flags |= NLM_F_DUMP
1386 rep = None
1387
1388 try:
1389 rep = self.nlm_request(
1390 msg,
1391 msg_type=self.prid,
1392 msg_flags=msg_flags,
1393 )
1394 except NetlinkError as ne:
1395 raise ne
1396 return rep
1397
1398 def miss(self, packetmsg):
1399 seq = packetmsg["header"]["sequence_number"]
1400 keystr = "(none)"
1401 key_field = packetmsg.get_attr("OVS_PACKET_ATTR_KEY")
1402 if key_field is not None:
1403 keystr = key_field.dpstr(None, True)
1404
1405 pktdata = packetmsg.get_attr("OVS_PACKET_ATTR_PACKET")
1406 pktpres = "yes" if pktdata is not None else "no"
1407
1408 print("MISS upcall[%d/%s]: %s" % (seq, pktpres, keystr), flush=True)
1409
1410 def execute(self, packetmsg):
1411 print("userspace execute command")
1412
1413 def action(self, packetmsg):
1414 print("userspace action command")
1415
1416
1417def print_ovsdp_full(dp_lookup_rep, ifindex, ndb=NDB(), vpl=OvsVport()):
1418 dp_name = dp_lookup_rep.get_attr("OVS_DP_ATTR_NAME")
1419 base_stats = dp_lookup_rep.get_attr("OVS_DP_ATTR_STATS")
1420 megaflow_stats = dp_lookup_rep.get_attr("OVS_DP_ATTR_MEGAFLOW_STATS")
1421 user_features = dp_lookup_rep.get_attr("OVS_DP_ATTR_USER_FEATURES")
1422 masks_cache_size = dp_lookup_rep.get_attr("OVS_DP_ATTR_MASKS_CACHE_SIZE")
1423
1424 print("%s:" % dp_name)
1425 print(
1426 " lookups: hit:%d missed:%d lost:%d"
1427 % (base_stats["hit"], base_stats["missed"], base_stats["lost"])
1428 )
1429 print(" flows:%d" % base_stats["flows"])
1430 pkts = base_stats["hit"] + base_stats["missed"]
1431 avg = (megaflow_stats["mask_hit"] / pkts) if pkts != 0 else 0.0
1432 print(
1433 " masks: hit:%d total:%d hit/pkt:%f"
1434 % (megaflow_stats["mask_hit"], megaflow_stats["masks"], avg)
1435 )
1436 print(" caches:")
1437 print(" masks-cache: size:%d" % masks_cache_size)
1438
1439 if user_features is not None:
1440 print(" features: 0x%X" % user_features)
1441
1442 # port print out
1443 for iface in ndb.interfaces:
1444 rep = vpl.info(iface.ifname, ifindex)
1445 if rep is not None:
1446 print(
1447 " port %d: %s (%s)"
1448 % (
1449 rep.get_attr("OVS_VPORT_ATTR_PORT_NO"),
1450 rep.get_attr("OVS_VPORT_ATTR_NAME"),
1451 OvsVport.type_to_str(rep.get_attr("OVS_VPORT_ATTR_TYPE")),
1452 )
1453 )
1454
1455
1456def main(argv):
1457 nlmsg_atoms.ovskey = ovskey
1458 nlmsg_atoms.ovsactions = ovsactions
1459
1460 parser = argparse.ArgumentParser()
1461 parser.add_argument(
1462 "-v",
1463 "--verbose",
1464 action="count",
1465 help="Increment 'verbose' output counter.",
1466 default=0,
1467 )
1468 subparsers = parser.add_subparsers()
1469
1470 showdpcmd = subparsers.add_parser("show")
1471 showdpcmd.add_argument(
1472 "showdp", metavar="N", type=str, nargs="?", help="Datapath Name"
1473 )
1474
1475 adddpcmd = subparsers.add_parser("add-dp")
1476 adddpcmd.add_argument("adddp", help="Datapath Name")
1477 adddpcmd.add_argument(
1478 "-u",
1479 "--upcall",
1480 action="store_true",
1481 help="Leave open a reader for upcalls",
1482 )
1483 adddpcmd.add_argument(
1484 "-V",
1485 "--versioning",
1486 required=False,
1487 help="Specify a custom version / feature string",
1488 )
1489
1490 deldpcmd = subparsers.add_parser("del-dp")
1491 deldpcmd.add_argument("deldp", help="Datapath Name")
1492
1493 addifcmd = subparsers.add_parser("add-if")
1494 addifcmd.add_argument("dpname", help="Datapath Name")
1495 addifcmd.add_argument("addif", help="Interface name for adding")
1496 addifcmd.add_argument(
1497 "-u",
1498 "--upcall",
1499 action="store_true",
1500 help="Leave open a reader for upcalls",
1501 )
1502 addifcmd.add_argument(
1503 "-t",
1504 "--ptype",
1505 type=str,
1506 default="netdev",
1507 choices=["netdev", "internal"],
1508 help="Interface type (default netdev)",
1509 )
1510 delifcmd = subparsers.add_parser("del-if")
1511 delifcmd.add_argument("dpname", help="Datapath Name")
1512 delifcmd.add_argument("delif", help="Interface name for adding")
1513
1514 dumpflcmd = subparsers.add_parser("dump-flows")
1515 dumpflcmd.add_argument("dumpdp", help="Datapath Name")
1516
1517 args = parser.parse_args()
1518
1519 if args.verbose > 0:
1520 if args.verbose > 1:
1521 logging.basicConfig(level=logging.DEBUG)
1522
1523 ovspk = OvsPacket()
1524 ovsdp = OvsDatapath()
1525 ovsvp = OvsVport(ovspk)
1526 ovsflow = OvsFlow()
1527 ndb = NDB()
1528
1529 if hasattr(args, "showdp"):
1530 found = False
1531 for iface in ndb.interfaces:
1532 rep = None
1533 if args.showdp is None:
1534 rep = ovsdp.info(iface.ifname, 0)
1535 elif args.showdp == iface.ifname:
1536 rep = ovsdp.info(iface.ifname, 0)
1537
1538 if rep is not None:
1539 found = True
1540 print_ovsdp_full(rep, iface.index, ndb, ovsvp)
1541
1542 if not found:
1543 msg = "No DP found"
1544 if args.showdp is not None:
1545 msg += ":'%s'" % args.showdp
1546 print(msg)
1547 elif hasattr(args, "adddp"):
1548 rep = ovsdp.create(args.adddp, args.upcall, args.versioning, ovspk)
1549 if rep is None:
1550 print("DP '%s' already exists" % args.adddp)
1551 else:
1552 print("DP '%s' added" % args.adddp)
1553 if args.upcall:
1554 ovspk.upcall_handler(ovsflow)
1555 elif hasattr(args, "deldp"):
1556 ovsdp.destroy(args.deldp)
1557 elif hasattr(args, "addif"):
1558 rep = ovsdp.info(args.dpname, 0)
1559 if rep is None:
1560 print("DP '%s' not found." % args.dpname)
1561 return 1
1562 dpindex = rep["dpifindex"]
1563 rep = ovsvp.attach(rep["dpifindex"], args.addif, args.ptype)
1564 msg = "vport '%s'" % args.addif
1565 if rep and rep["header"]["error"] is None:
1566 msg += " added."
1567 else:
1568 msg += " failed to add."
1569 if args.upcall:
1570 if rep is None:
1571 rep = ovsvp.reset_upcall(dpindex, args.addif, ovspk)
1572 ovsvp.upcall_handler(ovsflow)
1573 elif hasattr(args, "delif"):
1574 rep = ovsdp.info(args.dpname, 0)
1575 if rep is None:
1576 print("DP '%s' not found." % args.dpname)
1577 return 1
1578 rep = ovsvp.detach(rep["dpifindex"], args.delif)
1579 msg = "vport '%s'" % args.delif
1580 if rep and rep["header"]["error"] is None:
1581 msg += " removed."
1582 else:
1583 msg += " failed to remove."
1584 elif hasattr(args, "dumpdp"):
1585 rep = ovsdp.info(args.dumpdp, 0)
1586 if rep is None:
1587 print("DP '%s' not found." % args.dumpdp)
1588 return 1
1589 rep = ovsflow.dump(rep["dpifindex"])
1590 for flow in rep:
1591 print(flow.dpstr(True if args.verbose > 0 else False))
1592
1593 return 0
1594
1595
1596if __name__ == "__main__":
1597 sys.exit(main(sys.argv))