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 re 13import struct 14import sys 15import time 16import types 17import uuid 18 19try: 20 from pyroute2 import NDB 21 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 31except ModuleNotFoundError: 32 print("Need to install the python pyroute2 package.") 33 sys.exit(0) 34 35 36OVS_DATAPATH_FAMILY = "ovs_datapath" 37OVS_VPORT_FAMILY = "ovs_vport" 38OVS_FLOW_FAMILY = "ovs_flow" 39OVS_PACKET_FAMILY = "ovs_packet" 40OVS_METER_FAMILY = "ovs_meter" 41OVS_CT_LIMIT_FAMILY = "ovs_ct_limit" 42 43OVS_DATAPATH_VERSION = 2 44OVS_DP_CMD_NEW = 1 45OVS_DP_CMD_DEL = 2 46OVS_DP_CMD_GET = 3 47OVS_DP_CMD_SET = 4 48 49OVS_VPORT_CMD_NEW = 1 50OVS_VPORT_CMD_DEL = 2 51OVS_VPORT_CMD_GET = 3 52OVS_VPORT_CMD_SET = 4 53 54OVS_FLOW_CMD_NEW = 1 55OVS_FLOW_CMD_DEL = 2 56OVS_FLOW_CMD_GET = 3 57OVS_FLOW_CMD_SET = 4 58 59 60def macstr(mac): 61 outstr = ":".join(["%02X" % i for i in mac]) 62 return outstr 63 64 65def strcspn(str1, str2): 66 tot = 0 67 for char in str1: 68 if str2.find(char) != -1: 69 return tot 70 tot += 1 71 return tot 72 73 74def strspn(str1, str2): 75 tot = 0 76 for char in str1: 77 if str2.find(char) == -1: 78 return tot 79 tot += 1 80 return tot 81 82 83def intparse(statestr, defmask="0xffffffff"): 84 totalparse = strspn(statestr, "0123456789abcdefABCDEFx/") 85 # scan until "/" 86 count = strspn(statestr, "x0123456789abcdefABCDEF") 87 88 firstnum = statestr[:count] 89 if firstnum[-1] == "/": 90 firstnum = firstnum[:-1] 91 k = int(firstnum, 0) 92 93 m = None 94 if defmask is not None: 95 secondnum = defmask 96 if statestr[count] == "/": 97 secondnum = statestr[count + 1 :] # this is wrong... 98 m = int(secondnum, 0) 99 100 return statestr[totalparse + 1 :], k, m 101 102 103def parse_flags(flag_str, flag_vals): 104 bitResult = 0 105 maskResult = 0 106 107 if len(flag_str) == 0: 108 return flag_str, bitResult, maskResult 109 110 if flag_str[0].isdigit(): 111 idx = 0 112 while flag_str[idx].isdigit() or flag_str[idx] == "x": 113 idx += 1 114 digits = flag_str[:idx] 115 flag_str = flag_str[idx:] 116 117 bitResult = int(digits, 0) 118 maskResult = int(digits, 0) 119 120 while len(flag_str) > 0 and (flag_str[0] == "+" or flag_str[0] == "-"): 121 if flag_str[0] == "+": 122 setFlag = True 123 elif flag_str[0] == "-": 124 setFlag = False 125 126 flag_str = flag_str[1:] 127 128 flag_len = 0 129 while ( 130 flag_str[flag_len] != "+" 131 and flag_str[flag_len] != "-" 132 and flag_str[flag_len] != "," 133 and flag_str[flag_len] != ")" 134 ): 135 flag_len += 1 136 137 flag = flag_str[0:flag_len] 138 139 if flag in flag_vals: 140 if maskResult & flag_vals[flag]: 141 raise KeyError( 142 "Flag %s set once, cannot be set in multiples" % flag 143 ) 144 145 if setFlag: 146 bitResult |= flag_vals[flag] 147 148 maskResult |= flag_vals[flag] 149 else: 150 raise KeyError("Missing flag value: %s" % flag) 151 152 flag_str = flag_str[flag_len:] 153 154 return flag_str, bitResult, maskResult 155 156 157def parse_ct_state(statestr): 158 ct_flags = { 159 "new": 1 << 0, 160 "est": 1 << 1, 161 "rel": 1 << 2, 162 "rpl": 1 << 3, 163 "inv": 1 << 4, 164 "trk": 1 << 5, 165 "snat": 1 << 6, 166 "dnat": 1 << 7, 167 } 168 169 return parse_flags(statestr, ct_flags) 170 171 172def convert_mac(data): 173 def to_bytes(mac): 174 mac_split = mac.split(":") 175 ret = bytearray([int(i, 16) for i in mac_split]) 176 return bytes(ret) 177 178 mac_str, _, mask_str = data.partition('/') 179 180 if not mac_str: 181 mac_str = mask_str = "00:00:00:00:00:00" 182 elif not mask_str: 183 mask_str = "FF:FF:FF:FF:FF:FF" 184 185 return to_bytes(mac_str), to_bytes(mask_str) 186 187def convert_ipv4(data): 188 ip, _, mask = data.partition('/') 189 190 if not ip: 191 ip = mask = 0 192 elif not mask: 193 mask = 0xFFFFFFFF 194 elif mask.isdigit(): 195 mask = (0xFFFFFFFF << (32 - int(mask))) & 0xFFFFFFFF 196 197 return int(ipaddress.IPv4Address(ip)), int(ipaddress.IPv4Address(mask)) 198 199def convert_int(size): 200 def convert_int_sized(data): 201 value, _, mask = data.partition('/') 202 203 if not value: 204 return 0, 0 205 elif not mask: 206 return int(value, 0), pow(2, size) - 1 207 else: 208 return int(value, 0), int(mask, 0) 209 210 return convert_int_sized 211 212def parse_starts_block(block_str, scanstr, returnskipped, scanregex=False): 213 if scanregex: 214 m = re.search(scanstr, block_str) 215 if m is None: 216 if returnskipped: 217 return block_str 218 return False 219 if returnskipped: 220 block_str = block_str[len(m.group(0)) :] 221 return block_str 222 return True 223 224 if block_str.startswith(scanstr): 225 if returnskipped: 226 block_str = block_str[len(scanstr) :] 227 else: 228 return True 229 230 if returnskipped: 231 return block_str 232 233 return False 234 235 236def parse_extract_field( 237 block_str, fieldstr, scanfmt, convert, masked=False, defval=None 238): 239 if fieldstr and not block_str.startswith(fieldstr): 240 return block_str, defval 241 242 if fieldstr: 243 str_skiplen = len(fieldstr) 244 str_skipped = block_str[str_skiplen:] 245 if str_skiplen == 0: 246 return str_skipped, defval 247 else: 248 str_skiplen = 0 249 str_skipped = block_str 250 251 m = re.search(scanfmt, str_skipped) 252 if m is None: 253 raise ValueError("Bad fmt string") 254 255 data = m.group(0) 256 if convert: 257 data = convert(m.group(0)) 258 259 str_skipped = str_skipped[len(m.group(0)) :] 260 if masked: 261 if str_skipped[0] == "/": 262 raise ValueError("Masking support TBD...") 263 264 str_skipped = str_skipped[strspn(str_skipped, ", ") :] 265 return str_skipped, data 266 267 268class ovs_dp_msg(genlmsg): 269 # include the OVS version 270 # We need a custom header rather than just being able to rely on 271 # genlmsg because fields ends up not expressing everything correctly 272 # if we use the canonical example of setting fields = (('customfield',),) 273 fields = genlmsg.fields + (("dpifindex", "I"),) 274 275 276class ovsactions(nla): 277 nla_flags = NLA_F_NESTED 278 279 nla_map = ( 280 ("OVS_ACTION_ATTR_UNSPEC", "none"), 281 ("OVS_ACTION_ATTR_OUTPUT", "uint32"), 282 ("OVS_ACTION_ATTR_USERSPACE", "userspace"), 283 ("OVS_ACTION_ATTR_SET", "none"), 284 ("OVS_ACTION_ATTR_PUSH_VLAN", "none"), 285 ("OVS_ACTION_ATTR_POP_VLAN", "flag"), 286 ("OVS_ACTION_ATTR_SAMPLE", "none"), 287 ("OVS_ACTION_ATTR_RECIRC", "uint32"), 288 ("OVS_ACTION_ATTR_HASH", "none"), 289 ("OVS_ACTION_ATTR_PUSH_MPLS", "none"), 290 ("OVS_ACTION_ATTR_POP_MPLS", "flag"), 291 ("OVS_ACTION_ATTR_SET_MASKED", "none"), 292 ("OVS_ACTION_ATTR_CT", "ctact"), 293 ("OVS_ACTION_ATTR_TRUNC", "uint32"), 294 ("OVS_ACTION_ATTR_PUSH_ETH", "none"), 295 ("OVS_ACTION_ATTR_POP_ETH", "flag"), 296 ("OVS_ACTION_ATTR_CT_CLEAR", "flag"), 297 ("OVS_ACTION_ATTR_PUSH_NSH", "none"), 298 ("OVS_ACTION_ATTR_POP_NSH", "flag"), 299 ("OVS_ACTION_ATTR_METER", "none"), 300 ("OVS_ACTION_ATTR_CLONE", "none"), 301 ("OVS_ACTION_ATTR_CHECK_PKT_LEN", "none"), 302 ("OVS_ACTION_ATTR_ADD_MPLS", "none"), 303 ("OVS_ACTION_ATTR_DEC_TTL", "none"), 304 ("OVS_ACTION_ATTR_DROP", "uint32"), 305 ) 306 307 class ctact(nla): 308 nla_flags = NLA_F_NESTED 309 310 nla_map = ( 311 ("OVS_CT_ATTR_NONE", "none"), 312 ("OVS_CT_ATTR_COMMIT", "flag"), 313 ("OVS_CT_ATTR_ZONE", "uint16"), 314 ("OVS_CT_ATTR_MARK", "none"), 315 ("OVS_CT_ATTR_LABELS", "none"), 316 ("OVS_CT_ATTR_HELPER", "asciiz"), 317 ("OVS_CT_ATTR_NAT", "natattr"), 318 ("OVS_CT_ATTR_FORCE_COMMIT", "flag"), 319 ("OVS_CT_ATTR_EVENTMASK", "uint32"), 320 ("OVS_CT_ATTR_TIMEOUT", "asciiz"), 321 ) 322 323 class natattr(nla): 324 nla_flags = NLA_F_NESTED 325 326 nla_map = ( 327 ("OVS_NAT_ATTR_NONE", "none"), 328 ("OVS_NAT_ATTR_SRC", "flag"), 329 ("OVS_NAT_ATTR_DST", "flag"), 330 ("OVS_NAT_ATTR_IP_MIN", "ipaddr"), 331 ("OVS_NAT_ATTR_IP_MAX", "ipaddr"), 332 ("OVS_NAT_ATTR_PROTO_MIN", "uint16"), 333 ("OVS_NAT_ATTR_PROTO_MAX", "uint16"), 334 ("OVS_NAT_ATTR_PERSISTENT", "flag"), 335 ("OVS_NAT_ATTR_PROTO_HASH", "flag"), 336 ("OVS_NAT_ATTR_PROTO_RANDOM", "flag"), 337 ) 338 339 def dpstr(self, more=False): 340 print_str = "nat(" 341 342 if self.get_attr("OVS_NAT_ATTR_SRC"): 343 print_str += "src" 344 elif self.get_attr("OVS_NAT_ATTR_DST"): 345 print_str += "dst" 346 else: 347 print_str += "XXX-unknown-nat" 348 349 if self.get_attr("OVS_NAT_ATTR_IP_MIN") or self.get_attr( 350 "OVS_NAT_ATTR_IP_MAX" 351 ): 352 if self.get_attr("OVS_NAT_ATTR_IP_MIN"): 353 print_str += "=%s," % str( 354 self.get_attr("OVS_NAT_ATTR_IP_MIN") 355 ) 356 357 if self.get_attr("OVS_NAT_ATTR_IP_MAX"): 358 print_str += "-%s," % str( 359 self.get_attr("OVS_NAT_ATTR_IP_MAX") 360 ) 361 else: 362 print_str += "," 363 364 if self.get_attr("OVS_NAT_ATTR_PROTO_MIN"): 365 print_str += "proto_min=%d," % self.get_attr( 366 "OVS_NAT_ATTR_PROTO_MIN" 367 ) 368 369 if self.get_attr("OVS_NAT_ATTR_PROTO_MAX"): 370 print_str += "proto_max=%d," % self.get_attr( 371 "OVS_NAT_ATTR_PROTO_MAX" 372 ) 373 374 if self.get_attr("OVS_NAT_ATTR_PERSISTENT"): 375 print_str += "persistent," 376 if self.get_attr("OVS_NAT_ATTR_HASH"): 377 print_str += "hash," 378 if self.get_attr("OVS_NAT_ATTR_RANDOM"): 379 print_str += "random" 380 print_str += ")" 381 return print_str 382 383 def dpstr(self, more=False): 384 print_str = "ct(" 385 386 if self.get_attr("OVS_CT_ATTR_COMMIT") is not None: 387 print_str += "commit," 388 if self.get_attr("OVS_CT_ATTR_ZONE") is not None: 389 print_str += "zone=%d," % self.get_attr("OVS_CT_ATTR_ZONE") 390 if self.get_attr("OVS_CT_ATTR_HELPER") is not None: 391 print_str += "helper=%s," % self.get_attr("OVS_CT_ATTR_HELPER") 392 if self.get_attr("OVS_CT_ATTR_NAT") is not None: 393 print_str += self.get_attr("OVS_CT_ATTR_NAT").dpstr(more) 394 print_str += "," 395 if self.get_attr("OVS_CT_ATTR_FORCE_COMMIT") is not None: 396 print_str += "force," 397 if self.get_attr("OVS_CT_ATTR_EVENTMASK") is not None: 398 print_str += "emask=0x%X," % self.get_attr( 399 "OVS_CT_ATTR_EVENTMASK" 400 ) 401 if self.get_attr("OVS_CT_ATTR_TIMEOUT") is not None: 402 print_str += "timeout=%s" % self.get_attr( 403 "OVS_CT_ATTR_TIMEOUT" 404 ) 405 print_str += ")" 406 return print_str 407 408 class userspace(nla): 409 nla_flags = NLA_F_NESTED 410 411 nla_map = ( 412 ("OVS_USERSPACE_ATTR_UNUSED", "none"), 413 ("OVS_USERSPACE_ATTR_PID", "uint32"), 414 ("OVS_USERSPACE_ATTR_USERDATA", "array(uint8)"), 415 ("OVS_USERSPACE_ATTR_EGRESS_TUN_PORT", "uint32"), 416 ) 417 418 def dpstr(self, more=False): 419 print_str = "userspace(" 420 if self.get_attr("OVS_USERSPACE_ATTR_PID") is not None: 421 print_str += "pid=%d," % self.get_attr( 422 "OVS_USERSPACE_ATTR_PID" 423 ) 424 if self.get_attr("OVS_USERSPACE_ATTR_USERDATA") is not None: 425 print_str += "userdata=" 426 for f in self.get_attr("OVS_USERSPACE_ATTR_USERDATA"): 427 print_str += "%x." % f 428 if self.get_attr("OVS_USERSPACE_ATTR_TUN_PORT") is not None: 429 print_str += "egress_tun_port=%d" % self.get_attr( 430 "OVS_USERSPACE_ATTR_TUN_PORT" 431 ) 432 print_str += ")" 433 return print_str 434 435 def dpstr(self, more=False): 436 print_str = "" 437 438 for field in self.nla_map: 439 if field[1] == "none" or self.get_attr(field[0]) is None: 440 continue 441 if print_str != "": 442 print_str += "," 443 444 if field[1] == "uint32": 445 if field[0] == "OVS_ACTION_ATTR_OUTPUT": 446 print_str += "%d" % int(self.get_attr(field[0])) 447 elif field[0] == "OVS_ACTION_ATTR_RECIRC": 448 print_str += "recirc(0x%x)" % int(self.get_attr(field[0])) 449 elif field[0] == "OVS_ACTION_ATTR_TRUNC": 450 print_str += "trunc(%d)" % int(self.get_attr(field[0])) 451 elif field[0] == "OVS_ACTION_ATTR_DROP": 452 print_str += "drop(%d)" % int(self.get_attr(field[0])) 453 elif field[1] == "flag": 454 if field[0] == "OVS_ACTION_ATTR_CT_CLEAR": 455 print_str += "ct_clear" 456 elif field[0] == "OVS_ACTION_ATTR_POP_VLAN": 457 print_str += "pop_vlan" 458 elif field[0] == "OVS_ACTION_ATTR_POP_ETH": 459 print_str += "pop_eth" 460 elif field[0] == "OVS_ACTION_ATTR_POP_NSH": 461 print_str += "pop_nsh" 462 elif field[0] == "OVS_ACTION_ATTR_POP_MPLS": 463 print_str += "pop_mpls" 464 else: 465 datum = self.get_attr(field[0]) 466 print_str += datum.dpstr(more) 467 468 return print_str 469 470 def parse(self, actstr): 471 while len(actstr) != 0: 472 parsed = False 473 if actstr.startswith("drop"): 474 # If no reason is provided, the implicit drop is used (i.e no 475 # action). If some reason is given, an explicit action is used. 476 actstr, reason = parse_extract_field( 477 actstr, 478 "drop(", 479 "([0-9]+)", 480 lambda x: int(x, 0), 481 False, 482 None, 483 ) 484 if reason is not None: 485 self["attrs"].append(["OVS_ACTION_ATTR_DROP", reason]) 486 parsed = True 487 else: 488 return 489 490 elif parse_starts_block(actstr, "^(\d+)", False, True): 491 actstr, output = parse_extract_field( 492 actstr, None, "(\d+)", lambda x: int(x), False, "0" 493 ) 494 self["attrs"].append(["OVS_ACTION_ATTR_OUTPUT", output]) 495 parsed = True 496 elif parse_starts_block(actstr, "recirc(", False): 497 actstr, recircid = parse_extract_field( 498 actstr, 499 "recirc(", 500 "([0-9a-fA-Fx]+)", 501 lambda x: int(x, 0), 502 False, 503 0, 504 ) 505 self["attrs"].append(["OVS_ACTION_ATTR_RECIRC", recircid]) 506 parsed = True 507 508 parse_flat_map = ( 509 ("ct_clear", "OVS_ACTION_ATTR_CT_CLEAR"), 510 ("pop_vlan", "OVS_ACTION_ATTR_POP_VLAN"), 511 ("pop_eth", "OVS_ACTION_ATTR_POP_ETH"), 512 ("pop_nsh", "OVS_ACTION_ATTR_POP_NSH"), 513 ) 514 515 for flat_act in parse_flat_map: 516 if parse_starts_block(actstr, flat_act[0], False): 517 actstr += len(flat_act[0]) 518 self["attrs"].append([flat_act[1]]) 519 actstr = actstr[strspn(actstr, ", ") :] 520 parsed = True 521 522 if parse_starts_block(actstr, "ct(", False): 523 actstr = actstr[len("ct(") :] 524 ctact = ovsactions.ctact() 525 526 for scan in ( 527 ("commit", "OVS_CT_ATTR_COMMIT", None), 528 ("force_commit", "OVS_CT_ATTR_FORCE_COMMIT", None), 529 ("zone", "OVS_CT_ATTR_ZONE", int), 530 ("mark", "OVS_CT_ATTR_MARK", int), 531 ("helper", "OVS_CT_ATTR_HELPER", lambda x, y: str(x)), 532 ("timeout", "OVS_CT_ATTR_TIMEOUT", lambda x, y: str(x)), 533 ): 534 if actstr.startswith(scan[0]): 535 actstr = actstr[len(scan[0]) :] 536 if scan[2] is not None: 537 if actstr[0] != "=": 538 raise ValueError("Invalid ct attr") 539 actstr = actstr[1:] 540 pos = strcspn(actstr, ",)") 541 datum = scan[2](actstr[:pos], 0) 542 ctact["attrs"].append([scan[1], datum]) 543 actstr = actstr[pos:] 544 else: 545 ctact["attrs"].append([scan[1], None]) 546 actstr = actstr[strspn(actstr, ", ") :] 547 # it seems strange to put this here, but nat() is a complex 548 # sub-action and this lets it sit anywhere in the ct() action 549 if actstr.startswith("nat"): 550 actstr = actstr[3:] 551 natact = ovsactions.ctact.natattr() 552 553 if actstr.startswith("("): 554 t = None 555 actstr = actstr[1:] 556 if actstr.startswith("src"): 557 t = "OVS_NAT_ATTR_SRC" 558 actstr = actstr[3:] 559 elif actstr.startswith("dst"): 560 t = "OVS_NAT_ATTR_DST" 561 actstr = actstr[3:] 562 563 actstr, ip_block_min = parse_extract_field( 564 actstr, "=", "([0-9a-fA-F\.]+)", str, False 565 ) 566 actstr, ip_block_max = parse_extract_field( 567 actstr, "-", "([0-9a-fA-F\.]+)", str, False 568 ) 569 570 actstr, proto_min = parse_extract_field( 571 actstr, ":", "(\d+)", int, False 572 ) 573 actstr, proto_max = parse_extract_field( 574 actstr, "-", "(\d+)", int, False 575 ) 576 577 if t is not None: 578 natact["attrs"].append([t, None]) 579 580 if ip_block_min is not None: 581 natact["attrs"].append( 582 ["OVS_NAT_ATTR_IP_MIN", ip_block_min] 583 ) 584 if ip_block_max is not None: 585 natact["attrs"].append( 586 ["OVS_NAT_ATTR_IP_MAX", ip_block_max] 587 ) 588 if proto_min is not None: 589 natact["attrs"].append( 590 ["OVS_NAT_ATTR_PROTO_MIN", proto_min] 591 ) 592 if proto_max is not None: 593 natact["attrs"].append( 594 ["OVS_NAT_ATTR_PROTO_MAX", proto_max] 595 ) 596 597 for natscan in ( 598 ("persistent", "OVS_NAT_ATTR_PERSISTENT"), 599 ("hash", "OVS_NAT_ATTR_PROTO_HASH"), 600 ("random", "OVS_NAT_ATTR_PROTO_RANDOM"), 601 ): 602 if actstr.startswith(natscan[0]): 603 actstr = actstr[len(natscan[0]) :] 604 natact["attrs"].append([natscan[1], None]) 605 actstr = actstr[strspn(actstr, ", ") :] 606 607 ctact["attrs"].append(["OVS_CT_ATTR_NAT", natact]) 608 actstr = actstr[strspn(actstr, ",) ") :] 609 610 self["attrs"].append(["OVS_ACTION_ATTR_CT", ctact]) 611 parsed = True 612 613 actstr = actstr[strspn(actstr, "), ") :] 614 if not parsed: 615 raise ValueError("Action str: '%s' not supported" % actstr) 616 617 618class ovskey(nla): 619 nla_flags = NLA_F_NESTED 620 nla_map = ( 621 ("OVS_KEY_ATTR_UNSPEC", "none"), 622 ("OVS_KEY_ATTR_ENCAP", "none"), 623 ("OVS_KEY_ATTR_PRIORITY", "uint32"), 624 ("OVS_KEY_ATTR_IN_PORT", "uint32"), 625 ("OVS_KEY_ATTR_ETHERNET", "ethaddr"), 626 ("OVS_KEY_ATTR_VLAN", "uint16"), 627 ("OVS_KEY_ATTR_ETHERTYPE", "be16"), 628 ("OVS_KEY_ATTR_IPV4", "ovs_key_ipv4"), 629 ("OVS_KEY_ATTR_IPV6", "ovs_key_ipv6"), 630 ("OVS_KEY_ATTR_TCP", "ovs_key_tcp"), 631 ("OVS_KEY_ATTR_UDP", "ovs_key_udp"), 632 ("OVS_KEY_ATTR_ICMP", "ovs_key_icmp"), 633 ("OVS_KEY_ATTR_ICMPV6", "ovs_key_icmpv6"), 634 ("OVS_KEY_ATTR_ARP", "ovs_key_arp"), 635 ("OVS_KEY_ATTR_ND", "ovs_key_nd"), 636 ("OVS_KEY_ATTR_SKB_MARK", "uint32"), 637 ("OVS_KEY_ATTR_TUNNEL", "none"), 638 ("OVS_KEY_ATTR_SCTP", "ovs_key_sctp"), 639 ("OVS_KEY_ATTR_TCP_FLAGS", "be16"), 640 ("OVS_KEY_ATTR_DP_HASH", "uint32"), 641 ("OVS_KEY_ATTR_RECIRC_ID", "uint32"), 642 ("OVS_KEY_ATTR_MPLS", "array(ovs_key_mpls)"), 643 ("OVS_KEY_ATTR_CT_STATE", "uint32"), 644 ("OVS_KEY_ATTR_CT_ZONE", "uint16"), 645 ("OVS_KEY_ATTR_CT_MARK", "uint32"), 646 ("OVS_KEY_ATTR_CT_LABELS", "none"), 647 ("OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4", "ovs_key_ct_tuple_ipv4"), 648 ("OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6", "ovs_key_ct_tuple_ipv6"), 649 ("OVS_KEY_ATTR_NSH", "none"), 650 ("OVS_KEY_ATTR_PACKET_TYPE", "none"), 651 ("OVS_KEY_ATTR_ND_EXTENSIONS", "none"), 652 ("OVS_KEY_ATTR_TUNNEL_INFO", "none"), 653 ("OVS_KEY_ATTR_IPV6_EXTENSIONS", "none"), 654 ) 655 656 class ovs_key_proto(nla): 657 fields = ( 658 ("src", "!H"), 659 ("dst", "!H"), 660 ) 661 662 fields_map = ( 663 ("src", "src", "%d", lambda x: int(x) if x else 0, 664 convert_int(16)), 665 ("dst", "dst", "%d", lambda x: int(x) if x else 0, 666 convert_int(16)), 667 ) 668 669 def __init__( 670 self, 671 protostr, 672 data=None, 673 offset=None, 674 parent=None, 675 length=None, 676 init=None, 677 ): 678 self.proto_str = protostr 679 nla.__init__( 680 self, 681 data=data, 682 offset=offset, 683 parent=parent, 684 length=length, 685 init=init, 686 ) 687 688 def parse(self, flowstr, typeInst): 689 if not flowstr.startswith(self.proto_str): 690 return None, None 691 692 k = typeInst() 693 m = typeInst() 694 695 flowstr = flowstr[len(self.proto_str) :] 696 if flowstr.startswith("("): 697 flowstr = flowstr[1:] 698 699 keybits = b"" 700 maskbits = b"" 701 for f in self.fields_map: 702 if flowstr.startswith(f[1]): 703 # the following assumes that the field looks 704 # something like 'field.' where '.' is a 705 # character that we don't exactly care about. 706 flowstr = flowstr[len(f[1]) + 1 :] 707 splitchar = 0 708 for c in flowstr: 709 if c == "," or c == ")": 710 break 711 splitchar += 1 712 data = flowstr[:splitchar] 713 flowstr = flowstr[splitchar:] 714 else: 715 data = "" 716 717 if len(f) > 4: 718 k[f[0]], m[f[0]] = f[4](data) 719 else: 720 k[f[0]] = f[3](data) 721 m[f[0]] = f[3](data) 722 723 flowstr = flowstr[strspn(flowstr, ", ") :] 724 if len(flowstr) == 0: 725 return flowstr, k, m 726 727 flowstr = flowstr[strspn(flowstr, "), ") :] 728 729 return flowstr, k, m 730 731 def dpstr(self, masked=None, more=False): 732 outstr = self.proto_str + "(" 733 first = False 734 for f in self.fields_map: 735 if first: 736 outstr += "," 737 if masked is None: 738 outstr += "%s=" % f[0] 739 if isinstance(f[2], str): 740 outstr += f[2] % self[f[1]] 741 else: 742 outstr += f[2](self[f[1]]) 743 first = True 744 elif more or f[3](masked[f[1]]) != 0: 745 outstr += "%s=" % f[0] 746 if isinstance(f[2], str): 747 outstr += f[2] % self[f[1]] 748 else: 749 outstr += f[2](self[f[1]]) 750 outstr += "/" 751 if isinstance(f[2], str): 752 outstr += f[2] % masked[f[1]] 753 else: 754 outstr += f[2](masked[f[1]]) 755 first = True 756 outstr += ")" 757 return outstr 758 759 class ethaddr(ovs_key_proto): 760 fields = ( 761 ("src", "!6s"), 762 ("dst", "!6s"), 763 ) 764 765 fields_map = ( 766 ( 767 "src", 768 "src", 769 macstr, 770 lambda x: int.from_bytes(x, "big"), 771 convert_mac, 772 ), 773 ( 774 "dst", 775 "dst", 776 macstr, 777 lambda x: int.from_bytes(x, "big"), 778 convert_mac, 779 ), 780 ) 781 782 def __init__( 783 self, 784 data=None, 785 offset=None, 786 parent=None, 787 length=None, 788 init=None, 789 ): 790 ovskey.ovs_key_proto.__init__( 791 self, 792 "eth", 793 data=data, 794 offset=offset, 795 parent=parent, 796 length=length, 797 init=init, 798 ) 799 800 class ovs_key_ipv4(ovs_key_proto): 801 fields = ( 802 ("src", "!I"), 803 ("dst", "!I"), 804 ("proto", "B"), 805 ("tos", "B"), 806 ("ttl", "B"), 807 ("frag", "B"), 808 ) 809 810 fields_map = ( 811 ( 812 "src", 813 "src", 814 lambda x: str(ipaddress.IPv4Address(x)), 815 int, 816 convert_ipv4, 817 ), 818 ( 819 "dst", 820 "dst", 821 lambda x: str(ipaddress.IPv4Address(x)), 822 int, 823 convert_ipv4, 824 ), 825 ("proto", "proto", "%d", lambda x: int(x) if x else 0, 826 convert_int(8)), 827 ("tos", "tos", "%d", lambda x: int(x) if x else 0, 828 convert_int(8)), 829 ("ttl", "ttl", "%d", lambda x: int(x) if x else 0, 830 convert_int(8)), 831 ("frag", "frag", "%d", lambda x: int(x) if x else 0, 832 convert_int(8)), 833 ) 834 835 def __init__( 836 self, 837 data=None, 838 offset=None, 839 parent=None, 840 length=None, 841 init=None, 842 ): 843 ovskey.ovs_key_proto.__init__( 844 self, 845 "ipv4", 846 data=data, 847 offset=offset, 848 parent=parent, 849 length=length, 850 init=init, 851 ) 852 853 class ovs_key_ipv6(ovs_key_proto): 854 fields = ( 855 ("src", "!16s"), 856 ("dst", "!16s"), 857 ("label", "!I"), 858 ("proto", "B"), 859 ("tclass", "B"), 860 ("hlimit", "B"), 861 ("frag", "B"), 862 ) 863 864 fields_map = ( 865 ( 866 "src", 867 "src", 868 lambda x: str(ipaddress.IPv6Address(x)), 869 lambda x: int.from_bytes(x, "big"), 870 lambda x: ipaddress.IPv6Address(x), 871 ), 872 ( 873 "dst", 874 "dst", 875 lambda x: str(ipaddress.IPv6Address(x)), 876 lambda x: int.from_bytes(x, "big"), 877 lambda x: ipaddress.IPv6Address(x), 878 ), 879 ("label", "label", "%d", int), 880 ("proto", "proto", "%d", int), 881 ("tclass", "tclass", "%d", int), 882 ("hlimit", "hlimit", "%d", int), 883 ("frag", "frag", "%d", int), 884 ) 885 886 def __init__( 887 self, 888 data=None, 889 offset=None, 890 parent=None, 891 length=None, 892 init=None, 893 ): 894 ovskey.ovs_key_proto.__init__( 895 self, 896 "ipv6", 897 data=data, 898 offset=offset, 899 parent=parent, 900 length=length, 901 init=init, 902 ) 903 904 class ovs_key_tcp(ovs_key_proto): 905 def __init__( 906 self, 907 data=None, 908 offset=None, 909 parent=None, 910 length=None, 911 init=None, 912 ): 913 ovskey.ovs_key_proto.__init__( 914 self, 915 "tcp", 916 data=data, 917 offset=offset, 918 parent=parent, 919 length=length, 920 init=init, 921 ) 922 923 class ovs_key_udp(ovs_key_proto): 924 def __init__( 925 self, 926 data=None, 927 offset=None, 928 parent=None, 929 length=None, 930 init=None, 931 ): 932 ovskey.ovs_key_proto.__init__( 933 self, 934 "udp", 935 data=data, 936 offset=offset, 937 parent=parent, 938 length=length, 939 init=init, 940 ) 941 942 class ovs_key_sctp(ovs_key_proto): 943 def __init__( 944 self, 945 data=None, 946 offset=None, 947 parent=None, 948 length=None, 949 init=None, 950 ): 951 ovskey.ovs_key_proto.__init__( 952 self, 953 "sctp", 954 data=data, 955 offset=offset, 956 parent=parent, 957 length=length, 958 init=init, 959 ) 960 961 class ovs_key_icmp(ovs_key_proto): 962 fields = ( 963 ("type", "B"), 964 ("code", "B"), 965 ) 966 967 fields_map = ( 968 ("type", "type", "%d", lambda x: int(x) if x else 0), 969 ("code", "code", "%d", lambda x: int(x) if x else 0), 970 ) 971 972 def __init__( 973 self, 974 data=None, 975 offset=None, 976 parent=None, 977 length=None, 978 init=None, 979 ): 980 ovskey.ovs_key_proto.__init__( 981 self, 982 "icmp", 983 data=data, 984 offset=offset, 985 parent=parent, 986 length=length, 987 init=init, 988 ) 989 990 class ovs_key_icmpv6(ovs_key_icmp): 991 def __init__( 992 self, 993 data=None, 994 offset=None, 995 parent=None, 996 length=None, 997 init=None, 998 ): 999 ovskey.ovs_key_proto.__init__( 1000 self, 1001 "icmpv6", 1002 data=data, 1003 offset=offset, 1004 parent=parent, 1005 length=length, 1006 init=init, 1007 ) 1008 1009 class ovs_key_arp(ovs_key_proto): 1010 fields = ( 1011 ("sip", "!I"), 1012 ("tip", "!I"), 1013 ("op", "!H"), 1014 ("sha", "!6s"), 1015 ("tha", "!6s"), 1016 ("pad", "xx"), 1017 ) 1018 1019 fields_map = ( 1020 ( 1021 "sip", 1022 "sip", 1023 lambda x: str(ipaddress.IPv4Address(x)), 1024 int, 1025 convert_ipv4, 1026 ), 1027 ( 1028 "tip", 1029 "tip", 1030 lambda x: str(ipaddress.IPv4Address(x)), 1031 int, 1032 convert_ipv4, 1033 ), 1034 ("op", "op", "%d", lambda x: int(x) if x else 0), 1035 ( 1036 "sha", 1037 "sha", 1038 macstr, 1039 lambda x: int.from_bytes(x, "big"), 1040 convert_mac, 1041 ), 1042 ( 1043 "tha", 1044 "tha", 1045 macstr, 1046 lambda x: int.from_bytes(x, "big"), 1047 convert_mac, 1048 ), 1049 ) 1050 1051 def __init__( 1052 self, 1053 data=None, 1054 offset=None, 1055 parent=None, 1056 length=None, 1057 init=None, 1058 ): 1059 ovskey.ovs_key_proto.__init__( 1060 self, 1061 "arp", 1062 data=data, 1063 offset=offset, 1064 parent=parent, 1065 length=length, 1066 init=init, 1067 ) 1068 1069 class ovs_key_nd(ovs_key_proto): 1070 fields = ( 1071 ("target", "!16s"), 1072 ("sll", "!6s"), 1073 ("tll", "!6s"), 1074 ) 1075 1076 fields_map = ( 1077 ( 1078 "target", 1079 "target", 1080 lambda x: str(ipaddress.IPv6Address(x)), 1081 lambda x: int.from_bytes(x, "big"), 1082 ), 1083 ("sll", "sll", macstr, lambda x: int.from_bytes(x, "big")), 1084 ("tll", "tll", macstr, lambda x: int.from_bytes(x, "big")), 1085 ) 1086 1087 def __init__( 1088 self, 1089 data=None, 1090 offset=None, 1091 parent=None, 1092 length=None, 1093 init=None, 1094 ): 1095 ovskey.ovs_key_proto.__init__( 1096 self, 1097 "nd", 1098 data=data, 1099 offset=offset, 1100 parent=parent, 1101 length=length, 1102 init=init, 1103 ) 1104 1105 class ovs_key_ct_tuple_ipv4(ovs_key_proto): 1106 fields = ( 1107 ("src", "!I"), 1108 ("dst", "!I"), 1109 ("tp_src", "!H"), 1110 ("tp_dst", "!H"), 1111 ("proto", "B"), 1112 ) 1113 1114 fields_map = ( 1115 ( 1116 "src", 1117 "src", 1118 lambda x: str(ipaddress.IPv4Address(x)), 1119 int, 1120 ), 1121 ( 1122 "dst", 1123 "dst", 1124 lambda x: str(ipaddress.IPv6Address(x)), 1125 int, 1126 ), 1127 ("tp_src", "tp_src", "%d", int), 1128 ("tp_dst", "tp_dst", "%d", int), 1129 ("proto", "proto", "%d", int), 1130 ) 1131 1132 def __init__( 1133 self, 1134 data=None, 1135 offset=None, 1136 parent=None, 1137 length=None, 1138 init=None, 1139 ): 1140 ovskey.ovs_key_proto.__init__( 1141 self, 1142 "ct_tuple4", 1143 data=data, 1144 offset=offset, 1145 parent=parent, 1146 length=length, 1147 init=init, 1148 ) 1149 1150 class ovs_key_ct_tuple_ipv6(nla): 1151 fields = ( 1152 ("src", "!16s"), 1153 ("dst", "!16s"), 1154 ("tp_src", "!H"), 1155 ("tp_dst", "!H"), 1156 ("proto", "B"), 1157 ) 1158 1159 fields_map = ( 1160 ( 1161 "src", 1162 "src", 1163 lambda x: str(ipaddress.IPv6Address(x)), 1164 lambda x: int.from_bytes(x, "big", convertmac), 1165 ), 1166 ( 1167 "dst", 1168 "dst", 1169 lambda x: str(ipaddress.IPv6Address(x)), 1170 lambda x: int.from_bytes(x, "big"), 1171 ), 1172 ("tp_src", "tp_src", "%d", int), 1173 ("tp_dst", "tp_dst", "%d", int), 1174 ("proto", "proto", "%d", int), 1175 ) 1176 1177 def __init__( 1178 self, 1179 data=None, 1180 offset=None, 1181 parent=None, 1182 length=None, 1183 init=None, 1184 ): 1185 ovskey.ovs_key_proto.__init__( 1186 self, 1187 "ct_tuple6", 1188 data=data, 1189 offset=offset, 1190 parent=parent, 1191 length=length, 1192 init=init, 1193 ) 1194 1195 class ovs_key_mpls(nla): 1196 fields = (("lse", ">I"),) 1197 1198 def parse(self, flowstr, mask=None): 1199 for field in ( 1200 ("OVS_KEY_ATTR_PRIORITY", "skb_priority", intparse), 1201 ("OVS_KEY_ATTR_SKB_MARK", "skb_mark", intparse), 1202 ("OVS_KEY_ATTR_RECIRC_ID", "recirc_id", intparse), 1203 ("OVS_KEY_ATTR_DP_HASH", "dp_hash", intparse), 1204 ("OVS_KEY_ATTR_CT_STATE", "ct_state", parse_ct_state), 1205 ("OVS_KEY_ATTR_CT_ZONE", "ct_zone", intparse), 1206 ("OVS_KEY_ATTR_CT_MARK", "ct_mark", intparse), 1207 ("OVS_KEY_ATTR_IN_PORT", "in_port", intparse), 1208 ( 1209 "OVS_KEY_ATTR_ETHERNET", 1210 "eth", 1211 ovskey.ethaddr, 1212 ), 1213 ( 1214 "OVS_KEY_ATTR_ETHERTYPE", 1215 "eth_type", 1216 lambda x: intparse(x, "0xffff"), 1217 ), 1218 ( 1219 "OVS_KEY_ATTR_IPV4", 1220 "ipv4", 1221 ovskey.ovs_key_ipv4, 1222 ), 1223 ( 1224 "OVS_KEY_ATTR_IPV6", 1225 "ipv6", 1226 ovskey.ovs_key_ipv6, 1227 ), 1228 ( 1229 "OVS_KEY_ATTR_ARP", 1230 "arp", 1231 ovskey.ovs_key_arp, 1232 ), 1233 ( 1234 "OVS_KEY_ATTR_TCP", 1235 "tcp", 1236 ovskey.ovs_key_tcp, 1237 ), 1238 ( 1239 "OVS_KEY_ATTR_UDP", 1240 "udp", 1241 ovskey.ovs_key_udp, 1242 ), 1243 ( 1244 "OVS_KEY_ATTR_ICMP", 1245 "icmp", 1246 ovskey.ovs_key_icmp, 1247 ), 1248 ( 1249 "OVS_KEY_ATTR_TCP_FLAGS", 1250 "tcp_flags", 1251 lambda x: parse_flags(x, None), 1252 ), 1253 ): 1254 fld = field[1] + "(" 1255 if not flowstr.startswith(fld): 1256 continue 1257 1258 if not isinstance(field[2], types.FunctionType): 1259 nk = field[2]() 1260 flowstr, k, m = nk.parse(flowstr, field[2]) 1261 else: 1262 flowstr = flowstr[len(fld) :] 1263 flowstr, k, m = field[2](flowstr) 1264 1265 if m and mask is not None: 1266 mask["attrs"].append([field[0], m]) 1267 self["attrs"].append([field[0], k]) 1268 1269 flowstr = flowstr[strspn(flowstr, "),") :] 1270 1271 return flowstr 1272 1273 def dpstr(self, mask=None, more=False): 1274 print_str = "" 1275 1276 for field in ( 1277 ( 1278 "OVS_KEY_ATTR_PRIORITY", 1279 "skb_priority", 1280 "%d", 1281 lambda x: False, 1282 True, 1283 ), 1284 ( 1285 "OVS_KEY_ATTR_SKB_MARK", 1286 "skb_mark", 1287 "%d", 1288 lambda x: False, 1289 True, 1290 ), 1291 ( 1292 "OVS_KEY_ATTR_RECIRC_ID", 1293 "recirc_id", 1294 "0x%08X", 1295 lambda x: False, 1296 True, 1297 ), 1298 ( 1299 "OVS_KEY_ATTR_DP_HASH", 1300 "dp_hash", 1301 "0x%08X", 1302 lambda x: False, 1303 True, 1304 ), 1305 ( 1306 "OVS_KEY_ATTR_CT_STATE", 1307 "ct_state", 1308 "0x%04x", 1309 lambda x: False, 1310 True, 1311 ), 1312 ( 1313 "OVS_KEY_ATTR_CT_ZONE", 1314 "ct_zone", 1315 "0x%04x", 1316 lambda x: False, 1317 True, 1318 ), 1319 ( 1320 "OVS_KEY_ATTR_CT_MARK", 1321 "ct_mark", 1322 "0x%08x", 1323 lambda x: False, 1324 True, 1325 ), 1326 ( 1327 "OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4", 1328 None, 1329 None, 1330 False, 1331 False, 1332 ), 1333 ( 1334 "OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6", 1335 None, 1336 None, 1337 False, 1338 False, 1339 ), 1340 ( 1341 "OVS_KEY_ATTR_IN_PORT", 1342 "in_port", 1343 "%d", 1344 lambda x: True, 1345 True, 1346 ), 1347 ("OVS_KEY_ATTR_ETHERNET", None, None, False, False), 1348 ( 1349 "OVS_KEY_ATTR_ETHERTYPE", 1350 "eth_type", 1351 "0x%04x", 1352 lambda x: int(x) == 0xFFFF, 1353 True, 1354 ), 1355 ("OVS_KEY_ATTR_IPV4", None, None, False, False), 1356 ("OVS_KEY_ATTR_IPV6", None, None, False, False), 1357 ("OVS_KEY_ATTR_ARP", None, None, False, False), 1358 ("OVS_KEY_ATTR_TCP", None, None, False, False), 1359 ( 1360 "OVS_KEY_ATTR_TCP_FLAGS", 1361 "tcp_flags", 1362 "0x%04x", 1363 lambda x: False, 1364 True, 1365 ), 1366 ("OVS_KEY_ATTR_UDP", None, None, False, False), 1367 ("OVS_KEY_ATTR_SCTP", None, None, False, False), 1368 ("OVS_KEY_ATTR_ICMP", None, None, False, False), 1369 ("OVS_KEY_ATTR_ICMPV6", None, None, False, False), 1370 ("OVS_KEY_ATTR_ND", None, None, False, False), 1371 ): 1372 v = self.get_attr(field[0]) 1373 if v is not None: 1374 m = None if mask is None else mask.get_attr(field[0]) 1375 if field[4] is False: 1376 print_str += v.dpstr(m, more) 1377 print_str += "," 1378 else: 1379 if m is None or field[3](m): 1380 print_str += field[1] + "(" 1381 print_str += field[2] % v 1382 print_str += ")," 1383 elif more or m != 0: 1384 print_str += field[1] + "(" 1385 print_str += (field[2] % v) + "/" + (field[2] % m) 1386 print_str += ")," 1387 1388 return print_str 1389 1390 1391class OvsPacket(GenericNetlinkSocket): 1392 OVS_PACKET_CMD_MISS = 1 # Flow table miss 1393 OVS_PACKET_CMD_ACTION = 2 # USERSPACE action 1394 OVS_PACKET_CMD_EXECUTE = 3 # Apply actions to packet 1395 1396 class ovs_packet_msg(ovs_dp_msg): 1397 nla_map = ( 1398 ("OVS_PACKET_ATTR_UNSPEC", "none"), 1399 ("OVS_PACKET_ATTR_PACKET", "array(uint8)"), 1400 ("OVS_PACKET_ATTR_KEY", "ovskey"), 1401 ("OVS_PACKET_ATTR_ACTIONS", "ovsactions"), 1402 ("OVS_PACKET_ATTR_USERDATA", "none"), 1403 ("OVS_PACKET_ATTR_EGRESS_TUN_KEY", "none"), 1404 ("OVS_PACKET_ATTR_UNUSED1", "none"), 1405 ("OVS_PACKET_ATTR_UNUSED2", "none"), 1406 ("OVS_PACKET_ATTR_PROBE", "none"), 1407 ("OVS_PACKET_ATTR_MRU", "uint16"), 1408 ("OVS_PACKET_ATTR_LEN", "uint32"), 1409 ("OVS_PACKET_ATTR_HASH", "uint64"), 1410 ) 1411 1412 def __init__(self): 1413 GenericNetlinkSocket.__init__(self) 1414 self.bind(OVS_PACKET_FAMILY, OvsPacket.ovs_packet_msg) 1415 1416 def upcall_handler(self, up=None): 1417 print("listening on upcall packet handler:", self.epid) 1418 while True: 1419 try: 1420 msgs = self.get() 1421 for msg in msgs: 1422 if not up: 1423 continue 1424 if msg["cmd"] == OvsPacket.OVS_PACKET_CMD_MISS: 1425 up.miss(msg) 1426 elif msg["cmd"] == OvsPacket.OVS_PACKET_CMD_ACTION: 1427 up.action(msg) 1428 elif msg["cmd"] == OvsPacket.OVS_PACKET_CMD_EXECUTE: 1429 up.execute(msg) 1430 else: 1431 print("Unkonwn cmd: %d" % msg["cmd"]) 1432 except NetlinkError as ne: 1433 raise ne 1434 1435 1436class OvsDatapath(GenericNetlinkSocket): 1437 OVS_DP_F_VPORT_PIDS = 1 << 1 1438 OVS_DP_F_DISPATCH_UPCALL_PER_CPU = 1 << 3 1439 1440 class dp_cmd_msg(ovs_dp_msg): 1441 """ 1442 Message class that will be used to communicate with the kernel module. 1443 """ 1444 1445 nla_map = ( 1446 ("OVS_DP_ATTR_UNSPEC", "none"), 1447 ("OVS_DP_ATTR_NAME", "asciiz"), 1448 ("OVS_DP_ATTR_UPCALL_PID", "array(uint32)"), 1449 ("OVS_DP_ATTR_STATS", "dpstats"), 1450 ("OVS_DP_ATTR_MEGAFLOW_STATS", "megaflowstats"), 1451 ("OVS_DP_ATTR_USER_FEATURES", "uint32"), 1452 ("OVS_DP_ATTR_PAD", "none"), 1453 ("OVS_DP_ATTR_MASKS_CACHE_SIZE", "uint32"), 1454 ("OVS_DP_ATTR_PER_CPU_PIDS", "array(uint32)"), 1455 ) 1456 1457 class dpstats(nla): 1458 fields = ( 1459 ("hit", "=Q"), 1460 ("missed", "=Q"), 1461 ("lost", "=Q"), 1462 ("flows", "=Q"), 1463 ) 1464 1465 class megaflowstats(nla): 1466 fields = ( 1467 ("mask_hit", "=Q"), 1468 ("masks", "=I"), 1469 ("padding", "=I"), 1470 ("cache_hits", "=Q"), 1471 ("pad1", "=Q"), 1472 ) 1473 1474 def __init__(self): 1475 GenericNetlinkSocket.__init__(self) 1476 self.bind(OVS_DATAPATH_FAMILY, OvsDatapath.dp_cmd_msg) 1477 1478 def info(self, dpname, ifindex=0): 1479 msg = OvsDatapath.dp_cmd_msg() 1480 msg["cmd"] = OVS_DP_CMD_GET 1481 msg["version"] = OVS_DATAPATH_VERSION 1482 msg["reserved"] = 0 1483 msg["dpifindex"] = ifindex 1484 msg["attrs"].append(["OVS_DP_ATTR_NAME", dpname]) 1485 1486 try: 1487 reply = self.nlm_request( 1488 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST 1489 ) 1490 reply = reply[0] 1491 except NetlinkError as ne: 1492 if ne.code == errno.ENODEV: 1493 reply = None 1494 else: 1495 raise ne 1496 1497 return reply 1498 1499 def create( 1500 self, dpname, shouldUpcall=False, versionStr=None, p=OvsPacket() 1501 ): 1502 msg = OvsDatapath.dp_cmd_msg() 1503 msg["cmd"] = OVS_DP_CMD_NEW 1504 if versionStr is None: 1505 msg["version"] = OVS_DATAPATH_VERSION 1506 else: 1507 msg["version"] = int(versionStr.split(":")[0], 0) 1508 msg["reserved"] = 0 1509 msg["dpifindex"] = 0 1510 msg["attrs"].append(["OVS_DP_ATTR_NAME", dpname]) 1511 1512 dpfeatures = 0 1513 if versionStr is not None and versionStr.find(":") != -1: 1514 dpfeatures = int(versionStr.split(":")[1], 0) 1515 else: 1516 if versionStr is None or versionStr.find(":") == -1: 1517 dpfeatures |= OvsDatapath.OVS_DP_F_DISPATCH_UPCALL_PER_CPU 1518 dpfeatures &= ~OvsDatapath.OVS_DP_F_VPORT_PIDS 1519 1520 nproc = multiprocessing.cpu_count() 1521 procarray = [] 1522 for i in range(1, nproc): 1523 procarray += [int(p.epid)] 1524 msg["attrs"].append(["OVS_DP_ATTR_UPCALL_PID", procarray]) 1525 msg["attrs"].append(["OVS_DP_ATTR_USER_FEATURES", dpfeatures]) 1526 if not shouldUpcall: 1527 msg["attrs"].append(["OVS_DP_ATTR_UPCALL_PID", [0]]) 1528 1529 try: 1530 reply = self.nlm_request( 1531 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK 1532 ) 1533 reply = reply[0] 1534 except NetlinkError as ne: 1535 if ne.code == errno.EEXIST: 1536 reply = None 1537 else: 1538 raise ne 1539 1540 return reply 1541 1542 def destroy(self, dpname): 1543 msg = OvsDatapath.dp_cmd_msg() 1544 msg["cmd"] = OVS_DP_CMD_DEL 1545 msg["version"] = OVS_DATAPATH_VERSION 1546 msg["reserved"] = 0 1547 msg["dpifindex"] = 0 1548 msg["attrs"].append(["OVS_DP_ATTR_NAME", dpname]) 1549 1550 try: 1551 reply = self.nlm_request( 1552 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK 1553 ) 1554 reply = reply[0] 1555 except NetlinkError as ne: 1556 if ne.code == errno.ENODEV: 1557 reply = None 1558 else: 1559 raise ne 1560 1561 return reply 1562 1563 1564class OvsVport(GenericNetlinkSocket): 1565 OVS_VPORT_TYPE_NETDEV = 1 1566 OVS_VPORT_TYPE_INTERNAL = 2 1567 OVS_VPORT_TYPE_GRE = 3 1568 OVS_VPORT_TYPE_VXLAN = 4 1569 OVS_VPORT_TYPE_GENEVE = 5 1570 1571 class ovs_vport_msg(ovs_dp_msg): 1572 nla_map = ( 1573 ("OVS_VPORT_ATTR_UNSPEC", "none"), 1574 ("OVS_VPORT_ATTR_PORT_NO", "uint32"), 1575 ("OVS_VPORT_ATTR_TYPE", "uint32"), 1576 ("OVS_VPORT_ATTR_NAME", "asciiz"), 1577 ("OVS_VPORT_ATTR_OPTIONS", "none"), 1578 ("OVS_VPORT_ATTR_UPCALL_PID", "array(uint32)"), 1579 ("OVS_VPORT_ATTR_STATS", "vportstats"), 1580 ("OVS_VPORT_ATTR_PAD", "none"), 1581 ("OVS_VPORT_ATTR_IFINDEX", "uint32"), 1582 ("OVS_VPORT_ATTR_NETNSID", "uint32"), 1583 ) 1584 1585 class vportstats(nla): 1586 fields = ( 1587 ("rx_packets", "=Q"), 1588 ("tx_packets", "=Q"), 1589 ("rx_bytes", "=Q"), 1590 ("tx_bytes", "=Q"), 1591 ("rx_errors", "=Q"), 1592 ("tx_errors", "=Q"), 1593 ("rx_dropped", "=Q"), 1594 ("tx_dropped", "=Q"), 1595 ) 1596 1597 def type_to_str(vport_type): 1598 if vport_type == OvsVport.OVS_VPORT_TYPE_NETDEV: 1599 return "netdev" 1600 elif vport_type == OvsVport.OVS_VPORT_TYPE_INTERNAL: 1601 return "internal" 1602 elif vport_type == OvsVport.OVS_VPORT_TYPE_GRE: 1603 return "gre" 1604 elif vport_type == OvsVport.OVS_VPORT_TYPE_VXLAN: 1605 return "vxlan" 1606 elif vport_type == OvsVport.OVS_VPORT_TYPE_GENEVE: 1607 return "geneve" 1608 raise ValueError("Unknown vport type:%d" % vport_type) 1609 1610 def str_to_type(vport_type): 1611 if vport_type == "netdev": 1612 return OvsVport.OVS_VPORT_TYPE_NETDEV 1613 elif vport_type == "internal": 1614 return OvsVport.OVS_VPORT_TYPE_INTERNAL 1615 elif vport_type == "gre": 1616 return OvsVport.OVS_VPORT_TYPE_INTERNAL 1617 elif vport_type == "vxlan": 1618 return OvsVport.OVS_VPORT_TYPE_VXLAN 1619 elif vport_type == "geneve": 1620 return OvsVport.OVS_VPORT_TYPE_GENEVE 1621 raise ValueError("Unknown vport type: '%s'" % vport_type) 1622 1623 def __init__(self, packet=OvsPacket()): 1624 GenericNetlinkSocket.__init__(self) 1625 self.bind(OVS_VPORT_FAMILY, OvsVport.ovs_vport_msg) 1626 self.upcall_packet = packet 1627 1628 def info(self, vport_name, dpifindex=0, portno=None): 1629 msg = OvsVport.ovs_vport_msg() 1630 1631 msg["cmd"] = OVS_VPORT_CMD_GET 1632 msg["version"] = OVS_DATAPATH_VERSION 1633 msg["reserved"] = 0 1634 msg["dpifindex"] = dpifindex 1635 1636 if portno is None: 1637 msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_name]) 1638 else: 1639 msg["attrs"].append(["OVS_VPORT_ATTR_PORT_NO", portno]) 1640 1641 try: 1642 reply = self.nlm_request( 1643 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST 1644 ) 1645 reply = reply[0] 1646 except NetlinkError as ne: 1647 if ne.code == errno.ENODEV: 1648 reply = None 1649 else: 1650 raise ne 1651 return reply 1652 1653 def attach(self, dpindex, vport_ifname, ptype): 1654 msg = OvsVport.ovs_vport_msg() 1655 1656 msg["cmd"] = OVS_VPORT_CMD_NEW 1657 msg["version"] = OVS_DATAPATH_VERSION 1658 msg["reserved"] = 0 1659 msg["dpifindex"] = dpindex 1660 port_type = OvsVport.str_to_type(ptype) 1661 1662 msg["attrs"].append(["OVS_VPORT_ATTR_TYPE", port_type]) 1663 msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_ifname]) 1664 msg["attrs"].append( 1665 ["OVS_VPORT_ATTR_UPCALL_PID", [self.upcall_packet.epid]] 1666 ) 1667 1668 try: 1669 reply = self.nlm_request( 1670 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK 1671 ) 1672 reply = reply[0] 1673 except NetlinkError as ne: 1674 if ne.code == errno.EEXIST: 1675 reply = None 1676 else: 1677 raise ne 1678 return reply 1679 1680 def reset_upcall(self, dpindex, vport_ifname, p=None): 1681 msg = OvsVport.ovs_vport_msg() 1682 1683 msg["cmd"] = OVS_VPORT_CMD_SET 1684 msg["version"] = OVS_DATAPATH_VERSION 1685 msg["reserved"] = 0 1686 msg["dpifindex"] = dpindex 1687 msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_ifname]) 1688 1689 if p == None: 1690 p = self.upcall_packet 1691 else: 1692 self.upcall_packet = p 1693 1694 msg["attrs"].append(["OVS_VPORT_ATTR_UPCALL_PID", [p.epid]]) 1695 1696 try: 1697 reply = self.nlm_request( 1698 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK 1699 ) 1700 reply = reply[0] 1701 except NetlinkError as ne: 1702 raise ne 1703 return reply 1704 1705 def detach(self, dpindex, vport_ifname): 1706 msg = OvsVport.ovs_vport_msg() 1707 1708 msg["cmd"] = OVS_VPORT_CMD_DEL 1709 msg["version"] = OVS_DATAPATH_VERSION 1710 msg["reserved"] = 0 1711 msg["dpifindex"] = dpindex 1712 msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_ifname]) 1713 1714 try: 1715 reply = self.nlm_request( 1716 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK 1717 ) 1718 reply = reply[0] 1719 except NetlinkError as ne: 1720 if ne.code == errno.ENODEV: 1721 reply = None 1722 else: 1723 raise ne 1724 return reply 1725 1726 def upcall_handler(self, handler=None): 1727 self.upcall_packet.upcall_handler(handler) 1728 1729 1730class OvsFlow(GenericNetlinkSocket): 1731 class ovs_flow_msg(ovs_dp_msg): 1732 nla_map = ( 1733 ("OVS_FLOW_ATTR_UNSPEC", "none"), 1734 ("OVS_FLOW_ATTR_KEY", "ovskey"), 1735 ("OVS_FLOW_ATTR_ACTIONS", "ovsactions"), 1736 ("OVS_FLOW_ATTR_STATS", "flowstats"), 1737 ("OVS_FLOW_ATTR_TCP_FLAGS", "uint8"), 1738 ("OVS_FLOW_ATTR_USED", "uint64"), 1739 ("OVS_FLOW_ATTR_CLEAR", "none"), 1740 ("OVS_FLOW_ATTR_MASK", "ovskey"), 1741 ("OVS_FLOW_ATTR_PROBE", "none"), 1742 ("OVS_FLOW_ATTR_UFID", "array(uint32)"), 1743 ("OVS_FLOW_ATTR_UFID_FLAGS", "uint32"), 1744 ) 1745 1746 class flowstats(nla): 1747 fields = ( 1748 ("packets", "=Q"), 1749 ("bytes", "=Q"), 1750 ) 1751 1752 def dpstr(self, more=False): 1753 ufid = self.get_attr("OVS_FLOW_ATTR_UFID") 1754 ufid_str = "" 1755 if ufid is not None: 1756 ufid_str = ( 1757 "ufid:{:08x}-{:04x}-{:04x}-{:04x}-{:04x}{:08x}".format( 1758 ufid[0], 1759 ufid[1] >> 16, 1760 ufid[1] & 0xFFFF, 1761 ufid[2] >> 16, 1762 ufid[2] & 0, 1763 ufid[3], 1764 ) 1765 ) 1766 1767 key_field = self.get_attr("OVS_FLOW_ATTR_KEY") 1768 keymsg = None 1769 if key_field is not None: 1770 keymsg = key_field 1771 1772 mask_field = self.get_attr("OVS_FLOW_ATTR_MASK") 1773 maskmsg = None 1774 if mask_field is not None: 1775 maskmsg = mask_field 1776 1777 acts_field = self.get_attr("OVS_FLOW_ATTR_ACTIONS") 1778 actsmsg = None 1779 if acts_field is not None: 1780 actsmsg = acts_field 1781 1782 print_str = "" 1783 1784 if more: 1785 print_str += ufid_str + "," 1786 1787 if keymsg is not None: 1788 print_str += keymsg.dpstr(maskmsg, more) 1789 1790 stats = self.get_attr("OVS_FLOW_ATTR_STATS") 1791 if stats is None: 1792 print_str += " packets:0, bytes:0," 1793 else: 1794 print_str += " packets:%d, bytes:%d," % ( 1795 stats["packets"], 1796 stats["bytes"], 1797 ) 1798 1799 used = self.get_attr("OVS_FLOW_ATTR_USED") 1800 print_str += " used:" 1801 if used is None: 1802 print_str += "never," 1803 else: 1804 used_time = int(used) 1805 cur_time_sec = time.clock_gettime(time.CLOCK_MONOTONIC) 1806 used_time = (cur_time_sec * 1000) - used_time 1807 print_str += "{}s,".format(used_time / 1000) 1808 1809 print_str += " actions:" 1810 if ( 1811 actsmsg is None 1812 or "attrs" not in actsmsg 1813 or len(actsmsg["attrs"]) == 0 1814 ): 1815 print_str += "drop" 1816 else: 1817 print_str += actsmsg.dpstr(more) 1818 1819 return print_str 1820 1821 def parse(self, flowstr, actstr, dpidx=0): 1822 OVS_UFID_F_OMIT_KEY = 1 << 0 1823 OVS_UFID_F_OMIT_MASK = 1 << 1 1824 OVS_UFID_F_OMIT_ACTIONS = 1 << 2 1825 1826 self["cmd"] = 0 1827 self["version"] = 0 1828 self["reserved"] = 0 1829 self["dpifindex"] = 0 1830 1831 if flowstr.startswith("ufid:"): 1832 count = 5 1833 while flowstr[count] != ",": 1834 count += 1 1835 ufidstr = flowstr[5:count] 1836 flowstr = flowstr[count + 1 :] 1837 else: 1838 ufidstr = str(uuid.uuid4()) 1839 uuidRawObj = uuid.UUID(ufidstr).fields 1840 1841 self["attrs"].append( 1842 [ 1843 "OVS_FLOW_ATTR_UFID", 1844 [ 1845 uuidRawObj[0], 1846 uuidRawObj[1] << 16 | uuidRawObj[2], 1847 uuidRawObj[3] << 24 1848 | uuidRawObj[4] << 16 1849 | uuidRawObj[5] & (0xFF << 32) >> 32, 1850 uuidRawObj[5] & (0xFFFFFFFF), 1851 ], 1852 ] 1853 ) 1854 self["attrs"].append( 1855 [ 1856 "OVS_FLOW_ATTR_UFID_FLAGS", 1857 int( 1858 OVS_UFID_F_OMIT_KEY 1859 | OVS_UFID_F_OMIT_MASK 1860 | OVS_UFID_F_OMIT_ACTIONS 1861 ), 1862 ] 1863 ) 1864 1865 k = ovskey() 1866 m = ovskey() 1867 k.parse(flowstr, m) 1868 self["attrs"].append(["OVS_FLOW_ATTR_KEY", k]) 1869 self["attrs"].append(["OVS_FLOW_ATTR_MASK", m]) 1870 1871 a = ovsactions() 1872 a.parse(actstr) 1873 self["attrs"].append(["OVS_FLOW_ATTR_ACTIONS", a]) 1874 1875 def __init__(self): 1876 GenericNetlinkSocket.__init__(self) 1877 1878 self.bind(OVS_FLOW_FAMILY, OvsFlow.ovs_flow_msg) 1879 1880 def add_flow(self, dpifindex, flowmsg): 1881 """ 1882 Send a new flow message to the kernel. 1883 1884 dpifindex should be a valid datapath obtained by calling 1885 into the OvsDatapath lookup 1886 1887 flowmsg is a flow object obtained by calling a dpparse 1888 """ 1889 1890 flowmsg["cmd"] = OVS_FLOW_CMD_NEW 1891 flowmsg["version"] = OVS_DATAPATH_VERSION 1892 flowmsg["reserved"] = 0 1893 flowmsg["dpifindex"] = dpifindex 1894 1895 try: 1896 reply = self.nlm_request( 1897 flowmsg, 1898 msg_type=self.prid, 1899 msg_flags=NLM_F_REQUEST | NLM_F_ACK, 1900 ) 1901 reply = reply[0] 1902 except NetlinkError as ne: 1903 print(flowmsg) 1904 raise ne 1905 return reply 1906 1907 def dump(self, dpifindex, flowspec=None): 1908 """ 1909 Returns a list of messages containing flows. 1910 1911 dpifindex should be a valid datapath obtained by calling 1912 into the OvsDatapath lookup 1913 1914 flowpsec is a string which represents a flow in the dpctl 1915 format. 1916 """ 1917 msg = OvsFlow.ovs_flow_msg() 1918 1919 msg["cmd"] = OVS_FLOW_CMD_GET 1920 msg["version"] = OVS_DATAPATH_VERSION 1921 msg["reserved"] = 0 1922 msg["dpifindex"] = dpifindex 1923 1924 msg_flags = NLM_F_REQUEST | NLM_F_ACK 1925 if flowspec is None: 1926 msg_flags |= NLM_F_DUMP 1927 rep = None 1928 1929 try: 1930 rep = self.nlm_request( 1931 msg, 1932 msg_type=self.prid, 1933 msg_flags=msg_flags, 1934 ) 1935 except NetlinkError as ne: 1936 raise ne 1937 return rep 1938 1939 def miss(self, packetmsg): 1940 seq = packetmsg["header"]["sequence_number"] 1941 keystr = "(none)" 1942 key_field = packetmsg.get_attr("OVS_PACKET_ATTR_KEY") 1943 if key_field is not None: 1944 keystr = key_field.dpstr(None, True) 1945 1946 pktdata = packetmsg.get_attr("OVS_PACKET_ATTR_PACKET") 1947 pktpres = "yes" if pktdata is not None else "no" 1948 1949 print("MISS upcall[%d/%s]: %s" % (seq, pktpres, keystr), flush=True) 1950 1951 def execute(self, packetmsg): 1952 print("userspace execute command") 1953 1954 def action(self, packetmsg): 1955 print("userspace action command") 1956 1957 1958def print_ovsdp_full(dp_lookup_rep, ifindex, ndb=NDB(), vpl=OvsVport()): 1959 dp_name = dp_lookup_rep.get_attr("OVS_DP_ATTR_NAME") 1960 base_stats = dp_lookup_rep.get_attr("OVS_DP_ATTR_STATS") 1961 megaflow_stats = dp_lookup_rep.get_attr("OVS_DP_ATTR_MEGAFLOW_STATS") 1962 user_features = dp_lookup_rep.get_attr("OVS_DP_ATTR_USER_FEATURES") 1963 masks_cache_size = dp_lookup_rep.get_attr("OVS_DP_ATTR_MASKS_CACHE_SIZE") 1964 1965 print("%s:" % dp_name) 1966 print( 1967 " lookups: hit:%d missed:%d lost:%d" 1968 % (base_stats["hit"], base_stats["missed"], base_stats["lost"]) 1969 ) 1970 print(" flows:%d" % base_stats["flows"]) 1971 pkts = base_stats["hit"] + base_stats["missed"] 1972 avg = (megaflow_stats["mask_hit"] / pkts) if pkts != 0 else 0.0 1973 print( 1974 " masks: hit:%d total:%d hit/pkt:%f" 1975 % (megaflow_stats["mask_hit"], megaflow_stats["masks"], avg) 1976 ) 1977 print(" caches:") 1978 print(" masks-cache: size:%d" % masks_cache_size) 1979 1980 if user_features is not None: 1981 print(" features: 0x%X" % user_features) 1982 1983 # port print out 1984 for iface in ndb.interfaces: 1985 rep = vpl.info(iface.ifname, ifindex) 1986 if rep is not None: 1987 print( 1988 " port %d: %s (%s)" 1989 % ( 1990 rep.get_attr("OVS_VPORT_ATTR_PORT_NO"), 1991 rep.get_attr("OVS_VPORT_ATTR_NAME"), 1992 OvsVport.type_to_str(rep.get_attr("OVS_VPORT_ATTR_TYPE")), 1993 ) 1994 ) 1995 1996 1997def main(argv): 1998 nlmsg_atoms.ovskey = ovskey 1999 nlmsg_atoms.ovsactions = ovsactions 2000 2001 parser = argparse.ArgumentParser() 2002 parser.add_argument( 2003 "-v", 2004 "--verbose", 2005 action="count", 2006 help="Increment 'verbose' output counter.", 2007 default=0, 2008 ) 2009 subparsers = parser.add_subparsers() 2010 2011 showdpcmd = subparsers.add_parser("show") 2012 showdpcmd.add_argument( 2013 "showdp", metavar="N", type=str, nargs="?", help="Datapath Name" 2014 ) 2015 2016 adddpcmd = subparsers.add_parser("add-dp") 2017 adddpcmd.add_argument("adddp", help="Datapath Name") 2018 adddpcmd.add_argument( 2019 "-u", 2020 "--upcall", 2021 action="store_true", 2022 help="Leave open a reader for upcalls", 2023 ) 2024 adddpcmd.add_argument( 2025 "-V", 2026 "--versioning", 2027 required=False, 2028 help="Specify a custom version / feature string", 2029 ) 2030 2031 deldpcmd = subparsers.add_parser("del-dp") 2032 deldpcmd.add_argument("deldp", help="Datapath Name") 2033 2034 addifcmd = subparsers.add_parser("add-if") 2035 addifcmd.add_argument("dpname", help="Datapath Name") 2036 addifcmd.add_argument("addif", help="Interface name for adding") 2037 addifcmd.add_argument( 2038 "-u", 2039 "--upcall", 2040 action="store_true", 2041 help="Leave open a reader for upcalls", 2042 ) 2043 addifcmd.add_argument( 2044 "-t", 2045 "--ptype", 2046 type=str, 2047 default="netdev", 2048 choices=["netdev", "internal"], 2049 help="Interface type (default netdev)", 2050 ) 2051 delifcmd = subparsers.add_parser("del-if") 2052 delifcmd.add_argument("dpname", help="Datapath Name") 2053 delifcmd.add_argument("delif", help="Interface name for adding") 2054 2055 dumpflcmd = subparsers.add_parser("dump-flows") 2056 dumpflcmd.add_argument("dumpdp", help="Datapath Name") 2057 2058 addflcmd = subparsers.add_parser("add-flow") 2059 addflcmd.add_argument("flbr", help="Datapath name") 2060 addflcmd.add_argument("flow", help="Flow specification") 2061 addflcmd.add_argument("acts", help="Flow actions") 2062 2063 args = parser.parse_args() 2064 2065 if args.verbose > 0: 2066 if args.verbose > 1: 2067 logging.basicConfig(level=logging.DEBUG) 2068 2069 ovspk = OvsPacket() 2070 ovsdp = OvsDatapath() 2071 ovsvp = OvsVport(ovspk) 2072 ovsflow = OvsFlow() 2073 ndb = NDB() 2074 2075 if hasattr(args, "showdp"): 2076 found = False 2077 for iface in ndb.interfaces: 2078 rep = None 2079 if args.showdp is None: 2080 rep = ovsdp.info(iface.ifname, 0) 2081 elif args.showdp == iface.ifname: 2082 rep = ovsdp.info(iface.ifname, 0) 2083 2084 if rep is not None: 2085 found = True 2086 print_ovsdp_full(rep, iface.index, ndb, ovsvp) 2087 2088 if not found: 2089 msg = "No DP found" 2090 if args.showdp is not None: 2091 msg += ":'%s'" % args.showdp 2092 print(msg) 2093 elif hasattr(args, "adddp"): 2094 rep = ovsdp.create(args.adddp, args.upcall, args.versioning, ovspk) 2095 if rep is None: 2096 print("DP '%s' already exists" % args.adddp) 2097 else: 2098 print("DP '%s' added" % args.adddp) 2099 if args.upcall: 2100 ovspk.upcall_handler(ovsflow) 2101 elif hasattr(args, "deldp"): 2102 ovsdp.destroy(args.deldp) 2103 elif hasattr(args, "addif"): 2104 rep = ovsdp.info(args.dpname, 0) 2105 if rep is None: 2106 print("DP '%s' not found." % args.dpname) 2107 return 1 2108 dpindex = rep["dpifindex"] 2109 rep = ovsvp.attach(rep["dpifindex"], args.addif, args.ptype) 2110 msg = "vport '%s'" % args.addif 2111 if rep and rep["header"]["error"] is None: 2112 msg += " added." 2113 else: 2114 msg += " failed to add." 2115 if args.upcall: 2116 if rep is None: 2117 rep = ovsvp.reset_upcall(dpindex, args.addif, ovspk) 2118 ovsvp.upcall_handler(ovsflow) 2119 elif hasattr(args, "delif"): 2120 rep = ovsdp.info(args.dpname, 0) 2121 if rep is None: 2122 print("DP '%s' not found." % args.dpname) 2123 return 1 2124 rep = ovsvp.detach(rep["dpifindex"], args.delif) 2125 msg = "vport '%s'" % args.delif 2126 if rep and rep["header"]["error"] is None: 2127 msg += " removed." 2128 else: 2129 msg += " failed to remove." 2130 elif hasattr(args, "dumpdp"): 2131 rep = ovsdp.info(args.dumpdp, 0) 2132 if rep is None: 2133 print("DP '%s' not found." % args.dumpdp) 2134 return 1 2135 rep = ovsflow.dump(rep["dpifindex"]) 2136 for flow in rep: 2137 print(flow.dpstr(True if args.verbose > 0 else False)) 2138 elif hasattr(args, "flbr"): 2139 rep = ovsdp.info(args.flbr, 0) 2140 if rep is None: 2141 print("DP '%s' not found." % args.flbr) 2142 return 1 2143 flow = OvsFlow.ovs_flow_msg() 2144 flow.parse(args.flow, args.acts, rep["dpifindex"]) 2145 ovsflow.add_flow(rep["dpifindex"], flow) 2146 2147 return 0 2148 2149 2150if __name__ == "__main__": 2151 sys.exit(main(sys.argv)) 2152