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