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