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", "none"), 303 ("OVS_ACTION_ATTR_CHECK_PKT_LEN", "none"), 304 ("OVS_ACTION_ATTR_ADD_MPLS", "none"), 305 ("OVS_ACTION_ATTR_DEC_TTL", "none"), 306 ("OVS_ACTION_ATTR_DROP", "uint32"), 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 print_str += datum.dpstr(more) 469 470 return print_str 471 472 def parse(self, actstr): 473 while len(actstr) != 0: 474 parsed = False 475 if actstr.startswith("drop"): 476 # If no reason is provided, the implicit drop is used (i.e no 477 # action). If some reason is given, an explicit action is used. 478 actstr, reason = parse_extract_field( 479 actstr, 480 "drop(", 481 "([0-9]+)", 482 lambda x: int(x, 0), 483 False, 484 None, 485 ) 486 if reason is not None: 487 self["attrs"].append(["OVS_ACTION_ATTR_DROP", reason]) 488 parsed = True 489 else: 490 return 491 492 elif parse_starts_block(actstr, "^(\d+)", False, True): 493 actstr, output = parse_extract_field( 494 actstr, None, "(\d+)", lambda x: int(x), False, "0" 495 ) 496 self["attrs"].append(["OVS_ACTION_ATTR_OUTPUT", output]) 497 parsed = True 498 elif parse_starts_block(actstr, "recirc(", False): 499 actstr, recircid = parse_extract_field( 500 actstr, 501 "recirc(", 502 "([0-9a-fA-Fx]+)", 503 lambda x: int(x, 0), 504 False, 505 0, 506 ) 507 self["attrs"].append(["OVS_ACTION_ATTR_RECIRC", recircid]) 508 parsed = True 509 510 parse_flat_map = ( 511 ("ct_clear", "OVS_ACTION_ATTR_CT_CLEAR"), 512 ("pop_vlan", "OVS_ACTION_ATTR_POP_VLAN"), 513 ("pop_eth", "OVS_ACTION_ATTR_POP_ETH"), 514 ("pop_nsh", "OVS_ACTION_ATTR_POP_NSH"), 515 ) 516 517 for flat_act in parse_flat_map: 518 if parse_starts_block(actstr, flat_act[0], False): 519 actstr += len(flat_act[0]) 520 self["attrs"].append([flat_act[1]]) 521 actstr = actstr[strspn(actstr, ", ") :] 522 parsed = True 523 524 if parse_starts_block(actstr, "ct(", False): 525 actstr = actstr[len("ct(") :] 526 ctact = ovsactions.ctact() 527 528 for scan in ( 529 ("commit", "OVS_CT_ATTR_COMMIT", None), 530 ("force_commit", "OVS_CT_ATTR_FORCE_COMMIT", None), 531 ("zone", "OVS_CT_ATTR_ZONE", int), 532 ("mark", "OVS_CT_ATTR_MARK", int), 533 ("helper", "OVS_CT_ATTR_HELPER", lambda x, y: str(x)), 534 ("timeout", "OVS_CT_ATTR_TIMEOUT", lambda x, y: str(x)), 535 ): 536 if actstr.startswith(scan[0]): 537 actstr = actstr[len(scan[0]) :] 538 if scan[2] is not None: 539 if actstr[0] != "=": 540 raise ValueError("Invalid ct attr") 541 actstr = actstr[1:] 542 pos = strcspn(actstr, ",)") 543 datum = scan[2](actstr[:pos], 0) 544 ctact["attrs"].append([scan[1], datum]) 545 actstr = actstr[pos:] 546 else: 547 ctact["attrs"].append([scan[1], None]) 548 actstr = actstr[strspn(actstr, ", ") :] 549 # it seems strange to put this here, but nat() is a complex 550 # sub-action and this lets it sit anywhere in the ct() action 551 if actstr.startswith("nat"): 552 actstr = actstr[3:] 553 natact = ovsactions.ctact.natattr() 554 555 if actstr.startswith("("): 556 t = None 557 actstr = actstr[1:] 558 if actstr.startswith("src"): 559 t = "OVS_NAT_ATTR_SRC" 560 actstr = actstr[3:] 561 elif actstr.startswith("dst"): 562 t = "OVS_NAT_ATTR_DST" 563 actstr = actstr[3:] 564 565 actstr, ip_block_min = parse_extract_field( 566 actstr, "=", "([0-9a-fA-F\.]+)", str, False 567 ) 568 actstr, ip_block_max = parse_extract_field( 569 actstr, "-", "([0-9a-fA-F\.]+)", str, False 570 ) 571 572 actstr, proto_min = parse_extract_field( 573 actstr, ":", "(\d+)", int, False 574 ) 575 actstr, proto_max = parse_extract_field( 576 actstr, "-", "(\d+)", int, False 577 ) 578 579 if t is not None: 580 natact["attrs"].append([t, None]) 581 582 if ip_block_min is not None: 583 natact["attrs"].append( 584 ["OVS_NAT_ATTR_IP_MIN", ip_block_min] 585 ) 586 if ip_block_max is not None: 587 natact["attrs"].append( 588 ["OVS_NAT_ATTR_IP_MAX", ip_block_max] 589 ) 590 if proto_min is not None: 591 natact["attrs"].append( 592 ["OVS_NAT_ATTR_PROTO_MIN", proto_min] 593 ) 594 if proto_max is not None: 595 natact["attrs"].append( 596 ["OVS_NAT_ATTR_PROTO_MAX", proto_max] 597 ) 598 599 for natscan in ( 600 ("persistent", "OVS_NAT_ATTR_PERSISTENT"), 601 ("hash", "OVS_NAT_ATTR_PROTO_HASH"), 602 ("random", "OVS_NAT_ATTR_PROTO_RANDOM"), 603 ): 604 if actstr.startswith(natscan[0]): 605 actstr = actstr[len(natscan[0]) :] 606 natact["attrs"].append([natscan[1], None]) 607 actstr = actstr[strspn(actstr, ", ") :] 608 609 ctact["attrs"].append(["OVS_CT_ATTR_NAT", natact]) 610 actstr = actstr[strspn(actstr, ",) ") :] 611 612 self["attrs"].append(["OVS_ACTION_ATTR_CT", ctact]) 613 parsed = True 614 615 actstr = actstr[strspn(actstr, "), ") :] 616 if not parsed: 617 raise ValueError("Action str: '%s' not supported" % actstr) 618 619 620class ovskey(nla): 621 nla_flags = NLA_F_NESTED 622 nla_map = ( 623 ("OVS_KEY_ATTR_UNSPEC", "none"), 624 ("OVS_KEY_ATTR_ENCAP", "none"), 625 ("OVS_KEY_ATTR_PRIORITY", "uint32"), 626 ("OVS_KEY_ATTR_IN_PORT", "uint32"), 627 ("OVS_KEY_ATTR_ETHERNET", "ethaddr"), 628 ("OVS_KEY_ATTR_VLAN", "uint16"), 629 ("OVS_KEY_ATTR_ETHERTYPE", "be16"), 630 ("OVS_KEY_ATTR_IPV4", "ovs_key_ipv4"), 631 ("OVS_KEY_ATTR_IPV6", "ovs_key_ipv6"), 632 ("OVS_KEY_ATTR_TCP", "ovs_key_tcp"), 633 ("OVS_KEY_ATTR_UDP", "ovs_key_udp"), 634 ("OVS_KEY_ATTR_ICMP", "ovs_key_icmp"), 635 ("OVS_KEY_ATTR_ICMPV6", "ovs_key_icmpv6"), 636 ("OVS_KEY_ATTR_ARP", "ovs_key_arp"), 637 ("OVS_KEY_ATTR_ND", "ovs_key_nd"), 638 ("OVS_KEY_ATTR_SKB_MARK", "uint32"), 639 ("OVS_KEY_ATTR_TUNNEL", "none"), 640 ("OVS_KEY_ATTR_SCTP", "ovs_key_sctp"), 641 ("OVS_KEY_ATTR_TCP_FLAGS", "be16"), 642 ("OVS_KEY_ATTR_DP_HASH", "uint32"), 643 ("OVS_KEY_ATTR_RECIRC_ID", "uint32"), 644 ("OVS_KEY_ATTR_MPLS", "array(ovs_key_mpls)"), 645 ("OVS_KEY_ATTR_CT_STATE", "uint32"), 646 ("OVS_KEY_ATTR_CT_ZONE", "uint16"), 647 ("OVS_KEY_ATTR_CT_MARK", "uint32"), 648 ("OVS_KEY_ATTR_CT_LABELS", "none"), 649 ("OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4", "ovs_key_ct_tuple_ipv4"), 650 ("OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6", "ovs_key_ct_tuple_ipv6"), 651 ("OVS_KEY_ATTR_NSH", "none"), 652 ("OVS_KEY_ATTR_PACKET_TYPE", "none"), 653 ("OVS_KEY_ATTR_ND_EXTENSIONS", "none"), 654 ("OVS_KEY_ATTR_TUNNEL_INFO", "none"), 655 ("OVS_KEY_ATTR_IPV6_EXTENSIONS", "none"), 656 ) 657 658 class ovs_key_proto(nla): 659 fields = ( 660 ("src", "!H"), 661 ("dst", "!H"), 662 ) 663 664 fields_map = ( 665 ("src", "src", "%d", lambda x: int(x) if x else 0, 666 convert_int(16)), 667 ("dst", "dst", "%d", lambda x: int(x) if x else 0, 668 convert_int(16)), 669 ) 670 671 def __init__( 672 self, 673 protostr, 674 data=None, 675 offset=None, 676 parent=None, 677 length=None, 678 init=None, 679 ): 680 self.proto_str = protostr 681 nla.__init__( 682 self, 683 data=data, 684 offset=offset, 685 parent=parent, 686 length=length, 687 init=init, 688 ) 689 690 def parse(self, flowstr, typeInst): 691 if not flowstr.startswith(self.proto_str): 692 return None, None 693 694 k = typeInst() 695 m = typeInst() 696 697 flowstr = flowstr[len(self.proto_str) :] 698 if flowstr.startswith("("): 699 flowstr = flowstr[1:] 700 701 keybits = b"" 702 maskbits = b"" 703 for f in self.fields_map: 704 if flowstr.startswith(f[1]): 705 # the following assumes that the field looks 706 # something like 'field.' where '.' is a 707 # character that we don't exactly care about. 708 flowstr = flowstr[len(f[1]) + 1 :] 709 splitchar = 0 710 for c in flowstr: 711 if c == "," or c == ")": 712 break 713 splitchar += 1 714 data = flowstr[:splitchar] 715 flowstr = flowstr[splitchar:] 716 else: 717 data = "" 718 719 if len(f) > 4: 720 k[f[0]], m[f[0]] = f[4](data) 721 else: 722 k[f[0]] = f[3](data) 723 m[f[0]] = f[3](data) 724 725 flowstr = flowstr[strspn(flowstr, ", ") :] 726 if len(flowstr) == 0: 727 return flowstr, k, m 728 729 flowstr = flowstr[strspn(flowstr, "), ") :] 730 731 return flowstr, k, m 732 733 def dpstr(self, masked=None, more=False): 734 outstr = self.proto_str + "(" 735 first = False 736 for f in self.fields_map: 737 if first: 738 outstr += "," 739 if masked is None: 740 outstr += "%s=" % f[0] 741 if isinstance(f[2], str): 742 outstr += f[2] % self[f[1]] 743 else: 744 outstr += f[2](self[f[1]]) 745 first = True 746 elif more or f[3](masked[f[1]]) != 0: 747 outstr += "%s=" % f[0] 748 if isinstance(f[2], str): 749 outstr += f[2] % self[f[1]] 750 else: 751 outstr += f[2](self[f[1]]) 752 outstr += "/" 753 if isinstance(f[2], str): 754 outstr += f[2] % masked[f[1]] 755 else: 756 outstr += f[2](masked[f[1]]) 757 first = True 758 outstr += ")" 759 return outstr 760 761 class ethaddr(ovs_key_proto): 762 fields = ( 763 ("src", "!6s"), 764 ("dst", "!6s"), 765 ) 766 767 fields_map = ( 768 ( 769 "src", 770 "src", 771 macstr, 772 lambda x: int.from_bytes(x, "big"), 773 convert_mac, 774 ), 775 ( 776 "dst", 777 "dst", 778 macstr, 779 lambda x: int.from_bytes(x, "big"), 780 convert_mac, 781 ), 782 ) 783 784 def __init__( 785 self, 786 data=None, 787 offset=None, 788 parent=None, 789 length=None, 790 init=None, 791 ): 792 ovskey.ovs_key_proto.__init__( 793 self, 794 "eth", 795 data=data, 796 offset=offset, 797 parent=parent, 798 length=length, 799 init=init, 800 ) 801 802 class ovs_key_ipv4(ovs_key_proto): 803 fields = ( 804 ("src", "!I"), 805 ("dst", "!I"), 806 ("proto", "B"), 807 ("tos", "B"), 808 ("ttl", "B"), 809 ("frag", "B"), 810 ) 811 812 fields_map = ( 813 ( 814 "src", 815 "src", 816 lambda x: str(ipaddress.IPv4Address(x)), 817 int, 818 convert_ipv4, 819 ), 820 ( 821 "dst", 822 "dst", 823 lambda x: str(ipaddress.IPv4Address(x)), 824 int, 825 convert_ipv4, 826 ), 827 ("proto", "proto", "%d", lambda x: int(x) if x else 0, 828 convert_int(8)), 829 ("tos", "tos", "%d", lambda x: int(x) if x else 0, 830 convert_int(8)), 831 ("ttl", "ttl", "%d", lambda x: int(x) if x else 0, 832 convert_int(8)), 833 ("frag", "frag", "%d", lambda x: int(x) if x else 0, 834 convert_int(8)), 835 ) 836 837 def __init__( 838 self, 839 data=None, 840 offset=None, 841 parent=None, 842 length=None, 843 init=None, 844 ): 845 ovskey.ovs_key_proto.__init__( 846 self, 847 "ipv4", 848 data=data, 849 offset=offset, 850 parent=parent, 851 length=length, 852 init=init, 853 ) 854 855 class ovs_key_ipv6(ovs_key_proto): 856 fields = ( 857 ("src", "!16s"), 858 ("dst", "!16s"), 859 ("label", "!I"), 860 ("proto", "B"), 861 ("tclass", "B"), 862 ("hlimit", "B"), 863 ("frag", "B"), 864 ) 865 866 fields_map = ( 867 ( 868 "src", 869 "src", 870 lambda x: str(ipaddress.IPv6Address(x)), 871 lambda x: int.from_bytes(x, "big"), 872 lambda x: ipaddress.IPv6Address(x), 873 ), 874 ( 875 "dst", 876 "dst", 877 lambda x: str(ipaddress.IPv6Address(x)), 878 lambda x: int.from_bytes(x, "big"), 879 lambda x: ipaddress.IPv6Address(x), 880 ), 881 ("label", "label", "%d", int), 882 ("proto", "proto", "%d", int), 883 ("tclass", "tclass", "%d", int), 884 ("hlimit", "hlimit", "%d", int), 885 ("frag", "frag", "%d", int), 886 ) 887 888 def __init__( 889 self, 890 data=None, 891 offset=None, 892 parent=None, 893 length=None, 894 init=None, 895 ): 896 ovskey.ovs_key_proto.__init__( 897 self, 898 "ipv6", 899 data=data, 900 offset=offset, 901 parent=parent, 902 length=length, 903 init=init, 904 ) 905 906 class ovs_key_tcp(ovs_key_proto): 907 def __init__( 908 self, 909 data=None, 910 offset=None, 911 parent=None, 912 length=None, 913 init=None, 914 ): 915 ovskey.ovs_key_proto.__init__( 916 self, 917 "tcp", 918 data=data, 919 offset=offset, 920 parent=parent, 921 length=length, 922 init=init, 923 ) 924 925 class ovs_key_udp(ovs_key_proto): 926 def __init__( 927 self, 928 data=None, 929 offset=None, 930 parent=None, 931 length=None, 932 init=None, 933 ): 934 ovskey.ovs_key_proto.__init__( 935 self, 936 "udp", 937 data=data, 938 offset=offset, 939 parent=parent, 940 length=length, 941 init=init, 942 ) 943 944 class ovs_key_sctp(ovs_key_proto): 945 def __init__( 946 self, 947 data=None, 948 offset=None, 949 parent=None, 950 length=None, 951 init=None, 952 ): 953 ovskey.ovs_key_proto.__init__( 954 self, 955 "sctp", 956 data=data, 957 offset=offset, 958 parent=parent, 959 length=length, 960 init=init, 961 ) 962 963 class ovs_key_icmp(ovs_key_proto): 964 fields = ( 965 ("type", "B"), 966 ("code", "B"), 967 ) 968 969 fields_map = ( 970 ("type", "type", "%d", lambda x: int(x) if x else 0), 971 ("code", "code", "%d", lambda x: int(x) if x else 0), 972 ) 973 974 def __init__( 975 self, 976 data=None, 977 offset=None, 978 parent=None, 979 length=None, 980 init=None, 981 ): 982 ovskey.ovs_key_proto.__init__( 983 self, 984 "icmp", 985 data=data, 986 offset=offset, 987 parent=parent, 988 length=length, 989 init=init, 990 ) 991 992 class ovs_key_icmpv6(ovs_key_icmp): 993 def __init__( 994 self, 995 data=None, 996 offset=None, 997 parent=None, 998 length=None, 999 init=None, 1000 ): 1001 ovskey.ovs_key_proto.__init__( 1002 self, 1003 "icmpv6", 1004 data=data, 1005 offset=offset, 1006 parent=parent, 1007 length=length, 1008 init=init, 1009 ) 1010 1011 class ovs_key_arp(ovs_key_proto): 1012 fields = ( 1013 ("sip", "!I"), 1014 ("tip", "!I"), 1015 ("op", "!H"), 1016 ("sha", "!6s"), 1017 ("tha", "!6s"), 1018 ("pad", "xx"), 1019 ) 1020 1021 fields_map = ( 1022 ( 1023 "sip", 1024 "sip", 1025 lambda x: str(ipaddress.IPv4Address(x)), 1026 int, 1027 convert_ipv4, 1028 ), 1029 ( 1030 "tip", 1031 "tip", 1032 lambda x: str(ipaddress.IPv4Address(x)), 1033 int, 1034 convert_ipv4, 1035 ), 1036 ("op", "op", "%d", lambda x: int(x) if x else 0), 1037 ( 1038 "sha", 1039 "sha", 1040 macstr, 1041 lambda x: int.from_bytes(x, "big"), 1042 convert_mac, 1043 ), 1044 ( 1045 "tha", 1046 "tha", 1047 macstr, 1048 lambda x: int.from_bytes(x, "big"), 1049 convert_mac, 1050 ), 1051 ) 1052 1053 def __init__( 1054 self, 1055 data=None, 1056 offset=None, 1057 parent=None, 1058 length=None, 1059 init=None, 1060 ): 1061 ovskey.ovs_key_proto.__init__( 1062 self, 1063 "arp", 1064 data=data, 1065 offset=offset, 1066 parent=parent, 1067 length=length, 1068 init=init, 1069 ) 1070 1071 class ovs_key_nd(ovs_key_proto): 1072 fields = ( 1073 ("target", "!16s"), 1074 ("sll", "!6s"), 1075 ("tll", "!6s"), 1076 ) 1077 1078 fields_map = ( 1079 ( 1080 "target", 1081 "target", 1082 lambda x: str(ipaddress.IPv6Address(x)), 1083 lambda x: int.from_bytes(x, "big"), 1084 ), 1085 ("sll", "sll", macstr, lambda x: int.from_bytes(x, "big")), 1086 ("tll", "tll", macstr, lambda x: int.from_bytes(x, "big")), 1087 ) 1088 1089 def __init__( 1090 self, 1091 data=None, 1092 offset=None, 1093 parent=None, 1094 length=None, 1095 init=None, 1096 ): 1097 ovskey.ovs_key_proto.__init__( 1098 self, 1099 "nd", 1100 data=data, 1101 offset=offset, 1102 parent=parent, 1103 length=length, 1104 init=init, 1105 ) 1106 1107 class ovs_key_ct_tuple_ipv4(ovs_key_proto): 1108 fields = ( 1109 ("src", "!I"), 1110 ("dst", "!I"), 1111 ("tp_src", "!H"), 1112 ("tp_dst", "!H"), 1113 ("proto", "B"), 1114 ) 1115 1116 fields_map = ( 1117 ( 1118 "src", 1119 "src", 1120 lambda x: str(ipaddress.IPv4Address(x)), 1121 int, 1122 convert_ipv4, 1123 ), 1124 ( 1125 "dst", 1126 "dst", 1127 lambda x: str(ipaddress.IPv4Address(x)), 1128 int, 1129 convert_ipv4, 1130 ), 1131 ("tp_src", "tp_src", "%d", int), 1132 ("tp_dst", "tp_dst", "%d", int), 1133 ("proto", "proto", "%d", int), 1134 ) 1135 1136 def __init__( 1137 self, 1138 data=None, 1139 offset=None, 1140 parent=None, 1141 length=None, 1142 init=None, 1143 ): 1144 ovskey.ovs_key_proto.__init__( 1145 self, 1146 "ct_tuple4", 1147 data=data, 1148 offset=offset, 1149 parent=parent, 1150 length=length, 1151 init=init, 1152 ) 1153 1154 class ovs_key_ct_tuple_ipv6(nla): 1155 fields = ( 1156 ("src", "!16s"), 1157 ("dst", "!16s"), 1158 ("tp_src", "!H"), 1159 ("tp_dst", "!H"), 1160 ("proto", "B"), 1161 ) 1162 1163 fields_map = ( 1164 ( 1165 "src", 1166 "src", 1167 lambda x: str(ipaddress.IPv6Address(x)), 1168 lambda x: int.from_bytes(x, "big", convertmac), 1169 ), 1170 ( 1171 "dst", 1172 "dst", 1173 lambda x: str(ipaddress.IPv6Address(x)), 1174 lambda x: int.from_bytes(x, "big"), 1175 ), 1176 ("tp_src", "tp_src", "%d", int), 1177 ("tp_dst", "tp_dst", "%d", int), 1178 ("proto", "proto", "%d", int), 1179 ) 1180 1181 def __init__( 1182 self, 1183 data=None, 1184 offset=None, 1185 parent=None, 1186 length=None, 1187 init=None, 1188 ): 1189 ovskey.ovs_key_proto.__init__( 1190 self, 1191 "ct_tuple6", 1192 data=data, 1193 offset=offset, 1194 parent=parent, 1195 length=length, 1196 init=init, 1197 ) 1198 1199 class ovs_key_mpls(nla): 1200 fields = (("lse", ">I"),) 1201 1202 def parse(self, flowstr, mask=None): 1203 for field in ( 1204 ("OVS_KEY_ATTR_PRIORITY", "skb_priority", intparse), 1205 ("OVS_KEY_ATTR_SKB_MARK", "skb_mark", intparse), 1206 ("OVS_KEY_ATTR_RECIRC_ID", "recirc_id", intparse), 1207 ("OVS_KEY_ATTR_DP_HASH", "dp_hash", intparse), 1208 ("OVS_KEY_ATTR_CT_STATE", "ct_state", parse_ct_state), 1209 ("OVS_KEY_ATTR_CT_ZONE", "ct_zone", intparse), 1210 ("OVS_KEY_ATTR_CT_MARK", "ct_mark", intparse), 1211 ("OVS_KEY_ATTR_IN_PORT", "in_port", intparse), 1212 ( 1213 "OVS_KEY_ATTR_ETHERNET", 1214 "eth", 1215 ovskey.ethaddr, 1216 ), 1217 ( 1218 "OVS_KEY_ATTR_ETHERTYPE", 1219 "eth_type", 1220 lambda x: intparse(x, "0xffff"), 1221 ), 1222 ( 1223 "OVS_KEY_ATTR_IPV4", 1224 "ipv4", 1225 ovskey.ovs_key_ipv4, 1226 ), 1227 ( 1228 "OVS_KEY_ATTR_IPV6", 1229 "ipv6", 1230 ovskey.ovs_key_ipv6, 1231 ), 1232 ( 1233 "OVS_KEY_ATTR_ARP", 1234 "arp", 1235 ovskey.ovs_key_arp, 1236 ), 1237 ( 1238 "OVS_KEY_ATTR_TCP", 1239 "tcp", 1240 ovskey.ovs_key_tcp, 1241 ), 1242 ( 1243 "OVS_KEY_ATTR_UDP", 1244 "udp", 1245 ovskey.ovs_key_udp, 1246 ), 1247 ( 1248 "OVS_KEY_ATTR_ICMP", 1249 "icmp", 1250 ovskey.ovs_key_icmp, 1251 ), 1252 ( 1253 "OVS_KEY_ATTR_TCP_FLAGS", 1254 "tcp_flags", 1255 lambda x: parse_flags(x, None), 1256 ), 1257 ): 1258 fld = field[1] + "(" 1259 if not flowstr.startswith(fld): 1260 continue 1261 1262 if not isinstance(field[2], types.FunctionType): 1263 nk = field[2]() 1264 flowstr, k, m = nk.parse(flowstr, field[2]) 1265 else: 1266 flowstr = flowstr[len(fld) :] 1267 flowstr, k, m = field[2](flowstr) 1268 1269 if m and mask is not None: 1270 mask["attrs"].append([field[0], m]) 1271 self["attrs"].append([field[0], k]) 1272 1273 flowstr = flowstr[strspn(flowstr, "),") :] 1274 1275 return flowstr 1276 1277 def dpstr(self, mask=None, more=False): 1278 print_str = "" 1279 1280 for field in ( 1281 ( 1282 "OVS_KEY_ATTR_PRIORITY", 1283 "skb_priority", 1284 "%d", 1285 lambda x: False, 1286 True, 1287 ), 1288 ( 1289 "OVS_KEY_ATTR_SKB_MARK", 1290 "skb_mark", 1291 "%d", 1292 lambda x: False, 1293 True, 1294 ), 1295 ( 1296 "OVS_KEY_ATTR_RECIRC_ID", 1297 "recirc_id", 1298 "0x%08X", 1299 lambda x: False, 1300 True, 1301 ), 1302 ( 1303 "OVS_KEY_ATTR_DP_HASH", 1304 "dp_hash", 1305 "0x%08X", 1306 lambda x: False, 1307 True, 1308 ), 1309 ( 1310 "OVS_KEY_ATTR_CT_STATE", 1311 "ct_state", 1312 "0x%04x", 1313 lambda x: False, 1314 True, 1315 ), 1316 ( 1317 "OVS_KEY_ATTR_CT_ZONE", 1318 "ct_zone", 1319 "0x%04x", 1320 lambda x: False, 1321 True, 1322 ), 1323 ( 1324 "OVS_KEY_ATTR_CT_MARK", 1325 "ct_mark", 1326 "0x%08x", 1327 lambda x: False, 1328 True, 1329 ), 1330 ( 1331 "OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4", 1332 None, 1333 None, 1334 False, 1335 False, 1336 ), 1337 ( 1338 "OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6", 1339 None, 1340 None, 1341 False, 1342 False, 1343 ), 1344 ( 1345 "OVS_KEY_ATTR_IN_PORT", 1346 "in_port", 1347 "%d", 1348 lambda x: True, 1349 True, 1350 ), 1351 ("OVS_KEY_ATTR_ETHERNET", None, None, False, False), 1352 ( 1353 "OVS_KEY_ATTR_ETHERTYPE", 1354 "eth_type", 1355 "0x%04x", 1356 lambda x: int(x) == 0xFFFF, 1357 True, 1358 ), 1359 ("OVS_KEY_ATTR_IPV4", None, None, False, False), 1360 ("OVS_KEY_ATTR_IPV6", None, None, False, False), 1361 ("OVS_KEY_ATTR_ARP", None, None, False, False), 1362 ("OVS_KEY_ATTR_TCP", None, None, False, False), 1363 ( 1364 "OVS_KEY_ATTR_TCP_FLAGS", 1365 "tcp_flags", 1366 "0x%04x", 1367 lambda x: False, 1368 True, 1369 ), 1370 ("OVS_KEY_ATTR_UDP", None, None, False, False), 1371 ("OVS_KEY_ATTR_SCTP", None, None, False, False), 1372 ("OVS_KEY_ATTR_ICMP", None, None, False, False), 1373 ("OVS_KEY_ATTR_ICMPV6", None, None, False, False), 1374 ("OVS_KEY_ATTR_ND", None, None, False, False), 1375 ): 1376 v = self.get_attr(field[0]) 1377 if v is not None: 1378 m = None if mask is None else mask.get_attr(field[0]) 1379 if field[4] is False: 1380 print_str += v.dpstr(m, more) 1381 print_str += "," 1382 else: 1383 if m is None or field[3](m): 1384 print_str += field[1] + "(" 1385 print_str += field[2] % v 1386 print_str += ")," 1387 elif more or m != 0: 1388 print_str += field[1] + "(" 1389 print_str += (field[2] % v) + "/" + (field[2] % m) 1390 print_str += ")," 1391 1392 return print_str 1393 1394 1395class OvsPacket(GenericNetlinkSocket): 1396 OVS_PACKET_CMD_MISS = 1 # Flow table miss 1397 OVS_PACKET_CMD_ACTION = 2 # USERSPACE action 1398 OVS_PACKET_CMD_EXECUTE = 3 # Apply actions to packet 1399 1400 class ovs_packet_msg(ovs_dp_msg): 1401 nla_map = ( 1402 ("OVS_PACKET_ATTR_UNSPEC", "none"), 1403 ("OVS_PACKET_ATTR_PACKET", "array(uint8)"), 1404 ("OVS_PACKET_ATTR_KEY", "ovskey"), 1405 ("OVS_PACKET_ATTR_ACTIONS", "ovsactions"), 1406 ("OVS_PACKET_ATTR_USERDATA", "none"), 1407 ("OVS_PACKET_ATTR_EGRESS_TUN_KEY", "none"), 1408 ("OVS_PACKET_ATTR_UNUSED1", "none"), 1409 ("OVS_PACKET_ATTR_UNUSED2", "none"), 1410 ("OVS_PACKET_ATTR_PROBE", "none"), 1411 ("OVS_PACKET_ATTR_MRU", "uint16"), 1412 ("OVS_PACKET_ATTR_LEN", "uint32"), 1413 ("OVS_PACKET_ATTR_HASH", "uint64"), 1414 ) 1415 1416 def __init__(self): 1417 GenericNetlinkSocket.__init__(self) 1418 self.bind(OVS_PACKET_FAMILY, OvsPacket.ovs_packet_msg) 1419 1420 def upcall_handler(self, up=None): 1421 print("listening on upcall packet handler:", self.epid) 1422 while True: 1423 try: 1424 msgs = self.get() 1425 for msg in msgs: 1426 if not up: 1427 continue 1428 if msg["cmd"] == OvsPacket.OVS_PACKET_CMD_MISS: 1429 up.miss(msg) 1430 elif msg["cmd"] == OvsPacket.OVS_PACKET_CMD_ACTION: 1431 up.action(msg) 1432 elif msg["cmd"] == OvsPacket.OVS_PACKET_CMD_EXECUTE: 1433 up.execute(msg) 1434 else: 1435 print("Unkonwn cmd: %d" % msg["cmd"]) 1436 except NetlinkError as ne: 1437 raise ne 1438 1439 1440class OvsDatapath(GenericNetlinkSocket): 1441 OVS_DP_F_VPORT_PIDS = 1 << 1 1442 OVS_DP_F_DISPATCH_UPCALL_PER_CPU = 1 << 3 1443 1444 class dp_cmd_msg(ovs_dp_msg): 1445 """ 1446 Message class that will be used to communicate with the kernel module. 1447 """ 1448 1449 nla_map = ( 1450 ("OVS_DP_ATTR_UNSPEC", "none"), 1451 ("OVS_DP_ATTR_NAME", "asciiz"), 1452 ("OVS_DP_ATTR_UPCALL_PID", "array(uint32)"), 1453 ("OVS_DP_ATTR_STATS", "dpstats"), 1454 ("OVS_DP_ATTR_MEGAFLOW_STATS", "megaflowstats"), 1455 ("OVS_DP_ATTR_USER_FEATURES", "uint32"), 1456 ("OVS_DP_ATTR_PAD", "none"), 1457 ("OVS_DP_ATTR_MASKS_CACHE_SIZE", "uint32"), 1458 ("OVS_DP_ATTR_PER_CPU_PIDS", "array(uint32)"), 1459 ) 1460 1461 class dpstats(nla): 1462 fields = ( 1463 ("hit", "=Q"), 1464 ("missed", "=Q"), 1465 ("lost", "=Q"), 1466 ("flows", "=Q"), 1467 ) 1468 1469 class megaflowstats(nla): 1470 fields = ( 1471 ("mask_hit", "=Q"), 1472 ("masks", "=I"), 1473 ("padding", "=I"), 1474 ("cache_hits", "=Q"), 1475 ("pad1", "=Q"), 1476 ) 1477 1478 def __init__(self): 1479 GenericNetlinkSocket.__init__(self) 1480 self.bind(OVS_DATAPATH_FAMILY, OvsDatapath.dp_cmd_msg) 1481 1482 def info(self, dpname, ifindex=0): 1483 msg = OvsDatapath.dp_cmd_msg() 1484 msg["cmd"] = OVS_DP_CMD_GET 1485 msg["version"] = OVS_DATAPATH_VERSION 1486 msg["reserved"] = 0 1487 msg["dpifindex"] = ifindex 1488 msg["attrs"].append(["OVS_DP_ATTR_NAME", dpname]) 1489 1490 try: 1491 reply = self.nlm_request( 1492 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST 1493 ) 1494 reply = reply[0] 1495 except NetlinkError as ne: 1496 if ne.code == errno.ENODEV: 1497 reply = None 1498 else: 1499 raise ne 1500 1501 return reply 1502 1503 def create( 1504 self, dpname, shouldUpcall=False, versionStr=None, p=OvsPacket() 1505 ): 1506 msg = OvsDatapath.dp_cmd_msg() 1507 msg["cmd"] = OVS_DP_CMD_NEW 1508 if versionStr is None: 1509 msg["version"] = OVS_DATAPATH_VERSION 1510 else: 1511 msg["version"] = int(versionStr.split(":")[0], 0) 1512 msg["reserved"] = 0 1513 msg["dpifindex"] = 0 1514 msg["attrs"].append(["OVS_DP_ATTR_NAME", dpname]) 1515 1516 dpfeatures = 0 1517 if versionStr is not None and versionStr.find(":") != -1: 1518 dpfeatures = int(versionStr.split(":")[1], 0) 1519 else: 1520 if versionStr is None or versionStr.find(":") == -1: 1521 dpfeatures |= OvsDatapath.OVS_DP_F_DISPATCH_UPCALL_PER_CPU 1522 dpfeatures &= ~OvsDatapath.OVS_DP_F_VPORT_PIDS 1523 1524 nproc = multiprocessing.cpu_count() 1525 procarray = [] 1526 for i in range(1, nproc): 1527 procarray += [int(p.epid)] 1528 msg["attrs"].append(["OVS_DP_ATTR_UPCALL_PID", procarray]) 1529 msg["attrs"].append(["OVS_DP_ATTR_USER_FEATURES", dpfeatures]) 1530 if not shouldUpcall: 1531 msg["attrs"].append(["OVS_DP_ATTR_UPCALL_PID", [0]]) 1532 1533 try: 1534 reply = self.nlm_request( 1535 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK 1536 ) 1537 reply = reply[0] 1538 except NetlinkError as ne: 1539 if ne.code == errno.EEXIST: 1540 reply = None 1541 else: 1542 raise ne 1543 1544 return reply 1545 1546 def destroy(self, dpname): 1547 msg = OvsDatapath.dp_cmd_msg() 1548 msg["cmd"] = OVS_DP_CMD_DEL 1549 msg["version"] = OVS_DATAPATH_VERSION 1550 msg["reserved"] = 0 1551 msg["dpifindex"] = 0 1552 msg["attrs"].append(["OVS_DP_ATTR_NAME", dpname]) 1553 1554 try: 1555 reply = self.nlm_request( 1556 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK 1557 ) 1558 reply = reply[0] 1559 except NetlinkError as ne: 1560 if ne.code == errno.ENODEV: 1561 reply = None 1562 else: 1563 raise ne 1564 1565 return reply 1566 1567 1568class OvsVport(GenericNetlinkSocket): 1569 OVS_VPORT_TYPE_NETDEV = 1 1570 OVS_VPORT_TYPE_INTERNAL = 2 1571 OVS_VPORT_TYPE_GRE = 3 1572 OVS_VPORT_TYPE_VXLAN = 4 1573 OVS_VPORT_TYPE_GENEVE = 5 1574 1575 class ovs_vport_msg(ovs_dp_msg): 1576 nla_map = ( 1577 ("OVS_VPORT_ATTR_UNSPEC", "none"), 1578 ("OVS_VPORT_ATTR_PORT_NO", "uint32"), 1579 ("OVS_VPORT_ATTR_TYPE", "uint32"), 1580 ("OVS_VPORT_ATTR_NAME", "asciiz"), 1581 ("OVS_VPORT_ATTR_OPTIONS", "none"), 1582 ("OVS_VPORT_ATTR_UPCALL_PID", "array(uint32)"), 1583 ("OVS_VPORT_ATTR_STATS", "vportstats"), 1584 ("OVS_VPORT_ATTR_PAD", "none"), 1585 ("OVS_VPORT_ATTR_IFINDEX", "uint32"), 1586 ("OVS_VPORT_ATTR_NETNSID", "uint32"), 1587 ) 1588 1589 class vportstats(nla): 1590 fields = ( 1591 ("rx_packets", "=Q"), 1592 ("tx_packets", "=Q"), 1593 ("rx_bytes", "=Q"), 1594 ("tx_bytes", "=Q"), 1595 ("rx_errors", "=Q"), 1596 ("tx_errors", "=Q"), 1597 ("rx_dropped", "=Q"), 1598 ("tx_dropped", "=Q"), 1599 ) 1600 1601 def type_to_str(vport_type): 1602 if vport_type == OvsVport.OVS_VPORT_TYPE_NETDEV: 1603 return "netdev" 1604 elif vport_type == OvsVport.OVS_VPORT_TYPE_INTERNAL: 1605 return "internal" 1606 elif vport_type == OvsVport.OVS_VPORT_TYPE_GRE: 1607 return "gre" 1608 elif vport_type == OvsVport.OVS_VPORT_TYPE_VXLAN: 1609 return "vxlan" 1610 elif vport_type == OvsVport.OVS_VPORT_TYPE_GENEVE: 1611 return "geneve" 1612 raise ValueError("Unknown vport type:%d" % vport_type) 1613 1614 def str_to_type(vport_type): 1615 if vport_type == "netdev": 1616 return OvsVport.OVS_VPORT_TYPE_NETDEV 1617 elif vport_type == "internal": 1618 return OvsVport.OVS_VPORT_TYPE_INTERNAL 1619 elif vport_type == "gre": 1620 return OvsVport.OVS_VPORT_TYPE_INTERNAL 1621 elif vport_type == "vxlan": 1622 return OvsVport.OVS_VPORT_TYPE_VXLAN 1623 elif vport_type == "geneve": 1624 return OvsVport.OVS_VPORT_TYPE_GENEVE 1625 raise ValueError("Unknown vport type: '%s'" % vport_type) 1626 1627 def __init__(self, packet=OvsPacket()): 1628 GenericNetlinkSocket.__init__(self) 1629 self.bind(OVS_VPORT_FAMILY, OvsVport.ovs_vport_msg) 1630 self.upcall_packet = packet 1631 1632 def info(self, vport_name, dpifindex=0, portno=None): 1633 msg = OvsVport.ovs_vport_msg() 1634 1635 msg["cmd"] = OVS_VPORT_CMD_GET 1636 msg["version"] = OVS_DATAPATH_VERSION 1637 msg["reserved"] = 0 1638 msg["dpifindex"] = dpifindex 1639 1640 if portno is None: 1641 msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_name]) 1642 else: 1643 msg["attrs"].append(["OVS_VPORT_ATTR_PORT_NO", portno]) 1644 1645 try: 1646 reply = self.nlm_request( 1647 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST 1648 ) 1649 reply = reply[0] 1650 except NetlinkError as ne: 1651 if ne.code == errno.ENODEV: 1652 reply = None 1653 else: 1654 raise ne 1655 return reply 1656 1657 def attach(self, dpindex, vport_ifname, ptype): 1658 msg = OvsVport.ovs_vport_msg() 1659 1660 msg["cmd"] = OVS_VPORT_CMD_NEW 1661 msg["version"] = OVS_DATAPATH_VERSION 1662 msg["reserved"] = 0 1663 msg["dpifindex"] = dpindex 1664 port_type = OvsVport.str_to_type(ptype) 1665 1666 msg["attrs"].append(["OVS_VPORT_ATTR_TYPE", port_type]) 1667 msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_ifname]) 1668 msg["attrs"].append( 1669 ["OVS_VPORT_ATTR_UPCALL_PID", [self.upcall_packet.epid]] 1670 ) 1671 1672 try: 1673 reply = self.nlm_request( 1674 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK 1675 ) 1676 reply = reply[0] 1677 except NetlinkError as ne: 1678 if ne.code == errno.EEXIST: 1679 reply = None 1680 else: 1681 raise ne 1682 return reply 1683 1684 def reset_upcall(self, dpindex, vport_ifname, p=None): 1685 msg = OvsVport.ovs_vport_msg() 1686 1687 msg["cmd"] = OVS_VPORT_CMD_SET 1688 msg["version"] = OVS_DATAPATH_VERSION 1689 msg["reserved"] = 0 1690 msg["dpifindex"] = dpindex 1691 msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_ifname]) 1692 1693 if p == None: 1694 p = self.upcall_packet 1695 else: 1696 self.upcall_packet = p 1697 1698 msg["attrs"].append(["OVS_VPORT_ATTR_UPCALL_PID", [p.epid]]) 1699 1700 try: 1701 reply = self.nlm_request( 1702 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK 1703 ) 1704 reply = reply[0] 1705 except NetlinkError as ne: 1706 raise ne 1707 return reply 1708 1709 def detach(self, dpindex, vport_ifname): 1710 msg = OvsVport.ovs_vport_msg() 1711 1712 msg["cmd"] = OVS_VPORT_CMD_DEL 1713 msg["version"] = OVS_DATAPATH_VERSION 1714 msg["reserved"] = 0 1715 msg["dpifindex"] = dpindex 1716 msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_ifname]) 1717 1718 try: 1719 reply = self.nlm_request( 1720 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK 1721 ) 1722 reply = reply[0] 1723 except NetlinkError as ne: 1724 if ne.code == errno.ENODEV: 1725 reply = None 1726 else: 1727 raise ne 1728 return reply 1729 1730 def upcall_handler(self, handler=None): 1731 self.upcall_packet.upcall_handler(handler) 1732 1733 1734class OvsFlow(GenericNetlinkSocket): 1735 class ovs_flow_msg(ovs_dp_msg): 1736 nla_map = ( 1737 ("OVS_FLOW_ATTR_UNSPEC", "none"), 1738 ("OVS_FLOW_ATTR_KEY", "ovskey"), 1739 ("OVS_FLOW_ATTR_ACTIONS", "ovsactions"), 1740 ("OVS_FLOW_ATTR_STATS", "flowstats"), 1741 ("OVS_FLOW_ATTR_TCP_FLAGS", "uint8"), 1742 ("OVS_FLOW_ATTR_USED", "uint64"), 1743 ("OVS_FLOW_ATTR_CLEAR", "none"), 1744 ("OVS_FLOW_ATTR_MASK", "ovskey"), 1745 ("OVS_FLOW_ATTR_PROBE", "none"), 1746 ("OVS_FLOW_ATTR_UFID", "array(uint32)"), 1747 ("OVS_FLOW_ATTR_UFID_FLAGS", "uint32"), 1748 ) 1749 1750 class flowstats(nla): 1751 fields = ( 1752 ("packets", "=Q"), 1753 ("bytes", "=Q"), 1754 ) 1755 1756 def dpstr(self, more=False): 1757 ufid = self.get_attr("OVS_FLOW_ATTR_UFID") 1758 ufid_str = "" 1759 if ufid is not None: 1760 ufid_str = ( 1761 "ufid:{:08x}-{:04x}-{:04x}-{:04x}-{:04x}{:08x}".format( 1762 ufid[0], 1763 ufid[1] >> 16, 1764 ufid[1] & 0xFFFF, 1765 ufid[2] >> 16, 1766 ufid[2] & 0, 1767 ufid[3], 1768 ) 1769 ) 1770 1771 key_field = self.get_attr("OVS_FLOW_ATTR_KEY") 1772 keymsg = None 1773 if key_field is not None: 1774 keymsg = key_field 1775 1776 mask_field = self.get_attr("OVS_FLOW_ATTR_MASK") 1777 maskmsg = None 1778 if mask_field is not None: 1779 maskmsg = mask_field 1780 1781 acts_field = self.get_attr("OVS_FLOW_ATTR_ACTIONS") 1782 actsmsg = None 1783 if acts_field is not None: 1784 actsmsg = acts_field 1785 1786 print_str = "" 1787 1788 if more: 1789 print_str += ufid_str + "," 1790 1791 if keymsg is not None: 1792 print_str += keymsg.dpstr(maskmsg, more) 1793 1794 stats = self.get_attr("OVS_FLOW_ATTR_STATS") 1795 if stats is None: 1796 print_str += " packets:0, bytes:0," 1797 else: 1798 print_str += " packets:%d, bytes:%d," % ( 1799 stats["packets"], 1800 stats["bytes"], 1801 ) 1802 1803 used = self.get_attr("OVS_FLOW_ATTR_USED") 1804 print_str += " used:" 1805 if used is None: 1806 print_str += "never," 1807 else: 1808 used_time = int(used) 1809 cur_time_sec = time.clock_gettime(time.CLOCK_MONOTONIC) 1810 used_time = (cur_time_sec * 1000) - used_time 1811 print_str += "{}s,".format(used_time / 1000) 1812 1813 print_str += " actions:" 1814 if ( 1815 actsmsg is None 1816 or "attrs" not in actsmsg 1817 or len(actsmsg["attrs"]) == 0 1818 ): 1819 print_str += "drop" 1820 else: 1821 print_str += actsmsg.dpstr(more) 1822 1823 return print_str 1824 1825 def parse(self, flowstr, actstr, dpidx=0): 1826 OVS_UFID_F_OMIT_KEY = 1 << 0 1827 OVS_UFID_F_OMIT_MASK = 1 << 1 1828 OVS_UFID_F_OMIT_ACTIONS = 1 << 2 1829 1830 self["cmd"] = 0 1831 self["version"] = 0 1832 self["reserved"] = 0 1833 self["dpifindex"] = 0 1834 1835 if flowstr.startswith("ufid:"): 1836 count = 5 1837 while flowstr[count] != ",": 1838 count += 1 1839 ufidstr = flowstr[5:count] 1840 flowstr = flowstr[count + 1 :] 1841 else: 1842 ufidstr = str(uuid.uuid4()) 1843 uuidRawObj = uuid.UUID(ufidstr).fields 1844 1845 self["attrs"].append( 1846 [ 1847 "OVS_FLOW_ATTR_UFID", 1848 [ 1849 uuidRawObj[0], 1850 uuidRawObj[1] << 16 | uuidRawObj[2], 1851 uuidRawObj[3] << 24 1852 | uuidRawObj[4] << 16 1853 | uuidRawObj[5] & (0xFF << 32) >> 32, 1854 uuidRawObj[5] & (0xFFFFFFFF), 1855 ], 1856 ] 1857 ) 1858 self["attrs"].append( 1859 [ 1860 "OVS_FLOW_ATTR_UFID_FLAGS", 1861 int( 1862 OVS_UFID_F_OMIT_KEY 1863 | OVS_UFID_F_OMIT_MASK 1864 | OVS_UFID_F_OMIT_ACTIONS 1865 ), 1866 ] 1867 ) 1868 1869 k = ovskey() 1870 m = ovskey() 1871 k.parse(flowstr, m) 1872 self["attrs"].append(["OVS_FLOW_ATTR_KEY", k]) 1873 self["attrs"].append(["OVS_FLOW_ATTR_MASK", m]) 1874 1875 a = ovsactions() 1876 a.parse(actstr) 1877 self["attrs"].append(["OVS_FLOW_ATTR_ACTIONS", a]) 1878 1879 def __init__(self): 1880 GenericNetlinkSocket.__init__(self) 1881 1882 self.bind(OVS_FLOW_FAMILY, OvsFlow.ovs_flow_msg) 1883 1884 def add_flow(self, dpifindex, flowmsg): 1885 """ 1886 Send a new flow message to the kernel. 1887 1888 dpifindex should be a valid datapath obtained by calling 1889 into the OvsDatapath lookup 1890 1891 flowmsg is a flow object obtained by calling a dpparse 1892 """ 1893 1894 flowmsg["cmd"] = OVS_FLOW_CMD_NEW 1895 flowmsg["version"] = OVS_DATAPATH_VERSION 1896 flowmsg["reserved"] = 0 1897 flowmsg["dpifindex"] = dpifindex 1898 1899 try: 1900 reply = self.nlm_request( 1901 flowmsg, 1902 msg_type=self.prid, 1903 msg_flags=NLM_F_REQUEST | NLM_F_ACK, 1904 ) 1905 reply = reply[0] 1906 except NetlinkError as ne: 1907 print(flowmsg) 1908 raise ne 1909 return reply 1910 1911 def del_flows(self, dpifindex): 1912 """ 1913 Send a del message to the kernel that will drop all flows. 1914 1915 dpifindex should be a valid datapath obtained by calling 1916 into the OvsDatapath lookup 1917 """ 1918 1919 flowmsg = OvsFlow.ovs_flow_msg() 1920 flowmsg["cmd"] = OVS_FLOW_CMD_DEL 1921 flowmsg["version"] = OVS_DATAPATH_VERSION 1922 flowmsg["reserved"] = 0 1923 flowmsg["dpifindex"] = dpifindex 1924 1925 try: 1926 reply = self.nlm_request( 1927 flowmsg, 1928 msg_type=self.prid, 1929 msg_flags=NLM_F_REQUEST | NLM_F_ACK, 1930 ) 1931 reply = reply[0] 1932 except NetlinkError as ne: 1933 print(flowmsg) 1934 raise ne 1935 return reply 1936 1937 def dump(self, dpifindex, flowspec=None): 1938 """ 1939 Returns a list of messages containing flows. 1940 1941 dpifindex should be a valid datapath obtained by calling 1942 into the OvsDatapath lookup 1943 1944 flowpsec is a string which represents a flow in the dpctl 1945 format. 1946 """ 1947 msg = OvsFlow.ovs_flow_msg() 1948 1949 msg["cmd"] = OVS_FLOW_CMD_GET 1950 msg["version"] = OVS_DATAPATH_VERSION 1951 msg["reserved"] = 0 1952 msg["dpifindex"] = dpifindex 1953 1954 msg_flags = NLM_F_REQUEST | NLM_F_ACK 1955 if flowspec is None: 1956 msg_flags |= NLM_F_DUMP 1957 rep = None 1958 1959 try: 1960 rep = self.nlm_request( 1961 msg, 1962 msg_type=self.prid, 1963 msg_flags=msg_flags, 1964 ) 1965 except NetlinkError as ne: 1966 raise ne 1967 return rep 1968 1969 def miss(self, packetmsg): 1970 seq = packetmsg["header"]["sequence_number"] 1971 keystr = "(none)" 1972 key_field = packetmsg.get_attr("OVS_PACKET_ATTR_KEY") 1973 if key_field is not None: 1974 keystr = key_field.dpstr(None, True) 1975 1976 pktdata = packetmsg.get_attr("OVS_PACKET_ATTR_PACKET") 1977 pktpres = "yes" if pktdata is not None else "no" 1978 1979 print("MISS upcall[%d/%s]: %s" % (seq, pktpres, keystr), flush=True) 1980 1981 def execute(self, packetmsg): 1982 print("userspace execute command") 1983 1984 def action(self, packetmsg): 1985 print("userspace action command") 1986 1987 1988def print_ovsdp_full(dp_lookup_rep, ifindex, ndb=NDB(), vpl=OvsVport()): 1989 dp_name = dp_lookup_rep.get_attr("OVS_DP_ATTR_NAME") 1990 base_stats = dp_lookup_rep.get_attr("OVS_DP_ATTR_STATS") 1991 megaflow_stats = dp_lookup_rep.get_attr("OVS_DP_ATTR_MEGAFLOW_STATS") 1992 user_features = dp_lookup_rep.get_attr("OVS_DP_ATTR_USER_FEATURES") 1993 masks_cache_size = dp_lookup_rep.get_attr("OVS_DP_ATTR_MASKS_CACHE_SIZE") 1994 1995 print("%s:" % dp_name) 1996 print( 1997 " lookups: hit:%d missed:%d lost:%d" 1998 % (base_stats["hit"], base_stats["missed"], base_stats["lost"]) 1999 ) 2000 print(" flows:%d" % base_stats["flows"]) 2001 pkts = base_stats["hit"] + base_stats["missed"] 2002 avg = (megaflow_stats["mask_hit"] / pkts) if pkts != 0 else 0.0 2003 print( 2004 " masks: hit:%d total:%d hit/pkt:%f" 2005 % (megaflow_stats["mask_hit"], megaflow_stats["masks"], avg) 2006 ) 2007 print(" caches:") 2008 print(" masks-cache: size:%d" % masks_cache_size) 2009 2010 if user_features is not None: 2011 print(" features: 0x%X" % user_features) 2012 2013 # port print out 2014 for iface in ndb.interfaces: 2015 rep = vpl.info(iface.ifname, ifindex) 2016 if rep is not None: 2017 print( 2018 " port %d: %s (%s)" 2019 % ( 2020 rep.get_attr("OVS_VPORT_ATTR_PORT_NO"), 2021 rep.get_attr("OVS_VPORT_ATTR_NAME"), 2022 OvsVport.type_to_str(rep.get_attr("OVS_VPORT_ATTR_TYPE")), 2023 ) 2024 ) 2025 2026 2027def main(argv): 2028 nlmsg_atoms.ovskey = ovskey 2029 nlmsg_atoms.ovsactions = ovsactions 2030 2031 # version check for pyroute2 2032 prverscheck = pyroute2.__version__.split(".") 2033 if int(prverscheck[0]) == 0 and int(prverscheck[1]) < 6: 2034 print("Need to upgrade the python pyroute2 package to >= 0.6.") 2035 sys.exit(0) 2036 2037 parser = argparse.ArgumentParser() 2038 parser.add_argument( 2039 "-v", 2040 "--verbose", 2041 action="count", 2042 help="Increment 'verbose' output counter.", 2043 default=0, 2044 ) 2045 subparsers = parser.add_subparsers() 2046 2047 showdpcmd = subparsers.add_parser("show") 2048 showdpcmd.add_argument( 2049 "showdp", metavar="N", type=str, nargs="?", help="Datapath Name" 2050 ) 2051 2052 adddpcmd = subparsers.add_parser("add-dp") 2053 adddpcmd.add_argument("adddp", help="Datapath Name") 2054 adddpcmd.add_argument( 2055 "-u", 2056 "--upcall", 2057 action="store_true", 2058 help="Leave open a reader for upcalls", 2059 ) 2060 adddpcmd.add_argument( 2061 "-V", 2062 "--versioning", 2063 required=False, 2064 help="Specify a custom version / feature string", 2065 ) 2066 2067 deldpcmd = subparsers.add_parser("del-dp") 2068 deldpcmd.add_argument("deldp", help="Datapath Name") 2069 2070 addifcmd = subparsers.add_parser("add-if") 2071 addifcmd.add_argument("dpname", help="Datapath Name") 2072 addifcmd.add_argument("addif", help="Interface name for adding") 2073 addifcmd.add_argument( 2074 "-u", 2075 "--upcall", 2076 action="store_true", 2077 help="Leave open a reader for upcalls", 2078 ) 2079 addifcmd.add_argument( 2080 "-t", 2081 "--ptype", 2082 type=str, 2083 default="netdev", 2084 choices=["netdev", "internal"], 2085 help="Interface type (default netdev)", 2086 ) 2087 delifcmd = subparsers.add_parser("del-if") 2088 delifcmd.add_argument("dpname", help="Datapath Name") 2089 delifcmd.add_argument("delif", help="Interface name for adding") 2090 2091 dumpflcmd = subparsers.add_parser("dump-flows") 2092 dumpflcmd.add_argument("dumpdp", help="Datapath Name") 2093 2094 addflcmd = subparsers.add_parser("add-flow") 2095 addflcmd.add_argument("flbr", help="Datapath name") 2096 addflcmd.add_argument("flow", help="Flow specification") 2097 addflcmd.add_argument("acts", help="Flow actions") 2098 2099 delfscmd = subparsers.add_parser("del-flows") 2100 delfscmd.add_argument("flsbr", help="Datapath name") 2101 2102 args = parser.parse_args() 2103 2104 if args.verbose > 0: 2105 if args.verbose > 1: 2106 logging.basicConfig(level=logging.DEBUG) 2107 2108 ovspk = OvsPacket() 2109 ovsdp = OvsDatapath() 2110 ovsvp = OvsVport(ovspk) 2111 ovsflow = OvsFlow() 2112 ndb = NDB() 2113 2114 if hasattr(args, "showdp"): 2115 found = False 2116 for iface in ndb.interfaces: 2117 rep = None 2118 if args.showdp is None: 2119 rep = ovsdp.info(iface.ifname, 0) 2120 elif args.showdp == iface.ifname: 2121 rep = ovsdp.info(iface.ifname, 0) 2122 2123 if rep is not None: 2124 found = True 2125 print_ovsdp_full(rep, iface.index, ndb, ovsvp) 2126 2127 if not found: 2128 msg = "No DP found" 2129 if args.showdp is not None: 2130 msg += ":'%s'" % args.showdp 2131 print(msg) 2132 elif hasattr(args, "adddp"): 2133 rep = ovsdp.create(args.adddp, args.upcall, args.versioning, ovspk) 2134 if rep is None: 2135 print("DP '%s' already exists" % args.adddp) 2136 else: 2137 print("DP '%s' added" % args.adddp) 2138 if args.upcall: 2139 ovspk.upcall_handler(ovsflow) 2140 elif hasattr(args, "deldp"): 2141 ovsdp.destroy(args.deldp) 2142 elif hasattr(args, "addif"): 2143 rep = ovsdp.info(args.dpname, 0) 2144 if rep is None: 2145 print("DP '%s' not found." % args.dpname) 2146 return 1 2147 dpindex = rep["dpifindex"] 2148 rep = ovsvp.attach(rep["dpifindex"], args.addif, args.ptype) 2149 msg = "vport '%s'" % args.addif 2150 if rep and rep["header"]["error"] is None: 2151 msg += " added." 2152 else: 2153 msg += " failed to add." 2154 if args.upcall: 2155 if rep is None: 2156 rep = ovsvp.reset_upcall(dpindex, args.addif, ovspk) 2157 ovsvp.upcall_handler(ovsflow) 2158 elif hasattr(args, "delif"): 2159 rep = ovsdp.info(args.dpname, 0) 2160 if rep is None: 2161 print("DP '%s' not found." % args.dpname) 2162 return 1 2163 rep = ovsvp.detach(rep["dpifindex"], args.delif) 2164 msg = "vport '%s'" % args.delif 2165 if rep and rep["header"]["error"] is None: 2166 msg += " removed." 2167 else: 2168 msg += " failed to remove." 2169 elif hasattr(args, "dumpdp"): 2170 rep = ovsdp.info(args.dumpdp, 0) 2171 if rep is None: 2172 print("DP '%s' not found." % args.dumpdp) 2173 return 1 2174 rep = ovsflow.dump(rep["dpifindex"]) 2175 for flow in rep: 2176 print(flow.dpstr(True if args.verbose > 0 else False)) 2177 elif hasattr(args, "flbr"): 2178 rep = ovsdp.info(args.flbr, 0) 2179 if rep is None: 2180 print("DP '%s' not found." % args.flbr) 2181 return 1 2182 flow = OvsFlow.ovs_flow_msg() 2183 flow.parse(args.flow, args.acts, rep["dpifindex"]) 2184 ovsflow.add_flow(rep["dpifindex"], flow) 2185 elif hasattr(args, "flsbr"): 2186 rep = ovsdp.info(args.flsbr, 0) 2187 if rep is None: 2188 print("DP '%s' not found." % args.flsbr) 2189 ovsflow.del_flows(rep["dpifindex"]) 2190 2191 return 0 2192 2193 2194if __name__ == "__main__": 2195 sys.exit(main(sys.argv)) 2196