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